From fefc2303aa5ebc3622389dae32af39ca1262f23a Mon Sep 17 00:00:00 2001 From: Atsuishio <842960157@qq.com> Date: Sun, 13 Apr 2025 01:02:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=BD=A6=E8=BD=BD=E7=83=9F?= =?UTF-8?q?=E9=9B=BE=E8=AF=B1=E9=A5=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/overlay/VehicleHudOverlay.java | 8 ++ .../client/particle/CustomCloudParticle.java | 8 +- .../client/particle/CustomSmokeParticle.java | 68 +++++++++++++++ .../entity/SmokeDecoyEntityRenderer.java | 27 ++++++ .../entity/projectile/DecoyEntity.java | 9 ++ .../entity/projectile/FlareDecoyEntity.java | 12 ++- .../projectile/JavelinMissileEntity.java | 6 +- .../entity/projectile/SmokeDecoyEntity.java | 72 ++++++++++++++++ .../entity/projectile/WgMissileEntity.java | 2 +- .../entity/vehicle/Ah6Entity.java | 35 +------- .../entity/vehicle/Bmp2Entity.java | 7 ++ .../entity/vehicle/DroneEntity.java | 2 +- .../entity/vehicle/Lav150Entity.java | 7 ++ .../entity/vehicle/PrismTankEntity.java | 7 ++ .../entity/vehicle/Yx100Entity.java | 7 ++ .../vehicle/base/MobileVehicleEntity.java | 79 ++++++++++++++++-- .../superbwarfare/init/ModEntities.java | 4 +- .../init/ModEntityRenderers.java | 1 + .../superbwarfare/init/ModParticleTypes.java | 1 + .../superbwarfare/init/ModParticles.java | 2 + .../superbwarfare/init/ModSounds.java | 1 + .../item/gun/launcher/JavelinItem.java | 12 +-- .../message/send/TacticalSprintMessage.java | 2 +- .../superbwarfare/tools/ParticleTool.java | 1 + .../superbwarfare/tools/TraceTool.java | 3 +- .../assets/superbwarfare/lang/en_us.json | 1 + .../assets/superbwarfare/lang/zh_cn.json | 1 + .../superbwarfare/particles/custom_smoke.json | 12 +++ .../assets/superbwarfare/sounds.json | 8 ++ .../superbwarfare/sounds/smoke_fire.ogg | Bin 0 -> 23708 bytes 30 files changed, 342 insertions(+), 63 deletions(-) create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/particle/CustomSmokeParticle.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SmokeDecoyEntityRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/DecoyEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmokeDecoyEntity.java create mode 100644 src/main/resources/assets/superbwarfare/particles/custom_smoke.json create mode 100644 src/main/resources/assets/superbwarfare/sounds/smoke_fire.ogg diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java index 6fc1fcf38..4d8b7cd24 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java @@ -47,6 +47,7 @@ import java.util.concurrent.atomic.AtomicReference; import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; import static com.atsuishio.superbwarfare.client.overlay.CrossHairOverlay.*; +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.DECOY_COUNT; @OnlyIn(Dist.CLIENT) public class VehicleHudOverlay implements LayeredDraw.Layer { @@ -233,6 +234,9 @@ public class VehicleHudOverlay implements LayeredDraw.Layer { double heal = mobileVehicle.getHealth() / mobileVehicle.getMaxHealth(); guiGraphics.drawString(Minecraft.getInstance().font, Component.literal(FormatTool.format0D(100 * heal)), w / 2 - 165, h / 2 - 46, Mth.hsvToRgb((float) heal / 3.745318352059925F, 1.0F, 1.0F), false); + // 诱饵 + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("SMOKE " + mobileVehicle.getEntityData().get(DECOY_COUNT)), w / 2 - 165, h / 2 - 36, 0x66FF00, false); + renderKillIndicator(guiGraphics, w, h); } else if (Minecraft.getInstance().options.getCameraType() == CameraType.THIRD_PERSON_BACK && !ClientEventHandler.zoomVehicle) { Vec3 p = RenderHelper.worldToScreen(new Vec3(Mth.lerp(deltaTracker.getGameTimeDeltaPartialTick(true), player.xo, player.getX()), Mth.lerp(deltaTracker.getGameTimeDeltaPartialTick(true), player.yo + player.getEyeHeight(), player.getEyeY()), Mth.lerp(deltaTracker.getGameTimeDeltaPartialTick(true), player.zo, player.getZ())).add(iLand.getBarrelVec(deltaTracker.getGameTimeDeltaPartialTick(true)).scale(192)), cameraPos); @@ -258,6 +262,10 @@ public class VehicleHudOverlay implements LayeredDraw.Layer { guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("HP " + FormatTool.format0D(100 * mobileVehicle.getHealth() / mobileVehicle.getMaxHealth())), 30, 1, Mth.hsvToRgb(0F, (float) health, 1.0F), false); + if (mobileVehicle.hasDecoy()) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("SMOKE " + mobileVehicle.getEntityData().get(DECOY_COUNT)), 30, 11, -1, false); + } + poseStack.popPose(); poseStack.popPose(); } diff --git a/src/main/java/com/atsuishio/superbwarfare/client/particle/CustomCloudParticle.java b/src/main/java/com/atsuishio/superbwarfare/client/particle/CustomCloudParticle.java index 79830dc87..d9aed434f 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/particle/CustomCloudParticle.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/particle/CustomCloudParticle.java @@ -9,14 +9,14 @@ import org.jetbrains.annotations.NotNull; @OnlyIn(Dist.CLIENT) public class CustomCloudParticle extends TextureSheetParticle { - public static FireStarParticleProvider provider(SpriteSet spriteSet) { - return new FireStarParticleProvider(spriteSet); + public static CustomCloudParticleProvider provider(SpriteSet spriteSet) { + return new CustomCloudParticleProvider(spriteSet); } - public static class FireStarParticleProvider implements ParticleProvider { + public static class CustomCloudParticleProvider implements ParticleProvider { private final SpriteSet spriteSet; - public FireStarParticleProvider(SpriteSet spriteSet) { + public CustomCloudParticleProvider(SpriteSet spriteSet) { this.spriteSet = spriteSet; } diff --git a/src/main/java/com/atsuishio/superbwarfare/client/particle/CustomSmokeParticle.java b/src/main/java/com/atsuishio/superbwarfare/client/particle/CustomSmokeParticle.java new file mode 100644 index 000000000..1e548fdfc --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/particle/CustomSmokeParticle.java @@ -0,0 +1,68 @@ +package com.atsuishio.superbwarfare.client.particle; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.*; +import net.minecraft.core.particles.SimpleParticleType; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import org.jetbrains.annotations.NotNull; + +@OnlyIn(Dist.CLIENT) +public class CustomSmokeParticle extends TextureSheetParticle { + public static FireStarParticleProvider provider(SpriteSet spriteSet) { + return new FireStarParticleProvider(spriteSet); + } + + public static class FireStarParticleProvider implements ParticleProvider { + private final SpriteSet spriteSet; + + public FireStarParticleProvider(SpriteSet spriteSet) { + this.spriteSet = spriteSet; + } + + public Particle createParticle(@NotNull SimpleParticleType typeIn, @NotNull ClientLevel worldIn, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) { + return new CustomSmokeParticle(worldIn, x, y, z, xSpeed, ySpeed, zSpeed, this.spriteSet); + } + } + + private final SpriteSet spriteSet; + + protected CustomSmokeParticle(ClientLevel world, double x, double y, double z, double vx, double vy, double vz, SpriteSet spriteSet) { + super(world, x, y, z); + this.spriteSet = spriteSet; + this.setSize(0.4f, 0.4f); + this.quadSize *= 10f; + this.lifetime = this.random.nextInt(200) + 600; + this.gravity = 0.001f; + this.hasPhysics = false; + this.xd = vx * 0.9; + this.yd = vy * 0.9; + this.zd = vz * 0.9; + this.setSpriteFromAge(spriteSet); + } + + @Override + public int getLightColor(float partialTick) { + return 15728880; + } + + @Override + public @NotNull ParticleRenderType getRenderType() { + return ParticleRenderType.PARTICLE_SHEET_TRANSLUCENT; + } + + @Override + public void tick() { + super.tick(); + if (!this.removed) { + this.setSprite(this.spriteSet.get(Math.min((this.age / 8) + 1, 8), 8)); + } + if (this.age++ < this.lifetime && !(this.alpha <= 0.0F)) { + if (this.age >= this.lifetime - 60 && this.alpha > 0.01F) { + this.alpha -= 0.015F; + } + } else { + this.remove(); + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SmokeDecoyEntityRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SmokeDecoyEntityRenderer.java new file mode 100644 index 000000000..d166c848e --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SmokeDecoyEntityRenderer.java @@ -0,0 +1,27 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.entity.projectile.SmokeDecoyEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; + +public class SmokeDecoyEntityRenderer extends EntityRenderer { + public SmokeDecoyEntityRenderer(EntityRendererProvider.Context pContext) { + super(pContext); + } + + @ParametersAreNonnullByDefault + public void render(SmokeDecoyEntity pEntity, float pEntityYaw, float pPartialTicks, PoseStack pMatrixStack, MultiBufferSource pBuffer, int pPackedLight) { + super.render(pEntity, pEntityYaw, pPartialTicks, pMatrixStack, pBuffer, pPackedLight); + } + + @Override + public ResourceLocation getTextureLocation(@NotNull SmokeDecoyEntity flareDecoy) { + return null; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/DecoyEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/DecoyEntity.java new file mode 100644 index 000000000..0c0a76d6e --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/DecoyEntity.java @@ -0,0 +1,9 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import net.minecraft.world.phys.Vec3; + +public interface DecoyEntity { + String getStringUUID(); + + Vec3 getPosition(); +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FlareDecoyEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FlareDecoyEntity.java index 386ea368a..09ea28cbf 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FlareDecoyEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FlareDecoyEntity.java @@ -9,19 +9,18 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.MoverType; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; -public class FlareDecoyEntity extends Entity { +public class FlareDecoyEntity extends Entity implements DecoyEntity { public FlareDecoyEntity(EntityType type, Level world) { super(type, world); } - public FlareDecoyEntity(LivingEntity entity, Level level) { + public FlareDecoyEntity(Level level) { super(ModEntities.FLARE_DECOY.get(), level); } @@ -54,7 +53,7 @@ public class FlareDecoyEntity extends Entity { } public void decoyShoot(Entity entity, Vec3 shootVec, float pVelocity, float pInaccuracy) { - Vec3 vec3 = shootVec.normalize().add(this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy), this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy), this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy)).scale((double) pVelocity); + Vec3 vec3 = shootVec.normalize().add(this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy), this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy), this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy)).scale(pVelocity); this.setDeltaMovement(entity.getDeltaMovement().scale(0.75).add(vec3)); double d0 = vec3.horizontalDistance(); this.setYRot((float) (Mth.atan2(vec3.x, vec3.z) * 57.2957763671875)); @@ -62,4 +61,9 @@ public class FlareDecoyEntity extends Entity { this.yRotO = this.getYRot(); this.xRotO = this.getXRot(); } + + @Override + public Vec3 getPosition() { + return position(); + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java index 3c7584c7a..993ea83be 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java @@ -215,11 +215,11 @@ public class JavelinMissileEntity extends FastThrowableProjectile implements Geo public void tick() { super.tick(); Entity entity = EntityFindUtil.findEntity(this.level(), entityData.get(TARGET_UUID)); - List decoy = SeekTool.seekLivingEntities(this, this.level(), 48, 160); + List decoy = SeekTool.seekLivingEntities(this, this.level(), 32, 90); for (var e : decoy) { - if (e instanceof FlareDecoyEntity flareDecoy && !distracted) { - this.entityData.set(TARGET_UUID, flareDecoy.getStringUUID()); + if (e instanceof DecoyEntity decoyEntity && !distracted) { + this.entityData.set(TARGET_UUID, decoyEntity.getStringUUID()); distracted = true; } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmokeDecoyEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmokeDecoyEntity.java new file mode 100644 index 000000000..d29e10817 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmokeDecoyEntity.java @@ -0,0 +1,72 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModParticleTypes; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; + +public class SmokeDecoyEntity extends Entity implements DecoyEntity { + + public SmokeDecoyEntity(EntityType type, Level world) { + super(type, world); + } + + public SmokeDecoyEntity(Level level) { + super(ModEntities.SMOKE_DECOY.get(), level); + } + + @Override + protected void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { + } + + @Override + protected void addAdditionalSaveData(@NotNull CompoundTag compoundTag) { + } + + @Override + protected void defineSynchedData(SynchedEntityData.@NotNull Builder builder) { + } + + @Override + public void tick() { + super.tick(); + this.move(MoverType.SELF, this.getDeltaMovement()); + if (tickCount == 4) { + if (this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ModParticleTypes.CUSTOM_SMOKE.get(), this.xo, this.yo, this.zo, + 100, 0, 0, 0, 0.07, true); + } + this.level().playSound(null, this, ModSounds.SMOKE_FIRE.get(), this.getSoundSource(), 1, random.nextFloat() * 0.05f + 1); + this.setDeltaMovement(Vec3.ZERO); + } + + if (this.tickCount > 400) { + this.discard(); + } + } + + public void decoyShoot(Entity entity, Vec3 shootVec, float pVelocity, float pInaccuracy) { + Vec3 vec3 = shootVec.normalize().add(this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy), this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy), this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy)).scale((double) pVelocity); + this.setDeltaMovement(entity.getDeltaMovement().scale(0.75).add(vec3)); + double d0 = vec3.horizontalDistance(); + this.setYRot((float) (Mth.atan2(vec3.x, vec3.z) * 57.2957763671875)); + this.setXRot((float) (Mth.atan2(vec3.y, d0) * 57.2957763671875)); + this.yRotO = this.getYRot(); + this.xRotO = this.getXRot(); + } + + @Override + public Vec3 getPosition() { + return position(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java index 011e3df61..0bce267a7 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java @@ -178,7 +178,7 @@ public class WgMissileEntity extends FastThrowableProjectile implements GeoEntit Entity lookingEntity = TraceTool.vehiclefFindLookingEntity(vehicle, vehicle.getNewEyePos(1), 512); Vec3 toVec; - if (lookingEntity != null) { + if (lookingEntity != null && lookingEntity != this) { toVec = this.position().vectorTo(lookingEntity.getEyePosition()).normalize(); } else { BlockHitResult result = level().clip(new ClipContext(vehicle.getNewEyePos(1), vehicle.getNewEyePos(1).add(lookVec.scale(512)), diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java index cad95e535..392d760d7 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java @@ -67,13 +67,11 @@ public class Ah6Entity extends ContainerMobileVehicleEntity implements GeoEntity private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); public static final EntityDataAccessor PROPELLER_ROT = SynchedEntityData.defineId(Ah6Entity.class, EntityDataSerializers.FLOAT); - public static final EntityDataAccessor DECOY_COUNT = SynchedEntityData.defineId(Ah6Entity.class, EntityDataSerializers.INT); public static final EntityDataAccessor LOADED_ROCKET = SynchedEntityData.defineId(Ah6Entity.class, EntityDataSerializers.INT); public boolean engineStart; public boolean engineStartOver; public double velocity; - public int decoyReloadCoolDown; public int fireIndex; public int holdTick; public int holdPowerTick; @@ -117,8 +115,7 @@ public class Ah6Entity extends ContainerMobileVehicleEntity implements GeoEntity protected void defineSynchedData(SynchedEntityData.Builder builder) { super.defineSynchedData(builder); builder.define(LOADED_ROCKET, 0) - .define(PROPELLER_ROT, 0f) - .define(DECOY_COUNT, 3); + .define(PROPELLER_ROT, 0f); } @Override @@ -126,7 +123,6 @@ public class Ah6Entity extends ContainerMobileVehicleEntity implements GeoEntity super.addAdditionalSaveData(compound); compound.putInt("LoadedRocket", this.entityData.get(LOADED_ROCKET)); compound.putFloat("PropellerRot", this.entityData.get(PROPELLER_ROT)); - compound.putInt("DecoyCount", this.entityData.get(DECOY_COUNT)); } @Override @@ -134,7 +130,6 @@ public class Ah6Entity extends ContainerMobileVehicleEntity implements GeoEntity super.readAdditionalSaveData(compound); this.entityData.set(LOADED_ROCKET, compound.getInt("LoadedRocket")); this.entityData.set(PROPELLER_ROT, compound.getFloat("PropellerRot")); - this.entityData.set(DECOY_COUNT, compound.getInt("DecoyCount")); } @Override @@ -189,9 +184,6 @@ public class Ah6Entity extends ContainerMobileVehicleEntity implements GeoEntity if (reloadCoolDown > 0) { reloadCoolDown--; } - if (decoyReloadCoolDown > 0) { - decoyReloadCoolDown--; - } handleAmmo(); } @@ -242,31 +234,6 @@ public class Ah6Entity extends ContainerMobileVehicleEntity implements GeoEntity } } - public void releaseDecoy() { - if (decoyInputDown) { - if (this.entityData.get(DECOY_COUNT) > 0 && this.level() instanceof ServerLevel) { - Entity passenger = getFirstPassenger(); - for (int i = 0; i < 4; i++) { - FlareDecoyEntity flareDecoyEntity = new FlareDecoyEntity((LivingEntity) passenger, this.level()); - flareDecoyEntity.setPos(this.getX() + this.getDeltaMovement().x, this.getY() + 0.5 + this.getDeltaMovement().y, this.getZ() + this.getDeltaMovement().z); - flareDecoyEntity.decoyShoot(this, this.getViewVector(1).yRot((45 + 90 * i) * Mth.DEG_TO_RAD), 0.8f, 8); - this.level().addFreshEntity(flareDecoyEntity); - } - this.level().playSound(null, this, ModSounds.DECOY_FIRE.get(), this.getSoundSource(), 1, 1); - if (this.getEntityData().get(DECOY_COUNT) == 3) { - decoyReloadCoolDown = 300; - } - this.getEntityData().set(DECOY_COUNT, this.getEntityData().get(DECOY_COUNT) - 1); - } - decoyInputDown = false; - } - if (this.entityData.get(DECOY_COUNT) < 3 && decoyReloadCoolDown == 0 && this.level() instanceof ServerLevel) { - this.entityData.set(DECOY_COUNT, this.entityData.get(DECOY_COUNT) + 1); - this.level().playSound(null, this, ModSounds.DECOY_RELOAD.get(), this.getSoundSource(), 1, 1); - decoyReloadCoolDown = 300; - } - } - @Override public void travel() { Entity passenger = getFirstPassenger(); diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java index 2a2e58193..82b4f98c8 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java @@ -235,6 +235,8 @@ public class Bmp2Entity extends ContainerMobileVehicleEntity implements GeoEntit this.terrainCompat(4f, 5f); inertiaRotate(1); + releaseSmokeDecoy(); + lowHealthWarning(); this.refreshDimensions(); } @@ -716,4 +718,9 @@ public class Bmp2Entity extends ContainerMobileVehicleEntity implements GeoEntit guiGraphics.drawString(font, Component.literal("9M113 " + this.getEntityData().get(LOADED_MISSILE) + " " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : this.getEntityData().get(MISSILE_COUNT))), 30, -9, -1, false); } } + + @Override + public boolean hasDecoy() { + return true; + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/DroneEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/DroneEntity.java index 1f9de44d4..71eab402a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/DroneEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/DroneEntity.java @@ -454,7 +454,7 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity { final Vec3 center = new Vec3(this.getX(), this.getY(), this.getZ()); for (Entity target : level.getEntitiesOfClass(Entity.class, aabb, e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { if (this != target && target != null - && !(target instanceof ItemEntity || target instanceof Projectile || target instanceof ProjectileEntity || target instanceof LaserEntity || target instanceof FlareDecoyEntity || target instanceof AreaEffectCloud || target instanceof C4Entity)) { + && !(target instanceof ItemEntity || target instanceof Projectile || target instanceof ProjectileEntity || target instanceof LaserEntity || target instanceof DecoyEntity || target instanceof AreaEffectCloud || target instanceof C4Entity)) { hitEntityCrash(controller, target); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java index 4e55ec610..3b73608d1 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java @@ -191,6 +191,8 @@ public class Lav150Entity extends ContainerMobileVehicleEntity implements GeoEnt this.terrainCompat(2.7f, 3.61f); inertiaRotate(1.25f); + releaseSmokeDecoy(); + this.refreshDimensions(); } @@ -621,4 +623,9 @@ public class Lav150Entity extends ContainerMobileVehicleEntity implements GeoEnt guiGraphics.drawString(font, Component.literal("7.62MM COAX " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : this.getAmmoCount(player))), 30, -9, Mth.hsvToRgb(0F, (float) heat2, 1.0F), false); } } + + @Override + public boolean hasDecoy() { + return true; + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/PrismTankEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/PrismTankEntity.java index a5c1e6039..168407890 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/PrismTankEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/PrismTankEntity.java @@ -219,6 +219,8 @@ public class PrismTankEntity extends ContainerMobileVehicleEntity implements Geo this.terrainCompat(4.6375f, 5.171875f); inertiaRotate(1); + releaseSmokeDecoy(); + lowHealthWarning(); this.refreshDimensions(); } @@ -760,4 +762,9 @@ public class PrismTankEntity extends ContainerMobileVehicleEntity implements Geo double heat = this.getEntityData().get(HEAT) / 100.0F; guiGraphics.drawString(font, Component.literal("LASER " + (this.getEntityData().get(HEAT) + 25) + " ℃"), 30, -9, Mth.hsvToRgb(0F, (float) heat, 1.0F), false); } + + @Override + public boolean hasDecoy() { + return true; + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java index 6b1ffe9ea..3234ff4ac 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java @@ -332,6 +332,8 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti this.terrainCompat(4.6f, 6.7f); inertiaRotate(1.2f); + releaseSmokeDecoy(); + this.refreshDimensions(); } @@ -1219,4 +1221,9 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti guiGraphics.drawString(font, Component.literal("12.7MM HMG " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : this.getAmmoCount(player))), 30, -9, Mth.hsvToRgb(0F, (float) heat2, 1.0F), false); } } + + @Override + public boolean hasDecoy() { + return true; + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/MobileVehicleEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/MobileVehicleEntity.java index fbbbfbdc7..b68829b20 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/MobileVehicleEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/MobileVehicleEntity.java @@ -2,6 +2,8 @@ package com.atsuishio.superbwarfare.entity.vehicle.base; import com.atsuishio.superbwarfare.config.server.VehicleConfig; import com.atsuishio.superbwarfare.entity.TargetEntity; +import com.atsuishio.superbwarfare.entity.projectile.FlareDecoyEntity; +import com.atsuishio.superbwarfare.entity.projectile.SmokeDecoyEntity; import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity; import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModSounds; @@ -52,7 +54,9 @@ public abstract class MobileVehicleEntity extends EnergyVehicleEntity implements public static final EntityDataAccessor COAX_HEAT = SynchedEntityData.defineId(MobileVehicleEntity.class, EntityDataSerializers.INT); public static final EntityDataAccessor AMMO = SynchedEntityData.defineId(MobileVehicleEntity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor DECOY_COUNT = SynchedEntityData.defineId(MobileVehicleEntity.class, EntityDataSerializers.INT); + public int decoyReloadCoolDown; public static boolean IGNORE_ENTITY_GROUND_CHECK_STEPPING = false; public boolean leftInputDown; public boolean rightInputDown; @@ -193,6 +197,10 @@ public abstract class MobileVehicleEntity extends EnergyVehicleEntity implements cannotFireCoax = false; } + if (decoyReloadCoolDown > 0) { + decoyReloadCoolDown--; + } + if (this.entityData.get(HEAT) > 100 && !cannotFire) { cannotFire = true; this.level().playSound(null, this.getOnPos(), ModSounds.MINIGUN_OVERHEAT.get(), SoundSource.PLAYERS, 1, 1); @@ -220,6 +228,56 @@ public abstract class MobileVehicleEntity extends EnergyVehicleEntity implements this.refreshDimensions(); } + //烟雾诱饵 + public void releaseSmokeDecoy() { + if (decoyInputDown) { + if (this.entityData.get(DECOY_COUNT) > 0 && this.level() instanceof ServerLevel) { + Entity passenger = getFirstPassenger(); + for (int i = 0; i < 16; i++) { + SmokeDecoyEntity smokeDecoyEntity = new SmokeDecoyEntity(this.level()); + smokeDecoyEntity.setPos(this.getX(), this.getY() + 2, this.getZ()); + smokeDecoyEntity.decoyShoot(this, this.getViewVector(1).yRot((11.25F + 22.5F * i) * Mth.DEG_TO_RAD), 3.2f, 8); + this.level().addFreshEntity(smokeDecoyEntity); + } + this.level().playSound(null, this, ModSounds.DECOY_FIRE.get(), this.getSoundSource(), 1, 1); + decoyReloadCoolDown = 400; + this.getEntityData().set(DECOY_COUNT, this.getEntityData().get(DECOY_COUNT) - 1); + } + decoyInputDown = false; + } + if (this.entityData.get(DECOY_COUNT) < 1 && decoyReloadCoolDown == 0 && this.level() instanceof ServerLevel) { + this.entityData.set(DECOY_COUNT, this.entityData.get(DECOY_COUNT) + 1); + this.level().playSound(null, this, ModSounds.DECOY_RELOAD.get(), this.getSoundSource(), 1, 1); + decoyReloadCoolDown = 400; + } + } + + //热诱弹诱饵 + public void releaseDecoy() { + if (decoyInputDown) { + if (this.entityData.get(DECOY_COUNT) > 0 && this.level() instanceof ServerLevel) { + Entity passenger = getFirstPassenger(); + for (int i = 0; i < 4; i++) { + FlareDecoyEntity flareDecoyEntity = new FlareDecoyEntity(this.level()); + flareDecoyEntity.setPos(this.getX() + this.getDeltaMovement().x, this.getY() + 0.5 + this.getDeltaMovement().y, this.getZ() + this.getDeltaMovement().z); + flareDecoyEntity.decoyShoot(this, this.getViewVector(1).yRot((45 + 90 * i) * Mth.DEG_TO_RAD), 0.8f, 8); + this.level().addFreshEntity(flareDecoyEntity); + } + this.level().playSound(null, this, ModSounds.DECOY_FIRE.get(), this.getSoundSource(), 1, 1); + if (this.getEntityData().get(DECOY_COUNT) == 3) { + decoyReloadCoolDown = 300; + } + this.getEntityData().set(DECOY_COUNT, this.getEntityData().get(DECOY_COUNT) - 1); + } + decoyInputDown = false; + } + if (this.entityData.get(DECOY_COUNT) < 3 && decoyReloadCoolDown == 0 && this.level() instanceof ServerLevel) { + this.entityData.set(DECOY_COUNT, this.entityData.get(DECOY_COUNT) + 1); + this.level().playSound(null, this, ModSounds.DECOY_RELOAD.get(), this.getSoundSource(), 1, 1); + decoyReloadCoolDown = 300; + } + } + // 惯性倾斜 public void inertiaRotate(float multiple) { @@ -646,28 +704,35 @@ public abstract class MobileVehicleEntity extends EnergyVehicleEntity implements this.recoilShake = pRecoilShake; } + public boolean hasDecoy() { + return false; + } + @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { super.defineSynchedData(builder); - builder.define(CANNON_RECOIL_TIME, 0); - builder.define(POWER, 0f); - builder.define(YAW, 0f); - builder.define(AMMO, 0); - builder.define(FIRE_ANIM, 0); - builder.define(HEAT, 0); - builder.define(COAX_HEAT, 0); + builder.define(CANNON_RECOIL_TIME, 0) + .define(POWER, 0f) + .define(YAW, 0f) + .define(AMMO, 0) + .define(FIRE_ANIM, 0) + .define(HEAT, 0) + .define(COAX_HEAT, 0) + .define(DECOY_COUNT, 0); } @Override protected void readAdditionalSaveData(CompoundTag compound) { super.readAdditionalSaveData(compound); this.entityData.set(POWER, compound.getFloat("Power")); + this.entityData.set(DECOY_COUNT, compound.getInt("DecoyCount")); } @Override public void addAdditionalSaveData(CompoundTag compound) { super.addAdditionalSaveData(compound); compound.putFloat("Power", this.entityData.get(POWER)); + compound.putInt("DecoyCount", this.entityData.get(DECOY_COUNT)); } public boolean canCrushEntities() { diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java b/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java index 287589843..0d122f532 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java @@ -36,6 +36,8 @@ public class ModEntities { EntityType.Builder.of(LaserEntity::new, MobCategory.MISC).sized(0.1f, 0.1f).fireImmune().setUpdateInterval(1)); public static final DeferredHolder, EntityType> FLARE_DECOY = register("flare_decoy", EntityType.Builder.of(FlareDecoyEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final DeferredHolder, EntityType> SMOKE_DECOY = register("smoke_decoy", + EntityType.Builder.of(SmokeDecoyEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).noSave().sized(3f, 3f)); public static final DeferredHolder, EntityType> CLAYMORE = register("claymore", EntityType.Builder.of(ClaymoreEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); public static final DeferredHolder, EntityType> C_4 = register("c4", @@ -101,7 +103,7 @@ public class ModEntities { EntityType.Builder.of(Yx100Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).fireImmune().sized(5.5f, 3.25f)); public static final DeferredHolder, EntityType> DRONE = register("drone", - EntityType.Builder.of(DroneEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).sized(0.6f, 0.2f)); + EntityType.Builder.of(DroneEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).sized(0.6f, 0.2f)); public static final DeferredHolder, EntityType> LASER_TOWER = register("laser_tower", EntityType.Builder.of(LaserTowerEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).fireImmune().sized(0.9f, 1.65f)); public static final DeferredHolder, EntityType> PRISM_TANK = register("prism_tank", diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java b/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java index 283f2afd1..481e87e75 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java @@ -36,6 +36,7 @@ public class ModEntityRenderers { event.registerEntityRenderer(ModEntities.WHEEL_CHAIR.get(), WheelChairRenderer::new); event.registerEntityRenderer(ModEntities.AH_6.get(), Ah6Renderer::new); event.registerEntityRenderer(ModEntities.FLARE_DECOY.get(), FlareDecoyEntityRenderer::new); + event.registerEntityRenderer(ModEntities.SMOKE_DECOY.get(), SmokeDecoyEntityRenderer::new); event.registerEntityRenderer(ModEntities.LAV_150.get(), Lav150Renderer::new); event.registerEntityRenderer(ModEntities.SMALL_CANNON_SHELL.get(), SmallCannonShellRenderer::new); event.registerEntityRenderer(ModEntities.TOM_6.get(), Tom6Renderer::new); diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModParticleTypes.java b/src/main/java/com/atsuishio/superbwarfare/init/ModParticleTypes.java index db1276f5c..26b2ef8a3 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModParticleTypes.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModParticleTypes.java @@ -13,5 +13,6 @@ public class ModParticleTypes { public static final DeferredHolder, SimpleParticleType> FIRE_STAR = REGISTRY.register("fire_star", () -> new SimpleParticleType(false)); public static final DeferredHolder, SimpleParticleType> BULLET_HOLE = REGISTRY.register("bullet_hole", () -> new SimpleParticleType(false)); public static final DeferredHolder, SimpleParticleType> CUSTOM_CLOUD = REGISTRY.register("custom_cloud", () -> new SimpleParticleType(false)); + public static final DeferredHolder, SimpleParticleType> CUSTOM_SMOKE = REGISTRY.register("custom_smoke", () -> new SimpleParticleType(false)); } diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModParticles.java b/src/main/java/com/atsuishio/superbwarfare/init/ModParticles.java index 07f0d53ac..d602a9630 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModParticles.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModParticles.java @@ -2,6 +2,7 @@ package com.atsuishio.superbwarfare.init; import com.atsuishio.superbwarfare.client.particle.BulletHoleParticle; import com.atsuishio.superbwarfare.client.particle.CustomCloudParticle; +import com.atsuishio.superbwarfare.client.particle.CustomSmokeParticle; import com.atsuishio.superbwarfare.client.particle.FireStarParticle; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; @@ -15,6 +16,7 @@ public class ModParticles { event.registerSpriteSet(ModParticleTypes.FIRE_STAR.get(), FireStarParticle::provider); event.registerSpriteSet(ModParticleTypes.BULLET_HOLE.get(), BulletHoleParticle::provider); event.registerSpriteSet(ModParticleTypes.CUSTOM_CLOUD.get(), CustomCloudParticle::provider); + event.registerSpriteSet(ModParticleTypes.CUSTOM_SMOKE.get(), CustomSmokeParticle::provider); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModSounds.java b/src/main/java/com/atsuishio/superbwarfare/init/ModSounds.java index bbe23ffa9..da355e73e 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModSounds.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModSounds.java @@ -438,6 +438,7 @@ public class ModSounds { public static final DeferredHolder INSIDIOUS_FAR = REGISTRY.register("insidious_far", () -> SoundEvent.createVariableRangeEvent(Mod.loc("insidious_far"))); public static final DeferredHolder INSIDIOUS_VERYFAR = REGISTRY.register("insidious_veryfar", () -> SoundEvent.createVariableRangeEvent(Mod.loc("insidious_veryfar"))); public static final DeferredHolder INSIDIOUS_RELOAD_EMPTY = REGISTRY.register("insidious_reload_empty", () -> SoundEvent.createVariableRangeEvent(Mod.loc("insidious_reload_empty"))); + public static final DeferredHolder SMOKE_FIRE = REGISTRY.register("smoke_fire", () -> SoundEvent.createVariableRangeEvent(Mod.loc("smoke_fire"))); } diff --git a/src/main/java/com/atsuishio/superbwarfare/item/gun/launcher/JavelinItem.java b/src/main/java/com/atsuishio/superbwarfare/item/gun/launcher/JavelinItem.java index 8cf67bafc..f5bfdbe68 100644 --- a/src/main/java/com/atsuishio/superbwarfare/item/gun/launcher/JavelinItem.java +++ b/src/main/java/com/atsuishio/superbwarfare/item/gun/launcher/JavelinItem.java @@ -3,7 +3,7 @@ package com.atsuishio.superbwarfare.item.gun.launcher; import com.atsuishio.superbwarfare.Mod; import com.atsuishio.superbwarfare.client.renderer.item.JavelinItemRenderer; import com.atsuishio.superbwarfare.client.tooltip.component.LauncherImageComponent; -import com.atsuishio.superbwarfare.entity.projectile.FlareDecoyEntity; +import com.atsuishio.superbwarfare.entity.projectile.DecoyEntity; import com.atsuishio.superbwarfare.entity.projectile.JavelinMissileEntity; import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; import com.atsuishio.superbwarfare.event.ClientEventHandler; @@ -143,11 +143,11 @@ public class JavelinItem extends GunItem implements GeoItem, SpecialFireWeapon { List decoy = SeekTool.seekLivingEntities(player, player.level(), 512, 8); for (var e : decoy) { - if (e instanceof FlareDecoyEntity flareDecoy) { - tag.putString("TargetEntity", flareDecoy.getStringUUID()); - tag.putDouble("TargetPosX", flareDecoy.getX()); - tag.putDouble("TargetPosY", flareDecoy.getEyeY()); - tag.putDouble("TargetPosZ", flareDecoy.getZ()); + if (e instanceof DecoyEntity decoyEntity) { + tag.putString("TargetEntity", decoyEntity.getStringUUID()); + tag.putDouble("TargetPosX", decoyEntity.getPosition().x); + tag.putDouble("TargetPosY", decoyEntity.getPosition().y); + tag.putDouble("TargetPosZ", decoyEntity.getPosition().z); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/send/TacticalSprintMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/send/TacticalSprintMessage.java index 90e17fa09..539508a04 100644 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/send/TacticalSprintMessage.java +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/send/TacticalSprintMessage.java @@ -10,7 +10,7 @@ import net.neoforged.neoforge.network.handling.IPayloadContext; import org.jetbrains.annotations.NotNull; public record TacticalSprintMessage(boolean sprint) implements CustomPacketPayload { - public static final Type TYPE = new Type<>(Mod.loc("vehicle_fire")); + public static final Type TYPE = new Type<>(Mod.loc("tactical_sprint")); public static final StreamCodec STREAM_CODEC = StreamCodec.composite( ByteBufCodecs.BOOL, diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/ParticleTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/ParticleTool.java index 31c612766..a334b3b1c 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/ParticleTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/ParticleTool.java @@ -48,6 +48,7 @@ public class ParticleTool { sendParticle(serverLevel, ParticleTypes.CAMPFIRE_COSY_SMOKE, x, y, z, 3, 0.1, 0.1, 0.1, 0.02, true); sendParticle(serverLevel, ParticleTypes.LARGE_SMOKE, x, y, z, 4, 0.2, 0.2, 0.2, 0.02, true); sendParticle(serverLevel, ModParticleTypes.FIRE_STAR.get(), x, y, z, 6, 0, 0, 0, 0.2, true); + sendParticle(serverLevel, ModParticleTypes.CUSTOM_SMOKE.get(), x, y, z, 400, 0.2, 0.2, 0.2, 0.05, true); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java index 4056c53ac..4a139bc11 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java @@ -1,5 +1,6 @@ package com.atsuishio.superbwarfare.tools; +import com.atsuishio.superbwarfare.entity.projectile.DecoyEntity; import com.atsuishio.superbwarfare.entity.projectile.DestroyableProjectileEntity; import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; import net.minecraft.core.BlockPos; @@ -105,7 +106,7 @@ public class TraceTool { Vec3 viewVec = vehicle.getBarrelVector(1); Vec3 toVec = eye.add(viewVec.x * entityReach, viewVec.y * entityReach, viewVec.z * entityReach); AABB aabb = vehicle.getBoundingBox().expandTowards(viewVec.scale(entityReach)).inflate(1.0D, 1.0D, 1.0D); - EntityHitResult entityhitresult = ProjectileUtil.getEntityHitResult(vehicle, eye, toVec, aabb, p -> !p.isSpectator() && p.isAlive() && !(p instanceof Projectile && !(p instanceof DestroyableProjectileEntity)), distance); + EntityHitResult entityhitresult = ProjectileUtil.getEntityHitResult(vehicle, eye, toVec, aabb, p -> !p.isSpectator() && p.isAlive() && !(p instanceof Projectile && !(p instanceof DestroyableProjectileEntity)) && SeekTool.baseFilter(p) && !(p instanceof DecoyEntity), distance); if (entityhitresult != null) { hitResult = entityhitresult; diff --git a/src/main/resources/assets/superbwarfare/lang/en_us.json b/src/main/resources/assets/superbwarfare/lang/en_us.json index baceea8eb..2702f8338 100644 --- a/src/main/resources/assets/superbwarfare/lang/en_us.json +++ b/src/main/resources/assets/superbwarfare/lang/en_us.json @@ -443,6 +443,7 @@ "entity.superbwarfare.laser_tower": "Laser Defense Tower", "entity.superbwarfare.prism_tank": "Prism Tank", "entity.superbwarfare.swarm_drone": "Swarm Drone", + "entity.superbwarfare.smoke_decoy": "Smoke", "key.categories.superbwarfare": "Superb Warfare", "key.superbwarfare.hold_zoom": "Zoom (Hold)", diff --git a/src/main/resources/assets/superbwarfare/lang/zh_cn.json b/src/main/resources/assets/superbwarfare/lang/zh_cn.json index fb2c0f9eb..cfa2441ba 100644 --- a/src/main/resources/assets/superbwarfare/lang/zh_cn.json +++ b/src/main/resources/assets/superbwarfare/lang/zh_cn.json @@ -441,6 +441,7 @@ "entity.superbwarfare.laser_tower": "激光防御塔", "entity.superbwarfare.prism_tank": "光棱坦克", "entity.superbwarfare.swarm_drone": "蜂群无人机", + "entity.superbwarfare.smoke_decoy": "烟雾", "key.categories.superbwarfare": "卓越前线", "key.superbwarfare.hold_zoom": "瞄准(按住)", diff --git a/src/main/resources/assets/superbwarfare/particles/custom_smoke.json b/src/main/resources/assets/superbwarfare/particles/custom_smoke.json new file mode 100644 index 000000000..f970e447f --- /dev/null +++ b/src/main/resources/assets/superbwarfare/particles/custom_smoke.json @@ -0,0 +1,12 @@ +{ + "textures": [ + "minecraft:generic_0", + "minecraft:generic_1", + "minecraft:generic_2", + "minecraft:generic_3", + "minecraft:generic_4", + "minecraft:generic_5", + "minecraft:generic_6", + "minecraft:generic_7" + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/sounds.json b/src/main/resources/assets/superbwarfare/sounds.json index 8b2716dd1..3a4173ebb 100644 --- a/src/main/resources/assets/superbwarfare/sounds.json +++ b/src/main/resources/assets/superbwarfare/sounds.json @@ -3035,5 +3035,13 @@ "stream": false } ] + }, + "smoke_fire": { + "sounds": [ + { + "name": "superbwarfare:smoke_fire", + "stream": false + } + ] } } \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/sounds/smoke_fire.ogg b/src/main/resources/assets/superbwarfare/sounds/smoke_fire.ogg new file mode 100644 index 0000000000000000000000000000000000000000..98ecd7a2887f7c2428eccdc452ebeec2184ab432 GIT binary patch literal 23708 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 ae^