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.SoundEvent
import net.minecraft.sounds.SoundEvents import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource import net.minecraft.sounds.SoundSource
import net.minecraft.tags.ItemTags
import net.minecraft.util.Mth import net.minecraft.util.Mth
import net.minecraft.world.BossEvent import net.minecraft.world.BossEvent
import net.minecraft.world.damagesource.DamageSource 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.npc.Villager
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.entity.projectile.SmallFireball 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.level.Level
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
import ru.dbotthepony.mc.otm.registry.game.MSoundEvents 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, RammingGoal(this))
goalSelector.addGoal(2, StayNearGoal(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)) 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) { private fun shootMissile(math: Float) {
if (level().isClientSide) return if (level().isClientSide) return
//idea: make it fire 3 rockets that fall onto the ground instead of just straight/homing missiles/rockets val offset_dist = 1.2
//TODO
val offset_dist = 1.4
val viewVector = this.getViewVector(1.0F).normalize() val viewVector = this.getViewVector(1.0F).normalize()
val leftVec = Vec3(-viewVector.z, 0.0, viewVector.x).normalize().scale(offset_dist) val leftVec = Vec3(-viewVector.z, 0.0, viewVector.x).normalize().scale(offset_dist)
val gun_x = x + leftVec.x val gun_x = x + leftVec.x
val gun_z = z + leftVec.z val gun_z = z + leftVec.z
val gun_y = y + 1.2 val gun_y = y + 2.2
//stfu idea i like my underscores //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 missileY = gun_y
val missileZ = gun_z val missileZ = gun_z
val fireball = SmallFireball(level(), missileX, missileY, missileZ, viewVector) val rocket1 = RocketProjectile(level())
fireball.shootFromRotation(this, this.xRot, this.yHeadRot, 0.0F, 1.5F, 0.2F) val rocket2 = RocketProjectile(level())
fireball.setPos(missileX, missileY, missileZ) val rocket3 = RocketProjectile(level())
fireball.owner = this
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 //charge attack
@ -300,11 +314,20 @@ class Enforcer(type: EntityType<Enforcer>, level: Level) : Monster(type,level) {
val knockbackStrength = 1.5 val knockbackStrength = 1.5
val knockback = dir.scale(knockbackStrength) val knockback = dir.scale(knockbackStrength)
target.push(knockback.x, 0.5, knockback.z)
val damageAmount = 14.0f val damageAmount = 14.0f
target.hurt(mob.damageSources().mobAttack(mob), damageAmount) 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() stop()
} }
} }
@ -319,7 +342,7 @@ class Enforcer(type: EntityType<Enforcer>, level: Level) : Monster(type,level) {
} }
companion object { companion object {
private const val minCooldown = 35 private const val minCooldown = 50
private const val maxCooldown = 60 private const val maxCooldown = 60
private const val windupTime = 20 private const val windupTime = 20
private const val maxChargeTime = 40 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 cooldown = 0
private var rocketcooldown = 0
private val tickList = TickList() private val tickList = TickList()
init { 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() 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 val SHOOT_AT = intArrayOf(5, 7, 9)
private const val MIN_COOLDOWN = 5 private const val MIN_COOLDOWN = 5
private const val MAX_COOLDOWN = 15 private const val MAX_COOLDOWN = 15
private const val ROCKET_COOLDOWN = 20
private const val CYCLE_LENGTH = 20 private const val CYCLE_LENGTH = 20
} }
} }

View File

@ -1,88 +1,57 @@
package ru.dbotthepony.mc.otm.entity package ru.dbotthepony.mc.otm.entity
import net.minecraft.core.particles.ParticleTypes import net.minecraft.core.particles.ParticleTypes
import net.minecraft.network.syncher.SynchedEntityData import net.minecraft.sounds.SoundEvent
import net.minecraft.world.damagesource.DamageTypes import net.minecraft.sounds.SoundEvents
import net.minecraft.world.entity.projectile.Projectile import net.minecraft.world.entity.projectile.AbstractArrow
import net.minecraft.world.entity.projectile.ProjectileUtil
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.phys.BlockHitResult import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.EntityHitResult 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.game.MEntityTypes
import ru.dbotthepony.mc.otm.registry.MatteryDamageSource
import ru.dbotthepony.mc.otm.util.damageType
class RocketProjectile(level: Level) : Projectile(MEntityTypes.PLASMA, level) { class RocketProjectile(level: Level) : AbstractArrow(MEntityTypes.ROCKET, level) {
var inflictor: ItemStack? = null
var damage = 6.0f
var ttl = 200
override fun defineSynchedData(p_326003_: SynchedEntityData.Builder) { init {
setBaseDamage(5.0)
} setCritArrow(false)
pickup = Pickup.DISALLOWED
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_)
} }
override fun tick() { override fun tick() {
if (--ttl <= 0) { if (!inGround) deltaMovement = deltaMovement.add(0.0, -0.05, 0.0)
discard()
return
}
super.tick() super.tick()
if (level().isClientSide) {
val trace = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity) level().addParticle(ParticleTypes.CAMPFIRE_COSY_SMOKE, xOld, yOld, zOld, 0.0, 0.0, 0.0)
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 (trace.type != HitResult.Type.MISS && !EventHooks.onProjectileImpact(this, trace)) { override fun onHitEntity(result: EntityHitResult) {
onHit(trace) 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 //asdasdadad
val y = y + deltaMovement.y override fun playSound(sound: SoundEvent, volume: Float, pitch: Float) {
val z = z + deltaMovement.z if (sound != SoundEvents.ARROW_HIT) {
super.playSound(sound, volume, pitch)
}
}
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.fml.event.lifecycle.FMLClientSetupEvent
import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent
import ru.dbotthepony.mc.otm.client.render.entity.* 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.entity.*
import ru.dbotthepony.mc.otm.registry.MDeferredRegister import ru.dbotthepony.mc.otm.registry.MDeferredRegister
import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.registry.MNames
@ -119,6 +120,7 @@ object MEntityTypes {
private fun registerClient(event: FMLClientSetupEvent) { private fun registerClient(event: FMLClientSetupEvent) {
event.enqueueWork { event.enqueueWork {
EntityRenderers.register(PLASMA) { PlasmaProjectileRenderer(it) as EntityRenderer<Entity> } EntityRenderers.register(PLASMA) { PlasmaProjectileRenderer(it) as EntityRenderer<Entity> }
EntityRenderers.register(ROCKET) { RocketRenderer(it) as EntityRenderer<Entity> }
for (type in CARGO_CRATE_MINECARTS.values) { for (type in CARGO_CRATE_MINECARTS.values) {
EntityRenderers.register(type) { MinecartRenderer<MinecartCargoCrate>(it, ModelLayers.CHEST_MINECART) as EntityRenderer<Entity> } 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