// Brass & Sigil — Waystones placement policy // // Rules: // - Regular waystones (6 stone variants): 1 per player. Forces players to // build actual transport infrastructure (trains/roads/canals) for // long-distance routes instead of waystone-spamming. // - Sharestones (16 colors): banned. Pair-teleport between solo-placed // sharestones defeats the "build transport" intent, and a sharestone // placed just outside someone's claim gives an unrestricted teleport- // adjacent vector. // - Portstones (16 colors): banned pending separate design discussion. // - Warp plates: not restricted (single-block teleport pad; revisit if // it becomes a workaround). // - Warp scrolls / warp stones: untouched (consumable / cooldown-bound). // // Per-player count lives in player.persistentData.bnsWaystoneCount. // Decrement on break works because waystones-common.toml has // restrictedWaystones = ["PLAYER"] -- only the owner can break their own // waystone, so breaker == owner in normal play. const WAYSTONE_CAP = 1; const REGULAR_WAYSTONES = new Set([ 'waystones:waystone', 'waystones:mossy_waystone', 'waystones:sandy_waystone', 'waystones:blackstone_waystone', 'waystones:deepslate_waystone', 'waystones:end_stone_waystone', ]); // Build the colored-block ban list once instead of typing 32 strings. const COLORS = [ 'white', 'orange', 'magenta', 'light_blue', 'yellow', 'lime', 'pink', 'gray', 'light_gray', 'cyan', 'purple', 'blue', 'brown', 'green', 'red', 'black', ]; const BANNED_BLOCKS = new Set(); COLORS.forEach(c => { BANNED_BLOCKS.add(`waystones:${c}_sharestone`); BANNED_BLOCKS.add(`waystones:${c}_portstone`); }); // Helper: replace the just-placed block with air and refund the item. function refund(event, blockId) { event.block.set('minecraft:air'); if (event.player) { event.player.give(Item.of(blockId)); } } BlockEvents.placed(event => { const blockId = event.block.id; const player = event.player; // Skip non-player placements (dispensers, mob events) -- nothing to refund. if (!player) return; if (BANNED_BLOCKS.has(blockId)) { refund(event, blockId); player.tell(Text.red( 'That block is disabled. Use a regular Waystone (1 per player) ' + 'and build transport between distant bases.' )); console.info(`[bns/waystones_policy] denied ${blockId} placement by ${player.username} (banned)`); return; } if (REGULAR_WAYSTONES.has(blockId)) { const data = player.persistentData; const current = data.getInt('bnsWaystoneCount'); if (current >= WAYSTONE_CAP) { refund(event, blockId); player.tell(Text.red( `You already have ${WAYSTONE_CAP} waystone. Break your existing one ` + `to relocate, or build infrastructure to reach distant bases.` )); console.info(`[bns/waystones_policy] denied ${blockId} placement by ${player.username} (already at cap ${current})`); return; } data.putInt('bnsWaystoneCount', current + 1); console.info(`[bns/waystones_policy] +1 waystone for ${player.username} (now ${current + 1})`); } }); BlockEvents.broken(event => { const blockId = event.block.id; if (!REGULAR_WAYSTONES.has(blockId)) return; const player = event.player; if (!player) return; // explosion / world clear -- accept count drift, rare const data = player.persistentData; const current = data.getInt('bnsWaystoneCount'); if (current > 0) { data.putInt('bnsWaystoneCount', current - 1); console.info(`[bns/waystones_policy] -1 waystone for ${player.username} (now ${current - 1})`); } });