Three related Cobblemon behaviours. Moves to Players has NPCs move towards players within a certain range. Force Battle initiates battles with players that they are right next to and can see. Finally, Stat Tracking records wins, losses, and interaction counts on both the player and the NPC, so later behaviours can branch on the result (alt dialogue after first defeat, a different reward on the third visit, a rematch dialogue branch that scales with rematch count). Together they are the foundation for trainers on an adventure Cobblemon server and mimic the battle mechanics of the mainline Pokemon games.
Moves to Players and Force Battle
Add these behaviours to an NPC, set the 'enabled' flags to true, and the NPC starts scanning every 5 ticks for players inside 2 different ranges. When a player is detected in the movement range, the NPC will start walking towards them. If they get close enough, the NPC will stop and trigger a dialogue and then the battle. Detection uses q.entity.can_see, so the NPC needs actual line of sight, not just proximity.
A few details that make the behaviour usable in practice:
- Ignore perm: players with specified 'ignore perm's are skipped. The default is
npc.battle.won.{{npc}}_forced_battle, so once a player has beaten the NPC it does not re-trigger. - Battle-state gating: players already in a battle or another dialogue are skipped, so two force-battle NPCs in the same room do not fight over the same player.
- One target per tick: the first eligible player breaks the loop. As such, a crowd does not get sequentially yanked into back-to-back battles.
The pre-battle dialogue is configurable. Leaving it blank picks from a pool of generic taunts. After-battle dialogue, scripts, and commands are layered on through the after_dialogue_* behaviours, the same composable hooks the rest of the dialogue system uses. As such, a force-battle NPC can grant a perm, give a reward, or open a follow-up conversation when the player wins.
Use cases
- Wild trainers: the classic Pokémon trope, dropped into the world without writing any scripts.
- Gym leaders: pair with
battle_won_permto grant a badge perm on win, and the NPC stops triggering. Pair withoptional_battlefor a rematch button after the first defeat. - Ambush enemies:
force_battle_radiusof 8 or more with a hidden NPC makes a "you can't sneak past" choke point. - Tutorial fights: small radius, scripted party, generous afterparty rewards.
Stat tracking
The Track Battles behaviour is a one-toggle add-on. When enabled, every battle resolves into several datapoints:
times_wonandtimes_loston the NPC's data (lifetime W/L for the trainer).times_wonandtimes_lostfor this player against this NPC on the player's data, along withtotal_winsandtotal_losses(both in general and against NPCs).
A companion behaviour, Track Interactions, does the same for non-battle interactions. times_interacted lives on both the NPC and the player. Both systems write through shared cobblemon:update_npc_tracked_stat and cobblemon:update_player_tracked_stat helpers, so any future tracked stat can hook in without touching the battle code.
The scope lens query tool
The behaviour exposes a debug query: hold a Scope Lens (configurable item) with the npc.check_tracked_stats perm (also configurable) and right-click any tracked NPC. The chat prints:
[INFO]: NPC <uuid> has been interacted with N times.
[INFO]: NPC <uuid> battle record: W wins, L losses.
It is intentionally hidden behind both a perm and a held item, so admins can drop in to audit an NPC without exposing the query to regular players. Other systems can read the same q.player.data.tracked_stat.* values from Molang to branch on them. As such, a quest can offer a special reward if the player has beaten a specific NPC three times, with no extra scripts required.
Techy Stuff
- Built on Cobblemon's behaviour, dialogue, and Molang systems, configured in JSON.
- The force-battle scanner runs as an
add_tasks_to_activitytask onminecraft:idlepriority 0, throttled to every 5 game ticks viamath.mod(q.entity.world.game_time, 5). - Battle outcomes hook into Cobblemon's battle callbacks. Tracked stat writes go through the shared
update_npc_tracked_stat/update_player_tracked_stathelpers and persist viasave_data(). - The scope-lens query reuses the same
print_and_tellchat helper as the dialogue and animation-interaction systems.
Built for the Callisto and Cobblewilds Cobblemon servers, but available for commission.