Sometimes you might not want to change the gamerule but still want a special explosion that spares blocks.
const getAABBofRadius = (centerX, centerY, centerZ, radius) => {
const [minX, minY, minZ, maxX, maxY, maxZ] = [-1, 1].map(c => [centerX, centerY, centerZ].map(n => n + radius * c)).reduce((a, b) => a.concat(b))
const aabb = AABB.of(minX, minY, minZ, maxX, maxY, maxZ)
return aabb
}
/**
*
* @param {Internal.Level_} level
* @param {number} x
* @param {number} y
* @param {number} z
* @param {number} power
* @param {Internal.Entity_} exploder
* @param {boolean} spareExploder
*/
function createPseudoExplosion(level, x ,y, z, power, exploder, spareExploder){
const aabb = getAABBofRadius(x, y, z, power * 2)
const explosionCenter = new Vec3d(x, y, z)
const marker = level.createEntity("marker")
marker.spawn()
const explosionDamageSource = marker.damageSources().explosion(marker, exploder)
level.spawnParticles("minecraft:explosion", false, x, y, z, 0, 0, 0, Math.floor(power/3), 1)
level.runCommandSilent(`playsound minecraft:entity.generic.explode master @a ${x} ${y} ${z} 1 1`)
level.getEntitiesWithin(aabb).forEach(entity => {
if(spareExploder && entity.equals(exploder)) return;
const entityPosisition = entity.position()
const distance = explosionCenter.distanceTo(entityPosisition)
const normalizedVec = entityPosisition.subtract(explosionCenter).normalize()
const exposure =
Array.from(Array(6).keys())
.map(n => explosionCenter.add(normalizedVec.scale(n + 1)))
.map(vec => level.getBlock(vec.x(), vec.y(), vec.z()).blockState.air)
.map(b => b ? 1 : 0)
.reduce((a, b) => a + b) / 6
const maxBlastProt = entity.living
? entity.armorSlots.map(item => item.getEnchantmentLevel("blast_protection")).reduce((a, b) => Math.max(a, b))
: 0
console.log(maxBlastProt)
const impact = (1 - distance / (2 * power)) * exposure * (1 - 0.15 * maxBlastProt)
const damageAmount = impact * (impact + 1) * power * 7 + 1
entity.attack(
explosionDamageSource,
damageAmount
)
if(entity.alive){
let velocity = normalizedVec.scale(exposure)
entity.setMotion(
entity.getMotionX() + velocity.x(),
entity.getMotionY() + velocity.y(),
entity.getMotionZ() + velocity.z()
)
}
})
marker.remove("discarded")
}
ItemEvents.rightClicked("stick", event=>{
let {level, player, player:{x, y, z}} = event
createPseudoExplosion(level, x, y, z, 3, player, true)
})