Fixed DreamCampfireBlock not working with silk touch.
Added first draft of shellstone, water cannon, Toreterror, primordial armor
This commit is contained in:
1 parent
4fd9789e5c
commit
cacffab333
147 files changed
+3134
-20
No files matched your search
@@ -147,7 +147,7 @@ public final class AntarchySettings {
|
||||
private static boolean basiliskPetrifyingGazeEnabled = true;
|
||||
private static int basiliskSpawnMaxLightLevel = 5;
|
||||
private static double basiliskHealth = 150.0D;
|
||||
private static double basiliskAttackDamage = 8.0D;
|
||||
private static double basiliskAttackDamage = 36.0D;
|
||||
private static double basiliskMovementSpeed = 0.30D;
|
||||
private static double basiliskArmor = 6.0D;
|
||||
private static double basiliskKnockbackResistance = 0.5D;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.craisinlord.antarchy.content;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.entity.MissileSquidEntity;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Position;
|
||||
import net.minecraft.core.dispenser.BlockSource;
|
||||
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.level.block.DispenserBlock;
|
||||
|
||||
public class SquidzookaDispenseBehavior extends DefaultDispenseItemBehavior {
|
||||
@Override
|
||||
protected ItemStack execute(BlockSource source, ItemStack stack) {
|
||||
Direction direction = source.state().getValue(DispenserBlock.FACING);
|
||||
Position position = DispenserBlock.getDispensePosition(source);
|
||||
|
||||
MissileSquidEntity squid = AntarchyObjects.MISSILE_SQUID.get().create(source.level());
|
||||
if (squid == null) return super.execute(source, stack);
|
||||
|
||||
squid.setPos(position.x(), position.y(), position.z());
|
||||
Vec3 vel = new Vec3(direction.getStepX(), direction.getStepY(), direction.getStepZ())
|
||||
.normalize()
|
||||
.scale(AntarchySettings.squidzookaLaunchVelocity());
|
||||
squid.launchAsProjectile(null, vel);
|
||||
source.level().addFreshEntity(squid);
|
||||
|
||||
if (stack.isDamageableItem()) {
|
||||
int nextDamage = stack.getDamageValue() + 1;
|
||||
if (nextDamage >= stack.getMaxDamage()) {
|
||||
stack.shrink(1);
|
||||
} else {
|
||||
stack.setDamageValue(nextDamage);
|
||||
}
|
||||
} else {
|
||||
stack.shrink(1);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.craisinlord.antarchy.content;
|
||||
|
||||
import com.craisinlord.antarchy.content.entity.WaterBombEntity;
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Position;
|
||||
import net.minecraft.core.dispenser.BlockSource;
|
||||
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.DispenserBlock;
|
||||
|
||||
public class WaterCannonDispenseBehavior extends DefaultDispenseItemBehavior {
|
||||
@Override
|
||||
protected ItemStack execute(BlockSource source, ItemStack stack) {
|
||||
Direction direction = source.state().getValue(DispenserBlock.FACING);
|
||||
Position position = DispenserBlock.getDispensePosition(source);
|
||||
|
||||
WaterBombEntity bomb = AntarchyObjects.WATER_BOMB.get().create(source.level());
|
||||
if (bomb == null) return super.execute(source, stack);
|
||||
bomb.setPos(position.x(), position.y(), position.z());
|
||||
bomb.shoot(direction.getStepX(), direction.getStepY() + 0.1D, direction.getStepZ(), 1.5F, 0.0F);
|
||||
source.level().addFreshEntity(bomb);
|
||||
|
||||
if (stack.isDamageableItem()) {
|
||||
int nextDamage = stack.getDamageValue() + 1;
|
||||
if (nextDamage >= stack.getMaxDamage()) {
|
||||
stack.shrink(1);
|
||||
} else {
|
||||
stack.setDamageValue(nextDamage);
|
||||
}
|
||||
} else {
|
||||
stack.shrink(1);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.craisinlord.antarchy.content.client.model;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.entity.ToreterrorEntity;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import software.bernie.geckolib.model.GeoModel;
|
||||
|
||||
public class ToreterrorModel extends GeoModel<ToreterrorEntity> {
|
||||
|
||||
@Override
|
||||
public ResourceLocation getModelResource(ToreterrorEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/toreterror.geo.json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTextureResource(ToreterrorEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/toreterror.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getAnimationResource(ToreterrorEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/toreterror.animation.json");
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.craisinlord.antarchy.content.client.renderer;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.model.ToreterrorModel;
|
||||
import com.craisinlord.antarchy.content.entity.ToreterrorEntity;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||
|
||||
public class ToreterrorRenderer extends GeoEntityRenderer<ToreterrorEntity> {
|
||||
|
||||
public ToreterrorRenderer(EntityRendererProvider.Context context) {
|
||||
super(context, new ToreterrorModel());
|
||||
this.shadowRadius = 2.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getDeathMaxRotation(ToreterrorEntity animatable) {
|
||||
return 0.0F;
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.craisinlord.antarchy.content.client.renderer;
|
||||
|
||||
import com.craisinlord.antarchy.content.entity.WaterBombEntity;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
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.core.BlockPos;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
public class WaterBombRenderer extends EntityRenderer<WaterBombEntity> {
|
||||
|
||||
private static final ResourceLocation WATER_TEXTURE = ResourceLocation.withDefaultNamespace("textures/block/water_still.png");
|
||||
|
||||
public WaterBombRenderer(EntityRendererProvider.Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getBlockLightLevel(WaterBombEntity entity, BlockPos pos) {
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(WaterBombEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight) {
|
||||
poseStack.pushPose();
|
||||
poseStack.mulPose(this.entityRenderDispatcher.cameraOrientation());
|
||||
poseStack.scale(0.5F, 0.5F, 0.5F);
|
||||
|
||||
VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityTranslucent(WATER_TEXTURE));
|
||||
PoseStack.Pose pose = poseStack.last();
|
||||
Matrix4f matrix4f = pose.pose();
|
||||
addVertex(vertexConsumer, pose, matrix4f, -0.5F, -0.5F, 0.0F, 1.0F, packedLight);
|
||||
addVertex(vertexConsumer, pose, matrix4f, 0.5F, -0.5F, 1.0F, 1.0F, packedLight);
|
||||
addVertex(vertexConsumer, pose, matrix4f, 0.5F, 0.5F, 1.0F, 0.0F, packedLight);
|
||||
addVertex(vertexConsumer, pose, matrix4f, -0.5F, 0.5F, 0.0F, 0.0F, packedLight);
|
||||
|
||||
poseStack.popPose();
|
||||
super.render(entity, entityYaw, partialTick, poseStack, buffer, packedLight);
|
||||
}
|
||||
|
||||
private static void addVertex(VertexConsumer vertexConsumer, PoseStack.Pose pose, Matrix4f matrix4f,
|
||||
float x, float y, float u, float v, int packedLight) {
|
||||
vertexConsumer.addVertex(matrix4f, x, y, 0.0F)
|
||||
.setColor(0.05F, 0.15F, 0.6F, 0.9F)
|
||||
.setUv(u, v)
|
||||
.setOverlay(OverlayTexture.NO_OVERLAY)
|
||||
.setLight(packedLight)
|
||||
.setNormal(pose, 0.0F, 0.0F, 1.0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTextureLocation(WaterBombEntity entity) {
|
||||
return WATER_TEXTURE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,514 @@
|
||||
package com.craisinlord.antarchy.content.entity;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.server.level.ServerBossEvent;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.world.BossEvent;
|
||||
import net.minecraft.world.Difficulty;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.MobSpawnType;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.entity.ai.goal.Goal;
|
||||
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
||||
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
||||
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
|
||||
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
|
||||
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
|
||||
import net.minecraft.world.entity.monster.Monster;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.ServerLevelAccessor;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import software.bernie.geckolib.animatable.GeoEntity;
|
||||
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||
import software.bernie.geckolib.animation.AnimatableManager;
|
||||
import software.bernie.geckolib.animation.AnimationController;
|
||||
import software.bernie.geckolib.animation.AnimationState;
|
||||
import software.bernie.geckolib.animation.PlayState;
|
||||
import software.bernie.geckolib.animation.RawAnimation;
|
||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ToreterrorEntity extends Monster implements GeoEntity {
|
||||
|
||||
private static final EntityDataAccessor<Integer> ANIMATION_STATE = SynchedEntityData.defineId(ToreterrorEntity.class, EntityDataSerializers.INT);
|
||||
|
||||
private static final int ANIM_IDLE = 0;
|
||||
private static final int ANIM_WALK = 1;
|
||||
private static final int ANIM_SHOOT = 2;
|
||||
private static final int ANIM_JUMP_ATTACK = 3;
|
||||
private static final int ANIM_SPIN = 4;
|
||||
private static final int ANIM_DEATH = 5;
|
||||
|
||||
private static final int DEATH_TICKS = 60;
|
||||
private static final int SHOOT_TOTAL_TICKS = 80;
|
||||
private static final int SHOOT_FIRE_START_TICK = 12;
|
||||
private static final int SHOOT_FIRE_END_TICK = 68;
|
||||
private static final int SHOOT_FIRE_INTERVAL = 8;
|
||||
private static final int SHOOT_BOMBER_TICK = 12;
|
||||
private static final int JUMP_TOTAL_TICKS = 40;
|
||||
private static final int JUMP_LAUNCH_TICK = 10;
|
||||
private static final int SPIN_TOTAL_TICKS = 40;
|
||||
private static final int SPIN_START_TICK = 3;
|
||||
private static final int SPIN_END_TICK = 22;
|
||||
private static final int SPIN_HIT_INTERVAL = 5;
|
||||
|
||||
private static final double RANGED_MIN_RANGE_SQR = 9.0D;
|
||||
private static final double RANGED_MAX_RANGE_SQR = 625.0D;
|
||||
private static final double MELEE_RANGE_SQR = 9.0D;
|
||||
private static final double SPIN_RADIUS = 4.5D;
|
||||
private static final double JUMP_SHOCKWAVE_RADIUS = 6.0D;
|
||||
|
||||
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("Idle");
|
||||
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
|
||||
private static final RawAnimation SHOOT_ANIM = RawAnimation.begin().thenPlay("shoot").thenLoop("Idle");
|
||||
private static final RawAnimation JUMP_ANIM = RawAnimation.begin().thenPlay("jump_attack").thenLoop("Idle");
|
||||
private static final RawAnimation SPIN_ANIM = RawAnimation.begin().thenPlay("spin_attack").thenLoop("Idle");
|
||||
private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlayAndHold("death");
|
||||
|
||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||
private final ServerBossEvent bossEvent = new ServerBossEvent(Component.translatable("entity.antarchy.toreterror"), BossEvent.BossBarColor.GREEN, BossEvent.BossBarOverlay.PROGRESS);
|
||||
|
||||
private int shootAnimTicks;
|
||||
private int jumpAnimTicks;
|
||||
private int spinAnimTicks;
|
||||
private int shootCooldown;
|
||||
private int jumpCooldown;
|
||||
private int spinCooldown;
|
||||
private boolean jumpLaunched;
|
||||
private boolean shockwaveApplied;
|
||||
private boolean shootUseWaterBombs;
|
||||
private boolean shootBomberFired;
|
||||
private int shootNextFireElapsed;
|
||||
private final Map<UUID, Integer> spinHitCooldowns = new HashMap<>();
|
||||
|
||||
public ToreterrorEntity(EntityType<? extends ToreterrorEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
this.xpReward = 50;
|
||||
}
|
||||
|
||||
public static AttributeSupplier.Builder createAttributes() {
|
||||
return Mob.createMobAttributes()
|
||||
.add(Attributes.MAX_HEALTH, AntarchySettings.toreterrorHealth())
|
||||
.add(Attributes.ATTACK_DAMAGE, 8.0D)
|
||||
.add(Attributes.MOVEMENT_SPEED, 0.25D)
|
||||
.add(Attributes.FOLLOW_RANGE, 48.0D)
|
||||
.add(Attributes.KNOCKBACK_RESISTANCE, 0.85D)
|
||||
.add(Attributes.ARMOR, 10.0D);
|
||||
}
|
||||
|
||||
public static boolean canSpawn(EntityType<ToreterrorEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, net.minecraft.util.RandomSource random) {
|
||||
boolean sturdy = level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
|
||||
return level.getDifficulty() != Difficulty.PEACEFUL && sturdy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||
super.defineSynchedData(builder);
|
||||
builder.define(ANIMATION_STATE, ANIM_IDLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerGoals() {
|
||||
this.goalSelector.addGoal(1, new ToreterrorRangedGoal());
|
||||
this.goalSelector.addGoal(2, new ToreterrorJumpGoal());
|
||||
this.goalSelector.addGoal(3, new ToreterrorSpinGoal());
|
||||
this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 16.0F));
|
||||
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
|
||||
this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.6D));
|
||||
this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers());
|
||||
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::canTargetEntity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||
controllers.add(new AnimationController<>(this, "main_controller", 0, this::mainAnimController));
|
||||
}
|
||||
|
||||
private PlayState mainAnimController(AnimationState<ToreterrorEntity> state) {
|
||||
int animState = this.getAnimationState();
|
||||
return switch (animState) {
|
||||
case ANIM_WALK -> state.setAndContinue(WALK_ANIM);
|
||||
case ANIM_SHOOT -> state.setAndContinue(SHOOT_ANIM);
|
||||
case ANIM_JUMP_ATTACK -> state.setAndContinue(JUMP_ANIM);
|
||||
case ANIM_SPIN -> state.setAndContinue(SPIN_ANIM);
|
||||
case ANIM_DEATH -> state.setAndContinue(DEATH_ANIM);
|
||||
default -> state.setAndContinue(IDLE_ANIM);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||
return this.geoCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if (this.level().isClientSide) return;
|
||||
|
||||
if (this.shootCooldown > 0) this.shootCooldown--;
|
||||
if (this.jumpCooldown > 0) this.jumpCooldown--;
|
||||
if (this.spinCooldown > 0) this.spinCooldown--;
|
||||
|
||||
this.spinHitCooldowns.replaceAll((uuid, cd) -> cd - 1);
|
||||
this.spinHitCooldowns.entrySet().removeIf(e -> e.getValue() <= 0);
|
||||
|
||||
if (this.isDeadOrDying()) {
|
||||
this.setAnimationState(ANIM_DEATH);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.shootAnimTicks > 0) {
|
||||
this.tickShootAnimation();
|
||||
} else if (this.jumpAnimTicks > 0) {
|
||||
this.tickJumpAnimation();
|
||||
} else if (this.spinAnimTicks > 0) {
|
||||
this.tickSpinAnimation();
|
||||
} else {
|
||||
this.updateIdleAnimation();
|
||||
}
|
||||
|
||||
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSeenByPlayer(ServerPlayer player) {
|
||||
super.startSeenByPlayer(player);
|
||||
this.bossEvent.addPlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopSeenByPlayer(ServerPlayer player) {
|
||||
super.stopSeenByPlayer(player);
|
||||
this.bossEvent.removePlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkFallDamage(double y, boolean onGround, net.minecraft.world.level.block.state.BlockState state, BlockPos pos) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeWhenFarAway(double distanceToClosestPlayer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAdditionalSaveData(CompoundTag tag) {
|
||||
super.addAdditionalSaveData(tag);
|
||||
tag.putInt("AnimationState", this.getAnimationState());
|
||||
tag.putInt("ShootCooldown", this.shootCooldown);
|
||||
tag.putInt("JumpCooldown", this.jumpCooldown);
|
||||
tag.putInt("SpinCooldown", this.spinCooldown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readAdditionalSaveData(CompoundTag tag) {
|
||||
super.readAdditionalSaveData(tag);
|
||||
this.entityData.set(ANIMATION_STATE, tag.contains("AnimationState") ? tag.getInt("AnimationState") : ANIM_IDLE);
|
||||
this.shootCooldown = tag.getInt("ShootCooldown");
|
||||
this.jumpCooldown = tag.getInt("JumpCooldown");
|
||||
this.spinCooldown = tag.getInt("SpinCooldown");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die(DamageSource damageSource) {
|
||||
if (!this.level().isClientSide) {
|
||||
this.setAnimationState(ANIM_DEATH);
|
||||
this.shootAnimTicks = 0;
|
||||
this.jumpAnimTicks = 0;
|
||||
this.spinAnimTicks = 0;
|
||||
this.setDeltaMovement(Vec3.ZERO);
|
||||
this.getNavigation().stop();
|
||||
}
|
||||
super.die(damageSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tickDeath() {
|
||||
this.deathTime++;
|
||||
if (this.deathTime == 1) {
|
||||
this.setAnimationState(ANIM_DEATH);
|
||||
}
|
||||
if (this.deathTime >= DEATH_TICKS) {
|
||||
this.remove(RemovalReason.KILLED);
|
||||
this.dropExperience(this);
|
||||
}
|
||||
}
|
||||
|
||||
public int getAnimationState() {
|
||||
return this.entityData.get(ANIMATION_STATE);
|
||||
}
|
||||
|
||||
private void setAnimationState(int state) {
|
||||
if (this.entityData.get(ANIMATION_STATE) != state) {
|
||||
this.entityData.set(ANIMATION_STATE, state);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateIdleAnimation() {
|
||||
Vec3 vel = this.getDeltaMovement();
|
||||
boolean moving = (vel.x * vel.x + vel.z * vel.z) > 0.0004D;
|
||||
this.setAnimationState(moving ? ANIM_WALK : ANIM_IDLE);
|
||||
}
|
||||
|
||||
private boolean isInAttackAnimation() {
|
||||
return this.shootAnimTicks > 0 || this.jumpAnimTicks > 0 || this.spinAnimTicks > 0;
|
||||
}
|
||||
|
||||
private void tickShootAnimation() {
|
||||
this.setAnimationState(ANIM_SHOOT);
|
||||
int elapsed = SHOOT_TOTAL_TICKS - this.shootAnimTicks;
|
||||
if (this.shootUseWaterBombs) {
|
||||
if (elapsed >= this.shootNextFireElapsed && this.shootNextFireElapsed <= SHOOT_FIRE_END_TICK) {
|
||||
this.shootNextFireElapsed += SHOOT_FIRE_INTERVAL;
|
||||
this.fireWaterBomb();
|
||||
}
|
||||
} else {
|
||||
if (!this.shootBomberFired && elapsed >= SHOOT_BOMBER_TICK) {
|
||||
this.shootBomberFired = true;
|
||||
this.fireBomberBurst();
|
||||
}
|
||||
}
|
||||
this.getNavigation().stop();
|
||||
this.setDeltaMovement(this.getDeltaMovement().scale(0.85D));
|
||||
if (this.getTarget() != null) {
|
||||
this.getLookControl().setLookAt(this.getTarget(), 30.0F, 20.0F);
|
||||
}
|
||||
this.shootAnimTicks--;
|
||||
if (this.shootAnimTicks <= 0) {
|
||||
this.shootCooldown = 100 + this.random.nextInt(60);
|
||||
}
|
||||
}
|
||||
|
||||
private void tickJumpAnimation() {
|
||||
this.setAnimationState(ANIM_JUMP_ATTACK);
|
||||
int elapsed = JUMP_TOTAL_TICKS - this.jumpAnimTicks;
|
||||
if (!this.jumpLaunched && elapsed >= JUMP_LAUNCH_TICK) {
|
||||
this.jumpLaunched = true;
|
||||
LivingEntity target = this.getTarget();
|
||||
if (target != null) {
|
||||
Vec3 toTarget = target.position().subtract(this.position()).normalize();
|
||||
this.setDeltaMovement(toTarget.x * 0.6D, 0.85D, toTarget.z * 0.6D);
|
||||
this.hasImpulse = true;
|
||||
}
|
||||
}
|
||||
if (this.jumpLaunched && this.onGround() && elapsed > JUMP_LAUNCH_TICK + 3 && !this.shockwaveApplied) {
|
||||
this.shockwaveApplied = true;
|
||||
this.applyJumpShockwave();
|
||||
}
|
||||
this.jumpAnimTicks--;
|
||||
if (this.jumpAnimTicks <= 0) {
|
||||
this.jumpCooldown = 140 + this.random.nextInt(80);
|
||||
}
|
||||
}
|
||||
|
||||
private void tickSpinAnimation() {
|
||||
this.setAnimationState(ANIM_SPIN);
|
||||
int elapsed = SPIN_TOTAL_TICKS - this.spinAnimTicks;
|
||||
this.getNavigation().stop();
|
||||
this.setDeltaMovement(this.getDeltaMovement().multiply(0.7D, 1.0D, 0.7D));
|
||||
if (elapsed >= SPIN_START_TICK && elapsed <= SPIN_END_TICK && elapsed % SPIN_HIT_INTERVAL == 0) {
|
||||
this.applySpinDamage();
|
||||
}
|
||||
this.spinAnimTicks--;
|
||||
if (this.spinAnimTicks <= 0) {
|
||||
this.spinCooldown = 160 + this.random.nextInt(80);
|
||||
this.spinHitCooldowns.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void fireWaterBomb() {
|
||||
if (!(this.level() instanceof ServerLevel serverLevel)) return;
|
||||
LivingEntity target = this.getTarget();
|
||||
if (target == null) return;
|
||||
WaterBombEntity bomb = new WaterBombEntity(this.level(), this);
|
||||
bomb.moveTo(this.getX(), this.getEyeY(), this.getZ(), this.getYRot(), 0);
|
||||
bomb.shootFromRotation(this, this.getXRot(), this.getYRot(), 0.0F, 1.4F, 1.5F);
|
||||
serverLevel.addFreshEntity(bomb);
|
||||
}
|
||||
|
||||
private void fireBomberBurst() {
|
||||
if (!(this.level() instanceof ServerLevel serverLevel)) return;
|
||||
LivingEntity target = this.getTarget();
|
||||
if (target == null) return;
|
||||
int count = 3;
|
||||
for (int i = 0; i < count; i++) {
|
||||
BomberEntity bomber = AntarchyObjects.BOMBER.get().create(this.level());
|
||||
if (bomber == null) continue;
|
||||
double spreadAngle = (i - count / 2.0D) * 20.0D;
|
||||
double yaw = Math.toRadians(this.getYRot() + spreadAngle);
|
||||
double vx = -Math.sin(yaw) * 1.2D;
|
||||
double vy = 0.4D;
|
||||
double vz = Math.cos(yaw) * 1.2D;
|
||||
bomber.moveTo(this.getX() + vx * 0.5D, this.getEyeY(), this.getZ() + vz * 0.5D, this.getYRot(), 0);
|
||||
bomber.setDeltaMovement(vx, vy, vz);
|
||||
bomber.setTarget(target);
|
||||
serverLevel.addFreshEntity(bomber);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyJumpShockwave() {
|
||||
if (!(this.level() instanceof ServerLevel serverLevel)) return;
|
||||
AABB shockArea = this.getBoundingBox().inflate(JUMP_SHOCKWAVE_RADIUS, 2.0D, JUMP_SHOCKWAVE_RADIUS);
|
||||
List<LivingEntity> victims = this.level().getEntitiesOfClass(LivingEntity.class, shockArea, this::canTargetEntity);
|
||||
float damage = (float) AntarchySettings.toreterrorJumpAttackDamage();
|
||||
for (LivingEntity victim : victims) {
|
||||
victim.hurt(this.damageSources().mobAttack(this), damage);
|
||||
Vec3 knockDir = victim.position().subtract(this.position()).normalize().add(0, 0.4D, 0);
|
||||
double knockback = AntarchySettings.toreterrorJumpAttackKnockback();
|
||||
victim.push(knockDir.x * knockback, 0.5D, knockDir.z * knockback);
|
||||
victim.hurtMarked = true;
|
||||
}
|
||||
this.playSound(SoundEvents.GENERIC_EXPLODE.value(), 1.5F, 0.75F);
|
||||
serverLevel.sendParticles(net.minecraft.core.particles.ParticleTypes.EXPLOSION, this.getX(), this.getY() + 0.5D, this.getZ(), 3, 1.0D, 0.3D, 1.0D, 0.0D);
|
||||
serverLevel.sendParticles(net.minecraft.core.particles.ParticleTypes.SPLASH, this.getX(), this.getY() + 0.5D, this.getZ(), 40, 2.0D, 0.5D, 2.0D, 0.2D);
|
||||
}
|
||||
|
||||
private void applySpinDamage() {
|
||||
if (!(this.level() instanceof ServerLevel)) return;
|
||||
AABB spinArea = this.getBoundingBox().inflate(SPIN_RADIUS, 2.0D, SPIN_RADIUS);
|
||||
List<LivingEntity> victims = this.level().getEntitiesOfClass(LivingEntity.class, spinArea, this::canTargetEntity);
|
||||
float damage = (float) AntarchySettings.toreterrorSpinDamage();
|
||||
double knockback = AntarchySettings.toreterrorSpinKnockback();
|
||||
for (LivingEntity victim : victims) {
|
||||
UUID id = victim.getUUID();
|
||||
if (this.spinHitCooldowns.getOrDefault(id, 0) > 0) continue;
|
||||
if (victim.hurt(this.damageSources().mobAttack(this), damage)) {
|
||||
this.spinHitCooldowns.put(id, 20);
|
||||
Vec3 knockDir = victim.position().subtract(this.position()).normalize();
|
||||
victim.push(knockDir.x * knockback, 0.35D, knockDir.z * knockback);
|
||||
victim.hurtMarked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canTargetEntity(@Nullable LivingEntity entity) {
|
||||
if (entity == null || !entity.isAlive() || entity == this || entity.getType() == this.getType()) return false;
|
||||
if (entity instanceof Player player) {
|
||||
return !player.isCreative() && !player.isSpectator() && this.level().getDifficulty() != Difficulty.PEACEFUL;
|
||||
}
|
||||
return entity instanceof Mob && entity.isAttackable();
|
||||
}
|
||||
|
||||
private final class ToreterrorRangedGoal extends Goal {
|
||||
ToreterrorRangedGoal() {
|
||||
this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
LivingEntity target = ToreterrorEntity.this.getTarget();
|
||||
if (target == null || ToreterrorEntity.this.isInAttackAnimation()) return false;
|
||||
if (ToreterrorEntity.this.shootCooldown > 0) return false;
|
||||
double distSqr = ToreterrorEntity.this.distanceToSqr(target);
|
||||
return distSqr >= RANGED_MIN_RANGE_SQR && distSqr <= RANGED_MAX_RANGE_SQR
|
||||
&& ToreterrorEntity.this.hasLineOfSight(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
ToreterrorEntity.this.shootAnimTicks = SHOOT_TOTAL_TICKS;
|
||||
ToreterrorEntity.this.shootUseWaterBombs = ToreterrorEntity.this.random.nextFloat() < (float) AntarchySettings.toreterrorRangedWaterBombChance();
|
||||
ToreterrorEntity.this.shootNextFireElapsed = SHOOT_FIRE_START_TICK;
|
||||
ToreterrorEntity.this.shootBomberFired = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canContinueToUse() {
|
||||
return ToreterrorEntity.this.shootAnimTicks > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
ToreterrorEntity.this.shootAnimTicks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private final class ToreterrorJumpGoal extends Goal {
|
||||
ToreterrorJumpGoal() {
|
||||
this.setFlags(EnumSet.of(Flag.MOVE, Flag.JUMP));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
LivingEntity target = ToreterrorEntity.this.getTarget();
|
||||
if (target == null || ToreterrorEntity.this.isInAttackAnimation()) return false;
|
||||
if (ToreterrorEntity.this.jumpCooldown > 0) return false;
|
||||
double distSqr = ToreterrorEntity.this.distanceToSqr(target);
|
||||
return distSqr <= RANGED_MAX_RANGE_SQR && ToreterrorEntity.this.onGround();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
ToreterrorEntity.this.jumpAnimTicks = JUMP_TOTAL_TICKS;
|
||||
ToreterrorEntity.this.jumpLaunched = false;
|
||||
ToreterrorEntity.this.shockwaveApplied = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canContinueToUse() {
|
||||
return ToreterrorEntity.this.jumpAnimTicks > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
ToreterrorEntity.this.jumpAnimTicks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private final class ToreterrorSpinGoal extends Goal {
|
||||
ToreterrorSpinGoal() {
|
||||
this.setFlags(EnumSet.of(Flag.MOVE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
LivingEntity target = ToreterrorEntity.this.getTarget();
|
||||
if (target == null || ToreterrorEntity.this.isInAttackAnimation()) return false;
|
||||
if (ToreterrorEntity.this.spinCooldown > 0) return false;
|
||||
return ToreterrorEntity.this.distanceToSqr(target) <= MELEE_RANGE_SQR && ToreterrorEntity.this.onGround();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
ToreterrorEntity.this.spinAnimTicks = SPIN_TOTAL_TICKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canContinueToUse() {
|
||||
return ToreterrorEntity.this.spinAnimTicks > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
ToreterrorEntity.this.spinAnimTicks = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.craisinlord.antarchy.content.entity;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.ThrowableProjectile;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class WaterBombEntity extends ThrowableProjectile {
|
||||
|
||||
private int lifetimeTicks;
|
||||
private final Map<UUID, Integer> hitCooldowns = new HashMap<>();
|
||||
|
||||
public WaterBombEntity(EntityType<? extends WaterBombEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
this.lifetimeTicks = AntarchySettings.waterBombLifetimeTicks();
|
||||
}
|
||||
|
||||
public WaterBombEntity(Level level, LivingEntity owner) {
|
||||
super(AntarchyObjects.WATER_BOMB.get(), owner, level);
|
||||
this.lifetimeTicks = AntarchySettings.waterBombLifetimeTicks();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double getDefaultGravity() {
|
||||
return AntarchySettings.waterBombGravity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
this.hitCooldowns.replaceAll((uuid, cd) -> cd - 1);
|
||||
this.hitCooldowns.entrySet().removeIf(e -> e.getValue() <= 0);
|
||||
|
||||
if (this.level() instanceof ServerLevel serverLevel) {
|
||||
serverLevel.sendParticles(ParticleTypes.DRIPPING_WATER, this.getX(), this.getY(), this.getZ(), 3, 0.15D, 0.15D, 0.15D, 0.0D);
|
||||
serverLevel.sendParticles(ParticleTypes.SPLASH, this.getX(), this.getY(), this.getZ(), 2, 0.1D, 0.1D, 0.1D, 0.01D);
|
||||
}
|
||||
|
||||
this.lifetimeTicks--;
|
||||
if (this.lifetimeTicks <= 0) {
|
||||
this.discard();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHitEntity(EntityHitResult result) {
|
||||
Entity entity = result.getEntity();
|
||||
if (entity == this.getOwner()) return;
|
||||
if (!(entity instanceof LivingEntity living)) return;
|
||||
|
||||
UUID id = entity.getUUID();
|
||||
if (this.hitCooldowns.getOrDefault(id, 0) > 0) return;
|
||||
|
||||
float damage = (float) AntarchySettings.waterBombDamage();
|
||||
if (living.hurt(this.damageSources().thrown(this, this.getOwner()), damage)) {
|
||||
this.hitCooldowns.put(id, 15);
|
||||
Vec3 knockDir = living.position().subtract(this.position()).normalize();
|
||||
double knockback = AntarchySettings.waterBombKnockback();
|
||||
living.push(knockDir.x * knockback, 0.3D, knockDir.z * knockback);
|
||||
living.hurtMarked = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHitBlock(BlockHitResult result) {
|
||||
BlockPos hitPos = result.getBlockPos().relative(result.getDirection());
|
||||
Level level = this.level();
|
||||
if (level.isEmptyBlock(hitPos) && level.getBlockState(hitPos.below()).isSolid()) {
|
||||
level.setBlock(hitPos, Blocks.WATER.defaultBlockState().setValue(LiquidBlock.LEVEL, 2), 3);
|
||||
level.scheduleTick(hitPos, Fluids.WATER, 2);
|
||||
}
|
||||
this.discard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAdditionalSaveData(CompoundTag tag) {
|
||||
super.addAdditionalSaveData(tag);
|
||||
tag.putInt("LifetimeTicks", this.lifetimeTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readAdditionalSaveData(CompoundTag tag) {
|
||||
super.readAdditionalSaveData(tag);
|
||||
this.lifetimeTicks = tag.contains("LifetimeTicks") ? tag.getInt("LifetimeTicks") : AntarchySettings.waterBombLifetimeTicks();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.craisinlord.antarchy.content.item;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.world.item.ArmorItem;
|
||||
import net.minecraft.world.item.ArmorMaterial;
|
||||
|
||||
public class PrimordialArmorItem extends ArmorItem {
|
||||
|
||||
public PrimordialArmorItem(Holder<ArmorMaterial> material, Type type, Properties properties) {
|
||||
super(material, type, properties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package com.craisinlord.antarchy.content.item;
|
||||
|
||||
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||
import com.craisinlord.antarchy.content.client.model.ResourceBackedGeoItemModel;
|
||||
import com.craisinlord.antarchy.content.entity.WaterBombEntity;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.stats.Stats;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.projectile.Projectile;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.ProjectileWeaponItem;
|
||||
import net.minecraft.world.item.UseAnim;
|
||||
import net.minecraft.world.level.Level;
|
||||
import software.bernie.geckolib.animatable.GeoItem;
|
||||
import software.bernie.geckolib.animatable.client.GeoRenderProvider;
|
||||
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||
import software.bernie.geckolib.animation.AnimatableManager;
|
||||
import software.bernie.geckolib.animation.AnimationController;
|
||||
import software.bernie.geckolib.animation.PlayState;
|
||||
import software.bernie.geckolib.animation.RawAnimation;
|
||||
import com.craisinlord.antarchy.content.client.renderer.AnimatedHeldItemRenderer;
|
||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class WaterCannonItem extends ProjectileWeaponItem implements GeoItem {
|
||||
|
||||
private static final String FIRE_CONTROLLER = "fire_controller";
|
||||
private static final String FIRE_ANIMATION = "water_cannon_fire";
|
||||
private static final Predicate<ItemStack> NO_PROJECTILES = stack -> false;
|
||||
private static final int FIRE_INTERVAL_TICKS = 8;
|
||||
private static final ResourceLocation MODEL_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "geo/water_cannon.geo.json");
|
||||
private static final ResourceLocation TEXTURE_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/models/item/water_cannon.png");
|
||||
private static final ResourceLocation ANIMATION_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "animations/water_cannon.animation.json");
|
||||
|
||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||
|
||||
public WaterCannonItem(Properties properties) {
|
||||
super(properties);
|
||||
GeoItem.registerSyncedAnimatable(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUseDuration(ItemStack stack, LivingEntity entity) {
|
||||
return 72000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand usedHand) {
|
||||
player.startUsingItem(usedHand);
|
||||
return InteractionResultHolder.consume(player.getItemInHand(usedHand));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUseTick(Level level, LivingEntity livingEntity, ItemStack stack, int remainingUseTicks) {
|
||||
if (!(livingEntity instanceof Player player)) return;
|
||||
int usedTicks = getUseDuration(stack, livingEntity) - remainingUseTicks;
|
||||
if (usedTicks % FIRE_INTERVAL_TICKS != 0) return;
|
||||
|
||||
level.playSound(null, player.getX(), player.getY(), player.getZ(),
|
||||
AntarchySoundEvents.SQUIDZOOKA_FIRE.get(), SoundSource.PLAYERS,
|
||||
0.8F, 0.9F + level.getRandom().nextFloat() * 0.2F);
|
||||
|
||||
if (!level.isClientSide()) {
|
||||
WaterBombEntity bomb = new WaterBombEntity(level, player);
|
||||
bomb.moveTo(player.getX(), player.getEyeY() - 0.1D, player.getZ(), player.getYRot(), player.getXRot());
|
||||
bomb.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F);
|
||||
level.addFreshEntity(bomb);
|
||||
stack.hurtAndBreak(1, player, player.getUsedItemHand() == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND);
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
triggerFireAnimation(serverLevel, player, stack);
|
||||
}
|
||||
}
|
||||
|
||||
player.awardStat(Stats.ITEM_USED.get(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public UseAnim getUseAnimation(ItemStack stack) {
|
||||
return UseAnim.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<ItemStack> getSupportedHeldProjectiles() {
|
||||
return NO_PROJECTILES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<ItemStack> getAllSupportedProjectiles() {
|
||||
return NO_PROJECTILES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultProjectileRange() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shootProjectile(LivingEntity livingEntity, Projectile projectile, int i, float velocity, float inaccuracy, float angle, LivingEntity target) {
|
||||
projectile.shootFromRotation(livingEntity, livingEntity.getXRot(), livingEntity.getYRot(), angle, velocity, inaccuracy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||
controllers.add(new AnimationController<>(this, FIRE_CONTROLLER, state -> PlayState.STOP)
|
||||
.triggerableAnim(FIRE_ANIMATION, RawAnimation.begin().thenPlay(FIRE_ANIMATION)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||
return this.geoCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createGeoRenderer(Consumer<GeoRenderProvider> consumer) {
|
||||
consumer.accept(new GeoRenderProvider() {
|
||||
private AnimatedHeldItemRenderer<WaterCannonItem> renderer;
|
||||
|
||||
@Override
|
||||
public net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer getGeoItemRenderer() {
|
||||
if (this.renderer == null) {
|
||||
this.renderer = new AnimatedHeldItemRenderer<>(new ResourceBackedGeoItemModel<>(MODEL_LOCATION, TEXTURE_LOCATION, ANIMATION_LOCATION));
|
||||
}
|
||||
return this.renderer;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void triggerFireAnimation(ServerLevel level, LivingEntity livingEntity, ItemStack stack) {
|
||||
long animatableId = GeoItem.getOrAssignId(stack, level);
|
||||
triggerAnim(livingEntity, animatableId, FIRE_CONTROLLER, FIRE_ANIMATION);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user