前言
本实例为Forge1.18.2,此类魔改脚本都应当放在kubejs/server_scripts里。
本人最近才接触JS,会的不多,本实例也是在学习与摸索过程中一点一点搓出来的,特意分享给大家。
正文
起初,只是因为觉得TAC的枪械在加了神化的情况下显得特别弱,于是我想着让枪械伤害也能造成神化的流血效果,在这样的想法驱动下,我给BA光环写了一套效果。
onEvent('entity.hurt', event => {
if (event.source.actual && event.entity.isLiving() && event.source.actual.isPlayer() && event.source.type === 'bullet' && event.source.actual.headArmorItem === 'yuushya:wriggle_nightbug' && event.source.actual.headArmorItem.getNbt()) {
let {entity, source} = event;
let actual = source.actual;
let health = Math.floor(entity.getHealth());
let maxHealth = Math.floor(entity.getMaxHealth());
let cmData = actual.headArmorItem.getNbt().CustomModelData;
if (cmData === 11821901) { // 破甲
let sundering = entity.potionEffects.getActive('apotheosis:sundering');
if (sundering == null) {
event.server.runCommandSilent(`effect give ${entity.id} apotheosis:sundering 15`);
} else {
let sua = sundering.amplifier + 1;
let sud = sundering.duration / 20;
let suTime = Math.round(sud + 1);
let suLevel = Math.min(sua, 250);
event.server.runCommandSilent(`effect give ${entity.id} apotheosis:sundering ${suTime} ${suLevel}`);
}
let strength = actual.potionEffects.getActive('minecraft:strength');
if (strength != null) {
let dx = entity.x - actual.x;
let dy = (entity.y+entity.eyeHeight) - (actual.y+actual.eyeHeight);
let dz = entity.z - actual.z;
let yaw = Math.atan2(dx, dz);
let yawDegrees = -(yaw * (180 / 3.14159)).toFixed(2);
let distance = Math.sqrt(dx * dx + dz * dz);
let pitch = Math.atan2(dy, distance);
let pitchDegrees = -(pitch * (180 / 3.14159)).toFixed(2);
actual.setRotation(yawDegrees,pitchDegrees);
}
}
if (cmData === 11821902) { // 闪电
if (health % 5 === 0 || health % 7 === 0){
event.server.scheduleInTicks(1, () => {
event.server.runCommandSilent(`execute in ${event.level.dimension} run summon minecraft:lightning_bolt ${entity.x} ${entity.y} ${entity.z}`);
entity.attack(event.source, event.damage*1.5);
})
}
}
if (cmData === 11821903) { // 爆炸
event.server.runCommandSilent(`execute in ${event.level.dimension} run summon minecraft:tnt ${entity.x} ${entity.y+1} ${entity.z}`);
}
if (cmData === 11821904) { // 起飞
event.server.runCommandSilent(`effect give ${entity.id} minecraft:levitation 1 100`);
}
if (cmData === 11821905) { // 护盾
let absorption = actual.potionEffects.getActive('minecraft:absorption');
if (absorption == null) {
event.server.runCommandSilent(`effect give ${actual} minecraft:absorption 5`);
event.server.runCommandSilent(`effect give ${actual} minecraft:resistance 5 1`);
} else {
let aba = absorption.amplifier + 1;
let abTime = aba * 5 - 5;
let abLevel = Math.min(aba, 4);
event.server.runCommandSilent(`effect give ${actual} minecraft:absorption ${5 + abTime} ${0 + abLevel}`);
event.server.runCommandSilent(`effect give ${actual} minecraft:resistance ${5 + abTime} 1`);
}
}
if (cmData === 11821906) { // 治疗
if (actual.crouching) {
event.server.runCommandSilent(`execute at ${actual} run effect give @e[type=!item,distance=..5] minecraft:instant_health`);
event.server.scheduleInTicks(1, () => {
for (let i = 0; i < 180; i++) {
let x = actual.x + 5 * Math.cos(i);
let z = actual.z + 5 * Math.sin(i);
let y = actual.y;
event.server.runCommandSilent(`execute in ${event.level.dimension} run particle dust 0 255 0 1 ${x} ${y + 0.1} ${z} 0 0 0 0.01 1`);
}
})
} else {
actual.heal(event.damage/2);
}
}
if (cmData === 11821907) { // 互换
let x1 = actual.x;
let y1 = actual.y;
let z1 = actual.z;
let yaw1 = actual.getYaw();
let pitch1 = actual.getPitch();
let x2 = entity.x;
let y2 = entity.y;
let z2 = entity.z;
let yaw2 = entity.getYaw();
let pitch2 = entity.getPitch();
event.server.runCommandSilent(`effect give ${actual} minecraft:resistance 1 4`)
event.server.runCommandSilent(`effect give ${entity.id} minecraft:resistance 1 4`)
event.server.scheduleInTicks(1, () => {
entity.playSound('minecraft:entity.enderman.teleport')
entity.setPositionAndRotation(x1,y1,z1,yaw1,pitch1)
})
event.server.scheduleInTicks(2, () => {
actual.playSound('minecraft:entity.enderman.teleport')
actual.setPositionAndRotation(x2,y2,z2,yaw2,pitch2)
})
}
if (cmData === 11821908) { // 破伤
let damage = event.damage;
let minDamage = Math.min(damage * 5, health - damage - 1);
if (health >= maxHealth * 0.9) {
event.server.scheduleInTicks(1, () => {
entity.attack(event.source, minDamage);
})
}
}
if (cmData === 11821909) { // 斩杀
if (health <= maxHealth / 3) {
event.server.scheduleInTicks(1, () => {
entity.kill();
})
}
}
if (cmData === 11821910) { // 范围
let entityList = event.level.getEntitiesWithin(AABB.of(
entity.x-3,
entity.y-1,
entity.z-3,
entity.x+3,
entity.y+3,
entity.z+3
))
for (let entities of entityList) {
entities.attack(event.source, event.damage/2);
}
}
if (cmData === 11821911) { // 流血
let bleeding = entity.potionEffects.getActive('apotheosis:bleeding');
if (bleeding == null) {
event.server.runCommandSilent(`effect give ${entity.id} apotheosis:bleeding 15`);
} else {
let bla = bleeding.amplifier + 1;
let bld = bleeding.duration / 20;
let blTime = Math.round(bld + 1);
let blLevel = Math.min(bla, 250);
event.server.runCommandSilent(`effect give ${entity.id} apotheosis:bleeding ${blTime} ${0 + blLevel}`);
}
}
if (cmData === 11821912) { // 赌徒
let random = () => Utils.random.nextInt(6); // 0-5
let randomList = [random(), random()]
event.server.scheduleInTicks(1, () => {
if (randomList[0] === 0) {
if (randomList[1] === 0 || randomList[1] === 2 || randomList[1] === 4) {
entity.attack(event.source, event.damage*19);
} else {
actual.attack(event.source, event.damage*19);
}
}
})
}
if (cmData === 11821913) { // 虚弱
let weakness = entity.potionEffects.getActive('minecraft:weakness');
if (weakness == null) {
event.server.runCommandSilent(`effect give ${entity.id} minecraft:weakness 15`);
} else {
let wea = weakness.amplifier + 1;
let wed = weakness.duration / 20;
let weTime = Math.round(wed + 15);
let weLevel = Math.min(wea, 4);
event.server.runCommandSilent(`effect give ${entity.id} minecraft:weakness ${weTime} ${0 + weLevel}`);
}
}
}
})
讲解
很显然,一下子全发出来肯定有很多人看不懂,所以我接下来会逐一解释,首先如果你想直接跑一遍这串脚本,你至少需要安装KJS,TAC,神化,悠然一派,方块小镇,热力系列。
其中,神化和悠然一派用到了药水效果,方块小镇用到了帽子模型,热力系列用到了核弹,你也许想问,既然是给BA光环写的效果那为啥没有BA光环?那是因为BA光环的获取方法都是硬编码,没法魔改,如果我想修改光环配方只能另想办法,所以!我用到了原版的自定义模型Data,也就是数据包,通过魔改同样可以戴头上的物品模型(也就是方块小镇的帽子模型)实现了光环的复刻 (缺点是动画效果没了,geo模型实在没办法)。
判断伤害来源
在entity.hurt事件中,使用if判断玩家是否具有特殊条件。
if (event.source.actual && event.entity.isLiving() && event.source.actual.isPlayer() && event.source.type === 'bullet' && event.source.actual.headArmorItem === 'yuushya:wriggle_nightbug' && event.source.actual.headArmorItem.getNbt())
event.source.actual 判断伤害源是否有直接伤害源(这条必须加,不然会报错),比如骷髅射箭击中玩家,伤害源为箭,直接伤害源为骷髅。
event.entity.isLiving() 判断受伤实体是否为活物。
event.source.actual.isPlayer() 判断直接伤害源是否是玩家。
event.source.type === 'bullet' 判断伤害源的类型是否为'bullet'(也就是子弹伤害)。
event.source.actual.headArmorItem === 'yuushya:wriggle_nightbug' 判断直接伤害源的头盔是否绝对等于'yuushya:wriggle_nightbug' 。
event.source.actual.headArmorItem.getNbt() 判断直接伤害源的头盔是否有NBT(这条也是必须加,不然就报错)。
定义
后面会重复使用的一些函数,可以提前定义常用函数以简化写法。
let { entity, source } = event;
let actual = source.actual;
let health = Math.floor(entity.getHealth());
let maxHealth = Math.floor(entity.getMaxHealth());
let cmData = actual.headArmorItem.getNbt().CustomModelData;
这些都比较通俗易懂,其中CustomModelData是一个自定义的模型ID,具体如何使用请看CustomModelData。
在这里我一共做了15个自定义模型,ID分别是11821901 - 11821915,不同ID对应了不同的物品模型。
if (cmData === 11821901)
以第一个举例,如果检测到物品NBT里的CustomModelData一栏绝对等于这个数,那么则为true。
获取实体药水效果
let sundering = entity.potionEffects.getActive('apotheosis:sundering'); // 判断受伤实体身上的药水效果是否为'apotheosis:sundering'(破甲)。
if (sundering == null) { // 如果受伤实体身上没有破甲效果。
event.server.runCommandSilent(`effect give ${entity.id} apotheosis:sundering 15`); // 给受伤实体一个流血15秒的效果。
} else { // 如果已经有破甲效果了。
let sua = sundering.amplifier + 1; // 获取效果等级+1。
let sud = sundering.duration / 20; // 获取效果时长(药水时长为tick值,游戏tick为每秒20,所以这里要除20)。
let suTime = Math.round(sud + 1); // 延长1秒的效果时长。
let suLevel = Math.min(sua, 250); // 设定一个最大值,不能超过250级。
event.server.runCommandSilent(`effect give ${entity.id} apotheosis:sundering ${suTime} ${suLevel}`); // 受伤实体的流血效果延长1秒并且增加1级。
}
锁头效果
let strength = actual.potionEffects.getActive('minecraft:strength'); // 检测直接伤害源身上的药水效果是否为'minecraft:strength'(力量)。
if (strength != null) { // 如果直接伤害源拥有力量效果。
let dx = entity.x - actual.x; // 获取受伤实体与直接伤害源的X差值。
let dy = (entity.y+entity.eyeHeight) - (actual.y+actual.eyeHeight); // 获取受伤实体与直接伤害源的视线高度差值。
let dz = entity.z - actual.z; // 获取受伤实体与直接伤害源的Z差值。
// 计算yaw值
let yaw = Math.atan2(dx, dz);
let yawDegrees = -(yaw * (180 / 3.14159)).toFixed(2);
// 计算pitch值
let distance = Math.sqrt(dx * dx + dz * dz);
let pitch = Math.atan2(dy, distance);
let pitchDegrees = -(pitch * (180 / 3.14159)).toFixed(2);
actual.setRotation(yawDegrees,pitchDegrees); // 设置直接伤害源的视线值(yaw值和pitch值)。
}
假随机效果
if (health % 5 === 0 || health % 7 === 0){ // 检测受伤实体的血量处于5或7是否没有余数,如果没有余数则为true。
event.server.scheduleInTicks(1, () => { // 延迟1tick执行。
event.server.runCommandSilent(`execute in ${event.level.dimension} run summon minecraft:lightning_bolt ${entity.x} ${entity.y} ${entity.z}`); // 在实体坐标中心生成闪电。
entity.attack(event.source, event.damage*1.5); // 给予受伤实体额外的1.5倍伤害,并且伤害的类型为伤害源。
})
}
画圆
if (actual.crouching) { // 检测直接伤害源是否为蹲下状态
event.server.runCommandSilent(`execute at ${actual} run effect give @e[type=!item,distance=..5] minecraft:instant_health`); // 半径5格內的所有除物品以外的实体获得瞬间治疗效果。
event.server.scheduleInTicks(1, () => { // 延迟1tick执行。
for (let i = 0; i < 180; i++) {
// 用180个粒子效果绘制一个半径为5格的圆形。
let x = actual.x + 5 * Math.cos(i);
let z = actual.z + 5 * Math.sin(i);
let y = actual.y;
event.server.runCommandSilent(`execute in ${event.level.dimension} run particle dust 0 255 0 1 ${x} ${y + 0.1} ${z} 0 0 0 0.01 1`);
}
})
} else { // 如果不是蹲下的。
actual.heal(event.damage/2); // 获取伤害的一半并用于治疗直接伤害源。
}
位置互换
//定义直接伤害源的x,y,z值和yaw,pitch值。
let x1 = actual.x;
let y1 = actual.y;
let z1 = actual.z;
let yaw1 = actual.getYaw();
let pitch1 = actual.getPitch();
//定义受伤实体的x,y,z值和yaw,pitch值。
let x2 = entity.x;
let y2 = entity.y;
let z2 = entity.z;
let yaw2 = entity.getYaw();
let pitch2 = entity.getPitch();
//给予直接伤害源和受伤实体1秒的抗性提升5(100%免伤)。
event.server.runCommandSilent(`effect give ${actual} minecraft:resistance 1 4`)
event.server.runCommandSilent(`effect give ${entity.id} minecraft:resistance 1 4`)
// 受伤实体延迟1tick传送到直接伤害源的位置,并且发出末影人传送的声音。
event.server.scheduleInTicks(1, () => {
entity.playSound('minecraft:entity.enderman.teleport')
entity.setPositionAndRotation(x1,y1,z1,yaw1,pitch1)
})
// 直接伤害源延迟2tick传送到受伤实体的位置,并且发出末影人传送的声音。
event.server.scheduleInTicks(2, () => {
actual.playSound('minecraft:entity.enderman.teleport')
actual.setPositionAndRotation(x2,y2,z2,yaw2,pitch2)
})
范围伤害
let entityList = event.level.getEntitiesWithin(AABB.of( // 检测一个范围內的所有实体。
entity.x-3,
entity.y-1,
entity.z-3,
entity.x+3,
entity.y+3,
entity.z+3
))
for (let entities of entityList) { // 遍历所有实体。
entities.attack(event.source, event.damage/2); // 额外造成伤害的一半,并且伤害类型为伤害源。
}
俄罗斯转盘
let random = () => Utils.random.nextInt(6); // 定义一个0-5之间的随机数(就是随机6个数)。
let randomList = [random(), random()] // 随机两次
event.server.scheduleInTicks(1, () => {
if (randomList[0] === 0) { // 如果第一个随机数绝对等于0(理论上六分之一概率)。
if (randomList[1] === 0 || randomList[1] === 2 || randomList[1] === 4) { // 如果第二个随机数绝对等于0,2或4(理论上二分之一概率)。
entity.attack(event.source, event.damage*19); // 给受伤实体额外造成19倍伤害,并且伤害类型为伤害源。
} else { // 如果第二个随机数不是0,2或4。
actual.attack(event.source, event.damage*19); // 给直接伤害源额外造成19倍伤害,并且伤害类型为伤害源。
}
}
})
DLC
这里就不是entity.hurt事件了,而且其他一些有意思的小功能。
吐籽
onEvent('item.food_eaten', event => { // 食物食用事件
// 检测玩家是否头戴有特殊NBT的物品。
if (event.player && event.player.headArmorItem === 'yuushya:wriggle_nightbug' && event.player.headArmorItem.getNbt() && event.entity.headArmorItem.getNbt().CustomModelData === 11821914) {
let spitting = event.player.potionEffects.getActive('atmospheric:spitting'); // 检测玩家是否有吐籽效果。
if (spitting == null) { // 如果没有吐籽效果。
event.server.runCommandSilent(`effect give ${event.player} atmospheric:spitting 5`); // 给予玩家5秒吐籽效果。
} else { // 如果已经有吐籽效果了。
let spa = spitting.amplifier + 1; // 获取效果等级+1。
let spd = spitting.duration / 20; // 获取效果时长除以20。
let spTime = Math.round(spd + 2); // 效果时长+2秒。
let spLevel = Math.min(spa, 250); // 效果等级最大不超过250级。
event.server.runCommandSilent(`effect give ${event.player} atmospheric:spitting ${spTime} ${0 + spLevel}`); // 玩家的吐籽效果延长2秒并且增加1级。
}
}
})
虚空湮灭
onEvent('entity.death', event => { // 实体死亡事件
// 检测实体是否为玩家,并且玩家是否头戴有特殊NBT的物品。
if (event.entity.isPlayer() && event.entity.headArmorItem === 'yuushya:wriggle_nightbug' && event.entity.headArmorItem.getNbt() && event.entity.headArmorItem.getNbt().CustomModelData === 11821915) {
event.entity.headArmorItem.count-=1; // 移除当前头戴的物品。
event.server.runCommandSilent(`execute at ${event.entity} run kill @e[type=!item,distance=..18]`); // kill掉半径18格內所有除物品以外的实体。
event.server.scheduleInTicks(1, () => {
event.server.runCommandSilent(`execute in ${event.level.dimension} run summon thermal:nuke_tnt ${event.entity.x} ${event.entity.y} ${event.entity.z}`); // 延迟1tick生成一颗核弹。
})
}
})