Example Scripts
Example Scripts
Section titled “Example Scripts”This page provides annotated walkthroughs of eight production-ready scripts. Each one demonstrates real patterns you can copy and adapt for your own server. The scripts are based on the mcmmo-style example scripts that ship with Ceremony.
1. Treecapitator (Tree Feller)
Section titled “1. Treecapitator (Tree Feller)”What it does: When a player with Woodcutting level 5 or higher breaks a log block, the entire tree is felled automatically. Sneaking disables the ability.
Key concepts: BFS traversal, re-entrancy guard, Java registry lookup, sneak-to-disable toggle.
/// <reference path="types/ceremony-api.d.ts" />
const BuiltInRegistries = Java.type('net.minecraft.core.registries.BuiltInRegistries');const BlockPos = Java.type('net.minecraft.core.BlockPos');const JourneyApi = Java.type('com.briar.journey.api.JourneyApi');
const MAX_BLOCKS = 128;const processing = new Set();
// Get the string ID of a block (e.g., "minecraft:oak_log")function getBlockId(state) { try { const key = BuiltInRegistries.BLOCK.getKey(state.getBlock()); return key ? key.toString() : ''; } catch (e) { return ''; }}
// Read the player's Woodcutting skill level from Journeyfunction getWoodcuttingLevel(player) { try { const api = JourneyApi.getInstance(); const profile = api.getPlayerProfile(player.getUUID()); return profile ? (profile.getSkill('woodcutting')?.getLevel() ?? 0) : 0; } catch (e) { return 0; }}
// BFS: find all connected log/leaf blocks starting from a positionfunction findTree(world, startPos) { const queue = [startPos]; const visited = new Set(); const logs = [];
visited.add(startPos.getX() + ',' + startPos.getY() + ',' + startPos.getZ());
// Check all 26 neighbors (including diagonals) for trees const offsets = []; for (let dx = -1; dx <= 1; dx++) { for (let dy = -1; dy <= 1; dy++) { for (let dz = -1; dz <= 1; dz++) { if (dx === 0 && dy === 0 && dz === 0) continue; offsets.push([dx, dy, dz]); } } }
while (queue.length > 0 && logs.length < MAX_BLOCKS) { const current = queue.shift(); const state = world.getBlockState(current); const id = getBlockId(state);
// Match log and wood blocks (oak_log, birch_wood, stripped_spruce_log, etc.) if (!id.includes('_log') && !id.includes('_wood')) continue;
logs.push(current);
for (const [dx, dy, dz] of offsets) { const neighbor = new BlockPos( current.getX() + dx, current.getY() + dy, current.getZ() + dz ); const nKey = neighbor.getX() + ',' + neighbor.getY() + ',' + neighbor.getZ(); if (!visited.has(nKey)) { visited.add(nKey); queue.push(neighbor); } } }
return logs;}
function onEnable() { Logger.info('[Treecapitator] Loaded!');
Events.on('blockBreak', (player, pos, state, world) => { // Re-entrancy guard: skip if this break was triggered by us const key = pos.getX() + ',' + pos.getY() + ',' + pos.getZ(); if (processing.has(key)) return;
// Only activate for log blocks const blockId = getBlockId(state); if (!blockId.includes('_log')) return;
// Sneak to disable -- lets players break single logs normally if (player.isShiftKeyDown()) return;
// Require Woodcutting level 5 if (getWoodcuttingLevel(player) < 5) return;
// Find all connected logs via BFS const logs = findTree(world, pos);
// Destroy each log, using the re-entrancy guard to prevent recursion for (const logPos of logs) { const logKey = logPos.getX() + ',' + logPos.getY() + ',' + logPos.getZ(); processing.add(logKey); try { world.destroyBlock(logPos, true, player); } finally { processing.delete(logKey); } }
// Visual and audio feedback sound(player, 'block.wood.break', 1.0, 0.8); msg(player, '<green>Felled <yellow>' + logs.length + '</yellow> logs!'); });}
function onDisable() { processing.clear();}Customization points:
- Change
MAX_BLOCKSto control the maximum tree size - Change the required level from
5to any value - Add or remove block ID suffixes in the match check to support modded log types
2. Vein Miner
Section titled “2. Vein Miner”What it does: When a player with Mining level 5 or higher sneaks and breaks an ore block, the entire connected vein of the same ore type is mined at once.
Key concepts: BFS with same-block-type matching, cardinal direction neighbors only, sneak-to-activate.
/// <reference path="types/ceremony-api.d.ts" />
const BuiltInRegistries = Java.type('net.minecraft.core.registries.BuiltInRegistries');const BlockPos = Java.type('net.minecraft.core.BlockPos');const JourneyApi = Java.type('com.briar.journey.api.JourneyApi');
const MAX_BLOCKS = 64;const processing = new Set();
function getBlockId(state) { try { const key = BuiltInRegistries.BLOCK.getKey(state.getBlock()); return key ? key.toString() : ''; } catch (e) { return ''; }}
function getMiningLevel(player) { try { const api = JourneyApi.getInstance(); const profile = api.getPlayerProfile(player.getUUID()); return profile ? (profile.getSkill('mining')?.getLevel() ?? 0) : 0; } catch (e) { return 0; }}
// BFS: find connected blocks of the exact same type (cardinal directions only)function findVein(world, startPos, targetId) { const queue = [startPos]; const visited = new Set(); const blocks = [];
visited.add(startPos.getX() + ',' + startPos.getY() + ',' + startPos.getZ());
// Cardinal directions only (6 neighbors, no diagonals) const directions = [ [1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1] ];
while (queue.length > 0 && blocks.length < MAX_BLOCKS) { const current = queue.shift(); const state = world.getBlockState(current); const id = getBlockId(state);
// Only match the exact same ore type if (id !== targetId) continue;
blocks.push(current);
for (const [dx, dy, dz] of directions) { const neighbor = new BlockPos( current.getX() + dx, current.getY() + dy, current.getZ() + dz ); const nKey = neighbor.getX() + ',' + neighbor.getY() + ',' + neighbor.getZ(); if (!visited.has(nKey)) { visited.add(nKey); queue.push(neighbor); } } }
return blocks;}
function onEnable() { Logger.info('[Vein Miner] Loaded!');
Events.on('blockBreak', (player, pos, state, world) => { const key = pos.getX() + ',' + pos.getY() + ',' + pos.getZ(); if (processing.has(key)) return;
const blockId = getBlockId(state); // Only activate for ore blocks if (!blockId.endsWith('_ore') && !blockId.includes('raw_')) return;
// Must be sneaking to activate (opposite of treecapitator) if (!player.isShiftKeyDown()) return;
// Require Mining level 5 if (getMiningLevel(player) < 5) return;
// Find the entire connected vein const vein = findVein(world, pos, blockId);
// Break all blocks in the vein for (const blockPos of vein) { const bKey = blockPos.getX() + ',' + blockPos.getY() + ',' + blockPos.getZ(); processing.add(bKey); try { world.destroyBlock(blockPos, true, player); } finally { processing.delete(bKey); } }
sound(player, 'entity.experience_orb.pickup', 0.8, 1.0); msg(player, '<aqua>Vein mined <yellow>' + vein.length + '</yellow> blocks!'); });}
function onDisable() { processing.clear();}Customization points:
- Change
MAX_BLOCKS(64 is conservative, 128 for larger veins) - Add diagonal neighbors to the
directionsarray for looser vein matching - Modify the block ID check to support modded ores
3. Green Thumb (Auto-Replant)
Section titled “3. Green Thumb (Auto-Replant)”What it does: When a player with Herbalism level 5 or higher harvests a fully-grown crop, the crop is automatically replanted at age 0 after a short delay.
Key concepts: Java block state properties, Game.scheduler.after for delayed replant, age property checking.
/// <reference path="types/ceremony-api.d.ts" />
const BuiltInRegistries = Java.type('net.minecraft.core.registries.BuiltInRegistries');const BlockPos = Java.type('net.minecraft.core.BlockPos');const JourneyApi = Java.type('com.briar.journey.api.JourneyApi');
// Blocks that count as cropsconst CROP_IDS = new Set([ 'minecraft:wheat', 'minecraft:carrots', 'minecraft:potatoes', 'minecraft:beetroots', 'minecraft:nether_wart']);
function getBlockId(state) { try { const key = BuiltInRegistries.BLOCK.getKey(state.getBlock()); return key ? key.toString() : ''; } catch (e) { return ''; }}
function getHerbalismLevel(player) { try { const api = JourneyApi.getInstance(); const profile = api.getPlayerProfile(player.getUUID()); return profile ? (profile.getSkill('herbalism')?.getLevel() ?? 0) : 0; } catch (e) { return 0; }}
// Check if a crop is fully grown by reading the "age" block state propertyfunction isFullyGrown(state) { try { const properties = state.getProperties(); for (const prop of properties) { if (prop.getName() === 'age') { const currentAge = state.getValue(prop); // Get all possible values and find the max const possibleValues = prop.getPossibleValues(); let maxAge = 0; for (const val of possibleValues) { if (val > maxAge) maxAge = val; } return currentAge >= maxAge; } } } catch (e) { Logger.warn('[GreenThumb] Failed to check crop age: ' + e.message); } return false;}
function onEnable() { Logger.info('[Green Thumb] Loaded!');
Events.on('blockBreak', (player, pos, state, world) => { const blockId = getBlockId(state);
// Only activate for crop blocks if (!CROP_IDS.has(blockId)) return;
// Must be fully grown if (!isFullyGrown(state)) return;
// Require Herbalism level 5 if (getHerbalismLevel(player) < 5) return;
// Remember the block type and position for replanting const block = state.getBlock(); const replantPos = new BlockPos(pos.getX(), pos.getY(), pos.getZ());
// Replant after a 2-tick delay (after the block is broken) Game.scheduler.after(2, () => { try { // Place the crop back at age 0 (default state) const defaultState = block.defaultBlockState(); world.setBlock(replantPos, defaultState, 3); Game.particles.spawn( world, replantPos.getX() + 0.5, replantPos.getY() + 0.5, replantPos.getZ() + 0.5, ParticleTypes.HAPPY_VILLAGER, 5 ); } catch (e) { Logger.warn('[GreenThumb] Failed to replant: ' + e.message); } });
msg(player, '<green>Auto-replanted!'); });}
function onDisable() {}Customization points:
- Add modded crop IDs to the
CROP_IDSset - Change the delay from 2 ticks to a longer value for a more visible replant animation
- Add a chance-based system where higher Herbalism levels replant more reliably
4. Excavation Treasures (Treasure Hunter)
Section titled “4. Excavation Treasures (Treasure Hunter)”What it does: When a player with Excavation level 5 or higher breaks dirt, sand, gravel, or clay, they have a chance to find bonus treasure items. Higher levels unlock better tiers with rarer drops.
Key concepts: Tiered reward tables, random chance rolls, command-based item giving.
/// <reference path="types/ceremony-api.d.ts" />
const BuiltInRegistries = Java.type('net.minecraft.core.registries.BuiltInRegistries');const JourneyApi = Java.type('com.briar.journey.api.JourneyApi');
// Blocks that can yield treasuresconst DIGGABLE = new Set([ 'minecraft:dirt', 'minecraft:grass_block', 'minecraft:sand', 'minecraft:gravel', 'minecraft:clay', 'minecraft:soul_sand', 'minecraft:red_sand', 'minecraft:coarse_dirt', 'minecraft:rooted_dirt']);
// Reward tiers -- checked from best to worst, first match winsconst TIERS = [ { minLevel: 25, chance: 0.02, items: ['minecraft:diamond', 'minecraft:emerald', 'minecraft:netherite_scrap'] }, { minLevel: 15, chance: 0.05, items: ['minecraft:gold_ingot', 'minecraft:lapis_lazuli', 'minecraft:amethyst_shard'] }, { minLevel: 10, chance: 0.10, items: ['minecraft:iron_ingot', 'minecraft:redstone', 'minecraft:quartz'] }, { minLevel: 5, chance: 0.15, items: ['minecraft:coal', 'minecraft:flint', 'minecraft:bone', 'minecraft:string'] },];
function getBlockId(state) { try { const key = BuiltInRegistries.BLOCK.getKey(state.getBlock()); return key ? key.toString() : ''; } catch (e) { return ''; }}
function getExcavationLevel(player) { try { const api = JourneyApi.getInstance(); const profile = api.getPlayerProfile(player.getUUID()); return profile ? (profile.getSkill('excavation')?.getLevel() ?? 0) : 0; } catch (e) { return 0; }}
function rollTreasure(level) { for (const tier of TIERS) { if (level >= tier.minLevel && Math.random() < tier.chance) { return tier.items[Math.floor(Math.random() * tier.items.length)]; } } return null;}
function runCommand(cmd) { try { Server.getCommands().performPrefixedCommand( Server.createCommandSourceStack().withSuppressedOutput(), cmd ); } catch (e) { Logger.warn('[Treasures] Command failed: ' + e.message); }}
function onEnable() { Logger.info('[Excavation Treasures] Loaded!');
Events.on('blockBreak', (player, pos, state, world) => { const blockId = getBlockId(state); if (!DIGGABLE.has(blockId)) return;
const level = getExcavationLevel(player); if (level < 5) return;
const treasure = rollTreasure(level); if (!treasure) return;
// Give the treasure item via server command const name = player.getName().getString(); runCommand('give ' + name + ' ' + treasure + ' 1');
// Notify the player const itemName = treasure.split(':')[1].replace(/_/g, ' '); msg(player, '<gold>Treasure found! <yellow>' + itemName); sound(player, 'entity.experience_orb.pickup', 0.6, 1.4);
// Sparkle particles at the dig site Game.particles.spawn( world, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, ParticleTypes.HAPPY_VILLAGER, 8 ); });}
function onDisable() {}Customization points:
- Edit the
TIERSarray to change drop rates, level requirements, and item pools - Add modded items to the reward lists
- Add the
DIGGABLEset to include modded soil types
5. Archery Daze
Section titled “5. Archery Daze”What it does: When a player with Archery level 10 or higher kills a mob with a bow, all mobs within 5 blocks of the killed mob are stunned (given Slowness and Weakness effects) for several seconds.
Key concepts: AABB entity search, MobEffectInstance creation, Java Holder access.
/// <reference path="types/ceremony-api.d.ts" />
const MobEffectInstance = Java.type('net.minecraft.world.effect.MobEffectInstance');const BuiltInRegistries = Java.type('net.minecraft.core.registries.BuiltInRegistries');const ResourceLocation = Java.type('net.minecraft.resources.ResourceLocation');const JourneyApi = Java.type('com.briar.journey.api.JourneyApi');const AABB = Java.type('net.minecraft.world.phys.AABB');
const STUN_RADIUS = 5.0;const STUN_DURATION = 80; // 4 seconds in ticks
function getArcheryLevel(player) { try { const api = JourneyApi.getInstance(); const profile = api.getPlayerProfile(player.getUUID()); return profile ? (profile.getSkill('archery')?.getLevel() ?? 0) : 0; } catch (e) { return 0; }}
// Get a mob effect holder by ID (required for MobEffectInstance in modern MC)function getEffectHolder(effectId) { try { const key = ResourceLocation.parse(effectId); const effect = BuiltInRegistries.MOB_EFFECT.get(key); if (!effect) return null; return BuiltInRegistries.MOB_EFFECT.wrapAsHolder(effect); } catch (e) { Logger.warn('[ArcheryDaze] Failed to get effect holder: ' + e.message); return null; }}
function onEnable() { Logger.info('[Archery Daze] Loaded!');
Events.on('entityKilledOther', (world, killer, killed) => { // Check if the killer is a player const ServerPlayer = Java.type('net.minecraft.server.level.ServerPlayer'); if (!(killer instanceof ServerPlayer)) return;
// Require Archery level 10 if (getArcheryLevel(killer) < 10) return;
// Check if the player is holding a bow (killed with ranged weapon) try { const mainHand = killer.getMainHandItem(); const itemId = BuiltInRegistries.ITEM.getKey(mainHand.getItem()).toString(); if (itemId !== 'minecraft:bow' && itemId !== 'minecraft:crossbow') return; } catch (e) { return; }
// Find all mobs within STUN_RADIUS of the killed entity const pos = killed.position(); const searchBox = new AABB( pos.x() - STUN_RADIUS, pos.y() - STUN_RADIUS, pos.z() - STUN_RADIUS, pos.x() + STUN_RADIUS, pos.y() + STUN_RADIUS, pos.z() + STUN_RADIUS );
const LivingEntity = Java.type('net.minecraft.world.entity.LivingEntity'); const nearby = world.getEntitiesOfClass(LivingEntity.class, searchBox);
// Apply stun effects to nearby mobs (not players) const slowness = getEffectHolder('minecraft:slowness'); const weakness = getEffectHolder('minecraft:weakness');
let stunCount = 0; for (const entity of nearby) { if (entity instanceof ServerPlayer) continue; // Do not stun players if (entity === killed) continue;
try { if (slowness) entity.addEffect(new MobEffectInstance(slowness, STUN_DURATION, 2)); if (weakness) entity.addEffect(new MobEffectInstance(weakness, STUN_DURATION, 1)); stunCount++; } catch (e) { Logger.warn('[ArcheryDaze] Failed to apply effect: ' + e.message); } }
if (stunCount > 0) { msg(killer, '<yellow>Daze! Stunned <gold>' + stunCount + '</gold> nearby mobs!'); sound(killer, 'entity.elder_guardian.curse', 0.5, 1.5); } });}
function onDisable() {}Customization points:
- Adjust
STUN_RADIUSandSTUN_DURATIONto balance the ability - Change the effect amplifier (the
2inMobEffectInstance(slowness, duration, 2)) - Add more effects like Blindness or Glowing
6. Shiny Charm
Section titled “6. Shiny Charm”What it does: When a player with Taming level 10 or higher catches a Pokemon, there is a bonus chance (scaling with level) that the Pokemon becomes shiny.
Key concepts: Cobblemon events, Pokemon manipulation, probability-based mechanics.
/// <reference path="types/ceremony-api.d.ts" />
const JourneyApi = Java.type('com.briar.journey.api.JourneyApi');
// Base shiny chance bonus: 5% at level 10, scaling up to 15% at level 50const BASE_CHANCE = 0.05;const MAX_CHANCE = 0.15;const MIN_LEVEL = 10;const MAX_LEVEL = 50;
function getTamingLevel(player) { try { const api = JourneyApi.getInstance(); const profile = api.getPlayerProfile(player.getUUID()); return profile ? (profile.getSkill('taming')?.getLevel() ?? 0) : 0; } catch (e) { return 0; }}
function getShinyChance(level) { if (level < MIN_LEVEL) return 0; // Linear scale from BASE_CHANCE at MIN_LEVEL to MAX_CHANCE at MAX_LEVEL const t = Math.min((level - MIN_LEVEL) / (MAX_LEVEL - MIN_LEVEL), 1.0); return BASE_CHANCE + t * (MAX_CHANCE - BASE_CHANCE);}
function onEnable() { Logger.info('[Shiny Charm] Loaded!');
// Listen for Cobblemon Pokemon capture events Events.on('pokemonCaptured', (event) => { try { const player = event.getPlayer(); const pokemon = event.getPokemon();
// Skip if already shiny if (pokemon.getShiny()) return;
const level = getTamingLevel(player); const chance = getShinyChance(level); if (chance <= 0) return;
// Roll for shiny if (Math.random() < chance) { pokemon.setShiny(true);
const pokemonName = pokemon.getSpecies().getName(); msg(player, '<gradient:gold:yellow>Your ' + pokemonName + ' became SHINY!</gradient>'); title(player, '<gold>SHINY!', '<yellow>' + pokemonName, 5, 40, 10); sound(player, 'entity.player.levelup', 1.0, 1.5);
// Announce to server const playerName = player.getName().getString(); broadcast('<gold>' + playerName + ' caught a <yellow>SHINY ' + pokemonName + '</yellow>!'); } } catch (e) { Logger.warn('[ShinyCharm] Error: ' + e.message); } });}
function onDisable() {}Customization points:
- Adjust
BASE_CHANCE,MAX_CHANCE,MIN_LEVEL, andMAX_LEVELto tune the probability curve - Change the scaling from linear to exponential for a different feel
- Add special particle effects or fireworks for shiny catches
7. Stamina Master
Section titled “7. Stamina Master”What it does: Players with Taming level 5 or higher experience reduced stamina drain when riding Pokemon. The reduction scales with level, and at max level (50), stamina drain is completely eliminated.
Key concepts: Event modification (setRideStamina), level-scaled reduction, infinite stamina at max level.
/// <reference path="types/ceremony-api.d.ts" />
const JourneyApi = Java.type('com.briar.journey.api.JourneyApi');
const MIN_LEVEL = 5;const MAX_LEVEL = 50;
// At MIN_LEVEL: reduce drain by 20%. At MAX_LEVEL: reduce by 100% (infinite stamina).const MIN_REDUCTION = 0.20;const MAX_REDUCTION = 1.00;
function getTamingLevel(player) { try { const api = JourneyApi.getInstance(); const profile = api.getPlayerProfile(player.getUUID()); return profile ? (profile.getSkill('taming')?.getLevel() ?? 0) : 0; } catch (e) { return 0; }}
function getReduction(level) { if (level < MIN_LEVEL) return 0; if (level >= MAX_LEVEL) return MAX_REDUCTION; const t = (level - MIN_LEVEL) / (MAX_LEVEL - MIN_LEVEL); return MIN_REDUCTION + t * (MAX_REDUCTION - MIN_REDUCTION);}
function onEnable() { Logger.info('[Stamina Master] Loaded!');
// Listen for Pokemon ride stamina drain events Events.on('rideStaminaDrain', (event) => { try { const player = event.getPlayer(); const level = getTamingLevel(player); const reduction = getReduction(level);
if (reduction <= 0) return;
if (reduction >= 1.0) { // Max level: infinite stamina, set drain to 0 event.setRideStamina(event.getCurrentStamina()); } else { // Reduce the stamina drain proportionally const currentStamina = event.getCurrentStamina(); const newStamina = event.getNewStamina(); const drain = currentStamina - newStamina; const reducedDrain = drain * (1.0 - reduction); event.setRideStamina(currentStamina - reducedDrain); } } catch (e) { Logger.warn('[StaminaMaster] Error: ' + e.message); } });}
function onDisable() {}Customization points:
- Change
MIN_REDUCTIONandMAX_REDUCTIONto adjust the scaling curve - Add an action bar message showing the current stamina reduction percentage
- Add a visual effect when infinite stamina is active at max level
8. Battle Rewards
Section titled “8. Battle Rewards”What it does: Players with Taming level 5 or higher earn bonus currency when they win wild Pokemon battles. The reward scales with their Taming level.
Key concepts: Cobblemon battle events, ActorType checking, economy command integration.
/// <reference path="types/ceremony-api.d.ts" />
const JourneyApi = Java.type('com.briar.journey.api.JourneyApi');
const MIN_LEVEL = 5;const BASE_REWARD = 50; // Currency at MIN_LEVELconst MAX_REWARD = 500; // Currency at level 50const MAX_LEVEL = 50;
function getTamingLevel(player) { try { const api = JourneyApi.getInstance(); const profile = api.getPlayerProfile(player.getUUID()); return profile ? (profile.getSkill('taming')?.getLevel() ?? 0) : 0; } catch (e) { return 0; }}
function calculateReward(level) { if (level < MIN_LEVEL) return 0; const t = Math.min((level - MIN_LEVEL) / (MAX_LEVEL - MIN_LEVEL), 1.0); return Math.floor(BASE_REWARD + t * (MAX_REWARD - BASE_REWARD));}
function runCommand(cmd) { try { Server.getCommands().performPrefixedCommand( Server.createCommandSourceStack().withSuppressedOutput(), cmd ); } catch (e) { Logger.warn('[BattleRewards] Command failed: ' + e.message); }}
function onEnable() { Logger.info('[Battle Rewards] Loaded!');
Events.on('battleVictory', (event) => { try { // Get all battle actors const winners = event.getWinners();
for (const actor of winners) { // Only reward player actors, not wild Pokemon or NPCs const ActorType = Java.type('com.cobblemon.mod.common.api.battles.model.actor.ActorType'); if (actor.getType() !== ActorType.PLAYER) continue;
// Check if this was a wild battle (not PvP or NPC) if (!event.wasWildBattle()) continue;
const player = actor.getEntity(); if (!player) continue;
const level = getTamingLevel(player); const reward = calculateReward(level); if (reward <= 0) continue;
// Give currency via economy command const name = player.getName().getString(); runCommand('eco give ' + name + ' ' + reward);
msg(player, '<gold>Battle bonus! <yellow>+' + reward + ' coins</yellow> <gray>(Taming Lv.' + level + ')'); sound(player, 'entity.experience_orb.pickup', 0.7, 1.2); } } catch (e) { Logger.warn('[BattleRewards] Error: ' + e.message); } });}
function onDisable() {}Customization points:
- Change
BASE_REWARDandMAX_REWARDto balance your server economy - Replace the
eco givecommand with your economy mod’s specific command - Add bonus multipliers for defeating higher-level Pokemon
- Restrict rewards to specific battle types (wild only, or include NPC trainers)
Script Summary
Section titled “Script Summary”| Script | Skill | Min Level | Key Pattern |
|---|---|---|---|
| Treecapitator | Woodcutting | 5 | BFS traversal, re-entrancy guard |
| Vein Miner | Mining | 5 | BFS with type matching |
| Green Thumb | Herbalism | 5 | Block state properties, delayed replant |
| Excavation Treasures | Excavation | 5 | Tiered rewards, random chance |
| Archery Daze | Archery | 10 | AABB search, MobEffectInstance |
| Shiny Charm | Taming | 10 | Pokemon events, probability scaling |
| Stamina Master | Taming | 5 | Event modification, level scaling |
| Battle Rewards | Taming | 5 | Battle events, economy integration |
Next Steps
Section titled “Next Steps”- Common Patterns — Reusable patterns referenced throughout these scripts
- Events Reference — Full list of all 140+ events you can listen for
- Global Functions — Reference for
msg(),sound(),title(), and other helpers