From 0a21a0432ede0dce8e040d3b1882fe8a05d37bbb Mon Sep 17 00:00:00 2001 From: GearShocky Date: Fri, 4 Apr 2025 03:36:54 +0500 Subject: [PATCH] Enforcer rocket attack --- .../otm/client/model/entity/RocketModel.java | 46 ++++++++ .../client/render/entity/RocketRenderer.kt | 51 +++++++++ .../ru/dbotthepony/mc/otm/entity/Enforcer.kt | 67 +++++++++--- .../mc/otm/entity/RocketProjectile.kt | 99 ++++++------------ .../mc/otm/registry/game/MEntityTypes.kt | 2 + .../textures/entity/missile.png | Bin 241 -> 519 bytes 6 files changed, 185 insertions(+), 80 deletions(-) create mode 100644 src/main/java/ru/dbotthepony/mc/otm/client/model/entity/RocketModel.java create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/RocketRenderer.kt diff --git a/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/RocketModel.java b/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/RocketModel.java new file mode 100644 index 000000000..fcfe31a9a --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/client/model/entity/RocketModel.java @@ -0,0 +1,46 @@ +package ru.dbotthepony.mc.otm.client.model.entity; + +import net.minecraft.client.model.HierarchicalModel; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; +import net.minecraft.world.entity.Entity; +import ru.dbotthepony.mc.otm.entity.RocketProjectile; +import ru.dbotthepony.mc.otm.registry.MNames; + +import static ru.dbotthepony.mc.otm.OverdriveThatMatters.loc; + +public class RocketModel extends HierarchicalModel { + public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(loc(MNames.ROCKET), "main"); + private final ModelPart mainPart; + + public RocketModel(ModelPart root) { + this.mainPart = root.getChild("bb_main"); + } + + public static LayerDefinition createBodyLayer() { + MeshDefinition meshDefinition = new MeshDefinition(); + PartDefinition partDefinition = meshDefinition.getRoot(); + + partDefinition.addOrReplaceChild( + "bb_main", + CubeListBuilder.create() + .texOffs(0, 0) + .addBox(-2.0F, -2.0F, -6.0F, 4.0F, 4.0F, 12.0F), + PartPose.offset(0.0F, 0.0F, 0.0F) + ); + + return LayerDefinition.create(meshDefinition, 32, 16); + } + + @Override + public void setupAnim(RocketProjectile entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + + } + + @Override + public ModelPart root() { + return mainPart; + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/RocketRenderer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/RocketRenderer.kt new file mode 100644 index 000000000..6b4aa5e00 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/entity/RocketRenderer.kt @@ -0,0 +1,51 @@ +package ru.dbotthepony.mc.otm.client.renderer.entity + +import com.mojang.blaze3d.vertex.PoseStack +import net.minecraft.client.model.geom.ModelPart +import net.minecraft.client.renderer.MultiBufferSource +import net.minecraft.client.renderer.RenderType +import net.minecraft.client.renderer.entity.EntityRenderer +import net.minecraft.client.renderer.entity.EntityRendererProvider +import net.minecraft.client.renderer.texture.OverlayTexture +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.phys.Vec3 +import ru.dbotthepony.mc.otm.OverdriveThatMatters.loc +import ru.dbotthepony.mc.otm.client.model.entity.RocketModel +import ru.dbotthepony.mc.otm.entity.RocketProjectile + +class RocketRenderer(context: EntityRendererProvider.Context) : EntityRenderer(context) { + + private val model: ModelPart = RocketModel.createBodyLayer().bakeRoot() + private val TEXTURE = loc("textures/entity/missile.png") + + override fun getTextureLocation(entity: RocketProjectile): ResourceLocation = TEXTURE + + override fun render( + entity: RocketProjectile, + yaw: Float, + partialTicks: Float, + poseStack: PoseStack, + buffer: MultiBufferSource, + packedLight: Int + ) { + poseStack.pushPose() + + val motion: Vec3 = entity.deltaMovement + val speed = motion.length() + + if (speed > 0) { + val yawRotation = Math.toDegrees(Math.atan2(motion.x, motion.z)).toFloat() + + val pitch = Math.toDegrees(-motion.y / speed).toFloat() + + poseStack.mulPose(com.mojang.math.Axis.YP.rotationDegrees(yawRotation)) + poseStack.mulPose(com.mojang.math.Axis.XP.rotationDegrees(pitch+ 180F)) + } + + val vertexConsumer = buffer.getBuffer(RenderType.entityCutout(TEXTURE)) + model.render(poseStack, vertexConsumer, 15728880, OverlayTexture.NO_OVERLAY) + + poseStack.popPose() + super.render(entity, yaw, partialTicks, poseStack, buffer, packedLight) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Enforcer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Enforcer.kt index b19114717..1d44d4ba7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Enforcer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Enforcer.kt @@ -10,6 +10,7 @@ import net.minecraft.server.level.ServerPlayer import net.minecraft.sounds.SoundEvent import net.minecraft.sounds.SoundEvents import net.minecraft.sounds.SoundSource +import net.minecraft.tags.ItemTags import net.minecraft.util.Mth import net.minecraft.world.BossEvent import net.minecraft.world.damagesource.DamageSource @@ -32,6 +33,8 @@ import net.minecraft.world.entity.monster.Zombie import net.minecraft.world.entity.npc.Villager import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.projectile.SmallFireball +import net.minecraft.world.item.Items +import net.minecraft.world.item.ShieldItem import net.minecraft.world.level.Level import net.minecraft.world.phys.Vec3 import ru.dbotthepony.mc.otm.registry.game.MSoundEvents @@ -89,7 +92,7 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { goalSelector.addGoal(2, RammingGoal(this)) goalSelector.addGoal(2, StayNearGoal(this)) - goalSelector.addGoal(2, BlazeFireballGoal(this)) + goalSelector.addGoal(2, EnforcerArsenalGoal(this)) goalSelector.addGoal(7, LookAtPlayerGoal(this, Player::class.java, 8f)) } @@ -168,16 +171,13 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { private fun shootMissile(math: Float) { if (level().isClientSide) return - //idea: make it fire 3 rockets that fall onto the ground instead of just straight/homing missiles/rockets - //TODO - - val offset_dist = 1.4 + val offset_dist = 1.2 val viewVector = this.getViewVector(1.0F).normalize() val leftVec = Vec3(-viewVector.z, 0.0, viewVector.x).normalize().scale(offset_dist) val gun_x = x + leftVec.x val gun_z = z + leftVec.z - val gun_y = y + 1.2 + val gun_y = y + 2.2 //stfu idea i like my underscores @@ -185,12 +185,26 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { val missileY = gun_y val missileZ = gun_z - val fireball = SmallFireball(level(), missileX, missileY, missileZ, viewVector) - fireball.shootFromRotation(this, this.xRot, this.yHeadRot, 0.0F, 1.5F, 0.2F) - fireball.setPos(missileX, missileY, missileZ) - fireball.owner = this + val rocket1 = RocketProjectile(level()) + val rocket2 = RocketProjectile(level()) + val rocket3 = RocketProjectile(level()) + + rocket1.setPos(missileX, missileY, missileZ) + rocket2.setPos(missileX, missileY, missileZ) + rocket3.setPos(missileX, missileY, missileZ) + + rocket1.shootFromRotation(this, this.xRot, this.yHeadRot, 0.0F, 1.2F, 0.4F) + rocket2.shootFromRotation(this, this.xRot-15, this.yHeadRot, 0.0F, 1.2F, 0.4F) + rocket3.shootFromRotation(this, this.xRot-30, this.yHeadRot, 0.0F, 1.2F, 0.4F) + + rocket1.owner = this + rocket2.owner = this + rocket3.owner = this + + level().addFreshEntity(rocket1) + level().addFreshEntity(rocket2) + level().addFreshEntity(rocket3) - level().addFreshEntity(fireball) } //charge attack @@ -300,11 +314,20 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { val knockbackStrength = 1.5 val knockback = dir.scale(knockbackStrength) - target.push(knockback.x, 0.5, knockback.z) - val damageAmount = 14.0f target.hurt(mob.damageSources().mobAttack(mob), damageAmount) + if (target is Player) { + val player = target as Player + + if (player.isBlocking) { + target.disableShield() + if (!player.level().isClientSide) { + mob.playSound(SoundEvents.ZOMBIE_BREAK_WOODEN_DOOR, 1.0f, 1.0f) + } + } + } + target.push(knockback.x, 0.5, knockback.z) stop() } } @@ -319,7 +342,7 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { } companion object { - private const val minCooldown = 35 + private const val minCooldown = 50 private const val maxCooldown = 60 private const val windupTime = 20 private const val maxChargeTime = 40 @@ -365,8 +388,10 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { } } - class BlazeFireballGoal(private val mob: Enforcer) : Goal() { + class EnforcerArsenalGoal(private val mob: Enforcer) : Goal() { private var cooldown = 0 + private var rocketcooldown = 0 + private val tickList = TickList() init { @@ -392,6 +417,15 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { } } + if (--rocketcooldown <= 0) { + rocketcooldown = ROCKET_COOLDOWN + Mth.nextInt(mob.random, MIN_COOLDOWN, MAX_COOLDOWN) + + + mob.shootMissile(0.5f) + mob.playSound(SoundEvents.WITHER_SHOOT, 1.0f, Mth.nextFloat(mob.random, 0.9f, 1.1f)) + + } + tickList.tick() } @@ -405,6 +439,9 @@ class Enforcer(type: EntityType, level: Level) : Monster(type,level) { private val SHOOT_AT = intArrayOf(5, 7, 9) private const val MIN_COOLDOWN = 5 private const val MAX_COOLDOWN = 15 + + private const val ROCKET_COOLDOWN = 20 + private const val CYCLE_LENGTH = 20 } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/RocketProjectile.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/RocketProjectile.kt index eac43e839..86e304a96 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/RocketProjectile.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/RocketProjectile.kt @@ -1,88 +1,57 @@ package ru.dbotthepony.mc.otm.entity import net.minecraft.core.particles.ParticleTypes -import net.minecraft.network.syncher.SynchedEntityData -import net.minecraft.world.damagesource.DamageTypes -import net.minecraft.world.entity.projectile.Projectile -import net.minecraft.world.entity.projectile.ProjectileUtil +import net.minecraft.sounds.SoundEvent +import net.minecraft.sounds.SoundEvents +import net.minecraft.world.entity.projectile.AbstractArrow import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level -import net.minecraft.world.level.block.Blocks import net.minecraft.world.phys.BlockHitResult import net.minecraft.world.phys.EntityHitResult -import net.minecraft.world.phys.HitResult -import net.neoforged.neoforge.event.EventHooks import ru.dbotthepony.mc.otm.registry.game.MEntityTypes -import ru.dbotthepony.mc.otm.registry.MatteryDamageSource -import ru.dbotthepony.mc.otm.util.damageType -class RocketProjectile(level: Level) : Projectile(MEntityTypes.PLASMA, level) { - var inflictor: ItemStack? = null - var damage = 6.0f - var ttl = 200 +class RocketProjectile(level: Level) : AbstractArrow(MEntityTypes.ROCKET, level) { - override fun defineSynchedData(p_326003_: SynchedEntityData.Builder) { - - } - - override fun onHit(p_37260_: HitResult) { - super.onHit(p_37260_) - - if (!level().isClientSide) { - discard() - } - } - - override fun onHitEntity(p_37259_: EntityHitResult) { - super.onHitEntity(p_37259_) - - if (!level().isClientSide) { - p_37259_.entity.hurt(MatteryDamageSource(level().registryAccess().damageType(DamageTypes.EXPLOSION), owner, inflictor), damage) - level().explode(this, x, y, z, 2.5f, Level.ExplosionInteraction.BLOCK) - } - } - - override fun onHitBlock(p_37258_: BlockHitResult) { - super.onHitBlock(p_37258_) + init { + setBaseDamage(5.0) + setCritArrow(false) + pickup = Pickup.DISALLOWED } override fun tick() { - if (--ttl <= 0) { - discard() - return - } + if (!inGround) deltaMovement = deltaMovement.add(0.0, -0.05, 0.0) super.tick() - - val trace = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity) - - if (trace.type == HitResult.Type.BLOCK) { - val pos = (trace as BlockHitResult).blockPos - val state = level().getBlockState(pos) - level().explode(this, x, y, z, 2.5f, Level.ExplosionInteraction.BLOCK) - - - if (state.`is`(Blocks.NETHER_PORTAL) || state.`is`(Blocks.END_GATEWAY)) { - onHitBlock(trace) - - // don't teleport plasma projectile - if (!level().isClientSide) - discard() - - return - } + if (level().isClientSide) { + level().addParticle(ParticleTypes.CAMPFIRE_COSY_SMOKE, xOld, yOld, zOld, 0.0, 0.0, 0.0) } + } - if (trace.type != HitResult.Type.MISS && !EventHooks.onProjectileImpact(this, trace)) { - onHit(trace) + override fun onHitEntity(result: EntityHitResult) { + if (!level().isClientSide) { + level().explode(null, x, y, z, 2.0f, Level.ExplosionInteraction.NONE) + discard() } + super.onHitEntity(result) + } - checkInsideBlocks() + override fun onHitBlock(result: BlockHitResult) { + if (!level().isClientSide) { + level().explode(null, x, y, z, 2.0f, Level.ExplosionInteraction.NONE) + discard() + } + super.onHitBlock(result) + } - val x = x + deltaMovement.x - val y = y + deltaMovement.y - val z = z + deltaMovement.z + //asdasdadad + override fun playSound(sound: SoundEvent, volume: Float, pitch: Float) { + if (sound != SoundEvents.ARROW_HIT) { + super.playSound(sound, volume, pitch) + } + } - setPos(x, y, z) + override fun getDefaultPickupItem(): ItemStack { + return ItemStack.EMPTY } } + diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MEntityTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MEntityTypes.kt index 16f23debb..8f012aaa9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MEntityTypes.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MEntityTypes.kt @@ -14,6 +14,7 @@ import net.neoforged.bus.api.IEventBus import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent import ru.dbotthepony.mc.otm.client.render.entity.* +import ru.dbotthepony.mc.otm.client.renderer.entity.RocketRenderer import ru.dbotthepony.mc.otm.entity.* import ru.dbotthepony.mc.otm.registry.MDeferredRegister import ru.dbotthepony.mc.otm.registry.MNames @@ -119,6 +120,7 @@ object MEntityTypes { private fun registerClient(event: FMLClientSetupEvent) { event.enqueueWork { EntityRenderers.register(PLASMA) { PlasmaProjectileRenderer(it) as EntityRenderer } + EntityRenderers.register(ROCKET) { RocketRenderer(it) as EntityRenderer } for (type in CARGO_CRATE_MINECARTS.values) { EntityRenderers.register(type) { MinecartRenderer(it, ModelLayers.CHEST_MINECART) as EntityRenderer } diff --git a/src/main/resources/assets/overdrive_that_matters/textures/entity/missile.png b/src/main/resources/assets/overdrive_that_matters/textures/entity/missile.png index 5ae8c9d32baf7997aa3be83a53b7a504d46e5c3f..064cd8338848622d01d768c5386c675e0cc6f17b 100644 GIT binary patch literal 519 zcmeAS@N?(olHy`uVBq!ia0vp^3P3Et!3-oF?)7E^DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheasfUeuEm9g_4V~}ad9_q-u(anf47In!jO<3cZ>f2mW2I`{)!E&m5;oe{v$~oL6o=GDYRSm5HL~q=nn>8SGLyDO(_^ z<~hll!*i3FL|u=lbD4m&Q9#EhhG!O)rALo9aJOpoTgo%%pVPCIT*qPeyz6bB#AAl* W`Mj~!IbE?J*Lb@6xvXfywOOpOgeaexw&MW-QJT2fPjJF Y*E-#)`F}1>0lJ&P)78&qol`;+05hdl4FCWD