From 81fa2b52703b13b82b5fbee9a3b8e51e2164996b Mon Sep 17 00:00:00 2001 From: Andy0106 <1850270257@qq.com> Date: Wed, 22 Jan 2025 21:20:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0C4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../superbwarfare/client/ClickHandler.java | 11 + .../client/model/entity/ExplosiveModel.java | 30 ++ .../client/overlay/KillMessageOverlay.java | 2 + .../renderer/entity/ExplosiveRenderer.java | 54 +++ .../config/server/ExplosionConfig.java | 17 + .../superbwarfare/entity/DroneEntity.java | 33 +- .../superbwarfare/entity/ExplosiveEntity.java | 322 ++++++++++++++++++ .../entity/projectile/ProjectileEntity.java | 4 +- .../entity/vehicle/Ah6Entity.java | 5 - .../entity/vehicle/ContainerMobileEntity.java | 6 +- .../entity/vehicle/VehicleEntity.java | 7 +- .../superbwarfare/init/ModDamageTypes.java | 5 + .../superbwarfare/init/ModEntities.java | 2 + .../init/ModEntityRenderers.java | 1 + .../superbwarfare/init/ModItems.java | 1 + .../superbwarfare/init/ModKeyMappings.java | 2 + .../superbwarfare/init/ModVillagers.java | 4 + .../superbwarfare/item/ExplosiveMine.java | 45 +++ .../superbwarfare/tools/DamageTypeTool.java | 2 +- .../superbwarfare/tools/SeekTool.java | 9 +- .../animations/c4.animation.json | 8 + .../assets/superbwarfare/geo/c4.geo.json | 97 ++++++ .../assets/superbwarfare/lang/en_us.json | 6 + .../assets/superbwarfare/lang/zh_cn.json | 6 + .../superbwarfare/models/custom/c4.json | 142 ++++++++ .../models/displaysettings/c4.item.json | 40 +++ .../models/item/explosive_mine.json | 7 + .../superbwarfare/textures/block/c4.png | Bin 0 -> 370 bytes .../superbwarfare/textures/entity/c4.png | Bin 0 -> 370 bytes .../textures/entity/c4_alter.png | Bin 0 -> 377 bytes .../assets/superbwarfare/textures/item/c4.png | Bin 0 -> 370 bytes .../data/superbwarfare/damage_type/c4.json | 5 + .../superbwarfare/recipes/c4_crafting.json | 24 ++ 35 files changed, 880 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/ExplosiveModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ExplosiveRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/ExplosiveEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/ExplosiveMine.java create mode 100644 src/main/resources/assets/superbwarfare/animations/c4.animation.json create mode 100644 src/main/resources/assets/superbwarfare/geo/c4.geo.json create mode 100644 src/main/resources/assets/superbwarfare/models/custom/c4.json create mode 100644 src/main/resources/assets/superbwarfare/models/displaysettings/c4.item.json create mode 100644 src/main/resources/assets/superbwarfare/models/item/explosive_mine.json create mode 100644 src/main/resources/assets/superbwarfare/textures/block/c4.png create mode 100644 src/main/resources/assets/superbwarfare/textures/entity/c4.png create mode 100644 src/main/resources/assets/superbwarfare/textures/entity/c4_alter.png create mode 100644 src/main/resources/assets/superbwarfare/textures/item/c4.png create mode 100644 src/main/resources/data/superbwarfare/damage_type/c4.json create mode 100644 src/main/resources/data/superbwarfare/recipes/c4_crafting.json diff --git a/.gitignore b/.gitignore index 6342f909b..c14fc0510 100644 --- a/.gitignore +++ b/.gitignore @@ -119,4 +119,5 @@ run/ # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar -.mcreator \ No newline at end of file +.mcreator +*.bbmodel \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37aef8d3f..44e1b286a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.1.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/com/atsuishio/superbwarfare/client/ClickHandler.java b/src/main/java/com/atsuishio/superbwarfare/client/ClickHandler.java index 6094cdc04..485f0dcab 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/ClickHandler.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/ClickHandler.java @@ -21,6 +21,7 @@ import com.atsuishio.superbwarfare.tools.TraceTool; import com.mojang.blaze3d.platform.InputConstants; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundSource; import net.minecraft.util.Mth; @@ -218,6 +219,9 @@ public class ClickHandler { ClientEventHandler.holdFire = false; ModUtils.PACKET_HANDLER.sendToServer(new EditModeMessage(0)); } + if (key == ModKeyMappings.LAUNCH.getKey().getValue()) { + handleLaunchPress(player); + } if (player.getCapability(ModVariables.PLAYER_VARIABLES_CAPABILITY, null).orElse(new ModVariables.PlayerVariables()).edit) { if (!(stack.getItem() instanceof GunItem gunItem)) return; @@ -470,4 +474,11 @@ public class ClickHandler { } ModUtils.PACKET_HANDLER.sendToServer(new PlayerStopRidingMessage(0)); } + + private static void handleLaunchPress(Player player) { + ItemStack item = player.getMainHandItem(); + if (item.is(ModItems.EXPLOSIVE_MINE.get())) { + item.use(player.level(),player,player.getUsedItemHand()); + } + } } \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/ExplosiveModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/ExplosiveModel.java new file mode 100644 index 000000000..c621f23bd --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/ExplosiveModel.java @@ -0,0 +1,30 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.ExplosiveEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +import java.util.UUID; + +public class ExplosiveModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(ExplosiveEntity entity) { + return ModUtils.loc("animations/c4.animation.json"); + } + + @Override + public ResourceLocation getModelResource(ExplosiveEntity entity) { + return ModUtils.loc("geo/c4.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(ExplosiveEntity entity) { + UUID uuid = entity.getUUID(); + if (uuid.getLeastSignificantBits() % 114 == 0) { + return ModUtils.loc("textures/entity/c4_alter.png"); + } + return ModUtils.loc("textures/entity/c4.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/KillMessageOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/KillMessageOverlay.java index b05e19303..b382cd011 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/overlay/KillMessageOverlay.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/KillMessageOverlay.java @@ -268,6 +268,8 @@ public class KillMessageOverlay { icon = BEAST; } else if (record.damageType == ModDamageTypes.MINE) { icon = CLAYMORE; + } else if (record.damageType == ModDamageTypes.C4) { + icon = EXPLOSION; } else if (record.damageType == ResourceKey.create(Registries.DAMAGE_TYPE, new ResourceLocation("dreamaticvoyage", "bleeding"))) { icon = BLEEDING; } else if (record.damageType == ResourceKey.create(Registries.DAMAGE_TYPE, new ResourceLocation("dreamaticvoyage", "blood_crystal"))) { diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ExplosiveRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ExplosiveRenderer.java new file mode 100644 index 000000000..9099768a6 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ExplosiveRenderer.java @@ -0,0 +1,54 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.ExplosiveModel; +import com.atsuishio.superbwarfare.entity.ExplosiveEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class ExplosiveRenderer extends GeoEntityRenderer { + + public ExplosiveRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new ExplosiveModel()); + this.shadowRadius = 0f; + } + + @Override + public RenderType getRenderType(ExplosiveEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, ExplosiveEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, + float blue, float alpha) { + float scale = 0.5f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, red, green, blue, alpha); + } + + @Override + public void render(ExplosiveEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(ExplosiveEntity entityLivingBaseIn) { + return 0.0F; + } + + @Override + public boolean shouldShowName(ExplosiveEntity animatable) { + return false; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/config/server/ExplosionConfig.java b/src/main/java/com/atsuishio/superbwarfare/config/server/ExplosionConfig.java index 59d8b6a21..3945b9ce3 100644 --- a/src/main/java/com/atsuishio/superbwarfare/config/server/ExplosionConfig.java +++ b/src/main/java/com/atsuishio/superbwarfare/config/server/ExplosionConfig.java @@ -19,6 +19,10 @@ public class ExplosionConfig { public static ForgeConfigSpec.IntValue DRONE_KAMIKAZE_EXPLOSION_DAMAGE; public static ForgeConfigSpec.IntValue DRONE_KAMIKAZE_EXPLOSION_RADIUS; + public static ForgeConfigSpec.IntValue C4_EXPLOSION_COUNTDOWN; + public static ForgeConfigSpec.IntValue C4_EXPLOSION_DAMAGE; + public static ForgeConfigSpec.IntValue C4_EXPLOSION_RADIUS; + public static void init(ForgeConfigSpec.Builder builder) { builder.push("explosion"); @@ -72,6 +76,19 @@ public class ExplosionConfig { DRONE_KAMIKAZE_EXPLOSION_RADIUS = builder.defineInRange("drone_kamikaze_explosion_radius", 9, 1, 50); builder.pop(); + + builder.push("C4"); + + builder.comment("The explosion damage of C4"); + C4_EXPLOSION_DAMAGE = builder.defineInRange("c4_explosion_damage", 700, 1, Integer.MAX_VALUE); + + builder.comment("The explosion countdown of C4"); + C4_EXPLOSION_COUNTDOWN = builder.defineInRange("c4_explosion_countdown", 514, 1, Integer.MAX_VALUE); + + builder.comment("The explosion radius of C4"); + C4_EXPLOSION_RADIUS = builder.defineInRange("c4_explosion_radius", 24, 1, Integer.MAX_VALUE); + + builder.pop(); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/DroneEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/DroneEntity.java index f0dc2821d..dcfddda64 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/DroneEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/DroneEntity.java @@ -61,6 +61,7 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity { public static final EntityDataAccessor CONTROLLER = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.STRING); public static final EntityDataAccessor AMMO = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.INT); public static final EntityDataAccessor KAMIKAZE = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.BOOLEAN); + public static final EntityDataAccessor KAMIKAZE_MODE = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.INT); public static final EntityDataAccessor DELTA_ROT = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.FLOAT); public static final EntityDataAccessor DELTA_X_ROT = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.FLOAT); public static final EntityDataAccessor PROPELLER_ROT = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.FLOAT); @@ -123,6 +124,7 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity { this.entityData.define(LINKED, false); this.entityData.define(AMMO, 0); this.entityData.define(KAMIKAZE, false); + this.entityData.define(KAMIKAZE_MODE, 0); } @Override @@ -142,6 +144,7 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity { compound.putString("Controller", this.entityData.get(CONTROLLER)); compound.putInt("Ammo", this.entityData.get(AMMO)); compound.putBoolean("Kamikaze", this.entityData.get(KAMIKAZE)); + compound.putInt("Kamikaze", this.entityData.get(KAMIKAZE_MODE)); } @Override @@ -155,6 +158,8 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity { this.entityData.set(AMMO, compound.getInt("Ammo")); if (compound.contains("Kamikaze")) this.entityData.set(KAMIKAZE, compound.getBoolean("Kamikaze")); + if (compound.contains("KamikazeMode")) + this.entityData.set(KAMIKAZE_MODE, compound.getInt("KamikazeMode")); } @Override @@ -318,6 +323,15 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity { if (player instanceof ServerPlayer serverPlayer) { serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1); } + } else if (stack.getItem() == ModItems.EXPLOSIVE_MINE.get() && this.entityData.get(AMMO) == 0 && !this.entityData.get(KAMIKAZE)) { + if (!player.isCreative()) { + stack.shrink(1); + } + this.entityData.set(KAMIKAZE, true); + this.entityData.set(KAMIKAZE_MODE, 1); + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1); + } } return InteractionResult.sidedSuccess(this.level().isClientSide()); @@ -470,7 +484,7 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity { } if (this.entityData.get(KAMIKAZE)) { - kamikazeExplosion(); + kamikazeExplosion(this.entityData.get(KAMIKAZE_MODE)); } ItemStack stack = new ItemStack(ModItems.RGO_GRENADE.get(), this.entityData.get(AMMO)); @@ -497,11 +511,20 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity { } - private void kamikazeExplosion() { + private void kamikazeExplosion(int mode) { Entity attacker = EntityFindUtil.findEntity(this.level(), this.entityData.get(LAST_ATTACKER_UUID)); - CustomExplosion explosion = new CustomExplosion(this.level(), this, - ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), attacker, attacker), ExplosionConfig.DRONE_KAMIKAZE_EXPLOSION_DAMAGE.get(), - this.getX(), this.getY(), this.getZ(), ExplosionConfig.DRONE_KAMIKAZE_EXPLOSION_RADIUS.get(), ExplosionDestroyConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + CustomExplosion explosion; + switch(mode) { + case 1: + explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), attacker, attacker), ExplosionConfig.C4_EXPLOSION_DAMAGE.get(), + this.getX(), this.getY(), this.getZ(), ExplosionConfig.C4_EXPLOSION_RADIUS.get(), ExplosionDestroyConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + break; + default: + explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), attacker, attacker), ExplosionConfig.DRONE_KAMIKAZE_EXPLOSION_DAMAGE.get(), + this.getX(), this.getY(), this.getZ(), ExplosionConfig.DRONE_KAMIKAZE_EXPLOSION_RADIUS.get(), ExplosionDestroyConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + } explosion.explode(); ForgeEventFactory.onExplosionStart(this.level(), explosion); explosion.finalizeExplosion(false); diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/ExplosiveEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/ExplosiveEntity.java new file mode 100644 index 000000000..fb00a3aab --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/ExplosiveEntity.java @@ -0,0 +1,322 @@ +package com.atsuishio.superbwarfare.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.ExplosionDestroyConfig; +import com.atsuishio.superbwarfare.entity.vehicle.VehicleEntity; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializer; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.players.OldUsersConverter; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.items.ItemHandlerHelper; +import org.joml.Vector3f; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.core.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.Optional; +import java.util.UUID; + +public class ExplosiveEntity extends Entity implements GeoEntity, AnimatedEntity, OwnableEntity { + + protected static final EntityDataAccessor> OWNER_UUID = SynchedEntityData.defineId(ExplosiveEntity.class, EntityDataSerializers.OPTIONAL_UUID); + protected static final EntityDataAccessor LAST_ATTACKER_UUID = SynchedEntityData.defineId(ExplosiveEntity.class, EntityDataSerializers.STRING); + protected static final EntityDataAccessor> TARGET_UUID = SynchedEntityData.defineId(ExplosiveEntity.class, EntityDataSerializers.OPTIONAL_UUID); + protected static final EntityDataAccessor REL_X = SynchedEntityData.defineId(ExplosiveEntity.class, EntityDataSerializers.FLOAT); + protected static final EntityDataAccessor REL_Y = SynchedEntityData.defineId(ExplosiveEntity.class, EntityDataSerializers.FLOAT); + protected static final EntityDataAccessor REL_Z = SynchedEntityData.defineId(ExplosiveEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor HEALTH = SynchedEntityData.defineId(ExplosiveEntity.class, EntityDataSerializers.FLOAT); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public ExplosiveEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public ExplosiveEntity(LivingEntity owner, Level level) { + super(ModEntities.EXPLOSIVE.get(), level); + this.setOwnerUUID(owner.getUUID()); + ModUtils.queueServerWork(1, () -> { + if (this.level().isClientSide()) return; + CompoundTag compoundTag = owner.serializeNBT(); + compoundTag.putUUID("C4UUID", this.getUUID()); + this.getOwner().deserializeNBT(compoundTag); + }); + } + + @Override + protected void defineSynchedData() { + this.entityData.define(OWNER_UUID, Optional.empty()); + this.entityData.define(LAST_ATTACKER_UUID, "undefined"); + this.entityData.define(HEALTH, 10f); + this.entityData.define(TARGET_UUID, Optional.empty()); + this.entityData.define(REL_X, 0.0f); + this.entityData.define(REL_Y, 0.0f); + this.entityData.define(REL_Z, 0.0f); + } + + @Override + public boolean isPickable() { + return !this.isRemoved(); + } + + @Override + public boolean hurt(DamageSource source, float amount) { + return false; + } + + public void setOwnerUUID(@Nullable UUID pUuid) { + this.entityData.set(OWNER_UUID, Optional.ofNullable(pUuid)); + } + + public void setTargetUUID(@Nullable UUID uuid) { + this.entityData.set(TARGET_UUID, Optional.ofNullable(uuid)); + } + + @Nullable + public UUID getOwnerUUID() { + return this.entityData.get(OWNER_UUID).orElse(null); + } + + @Nullable + public UUID getTargetUUID() { + return this.entityData.get(TARGET_UUID).orElse(null); + } + + public boolean isOwnedBy(LivingEntity pEntity) { + return pEntity == this.getOwner(); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + compound.putFloat("Health", this.entityData.get(HEALTH)); + compound.putString("LastAttacker", this.entityData.get(LAST_ATTACKER_UUID)); + if (this.getTargetUUID() != null) { + compound.putUUID("Target", this.getTargetUUID()); + compound.putFloat("RelativeX", this.entityData.get(REL_X)); + compound.putFloat("RelativeY", this.entityData.get(REL_Y)); + compound.putFloat("RelativeZ", this.entityData.get(REL_Z)); + } + if (this.getOwnerUUID() != null) { + compound.putUUID("Owner", this.getOwnerUUID()); + } + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + if (compound.contains("Health")) { + this.entityData.set(HEALTH, compound.getFloat("Health")); + } + + if (compound.contains("LastAttacker")) { + this.entityData.set(LAST_ATTACKER_UUID, compound.getString("LastAttacker")); + } + + UUID uuid; + if (compound.hasUUID("Owner")) { + uuid = compound.getUUID("Owner"); + } else { + String s = compound.getString("Owner"); + + assert this.getServer() != null; + uuid = OldUsersConverter.convertMobOwnerIfNecessary(this.getServer(), s); + } + + if (uuid != null) { + try { + this.setOwnerUUID(uuid); + } catch (Throwable ignored){} + } + + /* + * Target + **/ + if (compound.hasUUID("Target")) { + uuid = compound.getUUID("Target"); + } else { + String s = compound.getString("Target"); + + assert this.getServer() != null; + uuid = OldUsersConverter.convertMobOwnerIfNecessary(this.getServer(), s); + } + + if (uuid != null) { + try { + this.setTargetUUID(uuid); + + this.entityData.set(REL_X, compound.getFloat("RelativeX")); + this.entityData.set(REL_Y, compound.getFloat("RelativeY")); + this.entityData.set(REL_Z, compound.getFloat("RelativeZ")); + } catch (Throwable ignored){} + } + } + + public boolean isPlaced() { + return this.onGround() || this.getTargetUUID() != null; + } + + + @Override + public void tick() { + super.tick(); + var level = this.level(); + var x = this.getX(); + var y = this.getY(); + var z = this.getZ(); + + if (this.tickCount >= ExplosionConfig.C4_EXPLOSION_COUNTDOWN.get()) { + this.explode(); + } + + if (!this.isPlaced()) { + this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.03, 0.0)); + this.move(MoverType.SELF, this.getDeltaMovement()); + this.setDeltaMovement(this.getDeltaMovement().multiply(0.98, 0.98, 0.98)); + + for (Entity target : level.getEntitiesOfClass(Entity.class, this.getBoundingBox().inflate(1), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(this))).toList()) { + if (this.getUUID() == target.getUUID() || this.getOwnerUUID() == target.getUUID() || !(target instanceof LivingEntity || target instanceof VehicleEntity)) { + continue; + } + this.setTargetUUID(target.getUUID());; + + // var relpos = this.calcRelativePos(target); + // this.setRelativePos(((float) relpos.x), ((float) relpos.y), ((float) relpos.z)); + // if (!this.startRiding(target)) this.destroy(); + // ModUtils.LOGGER.info("Start Riding!"); + this.setInvisible(true); + break; + } + if (this.onGround()) { + this.destroy(); + } + } else { + ModUtils.queueServerWork(1, () -> { + if (level.isClientSide()) return; + if (this.getTargetUUID() == null) { + this.destroy(); + return; + } + Entity target = EntityFindUtil.findEntity(this.level(), this.getTargetUUID().toString()); + if (target == null) { + this.destroy(); + return; + } + if (!this.isInvisible()) { + this.setInvisible(true); + } + this.setPos(target.position().x, target.position().y + target.getBoundingBox().getYsize(), target.position().z); + }); + } + + + + this.refreshDimensions(); + } + + public void explode() { + if (!this.level().isClientSide()) { + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + this.discard(); + } + + ModUtils.queueServerWork(1, () -> { + if (this.level().isClientSide()) return; + + this.triggerExplode(this); + }); + this.discard(); + } + + public Vec3 getRelativePos() { + if (this.isPlaced()) { + return new Vec3(this.entityData.get(REL_X), this.entityData.get(REL_Y), this.entityData.get(REL_Z)); + } + return null; + } + + public Vec3 calcRelativePos(Entity target) { + return this.position().subtract(target.position()); + } + + public void setRelativePos(float x, float y, float z) { + this.entityData.set(REL_X, x); + this.entityData.set(REL_X, y); + this.entityData.set(REL_X, z); + } + + public void destroy() { + if (this.level() instanceof ServerLevel && this.tickCount < ExplosionConfig.C4_EXPLOSION_COUNTDOWN.get()) { + ItemEntity c4 = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), new ItemStack(ModItems.EXPLOSIVE_MINE.get())); + c4.setPickUpDelay(10); + this.level().addFreshEntity(c4); + this.discard(); + } + } + + private void triggerExplode(Entity target) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeC4Damage(this.level().registryAccess(), this.getOwner()), ExplosionConfig.C4_EXPLOSION_DAMAGE.get(), + target.getX(), target.getY(), target.getZ(), ExplosionConfig.C4_EXPLOSION_RADIUS.get(), ExplosionDestroyConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + net.minecraftforge.event.ForgeEventFactory.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + } + + @Override + public EntityDimensions getDimensions(Pose p_33597_) { + return super.getDimensions(p_33597_).scale((float) 0.5); + } + + @Override + public boolean isPushable() { + return true; + } + + @Override + public String getSyncedAnimation() { + return null; + } + + @Override + public void setAnimation(String animation) { + } + + @Override + public void setAnimationProcedure(String procedure) { + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java index 79f67c5e2..de98ce44a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/ProjectileEntity.java @@ -223,10 +223,10 @@ public class ProjectileEntity extends Entity implements IEntityAdditionalSpawnDa float eyeHeight = entity.getEyeHeight(); float bodyHeight = entity.getBbHeight(); if ((eyeHeight - 0.35) < hitBoxPos.y && hitBoxPos.y < (eyeHeight + 0.4) && - !(entity instanceof ClaymoreEntity || entity instanceof MortarEntity || entity instanceof IArmedVehicleEntity || entity instanceof DroneEntity)) { + !(entity instanceof ExplosiveEntity || entity instanceof ClaymoreEntity || entity instanceof MortarEntity || entity instanceof IArmedVehicleEntity || entity instanceof DroneEntity)) { headshot = true; } - if (hitBoxPos.y < (0.33 * bodyHeight) && !(entity instanceof ClaymoreEntity || entity instanceof MortarEntity || + if (hitBoxPos.y < (0.33 * bodyHeight) && !(entity instanceof ExplosiveEntity || entity instanceof ClaymoreEntity || entity instanceof MortarEntity || entity instanceof IArmedVehicleEntity || entity instanceof DroneEntity)) { legShot = true; } 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 3d7fa9b45..f4bae7626 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java @@ -419,11 +419,6 @@ public class Ah6Entity extends ContainerMobileEntity implements GeoEntity, IHeli entity.setYBodyRot(getYRot()); } - @Override - protected boolean canAddPassenger(Entity pPassenger) { - return this.getPassengers().size() < this.getMaxPassengers(); - } - public int getMaxPassengers() { return 2; } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/ContainerMobileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/ContainerMobileEntity.java index 730b18a95..125e61412 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/ContainerMobileEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/ContainerMobileEntity.java @@ -67,6 +67,10 @@ public class ContainerMobileEntity extends MobileVehicleEntity implements HasCus if (player.getVehicle() == this) return InteractionResult.PASS; ItemStack stack = player.getMainHandItem(); + if (stack.is(ModItems.EXPLOSIVE_MINE.get())) { + stack.use(player.level(), player, hand); + return InteractionResult.SUCCESS; + } if (player.isShiftKeyDown() && stack.is(ModItems.CROWBAR.get())) { ItemStack container = ContainerBlockItem.createInstance(this); if (!player.addItem(container)) { @@ -96,7 +100,7 @@ public class ContainerMobileEntity extends MobileVehicleEntity implements HasCus player.setYRot(this.getYRot()); return player.startRiding(this) ? InteractionResult.CONSUME : InteractionResult.PASS; } - if (this.getPassengers().size() < this.getMaxPassengers()) { + if (this.canAddPassenger(player)) { return player.startRiding(this) ? InteractionResult.CONSUME : InteractionResult.PASS; } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/VehicleEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/VehicleEntity.java index 744974eb1..9c2677820 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/VehicleEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/VehicleEntity.java @@ -1,6 +1,8 @@ package com.atsuishio.superbwarfare.entity.vehicle; +import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.entity.DroneEntity; +import com.atsuishio.superbwarfare.entity.ExplosiveEntity; import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModParticleTypes; @@ -129,7 +131,7 @@ public class VehicleEntity extends Entity { player.setYRot(this.getYRot()); return player.startRiding(this) ? InteractionResult.CONSUME : InteractionResult.PASS; } - if (this.getPassengers().size() < this.getMaxPassengers()) { + if (this.canAddPassenger(player)) { return player.startRiding(this) ? InteractionResult.CONSUME : InteractionResult.PASS; } } @@ -222,7 +224,8 @@ public class VehicleEntity extends Entity { @Override protected boolean canAddPassenger(Entity pPassenger) { - return this.getPassengers().size() < this.getMaxPassengers(); + ModUtils.LOGGER.info(pPassenger.getClass().toString()); + return this.getPassengers().size() < this.getMaxPassengers() || pPassenger instanceof ExplosiveEntity; } public int getMaxPassengers() { diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModDamageTypes.java b/src/main/java/com/atsuishio/superbwarfare/init/ModDamageTypes.java index 38ec98115..3d3da90cd 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModDamageTypes.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModDamageTypes.java @@ -22,6 +22,7 @@ public class ModDamageTypes { public static final ResourceKey GUN_FIRE_HEADSHOT_ABSOLUTE = ResourceKey.create(Registries.DAMAGE_TYPE, ModUtils.loc("gunfire_headshot_absolute")); public static final ResourceKey BURN = ResourceKey.create(Registries.DAMAGE_TYPE, ModUtils.loc("burn")); public static final ResourceKey MINE = ResourceKey.create(Registries.DAMAGE_TYPE, ModUtils.loc("mine")); + public static final ResourceKey C4 = ResourceKey.create(Registries.DAMAGE_TYPE, ModUtils.loc("c4")); public static final ResourceKey BEAST = ResourceKey.create(Registries.DAMAGE_TYPE, ModUtils.loc("beast")); public static final ResourceKey SHOCK = ResourceKey.create(Registries.DAMAGE_TYPE, ModUtils.loc("shock")); public static final ResourceKey PROJECTILE_BOOM = ResourceKey.create(Registries.DAMAGE_TYPE, ModUtils.loc("projectile_boom")); @@ -47,6 +48,10 @@ public class ModDamageTypes { return new DamageMessages(registryAccess.registry(Registries.DAMAGE_TYPE).get().getHolderOrThrow(MINE), entity); } + public static DamageSource causeC4Damage(RegistryAccess registryAccess, @Nullable Entity entity) { + return new DamageMessages(registryAccess.registry(Registries.DAMAGE_TYPE).get().getHolderOrThrow(C4), entity); + } + public static DamageSource causeShockDamage(RegistryAccess registryAccess, @Nullable Entity attacker) { return new DamageMessages(registryAccess.registry(Registries.DAMAGE_TYPE).get().getHolderOrThrow(SHOCK), attacker); } diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java b/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java index 3edffa1b6..78ff954b9 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java @@ -31,6 +31,8 @@ public class ModEntities { .sized(0.6f, 2f)); public static final RegistryObject> CLAYMORE = register("claymore", EntityType.Builder.of(ClaymoreEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(true).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final RegistryObject> EXPLOSIVE = register("c4", + EntityType.Builder.of(ExplosiveEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(true).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); public static final RegistryObject> MK_42 = register("mk_42", EntityType.Builder.of(Mk42Entity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(true).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(Mk42Entity::new).fireImmune().sized(3.4f, 3.5f)); public static final RegistryObject> MLE_1934 = register("mle_1934", diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java b/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java index b3ecaf6b8..74be64175 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java @@ -14,6 +14,7 @@ public class ModEntityRenderers { event.registerEntityRenderer(ModEntities.MORTAR.get(), MortarRenderer::new); event.registerEntityRenderer(ModEntities.SENPAI.get(), SenpaiRenderer::new); event.registerEntityRenderer(ModEntities.CLAYMORE.get(), ClaymoreRenderer::new); + event.registerEntityRenderer(ModEntities.EXPLOSIVE.get(), ExplosiveRenderer::new); event.registerEntityRenderer(ModEntities.TASER_BULLET_PROJECTILE.get(), TaserBulletProjectileRenderer::new); event.registerEntityRenderer(ModEntities.GUN_GRENADE.get(), GunGrenadeRenderer::new); event.registerEntityRenderer(ModEntities.TARGET.get(), TargetRenderer::new); diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java b/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java index e1379ff47..9603ca588 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java @@ -106,6 +106,7 @@ public class ModItems { public static final RegistryObject HAND_GRENADE = AMMO.register("hand_grenade", HandGrenade::new); public static final RegistryObject RGO_GRENADE = AMMO.register("rgo_grenade", RgoGrenade::new); public static final RegistryObject CLAYMORE_MINE = AMMO.register("claymore_mine", ClaymoreMine::new); + public static final RegistryObject EXPLOSIVE_MINE = AMMO.register("explosive_mine", ExplosiveMine::new); public static final RegistryObject HEAVY_AMMO = AMMO.register("heavy_ammo", () -> new Item(new Item.Properties())); public static final RegistryObject ROCKET_70 = AMMO.register("rocket_70", () -> new Item(new Item.Properties())); public static final RegistryObject SMALL_SHELL = AMMO.register("small_shell", () -> new Item(new Item.Properties())); diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModKeyMappings.java b/src/main/java/com/atsuishio/superbwarfare/init/ModKeyMappings.java index 9bc7ebc70..94d9de2d8 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModKeyMappings.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModKeyMappings.java @@ -55,6 +55,7 @@ public class ModKeyMappings { public static final KeyMapping SWITCH_ZOOM = new KeyMapping("key.superbwarfare.switch_zoom", GLFW.GLFW_KEY_UNKNOWN, "key.categories.superbwarfare"); public static final KeyMapping RELEASE_DECOY = new KeyMapping("key.superbwarfare.release_decoy", GLFW.GLFW_KEY_X, "key.categories.superbwarfare"); public static final KeyMapping MELEE = new KeyMapping("key.superbwarfare.melee", GLFW.GLFW_KEY_V, "key.categories.superbwarfare"); + public static final KeyMapping LAUNCH = new KeyMapping("key.superbwarfare.launch", GLFW.GLFW_KEY_H, "key.categories.superbwarfare"); @SubscribeEvent public static void registerKeyMappings(RegisterKeyMappingsEvent event) { @@ -77,6 +78,7 @@ public class ModKeyMappings { event.register(SWITCH_ZOOM); event.register(RELEASE_DECOY); event.register(MELEE); + event.register(LAUNCH); } @Mod.EventBusSubscriber(value = Dist.CLIENT) diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModVillagers.java b/src/main/java/com/atsuishio/superbwarfare/init/ModVillagers.java index c069234d0..f90f911a1 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModVillagers.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModVillagers.java @@ -152,6 +152,8 @@ public class ModVillagers { new ItemStack(ModItems.MORTAR_SHELLS.get(), 1), 16, 5, 0.05f)); trades.get(4).add(new BasicItemListing(new ItemStack(Items.EMERALD, 4), new ItemStack(ModItems.CLAYMORE_MINE.get(), 1), 16, 5, 0.05f)); + trades.get(4).add(new BasicItemListing(new ItemStack(Items.EMERALD, 4), + new ItemStack(ModItems.EXPLOSIVE_MINE.get(), 1), 16, 5, 0.05f)); trades.get(4).add(new BasicItemListing(new ItemStack(Items.EMERALD, 4), new ItemStack(ModItems.ROCKET.get(), 1), 16, 5, 0.05f)); @@ -165,6 +167,8 @@ public class ModVillagers { new ItemStack(Items.EMERALD, 2), 32, 5, 0.05f)); trades.get(4).add(new BasicItemListing(new ItemStack(ModItems.CLAYMORE_MINE.get(), 1), new ItemStack(Items.EMERALD, 2), 32, 5, 0.05f)); + trades.get(4).add(new BasicItemListing(new ItemStack(ModItems.EXPLOSIVE_MINE.get(), 1), + new ItemStack(Items.EMERALD, 2), 32, 5, 0.05f)); trades.get(4).add(new BasicItemListing(new ItemStack(ModItems.ROCKET.get(), 1), new ItemStack(Items.EMERALD, 2), 32, 5, 0.05f)); diff --git a/src/main/java/com/atsuishio/superbwarfare/item/ExplosiveMine.java b/src/main/java/com/atsuishio/superbwarfare/item/ExplosiveMine.java new file mode 100644 index 000000000..7a570a4ac --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/ExplosiveMine.java @@ -0,0 +1,45 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.entity.ExplosiveEntity; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +public class ExplosiveMine extends Item { + public ExplosiveMine() { + super(new Item.Properties()); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand hand) { + ItemStack stack = player.getItemInHand(hand); + + if (player.serializeNBT().contains("C4UUID") && player.serializeNBT().hasUUID("C4UUID")) { + if (EntityFindUtil.findEntity(player.level(),player.serializeNBT().getUUID("C4UUID").toString()) != null) { + return InteractionResultHolder.pass(stack); + } + } + if (!level.isClientSide) { + ExplosiveEntity entity = new ExplosiveEntity(player, level); + entity.moveTo(player.getX(), player.getY() + 1.1, player.getZ(), player.getYRot(), 0); + entity.setYBodyRot(player.getYRot()); + entity.setYHeadRot(player.getYRot()); + entity.setDeltaMovement(0.5 * player.getLookAngle().x, 0.5 * player.getLookAngle().y, 0.5 * player.getLookAngle().z); + + level.addFreshEntity(entity); + } + + player.getCooldowns().addCooldown(this, 20); + + if (!player.getAbilities().instabuild) { + stack.shrink(1); + } + + return InteractionResultHolder.consume(stack); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/DamageTypeTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/DamageTypeTool.java index a99535d2f..3dc92fd01 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/DamageTypeTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/DamageTypeTool.java @@ -32,7 +32,7 @@ public class DamageTypeTool { public static boolean isModDamage(DamageSource source) { return source.is(ModDamageTypes.GUN_FIRE_ABSOLUTE) || source.is(ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE) || source.is(ModDamageTypes.GUN_FIRE) || source.is(ModDamageTypes.GUN_FIRE_HEADSHOT) - || source.is(ModDamageTypes.MINE) || source.is(ModDamageTypes.SHOCK) + || source.is(ModDamageTypes.MINE) || source.is(ModDamageTypes.MINE) || source.is(ModDamageTypes.SHOCK) || source.is(ModDamageTypes.PROJECTILE_BOOM) || source.is(ModDamageTypes.CANNON_FIRE) || source.is(ModDamageTypes.BURN) || source.is(ModDamageTypes.LASER) || source.is(ModDamageTypes.LASER_HEADSHOT); diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java index 41ecd66bc..6277ad117 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java @@ -1,6 +1,7 @@ package com.atsuishio.superbwarfare.tools; import com.atsuishio.superbwarfare.entity.ClaymoreEntity; +import com.atsuishio.superbwarfare.entity.ExplosiveEntity; import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity; import com.atsuishio.superbwarfare.entity.vehicle.MobileVehicleEntity; import net.minecraft.core.BlockPos; @@ -39,7 +40,7 @@ public class SeekTool { && e.isAlive() && e.getVehicle() == null && !(e instanceof Player player && (player.isSpectator())) - && !(e instanceof ItemEntity || e instanceof ExperienceOrb || e instanceof HangingEntity || e instanceof ProjectileEntity || e instanceof Projectile || e instanceof ArmorStand || e instanceof ClaymoreEntity || e instanceof AreaEffectCloud) + && !(e instanceof ItemEntity || e instanceof ExperienceOrb || e instanceof HangingEntity || e instanceof ProjectileEntity || e instanceof Projectile || e instanceof ArmorStand || e instanceof ClaymoreEntity || e instanceof ExplosiveEntity || e instanceof AreaEffectCloud) ) { return level.clip(new ClipContext(entity.getEyePosition(), e.getEyePosition(), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entity)).getType() != HitResult.Type.BLOCK; @@ -54,7 +55,7 @@ public class SeekTool { if (e.distanceTo(entity) <= seekRange && calculateAngle(e, entity) < seekAngle && e != entity && e.isAlive() - && !(e instanceof ItemEntity || e instanceof ExperienceOrb || e instanceof HangingEntity || e instanceof ProjectileEntity || e instanceof Projectile || e instanceof ArmorStand || e instanceof ClaymoreEntity || e instanceof AreaEffectCloud) + && !(e instanceof ItemEntity || e instanceof ExperienceOrb || e instanceof HangingEntity || e instanceof ProjectileEntity || e instanceof Projectile || e instanceof ArmorStand || e instanceof ClaymoreEntity || e instanceof ExplosiveEntity || e instanceof AreaEffectCloud) && e.getVehicle() == null && !(e instanceof Player player && (player.isSpectator())) && (!e.isAlliedTo(entity) || e.getTeam() == null || e.getTeam().getName().equals("TDM"))) { @@ -71,7 +72,7 @@ public class SeekTool { if (e.distanceTo(entity) <= seekRange && calculateAngle(e, entity) < seekAngle && e != entity && e.isAlive() - && !(e instanceof ItemEntity || e instanceof ExperienceOrb || e instanceof HangingEntity || e instanceof ProjectileEntity || e instanceof Projectile || e instanceof ArmorStand || e instanceof ClaymoreEntity || e instanceof AreaEffectCloud) + && !(e instanceof ItemEntity || e instanceof ExperienceOrb || e instanceof HangingEntity || e instanceof ProjectileEntity || e instanceof Projectile || e instanceof ArmorStand || e instanceof ClaymoreEntity || e instanceof ExplosiveEntity || e instanceof AreaEffectCloud) && e.getVehicle() == null && !(e instanceof Player player && (player.isSpectator())) && (!e.isAlliedTo(entity) || e.getTeam() == null || e.getTeam().getName().equals("TDM"))) { @@ -86,7 +87,7 @@ public class SeekTool { return StreamSupport.stream(EntityFindUtil.getEntities(level).getAll().spliterator(), false) .filter(e -> e.distanceToSqr(pos.getX(), pos.getY(), pos.getZ()) <= range * range && e.isAlive() - && !(e instanceof ItemEntity || e instanceof ExperienceOrb || e instanceof HangingEntity || e instanceof ProjectileEntity || e instanceof Projectile || e instanceof ArmorStand || e instanceof ClaymoreEntity || e instanceof AreaEffectCloud) + && !(e instanceof ItemEntity || e instanceof ExperienceOrb || e instanceof HangingEntity || e instanceof ProjectileEntity || e instanceof Projectile || e instanceof ArmorStand || e instanceof ClaymoreEntity || e instanceof ExplosiveEntity || e instanceof AreaEffectCloud) && !(e instanceof Player player && player.isSpectator())) .toList(); } diff --git a/src/main/resources/assets/superbwarfare/animations/c4.animation.json b/src/main/resources/assets/superbwarfare/animations/c4.animation.json new file mode 100644 index 000000000..924c12f6d --- /dev/null +++ b/src/main/resources/assets/superbwarfare/animations/c4.animation.json @@ -0,0 +1,8 @@ +{ + "format_version": "1.8.0", + "animations": { + "animation.c4.idle": { + "animation_length": 0.5 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/geo/c4.geo.json b/src/main/resources/assets/superbwarfare/geo/c4.geo.json new file mode 100644 index 000000000..5d2db4b6a --- /dev/null +++ b/src/main/resources/assets/superbwarfare/geo/c4.geo.json @@ -0,0 +1,97 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.c4", + "texture_width": 32, + "texture_height": 32, + "visible_bounds_width": 2, + "visible_bounds_height": 1.5, + "visible_bounds_offset": [0, 0.25, 0] + }, + "bones": [ + { + "name": "c4", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-7, 0, -5], + "size": [15, 3, 11], + "uv": { + "north": {"uv": [14, 14], "uv_size": [14, 3]}, + "east": {"uv": [14, 20], "uv_size": [11, 3]}, + "south": {"uv": [14, 17], "uv_size": [14, 3]}, + "west": {"uv": [21, 0], "uv_size": [11, 3]}, + "up": {"uv": [0, 0], "uv_size": [14, 11]}, + "down": {"uv": [0, 22], "uv_size": [14, -11]} + } + }, + { + "origin": [-6, 3, -4], + "size": [2, 1, 9], + "uv": { + "north": {"uv": [11, 23], "uv_size": [2, 1]}, + "east": {"uv": [21, 12], "uv_size": [9, 1]}, + "south": {"uv": [23, 11], "uv_size": [2, 1]}, + "west": {"uv": [21, 13], "uv_size": [9, 1]}, + "up": {"uv": [21, 3], "uv_size": [2, 9]}, + "down": {"uv": [0, 31], "uv_size": [2, -9]} + } + } + ] + }, + { + "name": "button_group", + "parent": "c4", + "pivot": [-2, 3, -3], + "cubes": [ + { + "origin": [-2, 3, -3], + "size": [7, 1, 7], + "uv": { + "north": {"uv": [2, 22], "uv_size": [7, 1]}, + "east": {"uv": [2, 23], "uv_size": [7, 1]}, + "south": {"uv": [23, 3], "uv_size": [7, 1]}, + "west": {"uv": [23, 4], "uv_size": [7, 1]}, + "up": {"uv": [14, 0], "uv_size": [7, 7]}, + "down": {"uv": [14, 14], "uv_size": [7, -7]} + } + } + ] + }, + { + "name": "triggers", + "parent": "c4", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-2, 1, -6], + "size": [5, 1, 1], + "uv": { + "north": {"uv": [9, 22], "uv_size": [5, 1]}, + "east": {"uv": [15, 23], "uv_size": [1, 1]}, + "south": {"uv": [23, 5], "uv_size": [5, 1]}, + "west": {"uv": [16, 23], "uv_size": [1, 1]}, + "up": {"uv": [23, 6], "uv_size": [5, 1]}, + "down": {"uv": [23, 8], "uv_size": [5, -1]} + } + }, + { + "origin": [-6, 1, -6], + "size": [2, 1, 1], + "uv": { + "north": {"uv": [23, 8], "uv_size": [2, 1]}, + "east": {"uv": [13, 23], "uv_size": [1, 1]}, + "south": {"uv": [9, 23], "uv_size": [2, 1]}, + "west": {"uv": [14, 23], "uv_size": [1, 1]}, + "up": {"uv": [23, 9], "uv_size": [2, 1]}, + "down": {"uv": [23, 11], "uv_size": [2, -1]} + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/lang/en_us.json b/src/main/resources/assets/superbwarfare/lang/en_us.json index b0ec6aed6..d88e12147 100644 --- a/src/main/resources/assets/superbwarfare/lang/en_us.json +++ b/src/main/resources/assets/superbwarfare/lang/en_us.json @@ -174,6 +174,7 @@ "item.superbwarfare.mortar_barrel": "Mortar Barrel", "item.superbwarfare.mortar_deployer": "Mortar", "item.superbwarfare.claymore_mine": "Claymore", + "item.superbwarfare.explosive_mine": "C4", "item.superbwarfare.seeker": "Seeker", "item.superbwarfare.missile_engine": "Missile Engine", "item.superbwarfare.fusee": "Fusee", @@ -339,6 +340,9 @@ "death.attack.mine": "%1$s step on Claymore", "death.attack.mine.entity": "%1$s step on %2$s's Claymore", "death.attack.mine.item": "%1$s step on %2$s's Claymore", + "death.attack.c4": "%1$s gasified", + "death.attack.c4.entity": "%1$s was killed by %2$s's C4", + "death.attack.c4.item": "%1$s was killed by %2$s's C4", "death.attack.shock": "%1$s was shocked", "death.attack.shock.entity": "%1$s was shocked by %2$s", "death.attack.shock.item": "%1$s was shocked by %2$s", @@ -386,6 +390,7 @@ "entity.superbwarfare.mortar": "Mortar", "entity.superbwarfare.target": "Target", "entity.superbwarfare.claymore": "Claymore", + "entity.superbwarfare.explosive": "C4", "entity.superbwarfare.senpai": "Senpai", "entity.superbwarfare.mk_42": "5''/54 Mk42", "entity.superbwarfare.mle_1934": "138.6mm50 Mle1934 R1938", @@ -417,6 +422,7 @@ "key.superbwarfare.edit_grip": "Switch Grip", "key.superbwarfare.release_decoy": "Release Decoy", "key.superbwarfare.melee": "Melee", + "key.superbwarfare.launch": "Launch", "effect.superbwarfare.shock": "Shock", "effect.superbwarfare.burn": "Burn", diff --git a/src/main/resources/assets/superbwarfare/lang/zh_cn.json b/src/main/resources/assets/superbwarfare/lang/zh_cn.json index 2f45dfe47..9f651c78c 100644 --- a/src/main/resources/assets/superbwarfare/lang/zh_cn.json +++ b/src/main/resources/assets/superbwarfare/lang/zh_cn.json @@ -174,6 +174,7 @@ "item.superbwarfare.mortar_barrel": "迫击炮管", "item.superbwarfare.mortar_deployer": "迫击炮", "item.superbwarfare.claymore_mine": "阔剑地雷", + "item.superbwarfare.explosive_mine": "C4炸药", "item.superbwarfare.seeker": "导引头", "item.superbwarfare.missile_engine": "导弹发动机", "item.superbwarfare.fusee": "引信", @@ -337,6 +338,9 @@ "death.attack.mine": "%1$s不慎踩到了阔剑地雷", "death.attack.mine.entity": "%1$s踩到了%2$s的阔剑地雷", "death.attack.mine.item": "%1$s踩到了%2$s的阔剑地雷", + "death.attack.c4": "%1$s蒸发了", + "death.attack.c4.entity": "%1$s被%2$s的C4炸死了", + "death.attack.c4.item": "%1$s被%2$s的C4炸死了", "death.attack.shock": "%1$s被电麻了", "death.attack.shock.entity": "%1$s被%2$s电麻了", "death.attack.shock.item": "%1$s被%2$s电麻了", @@ -384,6 +388,7 @@ "entity.superbwarfare.mortar": "迫击炮", "entity.superbwarfare.target": "标靶", "entity.superbwarfare.claymore": "阔剑地雷", + "entity.superbwarfare.explosive": "C4", "entity.superbwarfare.senpai": "野兽先辈", "entity.superbwarfare.mk_42": "5''/54 Mk42", "entity.superbwarfare.mle_1934": "138.6mm50 Mle1934 R1938", @@ -415,6 +420,7 @@ "key.superbwarfare.edit_grip": "切换握把", "key.superbwarfare.release_decoy": "释放诱饵", "key.superbwarfare.melee": "枪械近战", + "key.superbwarfare.launch": "发射", "effect.superbwarfare.shock": "电击", "effect.superbwarfare.burn": "点燃", diff --git a/src/main/resources/assets/superbwarfare/models/custom/c4.json b/src/main/resources/assets/superbwarfare/models/custom/c4.json new file mode 100644 index 000000000..d8a2ad7be --- /dev/null +++ b/src/main/resources/assets/superbwarfare/models/custom/c4.json @@ -0,0 +1,142 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [32, 32], + "textures": { + "particle": "superbwarfare:entity/c4" + }, + "elements": [ + { + "name": "body", + "from": [0, 0, 3], + "to": [15, 3, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [15, 0, 3]}, + "faces": { + "north": {"uv": [7, 7, 14, 8.5], "texture": "#1"}, + "east": {"uv": [7, 10, 12.5, 11.5], "texture": "#1"}, + "south": {"uv": [7, 8.5, 14, 10], "texture": "#1"}, + "west": {"uv": [10.5, 0, 16, 1.5], "texture": "#1"}, + "up": {"uv": [7, 5.5, 0, 0], "texture": "#1"}, + "down": {"uv": [7, 5.5, 0, 11], "texture": "#1"} + } + }, + { + "name": "screen", + "from": [12, 3, 4], + "to": [14, 4, 13], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 3, 4]}, + "faces": { + "north": {"uv": [5.5, 11.5, 6.5, 12], "texture": "#1"}, + "east": {"uv": [10.5, 6, 15, 6.5], "texture": "#1"}, + "south": {"uv": [11.5, 5.5, 12.5, 6], "texture": "#1"}, + "west": {"uv": [10.5, 6.5, 15, 7], "texture": "#1"}, + "up": {"uv": [11.5, 6, 10.5, 1.5], "texture": "#1"}, + "down": {"uv": [1, 11, 0, 15.5], "texture": "#1"} + } + }, + { + "name": "panel", + "from": [3, 3, 5], + "to": [10, 4, 12], + "rotation": {"angle": 0, "axis": "y", "origin": [10, 3, 5]}, + "faces": { + "north": {"uv": [1, 11, 4.5, 11.5], "texture": "#1"}, + "east": {"uv": [1, 11.5, 4.5, 12], "texture": "#1"}, + "south": {"uv": [11.5, 1.5, 15, 2], "texture": "#1"}, + "west": {"uv": [11.5, 2, 15, 2.5], "texture": "#1"}, + "up": {"uv": [10.5, 3.5, 7, 0], "texture": "#1"}, + "down": {"uv": [10.5, 3.5, 7, 7], "texture": "#1"} + } + }, + { + "name": "black", + "from": [5, 1, 2], + "to": [10, 2, 3], + "rotation": {"angle": 0, "axis": "y", "origin": [10, 1, 2]}, + "faces": { + "north": {"uv": [4.5, 11, 7, 11.5], "texture": "#1"}, + "east": {"uv": [7.5, 11.5, 8, 12], "texture": "#1"}, + "south": {"uv": [11.5, 2.5, 14, 3], "texture": "#1"}, + "west": {"uv": [8, 11.5, 8.5, 12], "texture": "#1"}, + "up": {"uv": [14, 3.5, 11.5, 3], "texture": "#1"}, + "down": {"uv": [14, 3.5, 11.5, 4], "texture": "#1"} + } + }, + { + "name": "swtich", + "from": [12, 1, 2], + "to": [14, 2, 3], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 1, 2]}, + "faces": { + "north": {"uv": [11.5, 4, 12.5, 4.5], "texture": "#1"}, + "east": {"uv": [6.5, 11.5, 7, 12], "texture": "#1"}, + "south": {"uv": [4.5, 11.5, 5.5, 12], "texture": "#1"}, + "west": {"uv": [7, 11.5, 7.5, 12], "texture": "#1"}, + "up": {"uv": [12.5, 5, 11.5, 4.5], "texture": "#1"}, + "down": {"uv": [12.5, 5, 11.5, 5.5], "texture": "#1"} + } + } + ], + "gui_light": "front", + "display": { + "thirdperson_righthand": { + "rotation": [45, 50, 85], + "translation": [-2, 0, 1.5], + "scale": [0.3, 0.3, 0.3] + }, + "thirdperson_lefthand": { + "rotation": [45, 50, 85], + "translation": [-2, 0, 1.5], + "scale": [0.3, 0.3, 0.3] + }, + "firstperson_righthand": { + "rotation": [0, 50, 85], + "translation": [0, 1.5, 0], + "scale": [0.5, 0.5, 0.5] + }, + "firstperson_lefthand": { + "rotation": [0, -130, -85], + "translation": [0, 1.5, 0], + "scale": [0.5, 0.5, 0.5] + }, + "ground": { + "translation": [0, 2, 0], + "scale": [0.5, 0.5, 0.5] + }, + "gui": { + "rotation": [90, 90, 0], + "scale": [0.8, 0.8, 0.8] + }, + "head": { + "rotation": [90, 90, 0], + "translation": [0, -12, 4.75], + "scale": [0.2, 0.2, 0.2] + }, + "fixed": { + "rotation": [-90, -90, 0], + "translation": [0, 0, -7] + } + }, + "groups": [ + { + "name": "c4", + "origin": [8, 0, 8], + "color": 0, + "children": [ + 0, + 1, + { + "name": "button_group", + "origin": [10, 3, 5], + "color": 0, + "children": [2] + }, + { + "name": "triggers", + "origin": [8, 0, 8], + "color": 0, + "children": [3, 4] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/models/displaysettings/c4.item.json b/src/main/resources/assets/superbwarfare/models/displaysettings/c4.item.json new file mode 100644 index 000000000..efd8c74b0 --- /dev/null +++ b/src/main/resources/assets/superbwarfare/models/displaysettings/c4.item.json @@ -0,0 +1,40 @@ +{ + "credit": "Made with Blockbench", + "parent": "builtin/entity", + "texture_size": [32,32], + "gui_light": "front", + "display": { + "thirdperson_righthand": { + "rotation": [45, 50, 85], + "translation": [-2, 0, 1.5], + "scale": [0.3, 0.3, 0.3] + }, + "thirdperson_lefthand": { + "rotation": [45, 50, 85], + "translation": [-2, 0, 1.5], + "scale": [0.3, 0.3, 0.3] + }, + "firstperson_righthand": { + "rotation": [0, 50, 85], + "translation": [0, 1.5, 0], + "scale": [0.5, 0.5, 0.5] + }, + "firstperson_lefthand": { + "rotation": [0, -130, -95], + "translation": [0, 1.5, 0], + "scale": [0.5, 0.5, 0.5] + }, + "ground": { + "rotation": [90, 0, 0], + "translation": [0, 0, 4], + "scale": [0.5, 0.5, 0.5] + }, + "gui": { + "rotation": [90, 90, 0] + }, + "fixed": { + "rotation": [-90, -90, 0], + "translation": [0, 0, -7] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/models/item/explosive_mine.json b/src/main/resources/assets/superbwarfare/models/item/explosive_mine.json new file mode 100644 index 000000000..396265aad --- /dev/null +++ b/src/main/resources/assets/superbwarfare/models/item/explosive_mine.json @@ -0,0 +1,7 @@ +{ + "parent": "superbwarfare:custom/c4", + "textures": { + "1": "superbwarfare:block/c4", + "particle": "superbwarfare:item/c4" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/textures/block/c4.png b/src/main/resources/assets/superbwarfare/textures/block/c4.png new file mode 100644 index 0000000000000000000000000000000000000000..5739bf11ec2b2d1e21aecfc48825b0fb102fb124 GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^TPd7gn)>y;Z12$bi|OFqCh;c5Q8+Qv{`W@hH*U7J|^EK3f!Z1K`jP+G^N?aP%Q z^Fkm&@#xkUKz>u=(M5bbQu7}tJh-~qyoYBCSEGCTV+jy=k|Qoy!f^NUfz|2x5{c7- z-!zDJTWz?sgrQ5uf!85WNri=PRfeGf5M;<%9qI5s+t7ZX!MZ^$utER##iNWb9DKZ< z*zb}EJ;j*Cu*sQW=N|Q?EVea2xV-u#J_tw@um?=x@Z_wDNjTt~a6r}}P~-u3R7&NS zDg8WbHY^ewrv@Ei2)b4K!>M6~MnmZ8Z{_O}pSm9jHL$7u+2j}%!_++QN?_CFBDN<2 z8%q5TWHFdkz5OG%r)?6;ktHtwCQI{PVPKxe;Vx_Ns)3Q6p-{P>Csk~+4locIJYD@< J);T3K0RU=Pd7gn)>y;Z12$bi|OFqCh;c5Q8+Qv{`W@hH*U7J|^EK3f!Z1K`jP+G^N?aP%Q z^Fkm&@#xkUKz>u=(M5bbQu7}tJh-~qyoYBCSEGCTV+jy=k|Qoy!f^NUfz|2x5{c7- z-!zDJTWz?sgrQ5uf!85WNri=PRfeGf5M;<%9qI5s+t7ZX!MZ^$utER##iNWb9DKZ< z*zb}EJ;j*Cu*sQW=N|Q?EVea2xV-u#J_tw@um?=x@Z_wDNjTt~a6r}}P~-u3R7&NS zDg8WbHY^ewrv@Ei2)b4K!>M6~MnmZ8Z{_O}pSm9jHL$7u+2j}%!_++QN?_CFBDN<2 z8%q5TWHFdkz5OG%r)?6;ktHtwCQI{PVPKxe;Vx_Ns)3Q6p-{P>Csk~+4locIJYD@< J);T3K0RU=-xgid0Vc9vL#T8&Ke3>3^F!MK2mUGp0s36#ivdW1`tm zxWKugRpk1j=10FcdG_|QN|@LkKgghM&8^J5*6G3f$wq7-kTz4ViElx*R6=TcVoRjo zM&>GM?hTigFm%Z{@Hzx4sj$4;VP$9l1Q~KxM>@REHnbmTux?NbWH?=?wR<7cn;mNx zW=b_Q-nak%$6b7}mnBeF8Hd93?@OjE2olZIuuMAOoNz!EWRmKO!bV2^M#gdm*T4q- zjEPS#2HP1)d=N-D66Phy?2-BXAvfcqMGRqUSG~E{J~ckZzVYG9)8agr9tlZ&S<)vo zXPU7>yMv1xYZ&u}i`mb=KQNu5^5OUM`Tw7|F`FJ}P(KvN-eZ+;fRTZ(tJfrE-{yQ^ PSTcCJ`njxgN@xNAc&d=D literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/superbwarfare/textures/item/c4.png b/src/main/resources/assets/superbwarfare/textures/item/c4.png new file mode 100644 index 0000000000000000000000000000000000000000..5739bf11ec2b2d1e21aecfc48825b0fb102fb124 GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^TPd7gn)>y;Z12$bi|OFqCh;c5Q8+Qv{`W@hH*U7J|^EK3f!Z1K`jP+G^N?aP%Q z^Fkm&@#xkUKz>u=(M5bbQu7}tJh-~qyoYBCSEGCTV+jy=k|Qoy!f^NUfz|2x5{c7- z-!zDJTWz?sgrQ5uf!85WNri=PRfeGf5M;<%9qI5s+t7ZX!MZ^$utER##iNWb9DKZ< z*zb}EJ;j*Cu*sQW=N|Q?EVea2xV-u#J_tw@um?=x@Z_wDNjTt~a6r}}P~-u3R7&NS zDg8WbHY^ewrv@Ei2)b4K!>M6~MnmZ8Z{_O}pSm9jHL$7u+2j}%!_++QN?_CFBDN<2 z8%q5TWHFdkz5OG%r)?6;ktHtwCQI{PVPKxe;Vx_Ns)3Q6p-{P>Csk~+4locIJYD@< J);T3K0RU=