自己写整合包用过的一些脚本,都是非常简单的小玩意儿,想着多少有那么点价值就发出来,先发个TAC相关的。


onForgeEvent("com.tac.guns.event.GunProjectileHitEvent", event => {
    //使用global将函数全局化,方便游戏中热更新
    global.BulletHit(event)
})
//
global.BulletHit = event => {
    //获取弹头实体,个人习惯把未通过asKJS()方法转化为JS对象的东西命名为xyzRaw
    let bulletRaw = event.getProjectile()
    //KubeJs 自带的asKJS()方法,将前面的bulletRaw转化为EntityJS对象
    let bullet = bulletRaw.asKJS()
    //获取弹头当前正对的目标,即MC的rayTraceResult对象
    let ray = event.getRayTrace()
    //1.16.5 MinecraftForge原版方法和部分域被混淆,需要使用SRG名,func_12345678这种;1.18.2就用不着这个了
    let rayType = ray.func_216346_c().toString()//getType() //{MISS, BLOCK, ENTITY}
    if(//判断目标类型是方块
        rayType == 'BLOCK'
    //这个判断式的意义是限制子弹在自身有效射程的前半段才有破坏方块的能力,看你需不需要这个判断了
        && bullet.ticksExisted * 2 <= bulletRaw.life){
        //实际上到这里就结束了,后面都是仅做参考的个性化内容,不适用于任何整合包,要是实在一点都不会写的话可以看看(
        //获取方块坐标,其实就是个整形数组
        let bPos = ray.func_216350_a()//getBlockPos()
        let resultBlock
        let shooterRaw
        let worldRaw
        try{
            //获取射出该子弹的玩家,tac自己提供的方法
            shooterRaw = bulletRaw.getShooter()
            //获取所在的世界(维度);
            //因为这个事件本身是获取不到世界的,所以从前面一句获取的玩家身上调用;
            //当然这会导致一个小问题,如果玩家和弹头刚好不在同一个维度的话就会获取错误的方块。嘛无所谓啦(
            worldRaw = shooterRaw.field_70170_p//level
            //获取方块,不过这里获取的是KubeJS提供的BlockContainerJS对象,而不是原版的BlockState
            resultBlock = shooterRaw.asKJS().world.getBlock(bPos)
        }catch(error){
            console.warn(error.message)
        }finally{
            //一些数据可以直接从弹头实体的NBT里面读
            let bulletNBT = bullet.fullNBT
            //KubeJS为所有实体注册了一个用于标记等功能的NBT标签,对EntityJS对象读persistentData即可获取
            let bulletKJSData = bullet.persistentData
            //Pierce是0.3.14的新特性,让弹头可以像原版的穿透箭支一样贯穿多个实体
            let bPierce = bulletNBT.Projectile.Pierce
            if(shooterRaw && resultBlock
                    //persistentData的属性自己DIY就好,如果是新的没赋值过的属性,那它当前必定是undefined值,于是下面的或判断左侧的句子必定是成立的
                    && (!bulletKJSData.blockPierced || bulletKJSData.blockPierced < bPierce)
                    //我个人只打算判断个别种类的方块,利用MC原版的标签功能来标记这些方块,不在此列的方块一律不可击穿
                    //前面获取方块时选择获取BlockContainerJS就是为了读方块标签方便点
                    //说起方块标签,tac自己提供了一个"tac:bullet_ignore"标签,弹头从逻辑上是不会命中有这个标签的方块的,所以该脚本只能用于没有"tac:bullet_ingore"标签的方块……这时候说这个是不是有点晚?(
                    && resultBlock.hasTag('tac:bullet_may_destroy')
                    //还有一件事,tac自己会判断并破坏材质为"glass"的方块,所以该脚本对于玻璃类方块也是没意义的
                    // && resultBlock.getMaterial().getId() != 'glass'
                ){
                    //获取原版方块
                    blockState = worldRaw.func_180495_p(bPos)//getBlockState(BlockPos)
                    //下面这个式子建议把我的注释都删掉,调整一下格式再看(
                    let resistance = Math.min(Math.pow(
                        //获取方块硬度
                        blockState.func_185887_b(worldRaw, bPos)//getDestroySpeed(world, blockPos)
                        //"rock"材质的方块硬度从数值上来说都是偏低的(不要提黑曜石),所以给个额外倍率
                         * (resultBlock.material.id == 'rock'? 4:2)//getMaterial
                         , 2), 320)
                    //这个数据可以表示该子弹是否为复数弹丸,比如霰弹
                    //你也可以找些别的数据,比如弹头当前的速度之类
                    let projAmount = bulletNBT.General.ProjectileAmount
                    //弹头已在世界(服务器端)存在的时间,也就是出膛后经历的时长
                    let bulletLife = bullet.ticksExisted
                    //同样的,下面这个式子删掉注释再看
                    let bDMG =
                    //弹头如果在水里,破坏力降低。这里只影响了固定加算部分,本质上是我用来限制低威力的9mm弹的
                     (bullet.inWater? 1:15)
                      + (
                        //判断一下弹丸数,给刚出膛的霰弹一点破坏力buff
                        projAmount > 2?
                        //tac自带的方法,读到的数据会包含枪械的额外伤害加成(通常由配件提供)、复数弹丸的伤害分摊和子弹飞行途中的伤害衰减
                        //如果你想用子弹的初始威力作为变量,弹头实体的NBT里面有Projectile.Damage
                        bulletRaw.getDamage()
                         * (
                            //判断出膛时长
                            bulletLife > 1? (bulletLife > 4? 1:2):7)
                             : bulletRaw.getDamage())
                    //如果玩的人比较多就不要在这里消耗性能生成随机数了,没意义,这个事件的发生频率还是挺高的。我是单人游玩所以无所谓。
                    let RNG = Math.random()
                    //最终的判断,成立了就执行方块的破坏
                    if(bDMG * bPierce * RNG + 4 > resistance){
                        //如果你想看到“一枪只崩掉门的上半边”之类的景象的话,这个函数的最后一个值写0。反正不要写什么很大的值。
                        worldRaw.func_241212_a_(bPos, true, shooterRaw, 2)//destroyBlock(BlockPos pos, boolean dropBlock, Entity entity, int recursionLeft)
                        //这里是前面用到的那个自定义persistentData属性;
                        //所以这里给弹头实体加了个标记,经测试可以有效阻止同一个弹头反逻辑地间隔式破坏多个方块的现象发生……至少单人游戏是这样的(
                        if(typeof(bulletKJSData.blockPierced) == 'number'){
                            bulletKJSData.blockPierced ++
                        }else{bulletKJSData.blockPierced = 1}
                    }
            }
        }
    }else if(rayType == 'ENTITY'){//无关代码
        let shotRaw = ray.func_216348_a()//getEntity()
        let shot = shotRaw.asKJS()
        try{
            if(shot.type == 'iceandfire:fire_dragon' && shot.fullNBT.AgeTicks >= 1800000 || shot.type == 'iceandfire:dragon_multipart' && shotRaw.parent.dragonType.toString() == 'FIRE' && shotRaw.getAgeInTicks() >= 1800000){
                    let projNBT = bullet.fullNBT.Projectile
                    let potion = shot.potionEffects
                    let hiTempFactor = Math.min(0.2 * Math.min(shot.maxHealth / shot.health, 2.0) * potion.isActive('lesraisinsadd:deep_poison')? 1.8:1.0 * potion.isActive('lesraisinsadd:virus')? 1.5:1.0 + potion.isActive('mowziesmobs:frozen')? 0.25:0, 1.0)
                    // bullet.mergeFullNBT(`{Projectile:{Pierce:1,ArmorIgnore:${hiTempFactor * projNBT.ArmorIgnore}}}`)
                    bullet.getProjectile.deserializeNBT(`ArmorIgnore:${hiTempFactor * projNBT.ArmorIgnor},CriticalDamage:0.5`)
            }
        }catch(error){console.warn(error.message)}
    }
}