Enforcer rocket attack

This commit is contained in:
GearShocky 2025-04-04 03:36:54 +05:00
parent 2e354f5e84
commit 0a21a0432e
6 changed files with 185 additions and 80 deletions

View File

@ -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<RocketProjectile> {
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;
}
}

View File

@ -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<RocketProjectile>(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)
}
}

View File

@ -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<Enforcer>, 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<Enforcer>, 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<Enforcer>, 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<Enforcer>, 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<Enforcer>, 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<Enforcer>, 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<Enforcer>, 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<Enforcer>, 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
}
}

View File

@ -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()
if (level().isClientSide) {
level().addParticle(ParticleTypes.CAMPFIRE_COSY_SMOKE, xOld, yOld, zOld, 0.0, 0.0, 0.0)
}
}
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)
override fun onHitEntity(result: EntityHitResult) {
if (!level().isClientSide) {
level().explode(null, x, y, z, 2.0f, Level.ExplosionInteraction.NONE)
discard()
}
super.onHitEntity(result)
}
return
override fun onHitBlock(result: BlockHitResult) {
if (!level().isClientSide) {
level().explode(null, x, y, z, 2.0f, Level.ExplosionInteraction.NONE)
discard()
}
super.onHitBlock(result)
}
//asdasdadad
override fun playSound(sound: SoundEvent, volume: Float, pitch: Float) {
if (sound != SoundEvents.ARROW_HIT) {
super.playSound(sound, volume, pitch)
}
}
if (trace.type != HitResult.Type.MISS && !EventHooks.onProjectileImpact(this, trace)) {
onHit(trace)
}
checkInsideBlocks()
val x = x + deltaMovement.x
val y = y + deltaMovement.y
val z = z + deltaMovement.z
setPos(x, y, z)
override fun getDefaultPickupItem(): ItemStack {
return ItemStack.EMPTY
}
}

View File

@ -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<Entity> }
EntityRenderers.register(ROCKET) { RocketRenderer(it) as EntityRenderer<Entity> }
for (type in CARGO_CRATE_MINECARTS.values) {
EntityRenderers.register(type) { MinecartRenderer<MinecartCargoCrate>(it, ModelLayers.CHEST_MINECART) as EntityRenderer<Entity> }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

After

Width:  |  Height:  |  Size: 519 B