rolly polly mob, rolly caves biome, toreterror sounds, alpha mantis turning revert, scorpion and cloud shark updates
This commit is contained in:
1 parent
9d34c45285
commit
303a56f7fc
65 files changed
+10746
-2647
No files matched your search
@@ -106,6 +106,11 @@ public final class AntarchySettings {
|
||||
private static double alphaMantisFlyingSpeed = 0.77D;
|
||||
private static int alphaMantisSummonIntervalTicks = 300;
|
||||
private static int alphaMantisMaxMinions = 4;
|
||||
private static double rollyPollyHealth = 12.0D;
|
||||
private static double rollyPollyMovementSpeed = 0.3D;
|
||||
private static double rollyPollyRollSpeedMultiplier = 2.2D;
|
||||
private static double rollyPollyTumbleDamage = 1.0D;
|
||||
private static int rollyPollyTameChance = 3;
|
||||
private static double krakenProjectileDamageTakenMultiplier = 0.5D;
|
||||
private static boolean krakenSquidSpawnEnabled = true;
|
||||
private static boolean krakenMassSpawnEnabled = true;
|
||||
@@ -233,23 +238,23 @@ public final class AntarchySettings {
|
||||
private static final int reverieAmbientTargetMaxAgeTicks = 40;
|
||||
private static final int reverieAmbientPulseIntervalMinTicks = 12;
|
||||
private static final int reverieAmbientPulseIntervalMaxTicks = 19;
|
||||
private static double emperorScorpionHealth = 100.0D;
|
||||
private static double emperorScorpionAttackDamage = 12.0D;
|
||||
private static double emperorScorpionHealth = 400.0D;
|
||||
private static double emperorScorpionAttackDamage = 28.0D;
|
||||
private static double emperorScorpionMovementSpeed = 0.32D;
|
||||
private static double emperorScorpionArmor = 6.0D;
|
||||
private static double emperorScorpionKnockbackResistance = 0.6D;
|
||||
private static double emperorScorpionFollowRange = 32.0D;
|
||||
private static double emperorScorpionArmor = 25.0D;
|
||||
private static double emperorScorpionKnockbackResistance = 0.8D;
|
||||
private static double emperorScorpionFollowRange = 40.0D;
|
||||
private static int emperorScorpionXpReward = 25;
|
||||
private static int emperorScorpionClawAnimTicks = 12;
|
||||
private static int emperorScorpionClawHitTick = 6;
|
||||
private static int emperorScorpionClawCooldownTicks = 16;
|
||||
private static int emperorScorpionStingAnimTicks = 18;
|
||||
private static int emperorScorpionStingHitTick = 9;
|
||||
private static int emperorScorpionStingCooldownTicks = 42;
|
||||
private static int emperorScorpionPoisonTicks = 100;
|
||||
private static int emperorScorpionWeaknessTicks = 80;
|
||||
private static int emperorScorpionSummonIntervalTicks = 180;
|
||||
private static int emperorScorpionMaxSummonedScorpions = 4;
|
||||
private static int emperorScorpionClawAnimTicks = 23;
|
||||
private static int emperorScorpionClawHitTick = 12;
|
||||
private static int emperorScorpionClawCooldownTicks = 28;
|
||||
private static int emperorScorpionStingAnimTicks = 25;
|
||||
private static int emperorScorpionStingHitTick = 13;
|
||||
private static int emperorScorpionStingCooldownTicks = 60;
|
||||
private static int emperorScorpionPoisonTicks = 300;
|
||||
private static int emperorScorpionWeaknessTicks = 120;
|
||||
private static int emperorScorpionSummonIntervalTicks = 140;
|
||||
private static int emperorScorpionMaxSummonedScorpions = 8;
|
||||
private static double scorpionHealth = 30.0D;
|
||||
private static double scorpionAttackDamage = 5.0D;
|
||||
private static double scorpionMovementSpeed = 0.29D;
|
||||
@@ -819,6 +824,26 @@ public final class AntarchySettings {
|
||||
return alphaMantisMaxMinions;
|
||||
}
|
||||
|
||||
public static double rollyPollyHealth() {
|
||||
return rollyPollyHealth;
|
||||
}
|
||||
|
||||
public static double rollyPollyMovementSpeed() {
|
||||
return rollyPollyMovementSpeed;
|
||||
}
|
||||
|
||||
public static double rollyPollyRollSpeedMultiplier() {
|
||||
return rollyPollyRollSpeedMultiplier;
|
||||
}
|
||||
|
||||
public static double rollyPollyTumbleDamage() {
|
||||
return rollyPollyTumbleDamage;
|
||||
}
|
||||
|
||||
public static int rollyPollyTameChance() {
|
||||
return rollyPollyTameChance;
|
||||
}
|
||||
|
||||
public static double waspHealth() {
|
||||
return waspHealth;
|
||||
}
|
||||
@@ -1247,6 +1272,26 @@ public final class AntarchySettings {
|
||||
alphaMantisMaxMinions = value;
|
||||
}
|
||||
|
||||
public static void setRollyPollyHealth(double value) {
|
||||
rollyPollyHealth = value;
|
||||
}
|
||||
|
||||
public static void setRollyPollyMovementSpeed(double value) {
|
||||
rollyPollyMovementSpeed = value;
|
||||
}
|
||||
|
||||
public static void setRollyPollyRollSpeedMultiplier(double value) {
|
||||
rollyPollyRollSpeedMultiplier = value;
|
||||
}
|
||||
|
||||
public static void setRollyPollyTumbleDamage(double value) {
|
||||
rollyPollyTumbleDamage = value;
|
||||
}
|
||||
|
||||
public static void setRollyPollyTameChance(int value) {
|
||||
rollyPollyTameChance = value;
|
||||
}
|
||||
|
||||
public static void setKrakenProjectileDamageTakenMultiplier(double value) {
|
||||
krakenProjectileDamageTakenMultiplier = value;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ public final class AntarchyTags {
|
||||
public static final TagKey<Item> BUTTERFLY_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("butterfly_breeding_foods"));
|
||||
public static final TagKey<Item> REVERIE_DUPLICATION_ITEMS = TagKey.create(Registries.ITEM, id("reverie_duplication_items"));
|
||||
public static final TagKey<Item> HERCULES_BEETLE_FOOD = TagKey.create(Registries.ITEM, id("hercules_beetle_food"));
|
||||
public static final TagKey<Item> ROLLY_POLLY_FOOD = TagKey.create(Registries.ITEM, id("rolly_polly_food"));
|
||||
|
||||
private Items() {
|
||||
}
|
||||
|
||||
+6
-1
@@ -6,6 +6,11 @@ import net.minecraft.resources.ResourceLocation;
|
||||
import software.bernie.geckolib.model.GeoModel;
|
||||
|
||||
public class CloudSharkModel extends GeoModel<CloudSharkEntity> {
|
||||
public static final ResourceLocation BASE_TEXTURE =
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/cloud_shark/cloud_shark.png");
|
||||
public static final ResourceLocation EMISSIVE_TEXTURE =
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/cloud_shark/cloud_shark_emissive.png");
|
||||
|
||||
@Override
|
||||
public ResourceLocation getModelResource(CloudSharkEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/cloud_shark.geo.json");
|
||||
@@ -13,7 +18,7 @@ public class CloudSharkModel extends GeoModel<CloudSharkEntity> {
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTextureResource(CloudSharkEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/cloud_shark.png");
|
||||
return BASE_TEXTURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-1
@@ -7,6 +7,9 @@ import software.bernie.geckolib.model.GeoModel;
|
||||
|
||||
public class EmperorScorpionModel extends GeoModel<EmperorScorpionEntity> {
|
||||
|
||||
public static final ResourceLocation EMISSIVE_TEXTURE =
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/emperor_scorpion/emperor_scorpion_emissive.png");
|
||||
|
||||
@Override
|
||||
public ResourceLocation getModelResource(EmperorScorpionEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/emperor_scorpion.geo.json");
|
||||
@@ -14,7 +17,7 @@ public class EmperorScorpionModel extends GeoModel<EmperorScorpionEntity> {
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTextureResource(EmperorScorpionEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/emperor_scorpion.png");
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/emperor_scorpion/emperor_scorpion.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.craisinlord.antarchy.content.client.model;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.entity.RollyPollyEntity;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import software.bernie.geckolib.model.GeoModel;
|
||||
|
||||
public class RollyPollyModel extends GeoModel<RollyPollyEntity> {
|
||||
private static final ResourceLocation TEXTURE =
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/rolly_polly/rolly_polly.png");
|
||||
private static final ResourceLocation TEXTURE_SADDLED =
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/rolly_polly/rolly_polly_saddled.png");
|
||||
|
||||
@Override
|
||||
public ResourceLocation getModelResource(RollyPollyEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/rolly_polly.geo.json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTextureResource(RollyPollyEntity animatable) {
|
||||
return animatable.hasSaddle() ? TEXTURE_SADDLED : TEXTURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getAnimationResource(RollyPollyEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/rolly_polly.animation.json");
|
||||
}
|
||||
}
|
||||
+41
@@ -2,8 +2,17 @@ package com.craisinlord.antarchy.content.client.renderer;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.model.CloudSharkModel;
|
||||
import com.craisinlord.antarchy.content.entity.cloud_shark.CloudSharkEntity;
|
||||
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.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
||||
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||
import software.bernie.geckolib.renderer.layer.GeoRenderLayer;
|
||||
|
||||
public class CloudSharkRenderer extends GeoEntityRenderer<CloudSharkEntity> {
|
||||
private static final float SHADOW_RADIUS = 0.6F;
|
||||
@@ -11,5 +20,37 @@ public class CloudSharkRenderer extends GeoEntityRenderer<CloudSharkEntity> {
|
||||
public CloudSharkRenderer(EntityRendererProvider.Context context) {
|
||||
super(context, new CloudSharkModel());
|
||||
this.shadowRadius = SHADOW_RADIUS;
|
||||
this.addRenderLayer(new CloudSharkEmissiveLayer(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderType getRenderType(CloudSharkEntity animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) {
|
||||
return RenderType.entityCutoutNoCull(texture);
|
||||
}
|
||||
|
||||
private static final class CloudSharkEmissiveLayer extends GeoRenderLayer<CloudSharkEntity> {
|
||||
private CloudSharkEmissiveLayer(GeoEntityRenderer<CloudSharkEntity> renderer) {
|
||||
super(renderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(PoseStack poseStack, CloudSharkEntity animatable, BakedGeoModel bakedModel, @Nullable RenderType renderType,
|
||||
MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, float partialTick,
|
||||
int packedLight, int packedOverlay) {
|
||||
RenderType emissiveType = RenderType.eyes(CloudSharkModel.EMISSIVE_TEXTURE);
|
||||
VertexConsumer emissiveBuffer = bufferSource.getBuffer(emissiveType);
|
||||
this.getRenderer().reRender(
|
||||
bakedModel,
|
||||
poseStack,
|
||||
bufferSource,
|
||||
animatable,
|
||||
emissiveType,
|
||||
emissiveBuffer,
|
||||
partialTick,
|
||||
0xF000F0,
|
||||
OverlayTexture.NO_OVERLAY,
|
||||
0xFFFFFFFF
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
-1
@@ -2,14 +2,59 @@ package com.craisinlord.antarchy.content.client.renderer;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.model.EmperorScorpionModel;
|
||||
import com.craisinlord.antarchy.content.entity.EmperorScorpionEntity;
|
||||
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.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
||||
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||
import software.bernie.geckolib.renderer.layer.GeoRenderLayer;
|
||||
|
||||
public class EmperorScorpionRenderer extends GeoEntityRenderer<EmperorScorpionEntity> {
|
||||
|
||||
public EmperorScorpionRenderer(EntityRendererProvider.Context context) {
|
||||
super(context, new EmperorScorpionModel());
|
||||
this.shadowRadius = 3.0F;
|
||||
this.withScale(1.5F);
|
||||
this.addRenderLayer(new EmperorScorpionEmissiveLayer(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderType getRenderType(EmperorScorpionEntity animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) {
|
||||
return RenderType.entityCutoutNoCull(texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getDeathMaxRotation(EmperorScorpionEntity animatable) {
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
private static final class EmperorScorpionEmissiveLayer extends GeoRenderLayer<EmperorScorpionEntity> {
|
||||
private EmperorScorpionEmissiveLayer(GeoEntityRenderer<EmperorScorpionEntity> renderer) {
|
||||
super(renderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(PoseStack poseStack, EmperorScorpionEntity animatable, BakedGeoModel bakedModel, @Nullable RenderType renderType,
|
||||
MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, float partialTick,
|
||||
int packedLight, int packedOverlay) {
|
||||
RenderType emissiveType = RenderType.eyes(EmperorScorpionModel.EMISSIVE_TEXTURE);
|
||||
VertexConsumer emissiveBuffer = bufferSource.getBuffer(emissiveType);
|
||||
this.getRenderer().reRender(
|
||||
bakedModel,
|
||||
poseStack,
|
||||
bufferSource,
|
||||
animatable,
|
||||
emissiveType,
|
||||
emissiveBuffer,
|
||||
partialTick,
|
||||
0xF000F0,
|
||||
OverlayTexture.NO_OVERLAY,
|
||||
0xFFFFFFFF
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.craisinlord.antarchy.content.client.renderer;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.model.RollyPollyModel;
|
||||
import com.craisinlord.antarchy.content.entity.RollyPollyEntity;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||
|
||||
public class RollyPollyRenderer extends GeoEntityRenderer<RollyPollyEntity> {
|
||||
public RollyPollyRenderer(EntityRendererProvider.Context context) {
|
||||
super(context, new RollyPollyModel());
|
||||
this.shadowRadius = 0.5F;
|
||||
}
|
||||
}
|
||||
+104
-51
@@ -48,40 +48,50 @@ import software.bernie.geckolib.animation.RawAnimation;
|
||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||
|
||||
public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
private static final byte CLAW_ATTACK_ANIM_EVENT = 4;
|
||||
private static final byte SNAP_ATTACK_ANIM_EVENT = 4;
|
||||
private static final byte STING_ATTACK_ANIM_EVENT = 5;
|
||||
private static final byte AGRO_ANIM_EVENT = 6;
|
||||
|
||||
private static final int CLAW_ATTACK_ANIM_TICKS = 12;
|
||||
private static final int CLAW_ATTACK_HIT_TICK = 6;
|
||||
private static final int CLAW_ATTACK_COOLDOWN_TICKS = 16;
|
||||
private static final int STING_ATTACK_ANIM_TICKS = 18;
|
||||
private static final int STING_ATTACK_HIT_TICK = 9;
|
||||
private static final int STING_ATTACK_COOLDOWN_TICKS = 42;
|
||||
private static final int POISON_DURATION_TICKS = 100;
|
||||
private static final int WEAKNESS_DURATION_TICKS = 80;
|
||||
private static final int SUMMON_INTERVAL_TICKS = 180;
|
||||
private static final int MAX_SUMMONED_SCORPIONS = 4;
|
||||
private static final int SNAP_ATTACK_ANIM_TICKS = 23;
|
||||
private static final int SNAP_ATTACK_HIT_TICK = 12;
|
||||
private static final int SNAP_ATTACK_COOLDOWN_TICKS = 28;
|
||||
private static final int STING_ATTACK_ANIM_TICKS = 25;
|
||||
private static final int STING_ATTACK_HIT_TICK = 13;
|
||||
private static final int STING_ATTACK_COOLDOWN_TICKS = 60;
|
||||
private static final int AGRO_ANIM_TICKS = 30;
|
||||
private static final int DEATH_ANIM_TICKS = 40;
|
||||
private static final float STING_DAMAGE = 18.0F;
|
||||
private static final double STING_AOE_RADIUS = 5.0D;
|
||||
private static final int POISON_DURATION_TICKS = 300;
|
||||
private static final int WEAKNESS_DURATION_TICKS = 120;
|
||||
private static final int SUMMON_INTERVAL_TICKS = 140;
|
||||
private static final int MAX_SUMMONED_SCORPIONS = 8;
|
||||
private static final String EMPEROR_SUMMON_TAG = "antarchy_emperor_summoned";
|
||||
|
||||
private static final ResourceKey<Level> THORAXIS_KEY =
|
||||
ResourceKey.create(Registries.DIMENSION,
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "thoraxis"));
|
||||
|
||||
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
||||
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
|
||||
private static final RawAnimation ATTACK_ANIM = RawAnimation.begin().thenPlay("attack");
|
||||
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
||||
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
|
||||
private static final RawAnimation SNAP_ANIM = RawAnimation.begin().thenPlay("snap");
|
||||
private static final RawAnimation STING_ANIM = RawAnimation.begin().thenPlay("sting");
|
||||
private static final RawAnimation AGRO_ANIM = RawAnimation.begin().thenPlay("agro");
|
||||
private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlay("death");
|
||||
|
||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||
private final ServerBossEvent bossEvent =
|
||||
new ServerBossEvent(this.getDisplayName(), BossEvent.BossBarColor.RED, BossEvent.BossBarOverlay.PROGRESS);
|
||||
new ServerBossEvent(this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS);
|
||||
|
||||
private int attackAnimTicks = 0;
|
||||
private int attackHitTick = 0;
|
||||
private int attackCooldownTicks = 0;
|
||||
private int stingCooldownTicks = 0;
|
||||
private int agroAnimTicks = 0;
|
||||
private int summonCooldown = 0;
|
||||
private boolean attackDamageApplied = false;
|
||||
private boolean stingAttackActive = false;
|
||||
private boolean hasAgroed = false;
|
||||
@Nullable private LivingEntity attackTarget;
|
||||
|
||||
public EmperorScorpionEntity(EntityType<? extends EmperorScorpionEntity> entityType, Level level) {
|
||||
@@ -92,12 +102,13 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
|
||||
public static AttributeSupplier.Builder createAttributes() {
|
||||
return Monster.createMonsterAttributes()
|
||||
.add(Attributes.MAX_HEALTH, 200.0D)
|
||||
.add(Attributes.MAX_HEALTH, 400.0D)
|
||||
.add(Attributes.MOVEMENT_SPEED, 0.32D)
|
||||
.add(Attributes.ATTACK_DAMAGE, 18.0D)
|
||||
.add(Attributes.ARMOR, 6.0D)
|
||||
.add(Attributes.KNOCKBACK_RESISTANCE, 0.6D)
|
||||
.add(Attributes.FOLLOW_RANGE, 32.0D);
|
||||
.add(Attributes.ATTACK_DAMAGE, 28.0D)
|
||||
.add(Attributes.ARMOR, 25.0D)
|
||||
.add(Attributes.ARMOR_TOUGHNESS, 10.0D)
|
||||
.add(Attributes.KNOCKBACK_RESISTANCE, 0.8D)
|
||||
.add(Attributes.FOLLOW_RANGE, 40.0D);
|
||||
}
|
||||
|
||||
public static boolean canSpawn(EntityType<EmperorScorpionEntity> entityType, ServerLevelAccessor level,
|
||||
@@ -154,10 +165,27 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
this.resetAttackState();
|
||||
}
|
||||
}
|
||||
if (this.agroAnimTicks > 0) {
|
||||
this.agroAnimTicks--;
|
||||
}
|
||||
if (this.summonCooldown > 0) {
|
||||
this.summonCooldown--;
|
||||
}
|
||||
|
||||
if (!this.level().isClientSide) {
|
||||
if (this.getTarget() != null) {
|
||||
if (!this.hasAgroed) {
|
||||
this.hasAgroed = true;
|
||||
this.agroAnimTicks = AGRO_ANIM_TICKS;
|
||||
this.getNavigation().stop();
|
||||
this.level().broadcastEntityEvent(this, AGRO_ANIM_EVENT);
|
||||
this.playSound(AntarchySoundEvents.EMPEROR_SCORPION_ROAR.get(), 2.0F, 0.7F);
|
||||
}
|
||||
} else {
|
||||
this.hasAgroed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.getTarget() != null
|
||||
&& this.summonCooldown <= 0
|
||||
&& !this.isAttackLocked()
|
||||
@@ -175,7 +203,7 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
return;
|
||||
}
|
||||
|
||||
int toSpawn = 1 + this.random.nextInt(2);
|
||||
int toSpawn = 2 + this.random.nextInt(2);
|
||||
EntityType<ScorpionEntity> scorpionType = AntarchyObjects.SCORPION.get();
|
||||
for (int i = 0; i < toSpawn; i++) {
|
||||
double offsetX = (this.random.nextDouble() - 0.5D) * 6.0D;
|
||||
@@ -198,10 +226,10 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
|
||||
@Override
|
||||
public boolean doHurtTarget(Entity target) {
|
||||
return this.performStingAttack(target);
|
||||
return this.performSnapAttack(target);
|
||||
}
|
||||
|
||||
private boolean performClawAttack(Entity target) {
|
||||
private boolean performSnapAttack(Entity target) {
|
||||
boolean hurt = super.doHurtTarget(target);
|
||||
if (hurt) {
|
||||
this.playSound(AntarchySoundEvents.EMPEROR_SCORPION_ATTACK.get(), 0.9F, 0.95F + this.random.nextFloat() * 0.08F);
|
||||
@@ -210,32 +238,39 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
}
|
||||
|
||||
private boolean performStingAttack(Entity target) {
|
||||
boolean hurt;
|
||||
if (this.level() instanceof ServerLevel serverLevel) {
|
||||
hurt = target.hurt(AntarchyDamageSources.emperorScorpionSting(serverLevel, this),
|
||||
(float) this.getAttributeValue(Attributes.ATTACK_DAMAGE));
|
||||
} else {
|
||||
hurt = super.doHurtTarget(target);
|
||||
if (!(this.level() instanceof ServerLevel serverLevel)) {
|
||||
return false;
|
||||
}
|
||||
if (hurt && target instanceof LivingEntity living) {
|
||||
int poisonDuration = this.level().getDifficulty() == Difficulty.HARD
|
||||
? POISON_DURATION_TICKS * 2 : POISON_DURATION_TICKS;
|
||||
living.addEffect(new MobEffectInstance(MobEffects.POISON, poisonDuration, 0));
|
||||
living.addEffect(new MobEffectInstance(MobEffects.WEAKNESS, WEAKNESS_DURATION_TICKS, 0));
|
||||
boolean hurtAny = false;
|
||||
for (LivingEntity living : serverLevel.getEntitiesOfClass(LivingEntity.class,
|
||||
this.getBoundingBox().inflate(STING_AOE_RADIUS),
|
||||
entity -> entity != this
|
||||
&& entity.isAlive()
|
||||
&& !(entity instanceof EmperorScorpionEntity)
|
||||
&& !(entity instanceof ScorpionEntity))) {
|
||||
if (living.hurt(AntarchyDamageSources.emperorScorpionSting(serverLevel, this), STING_DAMAGE)) {
|
||||
hurtAny = true;
|
||||
int poisonDuration = this.level().getDifficulty() == Difficulty.HARD
|
||||
? POISON_DURATION_TICKS * 2 : POISON_DURATION_TICKS;
|
||||
living.addEffect(new MobEffectInstance(MobEffects.POISON, poisonDuration, 1));
|
||||
living.addEffect(new MobEffectInstance(MobEffects.WEAKNESS, WEAKNESS_DURATION_TICKS, 0));
|
||||
}
|
||||
}
|
||||
if (hurtAny) {
|
||||
this.playSound(AntarchySoundEvents.EMPEROR_SCORPION_ATTACK.get(), 1.0F, 0.9F + this.random.nextFloat() * 0.08F);
|
||||
}
|
||||
return hurt;
|
||||
return hurtAny;
|
||||
}
|
||||
|
||||
private void beginClawAttack(LivingEntity target) {
|
||||
private void beginSnapAttack(LivingEntity target) {
|
||||
this.attackTarget = target;
|
||||
this.attackAnimTicks = CLAW_ATTACK_ANIM_TICKS;
|
||||
this.attackHitTick = CLAW_ATTACK_HIT_TICK;
|
||||
this.attackCooldownTicks = CLAW_ATTACK_COOLDOWN_TICKS;
|
||||
this.attackAnimTicks = SNAP_ATTACK_ANIM_TICKS;
|
||||
this.attackHitTick = SNAP_ATTACK_HIT_TICK;
|
||||
this.attackCooldownTicks = SNAP_ATTACK_COOLDOWN_TICKS;
|
||||
this.attackDamageApplied = false;
|
||||
this.stingAttackActive = false;
|
||||
this.getNavigation().stop();
|
||||
this.level().broadcastEntityEvent(this, CLAW_ATTACK_ANIM_EVENT);
|
||||
this.level().broadcastEntityEvent(this, SNAP_ATTACK_ANIM_EVENT);
|
||||
this.commitLunge(target, 0.42D, 0.10D);
|
||||
}
|
||||
|
||||
@@ -259,14 +294,13 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
}
|
||||
|
||||
this.getLookControl().setLookAt(this.attackTarget, 30.0F, 30.0F);
|
||||
if (!this.attackDamageApplied
|
||||
&& this.attackAnimTicks == this.attackHitTick
|
||||
&& this.distanceToSqr(this.attackTarget) <= this.getAttackReachSqr(this.attackTarget)) {
|
||||
this.attackDamageApplied = true;
|
||||
if (!this.attackDamageApplied && this.attackAnimTicks == this.attackHitTick) {
|
||||
if (this.stingAttackActive) {
|
||||
this.attackDamageApplied = true;
|
||||
this.performStingAttack(this.attackTarget);
|
||||
} else {
|
||||
this.performClawAttack(this.attackTarget);
|
||||
} else if (this.distanceToSqr(this.attackTarget) <= this.getAttackReachSqr(this.attackTarget)) {
|
||||
this.attackDamageApplied = true;
|
||||
this.performSnapAttack(this.attackTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,13 +340,13 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
}
|
||||
|
||||
private boolean isAttackLocked() {
|
||||
return this.attackAnimTicks > 0;
|
||||
return this.attackAnimTicks > 0 || this.agroAnimTicks > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEntityEvent(byte id) {
|
||||
if (id == CLAW_ATTACK_ANIM_EVENT) {
|
||||
this.attackAnimTicks = CLAW_ATTACK_ANIM_TICKS;
|
||||
if (id == SNAP_ATTACK_ANIM_EVENT) {
|
||||
this.attackAnimTicks = SNAP_ATTACK_ANIM_TICKS;
|
||||
this.attackDamageApplied = false;
|
||||
this.stingAttackActive = false;
|
||||
return;
|
||||
@@ -323,6 +357,10 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
this.stingAttackActive = true;
|
||||
return;
|
||||
}
|
||||
if (id == AGRO_ANIM_EVENT) {
|
||||
this.agroAnimTicks = AGRO_ANIM_TICKS;
|
||||
return;
|
||||
}
|
||||
super.handleEntityEvent(id);
|
||||
}
|
||||
|
||||
@@ -332,8 +370,14 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
}
|
||||
|
||||
private PlayState mainController(AnimationState<EmperorScorpionEntity> state) {
|
||||
if (this.isDeadOrDying()) {
|
||||
return state.setAndContinue(DEATH_ANIM);
|
||||
}
|
||||
if (this.attackAnimTicks > 0) {
|
||||
return state.setAndContinue(ATTACK_ANIM);
|
||||
return state.setAndContinue(this.stingAttackActive ? STING_ANIM : SNAP_ANIM);
|
||||
}
|
||||
if (this.agroAnimTicks > 0) {
|
||||
return state.setAndContinue(AGRO_ANIM);
|
||||
}
|
||||
if (state.isMoving()) {
|
||||
return state.setAndContinue(WALK_ANIM);
|
||||
@@ -341,6 +385,15 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
return state.setAndContinue(IDLE_ANIM);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tickDeath() {
|
||||
this.deathTime++;
|
||||
if (this.deathTime >= DEATH_ANIM_TICKS && !this.level().isClientSide && !this.isRemoved()) {
|
||||
this.level().broadcastEntityEvent(this, (byte) 60);
|
||||
this.remove(RemovalReason.KILLED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||
return this.geoCache;
|
||||
@@ -421,7 +474,7 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
|
||||
if (EmperorScorpionEntity.this.shouldUseSting(enemy)) {
|
||||
EmperorScorpionEntity.this.beginStingAttack(enemy);
|
||||
} else {
|
||||
EmperorScorpionEntity.this.beginClawAttack(enemy);
|
||||
EmperorScorpionEntity.this.beginSnapAttack(enemy);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ public class MantisEntity extends Monster implements GeoEntity {
|
||||
|
||||
public MantisEntity(EntityType<? extends MantisEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
this.lookControl = new SteadyLookControl(this);
|
||||
this.setNoGravity(false);
|
||||
this.setPathfindingMalus(PathType.WATER, -1.0F);
|
||||
this.setPathfindingMalus(PathType.WATER_BORDER, 16.0F);
|
||||
@@ -208,14 +207,6 @@ public class MantisEntity extends Monster implements GeoEntity {
|
||||
LivingEntity target = this.getTarget();
|
||||
if (target != null && target.isAlive()) {
|
||||
this.getLookControl().setLookAt(target, 30.0F, 30.0F);
|
||||
// If the target is horizontally inside our (wide) footprint, walking toward
|
||||
// it only makes us pivot in place — hold position, attack reach covers it
|
||||
double dx = target.getX() - this.getX();
|
||||
double dz = target.getZ() - this.getZ();
|
||||
double halfWidth = this.getBbWidth() * 0.5D;
|
||||
if (!this.isFlyingNow() && dx * dx + dz * dz < halfWidth * halfWidth) {
|
||||
this.getNavigation().stop();
|
||||
}
|
||||
} else if (this.flyBurstTicks <= 0 && this.flyCooldownTicks <= 0 && this.onGround() && this.random.nextInt(180) == 0) {
|
||||
this.startFlightBurst();
|
||||
}
|
||||
@@ -330,31 +321,6 @@ public class MantisEntity extends Monster implements GeoEntity {
|
||||
return this.flyBurstTicks > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The mantis hitbox is several blocks wide, so a melee-range target is often
|
||||
* horizontally inside the footprint. The yaw from body center to such a target
|
||||
* flips wildly as the target moves past the center, which made the mantis spin
|
||||
* instead of facing the player — hold the current heading in that case.
|
||||
*/
|
||||
private static class SteadyLookControl extends net.minecraft.world.entity.ai.control.LookControl {
|
||||
SteadyLookControl(Mob mob) {
|
||||
super(mob);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (this.lookAtCooldown > 0) {
|
||||
double dx = this.wantedX - this.mob.getX();
|
||||
double dz = this.wantedZ - this.mob.getZ();
|
||||
double halfWidth = this.mob.getBbWidth() * 0.5D;
|
||||
if (dx * dx + dz * dz < halfWidth * halfWidth) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.tick();
|
||||
}
|
||||
}
|
||||
|
||||
private void tickDebugLog() {
|
||||
if (++this.debugLogTicks < 100) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,444 @@
|
||||
package com.craisinlord.antarchy.content.entity;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.AntarchyTags;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.AgeableMob;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.MoverType;
|
||||
import net.minecraft.world.entity.TamableAnimal;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
||||
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
||||
import net.minecraft.world.entity.ai.goal.PanicGoal;
|
||||
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
||||
import net.minecraft.world.entity.ai.goal.TemptGoal;
|
||||
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.level.Level;
|
||||
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;
|
||||
|
||||
public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
|
||||
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
||||
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
|
||||
private static final RawAnimation ROLL_UP_ANIM = RawAnimation.begin().thenPlay("wheel_mode");
|
||||
private static final RawAnimation ROLLING_ANIM = RawAnimation.begin().thenLoop("roll");
|
||||
private static final RawAnimation UNROLL_ANIM = RawAnimation.begin().thenPlay("normal_mode");
|
||||
|
||||
private static final int ANIM_IDLE = 0;
|
||||
private static final int ANIM_WALK = 1;
|
||||
private static final int ANIM_ROLL_UP = 2;
|
||||
private static final int ANIM_ROLLING = 3;
|
||||
private static final int ANIM_UNROLL = 4;
|
||||
|
||||
// wheel_mode is 0.75s, normal_mode is ~0.42s
|
||||
private static final int ROLL_UP_TICKS = 15;
|
||||
private static final int UNROLL_TICKS = 9;
|
||||
private static final int DEFENSIVE_CURL_TICKS = 100;
|
||||
private static final int TUMBLE_DAMAGE_INTERVAL_TICKS = 30;
|
||||
|
||||
private static final EntityDataAccessor<Integer> ANIMATION_STATE =
|
||||
SynchedEntityData.defineId(RollyPollyEntity.class, EntityDataSerializers.INT);
|
||||
private static final EntityDataAccessor<Boolean> SADDLED =
|
||||
SynchedEntityData.defineId(RollyPollyEntity.class, EntityDataSerializers.BOOLEAN);
|
||||
private static final EntityDataAccessor<Boolean> ROLLED =
|
||||
SynchedEntityData.defineId(RollyPollyEntity.class, EntityDataSerializers.BOOLEAN);
|
||||
|
||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||
|
||||
private int rollTransitionTicks;
|
||||
private boolean unrolling;
|
||||
private int defensiveCurlTicks;
|
||||
private int tumbleTicks;
|
||||
|
||||
public RollyPollyEntity(EntityType<? extends RollyPollyEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
}
|
||||
|
||||
public static AttributeSupplier.Builder createAttributes() {
|
||||
return Mob.createMobAttributes()
|
||||
.add(Attributes.MAX_HEALTH, AntarchySettings.rollyPollyHealth())
|
||||
.add(Attributes.MOVEMENT_SPEED, AntarchySettings.rollyPollyMovementSpeed())
|
||||
.add(Attributes.FOLLOW_RANGE, 16.0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||
super.defineSynchedData(builder);
|
||||
builder.define(ANIMATION_STATE, ANIM_IDLE);
|
||||
builder.define(SADDLED, false);
|
||||
builder.define(ROLLED, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerGoals() {
|
||||
this.goalSelector.addGoal(0, new FloatGoal(this));
|
||||
this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D) {
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
// Curled-up or tamed rolly pollies stand their ground
|
||||
return !RollyPollyEntity.this.isRolled() && !RollyPollyEntity.this.isTame() && super.canUse();
|
||||
}
|
||||
});
|
||||
this.goalSelector.addGoal(2, new TemptGoal(this, 1.1D, Ingredient.of(AntarchyTags.Items.ROLLY_POLLY_FOOD), false) {
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
return !RollyPollyEntity.this.isRolled() && super.canUse();
|
||||
}
|
||||
});
|
||||
this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 1.0D) {
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
return !RollyPollyEntity.this.isRolled() && !RollyPollyEntity.this.isVehicle() && super.canUse();
|
||||
}
|
||||
});
|
||||
this.goalSelector.addGoal(4, new LookAtPlayerGoal(this, Player.class, 8.0F));
|
||||
this.goalSelector.addGoal(5, new RandomLookAroundGoal(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFood(ItemStack stack) {
|
||||
return stack.is(AntarchyTags.Items.ROLLY_POLLY_FOOD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult mobInteract(Player player, InteractionHand hand) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
|
||||
if (this.isFood(stack)) {
|
||||
if (!this.level().isClientSide) {
|
||||
if (!player.getAbilities().instabuild) {
|
||||
stack.shrink(1);
|
||||
}
|
||||
if (!this.isTame()) {
|
||||
if (this.random.nextInt(AntarchySettings.rollyPollyTameChance()) == 0) {
|
||||
this.setTame(true, true);
|
||||
this.setOwnerUUID(player.getUUID());
|
||||
this.stopDefensiveCurl();
|
||||
this.setTarget(null);
|
||||
this.level().broadcastEntityEvent(this, (byte) 7);
|
||||
} else {
|
||||
this.level().broadcastEntityEvent(this, (byte) 6);
|
||||
}
|
||||
} else if (this.getHealth() < this.getMaxHealth()) {
|
||||
this.heal(4.0F);
|
||||
this.level().broadcastEntityEvent(this, (byte) 7);
|
||||
}
|
||||
}
|
||||
return InteractionResult.sidedSuccess(this.level().isClientSide);
|
||||
}
|
||||
|
||||
if (this.isTame()) {
|
||||
if (!this.hasSaddle() && stack.is(Items.SADDLE) && this.isOwnedBy(player)) {
|
||||
if (!this.level().isClientSide) {
|
||||
this.setSaddled(true);
|
||||
if (!player.getAbilities().instabuild) {
|
||||
stack.shrink(1);
|
||||
}
|
||||
this.playSound(SoundEvents.HORSE_SADDLE, 1.0F, 1.2F);
|
||||
}
|
||||
return InteractionResult.sidedSuccess(this.level().isClientSide);
|
||||
}
|
||||
|
||||
if (this.hasSaddle() && stack.isEmpty() && player.isShiftKeyDown() && this.isOwnedBy(player) && !player.isPassengerOfSameVehicle(this)) {
|
||||
if (!this.level().isClientSide) {
|
||||
this.setSaddled(false);
|
||||
this.spawnAtLocation(new ItemStack(Items.SADDLE));
|
||||
this.playSound(SoundEvents.HORSE_SADDLE, 1.0F, 0.9F);
|
||||
}
|
||||
return InteractionResult.sidedSuccess(this.level().isClientSide);
|
||||
}
|
||||
|
||||
if (this.hasSaddle() && stack.isEmpty() && !player.isPassengerOfSameVehicle(this)) {
|
||||
if (!this.level().isClientSide) {
|
||||
player.startRiding(this);
|
||||
}
|
||||
return InteractionResult.sidedSuccess(this.level().isClientSide);
|
||||
}
|
||||
}
|
||||
|
||||
return super.mobInteract(player, hand);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasSaddle() {
|
||||
return this.entityData.get(SADDLED);
|
||||
}
|
||||
|
||||
public void setSaddled(boolean saddled) {
|
||||
this.entityData.set(SADDLED, saddled);
|
||||
}
|
||||
|
||||
public boolean isRolled() {
|
||||
return this.entityData.get(ROLLED);
|
||||
}
|
||||
|
||||
private void setRolled(boolean rolled) {
|
||||
this.entityData.set(ROLLED, rolled);
|
||||
}
|
||||
|
||||
/** Toggles wheel mode; called from the ridden-roll keybind payload. */
|
||||
public void handleRollToggle(ServerPlayer player) {
|
||||
if (!this.isTame() || !this.hasSaddle() || this.getControllingPassenger() != player) {
|
||||
return;
|
||||
}
|
||||
if (this.rollTransitionTicks > 0) {
|
||||
return;
|
||||
}
|
||||
if (this.isRolled()) {
|
||||
this.startUnroll();
|
||||
} else {
|
||||
this.startRollUp();
|
||||
}
|
||||
}
|
||||
|
||||
private void startRollUp() {
|
||||
this.setRolled(true);
|
||||
this.unrolling = false;
|
||||
this.rollTransitionTicks = ROLL_UP_TICKS;
|
||||
this.setAnimationState(ANIM_ROLL_UP);
|
||||
this.playSound(SoundEvents.ARMOR_EQUIP_TURTLE.value(), 0.8F, 1.4F);
|
||||
}
|
||||
|
||||
private void startUnroll() {
|
||||
this.unrolling = true;
|
||||
this.rollTransitionTicks = UNROLL_TICKS;
|
||||
this.setAnimationState(ANIM_UNROLL);
|
||||
this.playSound(SoundEvents.ARMOR_EQUIP_TURTLE.value(), 0.8F, 1.1F);
|
||||
}
|
||||
|
||||
private void stopDefensiveCurl() {
|
||||
this.defensiveCurlTicks = 0;
|
||||
if (this.isRolled() && !this.isVehicle()) {
|
||||
this.startUnroll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hurt(DamageSource source, float amount) {
|
||||
if (this.isRolled()) {
|
||||
amount *= 0.25F;
|
||||
}
|
||||
boolean hurt = super.hurt(source, amount);
|
||||
// Wild rolly pollies curl up defensively when attacked
|
||||
if (hurt && !this.level().isClientSide && !this.isTame() && this.isAlive()
|
||||
&& !this.isRolled() && this.rollTransitionTicks <= 0) {
|
||||
this.defensiveCurlTicks = DEFENSIVE_CURL_TICKS;
|
||||
this.startRollUp();
|
||||
}
|
||||
return hurt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if (this.level().isClientSide) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.rollTransitionTicks > 0) {
|
||||
this.rollTransitionTicks--;
|
||||
if (this.rollTransitionTicks <= 0) {
|
||||
if (this.unrolling) {
|
||||
this.setRolled(false);
|
||||
this.unrolling = false;
|
||||
this.setAnimationState(ANIM_IDLE);
|
||||
} else {
|
||||
this.setAnimationState(ANIM_ROLLING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.defensiveCurlTicks > 0) {
|
||||
this.defensiveCurlTicks--;
|
||||
this.getNavigation().stop();
|
||||
if (this.defensiveCurlTicks <= 0 && this.isRolled() && !this.isVehicle()) {
|
||||
this.startUnroll();
|
||||
}
|
||||
}
|
||||
|
||||
this.tickTumbleDamage();
|
||||
this.updateAnimationState();
|
||||
}
|
||||
|
||||
private void tickTumbleDamage() {
|
||||
if (!this.isRolled() || this.rollTransitionTicks > 0
|
||||
|| !(this.getControllingPassenger() instanceof Player rider)) {
|
||||
this.tumbleTicks = 0;
|
||||
return;
|
||||
}
|
||||
boolean moving = this.getDeltaMovement().horizontalDistanceSqr() > 0.003D;
|
||||
boolean helmeted = !rider.getItemBySlot(EquipmentSlot.HEAD).isEmpty();
|
||||
if (!moving || helmeted) {
|
||||
return;
|
||||
}
|
||||
if (++this.tumbleTicks >= TUMBLE_DAMAGE_INTERVAL_TICKS) {
|
||||
this.tumbleTicks = 0;
|
||||
rider.hurt(this.damageSources().generic(), (float) AntarchySettings.rollyPollyTumbleDamage());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAnimationState() {
|
||||
// Roll states are driven by the transition/tick logic above
|
||||
int state = this.getAnimationState();
|
||||
if (state == ANIM_ROLL_UP || state == ANIM_ROLLING || state == ANIM_UNROLL) {
|
||||
return;
|
||||
}
|
||||
boolean moving = this.getDeltaMovement().horizontalDistanceSqr() > 1.0E-4D;
|
||||
this.setAnimationState(moving ? ANIM_WALK : ANIM_IDLE);
|
||||
}
|
||||
|
||||
private int getAnimationState() {
|
||||
return this.entityData.get(ANIMATION_STATE);
|
||||
}
|
||||
|
||||
private void setAnimationState(int state) {
|
||||
this.entityData.set(ANIMATION_STATE, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public LivingEntity getControllingPassenger() {
|
||||
if (!this.isTame() || !this.hasSaddle()) {
|
||||
return null;
|
||||
}
|
||||
Entity passenger = this.getFirstPassenger();
|
||||
return passenger instanceof LivingEntity living ? living : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAddPassenger(Entity passenger) {
|
||||
return this.getPassengers().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void positionRider(Entity passenger, MoveFunction moveFunction) {
|
||||
if (this.hasPassenger(passenger)) {
|
||||
// When rolled the rider tucks into the center of the ball; otherwise sits on the shell
|
||||
double yOffset = this.isRolled() ? -0.25D : 0.45D;
|
||||
moveFunction.accept(passenger, this.getX(), this.getY() + yOffset, this.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void travel(Vec3 travelVector) {
|
||||
if (!(this.getControllingPassenger() instanceof Player rider) || !this.isVehicle()) {
|
||||
if (this.defensiveCurlTicks > 0) {
|
||||
super.travel(Vec3.ZERO);
|
||||
return;
|
||||
}
|
||||
super.travel(travelVector);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.rollTransitionTicks > 0) {
|
||||
// Hold still while rolling up / unrolling
|
||||
super.travel(Vec3.ZERO);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setYRot(rider.getYHeadRot());
|
||||
this.yBodyRot = this.getYRot();
|
||||
this.yHeadRot = this.getYRot();
|
||||
|
||||
float forward = rider.zza;
|
||||
float strafe = rider.xxa * 0.5F;
|
||||
if (forward < 0.0F) {
|
||||
forward *= 0.4F;
|
||||
}
|
||||
if (this.isRolled()) {
|
||||
// Rolling is fast but drifty
|
||||
strafe *= 0.35F;
|
||||
}
|
||||
|
||||
double speed = this.getAttributeValue(Attributes.MOVEMENT_SPEED)
|
||||
* (this.isRolled() ? AntarchySettings.rollyPollyRollSpeedMultiplier() : 1.0D);
|
||||
this.setSpeed((float) speed);
|
||||
|
||||
Vec3 input = new Vec3(strafe, 0.0D, forward);
|
||||
Vec3 motion = new Vec3(0.0D, this.getDeltaMovement().y, 0.0D);
|
||||
this.moveRelative(this.getSpeed(), input);
|
||||
this.setDeltaMovement(motion.add(this.getDeltaMovement().x, 0.0D, this.getDeltaMovement().z));
|
||||
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource damageSource) {
|
||||
if (this.isRolled()) {
|
||||
return false;
|
||||
}
|
||||
return super.causeFallDamage(fallDistance, multiplier, damageSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropEquipment() {
|
||||
super.dropEquipment();
|
||||
if (this.hasSaddle()) {
|
||||
this.spawnAtLocation(new ItemStack(Items.SADDLE));
|
||||
this.setSaddled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAdditionalSaveData(CompoundTag tag) {
|
||||
super.addAdditionalSaveData(tag);
|
||||
tag.putBoolean("Saddled", this.hasSaddle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readAdditionalSaveData(CompoundTag tag) {
|
||||
super.readAdditionalSaveData(tag);
|
||||
this.setSaddled(tag.getBoolean("Saddled"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||
controllers.add(new AnimationController<>(this, "main_controller", 2, this::mainAnimController));
|
||||
}
|
||||
|
||||
private PlayState mainAnimController(AnimationState<RollyPollyEntity> state) {
|
||||
return switch (this.getAnimationState()) {
|
||||
case ANIM_WALK -> state.setAndContinue(WALK_ANIM);
|
||||
case ANIM_ROLL_UP -> state.setAndContinue(ROLL_UP_ANIM);
|
||||
case ANIM_ROLLING -> state.setAndContinue(ROLLING_ANIM);
|
||||
case ANIM_UNROLL -> state.setAndContinue(UNROLL_ANIM);
|
||||
default -> state.setAndContinue(IDLE_ANIM);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||
return this.geoCache;
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.craisinlord.antarchy.content.network;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/** C2S: the rider pressed the roll keybind — toggle the rolly polly's wheel mode. */
|
||||
public record RollyPollyRollPayload() implements CustomPacketPayload {
|
||||
public static final Type<RollyPollyRollPayload> TYPE =
|
||||
new Type<>(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "rolly_polly_roll"));
|
||||
public static final StreamCodec<ByteBuf, RollyPollyRollPayload> STREAM_CODEC =
|
||||
StreamCodec.unit(new RollyPollyRollPayload());
|
||||
|
||||
@Override
|
||||
public Type<RollyPollyRollPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user