new king sounds
worm sizes performance improvements
This commit is contained in:
1 parent
89d41dd7e1
commit
f4f4e0c717
96 files changed
+2039
-470
No files matched your search
@@ -468,6 +468,9 @@ public final class AntarchySettings {
|
|||||||
private static double molevoreBreakRange = 1.8D;
|
private static double molevoreBreakRange = 1.8D;
|
||||||
private static double molevoreBreakVerticalRange = 2.2D;
|
private static double molevoreBreakVerticalRange = 2.2D;
|
||||||
private static double molevoreBreakHalfWidth = 1.1D;
|
private static double molevoreBreakHalfWidth = 1.1D;
|
||||||
|
private static double jumpyBugLatchDamage = 2.0D;
|
||||||
|
private static double waterCannonCooldownSeconds = 4.0D;
|
||||||
|
private static double toreterrorRangedWaterBombChance = 0.35D;
|
||||||
private static double nightmareHealth = 380.0D;
|
private static double nightmareHealth = 380.0D;
|
||||||
private static double nightmareAttackDamage = 16.0D;
|
private static double nightmareAttackDamage = 16.0D;
|
||||||
private static double nightmareMovementSpeed = 0.28D;
|
private static double nightmareMovementSpeed = 0.28D;
|
||||||
@@ -2715,6 +2718,21 @@ public final class AntarchySettings {
|
|||||||
public static double molevoreAttackDamage() { return molevoreAttackDamage; }
|
public static double molevoreAttackDamage() { return molevoreAttackDamage; }
|
||||||
public static void setMolevoreAttackDamage(double value) { molevoreAttackDamage = value; }
|
public static void setMolevoreAttackDamage(double value) { molevoreAttackDamage = value; }
|
||||||
|
|
||||||
|
public static double molevoreMovementSpeed() { return molevoreMovementSpeed; }
|
||||||
|
public static void setMolevoreMovementSpeed(double value) { molevoreMovementSpeed = value; }
|
||||||
|
|
||||||
|
public static double molevoreArmor() { return molevoreArmor; }
|
||||||
|
public static void setMolevoreArmor(double value) { molevoreArmor = value; }
|
||||||
|
|
||||||
|
public static double molevoreKnockbackResistance() { return molevoreKnockbackResistance; }
|
||||||
|
public static void setMolevoreKnockbackResistance(double value) { molevoreKnockbackResistance = value; }
|
||||||
|
|
||||||
|
public static double molevoreFollowRange() { return molevoreFollowRange; }
|
||||||
|
public static void setMolevoreFollowRange(double value) { molevoreFollowRange = value; }
|
||||||
|
|
||||||
|
public static int molevoreXpReward() { return molevoreXpReward; }
|
||||||
|
public static void setMolevoreXpReward(int value) { molevoreXpReward = value; }
|
||||||
|
|
||||||
public static int molevoreSpinTicks() { return molevoreSpinTicks; }
|
public static int molevoreSpinTicks() { return molevoreSpinTicks; }
|
||||||
public static void setMolevoreSpinTicks(int value) { molevoreSpinTicks = value; }
|
public static void setMolevoreSpinTicks(int value) { molevoreSpinTicks = value; }
|
||||||
|
|
||||||
@@ -2985,7 +3003,10 @@ public final class AntarchySettings {
|
|||||||
public static int bossMagicWardDurationTicks() { return bossMagicWardDurationTicks; }
|
public static int bossMagicWardDurationTicks() { return bossMagicWardDurationTicks; }
|
||||||
public static int bossMagicWardTriggerBreaches() { return bossMagicWardTriggerBreaches; }
|
public static int bossMagicWardTriggerBreaches() { return bossMagicWardTriggerBreaches; }
|
||||||
public static java.util.List<String> magicBurstDamageNamespaces() { return magicBurstDamageNamespaces; }
|
public static java.util.List<String> magicBurstDamageNamespaces() { return magicBurstDamageNamespaces; }
|
||||||
public static double jumpyBugLatchDamage() { return 2.0D; }
|
public static double jumpyBugLatchDamage() { return jumpyBugLatchDamage; }
|
||||||
public static double waterCannonCooldownSeconds() { return 4.0D; }
|
public static void setJumpyBugLatchDamage(double value) { jumpyBugLatchDamage = value; }
|
||||||
public static double toreterrorRangedWaterBombChance() { return 0.35D; }
|
public static double waterCannonCooldownSeconds() { return waterCannonCooldownSeconds; }
|
||||||
|
public static void setWaterCannonCooldownSeconds(double value) { waterCannonCooldownSeconds = value; }
|
||||||
|
public static double toreterrorRangedWaterBombChance() { return toreterrorRangedWaterBombChance; }
|
||||||
|
public static void setToreterrorRangedWaterBombChance(double value) { toreterrorRangedWaterBombChance = value; }
|
||||||
}
|
}
|
||||||
+11
@@ -60,6 +60,7 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
private static final double PORTAL_RADIUS = 1.35D;
|
private static final double PORTAL_RADIUS = 1.35D;
|
||||||
private static final double EXIT_OFFSET = 2.4D;
|
private static final double EXIT_OFFSET = 2.4D;
|
||||||
private static final Map<UUID, Long> TELEPORT_COOLDOWNS = new HashMap<>();
|
private static final Map<UUID, Long> TELEPORT_COOLDOWNS = new HashMap<>();
|
||||||
|
private static long lastTeleportCooldownCleanupTick = Long.MIN_VALUE;
|
||||||
|
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
private UUID linkedTearId;
|
private UUID linkedTearId;
|
||||||
@@ -118,6 +119,7 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.ageTicks++;
|
this.ageTicks++;
|
||||||
|
cleanupTeleportCooldowns(this.level().getGameTime());
|
||||||
if (this.ageTicks >= this.lifetimeTicks - COLLAPSE_WARNING_TICKS) {
|
if (this.ageTicks >= this.lifetimeTicks - COLLAPSE_WARNING_TICKS) {
|
||||||
this.setTearState(TearState.COLLAPSING);
|
this.setTearState(TearState.COLLAPSING);
|
||||||
}
|
}
|
||||||
@@ -235,6 +237,15 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
this.level().playSound(null, this.blockPosition(), SoundEvents.ENDERMAN_TELEPORT, SoundSource.NEUTRAL, 0.7F, 0.65F + this.random.nextFloat() * 0.2F);
|
this.level().playSound(null, this.blockPosition(), SoundEvents.ENDERMAN_TELEPORT, SoundSource.NEUTRAL, 0.7F, 0.65F + this.random.nextFloat() * 0.2F);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void cleanupTeleportCooldowns(long gameTime) {
|
||||||
|
if (gameTime <= lastTeleportCooldownCleanupTick
|
||||||
|
|| gameTime - lastTeleportCooldownCleanupTick < TELEPORT_COOLDOWN_TICKS * 4L) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastTeleportCooldownCleanupTick = gameTime;
|
||||||
|
TELEPORT_COOLDOWNS.entrySet().removeIf(entry -> entry.getValue() <= gameTime);
|
||||||
|
}
|
||||||
|
|
||||||
private Vec3 exitPosition() {
|
private Vec3 exitPosition() {
|
||||||
Vec3 facing = this.getViewVector(1.0F);
|
Vec3 facing = this.getViewVector(1.0F);
|
||||||
if (facing.lengthSqr() < 1.0E-4D) {
|
if (facing.lengthSqr() < 1.0E-4D) {
|
||||||
|
|||||||
+19
@@ -1,11 +1,15 @@
|
|||||||
package com.craisinlord.antarchy.content.item;
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.SwordItem;
|
import net.minecraft.world.item.SwordItem;
|
||||||
@@ -21,6 +25,7 @@ public class BloodCrystalKatanaItem extends SwordItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static TrailCallback trailCallback = (player, durationTicks) -> {};
|
private static TrailCallback trailCallback = (player, durationTicks) -> {};
|
||||||
|
private static final Map<UUID, Long> DASH_UNTIL_TICK = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final Tier tier;
|
private final Tier tier;
|
||||||
private final int attackDamage;
|
private final int attackDamage;
|
||||||
@@ -56,9 +61,23 @@ public class BloodCrystalKatanaItem extends SwordItem {
|
|||||||
player.hasImpulse = true;
|
player.hasImpulse = true;
|
||||||
player.hurtMarked = true;
|
player.hurtMarked = true;
|
||||||
trailCallback.trigger(player, AntarchySettings.bloodCrystalKatanaTrailDurationTicks());
|
trailCallback.trigger(player, AntarchySettings.bloodCrystalKatanaTrailDurationTicks());
|
||||||
|
long now = player.level().getGameTime();
|
||||||
|
DASH_UNTIL_TICK.put(player.getUUID(), now + AntarchySettings.bloodCrystalKatanaTrailDurationTicks());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isDashing(Entity entity) {
|
||||||
|
if (!(entity instanceof ServerPlayer player)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Long until = DASH_UNTIL_TICK.get(player.getUUID());
|
||||||
|
if (until == null || player.level().getGameTime() >= until) {
|
||||||
|
DASH_UNTIL_TICK.remove(player.getUUID());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
||||||
tooltipComponents.add(Component.translatable("tooltip.antarchy.blood_crystal_katana.launch").withStyle(ChatFormatting.RED));
|
tooltipComponents.add(Component.translatable("tooltip.antarchy.blood_crystal_katana.launch").withStyle(ChatFormatting.RED));
|
||||||
|
|||||||
+8
@@ -16,6 +16,14 @@ import net.minecraft.world.level.biome.Climate;
|
|||||||
import net.minecraft.world.level.biome.MultiNoiseBiomeSource;
|
import net.minecraft.world.level.biome.MultiNoiseBiomeSource;
|
||||||
|
|
||||||
public class ElythiaBiomeSource extends BiomeSource {
|
public class ElythiaBiomeSource extends BiomeSource {
|
||||||
|
public static final Codec<ElythiaBiomeSource> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||||
|
MultiNoiseBiomeSource.DIRECT_CODEC.forGetter(ElythiaBiomeSource::parameters),
|
||||||
|
Codec.INT.optionalFieldOf("moleworm_caves_max_y", 72).forGetter(ElythiaBiomeSource::molewormCavesMaxY),
|
||||||
|
Codec.INT.optionalFieldOf("surface_biome_sample_y", 160).forGetter(ElythiaBiomeSource::surfaceBiomeSampleY),
|
||||||
|
Codec.INT.optionalFieldOf("ocean_max_y", 85).forGetter(ElythiaBiomeSource::oceanMaxY),
|
||||||
|
Codec.INT.optionalFieldOf("sea_level", 78).forGetter(ElythiaBiomeSource::seaLevel),
|
||||||
|
Codec.INT.optionalFieldOf("cloud_sea_min_y", 360).forGetter(ElythiaBiomeSource::cloudSeaMinY)
|
||||||
|
).apply(instance, ElythiaBiomeSource::new));
|
||||||
private static final ResourceKey<Biome> MOLEWORM_CAVES = ResourceKey.create(
|
private static final ResourceKey<Biome> MOLEWORM_CAVES = ResourceKey.create(
|
||||||
Registries.BIOME,
|
Registries.BIOME,
|
||||||
new ResourceLocation(Antarchy.MODID, "moleworm_caves")
|
new ResourceLocation(Antarchy.MODID, "moleworm_caves")
|
||||||
|
|||||||
+6
@@ -17,6 +17,12 @@ import net.minecraft.world.level.biome.Climate;
|
|||||||
import net.minecraft.world.level.biome.MultiNoiseBiomeSource;
|
import net.minecraft.world.level.biome.MultiNoiseBiomeSource;
|
||||||
|
|
||||||
public final class ThoraxisBiomeSource extends BiomeSource {
|
public final class ThoraxisBiomeSource extends BiomeSource {
|
||||||
|
public static final Codec<ThoraxisBiomeSource> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||||
|
MultiNoiseBiomeSource.DIRECT_CODEC.forGetter(ThoraxisBiomeSource::parameters),
|
||||||
|
Codec.INT.optionalFieldOf("dream_dunes_max_y", 160).forGetter(ThoraxisBiomeSource::dreamDunesMaxY),
|
||||||
|
Codec.INT.optionalFieldOf("umbral_hills_max_y", 160).forGetter(ThoraxisBiomeSource::umbralHillsMaxY),
|
||||||
|
Codec.INT.optionalFieldOf("lucid_pools_min_y", 116).forGetter(ThoraxisBiomeSource::lucidPoolsMinY)
|
||||||
|
).apply(instance, ThoraxisBiomeSource::new));
|
||||||
private static final int REGION_NOISE_SCALE = 96;
|
private static final int REGION_NOISE_SCALE = 96;
|
||||||
private static final int REGION_DETAIL_SCALE = 41;
|
private static final int REGION_DETAIL_SCALE = 41;
|
||||||
private static final int VERTICAL_NOISE_SCALE = 8;
|
private static final int VERTICAL_NOISE_SCALE = 8;
|
||||||
|
|||||||
@@ -254,6 +254,7 @@ public final class AntarchySettings {
|
|||||||
private static double queenBlackHoleRadius = 14.0D;
|
private static double queenBlackHoleRadius = 14.0D;
|
||||||
private static int queenBlackHoleActiveTicks = 120;
|
private static int queenBlackHoleActiveTicks = 120;
|
||||||
private static double queenBlackHolePullStrength = 0.16D;
|
private static double queenBlackHolePullStrength = 0.16D;
|
||||||
|
private static int queenBlackHoleBlockSuctionCap = 160;
|
||||||
private static double queenFinalTimeFieldRadius = 20.0D;
|
private static double queenFinalTimeFieldRadius = 20.0D;
|
||||||
private static double queenFinalTimeFieldRate = 0.05D;
|
private static double queenFinalTimeFieldRate = 0.05D;
|
||||||
private static int queenFinalTimeFieldDurationTicks = 45;
|
private static int queenFinalTimeFieldDurationTicks = 45;
|
||||||
@@ -273,7 +274,7 @@ public final class AntarchySettings {
|
|||||||
private static double royalBossKnockbackResistance = 1.0D;
|
private static double royalBossKnockbackResistance = 1.0D;
|
||||||
private static double royalBossStepHeight = 3.0D;
|
private static double royalBossStepHeight = 3.0D;
|
||||||
private static double royalBossMaxSingleHitDamage = 250.0D;
|
private static double royalBossMaxSingleHitDamage = 250.0D;
|
||||||
private static double royalBossBiteReach = 10.0D;
|
private static double royalBossBiteReach = 12.0D;
|
||||||
private static double royalBossBiteDamageMultiplier = 1.6D;
|
private static double royalBossBiteDamageMultiplier = 1.6D;
|
||||||
private static int royalBossBiteCooldownTicks = 45;
|
private static int royalBossBiteCooldownTicks = 45;
|
||||||
private static boolean basiliskPetrifyingGazeEnabled = true;
|
private static boolean basiliskPetrifyingGazeEnabled = true;
|
||||||
@@ -558,6 +559,10 @@ public final class AntarchySettings {
|
|||||||
private static double queenBeamTracking = 0.1D;
|
private static double queenBeamTracking = 0.1D;
|
||||||
private static double queenBeamTerrainRadius = 5.0D;
|
private static double queenBeamTerrainRadius = 5.0D;
|
||||||
private static int queenBeamTerrainCap = 192;
|
private static int queenBeamTerrainCap = 192;
|
||||||
|
private static int queenBeamPhaseOneCap = 1;
|
||||||
|
private static int queenBeamPhaseTwoCap = 2;
|
||||||
|
private static int queenBeamPhaseThreeCap = 3;
|
||||||
|
private static double queenBeamPhaseThreeMaxVolleyChance = 0.2D;
|
||||||
private static double kingBeamDamage = 50.0D;
|
private static double kingBeamDamage = 50.0D;
|
||||||
private static double kingBeamRange = 100.0D;
|
private static double kingBeamRange = 100.0D;
|
||||||
private static double kingBeamMinimumRange = 32.0D;
|
private static double kingBeamMinimumRange = 32.0D;
|
||||||
@@ -2051,6 +2056,8 @@ public final class AntarchySettings {
|
|||||||
public static void setQueenBlackHoleActiveTicks(int v) { queenBlackHoleActiveTicks = v; }
|
public static void setQueenBlackHoleActiveTicks(int v) { queenBlackHoleActiveTicks = v; }
|
||||||
public static double queenBlackHolePullStrength() { return queenBlackHolePullStrength; }
|
public static double queenBlackHolePullStrength() { return queenBlackHolePullStrength; }
|
||||||
public static void setQueenBlackHolePullStrength(double v) { queenBlackHolePullStrength = v; }
|
public static void setQueenBlackHolePullStrength(double v) { queenBlackHolePullStrength = v; }
|
||||||
|
public static int queenBlackHoleBlockSuctionCap() { return queenBlackHoleBlockSuctionCap; }
|
||||||
|
public static void setQueenBlackHoleBlockSuctionCap(int v) { queenBlackHoleBlockSuctionCap = v; }
|
||||||
public static double queenFinalTimeFieldRadius() { return queenFinalTimeFieldRadius; }
|
public static double queenFinalTimeFieldRadius() { return queenFinalTimeFieldRadius; }
|
||||||
public static void setQueenFinalTimeFieldRadius(double v) { queenFinalTimeFieldRadius = v; }
|
public static void setQueenFinalTimeFieldRadius(double v) { queenFinalTimeFieldRadius = v; }
|
||||||
public static double queenFinalTimeFieldRate() { return queenFinalTimeFieldRate; }
|
public static double queenFinalTimeFieldRate() { return queenFinalTimeFieldRate; }
|
||||||
@@ -2910,6 +2917,14 @@ public final class AntarchySettings {
|
|||||||
public static void setQueenBeamTerrainRadius(double v) { queenBeamTerrainRadius = v; }
|
public static void setQueenBeamTerrainRadius(double v) { queenBeamTerrainRadius = v; }
|
||||||
public static int queenBeamTerrainCap() { return queenBeamTerrainCap; }
|
public static int queenBeamTerrainCap() { return queenBeamTerrainCap; }
|
||||||
public static void setQueenBeamTerrainCap(int v) { queenBeamTerrainCap = v; }
|
public static void setQueenBeamTerrainCap(int v) { queenBeamTerrainCap = v; }
|
||||||
|
public static int queenBeamPhaseOneCap() { return queenBeamPhaseOneCap; }
|
||||||
|
public static void setQueenBeamPhaseOneCap(int v) { queenBeamPhaseOneCap = v; }
|
||||||
|
public static int queenBeamPhaseTwoCap() { return queenBeamPhaseTwoCap; }
|
||||||
|
public static void setQueenBeamPhaseTwoCap(int v) { queenBeamPhaseTwoCap = v; }
|
||||||
|
public static int queenBeamPhaseThreeCap() { return queenBeamPhaseThreeCap; }
|
||||||
|
public static void setQueenBeamPhaseThreeCap(int v) { queenBeamPhaseThreeCap = v; }
|
||||||
|
public static double queenBeamPhaseThreeMaxVolleyChance() { return queenBeamPhaseThreeMaxVolleyChance; }
|
||||||
|
public static void setQueenBeamPhaseThreeMaxVolleyChance(double v) { queenBeamPhaseThreeMaxVolleyChance = v; }
|
||||||
public static double kingBeamDamage() { return kingBeamDamage; }
|
public static double kingBeamDamage() { return kingBeamDamage; }
|
||||||
public static void setKingBeamDamage(double v) { kingBeamDamage = v; }
|
public static void setKingBeamDamage(double v) { kingBeamDamage = v; }
|
||||||
public static double kingBeamRange() { return kingBeamRange; }
|
public static double kingBeamRange() { return kingBeamRange; }
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ public final class AntarchyObjects {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity>> ROYAL_BLACK_HOLE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity>>) UNBOUND;
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity>> ROYAL_BLACK_HOLE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity>>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>> ROYAL_ASSAILANT_BLACK_HOLE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>>) UNBOUND;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<Block> VORTEX_LENS = (Supplier<Block>) UNBOUND;
|
public static Supplier<Block> VORTEX_LENS = (Supplier<Block>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<BlockEntityType<VortexLensBlockEntity>> VORTEX_LENS_BLOCK_ENTITY = (Supplier<BlockEntityType<VortexLensBlockEntity>>) UNBOUND;
|
public static Supplier<BlockEntityType<VortexLensBlockEntity>> VORTEX_LENS_BLOCK_ENTITY = (Supplier<BlockEntityType<VortexLensBlockEntity>>) UNBOUND;
|
||||||
@@ -691,6 +693,10 @@ public final class AntarchyObjects {
|
|||||||
ROYAL_BLACK_HOLE = supplier;
|
ROYAL_BLACK_HOLE = supplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setRoyalAssailantBlackHole(Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>> supplier) {
|
||||||
|
ROYAL_ASSAILANT_BLACK_HOLE = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
public static void setVortexLens(Supplier<Block> supplier) {
|
public static void setVortexLens(Supplier<Block> supplier) {
|
||||||
VORTEX_LENS = supplier;
|
VORTEX_LENS = supplier;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -213,6 +213,9 @@ public final class AntarchySoundEvents {
|
|||||||
public static Supplier<SoundEvent> PRINCESS_SHOOT = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> PRINCESS_SHOOT = (Supplier<SoundEvent>) UNBOUND;
|
||||||
public static Supplier<SoundEvent> PRINCESS_FLY = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> PRINCESS_FLY = (Supplier<SoundEvent>) UNBOUND;
|
||||||
public static Supplier<SoundEvent> PRINCESS_STEP = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> PRINCESS_STEP = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> KING_DECREE = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> KING_SUCCESS = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> KING_JUDGEMENT = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
|
||||||
private AntarchySoundEvents() {
|
private AntarchySoundEvents() {
|
||||||
}
|
}
|
||||||
@@ -417,7 +420,10 @@ public final class AntarchySoundEvents {
|
|||||||
Supplier<SoundEvent> princessBite,
|
Supplier<SoundEvent> princessBite,
|
||||||
Supplier<SoundEvent> princessShoot,
|
Supplier<SoundEvent> princessShoot,
|
||||||
Supplier<SoundEvent> princessFly,
|
Supplier<SoundEvent> princessFly,
|
||||||
Supplier<SoundEvent> princessStep
|
Supplier<SoundEvent> princessStep,
|
||||||
|
Supplier<SoundEvent> kingDecree,
|
||||||
|
Supplier<SoundEvent> kingSuccess,
|
||||||
|
Supplier<SoundEvent> kingJudgement
|
||||||
) {
|
) {
|
||||||
SQUIDZOOKA_FIRE = squidzookaFire;
|
SQUIDZOOKA_FIRE = squidzookaFire;
|
||||||
SHRINK_RAY_CHARGE = shrinkRayCharge;
|
SHRINK_RAY_CHARGE = shrinkRayCharge;
|
||||||
@@ -619,6 +625,9 @@ public final class AntarchySoundEvents {
|
|||||||
PRINCESS_SHOOT = princessShoot;
|
PRINCESS_SHOOT = princessShoot;
|
||||||
PRINCESS_FLY = princessFly;
|
PRINCESS_FLY = princessFly;
|
||||||
PRINCESS_STEP = princessStep;
|
PRINCESS_STEP = princessStep;
|
||||||
|
KING_DECREE = kingDecree;
|
||||||
|
KING_SUCCESS = kingSuccess;
|
||||||
|
KING_JUDGEMENT = kingJudgement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void bindDimensionalTearSounds(
|
public static void bindDimensionalTearSounds(
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ public final class AntarchyTags {
|
|||||||
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_COMMON_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_common_spawns"));
|
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_COMMON_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_common_spawns"));
|
||||||
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_RARE_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_rare_spawns"));
|
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_RARE_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_rare_spawns"));
|
||||||
public static final TagKey<EntityType<?>> TIME_DILATION_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("time_dilation_immune"));
|
public static final TagKey<EntityType<?>> TIME_DILATION_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("time_dilation_immune"));
|
||||||
|
public static final TagKey<EntityType<?>> QUEEN_DOES_NOT_ATTACK = TagKey.create(Registries.ENTITY_TYPE, id("queen_does_not_attack"));
|
||||||
public static final TagKey<EntityType<?>> COMMANDED_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("commanded_blacklist"));
|
public static final TagKey<EntityType<?>> COMMANDED_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("commanded_blacklist"));
|
||||||
public static final TagKey<EntityType<?>> DILATED_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("dilated_blacklist"));
|
public static final TagKey<EntityType<?>> DILATED_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("dilated_blacklist"));
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -170,7 +170,7 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mount.moveTo(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D, level.random.nextFloat() * 360.0F, 0.0F);
|
mount.moveTo(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D, level.random.nextFloat() * 360.0F, 0.0F);
|
||||||
mount.setBaby(true);
|
mount.setGrowthProgress(0.0F);
|
||||||
mount.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), MobSpawnType.BREEDING, null);
|
mount.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), MobSpawnType.BREEDING, null);
|
||||||
if (placer != null) {
|
if (placer != null) {
|
||||||
mount.setTame(true, true);
|
mount.setTame(true, true);
|
||||||
|
|||||||
+20
@@ -17,6 +17,7 @@ public final class ClientTimeDilationTicker {
|
|||||||
private static ClientLevel activeLevel;
|
private static ClientLevel activeLevel;
|
||||||
private static final Map<ItemEntity, ItemSpinState> ITEM_SPIN_STATES = new WeakHashMap<>();
|
private static final Map<ItemEntity, ItemSpinState> ITEM_SPIN_STATES = new WeakHashMap<>();
|
||||||
private static final Map<LivingEntity, AttackAnimationState> ATTACK_ANIMATION_STATES = new WeakHashMap<>();
|
private static final Map<LivingEntity, AttackAnimationState> ATTACK_ANIMATION_STATES = new WeakHashMap<>();
|
||||||
|
private static final Map<LivingEntity, AnimationClockState> WALK_ANIMATION_STATES = new WeakHashMap<>();
|
||||||
private static final Map<Entity, AnimationClockState> ANIMATION_CLOCKS = new WeakHashMap<>();
|
private static final Map<Entity, AnimationClockState> ANIMATION_CLOCKS = new WeakHashMap<>();
|
||||||
|
|
||||||
private ClientTimeDilationTicker() {
|
private ClientTimeDilationTicker() {
|
||||||
@@ -28,9 +29,12 @@ public final class ClientTimeDilationTicker {
|
|||||||
activeFields = List.of();
|
activeFields = List.of();
|
||||||
ITEM_SPIN_STATES.clear();
|
ITEM_SPIN_STATES.clear();
|
||||||
ATTACK_ANIMATION_STATES.clear();
|
ATTACK_ANIMATION_STATES.clear();
|
||||||
|
WALK_ANIMATION_STATES.clear();
|
||||||
ANIMATION_CLOCKS.clear();
|
ANIMATION_CLOCKS.clear();
|
||||||
|
ContractionAfterimages.clear();
|
||||||
com.craisinlord.antarchy.content.time.TimeDilationApi.clearSyncedClientRates();
|
com.craisinlord.antarchy.content.time.TimeDilationApi.clearSyncedClientRates();
|
||||||
}
|
}
|
||||||
|
ContractionAfterimages.tick(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float dilateAnimationTime(Entity entity, float vanillaTime) {
|
public static float dilateAnimationTime(Entity entity, float vanillaTime) {
|
||||||
@@ -87,6 +91,22 @@ public final class ClientTimeDilationTicker {
|
|||||||
return rate >= TimeDilationMath.NORMAL_RATE ? amount : amount * (float) rate;
|
return rate >= TimeDilationMath.NORMAL_RATE ? amount : amount * (float) rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float dilateWalkPosition(LivingEntity entity, float vanillaPosition) {
|
||||||
|
double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity);
|
||||||
|
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||||
|
WALK_ANIMATION_STATES.remove(entity);
|
||||||
|
return vanillaPosition;
|
||||||
|
}
|
||||||
|
AnimationClockState state = WALK_ANIMATION_STATES.computeIfAbsent(entity,
|
||||||
|
ignored -> new AnimationClockState(vanillaPosition));
|
||||||
|
float delta = vanillaPosition - state.lastVanillaTime;
|
||||||
|
if (delta >= 0.0F) {
|
||||||
|
state.temporalTime += delta * (float) rate;
|
||||||
|
}
|
||||||
|
state.lastVanillaTime = vanillaPosition;
|
||||||
|
return state.temporalTime;
|
||||||
|
}
|
||||||
|
|
||||||
public static float dilateItemSpin(ItemEntity item, float vanillaSpin) {
|
public static float dilateItemSpin(ItemEntity item, float vanillaSpin) {
|
||||||
double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(item);
|
double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(item);
|
||||||
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
|||||||
+4
-4
@@ -5,19 +5,19 @@ import com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity;
|
|||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import software.bernie.geckolib.model.GeoModel;
|
import software.bernie.geckolib.model.GeoModel;
|
||||||
|
|
||||||
public class RoyalBlackHoleModel extends GeoModel<RoyalBlackHoleEntity> {
|
public class RoyalBlackHoleModel<T extends RoyalBlackHoleEntity> extends GeoModel<T> {
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation getModelResource(RoyalBlackHoleEntity animatable) {
|
public ResourceLocation getModelResource(T animatable) {
|
||||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/black_hole.geo.json");
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/black_hole.geo.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation getTextureResource(RoyalBlackHoleEntity animatable) {
|
public ResourceLocation getTextureResource(T animatable) {
|
||||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/queen/black_hole.png");
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/queen/black_hole.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation getAnimationResource(RoyalBlackHoleEntity animatable) {
|
public ResourceLocation getAnimationResource(T animatable) {
|
||||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/black_hole.animation.json");
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/black_hole.animation.json");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+6
-10
@@ -45,19 +45,14 @@ public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
|
|||||||
this.getBone(anchor).ifPresent(bone -> bone.setTrackingMatrices(true));
|
this.getBone(anchor).ifPresent(bone -> bone.setTrackingMatrices(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
RoyalHead.Slot slot = animatable.getRoyalBeamHeadSlot();
|
|
||||||
Vec3 beamEnd = animatable.getRoyalBeamEndPosition();
|
|
||||||
if (!animatable.isFiringRoyalBeam() || slot == null || beamEnd == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float partialTick = animationState.getPartialTick();
|
float partialTick = animationState.getPartialTick();
|
||||||
Vec3 origin = animatable.getRoyalBeamShootFrom(partialTick);
|
for (RoyalHead.Slot slot : RoyalHead.Slot.values()) {
|
||||||
|
Vec3 beamEnd = animatable.getRoyalBeamEndPosition(slot);
|
||||||
|
if (!animatable.isFiringRoyalBeam(slot) || beamEnd == null) continue;
|
||||||
|
Vec3 origin = animatable.getRoyalBeamShootFrom(slot, partialTick);
|
||||||
Vec3 direction = beamEnd.subtract(origin);
|
Vec3 direction = beamEnd.subtract(origin);
|
||||||
double horizontal = Math.sqrt(direction.x * direction.x + direction.z * direction.z);
|
double horizontal = Math.sqrt(direction.x * direction.x + direction.z * direction.z);
|
||||||
if (direction.lengthSqr() < 1.0E-6D || horizontal < 1.0E-4D) {
|
if (direction.lengthSqr() < 1.0E-6D || horizontal < 1.0E-4D) continue;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float desiredYaw = (float) (Mth.atan2(-direction.x, direction.z) * Mth.RAD_TO_DEG);
|
float desiredYaw = (float) (Mth.atan2(-direction.x, direction.z) * Mth.RAD_TO_DEG);
|
||||||
float bodyYaw = Mth.rotLerp(partialTick, animatable.yRotO, animatable.getYRot());
|
float bodyYaw = Mth.rotLerp(partialTick, animatable.yRotO, animatable.getYRot());
|
||||||
@@ -75,6 +70,7 @@ public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Vec3 getTrackedBeamAnchor(RoyalHead.Slot slot) {
|
public Vec3 getTrackedBeamAnchor(RoyalHead.Slot slot) {
|
||||||
|
|||||||
+3
@@ -14,6 +14,9 @@ public class RoyalElementalProjectileModel extends GeoModel<RoyalElementalProjec
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation getTextureResource(RoyalElementalProjectileEntity animatable) {
|
public ResourceLocation getTextureResource(RoyalElementalProjectileEntity animatable) {
|
||||||
|
if (animatable.isDreamFireball()) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/queen/dream_fire_ball.png");
|
||||||
|
}
|
||||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID,
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID,
|
||||||
"textures/entity/king/" + (animatable.isIceball() ? "ice_ball" : "fire_ball") + ".png");
|
"textures/entity/king/" + (animatable.isIceball() ? "ice_ball" : "fire_ball") + ".png");
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-6
@@ -6,22 +6,40 @@ import net.minecraft.resources.ResourceLocation;
|
|||||||
import software.bernie.geckolib.model.GeoModel;
|
import software.bernie.geckolib.model.GeoModel;
|
||||||
|
|
||||||
public class WormModel extends GeoModel<WormEntity> {
|
public class WormModel extends GeoModel<WormEntity> {
|
||||||
private static final ResourceLocation MODEL = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/worm_large.geo.json");
|
private static final ResourceLocation SMALL_MODEL = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/worm_small.geo.json");
|
||||||
private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/worm/worm_large.png");
|
private static final ResourceLocation MEDIUM_MODEL = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/worm_medium.geo.json");
|
||||||
private static final ResourceLocation ANIMATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/worm_large.animation.json");
|
private static final ResourceLocation LARGE_MODEL = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/worm_large.geo.json");
|
||||||
|
private static final ResourceLocation SMALL_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/worm/worm_small.png");
|
||||||
|
private static final ResourceLocation MEDIUM_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/worm/worm_medium.png");
|
||||||
|
private static final ResourceLocation LARGE_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/worm/worm_large.png");
|
||||||
|
private static final ResourceLocation SMALL_ANIMATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/worm_small.animation.json");
|
||||||
|
private static final ResourceLocation MEDIUM_ANIMATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/worm_medium.animation.json");
|
||||||
|
private static final ResourceLocation LARGE_ANIMATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/worm_large.animation.json");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation getModelResource(WormEntity animatable) {
|
public ResourceLocation getModelResource(WormEntity animatable) {
|
||||||
return MODEL;
|
return switch (animatable.getGrowthStage()) {
|
||||||
|
case SMALL -> SMALL_MODEL;
|
||||||
|
case MEDIUM -> MEDIUM_MODEL;
|
||||||
|
case LARGE -> LARGE_MODEL;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation getTextureResource(WormEntity animatable) {
|
public ResourceLocation getTextureResource(WormEntity animatable) {
|
||||||
return TEXTURE;
|
return switch (animatable.getGrowthStage()) {
|
||||||
|
case SMALL -> SMALL_TEXTURE;
|
||||||
|
case MEDIUM -> MEDIUM_TEXTURE;
|
||||||
|
case LARGE -> LARGE_TEXTURE;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation getAnimationResource(WormEntity animatable) {
|
public ResourceLocation getAnimationResource(WormEntity animatable) {
|
||||||
return ANIMATION;
|
return switch (animatable.getGrowthStage()) {
|
||||||
|
case SMALL -> SMALL_ANIMATION;
|
||||||
|
case MEDIUM -> MEDIUM_ANIMATION;
|
||||||
|
case LARGE -> LARGE_ANIMATION;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+4
@@ -19,7 +19,11 @@ public class RoyalBlackHoleRenderer extends GeoEntityRenderer<RoyalBlackHoleEnti
|
|||||||
@Override
|
@Override
|
||||||
public void render(RoyalBlackHoleEntity entity, float entityYaw, float partialTick, PoseStack poseStack,
|
public void render(RoyalBlackHoleEntity entity, float entityYaw, float partialTick, PoseStack poseStack,
|
||||||
MultiBufferSource bufferSource, int packedLight) {
|
MultiBufferSource bufferSource, int packedLight) {
|
||||||
|
poseStack.pushPose();
|
||||||
|
float scale = 1.5F * entity.visualGrowth();
|
||||||
|
poseStack.scale(scale, scale, scale);
|
||||||
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, 0xF000F0);
|
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, 0xF000F0);
|
||||||
|
poseStack.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+84
-17
@@ -5,6 +5,7 @@ import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
|
|||||||
import com.craisinlord.antarchy.content.entity.royal.KingEntity;
|
import com.craisinlord.antarchy.content.entity.royal.KingEntity;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.RoyalHead;
|
import com.craisinlord.antarchy.content.entity.royal.RoyalHead;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
||||||
|
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
@@ -13,15 +14,23 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
|||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
||||||
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||||
|
import software.bernie.geckolib.renderer.layer.GeoRenderLayer;
|
||||||
import software.bernie.geckolib.util.Color;
|
import software.bernie.geckolib.util.Color;
|
||||||
|
|
||||||
public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
||||||
private static final ResourceLocation QUEEN_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_beam_outer.png");
|
private static final ResourceLocation QUEEN_PURPLE_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_outer.png");
|
||||||
private static final ResourceLocation QUEEN_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_beam_inner.png");
|
private static final ResourceLocation QUEEN_PURPLE_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_inner.png");
|
||||||
private static final ResourceLocation QUEEN_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_beam_end_1.png");
|
private static final ResourceLocation QUEEN_PURPLE_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_end_1.png");
|
||||||
|
private static final ResourceLocation QUEEN_RED_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_red_beam_outer.png");
|
||||||
|
private static final ResourceLocation QUEEN_RED_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_red_beam_inner.png");
|
||||||
|
private static final ResourceLocation QUEEN_RED_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_red_beam_end_1.png");
|
||||||
|
private static final ResourceLocation QUEEN_BLACK_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_black_beam_outer.png");
|
||||||
|
private static final ResourceLocation QUEEN_BLACK_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_black_beam_inner.png");
|
||||||
|
private static final ResourceLocation QUEEN_BLACK_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_black_beam_end_1.png");
|
||||||
private static final ResourceLocation KING_FIRE_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_outer.png");
|
private static final ResourceLocation KING_FIRE_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_outer.png");
|
||||||
private static final ResourceLocation KING_FIRE_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_inner.png");
|
private static final ResourceLocation KING_FIRE_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_inner.png");
|
||||||
private static final ResourceLocation KING_FIRE_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_end_1.png");
|
private static final ResourceLocation KING_FIRE_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_end_1.png");
|
||||||
@@ -34,6 +43,45 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
|||||||
public RoyalBossRenderer(EntityRendererProvider.Context context) {
|
public RoyalBossRenderer(EntityRendererProvider.Context context) {
|
||||||
super(context, new RoyalBossModel());
|
super(context, new RoyalBossModel());
|
||||||
this.shadowRadius = 8.0F;
|
this.shadowRadius = 8.0F;
|
||||||
|
this.addRenderLayer(new RoyalAfterimageLayer(this));
|
||||||
|
this.addRenderLayer(new TemporalContractionGeoLayer<>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class RoyalAfterimageLayer extends GeoRenderLayer<RoyalBossEntity> {
|
||||||
|
private RoyalAfterimageLayer(RoyalBossRenderer renderer) {
|
||||||
|
super(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(PoseStack poseStack, RoyalBossEntity animatable, BakedGeoModel bakedModel, @Nullable RenderType renderType,
|
||||||
|
MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, float partialTick,
|
||||||
|
int packedLight, int packedOverlay) {
|
||||||
|
if (!animatable.isRoyalAccelerated() && (RoyalEffectHooks.contractedHolder() == null
|
||||||
|
|| !animatable.hasEffect(RoyalEffectHooks.contractedHolder()))) return;
|
||||||
|
Vec3 movement = animatable.getDeltaMovement();
|
||||||
|
if (movement.lengthSqr() < 1.0E-5D) return;
|
||||||
|
RenderType afterimageType = RenderType.entityTranslucent(this.getRenderer().getTextureLocation(animatable));
|
||||||
|
VertexConsumer afterimageBuffer = bufferSource.getBuffer(afterimageType);
|
||||||
|
int[] colors = {0x66FF5F6F, 0x4DFF4D60, 0x33FF3B52, 0x1FFF2944};
|
||||||
|
for (int i = colors.length - 1; i >= 0; i--) {
|
||||||
|
poseStack.pushPose();
|
||||||
|
Vec3 offset = movement.scale(-(i + 1) * 3.0D / RoyalBossEntity.MODEL_RENDER_SCALE);
|
||||||
|
poseStack.translate(offset.x, offset.y, offset.z);
|
||||||
|
this.getRenderer().reRender(
|
||||||
|
bakedModel,
|
||||||
|
poseStack,
|
||||||
|
bufferSource,
|
||||||
|
animatable,
|
||||||
|
afterimageType,
|
||||||
|
afterimageBuffer,
|
||||||
|
partialTick,
|
||||||
|
0xF000F0,
|
||||||
|
OverlayTexture.NO_OVERLAY,
|
||||||
|
colors[i]
|
||||||
|
);
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -68,18 +116,22 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
|||||||
public void render(RoyalBossEntity entity, float entityYaw, float partialTick, PoseStack poseStack,
|
public void render(RoyalBossEntity entity, float entityYaw, float partialTick, PoseStack poseStack,
|
||||||
MultiBufferSource bufferSource, int packedLight) {
|
MultiBufferSource bufferSource, int packedLight) {
|
||||||
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight);
|
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight);
|
||||||
Vec3 end = entity.getRoyalBeamEndPosition();
|
for (RoyalHead.Slot slot : RoyalHead.Slot.values()) {
|
||||||
if (!entity.isFiringRoyalBeam() || end == null) {
|
if (entity.isFiringRoyalBeam(slot) && entity.getRoyalBeamEndPosition(slot) != null) {
|
||||||
return;
|
renderBeam(entity, slot, partialTick, poseStack, bufferSource);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderBeam(RoyalBossEntity entity, RoyalHead.Slot beamHead, float partialTick,
|
||||||
|
PoseStack poseStack, MultiBufferSource bufferSource) {
|
||||||
|
Vec3 end = entity.getRoyalBeamEndPosition(beamHead);
|
||||||
|
if (end == null) return;
|
||||||
double x = Mth.lerp(partialTick, entity.xo, entity.getX());
|
double x = Mth.lerp(partialTick, entity.xo, entity.getX());
|
||||||
double y = Mth.lerp(partialTick, entity.yo, entity.getY());
|
double y = Mth.lerp(partialTick, entity.yo, entity.getY());
|
||||||
double z = Mth.lerp(partialTick, entity.zo, entity.getZ());
|
double z = Mth.lerp(partialTick, entity.zo, entity.getZ());
|
||||||
RoyalHead.Slot beamHead = entity.getRoyalBeamHeadSlot();
|
Vec3 trackedAnchor = ((RoyalBossModel) this.getGeoModel()).getTrackedBeamAnchor(beamHead);
|
||||||
Vec3 trackedAnchor = beamHead == null
|
Vec3 start = (trackedAnchor != null ? trackedAnchor : entity.getRoyalBeamShootFrom(beamHead, partialTick))
|
||||||
? null
|
|
||||||
: ((RoyalBossModel) this.getGeoModel()).getTrackedBeamAnchor(beamHead);
|
|
||||||
Vec3 start = (trackedAnchor != null ? trackedAnchor : entity.getRoyalBeamShootFrom(partialTick))
|
|
||||||
.subtract(x, y, z);
|
.subtract(x, y, z);
|
||||||
Vec3 finish = end.subtract(x, y, z);
|
Vec3 finish = end.subtract(x, y, z);
|
||||||
Vec3 axis = finish.subtract(start);
|
Vec3 axis = finish.subtract(start);
|
||||||
@@ -95,9 +147,9 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
|||||||
side1 = side1.normalize();
|
side1 = side1.normalize();
|
||||||
Vec3 side2 = dir.cross(side1).normalize();
|
Vec3 side2 = dir.cross(side1).normalize();
|
||||||
|
|
||||||
ResourceLocation outer = QUEEN_BEAM_OUTER;
|
ResourceLocation outer = QUEEN_PURPLE_BEAM_OUTER;
|
||||||
ResourceLocation inner = QUEEN_BEAM_INNER;
|
ResourceLocation inner = QUEEN_PURPLE_BEAM_INNER;
|
||||||
ResourceLocation endTexture = QUEEN_BEAM_END;
|
ResourceLocation endTexture = QUEEN_PURPLE_BEAM_END;
|
||||||
if (entity instanceof KingEntity) {
|
if (entity instanceof KingEntity) {
|
||||||
switch (entity.getRoyalBeamElement()) {
|
switch (entity.getRoyalBeamElement()) {
|
||||||
case FIRE -> {
|
case FIRE -> {
|
||||||
@@ -118,6 +170,21 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
|||||||
case GENERIC -> {
|
case GENERIC -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
switch (entity.getRoyalBeamElement(beamHead)) {
|
||||||
|
case QUEEN_RED -> {
|
||||||
|
outer = QUEEN_RED_BEAM_OUTER;
|
||||||
|
inner = QUEEN_RED_BEAM_INNER;
|
||||||
|
endTexture = QUEEN_RED_BEAM_END;
|
||||||
|
}
|
||||||
|
case QUEEN_BLACK -> {
|
||||||
|
outer = QUEEN_BLACK_BEAM_OUTER;
|
||||||
|
inner = QUEEN_BLACK_BEAM_INNER;
|
||||||
|
endTexture = QUEEN_BLACK_BEAM_END;
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float time = entity.tickCount + partialTick;
|
float time = entity.tickCount + partialTick;
|
||||||
@@ -125,19 +192,19 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
|||||||
float scroll = -time * BEAM_SCROLL_SPEED;
|
float scroll = -time * BEAM_SCROLL_SPEED;
|
||||||
var pose = poseStack.last().pose();
|
var pose = poseStack.last().pose();
|
||||||
|
|
||||||
VertexConsumer outerBuffer = bufferSource.getBuffer(RenderType.entityTranslucent(outer));
|
VertexConsumer outerBuffer = bufferSource.getBuffer(RenderType.entityTranslucentEmissive(outer));
|
||||||
drawBeamPlane(outerBuffer, pose, start, finish, side1.scale(BEAM_OUTER_RADIUS), scroll, scroll + tiles);
|
drawBeamPlane(outerBuffer, pose, start, finish, side1.scale(BEAM_OUTER_RADIUS), scroll, scroll + tiles);
|
||||||
drawBeamPlane(outerBuffer, pose, start, finish, side2.scale(BEAM_OUTER_RADIUS), scroll, scroll + tiles);
|
drawBeamPlane(outerBuffer, pose, start, finish, side2.scale(BEAM_OUTER_RADIUS), scroll, scroll + tiles);
|
||||||
|
|
||||||
float innerScroll = -time * BEAM_SCROLL_SPEED * 1.6F;
|
float innerScroll = -time * BEAM_SCROLL_SPEED * 1.6F;
|
||||||
VertexConsumer innerBuffer = bufferSource.getBuffer(RenderType.entityTranslucent(inner));
|
VertexConsumer innerBuffer = bufferSource.getBuffer(RenderType.entityTranslucentEmissive(inner));
|
||||||
drawBeamPlane(innerBuffer, pose, start, finish, side1.scale(BEAM_INNER_RADIUS), innerScroll, innerScroll + tiles);
|
drawBeamPlane(innerBuffer, pose, start, finish, side1.scale(BEAM_INNER_RADIUS), innerScroll, innerScroll + tiles);
|
||||||
drawBeamPlane(innerBuffer, pose, start, finish, side2.scale(BEAM_INNER_RADIUS), innerScroll, innerScroll + tiles);
|
drawBeamPlane(innerBuffer, pose, start, finish, side2.scale(BEAM_INNER_RADIUS), innerScroll, innerScroll + tiles);
|
||||||
|
|
||||||
float impactSize = 1.1F + 0.35F * Mth.sin(time * 0.6F);
|
float impactSize = 1.1F + 0.35F * Mth.sin(time * 0.6F);
|
||||||
Vec3 camLeft = new Vec3(this.entityRenderDispatcher.camera.getLeftVector());
|
Vec3 camLeft = new Vec3(this.entityRenderDispatcher.camera.getLeftVector());
|
||||||
Vec3 camUp = new Vec3(this.entityRenderDispatcher.camera.getUpVector());
|
Vec3 camUp = new Vec3(this.entityRenderDispatcher.camera.getUpVector());
|
||||||
VertexConsumer endBuffer = bufferSource.getBuffer(RenderType.entityTranslucent(endTexture));
|
VertexConsumer endBuffer = bufferSource.getBuffer(RenderType.entityTranslucentEmissive(endTexture));
|
||||||
drawBillboard(endBuffer, pose, finish, camLeft.scale(impactSize), camUp.scale(impactSize));
|
drawBillboard(endBuffer, pose, finish, camLeft.scale(impactSize), camUp.scale(impactSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-1
@@ -6,8 +6,11 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
||||||
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||||
|
|
||||||
@@ -17,13 +20,21 @@ public class RoyalElementalProjectileRenderer extends GeoEntityRenderer<RoyalEle
|
|||||||
this.shadowRadius = 0.0F;
|
this.shadowRadius = 0.0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RenderType getRenderType(RoyalElementalProjectileEntity animatable, ResourceLocation texture,
|
||||||
|
@Nullable MultiBufferSource bufferSource, float partialTick) {
|
||||||
|
return animatable.isIceball()
|
||||||
|
? RenderType.entityCutoutNoCull(texture)
|
||||||
|
: RenderType.entityTranslucentEmissive(texture);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preRender(PoseStack poseStack, RoyalElementalProjectileEntity animatable, BakedGeoModel model,
|
public void preRender(PoseStack poseStack, RoyalElementalProjectileEntity animatable, BakedGeoModel model,
|
||||||
MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender,
|
MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender,
|
||||||
float partialTick, int packedLight, int packedOverlay, int colour) {
|
float partialTick, int packedLight, int packedOverlay, int colour) {
|
||||||
super.preRender(poseStack, animatable, model, bufferSource, buffer, isReRender, partialTick,
|
super.preRender(poseStack, animatable, model, bufferSource, buffer, isReRender, partialTick,
|
||||||
packedLight, packedOverlay, colour);
|
packedLight, packedOverlay, colour);
|
||||||
float scale = animatable.isIceball() ? 0.75F : 0.36F;
|
float scale = animatable.isIceball() ? 0.75F : 0.72F;
|
||||||
poseStack.scale(scale, scale, scale);
|
poseStack.scale(scale, scale, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,5 +45,8 @@ public class RoyalElementalProjectileRenderer extends GeoEntityRenderer<RoyalEle
|
|||||||
float pitch = Mth.lerp(partialTick, entity.xRotO, entity.getXRot());
|
float pitch = Mth.lerp(partialTick, entity.xRotO, entity.getXRot());
|
||||||
poseStack.mulPose(Axis.YP.rotationDegrees(180.0F - yaw));
|
poseStack.mulPose(Axis.YP.rotationDegrees(180.0F - yaw));
|
||||||
poseStack.mulPose(Axis.XP.rotationDegrees(-pitch));
|
poseStack.mulPose(Axis.XP.rotationDegrees(-pitch));
|
||||||
|
if (!entity.isIceball()) {
|
||||||
|
poseStack.mulPose(Axis.ZP.rotationDegrees(180.0F));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+74
-1
@@ -8,14 +8,31 @@ import net.minecraft.client.renderer.MultiBufferSource;
|
|||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.PrinceEntity;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
||||||
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||||
|
|
||||||
public class RoyalMountRenderer extends GeoEntityRenderer<RoyalMountEntity> {
|
public class RoyalMountRenderer extends GeoEntityRenderer<RoyalMountEntity> {
|
||||||
|
private static final ResourceLocation QUEEN_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_outer.png");
|
||||||
|
private static final ResourceLocation QUEEN_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_inner.png");
|
||||||
|
private static final ResourceLocation QUEEN_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_end_1.png");
|
||||||
|
private static final ResourceLocation KING_FIRE_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_outer.png");
|
||||||
|
private static final ResourceLocation KING_FIRE_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_inner.png");
|
||||||
|
private static final ResourceLocation KING_FIRE_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_end_1.png");
|
||||||
|
private static final ResourceLocation KING_LIGHTNING_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_outer.png");
|
||||||
|
private static final ResourceLocation KING_LIGHTNING_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_inner.png");
|
||||||
|
private static final ResourceLocation KING_LIGHTNING_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_end_1.png");
|
||||||
|
private static final ResourceLocation KING_ICE_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_outer.png");
|
||||||
|
private static final ResourceLocation KING_ICE_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_inner.png");
|
||||||
|
private static final ResourceLocation KING_ICE_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_end_1.png");
|
||||||
public RoyalMountRenderer(EntityRendererProvider.Context context) {
|
public RoyalMountRenderer(EntityRendererProvider.Context context) {
|
||||||
super(context, new RoyalMountModel());
|
super(context, new RoyalMountModel());
|
||||||
this.shadowRadius = 1.1F;
|
this.shadowRadius = 1.1F;
|
||||||
|
this.addRenderLayer(new TemporalContractionGeoLayer<>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -27,8 +44,64 @@ public class RoyalMountRenderer extends GeoEntityRenderer<RoyalMountEntity> {
|
|||||||
public void preRender(PoseStack poseStack, RoyalMountEntity animatable, BakedGeoModel model, @Nullable MultiBufferSource bufferSource,
|
public void preRender(PoseStack poseStack, RoyalMountEntity animatable, BakedGeoModel model, @Nullable MultiBufferSource bufferSource,
|
||||||
@Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {
|
@Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {
|
||||||
super.preRender(poseStack, animatable, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour);
|
super.preRender(poseStack, animatable, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour);
|
||||||
float scale = animatable.getAgeScale();
|
float scale = animatable.getGrowthScale();
|
||||||
poseStack.scale(scale, scale, scale);
|
poseStack.scale(scale, scale, scale);
|
||||||
this.shadowRadius = 1.1F * scale;
|
this.shadowRadius = 1.1F * scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RoyalMountEntity entity, float entityYaw, float partialTick, PoseStack poseStack,
|
||||||
|
MultiBufferSource bufferSource, int packedLight) {
|
||||||
|
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight);
|
||||||
|
Vec3 end = entity.getBeamEndPosition();
|
||||||
|
if (!entity.isFiringBeam() || end == null) return;
|
||||||
|
double x = Mth.lerp(partialTick, entity.xo, entity.getX());
|
||||||
|
double y = Mth.lerp(partialTick, entity.yo, entity.getY());
|
||||||
|
double z = Mth.lerp(partialTick, entity.zo, entity.getZ());
|
||||||
|
Vec3 start = entity.beamShootFrom().subtract(x, y, z);
|
||||||
|
Vec3 finish = end.subtract(x, y, z);
|
||||||
|
Vec3 axis = finish.subtract(start);
|
||||||
|
double length = axis.length();
|
||||||
|
if (length < 0.05D) return;
|
||||||
|
Vec3 dir = axis.scale(1.0D / length);
|
||||||
|
Vec3 side = dir.cross(new Vec3(0.0D, 1.0D, 0.0D));
|
||||||
|
if (side.lengthSqr() < 1.0E-4D) side = dir.cross(new Vec3(1.0D, 0.0D, 0.0D));
|
||||||
|
side = side.normalize();
|
||||||
|
ResourceLocation outer = QUEEN_OUTER;
|
||||||
|
ResourceLocation inner = QUEEN_INNER;
|
||||||
|
ResourceLocation endTexture = QUEEN_END;
|
||||||
|
if (entity instanceof PrinceEntity) {
|
||||||
|
switch (entity.getBeamElement()) {
|
||||||
|
case FIRE -> { outer = KING_FIRE_OUTER; inner = KING_FIRE_INNER; endTexture = KING_FIRE_END; }
|
||||||
|
case ICE -> { outer = KING_ICE_OUTER; inner = KING_ICE_INNER; endTexture = KING_ICE_END; }
|
||||||
|
default -> { outer = KING_LIGHTNING_OUTER; inner = KING_LIGHTNING_INNER; endTexture = KING_LIGHTNING_END; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float time = entity.tickCount + partialTick;
|
||||||
|
float tiles = (float) (length / 3.0D);
|
||||||
|
org.joml.Matrix4f pose = poseStack.last().pose();
|
||||||
|
drawBeam(bufferSource.getBuffer(RenderType.entityTranslucentEmissive(outer)), pose, start, finish, side.scale(0.24D), -time * 0.32F, -time * 0.32F + tiles);
|
||||||
|
drawBeam(bufferSource.getBuffer(RenderType.entityTranslucentEmissive(inner)), pose, start, finish, side.scale(0.13D), -time * 0.5F, -time * 0.5F + tiles);
|
||||||
|
Vec3 up = new Vec3(this.entityRenderDispatcher.camera.getUpVector()).scale(0.55D);
|
||||||
|
Vec3 left = new Vec3(this.entityRenderDispatcher.camera.getLeftVector()).scale(0.55D);
|
||||||
|
drawQuad(bufferSource.getBuffer(RenderType.entityTranslucentEmissive(endTexture)), pose, finish.add(left).add(up), finish.subtract(left).add(up), finish.subtract(left).subtract(up), finish.add(left).subtract(up));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawBeam(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 start, Vec3 end, Vec3 half, float startV, float endV) {
|
||||||
|
drawQuad(vertices, pose, start.subtract(half), start.add(half), end.add(half), end.subtract(half), startV, endV);
|
||||||
|
drawQuad(vertices, pose, start.add(half), start.subtract(half), end.subtract(half), end.add(half), startV, endV);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawQuad(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 a, Vec3 b, Vec3 c, Vec3 d) {
|
||||||
|
drawQuad(vertices, pose, a, b, c, d, 0.0F, 1.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawQuad(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 a, Vec3 b, Vec3 c, Vec3 d, float startV, float endV) {
|
||||||
|
vertex(vertices, pose, a, 0.0F, startV); vertex(vertices, pose, b, 1.0F, startV); vertex(vertices, pose, c, 1.0F, endV); vertex(vertices, pose, d, 0.0F, endV);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void vertex(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 pos, float u, float v) {
|
||||||
|
vertices.addVertex(pose, (float) pos.x, (float) pos.y, (float) pos.z).setColor(255, 255, 255, 255).setUv(u, v)
|
||||||
|
.setOverlay(net.minecraft.client.renderer.texture.OverlayTexture.NO_OVERLAY).setLight(0x00F000F0).setNormal(0.0F, 1.0F, 0.0F);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
-16
@@ -1,14 +1,11 @@
|
|||||||
package com.craisinlord.antarchy.content.effect;
|
package com.craisinlord.antarchy.content.effect;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.Antarchy;
|
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
|
||||||
import net.minecraft.world.effect.MobEffectInstance;
|
|
||||||
import net.minecraft.world.effect.MobEffect;
|
import net.minecraft.world.effect.MobEffect;
|
||||||
import net.minecraft.world.effect.MobEffectCategory;
|
import net.minecraft.world.effect.MobEffectCategory;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
|
|
||||||
public final class InvertedMobEffect extends MobEffect {
|
public final class InvertedMobEffect extends MobEffect {
|
||||||
private static final AntarchyGravityTransition EFFECT_TRANSITION = new AntarchyGravityTransition(12);
|
private static final AntarchyGravityTransition EFFECT_TRANSITION = new AntarchyGravityTransition(12);
|
||||||
@@ -22,19 +19,6 @@ public final class InvertedMobEffect extends MobEffect {
|
|||||||
public boolean applyEffectTick(LivingEntity entity, int amplifier) {
|
public boolean applyEffectTick(LivingEntity entity, int amplifier) {
|
||||||
if (!entity.level().isClientSide()) {
|
if (!entity.level().isClientSide()) {
|
||||||
if (AntarchyGravityApi.getGravityDirection(entity) != AntarchyGravityDirection.UP || !AntarchyGravityApi.isGravityForced(entity)) {
|
if (AntarchyGravityApi.getGravityDirection(entity) != AntarchyGravityDirection.UP || !AntarchyGravityApi.isGravityForced(entity)) {
|
||||||
MobEffectInstance effect = entity.getEffect(com.craisinlord.antarchy.content.AntarchyObjects.INVERTED_EFFECT.get());
|
|
||||||
if (entity instanceof Player || com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager.isThoraxis(entity.level())) {
|
|
||||||
Antarchy.LOGGER.info(
|
|
||||||
"[antarchy-gravity] applying inverted gravity from effect targetType={} uuid={} pos=({}, {}, {}) dim={} duration={} ambient={} visible={} forcedBefore={} gameTime={}",
|
|
||||||
entity.getType(), entity.getUUID(), entity.getX(), entity.getY(), entity.getZ(),
|
|
||||||
entity.level().dimension().location(),
|
|
||||||
effect != null ? effect.getDuration() : -1,
|
|
||||||
effect != null && effect.isAmbient(),
|
|
||||||
effect != null && effect.isVisible(),
|
|
||||||
AntarchyGravityApi.isGravityForced(entity),
|
|
||||||
entity.level().getGameTime()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
AntarchyGravityApi.setForcedGravityDirection(entity, AntarchyGravityDirection.UP, EFFECT_TRANSITION);
|
AntarchyGravityApi.setForcedGravityDirection(entity, AntarchyGravityDirection.UP, EFFECT_TRANSITION);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+1
-1
@@ -101,7 +101,7 @@ public class ManticoreEntity extends Monster implements GeoEntity {
|
|||||||
return Mob.createMobAttributes()
|
return Mob.createMobAttributes()
|
||||||
.add(Attributes.MAX_HEALTH, AntarchySettings.manticoreHealth())
|
.add(Attributes.MAX_HEALTH, AntarchySettings.manticoreHealth())
|
||||||
.add(Attributes.MOVEMENT_SPEED, 0.3D)
|
.add(Attributes.MOVEMENT_SPEED, 0.3D)
|
||||||
.add(Attributes.FLYING_SPEED, 0.6D)
|
.add(Attributes.FLYING_SPEED, 1.2D)
|
||||||
.add(Attributes.ATTACK_DAMAGE, AntarchySettings.manticoreAttackDamage())
|
.add(Attributes.ATTACK_DAMAGE, AntarchySettings.manticoreAttackDamage())
|
||||||
.add(Attributes.FOLLOW_RANGE, 28.0D)
|
.add(Attributes.FOLLOW_RANGE, 28.0D)
|
||||||
.add(Attributes.KNOCKBACK_RESISTANCE, 0.2D);
|
.add(Attributes.KNOCKBACK_RESISTANCE, 0.2D);
|
||||||
|
|||||||
+10
@@ -351,6 +351,16 @@ public class ScorpionEntity extends Monster implements GeoEntity {
|
|||||||
ScorpionEntity.this.getNavigation().stop();
|
ScorpionEntity.this.getNavigation().stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// This goal overrides MeleeAttackGoal.tick, so the gravity mixin on the
|
||||||
|
// vanilla method cannot supply the inverted movement frame here.
|
||||||
|
LivingEntity target = ScorpionEntity.this.getTarget();
|
||||||
|
if (target != null && ThoraxisUndersideManager.shouldInvertInUnderside(ScorpionEntity.this)) {
|
||||||
|
ScorpionEntity.this.getNavigation().stop();
|
||||||
|
ScorpionEntity.this.getMoveControl().setWantedPosition(
|
||||||
|
target.getX(), target.getY(), target.getZ(), 1.15D);
|
||||||
|
this.checkAndPerformAttack(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
super.tick();
|
super.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,12 @@ import net.minecraft.world.level.block.Blocks;
|
|||||||
import net.minecraft.world.level.block.MultifaceBlock;
|
import net.minecraft.world.level.block.MultifaceBlock;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.entity.EntityDimensions;
|
||||||
|
import net.minecraft.world.entity.Pose;
|
||||||
|
import net.minecraft.world.DifficultyInstance;
|
||||||
|
import net.minecraft.world.entity.SpawnGroupData;
|
||||||
import software.bernie.geckolib.animatable.GeoEntity;
|
import software.bernie.geckolib.animatable.GeoEntity;
|
||||||
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||||
import software.bernie.geckolib.animation.AnimatableManager;
|
import software.bernie.geckolib.animation.AnimatableManager;
|
||||||
@@ -48,6 +53,42 @@ import software.bernie.geckolib.animation.RawAnimation;
|
|||||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
public class WormEntity extends Monster implements GeoEntity {
|
public class WormEntity extends Monster implements GeoEntity {
|
||||||
|
public enum GrowthStage {
|
||||||
|
SMALL(0, EntityDimensions.scalable(0.55F, 0.8F), 8.0D, 0.29D, 2.0D, 20.0D, 0.05D, 2),
|
||||||
|
MEDIUM(1, EntityDimensions.scalable(0.9F, 1.5F), 20.0D, 0.25D, 4.0D, 24.0D, 0.2D, 5),
|
||||||
|
LARGE(2, EntityDimensions.scalable(1.35F, 2.75F), 36.0D, 0.22D, 7.0D, 28.0D, 0.45D, 8);
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
private final EntityDimensions dimensions;
|
||||||
|
private final double health;
|
||||||
|
private final double speed;
|
||||||
|
private final double damage;
|
||||||
|
private final double followRange;
|
||||||
|
private final double knockbackResistance;
|
||||||
|
private final int xp;
|
||||||
|
|
||||||
|
GrowthStage(int id, EntityDimensions dimensions, double health, double speed, double damage,
|
||||||
|
double followRange, double knockbackResistance, int xp) {
|
||||||
|
this.id = id;
|
||||||
|
this.dimensions = dimensions;
|
||||||
|
this.health = health;
|
||||||
|
this.speed = speed;
|
||||||
|
this.damage = damage;
|
||||||
|
this.followRange = followRange;
|
||||||
|
this.knockbackResistance = knockbackResistance;
|
||||||
|
this.xp = xp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GrowthStage byId(int id) {
|
||||||
|
for (GrowthStage stage : values()) {
|
||||||
|
if (stage.id == id) return stage;
|
||||||
|
}
|
||||||
|
return LARGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int SMALL_GROWTH_TICKS = 20 * 60 * 2;
|
||||||
|
private static final int MEDIUM_GROWTH_TICKS = 20 * 60 * 3;
|
||||||
private static final ResourceKey<Biome> WORMY_CAVES = ResourceKey.create(
|
private static final ResourceKey<Biome> WORMY_CAVES = ResourceKey.create(
|
||||||
Registries.BIOME,
|
Registries.BIOME,
|
||||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "wormy_caves")
|
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "wormy_caves")
|
||||||
@@ -57,6 +98,7 @@ public class WormEntity extends Monster implements GeoEntity {
|
|||||||
private static final int MUCUS_TRAIL_INTERVAL = 6;
|
private static final int MUCUS_TRAIL_INTERVAL = 6;
|
||||||
private static final double MUCUS_TRAIL_MIN_DISTANCE_SQR = 0.36D;
|
private static final double MUCUS_TRAIL_MIN_DISTANCE_SQR = 0.36D;
|
||||||
private static final EntityDataAccessor<Integer> ANIMATION_STATE = SynchedEntityData.defineId(WormEntity.class, EntityDataSerializers.INT);
|
private static final EntityDataAccessor<Integer> ANIMATION_STATE = SynchedEntityData.defineId(WormEntity.class, EntityDataSerializers.INT);
|
||||||
|
private static final EntityDataAccessor<Integer> GROWTH_STAGE = SynchedEntityData.defineId(WormEntity.class, EntityDataSerializers.INT);
|
||||||
private static final int ANIM_INGROUND = 0;
|
private static final int ANIM_INGROUND = 0;
|
||||||
private static final int ANIM_CRAWL = 1;
|
private static final int ANIM_CRAWL = 1;
|
||||||
private static final int ANIM_ATTACK = 2;
|
private static final int ANIM_ATTACK = 2;
|
||||||
@@ -67,6 +109,7 @@ public class WormEntity extends Monster implements GeoEntity {
|
|||||||
private int attackAnimationTicks;
|
private int attackAnimationTicks;
|
||||||
private int mucusTrailCooldown;
|
private int mucusTrailCooldown;
|
||||||
private Vec3 lastMucusTrailPosition;
|
private Vec3 lastMucusTrailPosition;
|
||||||
|
private int growthAge;
|
||||||
|
|
||||||
public WormEntity(EntityType<? extends WormEntity> entityType, Level level) {
|
public WormEntity(EntityType<? extends WormEntity> entityType, Level level) {
|
||||||
super(entityType, level);
|
super(entityType, level);
|
||||||
@@ -103,6 +146,67 @@ public class WormEntity extends Monster implements GeoEntity {
|
|||||||
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||||
super.defineSynchedData(builder);
|
super.defineSynchedData(builder);
|
||||||
builder.define(ANIMATION_STATE, ANIM_INGROUND);
|
builder.define(ANIMATION_STATE, ANIM_INGROUND);
|
||||||
|
builder.define(GROWTH_STAGE, GrowthStage.LARGE.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GrowthStage getGrowthStage() {
|
||||||
|
return GrowthStage.byId(this.entityData.get(GROWTH_STAGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGrowthStage(GrowthStage stage) {
|
||||||
|
if (this.entityData.get(GROWTH_STAGE) == stage.id) return;
|
||||||
|
this.entityData.set(GROWTH_STAGE, stage.id);
|
||||||
|
this.refreshDimensions();
|
||||||
|
this.applyStageAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyStageAttributes() {
|
||||||
|
GrowthStage stage = this.getGrowthStage();
|
||||||
|
if (this.getAttribute(Attributes.MAX_HEALTH) != null) this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(stage.health);
|
||||||
|
if (this.getAttribute(Attributes.MOVEMENT_SPEED) != null) this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(stage.speed);
|
||||||
|
if (this.getAttribute(Attributes.ATTACK_DAMAGE) != null) this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(stage.damage);
|
||||||
|
if (this.getAttribute(Attributes.FOLLOW_RANGE) != null) this.getAttribute(Attributes.FOLLOW_RANGE).setBaseValue(stage.followRange);
|
||||||
|
if (this.getAttribute(Attributes.KNOCKBACK_RESISTANCE) != null) this.getAttribute(Attributes.KNOCKBACK_RESISTANCE).setBaseValue(stage.knockbackResistance);
|
||||||
|
this.xpReward = stage.xp;
|
||||||
|
if (!this.level().isClientSide) this.setHealth(Math.min(this.getHealth(), (float) stage.health));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||||
|
return this.getGrowthStage().dimensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSyncedDataUpdated(EntityDataAccessor<?> key) {
|
||||||
|
super.onSyncedDataUpdated(key);
|
||||||
|
if (GROWTH_STAGE.equals(key)) this.refreshDimensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnReason, SpawnGroupData spawnData) {
|
||||||
|
SpawnGroupData result = super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
|
||||||
|
if (spawnReason == MobSpawnType.NATURAL || spawnReason == MobSpawnType.CHUNK_GENERATION || spawnReason == MobSpawnType.SPAWN_EGG) {
|
||||||
|
float roll = this.random.nextFloat();
|
||||||
|
this.setGrowthStage(roll < 0.4F ? GrowthStage.SMALL : roll < 0.6F ? GrowthStage.MEDIUM : GrowthStage.LARGE);
|
||||||
|
this.growthAge = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.addAdditionalSaveData(tag);
|
||||||
|
tag.putInt("GrowthStage", this.getGrowthStage().id);
|
||||||
|
tag.putInt("GrowthAge", this.growthAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.readAdditionalSaveData(tag);
|
||||||
|
this.entityData.set(GROWTH_STAGE, tag.contains("GrowthStage") ? tag.getInt("GrowthStage") : GrowthStage.LARGE.id);
|
||||||
|
this.growthAge = tag.getInt("GrowthAge");
|
||||||
|
this.refreshDimensions();
|
||||||
|
this.applyStageAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -153,6 +257,7 @@ public class WormEntity extends Monster implements GeoEntity {
|
|||||||
if (this.level().isClientSide) {
|
if (this.level().isClientSide) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.tickGrowth();
|
||||||
this.tickMucusTrail();
|
this.tickMucusTrail();
|
||||||
if (this.attackAnimationTicks > 0) {
|
if (this.attackAnimationTicks > 0) {
|
||||||
this.attackAnimationTicks--;
|
this.attackAnimationTicks--;
|
||||||
@@ -160,7 +265,21 @@ public class WormEntity extends Monster implements GeoEntity {
|
|||||||
this.updateAnimationState();
|
this.updateAnimationState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tickGrowth() {
|
||||||
|
GrowthStage stage = this.getGrowthStage();
|
||||||
|
if (stage == GrowthStage.LARGE) return;
|
||||||
|
this.growthAge++;
|
||||||
|
if (stage == GrowthStage.SMALL && this.growthAge >= SMALL_GROWTH_TICKS) {
|
||||||
|
this.growthAge = 0;
|
||||||
|
this.setGrowthStage(GrowthStage.MEDIUM);
|
||||||
|
} else if (stage == GrowthStage.MEDIUM && this.growthAge >= MEDIUM_GROWTH_TICKS) {
|
||||||
|
this.growthAge = 0;
|
||||||
|
this.setGrowthStage(GrowthStage.LARGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void tickMucusTrail() {
|
private void tickMucusTrail() {
|
||||||
|
if (this.getGrowthStage() == GrowthStage.SMALL) return;
|
||||||
if (this.mucusTrailCooldown > 0) {
|
if (this.mucusTrailCooldown > 0) {
|
||||||
this.mucusTrailCooldown--;
|
this.mucusTrailCooldown--;
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -74,6 +74,7 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
private static final double PORTAL_RADIUS = 1.35D;
|
private static final double PORTAL_RADIUS = 1.35D;
|
||||||
private static final double EXIT_OFFSET = 2.4D;
|
private static final double EXIT_OFFSET = 2.4D;
|
||||||
private static final Map<UUID, Long> TELEPORT_COOLDOWNS = new HashMap<>();
|
private static final Map<UUID, Long> TELEPORT_COOLDOWNS = new HashMap<>();
|
||||||
|
private static long lastTeleportCooldownCleanupTick = Long.MIN_VALUE;
|
||||||
private static final Map<UUID, Set<UUID>> QUEEN_TEAR_IDS = new HashMap<>();
|
private static final Map<UUID, Set<UUID>> QUEEN_TEAR_IDS = new HashMap<>();
|
||||||
|
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
@@ -149,6 +150,7 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.ageTicks++;
|
this.ageTicks++;
|
||||||
|
cleanupTeleportCooldowns(this.level().getGameTime());
|
||||||
if (this.ageTicks == 1) {
|
if (this.ageTicks == 1) {
|
||||||
this.level().playSound(null, this.blockPosition(), AntarchySoundEvents.DIMENSIONAL_TEAR_OPEN.get(), SoundSource.HOSTILE, 1.0F, 1.0F);
|
this.level().playSound(null, this.blockPosition(), AntarchySoundEvents.DIMENSIONAL_TEAR_OPEN.get(), SoundSource.HOSTILE, 1.0F, 1.0F);
|
||||||
}
|
}
|
||||||
@@ -370,7 +372,7 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
entity.hasImpulse = true;
|
entity.hasImpulse = true;
|
||||||
if (entity instanceof LivingEntity living) {
|
if (entity instanceof LivingEntity living) {
|
||||||
int invertedDuration = AntarchySettings.dimensionalTearInvertedDurationTicks();
|
int invertedDuration = AntarchySettings.dimensionalTearInvertedDurationTicks();
|
||||||
Antarchy.LOGGER.info(
|
Antarchy.LOGGER.debug(
|
||||||
"[antarchy-dimensional-tear] applying inverted effect targetType={} uuid={} fromTear={} toTear={} startPos=({}, {}, {}) exitPos=({}, {}, {}) dim={} durationTicks={}",
|
"[antarchy-dimensional-tear] applying inverted effect targetType={} uuid={} fromTear={} toTear={} startPos=({}, {}, {}) exitPos=({}, {}, {}) dim={} durationTicks={}",
|
||||||
living.getType(), living.getUUID(), this.getUUID(), destination.getUUID(),
|
living.getType(), living.getUUID(), this.getUUID(), destination.getUUID(),
|
||||||
startPos.x, startPos.y, startPos.z,
|
startPos.x, startPos.y, startPos.z,
|
||||||
@@ -382,6 +384,15 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
this.level().playSound(null, this.blockPosition(), SoundEvents.ENDERMAN_TELEPORT, SoundSource.NEUTRAL, 0.7F, 0.65F + this.random.nextFloat() * 0.2F);
|
this.level().playSound(null, this.blockPosition(), SoundEvents.ENDERMAN_TELEPORT, SoundSource.NEUTRAL, 0.7F, 0.65F + this.random.nextFloat() * 0.2F);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void cleanupTeleportCooldowns(long gameTime) {
|
||||||
|
if (gameTime <= lastTeleportCooldownCleanupTick
|
||||||
|
|| gameTime - lastTeleportCooldownCleanupTick < TELEPORT_COOLDOWN_TICKS * 4L) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastTeleportCooldownCleanupTick = gameTime;
|
||||||
|
TELEPORT_COOLDOWNS.entrySet().removeIf(entry -> entry.getValue() <= gameTime);
|
||||||
|
}
|
||||||
|
|
||||||
private Vec3 exitPosition() {
|
private Vec3 exitPosition() {
|
||||||
Vec3 facing = this.getViewVector(1.0F);
|
Vec3 facing = this.getViewVector(1.0F);
|
||||||
if (facing.lengthSqr() < 1.0E-4D) {
|
if (facing.lengthSqr() < 1.0E-4D) {
|
||||||
|
|||||||
+16
-6
@@ -332,9 +332,12 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.tickRoyalPunishment();
|
this.tickRoyalPunishment();
|
||||||
if (this.iceBuildup.size() > 16) {
|
long gameTime = this.level().getGameTime();
|
||||||
this.iceBuildup.clear();
|
this.judgmentCooldowns.entrySet().removeIf(entry -> entry.getValue() <= gameTime);
|
||||||
}
|
this.lastPlayerDamageTime.entrySet().removeIf(entry -> gameTime - entry.getValue() > 600L);
|
||||||
|
ServerLevel serverLevel = (ServerLevel) this.level();
|
||||||
|
this.iceBuildup.entrySet().removeIf(entry -> serverLevel.getEntity(entry.getKey()) == null);
|
||||||
|
if (this.iceBuildup.size() > 16) this.iceBuildup.clear();
|
||||||
LivingEntity target = this.getTarget();
|
LivingEntity target = this.getTarget();
|
||||||
if (target != null && !this.isDeadOrDying() && this.level() instanceof ServerLevel level) {
|
if (target != null && !this.isDeadOrDying() && this.level() instanceof ServerLevel level) {
|
||||||
this.trackBehavior(target);
|
this.trackBehavior(target);
|
||||||
@@ -346,6 +349,7 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
if (this.isDeadOrDying() || !(this.level() instanceof ServerLevel)) {
|
if (this.isDeadOrDying() || !(this.level() instanceof ServerLevel)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.setRoyalFlying(true);
|
||||||
this.decreeRetreatPressure = false;
|
this.decreeRetreatPressure = false;
|
||||||
if (this.patrolCenter == null || this.position().distanceToSqr(this.patrolCenter) > 64.0D * 64.0D) {
|
if (this.patrolCenter == null || this.position().distanceToSqr(this.patrolCenter) > 64.0D * 64.0D) {
|
||||||
this.patrolCenter = this.position();
|
this.patrolCenter = this.position();
|
||||||
@@ -397,7 +401,7 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
away = away.normalize();
|
away = away.normalize();
|
||||||
this.exileTarget.setDeltaMovement(away.x * 2.6D, 1.35D, away.z * 2.6D);
|
this.exileTarget.setDeltaMovement(away.x * 2.6D, 1.35D, away.z * 2.6D);
|
||||||
this.exileTarget.hasImpulse = true;
|
this.exileTarget.hasImpulse = true;
|
||||||
this.triggerAnim("body_action", "wing_gust");
|
this.triggerAnim("wing_action", "wing_gust");
|
||||||
this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.82F);
|
this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.82F);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -555,6 +559,7 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
this.activeDecree = decree;
|
this.activeDecree = decree;
|
||||||
this.activeDecreeTicks = 300;
|
this.activeDecreeTicks = 300;
|
||||||
this.decreeCooldownTicks = 0;
|
this.decreeCooldownTicks = 0;
|
||||||
|
this.projectRoyalSound(AntarchySoundEvents.KING_DECREE.get(), 4.0F, 1.0F, target);
|
||||||
this.sendDecreeTitle(target);
|
this.sendDecreeTitle(target);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -672,7 +677,7 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
&& this.beginRoyalAttack("wing_gust", RoyalAttackLane.BODY, WING_GUST_COOLDOWN_TICKS,
|
&& this.beginRoyalAttack("wing_gust", RoyalAttackLane.BODY, WING_GUST_COOLDOWN_TICKS,
|
||||||
WING_GUST_WINDUP_TICKS, 1, 16, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
WING_GUST_WINDUP_TICKS, 1, 16, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||||
@Override public void onStart() {
|
@Override public void onStart() {
|
||||||
KingEntity.this.triggerAnim("body_action", "wing_gust");
|
KingEntity.this.triggerAnim("wing_action", "wing_gust");
|
||||||
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.85F);
|
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.85F);
|
||||||
}
|
}
|
||||||
@Override public void onActive(int elapsedTicks) {
|
@Override public void onActive(int elapsedTicks) {
|
||||||
@@ -775,6 +780,8 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||||
@Override public void onStart() {
|
@Override public void onStart() {
|
||||||
KingEntity.this.triggerAnim(RoyalHead.Slot.LEFT.controllerName(), "shoot");
|
KingEntity.this.triggerAnim(RoyalHead.Slot.LEFT.controllerName(), "shoot");
|
||||||
|
KingEntity.this.playRoyalSound(SoundEvents.FIRECHARGE_USE, 0.8F);
|
||||||
|
KingEntity.this.playRoyalSound(SoundEvents.GHAST_WARN, 1.2F);
|
||||||
}
|
}
|
||||||
@Override public void onActive(int elapsedTicks) {
|
@Override public void onActive(int elapsedTicks) {
|
||||||
Vec3 origin = KingEntity.this.headAnchor(KingEntity.this.royalHead(RoyalHead.Slot.LEFT));
|
Vec3 origin = KingEntity.this.headAnchor(KingEntity.this.royalHead(RoyalHead.Slot.LEFT));
|
||||||
@@ -891,6 +898,7 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
this.decreeRetreatPressure = false;
|
this.decreeRetreatPressure = false;
|
||||||
this.playRoyalSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 0.9F + this.random.nextFloat() * 0.15F);
|
this.playRoyalSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 0.9F + this.random.nextFloat() * 0.15F);
|
||||||
this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 0.8F + this.random.nextFloat() * 0.12F);
|
this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 0.8F + this.random.nextFloat() * 0.12F);
|
||||||
|
this.projectRoyalSound(AntarchySoundEvents.KING_DECREE.get(), 4.0F, 1.0F, target);
|
||||||
if (target instanceof ServerPlayer player) this.sendDecreeTitle(player);
|
if (target instanceof ServerPlayer player) this.sendDecreeTitle(player);
|
||||||
}
|
}
|
||||||
int countdown = this.activeDecree.countdownTicks(target);
|
int countdown = this.activeDecree.countdownTicks(target);
|
||||||
@@ -904,6 +912,7 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.activeDecree != null && --this.activeDecreeTicks <= 0) {
|
if (this.activeDecree != null && --this.activeDecreeTicks <= 0) {
|
||||||
|
this.projectRoyalSound(AntarchySoundEvents.KING_SUCCESS.get(), 4.0F, 1.0F, target);
|
||||||
this.endDecree(target);
|
this.endDecree(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -955,12 +964,12 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
this.endDecree(target);
|
this.endDecree(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resolves a decree violation once, using the existing bounded judgment while the new judgment system is pending. */
|
|
||||||
public void failActiveDecree(@Nullable LivingEntity target) {
|
public void failActiveDecree(@Nullable LivingEntity target) {
|
||||||
if (this.activeDecree == null || target == null || !target.isAlive()) {
|
if (this.activeDecree == null || target == null || !target.isAlive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (target instanceof ServerPlayer player) {
|
if (target instanceof ServerPlayer player) {
|
||||||
|
this.projectRoyalSound(AntarchySoundEvents.KING_JUDGEMENT.get(), 4.0F, 1.0F, target);
|
||||||
this.debugTriggerPunishment(RoyalPunishmentType.ROYAL_EXILE, player);
|
this.debugTriggerPunishment(RoyalPunishmentType.ROYAL_EXILE, player);
|
||||||
} else {
|
} else {
|
||||||
this.invokeJudgment(target);
|
this.invokeJudgment(target);
|
||||||
@@ -982,6 +991,7 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
long now = this.level().getGameTime();
|
long now = this.level().getGameTime();
|
||||||
if (this.judgmentCooldowns.getOrDefault(target.getUUID(), 0L) <= now) {
|
if (this.judgmentCooldowns.getOrDefault(target.getUUID(), 0L) <= now) {
|
||||||
this.judgmentCooldowns.put(target.getUUID(), now + 20L);
|
this.judgmentCooldowns.put(target.getUUID(), now + 20L);
|
||||||
|
this.projectRoyalSound(AntarchySoundEvents.KING_JUDGEMENT.get(), 4.0F, 1.0F, target);
|
||||||
target.hurt(this.damageSources().magic(), 6.0F);
|
target.hurt(this.damageSources().magic(), 6.0F);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -31,6 +31,15 @@ public class PrinceEntity extends RoyalMountEntity {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RoyalBeamElement getBeamElement() {
|
||||||
|
return switch (this.getBeamHead()) {
|
||||||
|
case 0 -> RoyalBeamElement.FIRE;
|
||||||
|
case 2 -> RoyalBeamElement.ICE;
|
||||||
|
default -> RoyalBeamElement.LIGHTNING;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String geoName() {
|
protected String geoName() {
|
||||||
return "prince";
|
return "prince";
|
||||||
|
|||||||
+142
-43
@@ -7,6 +7,7 @@ import com.craisinlord.antarchy.content.AntarchyTags;
|
|||||||
import com.craisinlord.antarchy.content.entity.ManticoreEntity;
|
import com.craisinlord.antarchy.content.entity.ManticoreEntity;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
@@ -21,23 +22,27 @@ import net.minecraft.world.entity.Entity;
|
|||||||
import net.minecraft.world.BossEvent;
|
import net.minecraft.world.BossEvent;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
|
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
|
||||||
import net.minecraft.world.entity.MobSpawnType;
|
import net.minecraft.world.entity.MobSpawnType;
|
||||||
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 com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamSettings;
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamSettings;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamTerrainMode;
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamTerrainMode;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackLane;
|
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackLane;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalEffectController;
|
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalEffectController;
|
||||||
import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity;
|
import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity;
|
||||||
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
|
||||||
import net.minecraft.world.damagesource.DamageSource;
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class QueenEntity extends RoyalBossEntity {
|
public class QueenEntity extends RoyalBossEntity {
|
||||||
|
static final double TIME_FIELD_RADIUS_SCALE = 3.0D;
|
||||||
private static final String SUMMON_COOLDOWN_KEY = "ManticoreSummonCooldownTicks";
|
private static final String SUMMON_COOLDOWN_KEY = "ManticoreSummonCooldownTicks";
|
||||||
private static final int FAILED_SUMMON_RETRY_TICKS = 20;
|
private static final int FAILED_SUMMON_RETRY_TICKS = 20;
|
||||||
private static final int POSITION_ATTEMPTS_PER_MANTICORE = 8;
|
private static final int POSITION_ATTEMPTS_PER_MANTICORE = 8;
|
||||||
@@ -47,7 +52,6 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
private static final DustParticleOptions ACCEL_DUST = new DustParticleOptions(new org.joml.Vector3f(1.0F, 0.15F, 0.15F), 2.0F);
|
private static final DustParticleOptions ACCEL_DUST = new DustParticleOptions(new org.joml.Vector3f(1.0F, 0.15F, 0.15F), 2.0F);
|
||||||
|
|
||||||
private static final int GRAVITY_STOMP_COOLDOWN = 180;
|
private static final int GRAVITY_STOMP_COOLDOWN = 180;
|
||||||
private static final int TIME_FIELD_COOLDOWN = 260;
|
|
||||||
private static final int MOMENTUM_LOCK_COOLDOWN = 420;
|
private static final int MOMENTUM_LOCK_COOLDOWN = 420;
|
||||||
private static final int MOMENTUM_LOCK_DURATION = 90;
|
private static final int MOMENTUM_LOCK_DURATION = 90;
|
||||||
private static final double MOMENTUM_LOCK_RADIUS = 26.0D;
|
private static final double MOMENTUM_LOCK_RADIUS = 26.0D;
|
||||||
@@ -61,13 +65,12 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
|
|
||||||
private int manticoreSummonCooldownTicks;
|
private int manticoreSummonCooldownTicks;
|
||||||
private int gravityStompCooldownTicks;
|
private int gravityStompCooldownTicks;
|
||||||
private int timeFieldCooldownTicks;
|
|
||||||
private int momentumLockCooldownTicks;
|
private int momentumLockCooldownTicks;
|
||||||
private int crushingGravityCooldownTicks;
|
private int crushingGravityCooldownTicks;
|
||||||
private int accelerationCooldownTicks;
|
private int accelerationCooldownTicks;
|
||||||
private int blackHoleCooldownTicks;
|
private int blackHoleCooldownTicks;
|
||||||
|
private final int[] dreamFireballCooldownTicks = new int[3];
|
||||||
private int idleWanderCooldownTicks;
|
private int idleWanderCooldownTicks;
|
||||||
private int finalTimeControlTicks;
|
|
||||||
private final RoyalEffectController royalEffects = new RoyalEffectController();
|
private final RoyalEffectController royalEffects = new RoyalEffectController();
|
||||||
private final Map<UUID, Vec3> frozenVelocities = new HashMap<>();
|
private final Map<UUID, Vec3> frozenVelocities = new HashMap<>();
|
||||||
|
|
||||||
@@ -89,6 +92,52 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double groundCombatBias() {
|
||||||
|
return 0.72D;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double biteApproachSpeed() {
|
||||||
|
return 1.55D;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void registerRoyalTargetGoals() {
|
||||||
|
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, KingEntity.class, true));
|
||||||
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
||||||
|
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(
|
||||||
|
this, Mob.class, 10, true, false, this::canAttack));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int selectBeamVolleyLimit(Phase phase) {
|
||||||
|
return switch (phase) {
|
||||||
|
case ONE -> AntarchySettings.queenBeamPhaseOneCap();
|
||||||
|
case TWO -> AntarchySettings.queenBeamPhaseTwoCap();
|
||||||
|
case THREE -> this.random.nextDouble() < AntarchySettings.queenBeamPhaseThreeMaxVolleyChance()
|
||||||
|
? AntarchySettings.queenBeamPhaseThreeCap()
|
||||||
|
: Math.min(2, AntarchySettings.queenBeamPhaseThreeCap());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldDistributeHeadTargets(LivingEntity primaryTarget) {
|
||||||
|
return !(primaryTarget instanceof KingEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canAttack(LivingEntity target) {
|
||||||
|
return !target.getType().is(AntarchyTags.Entities.QUEEN_DOES_NOT_ATTACK)
|
||||||
|
&& super.canAttack(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canDamageWithRoyalAttack(LivingEntity target) {
|
||||||
|
return target != this
|
||||||
|
&& target.isAlive()
|
||||||
|
&& (!(target instanceof Player player) || !player.isCreative() && !player.isSpectator())
|
||||||
|
&& !target.getType().is(AntarchyTags.Entities.QUEEN_DOES_NOT_ATTACK)
|
||||||
|
&& !this.isAlliedTo(target);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SoundEvent royalFlyLoopSound() {
|
protected SoundEvent royalFlyLoopSound() {
|
||||||
return AntarchySoundEvents.QUEEN_FLY_LOOP.get();
|
return AntarchySoundEvents.QUEEN_FLY_LOOP.get();
|
||||||
@@ -145,9 +194,20 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
return RoyalBeamTerrainMode.DESTROY;
|
return RoyalBeamTerrainMode.DESTROY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RoyalBeamElement royalBeamElement(@Nullable RoyalHead head) {
|
||||||
|
if (head == null) {
|
||||||
|
return RoyalBeamElement.QUEEN_BLACK;
|
||||||
|
}
|
||||||
|
return switch (head.slot()) {
|
||||||
|
case LEFT -> RoyalBeamElement.QUEEN_PURPLE;
|
||||||
|
case CENTER -> RoyalBeamElement.QUEEN_BLACK;
|
||||||
|
case RIGHT -> RoyalBeamElement.QUEEN_RED;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isFieldImmune(Entity entity) {
|
public static boolean isFieldImmune(Entity entity) {
|
||||||
return entity instanceof RoyalBossEntity
|
return entity.getType().is(AntarchyTags.Entities.QUEEN_DOES_NOT_ATTACK);
|
||||||
|| entity.getType().is(AntarchyTags.Entities.TIME_DILATION_IMMUNE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -162,10 +222,49 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
this.tickManticoreSummon();
|
this.tickManticoreSummon();
|
||||||
this.tickQueenAbilities();
|
this.tickQueenAbilities();
|
||||||
this.tickFinalTimeControl();
|
this.tickDreamFireballs();
|
||||||
|
this.tickFinalAcceleration();
|
||||||
this.royalEffects.tick();
|
this.royalEffects.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tickDreamFireballs() {
|
||||||
|
if (!(this.level() instanceof ServerLevel level)) return;
|
||||||
|
LivingEntity target = this.getTarget();
|
||||||
|
if (target == null || !target.isAlive() || !this.canAttack(target)) return;
|
||||||
|
for (RoyalHead head : new RoyalHead[] {this.royalHead(RoyalHead.Slot.LEFT), this.royalHead(RoyalHead.Slot.CENTER), this.royalHead(RoyalHead.Slot.RIGHT)}) {
|
||||||
|
int index = head.slot().ordinal();
|
||||||
|
if (this.dreamFireballCooldownTicks[index] > 0) {
|
||||||
|
this.dreamFireballCooldownTicks[index]--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!head.readyToAttack() || this.distanceTo(target) < 12.0D || this.distanceTo(target) > 52.0D) continue;
|
||||||
|
int cooldown = this.cooldown(180);
|
||||||
|
RoyalHead.Slot slot = head.slot();
|
||||||
|
if (!this.beginRoyalAttack("dream_fireball_" + slot.name(), this.headLane(head), cooldown, 12, 1, 5,
|
||||||
|
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||||
|
@Override public void onStart() {
|
||||||
|
head.startShoot();
|
||||||
|
QueenEntity.this.triggerAnim(slot.controllerName(), "shoot");
|
||||||
|
QueenEntity.this.playRoyalSound(net.minecraft.sounds.SoundEvents.FIRECHARGE_USE, 0.75F);
|
||||||
|
QueenEntity.this.playRoyalSound(net.minecraft.sounds.SoundEvents.GHAST_WARN, 1.35F);
|
||||||
|
}
|
||||||
|
@Override public void onActive(int elapsedTicks) {
|
||||||
|
Vec3 origin = QueenEntity.this.headAnchor(head);
|
||||||
|
Vec3 direction = target.getEyePosition().subtract(origin).normalize();
|
||||||
|
RoyalElementalProjectileEntity projectile = RoyalElementalProjectileEntity.create(
|
||||||
|
level, QueenEntity.this, RoyalBeamElement.DREAM_FIRE, origin, direction);
|
||||||
|
level.addFreshEntity(projectile);
|
||||||
|
QueenEntity.this.playRoyalSound(AntarchySoundEvents.QUEEN_BEAM_SHOOT.get(), 0.9F);
|
||||||
|
}
|
||||||
|
@Override public void onComplete() {
|
||||||
|
head.stopShoot();
|
||||||
|
}
|
||||||
|
})) {
|
||||||
|
this.dreamFireballCooldownTicks[index] = cooldown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void tickIdleWander() {
|
private void tickIdleWander() {
|
||||||
if (this.idleWanderCooldownTicks-- > 0) {
|
if (this.idleWanderCooldownTicks-- > 0) {
|
||||||
return;
|
return;
|
||||||
@@ -239,7 +338,6 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
|
|
||||||
private void tickQueenAbilities() {
|
private void tickQueenAbilities() {
|
||||||
if (this.gravityStompCooldownTicks > 0) this.gravityStompCooldownTicks--;
|
if (this.gravityStompCooldownTicks > 0) this.gravityStompCooldownTicks--;
|
||||||
if (this.timeFieldCooldownTicks > 0) this.timeFieldCooldownTicks--;
|
|
||||||
if (this.momentumLockCooldownTicks > 0) this.momentumLockCooldownTicks--;
|
if (this.momentumLockCooldownTicks > 0) this.momentumLockCooldownTicks--;
|
||||||
if (this.crushingGravityCooldownTicks > 0) this.crushingGravityCooldownTicks--;
|
if (this.crushingGravityCooldownTicks > 0) this.crushingGravityCooldownTicks--;
|
||||||
if (this.accelerationCooldownTicks > 0) this.accelerationCooldownTicks--;
|
if (this.accelerationCooldownTicks > 0) this.accelerationCooldownTicks--;
|
||||||
@@ -257,8 +355,8 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
boolean majorBusy = this.royalEffects.active("momentum_lock") || this.royalEffects.active("crushing_gravity");
|
boolean majorBusy = this.royalEffects.active("momentum_lock") || this.royalEffects.active("crushing_gravity");
|
||||||
boolean allowOverlap = phase != Phase.ONE;
|
boolean allowOverlap = phase != Phase.ONE;
|
||||||
String[] candidates = phase == Phase.ONE
|
String[] candidates = phase == Phase.ONE
|
||||||
? new String[] {"gravity_stomp", "time_field", "black_hole"}
|
? new String[] {"gravity_stomp", "black_hole"}
|
||||||
: new String[] {"gravity_stomp", "time_field", "black_hole", "momentum_lock", "crushing_gravity", "acceleration"};
|
: new String[] {"gravity_stomp", "black_hole", "momentum_lock", "crushing_gravity", "acceleration"};
|
||||||
String selected = this.attackScheduler.chooseWeighted(candidates, id -> {
|
String selected = this.attackScheduler.chooseWeighted(candidates, id -> {
|
||||||
if (!this.queenAttackReady(id, phase, majorBusy, allowOverlap)) return 0;
|
if (!this.queenAttackReady(id, phase, majorBusy, allowOverlap)) return 0;
|
||||||
return switch (id) {
|
return switch (id) {
|
||||||
@@ -270,36 +368,39 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
if (selected == null) return;
|
if (selected == null) return;
|
||||||
int cooldown = switch (selected) {
|
int cooldown = switch (selected) {
|
||||||
case "gravity_stomp" -> GRAVITY_STOMP_COOLDOWN;
|
case "gravity_stomp" -> GRAVITY_STOMP_COOLDOWN;
|
||||||
case "time_field" -> TIME_FIELD_COOLDOWN;
|
|
||||||
case "black_hole" -> BLACK_HOLE_COOLDOWN;
|
case "black_hole" -> BLACK_HOLE_COOLDOWN;
|
||||||
case "momentum_lock" -> MOMENTUM_LOCK_COOLDOWN;
|
case "momentum_lock" -> MOMENTUM_LOCK_COOLDOWN;
|
||||||
case "crushing_gravity" -> CRUSHING_GRAVITY_COOLDOWN;
|
case "crushing_gravity" -> CRUSHING_GRAVITY_COOLDOWN;
|
||||||
default -> ACCELERATION_COOLDOWN;
|
default -> ACCELERATION_COOLDOWN;
|
||||||
};
|
};
|
||||||
if (!this.beginRoyalAttack(selected, RoyalAttackLane.HAZARD, this.cooldown(cooldown),
|
RoyalAttackLane lane = "black_hole".equals(selected) ? RoyalAttackLane.CENTER_HEAD : RoyalAttackLane.HAZARD;
|
||||||
|
if (!this.beginRoyalAttack(selected, lane, this.cooldown(cooldown),
|
||||||
10, 1, 14, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
10, 1, 14, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||||
@Override public void onStart() {
|
@Override public void onStart() {
|
||||||
if ("gravity_stomp".equals(selected)) {
|
if ("gravity_stomp".equals(selected)) {
|
||||||
QueenEntity.this.triggerAnim("body_action", "stomp");
|
QueenEntity.this.triggerAnim("body_action", "stomp");
|
||||||
} else {
|
} else if ("momentum_lock".equals(selected)) {
|
||||||
QueenEntity.this.triggerAnim("body_action", "wing_gust");
|
QueenEntity.this.triggerAnim("wing_action", "wing_gust");
|
||||||
|
} else if ("black_hole".equals(selected)) {
|
||||||
|
QueenEntity.this.royalHead(RoyalHead.Slot.CENTER).startShoot();
|
||||||
|
QueenEntity.this.triggerAnim(RoyalHead.Slot.CENTER.controllerName(), "shoot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override public void onActive(int elapsedTicks) {
|
@Override public void onActive(int elapsedTicks) {
|
||||||
QueenEntity.this.performSelectedQueenAttack(selected, phase, cooldown, level, target);
|
QueenEntity.this.performSelectedQueenAttack(selected, cooldown, level, target);
|
||||||
|
}
|
||||||
|
@Override public void onComplete() {
|
||||||
|
if ("black_hole".equals(selected)) {
|
||||||
|
QueenEntity.this.royalHead(RoyalHead.Slot.CENTER).stopShoot();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})) return;
|
})) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performSelectedQueenAttack(String selected, Phase phase, int cooldown,
|
private void performSelectedQueenAttack(String selected, int cooldown,
|
||||||
ServerLevel level, LivingEntity target) {
|
ServerLevel level, LivingEntity target) {
|
||||||
switch (selected) {
|
switch (selected) {
|
||||||
case "gravity_stomp" -> { this.gravityStompCooldownTicks = cooldown; this.performGravityStomp(level, target); }
|
case "gravity_stomp" -> { this.gravityStompCooldownTicks = cooldown; this.performGravityStomp(level, target); }
|
||||||
case "time_field" -> {
|
|
||||||
this.timeFieldCooldownTicks = cooldown;
|
|
||||||
double fieldRate = phase == Phase.THREE ? 0.1D : 0.4D;
|
|
||||||
TimeDilationApi.createField(level, target.position(), 12.0D, fieldRate, 140 + phase.ordinal() * 40);
|
|
||||||
}
|
|
||||||
case "black_hole" -> { this.blackHoleCooldownTicks = cooldown; this.castBlackHole(level, target); }
|
case "black_hole" -> { this.blackHoleCooldownTicks = cooldown; this.castBlackHole(level, target); }
|
||||||
case "momentum_lock" -> { this.momentumLockCooldownTicks = cooldown; this.startMomentumLock(level); }
|
case "momentum_lock" -> { this.momentumLockCooldownTicks = cooldown; this.startMomentumLock(level); }
|
||||||
case "crushing_gravity" -> {
|
case "crushing_gravity" -> {
|
||||||
@@ -316,8 +417,9 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
if (!allowOverlap && majorBusy) return false;
|
if (!allowOverlap && majorBusy) return false;
|
||||||
return switch (id) {
|
return switch (id) {
|
||||||
case "gravity_stomp" -> this.gravityStompCooldownTicks <= 0;
|
case "gravity_stomp" -> this.gravityStompCooldownTicks <= 0;
|
||||||
case "time_field" -> this.timeFieldCooldownTicks <= 0;
|
case "black_hole" -> this.blackHoleCooldownTicks <= 0
|
||||||
case "black_hole" -> this.blackHoleCooldownTicks <= 0;
|
&& this.royalHead(RoyalHead.Slot.CENTER).readyToAttack()
|
||||||
|
&& !this.attackScheduler.laneBusy(RoyalAttackLane.CENTER_HEAD);
|
||||||
case "momentum_lock" -> !this.royalEffects.active("momentum_lock") && this.momentumLockCooldownTicks <= 0;
|
case "momentum_lock" -> !this.royalEffects.active("momentum_lock") && this.momentumLockCooldownTicks <= 0;
|
||||||
case "crushing_gravity" -> phase != Phase.ONE && !this.royalEffects.active("crushing_gravity") && this.crushingGravityCooldownTicks <= 0;
|
case "crushing_gravity" -> phase != Phase.ONE && !this.royalEffects.active("crushing_gravity") && this.crushingGravityCooldownTicks <= 0;
|
||||||
case "acceleration" -> phase == Phase.THREE && !this.royalEffects.active("acceleration") && this.accelerationCooldownTicks <= 0;
|
case "acceleration" -> phase == Phase.THREE && !this.royalEffects.active("acceleration") && this.accelerationCooldownTicks <= 0;
|
||||||
@@ -325,21 +427,13 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tickFinalTimeControl() {
|
private void tickFinalAcceleration() {
|
||||||
if (this.phase() != Phase.THREE || !(this.level() instanceof ServerLevel level)) {
|
if (this.phase() != Phase.THREE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.royalEffects.active("acceleration") && this.accelerationCooldownTicks <= 0) {
|
if (!this.royalEffects.active("acceleration") && this.accelerationCooldownTicks <= 0) {
|
||||||
this.startRoyalAcceleration();
|
this.startRoyalAcceleration();
|
||||||
}
|
}
|
||||||
if (this.finalTimeControlTicks-- <= 0) {
|
|
||||||
this.finalTimeControlTicks = AntarchySettings.queenFinalTimeFieldCooldownTicks();
|
|
||||||
LivingEntity target = this.getTarget();
|
|
||||||
if (target != null && target.isAlive()) {
|
|
||||||
TimeDilationApi.createField(level, target.position(), AntarchySettings.queenFinalTimeFieldRadius(),
|
|
||||||
AntarchySettings.queenFinalTimeFieldRate(), AntarchySettings.queenFinalTimeFieldDurationTicks());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performGravityStomp(ServerLevel level, LivingEntity target) {
|
private void performGravityStomp(ServerLevel level, LivingEntity target) {
|
||||||
@@ -347,26 +441,32 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 0.7F);
|
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 0.7F);
|
||||||
DamageSource source = this.damageSources().mobAttack(this);
|
DamageSource source = this.damageSources().mobAttack(this);
|
||||||
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class,
|
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class,
|
||||||
this.getBoundingBox().inflate(18.0D), entity -> entity instanceof Player && entity.isAlive())) {
|
this.getBoundingBox().inflate(18.0D), this::canDamageWithRoyalAttack)) {
|
||||||
double distance = Math.max(1.0D, living.distanceTo(this));
|
double distance = Math.max(1.0D, living.distanceTo(this));
|
||||||
living.hurt(source, (float) (12.0D * Math.max(0.25D, 1.0D - distance / 24.0D)));
|
living.hurt(source, (float) (12.0D * Math.max(0.25D, 1.0D - distance / 24.0D)));
|
||||||
Vec3 push = living.position().subtract(this.position()).normalize().scale(1.3D);
|
Vec3 push = living.position().subtract(this.position()).normalize().scale(1.3D);
|
||||||
living.setDeltaMovement(living.getDeltaMovement().add(push.x, 0.65D, push.z));
|
living.setDeltaMovement(living.getDeltaMovement().add(push.x, 0.65D, push.z));
|
||||||
living.hasImpulse = true;
|
living.hasImpulse = true;
|
||||||
}
|
}
|
||||||
level.sendParticles(ParticleTypes.SONIC_BOOM, this.getX(), this.getY() + 1.0D, this.getZ(), 4, 2.0D, 0.5D, 2.0D, 0.0D);
|
level.sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY() + 1.0D, this.getZ(),
|
||||||
|
18, 5.0D, 0.6D, 5.0D, 0.08D);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void castBlackHole(ServerLevel level, LivingEntity target) {
|
private void castBlackHole(ServerLevel level, LivingEntity target) {
|
||||||
|
double vertical = 2.0D + this.random.nextDouble() * 2.0D;
|
||||||
|
if (AntarchyGravityApi.isGravityInverted(target)) {
|
||||||
|
vertical = -vertical;
|
||||||
|
}
|
||||||
Vec3 anchor = target.position().add(
|
Vec3 anchor = target.position().add(
|
||||||
(this.random.nextDouble() - 0.5D) * 4.0D,
|
(this.random.nextDouble() - 0.5D) * 4.0D,
|
||||||
2.0D + this.random.nextDouble() * 2.0D,
|
vertical,
|
||||||
(this.random.nextDouble() - 0.5D) * 4.0D);
|
(this.random.nextDouble() - 0.5D) * 4.0D);
|
||||||
RoyalBlackHoleEntity hole = RoyalBlackHoleEntity.create(level, anchor, this.getUUID());
|
Vec3 mouth = this.beamAnchor(this.royalHead(RoyalHead.Slot.CENTER));
|
||||||
|
RoyalBlackHoleEntity hole = RoyalBlackHoleEntity.createProjectile(level, mouth, anchor, this.getUUID());
|
||||||
level.addFreshEntity(hole);
|
level.addFreshEntity(hole);
|
||||||
this.triggerAnim("body_action", "wing_gust");
|
|
||||||
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 1.0F);
|
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 1.0F);
|
||||||
level.sendParticles(ParticleTypes.REVERSE_PORTAL, anchor.x, anchor.y, anchor.z, 60, 1.0D, 1.0D, 1.0D, 0.4D);
|
level.sendParticles(ParticleTypes.REVERSE_PORTAL, mouth.x, mouth.y, mouth.z,
|
||||||
|
30, 0.6D, 0.6D, 0.6D, 0.25D);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startMomentumLock(ServerLevel level) {
|
private void startMomentumLock(ServerLevel level) {
|
||||||
@@ -390,7 +490,6 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
this.frozenVelocities.clear();
|
this.frozenVelocities.clear();
|
||||||
});
|
});
|
||||||
this.triggerAnim("body_action", "wing_gust");
|
|
||||||
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 0.5F);
|
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 0.5F);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,9 +497,11 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
if (!(this.level() instanceof ServerLevel level)) {
|
if (!(this.level() instanceof ServerLevel level)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (Map.Entry<UUID, Vec3> entry : this.frozenVelocities.entrySet()) {
|
for (Iterator<Map.Entry<UUID, Vec3>> iterator = this.frozenVelocities.entrySet().iterator(); iterator.hasNext();) {
|
||||||
|
Map.Entry<UUID, Vec3> entry = iterator.next();
|
||||||
Entity entity = level.getEntity(entry.getKey());
|
Entity entity = level.getEntity(entry.getKey());
|
||||||
if (entity == null || !entity.isAlive()) {
|
if (entity == null || !entity.isAlive()) {
|
||||||
|
iterator.remove();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
entity.setDeltaMovement(Vec3.ZERO);
|
entity.setDeltaMovement(Vec3.ZERO);
|
||||||
@@ -522,7 +623,6 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
super.addAdditionalSaveData(tag);
|
super.addAdditionalSaveData(tag);
|
||||||
tag.putInt(SUMMON_COOLDOWN_KEY, this.manticoreSummonCooldownTicks);
|
tag.putInt(SUMMON_COOLDOWN_KEY, this.manticoreSummonCooldownTicks);
|
||||||
tag.putInt("GravityStompCooldownTicks", this.gravityStompCooldownTicks);
|
tag.putInt("GravityStompCooldownTicks", this.gravityStompCooldownTicks);
|
||||||
tag.putInt("TimeFieldCooldownTicks", this.timeFieldCooldownTicks);
|
|
||||||
tag.putInt("AccelerationCooldownTicks", this.accelerationCooldownTicks);
|
tag.putInt("AccelerationCooldownTicks", this.accelerationCooldownTicks);
|
||||||
tag.putInt("BlackHoleCooldownTicks", this.blackHoleCooldownTicks);
|
tag.putInt("BlackHoleCooldownTicks", this.blackHoleCooldownTicks);
|
||||||
}
|
}
|
||||||
@@ -532,7 +632,6 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
super.readAdditionalSaveData(tag);
|
super.readAdditionalSaveData(tag);
|
||||||
this.manticoreSummonCooldownTicks = Math.max(0, tag.getInt(SUMMON_COOLDOWN_KEY));
|
this.manticoreSummonCooldownTicks = Math.max(0, tag.getInt(SUMMON_COOLDOWN_KEY));
|
||||||
this.gravityStompCooldownTicks = Math.max(0, tag.getInt("GravityStompCooldownTicks"));
|
this.gravityStompCooldownTicks = Math.max(0, tag.getInt("GravityStompCooldownTicks"));
|
||||||
this.timeFieldCooldownTicks = Math.max(0, tag.getInt("TimeFieldCooldownTicks"));
|
|
||||||
this.momentumLockCooldownTicks = Math.max(0, tag.getInt("MomentumLockCooldownTicks"));
|
this.momentumLockCooldownTicks = Math.max(0, tag.getInt("MomentumLockCooldownTicks"));
|
||||||
this.crushingGravityCooldownTicks = Math.max(0, tag.getInt("CrushingGravityCooldownTicks"));
|
this.crushingGravityCooldownTicks = Math.max(0, tag.getInt("CrushingGravityCooldownTicks"));
|
||||||
this.accelerationCooldownTicks = Math.max(0, tag.getInt("AccelerationCooldownTicks"));
|
this.accelerationCooldownTicks = Math.max(0, tag.getInt("AccelerationCooldownTicks"));
|
||||||
|
|||||||
+255
-35
@@ -2,20 +2,27 @@ package com.craisinlord.antarchy.content.entity.royal;
|
|||||||
|
|
||||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationFieldEntity;
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
import net.minecraft.network.syncher.SynchedEntityData;
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.damagesource.DamageSource;
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.ExperienceOrb;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||||
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
import net.minecraft.world.level.GameRules;
|
import net.minecraft.world.level.GameRules;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -33,21 +40,50 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
|||||||
SynchedEntityData.defineId(RoyalBlackHoleEntity.class, EntityDataSerializers.FLOAT);
|
SynchedEntityData.defineId(RoyalBlackHoleEntity.class, EntityDataSerializers.FLOAT);
|
||||||
private static final EntityDataAccessor<Boolean> COLLAPSING =
|
private static final EntityDataAccessor<Boolean> COLLAPSING =
|
||||||
SynchedEntityData.defineId(RoyalBlackHoleEntity.class, EntityDataSerializers.BOOLEAN);
|
SynchedEntityData.defineId(RoyalBlackHoleEntity.class, EntityDataSerializers.BOOLEAN);
|
||||||
|
private static final EntityDataAccessor<Float> VISUAL_GROWTH =
|
||||||
|
SynchedEntityData.defineId(RoyalBlackHoleEntity.class, EntityDataSerializers.FLOAT);
|
||||||
|
private static final EntityDataAccessor<Float> EFFECT_RADIUS =
|
||||||
|
SynchedEntityData.defineId(RoyalBlackHoleEntity.class, EntityDataSerializers.FLOAT);
|
||||||
private static final String OWNER_KEY = "OwnerUuid";
|
private static final String OWNER_KEY = "OwnerUuid";
|
||||||
private static final String AGE_KEY = "Age";
|
private static final String AGE_KEY = "Age";
|
||||||
private static final String ACTIVE_KEY = "ActiveTicks";
|
private static final String ACTIVE_KEY = "ActiveTicks";
|
||||||
private static final String ASSAILANT_KEY = "AssailantVariant";
|
private static final String TRAVEL_TICKS_KEY = "TravelTicks";
|
||||||
|
private static final String DESTINATION_X_KEY = "DestinationX";
|
||||||
|
private static final String DESTINATION_Y_KEY = "DestinationY";
|
||||||
|
private static final String DESTINATION_Z_KEY = "DestinationZ";
|
||||||
|
private static final String ANIMATION_AGE_KEY = "AnimationAge";
|
||||||
|
private static final String DILATION_FIELD_KEY = "DilationFieldUuid";
|
||||||
|
private static final String SUCKED_BLOCKS_KEY = "SuckedBlocks";
|
||||||
|
|
||||||
private static final double DEFAULT_RADIUS = 14.0D;
|
private static final double DEFAULT_RADIUS = 14.0D;
|
||||||
private static final int DEFAULT_ACTIVE_TICKS = 120;
|
private static final int QUEEN_ANIMATION_TICKS = 403;
|
||||||
private static final int COLLAPSE_TICKS = 12;
|
private static final int QUEEN_COLLAPSE_TICKS = 25;
|
||||||
|
private static final int QUEEN_ACTIVE_TICKS = QUEEN_ANIMATION_TICKS - QUEEN_COLLAPSE_TICKS;
|
||||||
|
private static final int QUEEN_PROJECTILE_TRAVEL_TICKS = 20;
|
||||||
|
private static final int BLOCK_SUCTION_INTERVAL = 5;
|
||||||
|
private static final int BLOCKS_PER_SUCTION = 3;
|
||||||
|
private static final int BLOCK_SUCTION_ATTEMPTS = 36;
|
||||||
|
private static final double MODEL_RENDER_SCALE = 1.5D;
|
||||||
|
private static final double EFFECT_GROWTH_START = 0.45D;
|
||||||
|
private static final double EFFECT_GROWTH_END = 1.6D;
|
||||||
|
private static final double EFFECT_GROWTH_FRACTION = 0.6D;
|
||||||
|
private static final double MODEL_BASELINE_Y = 24.0D;
|
||||||
|
private static final double CORE_CUBE_CENTER_Y = 146.0D;
|
||||||
|
private static final double CORE_START_OFFSET_Y = -100.0D;
|
||||||
|
private static final double CORE_END_OFFSET_Y = 505.0D;
|
||||||
|
private static final double CORE_RISE_END_SECONDS = 19.125D;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private UUID ownerId;
|
private UUID ownerId;
|
||||||
private int age;
|
private int age;
|
||||||
private int activeTicks = DEFAULT_ACTIVE_TICKS;
|
private int activeTicks = QUEEN_ACTIVE_TICKS;
|
||||||
private boolean assailantVariant;
|
private int animationAge;
|
||||||
|
private int suckedBlocks;
|
||||||
|
private int travelTicksRemaining;
|
||||||
|
@Nullable
|
||||||
|
private UUID dilationFieldId;
|
||||||
|
@Nullable
|
||||||
|
private Vec3 destination;
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
|
||||||
public RoyalBlackHoleEntity(EntityType<? extends RoyalBlackHoleEntity> entityType, Level level) {
|
public RoyalBlackHoleEntity(EntityType<? extends RoyalBlackHoleEntity> entityType, Level level) {
|
||||||
@@ -58,27 +94,37 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
|||||||
|
|
||||||
public static RoyalBlackHoleEntity create(ServerLevel level, Vec3 center, double radius, int activeTicks, @Nullable UUID ownerId) {
|
public static RoyalBlackHoleEntity create(ServerLevel level, Vec3 center, double radius, int activeTicks, @Nullable UUID ownerId) {
|
||||||
RoyalBlackHoleEntity hole = new RoyalBlackHoleEntity(AntarchyObjects.ROYAL_BLACK_HOLE.get(), level);
|
RoyalBlackHoleEntity hole = new RoyalBlackHoleEntity(AntarchyObjects.ROYAL_BLACK_HOLE.get(), level);
|
||||||
hole.setPos(center.x, center.y, center.z);
|
hole.configure(center, radius, activeTicks, ownerId);
|
||||||
hole.setRadius(radius > 0.0D ? radius : AntarchySettings.queenBlackHoleRadius());
|
|
||||||
hole.activeTicks = activeTicks > 0 ? Math.max(20, activeTicks) : AntarchySettings.queenBlackHoleActiveTicks();
|
|
||||||
hole.ownerId = ownerId;
|
|
||||||
return hole;
|
return hole;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RoyalBlackHoleEntity create(ServerLevel level, Vec3 center, @Nullable UUID ownerId) {
|
public static RoyalBlackHoleEntity create(ServerLevel level, Vec3 center, @Nullable UUID ownerId) {
|
||||||
return create(level, center, AntarchySettings.queenBlackHoleRadius(), AntarchySettings.queenBlackHoleActiveTicks(), ownerId);
|
return create(level, center, AntarchySettings.queenBlackHoleRadius(), QUEEN_ACTIVE_TICKS, ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RoyalBlackHoleEntity createAssailant(ServerLevel level, Vec3 center, @Nullable UUID ownerId) {
|
public static RoyalBlackHoleEntity createProjectile(ServerLevel level, Vec3 origin, Vec3 destination,
|
||||||
RoyalBlackHoleEntity hole = create(level, center, AntarchySettings.queenBlackHoleRadius(), AntarchySettings.queenBlackHoleActiveTicks(), ownerId);
|
@Nullable UUID ownerId) {
|
||||||
hole.assailantVariant = true;
|
RoyalBlackHoleEntity hole = create(level, origin, ownerId);
|
||||||
|
hole.activeTicks = QUEEN_ACTIVE_TICKS - QUEEN_PROJECTILE_TRAVEL_TICKS;
|
||||||
|
hole.destination = destination;
|
||||||
|
hole.travelTicksRemaining = QUEEN_PROJECTILE_TRAVEL_TICKS;
|
||||||
|
hole.entityData.set(VISUAL_GROWTH, 0.15F);
|
||||||
return hole;
|
return hole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final void configure(Vec3 center, double radius, int activeTicks, @Nullable UUID ownerId) {
|
||||||
|
this.setPos(center.x, center.y, center.z);
|
||||||
|
this.setRadius(radius > 0.0D ? radius : AntarchySettings.queenBlackHoleRadius());
|
||||||
|
this.activeTicks = activeTicks > 0 ? Math.max(20, activeTicks) : AntarchySettings.queenBlackHoleActiveTicks();
|
||||||
|
this.ownerId = ownerId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||||
builder.define(RADIUS, (float) DEFAULT_RADIUS);
|
builder.define(RADIUS, (float) DEFAULT_RADIUS);
|
||||||
builder.define(COLLAPSING, false);
|
builder.define(COLLAPSING, false);
|
||||||
|
builder.define(VISUAL_GROWTH, 1.0F);
|
||||||
|
builder.define(EFFECT_RADIUS, (float) (DEFAULT_RADIUS * EFFECT_GROWTH_START));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRadius(double radius) {
|
public void setRadius(double radius) {
|
||||||
@@ -89,28 +135,48 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
|||||||
return this.entityData.get(RADIUS);
|
return this.entityData.get(RADIUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double effectRadius() {
|
||||||
|
return Math.max(1.0D, this.entityData.get(EFFECT_RADIUS));
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeEffectRadius() {
|
||||||
|
double progress = this.activeTicks <= 0
|
||||||
|
? 1.0D
|
||||||
|
: Mth.clamp(this.age / (this.activeTicks * EFFECT_GROWTH_FRACTION), 0.0D, 1.0D);
|
||||||
|
return this.radius() * Mth.lerp(progress, EFFECT_GROWTH_START, EFFECT_GROWTH_END);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCollapsing() {
|
public boolean isCollapsing() {
|
||||||
return this.entityData.get(COLLAPSING);
|
return this.entityData.get(COLLAPSING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float visualGrowth() {
|
||||||
|
return this.entityData.get(VISUAL_GROWTH);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
this.animationAge++;
|
||||||
if (this.level().isClientSide) {
|
if (this.level().isClientSide) {
|
||||||
this.spawnClientParticles();
|
this.spawnClientParticles();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.travelTicksRemaining > 0 && this.destination != null) {
|
||||||
|
this.tickProjectileTravel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.age++;
|
this.age++;
|
||||||
if (!this.isCollapsing()) {
|
if (!this.isCollapsing()) {
|
||||||
if (this.assailantVariant) {
|
if (this.risesWhileActive()) {
|
||||||
this.setPos(this.getX(), this.getY() + 0.035D, this.getZ());
|
this.setPos(this.getX(), this.getY() + 0.035D, this.getZ());
|
||||||
}
|
}
|
||||||
|
this.entityData.set(EFFECT_RADIUS, (float) this.computeEffectRadius());
|
||||||
|
this.ensureAttachedDilationField();
|
||||||
this.applyPull();
|
this.applyPull();
|
||||||
if (this.age % 10 == 0 && this.level() instanceof ServerLevel level) {
|
if (this.pullsTerrainBlocks() && this.age % BLOCK_SUCTION_INTERVAL == 0
|
||||||
TimeDilationApi.createField(level, this.position(), Math.max(2.0D, this.radius() * 0.55D), 0.18D, 14, this.ownerId, !this.assailantVariant);
|
&& this.level() instanceof ServerLevel level) {
|
||||||
if (this.age % 20 == 0 && level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
this.pullTerrainBlocks(level);
|
||||||
RoyalBlockDestruction.destroySphere(level, this, this.position(), Math.min(2.0D, this.radius() * 0.2D), 8, 30.0D, 0.0F);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (this.age >= this.activeTicks) {
|
if (this.age >= this.activeTicks) {
|
||||||
this.entityData.set(COLLAPSING, true);
|
this.entityData.set(COLLAPSING, true);
|
||||||
@@ -118,22 +184,105 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.age >= COLLAPSE_TICKS) {
|
if (this.age >= this.collapseDurationTicks()) {
|
||||||
this.collapse();
|
this.collapse();
|
||||||
|
this.discardAttachedDilationField();
|
||||||
this.discard();
|
this.discard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tickProjectileTravel() {
|
||||||
|
Vec3 remaining = this.destination.subtract(this.position());
|
||||||
|
double distance = remaining.length();
|
||||||
|
if (distance <= 0.5D || this.travelTicksRemaining <= 1) {
|
||||||
|
this.setPos(this.destination.x, this.destination.y, this.destination.z);
|
||||||
|
this.travelTicksRemaining = 0;
|
||||||
|
this.destination = null;
|
||||||
|
this.entityData.set(VISUAL_GROWTH, 1.0F);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setPos(this.position().add(remaining.scale(1.0D / this.travelTicksRemaining)));
|
||||||
|
this.travelTicksRemaining--;
|
||||||
|
float progress = 1.0F - this.travelTicksRemaining / (float) QUEEN_PROJECTILE_TRAVEL_TICKS;
|
||||||
|
this.entityData.set(VISUAL_GROWTH, Mth.lerp(progress, 0.15F, 1.0F));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean risesWhileActive() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected double timeDilationRadius() {
|
||||||
|
return Math.max(2.0D, this.effectRadius() * 0.55D) * QueenEntity.TIME_FIELD_RADIUS_SCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean hasVisibleTimeDilationField() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int collapseDurationTicks() {
|
||||||
|
return QUEEN_COLLAPSE_TICKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean pullsTerrainBlocks() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the center of the animated black-hole cube in world coordinates. */
|
||||||
|
public Vec3 effectCenter() {
|
||||||
|
double animationSeconds = Math.min(CORE_RISE_END_SECONDS, this.animationAge / 20.0D);
|
||||||
|
double riseProgress = animationSeconds / CORE_RISE_END_SECONDS;
|
||||||
|
double animatedOffset = Mth.lerp(riseProgress, CORE_START_OFFSET_Y, CORE_END_OFFSET_Y);
|
||||||
|
double modelY = CORE_CUBE_CENTER_Y + animatedOffset;
|
||||||
|
double worldOffsetY = (modelY - MODEL_BASELINE_Y) / 16.0D * MODEL_RENDER_SCALE;
|
||||||
|
return this.position().add(0.0D, worldOffsetY, 0.0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureAttachedDilationField() {
|
||||||
|
if (!(this.level() instanceof ServerLevel level)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TimeDilationFieldEntity field = this.dilationFieldId != null
|
||||||
|
&& level.getEntity(this.dilationFieldId) instanceof TimeDilationFieldEntity existing
|
||||||
|
? existing
|
||||||
|
: null;
|
||||||
|
if (field == null || !field.isAlive()) {
|
||||||
|
int remainingTicks = Math.max(1, this.activeTicks - this.age + this.collapseDurationTicks());
|
||||||
|
field = TimeDilationApi.createField(level, this.effectCenter(), this.timeDilationRadius(), 0.18D,
|
||||||
|
remainingTicks, this.ownerId, this.hasVisibleTimeDilationField());
|
||||||
|
field.attachTo(this);
|
||||||
|
this.dilationFieldId = field.getUUID();
|
||||||
|
} else {
|
||||||
|
Vec3 center = this.effectCenter();
|
||||||
|
field.setPos(center.x, center.y, center.z);
|
||||||
|
field.setFieldRadius(this.timeDilationRadius());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void discardAttachedDilationField() {
|
||||||
|
if (this.dilationFieldId != null && this.level() instanceof ServerLevel level
|
||||||
|
&& level.getEntity(this.dilationFieldId) instanceof TimeDilationFieldEntity field) {
|
||||||
|
field.discard();
|
||||||
|
}
|
||||||
|
this.dilationFieldId = null;
|
||||||
|
}
|
||||||
|
|
||||||
private void applyPull() {
|
private void applyPull() {
|
||||||
Vec3 center = this.position();
|
Vec3 center = this.effectCenter();
|
||||||
double radius = this.radius();
|
double radius = this.effectRadius();
|
||||||
for (Entity entity : this.level().getEntitiesOfClass(Entity.class, new AABB(center, center).inflate(radius))) {
|
for (Entity entity : this.level().getEntitiesOfClass(Entity.class, new AABB(center, center).inflate(radius))) {
|
||||||
if (entity == this || this.isImmune(entity)) {
|
if (entity == this || entity instanceof TimeDilationFieldEntity || this.isImmune(entity)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Vec3 toCenter = center.subtract(entity.position());
|
Vec3 toCenter = center.subtract(entity.position());
|
||||||
double distance = toCenter.length();
|
double distance = toCenter.length();
|
||||||
if (distance < 0.5D || distance > radius) {
|
if (distance < 0.75D) {
|
||||||
|
if (entity instanceof ItemEntity || entity instanceof ExperienceOrb || entity instanceof FallingBlockEntity) {
|
||||||
|
entity.discard();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (distance > radius) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
double strength = AntarchySettings.queenBlackHolePullStrength() * (1.0D - distance / radius);
|
double strength = AntarchySettings.queenBlackHolePullStrength() * (1.0D - distance / radius);
|
||||||
@@ -144,12 +293,59 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pullTerrainBlocks(ServerLevel level) {
|
||||||
|
int cap = AntarchySettings.queenBlackHoleBlockSuctionCap();
|
||||||
|
if (cap <= 0 || this.suckedBlocks >= cap
|
||||||
|
|| !level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 center = this.effectCenter();
|
||||||
|
Vec3 terrainOrigin = this.position();
|
||||||
|
double radius = this.effectRadius();
|
||||||
|
int pulledThisTick = 0;
|
||||||
|
for (int attempt = 0; attempt < BLOCK_SUCTION_ATTEMPTS && pulledThisTick < BLOCKS_PER_SUCTION
|
||||||
|
&& this.suckedBlocks < cap; attempt++) {
|
||||||
|
BlockPos pos = BlockPos.containing(
|
||||||
|
terrainOrigin.x + (this.random.nextDouble() * 2.0D - 1.0D) * radius,
|
||||||
|
terrainOrigin.y + (this.random.nextDouble() * 2.0D - 1.0D) * radius,
|
||||||
|
terrainOrigin.z + (this.random.nextDouble() * 2.0D - 1.0D) * radius);
|
||||||
|
if (pos.distToCenterSqr(terrainOrigin.x, terrainOrigin.y, terrainOrigin.z) > radius * radius
|
||||||
|
|| pos.getY() < level.getMinBuildHeight()
|
||||||
|
|| pos.getY() >= level.getMaxBuildHeight()
|
||||||
|
|| !level.getWorldBorder().isWithinBounds(pos)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockState state = level.getBlockState(pos);
|
||||||
|
if (state.isAir() || level.getBlockEntity(pos) != null
|
||||||
|
|| state.getDestroySpeed(level, pos) < 0.0F
|
||||||
|
|| state.getBlock().getExplosionResistance() > 30.0F
|
||||||
|
|| state.getCollisionShape(level, pos).isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FallingBlockEntity falling = FallingBlockEntity.fall(level, pos, state);
|
||||||
|
if (falling == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Vec3 towardCenter = center.subtract(falling.position());
|
||||||
|
if (towardCenter.lengthSqr() > 0.001D) {
|
||||||
|
falling.setDeltaMovement(towardCenter.normalize().scale(0.28D));
|
||||||
|
}
|
||||||
|
falling.hasImpulse = true;
|
||||||
|
falling.hurtMarked = true;
|
||||||
|
pulledThisTick++;
|
||||||
|
this.suckedBlocks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void collapse() {
|
private void collapse() {
|
||||||
if (!(this.level() instanceof ServerLevel level)) {
|
if (!(this.level() instanceof ServerLevel level)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Vec3 center = this.position();
|
Vec3 center = this.effectCenter();
|
||||||
double radius = this.radius();
|
double radius = this.effectRadius();
|
||||||
DamageSource source = this.ownerEntity() != null
|
DamageSource source = this.ownerEntity() != null
|
||||||
? this.damageSources().mobAttack(this.ownerEntity())
|
? this.damageSources().mobAttack(this.ownerEntity())
|
||||||
: this.damageSources().magic();
|
: this.damageSources().magic();
|
||||||
@@ -172,10 +368,14 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isImmune(Entity entity) {
|
private boolean isImmune(Entity entity) {
|
||||||
if (entity instanceof RoyalBossEntity) {
|
if (this.ownerId != null && this.ownerId.equals(entity.getUUID())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.ownerId != null && this.ownerId.equals(entity.getUUID())) {
|
LivingEntity owner = this.ownerEntity();
|
||||||
|
if (owner instanceof QueenEntity) {
|
||||||
|
return entity.getType().is(com.craisinlord.antarchy.content.AntarchyTags.Entities.QUEEN_DOES_NOT_ATTACK);
|
||||||
|
}
|
||||||
|
if (entity instanceof RoyalBossEntity) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return entity.getType().is(com.craisinlord.antarchy.content.AntarchyTags.Entities.TIME_DILATION_IMMUNE);
|
return entity.getType().is(com.craisinlord.antarchy.content.AntarchyTags.Entities.TIME_DILATION_IMMUNE);
|
||||||
@@ -190,10 +390,10 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void spawnClientParticles() {
|
private void spawnClientParticles() {
|
||||||
Vec3 center = this.position();
|
Vec3 center = this.effectCenter();
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
double angle = this.random.nextDouble() * Math.PI * 2.0D;
|
double angle = this.random.nextDouble() * Math.PI * 2.0D;
|
||||||
double r = this.radius() * (0.3D + this.random.nextDouble() * 0.7D);
|
double r = this.effectRadius() * this.visualGrowth() * (0.3D + this.random.nextDouble() * 0.7D);
|
||||||
double px = center.x + Math.cos(angle) * r;
|
double px = center.x + Math.cos(angle) * r;
|
||||||
double pz = center.z + Math.sin(angle) * r;
|
double pz = center.z + Math.sin(angle) * r;
|
||||||
double py = center.y + (this.random.nextDouble() - 0.5D) * 3.0D;
|
double py = center.y + (this.random.nextDouble() - 0.5D) * 3.0D;
|
||||||
@@ -216,9 +416,19 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
|||||||
protected void readAdditionalSaveData(CompoundTag tag) {
|
protected void readAdditionalSaveData(CompoundTag tag) {
|
||||||
this.setRadius(tag.getDouble("Radius"));
|
this.setRadius(tag.getDouble("Radius"));
|
||||||
this.age = tag.getInt(AGE_KEY);
|
this.age = tag.getInt(AGE_KEY);
|
||||||
this.activeTicks = tag.contains(ACTIVE_KEY) ? tag.getInt(ACTIVE_KEY) : DEFAULT_ACTIVE_TICKS;
|
this.activeTicks = tag.contains(ACTIVE_KEY) ? tag.getInt(ACTIVE_KEY) : QUEEN_ACTIVE_TICKS;
|
||||||
|
this.animationAge = tag.contains(ANIMATION_AGE_KEY) ? tag.getInt(ANIMATION_AGE_KEY) : this.age;
|
||||||
|
this.suckedBlocks = tag.getInt(SUCKED_BLOCKS_KEY);
|
||||||
|
this.entityData.set(EFFECT_RADIUS, (float) this.computeEffectRadius());
|
||||||
this.ownerId = tag.hasUUID(OWNER_KEY) ? tag.getUUID(OWNER_KEY) : null;
|
this.ownerId = tag.hasUUID(OWNER_KEY) ? tag.getUUID(OWNER_KEY) : null;
|
||||||
this.assailantVariant = tag.getBoolean(ASSAILANT_KEY);
|
this.dilationFieldId = tag.hasUUID(DILATION_FIELD_KEY) ? tag.getUUID(DILATION_FIELD_KEY) : null;
|
||||||
|
this.travelTicksRemaining = Math.max(0, tag.getInt(TRAVEL_TICKS_KEY));
|
||||||
|
if (this.travelTicksRemaining > 0 && tag.contains(DESTINATION_X_KEY)) {
|
||||||
|
this.destination = new Vec3(tag.getDouble(DESTINATION_X_KEY), tag.getDouble(DESTINATION_Y_KEY),
|
||||||
|
tag.getDouble(DESTINATION_Z_KEY));
|
||||||
|
float progress = 1.0F - this.travelTicksRemaining / (float) QUEEN_PROJECTILE_TRAVEL_TICKS;
|
||||||
|
this.entityData.set(VISUAL_GROWTH, Mth.lerp(progress, 0.15F, 1.0F));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -226,10 +436,20 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
|||||||
tag.putDouble("Radius", this.radius());
|
tag.putDouble("Radius", this.radius());
|
||||||
tag.putInt(AGE_KEY, this.age);
|
tag.putInt(AGE_KEY, this.age);
|
||||||
tag.putInt(ACTIVE_KEY, this.activeTicks);
|
tag.putInt(ACTIVE_KEY, this.activeTicks);
|
||||||
|
tag.putInt(ANIMATION_AGE_KEY, this.animationAge);
|
||||||
|
tag.putInt(SUCKED_BLOCKS_KEY, this.suckedBlocks);
|
||||||
if (this.ownerId != null) {
|
if (this.ownerId != null) {
|
||||||
tag.putUUID(OWNER_KEY, this.ownerId);
|
tag.putUUID(OWNER_KEY, this.ownerId);
|
||||||
}
|
}
|
||||||
tag.putBoolean(ASSAILANT_KEY, this.assailantVariant);
|
if (this.dilationFieldId != null) {
|
||||||
|
tag.putUUID(DILATION_FIELD_KEY, this.dilationFieldId);
|
||||||
|
}
|
||||||
|
tag.putInt(TRAVEL_TICKS_KEY, this.travelTicksRemaining);
|
||||||
|
if (this.destination != null) {
|
||||||
|
tag.putDouble(DESTINATION_X_KEY, this.destination.x);
|
||||||
|
tag.putDouble(DESTINATION_Y_KEY, this.destination.y);
|
||||||
|
tag.putDouble(DESTINATION_Z_KEY, this.destination.z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -238,7 +458,7 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private PlayState blackHoleController(AnimationState<RoyalBlackHoleEntity> state) {
|
private PlayState blackHoleController(AnimationState<RoyalBlackHoleEntity> state) {
|
||||||
return state.setAndContinue(RawAnimation.begin().thenLoop("animation"));
|
return state.setAndContinue(RawAnimation.begin().thenPlay("animation"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -78,7 +78,7 @@ public class RoyalBoltEntity extends AbstractHurtingProjectile {
|
|||||||
case FIRE -> ParticleTypes.FLAME;
|
case FIRE -> ParticleTypes.FLAME;
|
||||||
case LIGHTNING -> ParticleTypes.ELECTRIC_SPARK;
|
case LIGHTNING -> ParticleTypes.ELECTRIC_SPARK;
|
||||||
case ICE -> ParticleTypes.SNOWFLAKE;
|
case ICE -> ParticleTypes.SNOWFLAKE;
|
||||||
case GENERIC -> ParticleTypes.WITCH;
|
default -> ParticleTypes.WITCH;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+335
-140
@@ -12,8 +12,10 @@ import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackLane;
|
|||||||
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler;
|
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
import net.minecraft.network.syncher.SynchedEntityData;
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
@@ -34,12 +36,14 @@ import net.minecraft.world.item.ItemStack;
|
|||||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
import net.minecraft.world.entity.ai.control.FlyingMoveControl;
|
import net.minecraft.world.entity.ai.control.FlyingMoveControl;
|
||||||
|
import net.minecraft.world.entity.ai.control.MoveControl;
|
||||||
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
||||||
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
||||||
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
||||||
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
|
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
|
||||||
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
|
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
|
||||||
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
|
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
|
||||||
|
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
|
||||||
import net.minecraft.world.entity.ai.navigation.PathNavigation;
|
import net.minecraft.world.entity.ai.navigation.PathNavigation;
|
||||||
import net.minecraft.world.entity.monster.Monster;
|
import net.minecraft.world.entity.monster.Monster;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
@@ -88,6 +92,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
|
|
||||||
private static final int BITE_DURATION_TICKS = 16;
|
private static final int BITE_DURATION_TICKS = 16;
|
||||||
private static final int BITE_HIT_TICK = 6;
|
private static final int BITE_HIT_TICK = 6;
|
||||||
|
private static final int HEAD_ATTACK_ANIMATION_TICKS = 25;
|
||||||
private static final int DEATH_TICKS = 60;
|
private static final int DEATH_TICKS = 60;
|
||||||
private static final double CRUSH_RADIUS = 3.5D;
|
private static final double CRUSH_RADIUS = 3.5D;
|
||||||
private static final int CRUSH_MAX_BLOCKS = 24;
|
private static final int CRUSH_MAX_BLOCKS = 24;
|
||||||
@@ -98,9 +103,6 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
private static final int OBSTRUCTION_CLEAR_MAX_BLOCKS = 24;
|
private static final int OBSTRUCTION_CLEAR_MAX_BLOCKS = 24;
|
||||||
private static final double OBSTRUCTION_CLEAR_MAX_RESISTANCE = 60.0D;
|
private static final double OBSTRUCTION_CLEAR_MAX_RESISTANCE = 60.0D;
|
||||||
private static final float OBSTRUCTION_CLEAR_DROP_CHANCE = 0.1F;
|
private static final float OBSTRUCTION_CLEAR_DROP_CHANCE = 0.1F;
|
||||||
// Keep visual muzzle points separate from the centered multipart hitboxes.
|
|
||||||
// Geo mouth fronts are near z=-219, with side heads centered at x=+/-21. At 2x render scale,
|
|
||||||
// one model pixel is 1/8 block.
|
|
||||||
private static final double BEAM_MUZZLE_FORWARD = 27.375D;
|
private static final double BEAM_MUZZLE_FORWARD = 27.375D;
|
||||||
private static final double BEAM_MUZZLE_CENTER_Y = 11.5D;
|
private static final double BEAM_MUZZLE_CENTER_Y = 11.5D;
|
||||||
private static final double BEAM_MUZZLE_SIDE_Y = 10.25D;
|
private static final double BEAM_MUZZLE_SIDE_Y = 10.25D;
|
||||||
@@ -110,22 +112,40 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
protected static final double FLYING_PREFERRED_HOVER = 6.0D;
|
protected static final double FLYING_PREFERRED_HOVER = 6.0D;
|
||||||
protected static final double FLYING_MAX_HOVER_ABOVE_GROUND = 24.0D;
|
protected static final double FLYING_MAX_HOVER_ABOVE_GROUND = 24.0D;
|
||||||
|
|
||||||
private static final EntityDataAccessor<Boolean> FIRING =
|
@SuppressWarnings("unchecked")
|
||||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN);
|
private static final EntityDataAccessor<Boolean>[] BEAM_ACTIVE = new EntityDataAccessor[] {
|
||||||
private static final EntityDataAccessor<Boolean> HAS_BEAM_END =
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN),
|
||||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN);
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN),
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN)
|
||||||
|
};
|
||||||
private static final EntityDataAccessor<Boolean> ACCELERATED =
|
private static final EntityDataAccessor<Boolean> ACCELERATED =
|
||||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN);
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN);
|
||||||
private static final EntityDataAccessor<Integer> BEAM_ELEMENT =
|
private static final EntityDataAccessor<Boolean> ROYAL_FLYING =
|
||||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.INT);
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN);
|
||||||
private static final EntityDataAccessor<Integer> BEAM_HEAD_SLOT =
|
@SuppressWarnings("unchecked")
|
||||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.INT);
|
private static final EntityDataAccessor<Integer>[] BEAM_ELEMENT = new EntityDataAccessor[] {
|
||||||
private static final EntityDataAccessor<Float> BEAM_END_X =
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.INT),
|
||||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT);
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.INT),
|
||||||
private static final EntityDataAccessor<Float> BEAM_END_Y =
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.INT)
|
||||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT);
|
};
|
||||||
private static final EntityDataAccessor<Float> BEAM_END_Z =
|
@SuppressWarnings("unchecked")
|
||||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT);
|
private static final EntityDataAccessor<Float>[] BEAM_END_X = new EntityDataAccessor[] {
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT),
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT),
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT)
|
||||||
|
};
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static final EntityDataAccessor<Float>[] BEAM_END_Y = new EntityDataAccessor[] {
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT),
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT),
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT)
|
||||||
|
};
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static final EntityDataAccessor<Float>[] BEAM_END_Z = new EntityDataAccessor[] {
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT),
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT),
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT)
|
||||||
|
};
|
||||||
|
|
||||||
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
||||||
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
|
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
|
||||||
@@ -133,7 +153,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlayAndHold("death");
|
private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlayAndHold("death");
|
||||||
|
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
protected final RoyalBeamController beamController = new RoyalBeamController(this);
|
protected final RoyalBeamController[] beamControllers = new RoyalBeamController[3];
|
||||||
protected final RoyalAttackScheduler attackScheduler = new RoyalAttackScheduler();
|
protected final RoyalAttackScheduler attackScheduler = new RoyalAttackScheduler();
|
||||||
private final ServerBossEvent bossEvent;
|
private final ServerBossEvent bossEvent;
|
||||||
private final RoyalHead[] heads = {
|
private final RoyalHead[] heads = {
|
||||||
@@ -141,21 +161,38 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
new RoyalHead(RoyalHead.Slot.CENTER),
|
new RoyalHead(RoyalHead.Slot.CENTER),
|
||||||
new RoyalHead(RoyalHead.Slot.RIGHT)
|
new RoyalHead(RoyalHead.Slot.RIGHT)
|
||||||
};
|
};
|
||||||
private int beamCooldownTicks;
|
private final int[] beamLoopSoundTicks = new int[3];
|
||||||
|
private final int[] assignedHeadCounts = new int[3];
|
||||||
|
private int beamVolleyLimit;
|
||||||
@Nullable
|
@Nullable
|
||||||
private RoyalHead activeBeamHead;
|
private Phase beamVolleyPhase;
|
||||||
private int beamLoopSoundTicks;
|
private final MoveControl groundMoveControl;
|
||||||
private int beamHeadCursor;
|
private final FlyingMoveControl flyingMoveControl;
|
||||||
private boolean beamStarted;
|
private final PathNavigation groundNavigation;
|
||||||
|
private final PathNavigation flyingNavigation;
|
||||||
|
private int locomotionDecisionTicks = 80;
|
||||||
|
private boolean landingForCombat;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Entity[] multipartParts;
|
private Entity[] multipartParts;
|
||||||
|
|
||||||
protected RoyalBossEntity(EntityType<? extends RoyalBossEntity> entityType, Level level) {
|
protected RoyalBossEntity(EntityType<? extends RoyalBossEntity> entityType, Level level) {
|
||||||
super(entityType, level);
|
super(entityType, level);
|
||||||
|
for (int i = 0; i < this.beamControllers.length; i++) {
|
||||||
|
this.beamControllers[i] = new RoyalBeamController(this);
|
||||||
|
}
|
||||||
this.xpReward = 500;
|
this.xpReward = 500;
|
||||||
|
this.groundMoveControl = new MoveControl(this);
|
||||||
|
this.flyingMoveControl = new FlyingMoveControl(this, 20, true);
|
||||||
|
this.groundNavigation = new GroundPathNavigation(this, level);
|
||||||
|
FlyingPathNavigation flyingNavigation = new FlyingPathNavigation(this, level);
|
||||||
|
flyingNavigation.setCanFloat(true);
|
||||||
|
this.flyingNavigation = flyingNavigation;
|
||||||
if (this.isFlyingBoss()) {
|
if (this.isFlyingBoss()) {
|
||||||
this.moveControl = new FlyingMoveControl(this, 20, true);
|
this.moveControl = this.flyingMoveControl;
|
||||||
|
this.navigation = this.flyingNavigation;
|
||||||
|
} else {
|
||||||
|
this.navigation = this.groundNavigation;
|
||||||
}
|
}
|
||||||
this.bossEvent = new com.craisinlord.antarchy.content.boss.EntityLinkedServerBossEvent(
|
this.bossEvent = new com.craisinlord.antarchy.content.boss.EntityLinkedServerBossEvent(
|
||||||
this.getUUID(),
|
this.getUUID(),
|
||||||
@@ -222,6 +259,14 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
|
|
||||||
protected abstract boolean isFlyingBoss();
|
protected abstract boolean isFlyingBoss();
|
||||||
|
|
||||||
|
protected double groundCombatBias() {
|
||||||
|
return 0.35D;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected double biteApproachSpeed() {
|
||||||
|
return 1.3D;
|
||||||
|
}
|
||||||
|
|
||||||
public String geoNameForRender() {
|
public String geoNameForRender() {
|
||||||
return this.geoName();
|
return this.geoName();
|
||||||
}
|
}
|
||||||
@@ -258,21 +303,33 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
this.goalSelector.addGoal(0, new FloatGoal(this));
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
||||||
this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 48.0F));
|
this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 48.0F));
|
||||||
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
|
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
|
||||||
|
this.registerRoyalTargetGoals();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void registerRoyalTargetGoals() {
|
||||||
this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
|
||||||
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canDamageWithRoyalAttack(LivingEntity target) {
|
||||||
|
return target != this
|
||||||
|
&& !(target instanceof RoyalBossEntity)
|
||||||
|
&& target.getType() != this.getType()
|
||||||
|
&& !this.isAlliedTo(target);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||||
super.defineSynchedData(builder);
|
super.defineSynchedData(builder);
|
||||||
builder.define(FIRING, false);
|
|
||||||
builder.define(HAS_BEAM_END, false);
|
|
||||||
builder.define(ACCELERATED, false);
|
builder.define(ACCELERATED, false);
|
||||||
builder.define(BEAM_ELEMENT, RoyalBeamElement.GENERIC.ordinal());
|
builder.define(ROYAL_FLYING, true);
|
||||||
builder.define(BEAM_HEAD_SLOT, -1);
|
for (int i = 0; i < 3; i++) {
|
||||||
builder.define(BEAM_END_X, 0.0F);
|
builder.define(BEAM_ACTIVE[i], false);
|
||||||
builder.define(BEAM_END_Y, 0.0F);
|
builder.define(BEAM_ELEMENT[i], RoyalBeamElement.GENERIC.ordinal());
|
||||||
builder.define(BEAM_END_Z, 0.0F);
|
builder.define(BEAM_END_X[i], 0.0F);
|
||||||
|
builder.define(BEAM_END_Y[i], 0.0F);
|
||||||
|
builder.define(BEAM_END_Z[i], 0.0F);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -308,9 +365,27 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
this.playSound(sound, (float) AntarchySettings.royalBossSoundVolume(), pitch);
|
this.playSound(sound, (float) AntarchySettings.royalBossSoundVolume(), pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void projectRoyalSound(SoundEvent sound, float volume, float pitch, @Nullable LivingEntity focus) {
|
||||||
|
if (this.level().isClientSide) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
java.util.Set<ServerPlayer> recipients = new java.util.LinkedHashSet<>(this.bossEvent.getPlayers());
|
||||||
|
if (focus instanceof ServerPlayer focusPlayer) {
|
||||||
|
recipients.add(focusPlayer);
|
||||||
|
}
|
||||||
|
for (ServerPlayer player : recipients) {
|
||||||
|
player.connection.send(new net.minecraft.network.protocol.game.ClientboundSoundPacket(
|
||||||
|
net.minecraft.core.Holder.direct(sound),
|
||||||
|
net.minecraft.sounds.SoundSource.HOSTILE,
|
||||||
|
player.getX(), player.getY(), player.getZ(),
|
||||||
|
volume, pitch,
|
||||||
|
this.random.nextLong()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void travel(Vec3 travelVector) {
|
public void travel(Vec3 travelVector) {
|
||||||
if (this.isFlyingBoss() && this.isEffectiveAi()) {
|
if (this.isRoyalFlying() && this.isEffectiveAi()) {
|
||||||
this.moveRelative(this.getSpeed(), travelVector);
|
this.moveRelative(this.getSpeed(), travelVector);
|
||||||
this.move(MoverType.SELF, this.getDeltaMovement());
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||||
this.setDeltaMovement(this.getDeltaMovement().scale(0.91D));
|
this.setDeltaMovement(this.getDeltaMovement().scale(0.91D));
|
||||||
@@ -336,19 +411,24 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
OBSTRUCTION_CLEAR_DROP_CHANCE);
|
OBSTRUCTION_CLEAR_DROP_CHANCE);
|
||||||
}
|
}
|
||||||
if (this.isFlyingBoss()) {
|
if (this.isFlyingBoss()) {
|
||||||
|
this.moveControl = this.isRoyalFlying() ? this.flyingMoveControl : this.groundMoveControl;
|
||||||
|
this.navigation = this.isRoyalFlying() ? this.flyingNavigation : this.groundNavigation;
|
||||||
this.setNoGravity(!AntarchyGravityApi.isGravityInverted(this));
|
this.setNoGravity(!AntarchyGravityApi.isGravityInverted(this));
|
||||||
|
if (!this.isRoyalFlying()) {
|
||||||
|
this.setNoGravity(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.level().isClientSide) {
|
if (this.level().isClientSide) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.isFlyingBoss() && !this.isDeadOrDying()) {
|
if (this.isRoyalFlying() && !this.isDeadOrDying() && !this.landingForCombat) {
|
||||||
this.tickFlyingAltitude();
|
this.tickFlyingAltitude();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());
|
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());
|
||||||
this.attackScheduler.tick();
|
this.attackScheduler.tick();
|
||||||
|
|
||||||
if (this.isFlyingBoss() && this.tickCount % 40 == 0 && this.royalFlyLoopSound() != null) {
|
if (this.isRoyalFlying() && this.tickCount % 40 == 0 && this.royalFlyLoopSound() != null) {
|
||||||
this.playRoyalSound(this.royalFlyLoopSound(), 0.92F + this.random.nextFloat() * 0.12F);
|
this.playRoyalSound(this.royalFlyLoopSound(), 0.92F + this.random.nextFloat() * 0.12F);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,6 +444,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.tickCombatLocomotionMode(primaryTarget);
|
||||||
this.getLookControl().setLookAt(primaryTarget, 30.0F, 30.0F);
|
this.getLookControl().setLookAt(primaryTarget, 30.0F, 30.0F);
|
||||||
this.assignHeadTargets(primaryTarget);
|
this.assignHeadTargets(primaryTarget);
|
||||||
this.tickRoyalBeam(primaryTarget);
|
this.tickRoyalBeam(primaryTarget);
|
||||||
@@ -400,45 +481,49 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void tickRoyalBeam(LivingEntity primaryTarget) {
|
private void tickRoyalBeam(LivingEntity primaryTarget) {
|
||||||
if (this.beamCooldownTicks > 0 || this.attackScheduler.laneBusy(this.beamLane())) {
|
Phase phase = this.phase();
|
||||||
this.beamCooldownTicks--;
|
int activeBeams = 0;
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
if (head.beamActive()) {
|
||||||
|
activeBeams++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (this.activeBeamHead != null) {
|
if (activeBeams == 0 || this.beamVolleyPhase != phase) {
|
||||||
LivingEntity beamTarget = this.activeBeamHead.target(this.level());
|
this.beamVolleyPhase = phase;
|
||||||
if (!this.activeBeamHead.shooting() || beamTarget == null || !beamTarget.isAlive()
|
this.beamVolleyLimit = Math.max(1, this.selectBeamVolleyLimit(phase));
|
||||||
|
}
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
int index = head.slot().ordinal();
|
||||||
|
RoyalBeamController controller = this.beamControllers[index];
|
||||||
|
if (controller.isFiring()) {
|
||||||
|
LivingEntity beamTarget = head.target(this.level());
|
||||||
|
if (!head.shooting() || beamTarget == null || !beamTarget.isAlive()
|
||||||
|| this.distanceTo(beamTarget) < this.royalBeamMinimumRange()) {
|
|| this.distanceTo(beamTarget) < this.royalBeamMinimumRange()) {
|
||||||
this.stopRoyalBeam();
|
this.stopRoyalBeam(head);
|
||||||
} else if (!this.beamStarted) {
|
continue;
|
||||||
return;
|
}
|
||||||
} else {
|
if (this.beamLoopSoundTicks[index]-- <= 0) {
|
||||||
if (this.beamLoopSoundTicks-- <= 0) {
|
this.beamLoopSoundTicks[index] = 20;
|
||||||
this.beamLoopSoundTicks = 20;
|
|
||||||
this.playRoyalSound(this.royalBeamLoopSound(), 1.0F);
|
this.playRoyalSound(this.royalBeamLoopSound(), 1.0F);
|
||||||
}
|
}
|
||||||
this.beamController.tick(
|
controller.tick(
|
||||||
this.beamAnchor(this.activeBeamHead),
|
this.beamAnchor(head),
|
||||||
beamTarget,
|
beamTarget,
|
||||||
this.royalBeamSettings(),
|
this.royalBeamSettings(),
|
||||||
this.royalBeamTerrainMode(this.activeBeamHead),
|
this.royalBeamTerrainMode(head),
|
||||||
this::setRoyalBeamEndPosition);
|
end -> this.setRoyalBeamEndPosition(head.slot(), end));
|
||||||
Vec3 beamEnd = this.beamController.beamEndPosition();
|
Vec3 beamEnd = controller.beamEndPosition();
|
||||||
if (beamEnd != null) {
|
if (beamEnd != null) {
|
||||||
this.tickRoyalBeamEffects(this.activeBeamHead, this.beamAnchor(this.activeBeamHead), beamEnd);
|
this.tickRoyalBeamEffects(head, this.beamAnchor(head), beamEnd);
|
||||||
}
|
}
|
||||||
if (!this.beamController.isFiring()) {
|
if (!controller.isFiring()) {
|
||||||
this.stopRoyalBeam();
|
this.stopRoyalBeam(head);
|
||||||
}
|
}
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (activeBeams >= this.beamVolleyLimit) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.beamCooldownTicks > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Phase phase = this.phase();
|
|
||||||
for (int offset = 0; offset < this.heads.length; offset++) {
|
|
||||||
RoyalHead head = this.heads[(this.beamHeadCursor + offset) % this.heads.length];
|
|
||||||
LivingEntity target = head.target(this.level());
|
LivingEntity target = head.target(this.level());
|
||||||
if (!head.readyToAttack() || this.attackScheduler.laneBusy(this.headLane(head))
|
if (!head.readyToAttack() || this.attackScheduler.laneBusy(this.headLane(head))
|
||||||
|| target == null || !this.canAttack(target)
|
|| target == null || !this.canAttack(target)
|
||||||
@@ -454,62 +539,53 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
windup = Math.max(0, AntarchySettings.kingBeamWindupTicks());
|
windup = Math.max(0, AntarchySettings.kingBeamWindupTicks());
|
||||||
}
|
}
|
||||||
LivingEntity committedTarget = target;
|
LivingEntity committedTarget = target;
|
||||||
if (!this.attackScheduler.start("beam_" + head.slot().name(), this.beamLane(), cooldown,
|
if (!this.beginRoyalAttack("beam_" + head.slot().name(), this.headLane(head), cooldown,
|
||||||
windup, duration, 8, new RoyalAttackScheduler.Action() {
|
windup, duration, 8, new RoyalAttackScheduler.Action() {
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
head.startShoot();
|
head.startShoot();
|
||||||
|
RoyalBossEntity.this.triggerAnim(head.slot().controllerName(), "shoot");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActive(int elapsedTicks) {
|
public void onActive(int elapsedTicks) {
|
||||||
if (elapsedTicks != 0 || RoyalBossEntity.this.beamStarted) {
|
if (elapsedTicks != 0 || RoyalBossEntity.this.beamControllers[index].isFiring()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RoyalBossEntity.this.beamStarted = true;
|
RoyalBossEntity.this.beamControllers[index].start(
|
||||||
RoyalBossEntity.this.beamController.start(
|
|
||||||
RoyalBossEntity.this.beamAnchor(head), committedTarget.getEyePosition(), duration);
|
RoyalBossEntity.this.beamAnchor(head), committedTarget.getEyePosition(), duration);
|
||||||
RoyalBossEntity.this.entityData.set(BEAM_ELEMENT, RoyalBossEntity.this.royalBeamElement(head).ordinal());
|
RoyalBossEntity.this.entityData.set(BEAM_ELEMENT[index], RoyalBossEntity.this.royalBeamElement(head).ordinal());
|
||||||
RoyalBossEntity.this.entityData.set(BEAM_HEAD_SLOT, head.slot().ordinal());
|
RoyalBossEntity.this.entityData.set(BEAM_ACTIVE[index], true);
|
||||||
RoyalBossEntity.this.setFiringRoyalBeam(true);
|
RoyalBossEntity.this.beamLoopSoundTicks[index] = 20;
|
||||||
RoyalBossEntity.this.triggerAnim(head.slot().controllerName(), "shoot");
|
|
||||||
RoyalBossEntity.this.beamLoopSoundTicks = 20;
|
|
||||||
RoyalBossEntity.this.playRoyalSound(RoyalBossEntity.this.royalBeamStartSound(head), 1.0F);
|
RoyalBossEntity.this.playRoyalSound(RoyalBossEntity.this.royalBeamStartSound(head), 1.0F);
|
||||||
RoyalBossEntity.this.playRoyalSound(RoyalBossEntity.this.royalBeamShootSound(), 1.0F);
|
RoyalBossEntity.this.playRoyalSound(RoyalBossEntity.this.royalBeamShootSound(), 1.0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplete() {
|
public void onComplete() {
|
||||||
if (RoyalBossEntity.this.activeBeamHead == head) {
|
RoyalBossEntity.this.stopRoyalBeam(head);
|
||||||
RoyalBossEntity.this.stopRoyalBeam();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})) {
|
})) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
head.setBeamActive(true);
|
head.setBeamActive(true);
|
||||||
this.activeBeamHead = head;
|
activeBeams++;
|
||||||
this.beamHeadCursor = (head.slot().partIndex()) % this.heads.length;
|
|
||||||
this.beamCooldownTicks = cooldown;
|
|
||||||
this.beamStarted = false;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopRoyalBeam() {
|
protected int selectBeamVolleyLimit(Phase phase) {
|
||||||
if (this.activeBeamHead != null) {
|
return phase.maxConcurrentHeadAttacks();
|
||||||
this.activeBeamHead.setBeamActive(false);
|
|
||||||
this.activeBeamHead.stopShoot();
|
|
||||||
}
|
}
|
||||||
this.activeBeamHead = null;
|
|
||||||
this.beamStarted = false;
|
private void stopRoyalBeam(RoyalHead head) {
|
||||||
this.attackScheduler.cancel(this.beamLane());
|
int index = head.slot().ordinal();
|
||||||
this.beamController.stop();
|
head.setBeamActive(false);
|
||||||
this.entityData.set(BEAM_ELEMENT, RoyalBeamElement.GENERIC.ordinal());
|
head.stopShoot();
|
||||||
this.entityData.set(BEAM_HEAD_SLOT, -1);
|
this.beamControllers[index].stop();
|
||||||
|
this.entityData.set(BEAM_ACTIVE[index], false);
|
||||||
|
this.entityData.set(BEAM_ELEMENT[index], RoyalBeamElement.GENERIC.ordinal());
|
||||||
this.playRoyalSound(this.royalBeamEndSound(), 1.0F);
|
this.playRoyalSound(this.royalBeamEndSound(), 1.0F);
|
||||||
this.setFiringRoyalBeam(false);
|
this.setRoyalBeamEndPosition(head.slot(), null);
|
||||||
this.setRoyalBeamEndPosition(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Phase phase() {
|
public Phase phase() {
|
||||||
@@ -524,6 +600,12 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void assignHeadTargets(LivingEntity fallback) {
|
private void assignHeadTargets(LivingEntity fallback) {
|
||||||
|
if (!this.shouldDistributeHeadTargets(fallback)) {
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
head.setTarget(fallback);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
List<Player> candidates = this.level().getEntitiesOfClass(
|
List<Player> candidates = this.level().getEntitiesOfClass(
|
||||||
Player.class,
|
Player.class,
|
||||||
this.getBoundingBox().inflate(AntarchySettings.royalBossFollowRange()),
|
this.getBoundingBox().inflate(AntarchySettings.royalBossFollowRange()),
|
||||||
@@ -535,7 +617,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] assignedCounts = new int[candidates.size()];
|
Arrays.fill(this.assignedHeadCounts, 0);
|
||||||
for (RoyalHead head : this.heads) {
|
for (RoyalHead head : this.heads) {
|
||||||
Vec3 anchor = this.headAnchor(head);
|
Vec3 anchor = this.headAnchor(head);
|
||||||
int bestIndex = 0;
|
int bestIndex = 0;
|
||||||
@@ -543,47 +625,113 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
double bestDistance = Double.MAX_VALUE;
|
double bestDistance = Double.MAX_VALUE;
|
||||||
for (int i = 0; i < candidates.size(); i++) {
|
for (int i = 0; i < candidates.size(); i++) {
|
||||||
double distance = candidates.get(i).position().distanceToSqr(anchor);
|
double distance = candidates.get(i).position().distanceToSqr(anchor);
|
||||||
if (assignedCounts[i] < bestCount || (assignedCounts[i] == bestCount && distance < bestDistance)) {
|
if (this.assignedHeadCounts[i] < bestCount || (this.assignedHeadCounts[i] == bestCount && distance < bestDistance)) {
|
||||||
bestIndex = i;
|
bestIndex = i;
|
||||||
bestCount = assignedCounts[i];
|
bestCount = this.assignedHeadCounts[i];
|
||||||
bestDistance = distance;
|
bestDistance = distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assignedCounts[bestIndex]++;
|
this.assignedHeadCounts[bestIndex]++;
|
||||||
head.setTarget(candidates.get(bestIndex));
|
head.setTarget(candidates.get(bestIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean shouldDistributeHeadTargets(LivingEntity primaryTarget) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void steerTowardTarget(LivingEntity target) {
|
private void steerTowardTarget(LivingEntity target) {
|
||||||
double reach = this.getBbWidth() * 0.5D + this.biteReach() * 0.5D;
|
|
||||||
double dx = target.getX() - this.getX();
|
double dx = target.getX() - this.getX();
|
||||||
double dz = target.getZ() - this.getZ();
|
double dz = target.getZ() - this.getZ();
|
||||||
boolean closeHorizontally = (dx * dx + dz * dz) <= reach * reach;
|
double horizontalDistance = Math.sqrt(dx * dx + dz * dz);
|
||||||
|
Vec3 awayFromTarget = horizontalDistance > 1.0E-4D
|
||||||
|
? new Vec3(-dx / horizontalDistance, 0.0D, -dz / horizontalDistance)
|
||||||
|
: this.getViewVector(1.0F).multiply(-1.0D, 0.0D, -1.0D).normalize();
|
||||||
|
double standoff = Math.max(this.getBbWidth() * 0.55D,
|
||||||
|
BEAM_MUZZLE_FORWARD - this.biteReach() * 0.65D);
|
||||||
|
Vec3 wanted = target.position().add(awayFromTarget.scale(standoff));
|
||||||
|
boolean atStandoff = this.position().multiply(1.0D, 0.0D, 1.0D)
|
||||||
|
.distanceToSqr(wanted.multiply(1.0D, 0.0D, 1.0D)) <= 4.0D;
|
||||||
|
boolean anyHeadInBiteRange = Arrays.stream(this.heads)
|
||||||
|
.anyMatch(head -> this.headWithinBiteReach(head, target));
|
||||||
|
double approachSpeed = anyHeadInBiteRange ? 1.0D : this.biteApproachSpeed();
|
||||||
|
|
||||||
if (!this.isFlyingBoss()) {
|
if (!this.isRoyalFlying()) {
|
||||||
if (closeHorizontally) {
|
if (atStandoff) {
|
||||||
this.getNavigation().stop();
|
this.getNavigation().stop();
|
||||||
} else {
|
} else {
|
||||||
this.getMoveControl().setWantedPosition(target.getX(), target.getY(), target.getZ(), 1.0D);
|
this.getMoveControl().setWantedPosition(wanted.x, target.getY(), wanted.z, approachSpeed);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean inverted = AntarchyGravityApi.isGravityInverted(this);
|
boolean inverted = AntarchyGravityApi.isGravityInverted(this);
|
||||||
double groundBelowTarget = this.groundYBelow(target.getX(), target.getZ());
|
double groundBelowTarget = this.groundYBelow(wanted.x, wanted.z);
|
||||||
double wantedY = inverted
|
double wantedY = this.landingForCombat
|
||||||
|
? (inverted ? target.getY() + target.getBbHeight() - this.getBbHeight() : groundBelowTarget)
|
||||||
|
: inverted
|
||||||
? target.getY() - 3.0D
|
? target.getY() - 3.0D
|
||||||
: Mth.clamp(target.getY() + 3.0D,
|
: Mth.clamp(target.getY() + 3.0D,
|
||||||
groundBelowTarget + FLYING_MIN_HOVER,
|
groundBelowTarget + FLYING_MIN_HOVER,
|
||||||
groundBelowTarget + FLYING_MAX_HOVER_ABOVE_GROUND);
|
groundBelowTarget + FLYING_MAX_HOVER_ABOVE_GROUND);
|
||||||
boolean closeVertically = Math.abs(wantedY - this.getY()) <= 2.5D;
|
boolean closeVertically = Math.abs(wantedY - this.getY()) <= 2.5D;
|
||||||
if (closeHorizontally && closeVertically) {
|
if (atStandoff && closeVertically) {
|
||||||
this.getNavigation().stop();
|
this.getNavigation().stop();
|
||||||
} else {
|
} else {
|
||||||
this.getMoveControl().setWantedPosition(target.getX(), wantedY, target.getZ(), 1.1D);
|
this.getMoveControl().setWantedPosition(wanted.x, wantedY, wanted.z, approachSpeed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tickCombatLocomotionMode(LivingEntity target) {
|
||||||
|
if (!this.isFlyingBoss()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean inverted = AntarchyGravityApi.isGravityInverted(this);
|
||||||
|
double groundY = this.groundYBelow(this.getX(), this.getZ());
|
||||||
|
if (this.landingForCombat) {
|
||||||
|
if (!target.onGround()) {
|
||||||
|
this.landingForCombat = false;
|
||||||
|
this.locomotionDecisionTicks = 60;
|
||||||
|
} else if (this.onGround() || !inverted && this.getY() <= groundY + 1.0D) {
|
||||||
|
this.landingForCombat = false;
|
||||||
|
this.setRoyalFlying(false);
|
||||||
|
this.locomotionDecisionTicks = 100 + this.random.nextInt(100);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--this.locomotionDecisionTicks > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.isRoyalFlying()) {
|
||||||
|
this.locomotionDecisionTicks = 60 + this.random.nextInt(80);
|
||||||
|
if (target.onGround() && this.random.nextDouble() < this.groundCombatBias()) {
|
||||||
|
this.landingForCombat = true;
|
||||||
|
}
|
||||||
|
} else if (!target.onGround() || this.random.nextDouble() >= this.groundCombatBias()) {
|
||||||
|
this.setRoyalFlying(true);
|
||||||
|
this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.35D, 0.0D));
|
||||||
|
this.locomotionDecisionTicks = 80 + this.random.nextInt(100);
|
||||||
|
} else {
|
||||||
|
this.locomotionDecisionTicks = 80 + this.random.nextInt(80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRoyalFlying() {
|
||||||
|
return this.isFlyingBoss() && this.entityData.get(ROYAL_FLYING);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void setRoyalFlying(boolean flying) {
|
||||||
|
if (this.entityData.get(ROYAL_FLYING) == flying) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.navigation.stop();
|
||||||
|
this.entityData.set(ROYAL_FLYING, flying);
|
||||||
|
this.moveControl = flying ? this.flyingMoveControl : this.groundMoveControl;
|
||||||
|
this.navigation = flying ? this.flyingNavigation : this.groundNavigation;
|
||||||
|
this.setNoGravity(flying && !AntarchyGravityApi.isGravityInverted(this));
|
||||||
|
}
|
||||||
|
|
||||||
protected double groundYBelow(double x, double z) {
|
protected double groundYBelow(double x, double z) {
|
||||||
return this.level().getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
|
return this.level().getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
|
||||||
Mth.floor(x), Mth.floor(z));
|
Mth.floor(x), Mth.floor(z));
|
||||||
@@ -619,14 +767,14 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
Vec3 forward = new Vec3(-Math.sin(yaw), 0.0D, Math.cos(yaw));
|
Vec3 forward = new Vec3(-Math.sin(yaw), 0.0D, Math.cos(yaw));
|
||||||
Vec3 center = new Vec3(
|
Vec3 center = new Vec3(
|
||||||
this.getX() + forward.x * (this.getBbWidth() * 0.45D),
|
this.getX() + forward.x * (this.getBbWidth() * 0.45D),
|
||||||
this.getY() + (this.isFlyingBoss() ? 0.0D : 1.0D),
|
this.getY() + (this.isRoyalFlying() ? 0.0D : 1.0D),
|
||||||
this.getZ() + forward.z * (this.getBbWidth() * 0.45D));
|
this.getZ() + forward.z * (this.getBbWidth() * 0.45D));
|
||||||
RoyalBlockDestruction.destroySphere(serverLevel, this, center, CRUSH_RADIUS, CRUSH_MAX_BLOCKS, CRUSH_MAX_RESISTANCE, CRUSH_DROP_CHANCE);
|
RoyalBlockDestruction.destroySphere(serverLevel, this, center, CRUSH_RADIUS, CRUSH_MAX_BLOCKS, CRUSH_MAX_RESISTANCE, CRUSH_DROP_CHANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startBite(RoyalHead head, Phase phase) {
|
private void startBite(RoyalHead head, Phase phase) {
|
||||||
int cooldown = Math.max(10, Mth.floor(AntarchySettings.royalBossBiteCooldownTicks() * phase.cooldownScale()));
|
int cooldown = Math.max(10, Mth.floor(AntarchySettings.royalBossBiteCooldownTicks() * phase.cooldownScale()));
|
||||||
if (!this.attackScheduler.start("bite_" + head.slot().name(), headLane(head), cooldown,
|
if (!this.beginRoyalAttack("bite_" + head.slot().name(), headLane(head), cooldown,
|
||||||
BITE_HIT_TICK, 1, BITE_DURATION_TICKS - BITE_HIT_TICK,
|
BITE_HIT_TICK, 1, BITE_DURATION_TICKS - BITE_HIT_TICK,
|
||||||
new RoyalAttackScheduler.Action() {
|
new RoyalAttackScheduler.Action() {
|
||||||
@Override
|
@Override
|
||||||
@@ -663,7 +811,12 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
|
|
||||||
protected boolean beginRoyalAttack(String id, RoyalAttackLane lane, int cooldownTicks, int windupTicks,
|
protected boolean beginRoyalAttack(String id, RoyalAttackLane lane, int cooldownTicks, int windupTicks,
|
||||||
int activeTicks, int recoveryTicks, RoyalAttackScheduler.Action action) {
|
int activeTicks, int recoveryTicks, RoyalAttackScheduler.Action action) {
|
||||||
return this.attackScheduler.start(id, lane, cooldownTicks, windupTicks, activeTicks, recoveryTicks, action);
|
int protectedRecovery = recoveryTicks;
|
||||||
|
if (lane == RoyalAttackLane.LEFT_HEAD || lane == RoyalAttackLane.CENTER_HEAD || lane == RoyalAttackLane.RIGHT_HEAD) {
|
||||||
|
protectedRecovery = Math.max(recoveryTicks,
|
||||||
|
HEAD_ATTACK_ANIMATION_TICKS - Math.max(0, windupTicks) - Math.max(1, activeTicks));
|
||||||
|
}
|
||||||
|
return this.attackScheduler.start(id, lane, cooldownTicks, windupTicks, activeTicks, protectedRecovery, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyBiteHit(RoyalHead head) {
|
private void applyBiteHit(RoyalHead head) {
|
||||||
@@ -676,7 +829,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
DamageSource damageSource = this.damageSources().mobAttack(this);
|
DamageSource damageSource = this.damageSources().mobAttack(this);
|
||||||
AABB box = new AABB(anchor, anchor).inflate(reach);
|
AABB box = new AABB(anchor, anchor).inflate(reach);
|
||||||
for (LivingEntity living : this.level().getEntitiesOfClass(LivingEntity.class, box, entity -> entity.isAlive() && entity != this)) {
|
for (LivingEntity living : this.level().getEntitiesOfClass(LivingEntity.class, box, entity -> entity.isAlive() && entity != this)) {
|
||||||
if (living instanceof RoyalBossEntity || living.getType() == this.getType()) {
|
if (!this.canDamageWithRoyalAttack(living)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (living.position().distanceToSqr(anchor) > reach * reach) {
|
if (living.position().distanceToSqr(anchor) > reach * reach) {
|
||||||
@@ -753,12 +906,22 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
@Override
|
@Override
|
||||||
public void die(DamageSource damageSource) {
|
public void die(DamageSource damageSource) {
|
||||||
if (!this.level().isClientSide) {
|
if (!this.level().isClientSide) {
|
||||||
|
this.stopTriggeredAnim("wing_action", null);
|
||||||
|
this.stopTriggeredAnim("head_left", null);
|
||||||
|
this.stopTriggeredAnim("head_center", null);
|
||||||
|
this.stopTriggeredAnim("head_right", null);
|
||||||
|
this.stopTriggeredAnim("body_action", null);
|
||||||
for (RoyalHead head : this.heads) {
|
for (RoyalHead head : this.heads) {
|
||||||
head.reset();
|
head.reset();
|
||||||
}
|
}
|
||||||
this.beamController.stop();
|
for (RoyalBeamController controller : this.beamControllers) {
|
||||||
|
controller.stop();
|
||||||
|
}
|
||||||
this.setFiringRoyalBeam(false);
|
this.setFiringRoyalBeam(false);
|
||||||
this.setRoyalBeamEndPosition(null);
|
for (RoyalHead head : this.heads) {
|
||||||
|
this.stopRoyalBeam(head);
|
||||||
|
}
|
||||||
|
this.setRoyalFlying(false);
|
||||||
this.getNavigation().stop();
|
this.getNavigation().stop();
|
||||||
this.setDeltaMovement(Vec3.ZERO);
|
this.setDeltaMovement(Vec3.ZERO);
|
||||||
}
|
}
|
||||||
@@ -791,6 +954,13 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
@Override
|
@Override
|
||||||
protected void tickDeath() {
|
protected void tickDeath() {
|
||||||
this.deathTime++;
|
this.deathTime++;
|
||||||
|
this.setNoGravity(false);
|
||||||
|
Vec3 movement = this.getDeltaMovement();
|
||||||
|
if (this.onGround()) {
|
||||||
|
this.setDeltaMovement(movement.x * 0.6D, 0.0D, movement.z * 0.6D);
|
||||||
|
} else {
|
||||||
|
this.setDeltaMovement(movement.x * 0.8D, Math.min(-0.12D, movement.y), movement.z * 0.8D);
|
||||||
|
}
|
||||||
if (this.deathTime == 20 && !this.level().isClientSide()) {
|
if (this.deathTime == 20 && !this.level().isClientSide()) {
|
||||||
this.level().broadcastEntityEvent(this, (byte) 60);
|
this.level().broadcastEntityEvent(this, (byte) 60);
|
||||||
}
|
}
|
||||||
@@ -835,71 +1005,85 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFiringRoyalBeam() {
|
public boolean isFiringRoyalBeam() {
|
||||||
return this.entityData.get(FIRING);
|
for (RoyalHead.Slot slot : RoyalHead.Slot.values()) {
|
||||||
|
if (this.isFiringRoyalBeam(slot)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFiringRoyalBeam(boolean firing) {
|
public void setFiringRoyalBeam(boolean firing) {
|
||||||
this.entityData.set(FIRING, firing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public RoyalBeamController beamController() {
|
public RoyalBeamController beamController() {
|
||||||
return this.beamController;
|
return this.beamControllers[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRoyalBeamEndPosition(@Nullable Vec3 position) {
|
public void setRoyalBeamEndPosition(@Nullable Vec3 position) {
|
||||||
this.entityData.set(HAS_BEAM_END, position != null);
|
this.setRoyalBeamEndPosition(RoyalHead.Slot.CENTER, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoyalBeamEndPosition(RoyalHead.Slot slot, @Nullable Vec3 position) {
|
||||||
|
int index = slot.ordinal();
|
||||||
|
this.entityData.set(BEAM_ACTIVE[index], position != null || this.beamControllers[index].isFiring());
|
||||||
if (position != null) {
|
if (position != null) {
|
||||||
this.entityData.set(BEAM_END_X, (float) position.x);
|
this.entityData.set(BEAM_END_X[index], (float) position.x);
|
||||||
this.entityData.set(BEAM_END_Y, (float) position.y);
|
this.entityData.set(BEAM_END_Y[index], (float) position.y);
|
||||||
this.entityData.set(BEAM_END_Z, (float) position.z);
|
this.entityData.set(BEAM_END_Z[index], (float) position.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Vec3 getRoyalBeamEndPosition() {
|
public Vec3 getRoyalBeamEndPosition() {
|
||||||
if (!this.entityData.get(HAS_BEAM_END)) {
|
return this.getRoyalBeamEndPosition(RoyalHead.Slot.CENTER);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new Vec3(this.entityData.get(BEAM_END_X), this.entityData.get(BEAM_END_Y), this.entityData.get(BEAM_END_Z));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 getRoyalBeamShootFrom(float partialTicks) {
|
public Vec3 getRoyalBeamShootFrom(float partialTicks) {
|
||||||
int slotIndex = this.activeBeamHead != null
|
return this.getRoyalBeamShootFrom(RoyalHead.Slot.CENTER, partialTicks);
|
||||||
? this.activeBeamHead.slot().ordinal()
|
}
|
||||||
: this.entityData.get(BEAM_HEAD_SLOT);
|
|
||||||
if (slotIndex >= 0 && slotIndex < RoyalHead.Slot.values().length) {
|
public Vec3 getRoyalBeamShootFrom(RoyalHead.Slot slot, float partialTicks) {
|
||||||
double x = Mth.lerp(partialTicks, this.xo, this.getX());
|
double x = Mth.lerp(partialTicks, this.xo, this.getX());
|
||||||
double y = Mth.lerp(partialTicks, this.yo, this.getY());
|
double y = Mth.lerp(partialTicks, this.yo, this.getY());
|
||||||
double z = Mth.lerp(partialTicks, this.zo, this.getZ());
|
double z = Mth.lerp(partialTicks, this.zo, this.getZ());
|
||||||
float yaw = Mth.rotLerp(partialTicks, this.yRotO, this.getYRot());
|
float yaw = Mth.rotLerp(partialTicks, this.yRotO, this.getYRot());
|
||||||
return this.beamAnchor(RoyalHead.Slot.values()[slotIndex], x, y, z, yaw);
|
return this.beamAnchor(slot, x, y, z, yaw);
|
||||||
}
|
|
||||||
double x = Mth.lerp(partialTicks, this.xo, this.getX());
|
|
||||||
double y = Mth.lerp(partialTicks, this.yo, this.getY()) + this.getBbHeight() * 0.72D;
|
|
||||||
double z = Mth.lerp(partialTicks, this.zo, this.getZ());
|
|
||||||
return new Vec3(x, y, z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public RoyalBeamElement getRoyalBeamElement() {
|
public RoyalBeamElement getRoyalBeamElement() {
|
||||||
int ordinal = this.entityData.get(BEAM_ELEMENT);
|
return this.getRoyalBeamElement(RoyalHead.Slot.CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoyalBeamElement getRoyalBeamElement(RoyalHead.Slot slot) {
|
||||||
|
int ordinal = this.entityData.get(BEAM_ELEMENT[slot.ordinal()]);
|
||||||
return ordinal >= 0 && ordinal < RoyalBeamElement.values().length
|
return ordinal >= 0 && ordinal < RoyalBeamElement.values().length
|
||||||
? RoyalBeamElement.values()[ordinal]
|
? RoyalBeamElement.values()[ordinal]
|
||||||
: RoyalBeamElement.GENERIC;
|
: RoyalBeamElement.GENERIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFiringRoyalBeam(RoyalHead.Slot slot) {
|
||||||
|
return this.entityData.get(BEAM_ACTIVE[slot.ordinal()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Vec3 getRoyalBeamEndPosition(RoyalHead.Slot slot) {
|
||||||
|
int index = slot.ordinal();
|
||||||
|
if (!this.entityData.get(BEAM_ACTIVE[index])) return null;
|
||||||
|
return new Vec3(this.entityData.get(BEAM_END_X[index]), this.entityData.get(BEAM_END_Y[index]), this.entityData.get(BEAM_END_Z[index]));
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public RoyalHead.Slot getRoyalBeamHeadSlot() {
|
public RoyalHead.Slot getRoyalBeamHeadSlot() {
|
||||||
int slotIndex = this.activeBeamHead != null
|
for (RoyalHead.Slot slot : RoyalHead.Slot.values()) {
|
||||||
? this.activeBeamHead.slot().ordinal()
|
if (this.isFiringRoyalBeam(slot)) return slot;
|
||||||
: this.entityData.get(BEAM_HEAD_SLOT);
|
}
|
||||||
return slotIndex >= 0 && slotIndex < RoyalHead.Slot.values().length
|
return null;
|
||||||
? RoyalHead.Slot.values()[slotIndex]
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||||
controllers.add(new AnimationController<>(this, "locomotion", 4, this::locomotionPredicate));
|
controllers.add(new AnimationController<>(this, "locomotion", 4, this::locomotionPredicate));
|
||||||
|
controllers.add(new AnimationController<>(this, "wing_action", 0, RoyalBossEntity::headIdle)
|
||||||
|
.triggerableAnim("wing_gust", RawAnimation.begin().thenPlay("wing_gust")));
|
||||||
controllers.add(new AnimationController<>(this, "head_left", 0, RoyalBossEntity::headIdle)
|
controllers.add(new AnimationController<>(this, "head_left", 0, RoyalBossEntity::headIdle)
|
||||||
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_3"))
|
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_3"))
|
||||||
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_3")));
|
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_3")));
|
||||||
@@ -911,7 +1095,6 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_2")));
|
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_2")));
|
||||||
controllers.add(new AnimationController<>(this, "body_action", 0, this::bodyActionPredicate)
|
controllers.add(new AnimationController<>(this, "body_action", 0, this::bodyActionPredicate)
|
||||||
.triggerableAnim("stomp", RawAnimation.begin().thenPlay("stomp"))
|
.triggerableAnim("stomp", RawAnimation.begin().thenPlay("stomp"))
|
||||||
.triggerableAnim("wing_gust", RawAnimation.begin().thenPlay("wing_gust"))
|
|
||||||
.triggerableAnim("minion_spawn", RawAnimation.begin().thenPlay("minion_spawn")));
|
.triggerableAnim("minion_spawn", RawAnimation.begin().thenPlay("minion_spawn")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -919,7 +1102,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
if (this.isDeadOrDying()) {
|
if (this.isDeadOrDying()) {
|
||||||
return PlayState.STOP;
|
return PlayState.STOP;
|
||||||
}
|
}
|
||||||
if (this.isFlyingBoss()) {
|
if (this.isRoyalFlying()) {
|
||||||
state.setAndContinue(FLY_ANIM);
|
state.setAndContinue(FLY_ANIM);
|
||||||
} else if (state.isMoving()) {
|
} else if (state.isMoving()) {
|
||||||
state.setAndContinue(WALK_ANIM);
|
state.setAndContinue(WALK_ANIM);
|
||||||
@@ -940,6 +1123,18 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
return PlayState.STOP;
|
return PlayState.STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.addAdditionalSaveData(tag);
|
||||||
|
tag.putBoolean("RoyalFlying", this.isRoyalFlying());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.readAdditionalSaveData(tag);
|
||||||
|
this.setRoyalFlying(!tag.contains("RoyalFlying") || tag.getBoolean("RoyalFlying"));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||||
return this.geoCache;
|
return this.geoCache;
|
||||||
|
|||||||
+52
-7
@@ -5,6 +5,7 @@ import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
|||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
@@ -32,12 +33,12 @@ import software.bernie.geckolib.animation.PlayState;
|
|||||||
import software.bernie.geckolib.animation.RawAnimation;
|
import software.bernie.geckolib.animation.RawAnimation;
|
||||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
/** Shared travelling shell for the King's fireball and iceball. Impact rules stay element-specific. */
|
|
||||||
public class RoyalElementalProjectileEntity extends ThrowableProjectile implements GeoEntity {
|
public class RoyalElementalProjectileEntity extends ThrowableProjectile implements GeoEntity {
|
||||||
private static final EntityDataAccessor<Integer> ATTACK_TYPE =
|
private static final EntityDataAccessor<Integer> ATTACK_TYPE =
|
||||||
SynchedEntityData.defineId(RoyalElementalProjectileEntity.class, EntityDataSerializers.INT);
|
SynchedEntityData.defineId(RoyalElementalProjectileEntity.class, EntityDataSerializers.INT);
|
||||||
private static final int FIREBALL = 0;
|
private static final int FIREBALL = 0;
|
||||||
private static final int ICEBALL = 1;
|
private static final int ICEBALL = 1;
|
||||||
|
private static final int DREAM_FIREBALL = 2;
|
||||||
private static final int MAX_LIFETIME = 100;
|
private static final int MAX_LIFETIME = 100;
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
|
||||||
@@ -52,7 +53,8 @@ public class RoyalElementalProjectileEntity extends ThrowableProjectile implemen
|
|||||||
AntarchyObjects.ROYAL_ELEMENTAL_PROJECTILE.get(), level);
|
AntarchyObjects.ROYAL_ELEMENTAL_PROJECTILE.get(), level);
|
||||||
projectile.setOwner(owner);
|
projectile.setOwner(owner);
|
||||||
projectile.setPos(position.x, position.y, position.z);
|
projectile.setPos(position.x, position.y, position.z);
|
||||||
projectile.setAttackType(element == RoyalBeamElement.ICE ? ICEBALL : FIREBALL);
|
projectile.setAttackType(element == RoyalBeamElement.ICE ? ICEBALL
|
||||||
|
: element == RoyalBeamElement.DREAM_FIRE ? DREAM_FIREBALL : FIREBALL);
|
||||||
projectile.shoot(direction.x, direction.y, direction.z, element == RoyalBeamElement.ICE ? 0.8F : 1.05F, 0.0F);
|
projectile.shoot(direction.x, direction.y, direction.z, element == RoyalBeamElement.ICE ? 0.8F : 1.05F, 0.0F);
|
||||||
return projectile;
|
return projectile;
|
||||||
}
|
}
|
||||||
@@ -66,6 +68,10 @@ public class RoyalElementalProjectileEntity extends ThrowableProjectile implemen
|
|||||||
return this.entityData.get(ATTACK_TYPE) == ICEBALL;
|
return this.entityData.get(ATTACK_TYPE) == ICEBALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDreamFireball() {
|
||||||
|
return this.entityData.get(ATTACK_TYPE) == DREAM_FIREBALL;
|
||||||
|
}
|
||||||
|
|
||||||
private void setAttackType(int type) {
|
private void setAttackType(int type) {
|
||||||
this.entityData.set(ATTACK_TYPE, type);
|
this.entityData.set(ATTACK_TYPE, type);
|
||||||
}
|
}
|
||||||
@@ -87,7 +93,7 @@ public class RoyalElementalProjectileEntity extends ThrowableProjectile implemen
|
|||||||
}
|
}
|
||||||
super.tick();
|
super.tick();
|
||||||
if (this.level().isClientSide) {
|
if (this.level().isClientSide) {
|
||||||
this.level().addParticle(this.isIceball() ? ParticleTypes.SNOWFLAKE : ParticleTypes.FLAME,
|
this.level().addParticle(this.getTrailParticle(),
|
||||||
this.getX(), this.getY(), this.getZ(), 0.0D, 0.0D, 0.0D);
|
this.getX(), this.getY(), this.getZ(), 0.0D, 0.0D, 0.0D);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,20 +133,43 @@ public class RoyalElementalProjectileEntity extends ThrowableProjectile implemen
|
|||||||
private void impactFire(ServerLevel level, Vec3 center) {
|
private void impactFire(ServerLevel level, Vec3 center) {
|
||||||
DamageSource source = this.damageSources().mobProjectile(this, this.getOwner() instanceof LivingEntity living ? living : null);
|
DamageSource source = this.damageSources().mobProjectile(this, this.getOwner() instanceof LivingEntity living ? living : null);
|
||||||
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, new AABB(center, center).inflate(5.0D),
|
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, new AABB(center, center).inflate(5.0D),
|
||||||
entity -> entity.isAlive() && entity != this.getOwner())) {
|
this::canDamageWithImpact)) {
|
||||||
double distance = Math.max(0.5D, living.position().distanceTo(center));
|
double distance = Math.max(0.5D, living.position().distanceTo(center));
|
||||||
float falloff = (float) Math.max(0.25D, 1.0D - distance / 5.0D);
|
float falloff = (float) Math.max(0.25D, 1.0D - distance / 5.0D);
|
||||||
living.hurt(source, (float) (AntarchySettings.kingFireballDamage() * falloff));
|
living.hurt(source, (float) (AntarchySettings.kingFireballDamage() * falloff));
|
||||||
living.setRemainingFireTicks(Math.max(living.getRemainingFireTicks(), 120));
|
living.setRemainingFireTicks(Math.max(living.getRemainingFireTicks(), 120));
|
||||||
}
|
}
|
||||||
RoyalBlockDestruction.destroySphere(level, this, center, AntarchySettings.kingFireballRadius(), AntarchySettings.kingElementalTerrainCap(), 80.0D, 0.15F);
|
igniteImpact(level, center, this.isDreamFireball());
|
||||||
level.sendParticles(ParticleTypes.EXPLOSION_EMITTER, center.x, center.y, center.z, 4, 1.5D, 1.5D, 1.5D, 0.0D);
|
level.sendParticles(ParticleTypes.EXPLOSION_EMITTER, center.x, center.y, center.z, 4, 1.5D, 1.5D, 1.5D, 0.0D);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void igniteImpact(ServerLevel level, Vec3 center, boolean dream) {
|
||||||
|
double radius = AntarchySettings.kingFireballRadius();
|
||||||
|
int minX = (int) Math.floor(center.x - radius);
|
||||||
|
int minY = (int) Math.floor(center.y - radius);
|
||||||
|
int minZ = (int) Math.floor(center.z - radius);
|
||||||
|
int maxX = (int) Math.floor(center.x + radius);
|
||||||
|
int maxY = (int) Math.floor(center.y + radius);
|
||||||
|
int maxZ = (int) Math.floor(center.z + radius);
|
||||||
|
var fire = dream
|
||||||
|
? BuiltInRegistries.BLOCK.getOptional(net.minecraft.resources.ResourceLocation.fromNamespaceAndPath(
|
||||||
|
"antarchy", "dream_fire")).orElse(Blocks.FIRE)
|
||||||
|
: Blocks.FIRE;
|
||||||
|
for (BlockPos pos : BlockPos.betweenClosed(minX, minY, minZ, maxX, maxY, maxZ)) {
|
||||||
|
if (pos.distToCenterSqr(center.x, center.y, center.z) > radius * radius || !level.isEmptyBlock(pos)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BlockState state = fire.defaultBlockState();
|
||||||
|
if (state.canSurvive(level, pos)) {
|
||||||
|
level.setBlockAndUpdate(pos, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void impactIce(ServerLevel level, Vec3 center) {
|
private void impactIce(ServerLevel level, Vec3 center) {
|
||||||
DamageSource source = this.damageSources().mobProjectile(this, this.getOwner() instanceof LivingEntity living ? living : null);
|
DamageSource source = this.damageSources().mobProjectile(this, this.getOwner() instanceof LivingEntity living ? living : null);
|
||||||
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, new AABB(center, center).inflate(5.0D),
|
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, new AABB(center, center).inflate(5.0D),
|
||||||
entity -> entity.isAlive() && entity != this.getOwner())) {
|
this::canDamageWithImpact)) {
|
||||||
living.hurt(source, (float) AntarchySettings.kingIceballDamage());
|
living.hurt(source, (float) AntarchySettings.kingIceballDamage());
|
||||||
living.setTicksFrozen(Math.min(living.getTicksRequiredToFreeze() + 80, living.getTicksFrozen() + 180));
|
living.setTicksFrozen(Math.min(living.getTicksRequiredToFreeze() + 80, living.getTicksFrozen() + 180));
|
||||||
living.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.MOVEMENT_SLOWDOWN, 120, 3));
|
living.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.MOVEMENT_SLOWDOWN, 120, 3));
|
||||||
@@ -149,6 +178,14 @@ public class RoyalElementalProjectileEntity extends ThrowableProjectile implemen
|
|||||||
level.sendParticles(ParticleTypes.SNOWFLAKE, center.x, center.y, center.z, 80, 4.0D, 2.0D, 4.0D, 0.08D);
|
level.sendParticles(ParticleTypes.SNOWFLAKE, center.x, center.y, center.z, 80, 4.0D, 2.0D, 4.0D, 0.08D);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean canDamageWithImpact(LivingEntity target) {
|
||||||
|
Entity owner = this.getOwner();
|
||||||
|
if (!target.isAlive() || target == owner) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !(owner instanceof RoyalBossEntity royalBoss) || royalBoss.canDamageWithRoyalAttack(target);
|
||||||
|
}
|
||||||
|
|
||||||
private void coverInIce(ServerLevel level, Vec3 center, double radius, int cap) {
|
private void coverInIce(ServerLevel level, Vec3 center, double radius, int cap) {
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
int minX = (int) Math.floor(center.x - radius);
|
int minX = (int) Math.floor(center.x - radius);
|
||||||
@@ -168,7 +205,15 @@ public class RoyalElementalProjectileEntity extends ThrowableProjectile implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected net.minecraft.core.particles.ParticleOptions getTrailParticle() {
|
protected net.minecraft.core.particles.ParticleOptions getTrailParticle() {
|
||||||
return this.isIceball() ? ParticleTypes.SNOWFLAKE : ParticleTypes.FLAME;
|
if (this.isIceball()) {
|
||||||
|
return ParticleTypes.SNOWFLAKE;
|
||||||
|
}
|
||||||
|
if (this.isDreamFireball()
|
||||||
|
&& BuiltInRegistries.PARTICLE_TYPE.get(net.minecraft.resources.ResourceLocation.fromNamespaceAndPath(
|
||||||
|
"antarchy", "dream_fire_flame")) instanceof net.minecraft.core.particles.ParticleOptions dreamFlame) {
|
||||||
|
return dreamFlame;
|
||||||
|
}
|
||||||
|
return ParticleTypes.FLAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
-1
@@ -22,7 +22,6 @@ import software.bernie.geckolib.animation.RawAnimation;
|
|||||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
public class RoyalIceSpikeEntity extends Entity implements GeoEntity {
|
public class RoyalIceSpikeEntity extends Entity implements GeoEntity {
|
||||||
// The exported asset contains one coordinated animation for all four spike groups.
|
|
||||||
private static final RawAnimation SPIKE_ANIMATION = RawAnimation.begin().thenPlay("animation");
|
private static final RawAnimation SPIKE_ANIMATION = RawAnimation.begin().thenPlay("animation");
|
||||||
private static final String ANIMATION_CONTROLLER = "ice_spike";
|
private static final String ANIMATION_CONTROLLER = "ice_spike";
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
|||||||
+205
-23
@@ -4,6 +4,12 @@ import com.craisinlord.antarchy.config.AntarchySettings;
|
|||||||
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||||
import com.craisinlord.antarchy.content.AntarchyTags;
|
import com.craisinlord.antarchy.content.AntarchyTags;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamController;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamSettings;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamTerrainMode;
|
||||||
|
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
|
||||||
|
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
@@ -20,10 +26,12 @@ import net.minecraft.world.InteractionResult;
|
|||||||
import net.minecraft.world.damagesource.DamageSource;
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
import net.minecraft.world.entity.AgeableMob;
|
import net.minecraft.world.entity.AgeableMob;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityDimensions;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.Mob;
|
import net.minecraft.world.entity.Mob;
|
||||||
import net.minecraft.world.entity.MoverType;
|
import net.minecraft.world.entity.MoverType;
|
||||||
|
import net.minecraft.world.entity.Pose;
|
||||||
import net.minecraft.world.entity.TamableAnimal;
|
import net.minecraft.world.entity.TamableAnimal;
|
||||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
@@ -40,14 +48,18 @@ import net.minecraft.world.entity.ai.goal.target.OwnerHurtTargetGoal;
|
|||||||
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
|
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
|
||||||
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
|
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
|
||||||
import net.minecraft.world.entity.ai.navigation.PathNavigation;
|
import net.minecraft.world.entity.ai.navigation.PathNavigation;
|
||||||
|
import net.minecraft.world.entity.monster.Enemy;
|
||||||
import net.minecraft.world.entity.animal.FlyingAnimal;
|
import net.minecraft.world.entity.animal.FlyingAnimal;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.Items;
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.pathfinder.PathType;
|
import net.minecraft.world.level.pathfinder.PathType;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import software.bernie.geckolib.animatable.GeoEntity;
|
import software.bernie.geckolib.animatable.GeoEntity;
|
||||||
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||||
@@ -73,6 +85,20 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.BOOLEAN);
|
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.BOOLEAN);
|
||||||
private static final EntityDataAccessor<Boolean> SADDLED =
|
private static final EntityDataAccessor<Boolean> SADDLED =
|
||||||
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.BOOLEAN);
|
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.BOOLEAN);
|
||||||
|
private static final EntityDataAccessor<Boolean> BEAM_ACTIVE =
|
||||||
|
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.BOOLEAN);
|
||||||
|
private static final EntityDataAccessor<Integer> BEAM_HEAD =
|
||||||
|
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.INT);
|
||||||
|
private static final EntityDataAccessor<Boolean> HAS_BEAM_END =
|
||||||
|
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.BOOLEAN);
|
||||||
|
private static final EntityDataAccessor<Float> BEAM_END_X =
|
||||||
|
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.FLOAT);
|
||||||
|
private static final EntityDataAccessor<Float> BEAM_END_Y =
|
||||||
|
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.FLOAT);
|
||||||
|
private static final EntityDataAccessor<Float> BEAM_END_Z =
|
||||||
|
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.FLOAT);
|
||||||
|
private static final EntityDataAccessor<Float> GROWTH_PROGRESS =
|
||||||
|
SynchedEntityData.defineId(RoyalMountEntity.class, EntityDataSerializers.FLOAT);
|
||||||
|
|
||||||
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
||||||
private static final RawAnimation QUIRK_ANIM = RawAnimation.begin().thenLoop("quirk");
|
private static final RawAnimation QUIRK_ANIM = RawAnimation.begin().thenLoop("quirk");
|
||||||
@@ -85,7 +111,11 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
|
|
||||||
private static final int ACTION_TICKS = 12;
|
private static final int ACTION_TICKS = 12;
|
||||||
private static final int BITE_HIT_TICK = 6;
|
private static final int BITE_HIT_TICK = 6;
|
||||||
private static final int GROW_TICKS = 24000;
|
private static final int BEAM_WINDUP_TICKS = 24;
|
||||||
|
private static final int BEAM_COOLDOWN_TICKS = 240;
|
||||||
|
private static final int BEAM_DURATION_TICKS = 12;
|
||||||
|
private static final int COMMAND_COOLDOWN_TICKS = 360;
|
||||||
|
private static final int TIME_FIELD_COOLDOWN_TICKS = 260;
|
||||||
|
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
private final MoveControl groundMoveControl;
|
private final MoveControl groundMoveControl;
|
||||||
@@ -100,6 +130,12 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
private int flapSoundTimer;
|
private int flapSoundTimer;
|
||||||
private boolean riderAscendPressed;
|
private boolean riderAscendPressed;
|
||||||
private boolean riderDescendPressed;
|
private boolean riderDescendPressed;
|
||||||
|
private final RoyalBeamController beamController = new RoyalBeamController(this);
|
||||||
|
private int beamWindupTicks;
|
||||||
|
private int beamCooldownTicks;
|
||||||
|
private int beamHead;
|
||||||
|
private int commandCooldownTicks;
|
||||||
|
private int timeFieldCooldownTicks;
|
||||||
|
|
||||||
protected RoyalMountEntity(EntityType<? extends RoyalMountEntity> entityType, Level level) {
|
protected RoyalMountEntity(EntityType<? extends RoyalMountEntity> entityType, Level level) {
|
||||||
super(entityType, level);
|
super(entityType, level);
|
||||||
@@ -167,7 +203,7 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
this.goalSelector.addGoal(1, new SitWhenOrderedToGoal(this) {
|
this.goalSelector.addGoal(1, new SitWhenOrderedToGoal(this) {
|
||||||
@Override
|
@Override
|
||||||
public boolean canUse() {
|
public boolean canUse() {
|
||||||
return !RoyalMountEntity.this.isBaby() && super.canUse();
|
return super.canUse();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.goalSelector.addGoal(2, new RoyalMountSpitGoal(this));
|
this.goalSelector.addGoal(2, new RoyalMountSpitGoal(this));
|
||||||
@@ -182,14 +218,14 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canUse() {
|
public boolean canUse() {
|
||||||
return !RoyalMountEntity.this.isBaby() && !RoyalMountEntity.this.isVehicle() && super.canUse();
|
return !RoyalMountEntity.this.isVehicle() && super.canUse();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.goalSelector.addGoal(4, new RoyalMountFollowOwnerGoal(this));
|
this.goalSelector.addGoal(4, new RoyalMountFollowOwnerGoal(this));
|
||||||
this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 0.8D) {
|
this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 0.8D) {
|
||||||
@Override
|
@Override
|
||||||
public boolean canUse() {
|
public boolean canUse() {
|
||||||
return !RoyalMountEntity.this.isBaby() && !RoyalMountEntity.this.isVehicle()
|
return !RoyalMountEntity.this.isVehicle()
|
||||||
&& !RoyalMountEntity.this.isOrderedToSit() && super.canUse();
|
&& !RoyalMountEntity.this.isOrderedToSit() && super.canUse();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -197,25 +233,25 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this) {
|
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this) {
|
||||||
@Override
|
@Override
|
||||||
public boolean canUse() {
|
public boolean canUse() {
|
||||||
return !RoyalMountEntity.this.isBaby() && super.canUse();
|
return super.canUse();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this) {
|
this.targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this) {
|
||||||
@Override
|
@Override
|
||||||
public boolean canUse() {
|
public boolean canUse() {
|
||||||
return !RoyalMountEntity.this.isBaby() && super.canUse();
|
return super.canUse();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this) {
|
this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this) {
|
||||||
@Override
|
@Override
|
||||||
public boolean canUse() {
|
public boolean canUse() {
|
||||||
return !RoyalMountEntity.this.isBaby() && super.canUse();
|
return super.canUse();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.targetSelector.addGoal(3, new HurtByTargetGoal(this) {
|
this.targetSelector.addGoal(3, new HurtByTargetGoal(this) {
|
||||||
@Override
|
@Override
|
||||||
public boolean canUse() {
|
public boolean canUse() {
|
||||||
return !RoyalMountEntity.this.isBaby() && super.canUse();
|
return super.canUse();
|
||||||
}
|
}
|
||||||
}.setAlertOthers());
|
}.setAlertOthers());
|
||||||
}
|
}
|
||||||
@@ -226,6 +262,13 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
builder.define(ANIM_STATE, ANIM_IDLE);
|
builder.define(ANIM_STATE, ANIM_IDLE);
|
||||||
builder.define(FLYING, false);
|
builder.define(FLYING, false);
|
||||||
builder.define(SADDLED, false);
|
builder.define(SADDLED, false);
|
||||||
|
builder.define(BEAM_ACTIVE, false);
|
||||||
|
builder.define(BEAM_HEAD, -1);
|
||||||
|
builder.define(HAS_BEAM_END, false);
|
||||||
|
builder.define(BEAM_END_X, 0.0F);
|
||||||
|
builder.define(BEAM_END_Y, 0.0F);
|
||||||
|
builder.define(BEAM_END_Z, 0.0F);
|
||||||
|
builder.define(GROWTH_PROGRESS, 0.0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -233,6 +276,10 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
super.addAdditionalSaveData(tag);
|
super.addAdditionalSaveData(tag);
|
||||||
tag.putBoolean("Saddled", this.isSaddled());
|
tag.putBoolean("Saddled", this.isSaddled());
|
||||||
tag.putBoolean("Flying", this.isFlying());
|
tag.putBoolean("Flying", this.isFlying());
|
||||||
|
tag.putInt("BeamCooldown", this.beamCooldownTicks);
|
||||||
|
tag.putInt("CommandCooldown", this.commandCooldownTicks);
|
||||||
|
tag.putInt("TimeFieldCooldown", this.timeFieldCooldownTicks);
|
||||||
|
tag.putFloat("GrowthProgress", this.getGrowthProgress());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -240,12 +287,30 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
super.readAdditionalSaveData(tag);
|
super.readAdditionalSaveData(tag);
|
||||||
this.setSaddled(tag.getBoolean("Saddled"));
|
this.setSaddled(tag.getBoolean("Saddled"));
|
||||||
this.setFlying(tag.getBoolean("Flying"));
|
this.setFlying(tag.getBoolean("Flying"));
|
||||||
|
this.actionTicks = 0;
|
||||||
|
this.actionHit = false;
|
||||||
|
this.spitCooldown = 0;
|
||||||
|
this.beamCooldownTicks = Math.max(0, tag.getInt("BeamCooldown"));
|
||||||
|
this.commandCooldownTicks = Math.max(0, tag.getInt("CommandCooldown"));
|
||||||
|
this.timeFieldCooldownTicks = Math.max(0, tag.getInt("TimeFieldCooldown"));
|
||||||
|
this.setGrowthProgress(tag.contains("GrowthProgress") ? tag.getFloat("GrowthProgress") : 0.0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFlying() {
|
public boolean isFlying() {
|
||||||
return this.entityData.get(FLYING);
|
return this.entityData.get(FLYING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSyncedDataUpdated(EntityDataAccessor<?> key) {
|
||||||
|
super.onSyncedDataUpdated(key);
|
||||||
|
if (FLYING.equals(key) && this.groundMoveControl != null) {
|
||||||
|
boolean flying = this.entityData.get(FLYING);
|
||||||
|
this.moveControl = flying ? this.flyingMoveControl : this.groundMoveControl;
|
||||||
|
this.navigation = flying ? this.flyingNavigation : this.groundNavigation;
|
||||||
|
this.setNoGravity(flying);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setFlying(boolean flying) {
|
public void setFlying(boolean flying) {
|
||||||
if (this.entityData.get(FLYING) != flying) {
|
if (this.entityData.get(FLYING) != flying) {
|
||||||
this.entityData.set(FLYING, flying);
|
this.entityData.set(FLYING, flying);
|
||||||
@@ -274,12 +339,25 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
this.entityData.set(ANIM_STATE, state);
|
this.entityData.set(ANIM_STATE, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getAgeScale() {
|
public float getGrowthScale() {
|
||||||
if (!this.isBaby()) {
|
return 1.0F + 14.0F * this.getGrowthProgress();
|
||||||
return 1.0F;
|
|
||||||
}
|
}
|
||||||
float progress = 1.0F - Mth.clamp(-this.getAge() / (float) GROW_TICKS, 0.0F, 1.0F);
|
|
||||||
return 0.35F + 0.65F * progress;
|
public float getGrowthProgress() {
|
||||||
|
return this.entityData.get(GROWTH_PROGRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGrowthProgress(float progress) {
|
||||||
|
float clamped = Mth.clamp(progress, 0.0F, 1.0F);
|
||||||
|
if (this.getGrowthProgress() != clamped) {
|
||||||
|
this.entityData.set(GROWTH_PROGRESS, clamped);
|
||||||
|
this.refreshDimensions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||||
|
return super.getDefaultDimensions(pose).scale(this.getGrowthScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -297,9 +375,7 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
stack.shrink(1);
|
stack.shrink(1);
|
||||||
}
|
}
|
||||||
this.heal(8.0F);
|
this.heal(8.0F);
|
||||||
if (this.isBaby()) {
|
this.setGrowthProgress(this.getGrowthProgress() + (1.0F - this.getGrowthProgress()) * 0.1F);
|
||||||
this.ageUp((int) (-this.getAge() * 0.1F), true);
|
|
||||||
}
|
|
||||||
if (!this.isTame() && this.random.nextInt(3) == 0) {
|
if (!this.isTame() && this.random.nextInt(3) == 0) {
|
||||||
this.tame(player);
|
this.tame(player);
|
||||||
this.level().broadcastEntityEvent(this, (byte) 7);
|
this.level().broadcastEntityEvent(this, (byte) 7);
|
||||||
@@ -337,7 +413,7 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
return InteractionResult.sidedSuccess(this.level().isClientSide);
|
return InteractionResult.sidedSuccess(this.level().isClientSide);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack.isEmpty() && !this.isBaby() && !player.isPassenger()) {
|
if (stack.isEmpty() && !player.isPassenger()) {
|
||||||
if (!this.level().isClientSide) {
|
if (!this.level().isClientSide) {
|
||||||
this.setOrderedToSit(false);
|
this.setOrderedToSit(false);
|
||||||
this.setInSittingPose(false);
|
this.setInSittingPose(false);
|
||||||
@@ -365,10 +441,6 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
|
||||||
if (this.isBaby()) {
|
|
||||||
this.refreshDimensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.level().isClientSide) {
|
if (this.level().isClientSide) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -376,6 +448,7 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
if (this.spitCooldown > 0) {
|
if (this.spitCooldown > 0) {
|
||||||
this.spitCooldown--;
|
this.spitCooldown--;
|
||||||
}
|
}
|
||||||
|
this.tickRoyalAbilities();
|
||||||
|
|
||||||
if ((this.isFlying() || !this.onGround()) && --this.flapSoundTimer <= 0) {
|
if ((this.isFlying() || !this.onGround()) && --this.flapSoundTimer <= 0) {
|
||||||
this.flapSoundTimer = 24 + this.random.nextInt(12);
|
this.flapSoundTimer = 24 + this.random.nextInt(12);
|
||||||
@@ -406,6 +479,110 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tickRoyalAbilities() {
|
||||||
|
if (this.beamCooldownTicks > 0) this.beamCooldownTicks--;
|
||||||
|
if (this.commandCooldownTicks > 0) this.commandCooldownTicks--;
|
||||||
|
if (this.timeFieldCooldownTicks > 0) this.timeFieldCooldownTicks--;
|
||||||
|
if (this.beamWindupTicks > 0) {
|
||||||
|
this.beamWindupTicks--;
|
||||||
|
if (this.beamWindupTicks == 0) {
|
||||||
|
this.beamController.start(this.beamShootFrom(), this.beamTargetPosition(), BEAM_DURATION_TICKS);
|
||||||
|
this.entityData.set(BEAM_ACTIVE, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.beamController.isFiring()) {
|
||||||
|
this.beamController.tick(this.beamShootFrom(), this.getTarget(), this.beamSettings(), RoyalBeamTerrainMode.NONE, this::setBeamEndPosition);
|
||||||
|
if (!this.beamController.isFiring()) {
|
||||||
|
this.entityData.set(BEAM_ACTIVE, false);
|
||||||
|
this.entityData.set(BEAM_HEAD, -1);
|
||||||
|
this.beamCooldownTicks = BEAM_COOLDOWN_TICKS;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.isOrderedToSit()) return;
|
||||||
|
LivingEntity target = this.getTarget();
|
||||||
|
if (target == null && this.getControllingPassenger() instanceof Player) {
|
||||||
|
target = this.frontTarget();
|
||||||
|
if (target != null) this.setTarget(target);
|
||||||
|
}
|
||||||
|
if (target == null || !target.isAlive() || !this.hasLineOfSight(target)) return;
|
||||||
|
double targetDistance = this.distanceTo(target);
|
||||||
|
if (this.beamCooldownTicks <= 0 && this.beamWindupTicks <= 0 && targetDistance > 7.0D && targetDistance < 28.0D && this.tickCount % 20 == 0) {
|
||||||
|
this.beamHead = (this.beamHead + 1) % 3;
|
||||||
|
this.entityData.set(BEAM_HEAD, this.beamHead);
|
||||||
|
this.beamWindupTicks = BEAM_WINDUP_TICKS;
|
||||||
|
this.setAnimState(this.isFlying() ? ANIM_FLY_SHOOT : ANIM_SHOOT);
|
||||||
|
this.triggerAnim("main", this.isFlying() ? "fly_shoot" : "shoot");
|
||||||
|
this.playSound(this.shootSound(), 0.9F, 0.75F);
|
||||||
|
}
|
||||||
|
if (this instanceof PrinceEntity && this.commandCooldownTicks <= 0 && this.tickCount % 20 == 0) {
|
||||||
|
this.performPrinceCommand();
|
||||||
|
}
|
||||||
|
if (this instanceof PrincessEntity && this.timeFieldCooldownTicks <= 0 && this.tickCount % 20 == 0) {
|
||||||
|
this.performPrincessTimeField(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performPrinceCommand() {
|
||||||
|
if (!(this.level() instanceof ServerLevel level) || RoyalEffectHooks.commandedHolder() == null) return;
|
||||||
|
int applied = 0;
|
||||||
|
for (Mob mob : level.getEntitiesOfClass(Mob.class, this.getBoundingBox().inflate(16.0D), mob ->
|
||||||
|
mob != this && mob.isAlive() && mob instanceof Enemy && !mob.isAlliedTo(this)
|
||||||
|
&& !(mob instanceof RoyalBossEntity) && RoyalEffectEligibility.canApplyCommanded(mob))) {
|
||||||
|
if (applied >= 5) break;
|
||||||
|
if (mob.addEffect(new MobEffectInstance(RoyalEffectHooks.commandedHolder(), 300), this)) {
|
||||||
|
applied++;
|
||||||
|
level.sendParticles(ParticleTypes.HAPPY_VILLAGER, mob.getX(), mob.getY() + mob.getBbHeight(), mob.getZ(), 4, 0.2D, 0.2D, 0.2D, 0.02D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (applied > 0) {
|
||||||
|
this.commandCooldownTicks = COMMAND_COOLDOWN_TICKS;
|
||||||
|
this.playSound(this.shootSound(), 1.0F, 0.65F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performPrincessTimeField(@Nullable LivingEntity target) {
|
||||||
|
if (!(this.level() instanceof ServerLevel level)) return;
|
||||||
|
Vec3 center = target != null && target.isAlive() ? target.position() : this.position();
|
||||||
|
TimeDilationApi.createField(level, center, 8.0D, 0.45D, 100, this.getUUID());
|
||||||
|
this.timeFieldCooldownTicks = TIME_FIELD_COOLDOWN_TICKS;
|
||||||
|
level.sendParticles(ParticleTypes.END_ROD, center.x, center.y + 0.5D, center.z, 28, 1.2D, 0.6D, 1.2D, 0.03D);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RoyalBeamSettings beamSettings() {
|
||||||
|
float damage = this instanceof PrincessEntity ? 10.0F : 12.0F;
|
||||||
|
return new RoyalBeamSettings(28.0D, 0.08D, 4.0D, BEAM_DURATION_TICKS, 6, BEAM_COOLDOWN_TICKS,
|
||||||
|
0.35F, 0.45F, damage, 0.45F, 3, 0.0D, 0.0F, 0.0F, 0, 0.0F, 0.0F, 0.0F, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vec3 beamTargetPosition() {
|
||||||
|
LivingEntity target = this.getTarget();
|
||||||
|
return target != null ? target.getEyePosition() : this.getEyePosition().add(this.getLookAngle().scale(20.0D));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 beamShootFrom() {
|
||||||
|
float scale = this.getGrowthScale();
|
||||||
|
Vec3 forward = Vec3.directionFromRotation(0.0F, this.getYRot());
|
||||||
|
Vec3 side = new Vec3(-forward.z, 0.0D, forward.x);
|
||||||
|
return this.position().add(0.0D, 1.0D * scale, 0.0D).add(forward.scale(1.05D * scale)).add(side.scale((this.getBeamHead() - 1) * 0.72D * scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBeamHead() { return this.entityData.get(BEAM_HEAD); }
|
||||||
|
public boolean isFiringBeam() { return this.entityData.get(BEAM_ACTIVE); }
|
||||||
|
public Vec3 getBeamEndPosition() {
|
||||||
|
return this.entityData.get(HAS_BEAM_END) ? new Vec3(this.entityData.get(BEAM_END_X), this.entityData.get(BEAM_END_Y), this.entityData.get(BEAM_END_Z)) : null;
|
||||||
|
}
|
||||||
|
public RoyalBeamElement getBeamElement() { return RoyalBeamElement.GENERIC; }
|
||||||
|
public RoyalBeamController beamController() { return this.beamController; }
|
||||||
|
private void setBeamEndPosition(@Nullable Vec3 position) {
|
||||||
|
this.entityData.set(HAS_BEAM_END, position != null);
|
||||||
|
if (position != null) {
|
||||||
|
this.entityData.set(BEAM_END_X, (float) position.x);
|
||||||
|
this.entityData.set(BEAM_END_Y, (float) position.y);
|
||||||
|
this.entityData.set(BEAM_END_Z, (float) position.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void tickFlightState() {
|
private void tickFlightState() {
|
||||||
if (this.isVehicle()) {
|
if (this.isVehicle()) {
|
||||||
return;
|
return;
|
||||||
@@ -540,6 +717,11 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
|
|
||||||
public void setRiderAscend(boolean pressed) {
|
public void setRiderAscend(boolean pressed) {
|
||||||
this.riderAscendPressed = pressed;
|
this.riderAscendPressed = pressed;
|
||||||
|
if (pressed && !this.isFlying() && this.getControllingPassenger() != null) {
|
||||||
|
this.setFlying(true);
|
||||||
|
this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.35D, 0.0D));
|
||||||
|
this.hasImpulse = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRiderDescend(boolean pressed) {
|
public void setRiderDescend(boolean pressed) {
|
||||||
@@ -566,8 +748,8 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
|
|||||||
if (!this.hasPassenger(passenger)) {
|
if (!this.hasPassenger(passenger)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
double yOffset = (this.isFlying() ? 1.55D : 1.35D) * this.getAgeScale();
|
double yOffset = (this.isFlying() ? 1.55D : 1.35D) * this.getGrowthScale() - 1.0D;
|
||||||
Vec3 back = this.getLookAngle().scale(-0.35D * this.getAgeScale());
|
Vec3 back = this.getLookAngle().scale(-0.35D * this.getGrowthScale());
|
||||||
moveFunction.accept(passenger, this.getX() + back.x, this.getY() + yOffset, this.getZ() + back.z);
|
moveFunction.accept(passenger, this.getX() + back.x, this.getY() + yOffset, this.getZ() + back.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-1
@@ -1,5 +1,6 @@
|
|||||||
package com.craisinlord.antarchy.content.entity.royal;
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.ai.goal.Goal;
|
import net.minecraft.world.entity.ai.goal.Goal;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
@@ -58,7 +59,7 @@ public class RoyalMountFollowOwnerGoal extends Goal {
|
|||||||
|
|
||||||
double distanceSqr = this.mount.distanceToSqr(this.owner);
|
double distanceSqr = this.mount.distanceToSqr(this.owner);
|
||||||
if (distanceSqr > TELEPORT_DISTANCE * TELEPORT_DISTANCE) {
|
if (distanceSqr > TELEPORT_DISTANCE * TELEPORT_DISTANCE) {
|
||||||
this.mount.teleportTo(this.owner.getX(), this.owner.getY(), this.owner.getZ());
|
this.trySafeTeleport();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,4 +82,29 @@ public class RoyalMountFollowOwnerGoal extends Goal {
|
|||||||
public boolean requiresUpdateEveryTick() {
|
public boolean requiresUpdateEveryTick() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void trySafeTeleport() {
|
||||||
|
Vec3 ownerPosition = this.owner.position();
|
||||||
|
BlockPos ownerBlock = this.owner.blockPosition();
|
||||||
|
for (int radius = 0; radius <= 2; radius++) {
|
||||||
|
for (int dx = -radius; dx <= radius; dx++) {
|
||||||
|
for (int dz = -radius; dz <= radius; dz++) {
|
||||||
|
for (int dy = -1; dy <= 2; dy++) {
|
||||||
|
double x = ownerPosition.x + dx + 0.5D;
|
||||||
|
double y = ownerBlock.getY() + dy;
|
||||||
|
double z = ownerPosition.z + dz + 0.5D;
|
||||||
|
BlockPos floor = BlockPos.containing(x, y - 0.1D, z);
|
||||||
|
var destination = this.mount.getBoundingBox().move(x - this.mount.getX(), y - this.mount.getY(), z - this.mount.getZ());
|
||||||
|
if (!this.mount.level().noCollision(this.mount, destination)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.mount.isFlying() || !this.mount.level().getBlockState(floor).getCollisionShape(this.mount.level(), floor).isEmpty()) {
|
||||||
|
this.mount.teleportTo(x, y, z);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -13,7 +13,7 @@ public class RoyalMountSpitGoal extends Goal {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canUse() {
|
public boolean canUse() {
|
||||||
if (this.mount.isBaby() || this.mount.isVehicle() || this.mount.isOrderedToSit()) {
|
if (this.mount.isVehicle() || this.mount.isOrderedToSit()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LivingEntity target = this.mount.getTarget();
|
LivingEntity target = this.mount.getTarget();
|
||||||
|
|||||||
-1
@@ -8,7 +8,6 @@ import java.util.Map;
|
|||||||
import java.util.function.ToIntFunction;
|
import java.util.function.ToIntFunction;
|
||||||
import net.minecraft.util.RandomSource;
|
import net.minecraft.util.RandomSource;
|
||||||
|
|
||||||
/** Shared server-side arbitration for Royal attack lifecycles. */
|
|
||||||
public final class RoyalAttackScheduler {
|
public final class RoyalAttackScheduler {
|
||||||
public interface Action {
|
public interface Action {
|
||||||
default void onStart() {}
|
default void onStart() {}
|
||||||
|
|||||||
-1
@@ -3,7 +3,6 @@ package com.craisinlord.antarchy.content.entity.royal.attack;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/** Owns persistent per-tick effects started by a Royal attack. */
|
|
||||||
public final class RoyalEffectController {
|
public final class RoyalEffectController {
|
||||||
private record Effect(Runnable tick, Runnable end, int duration, int age) {
|
private record Effect(Runnable tick, Runnable end, int duration, int age) {
|
||||||
private Effect advance() {
|
private Effect advance() {
|
||||||
|
|||||||
+6
-3
@@ -1,5 +1,6 @@
|
|||||||
package com.craisinlord.antarchy.content.entity.royal.beam;
|
package com.craisinlord.antarchy.content.entity.royal.beam;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -34,6 +35,7 @@ public final class RoyalBeamController {
|
|||||||
private int beamAgeTicks;
|
private int beamAgeTicks;
|
||||||
private int trackingDelayTicks;
|
private int trackingDelayTicks;
|
||||||
private int terrainMutationsThisTick;
|
private int terrainMutationsThisTick;
|
||||||
|
private final Set<Integer> damagedThisTick = new HashSet<>();
|
||||||
private static final int ICE_MUTATIONS_PER_TICK = 3;
|
private static final int ICE_MUTATIONS_PER_TICK = 3;
|
||||||
private static final float ICE_IMPACT_RADIUS = 2.0F;
|
private static final float ICE_IMPACT_RADIUS = 2.0F;
|
||||||
|
|
||||||
@@ -137,17 +139,17 @@ public final class RoyalBeamController {
|
|||||||
Vec3 direction = beamEnd.subtract(shootFrom).normalize();
|
Vec3 direction = beamEnd.subtract(shootFrom).normalize();
|
||||||
double distance = shootFrom.distanceTo(beamEnd);
|
double distance = shootFrom.distanceTo(beamEnd);
|
||||||
DamageSource damageSource = this.owner.damageSources().mobAttack(this.owner);
|
DamageSource damageSource = this.owner.damageSources().mobAttack(this.owner);
|
||||||
Set<Integer> damagedThisTick = new HashSet<>();
|
this.damagedThisTick.clear();
|
||||||
boolean pathMutates = terrainMode == RoyalBeamTerrainMode.DESTROY;
|
boolean pathMutates = terrainMode == RoyalBeamTerrainMode.DESTROY;
|
||||||
for (double walked = settings.pathStep(); walked < Math.min(distance, settings.range()); walked += settings.pathStep()) {
|
for (double walked = settings.pathStep(); walked < Math.min(distance, settings.range()); walked += settings.pathStep()) {
|
||||||
Vec3 sample = shootFrom.add(direction.scale(walked));
|
Vec3 sample = shootFrom.add(direction.scale(walked));
|
||||||
hurtEntitiesAround(sample, settings.pathDamageRadius(), settings.damage(), settings.knockback(), damageSource, settings.requireLineOfSightForDamage(), damagedThisTick);
|
hurtEntitiesAround(sample, settings.pathDamageRadius(), settings.damage(), settings.knockback(), damageSource, settings.requireLineOfSightForDamage(), this.damagedThisTick);
|
||||||
if (pathMutates && shouldMutateTerrain(settings, walked)) {
|
if (pathMutates && shouldMutateTerrain(settings, walked)) {
|
||||||
mutateTerrainAround(sample, settings.pathTerrainRadius(), settings, terrainMode);
|
mutateTerrainAround(sample, settings.pathTerrainRadius(), settings, terrainMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hurtEntitiesAround(beamEnd, settings.impactDamageRadius(), settings.damage(), settings.knockback(), damageSource, settings.requireLineOfSightForDamage(), damagedThisTick);
|
hurtEntitiesAround(beamEnd, settings.impactDamageRadius(), settings.damage(), settings.knockback(), damageSource, settings.requireLineOfSightForDamage(), this.damagedThisTick);
|
||||||
|
|
||||||
if (!shouldMutateTerrain(settings, distance)) {
|
if (!shouldMutateTerrain(settings, distance)) {
|
||||||
return;
|
return;
|
||||||
@@ -193,6 +195,7 @@ public final class RoyalBeamController {
|
|||||||
if (living.is(this.owner)
|
if (living.is(this.owner)
|
||||||
|| this.owner.isAlliedTo(living)
|
|| this.owner.isAlliedTo(living)
|
||||||
|| living.getType() == this.owner.getType()
|
|| living.getType() == this.owner.getType()
|
||||||
|
|| this.owner instanceof RoyalBossEntity royalBoss && !royalBoss.canDamageWithRoyalAttack(living)
|
||||||
|| living.distanceToSqr(center) > radius * radius
|
|| living.distanceToSqr(center) > radius * radius
|
||||||
|| damagedThisTick.contains(living.getId())
|
|| damagedThisTick.contains(living.getId())
|
||||||
|| requireLineOfSight && !canEntityBeHurtFrom(center, living)) {
|
|| requireLineOfSight && !canEntityBeHurtFrom(center, living)) {
|
||||||
|
|||||||
+5
-1
@@ -4,5 +4,9 @@ public enum RoyalBeamElement {
|
|||||||
GENERIC,
|
GENERIC,
|
||||||
FIRE,
|
FIRE,
|
||||||
LIGHTNING,
|
LIGHTNING,
|
||||||
ICE
|
ICE,
|
||||||
|
QUEEN_PURPLE,
|
||||||
|
QUEEN_RED,
|
||||||
|
QUEEN_BLACK,
|
||||||
|
DREAM_FIRE
|
||||||
}
|
}
|
||||||
+1
-1
@@ -7,7 +7,7 @@ public final class AdvanceDecree implements RoyalDecree {
|
|||||||
public String translationKey() { return "decree.antarchy.advance"; }
|
public String translationKey() { return "decree.antarchy.advance"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { king.setDecreeRetreatPressure(true); }
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { king.setDecreeRetreatPressure(true); }
|
||||||
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
return target.distanceTo(king) > REQUIRED_RANGE ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
return target.distanceToSqr(king) > REQUIRED_RANGE * REQUIRED_RANGE ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int contextWeight(KingEntity king, LivingEntity target) {
|
public int contextWeight(KingEntity king, LivingEntity target) {
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ public final class ComeNoCloserDecree implements RoyalDecree {
|
|||||||
public String translationKey() { return "decree.antarchy.come_no_closer"; }
|
public String translationKey() { return "decree.antarchy.come_no_closer"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { }
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { }
|
||||||
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
return target.distanceTo(king) <= 16.0D ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
return target.distanceToSqr(king) <= 256.0D ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int contextWeight(KingEntity king, LivingEntity target) {
|
public int contextWeight(KingEntity king, LivingEntity target) {
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ public final class FightMeCowardDecree implements RoyalDecree {
|
|||||||
public String name() { return "FIGHT ME, COWARD!"; }
|
public String name() { return "FIGHT ME, COWARD!"; }
|
||||||
public String translationKey() { return "decree.antarchy.fight_me_coward"; }
|
public String translationKey() { return "decree.antarchy.fight_me_coward"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
if (target.distanceTo(king) > 28.0D) {
|
if (target.distanceToSqr(king) > 784.0D) {
|
||||||
Vec3 pull = king.position().subtract(target.position()).normalize().scale(0.35D);
|
Vec3 pull = king.position().subtract(target.position()).normalize().scale(0.35D);
|
||||||
target.setDeltaMovement(target.getDeltaMovement().add(pull.x, 0.05D, pull.z));
|
target.setDeltaMovement(target.getDeltaMovement().add(pull.x, 0.05D, pull.z));
|
||||||
target.hasImpulse = true;
|
target.hasImpulse = true;
|
||||||
@@ -15,6 +15,6 @@ public final class FightMeCowardDecree implements RoyalDecree {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
return target.distanceTo(king) > 28.0D ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
return target.distanceToSqr(king) > 784.0D ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -7,7 +7,7 @@ public final class KeepYourDistanceDecree implements RoyalDecree {
|
|||||||
public String translationKey() { return "decree.antarchy.keep_your_distance"; }
|
public String translationKey() { return "decree.antarchy.keep_your_distance"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { }
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { }
|
||||||
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
return target.distanceTo(king) <= INNER_RADIUS ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
return target.distanceToSqr(king) <= INNER_RADIUS * INNER_RADIUS ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int contextWeight(KingEntity king, LivingEntity target) {
|
public int contextWeight(KingEntity king, LivingEntity target) {
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ public final class NoRetreatDecree implements RoyalDecree {
|
|||||||
private static final double ALLOWED_RANGE = 26.0D;
|
private static final double ALLOWED_RANGE = 26.0D;
|
||||||
public String translationKey() { return "decree.antarchy.no_retreat"; }
|
public String translationKey() { return "decree.antarchy.no_retreat"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
if (target.distanceTo(king) > ALLOWED_RANGE) {
|
if (target.distanceToSqr(king) > ALLOWED_RANGE * ALLOWED_RANGE) {
|
||||||
king.invokeJudgment(target);
|
king.invokeJudgment(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-11
@@ -2,15 +2,10 @@ package com.craisinlord.antarchy.content.item;
|
|||||||
|
|
||||||
import com.craisinlord.antarchy.content.block.AntimetalScaffoldingBlock;
|
import com.craisinlord.antarchy.content.block.AntimetalScaffoldingBlock;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
import java.util.List;
|
|
||||||
import net.minecraft.ChatFormatting;
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.item.ScaffoldingBlockItem;
|
import net.minecraft.world.item.ScaffoldingBlockItem;
|
||||||
import net.minecraft.world.item.TooltipFlag;
|
|
||||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
@@ -22,12 +17,6 @@ public class AntimetalScaffoldingItem extends ScaffoldingBlockItem {
|
|||||||
super(block, properties);
|
super(block, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
|
||||||
// tooltipComponents.add(Component.translatable("tooltip.antarchy.antimetal_scaffolding").withStyle(ChatFormatting.DARK_AQUA));
|
|
||||||
// super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockPlaceContext updatePlacementContext(BlockPlaceContext context) {
|
public BlockPlaceContext updatePlacementContext(BlockPlaceContext context) {
|
||||||
|
|||||||
+4
-13
@@ -6,9 +6,6 @@ import com.craisinlord.antarchy.content.client.model.ResourceBackedGeoItemModel;
|
|||||||
import com.craisinlord.antarchy.content.client.renderer.AnimatedHeldItemRenderer;
|
import com.craisinlord.antarchy.content.client.renderer.AnimatedHeldItemRenderer;
|
||||||
import com.craisinlord.antarchy.content.entity.vortex.WindVortexEntity;
|
import com.craisinlord.antarchy.content.entity.vortex.WindVortexEntity;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
@@ -46,8 +43,6 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
|||||||
private static final ResourceLocation ANIMATION_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "animations/eye_of_the_storm.animation.json");
|
private static final ResourceLocation ANIMATION_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "animations/eye_of_the_storm.animation.json");
|
||||||
private static final String IDLE_CONTROLLER = "idle_controller";
|
private static final String IDLE_CONTROLLER = "idle_controller";
|
||||||
private static final String IDLE_ANIMATION = "spinning_idle";
|
private static final String IDLE_ANIMATION = "spinning_idle";
|
||||||
private static final Map<UUID, Long> LAST_UPDRAFT_TICK = new ConcurrentHashMap<>();
|
|
||||||
private static final Map<UUID, Long> LAST_SURGE_TICK = new ConcurrentHashMap<>();
|
|
||||||
private static final float SURGE_PROJECTILE_SPEED = 0.65F;
|
private static final float SURGE_PROJECTILE_SPEED = 0.65F;
|
||||||
|
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
@@ -67,12 +62,9 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
|||||||
return InteractionResultHolder.consume(stack);
|
return InteractionResultHolder.consume(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
long now = level.getGameTime();
|
if (player.getCooldowns().isOnCooldown(this)) {
|
||||||
Long last = LAST_UPDRAFT_TICK.get(player.getUUID());
|
|
||||||
if (last != null && now - last < AntarchySettings.eyeOfTheStormUpdraftCooldownTicks()) {
|
|
||||||
return InteractionResultHolder.fail(stack);
|
return InteractionResultHolder.fail(stack);
|
||||||
}
|
}
|
||||||
LAST_UPDRAFT_TICK.put(player.getUUID(), now);
|
|
||||||
|
|
||||||
ServerLevel serverLevel = (ServerLevel) level;
|
ServerLevel serverLevel = (ServerLevel) level;
|
||||||
WindVortexEntity vortex = WindVortexEntity.create(
|
WindVortexEntity vortex = WindVortexEntity.create(
|
||||||
@@ -92,6 +84,7 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
|||||||
player.setDeltaMovement(player.getDeltaMovement().add(0.0D, AntarchySettings.eyeOfTheStormUpdraftLaunchStrength(), 0.0D));
|
player.setDeltaMovement(player.getDeltaMovement().add(0.0D, AntarchySettings.eyeOfTheStormUpdraftLaunchStrength(), 0.0D));
|
||||||
player.hasImpulse = true;
|
player.hasImpulse = true;
|
||||||
player.resetFallDistance();
|
player.resetFallDistance();
|
||||||
|
player.getCooldowns().addCooldown(this, AntarchySettings.eyeOfTheStormUpdraftCooldownTicks());
|
||||||
if (player instanceof ServerPlayer serverPlayer) {
|
if (player instanceof ServerPlayer serverPlayer) {
|
||||||
serverPlayer.connection.send(new ClientboundSetEntityMotionPacket(serverPlayer));
|
serverPlayer.connection.send(new ClientboundSetEntityMotionPacket(serverPlayer));
|
||||||
}
|
}
|
||||||
@@ -109,15 +102,13 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long now = level.getGameTime();
|
if (player.getCooldowns().isOnCooldown(this)) {
|
||||||
Long last = LAST_SURGE_TICK.get(player.getUUID());
|
|
||||||
if (last != null && now - last < AntarchySettings.eyeOfTheStormSurgeCooldownTicks()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LAST_SURGE_TICK.put(player.getUUID(), now);
|
|
||||||
|
|
||||||
Vec3 look = player.getViewVector(1.0F);
|
Vec3 look = player.getViewVector(1.0F);
|
||||||
launchStormVortex(level, player.getEyePosition().add(look), look, player);
|
launchStormVortex(level, player.getEyePosition().add(look), look, player);
|
||||||
|
player.getCooldowns().addCooldown(this, AntarchySettings.eyeOfTheStormSurgeCooldownTicks());
|
||||||
|
|
||||||
player.awardStat(Stats.ITEM_USED.get(this));
|
player.awardStat(Stats.ITEM_USED.get(this));
|
||||||
stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND);
|
stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND);
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
package com.craisinlord.antarchy.content.item;
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import net.minecraft.ChatFormatting;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.world.item.BlockItem;
|
import net.minecraft.world.item.BlockItem;
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.item.TooltipFlag;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
public class MucusBlockItem extends BlockItem {
|
public class MucusBlockItem extends BlockItem {
|
||||||
@@ -15,9 +8,4 @@ public class MucusBlockItem extends BlockItem {
|
|||||||
super(block, properties);
|
super(block, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
|
||||||
// tooltipComponents.add(Component.translatable("tooltip.antarchy.mucus_slippery").withStyle(ChatFormatting.DARK_AQUA));
|
|
||||||
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
-11
@@ -1,6 +1,5 @@
|
|||||||
package com.craisinlord.antarchy.content.item;
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.Antarchy;
|
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
import com.craisinlord.antarchy.content.item.royal.RoyalGearHelper;
|
import com.craisinlord.antarchy.content.item.royal.RoyalGearHelper;
|
||||||
@@ -143,18 +142,8 @@ public class RoyalAssailantArmorItem extends ArmorItem {
|
|||||||
}
|
}
|
||||||
MobEffectInstance existing = player.getEffect(AntarchyObjects.INVERTED_EFFECT.get());
|
MobEffectInstance existing = player.getEffect(AntarchyObjects.INVERTED_EFFECT.get());
|
||||||
if (existing != null && existing.isInfiniteDuration()) {
|
if (existing != null && existing.isInfiniteDuration()) {
|
||||||
Antarchy.LOGGER.info(
|
|
||||||
"[antarchy-gravity] royal chestplate toggling inversion off player={} uuid={} pos=({}, {}, {}) dim={} existingDuration={} gameTime={}",
|
|
||||||
player.getGameProfile().getName(), player.getUUID(), player.getX(), player.getY(), player.getZ(),
|
|
||||||
player.level().dimension().location(), existing.getDuration(), player.level().getGameTime()
|
|
||||||
);
|
|
||||||
player.removeEffect(AntarchyObjects.INVERTED_EFFECT.get());
|
player.removeEffect(AntarchyObjects.INVERTED_EFFECT.get());
|
||||||
} else {
|
} else {
|
||||||
Antarchy.LOGGER.info(
|
|
||||||
"[antarchy-gravity] royal chestplate toggling inversion on player={} uuid={} pos=({}, {}, {}) dim={} existingDuration={} gameTime={}",
|
|
||||||
player.getGameProfile().getName(), player.getUUID(), player.getX(), player.getY(), player.getZ(),
|
|
||||||
player.level().dimension().location(), existing != null ? existing.getDuration() : -1, player.level().getGameTime()
|
|
||||||
);
|
|
||||||
player.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), -1, 0, false, false, true));
|
player.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), -1, 0, false, false, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
package com.craisinlord.antarchy.content.item;
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity;
|
import com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity;
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
@@ -81,7 +81,7 @@ public class RoyalAssailantBattleAxeItem extends AxeItem {
|
|||||||
return InteractionResultHolder.sidedSuccess(stack, true);
|
return InteractionResultHolder.sidedSuccess(stack, true);
|
||||||
}
|
}
|
||||||
if (level instanceof ServerLevel serverLevel) {
|
if (level instanceof ServerLevel serverLevel) {
|
||||||
RoyalBlackHoleEntity blackHole = RoyalBlackHoleEntity.createAssailant(
|
RoyalAssailantBlackHoleEntity blackHole = RoyalAssailantBlackHoleEntity.create(
|
||||||
serverLevel,
|
serverLevel,
|
||||||
player.position().add(player.getLookAngle().normalize().scale(2.0D)).add(0.0D, 2.0D, 0.0D),
|
player.position().add(player.getLookAngle().normalize().scale(2.0D)).add(0.0D, 2.0D, 0.0D),
|
||||||
player.getUUID());
|
player.getUUID());
|
||||||
|
|||||||
-14
@@ -13,15 +13,6 @@ import net.minecraft.util.Mth;
|
|||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
/**
|
|
||||||
* Server-authoritative swing physics for the worm hook: pulls the holding player taut against
|
|
||||||
* a rope anchored to a stuck {@link WormHookProjectileEntity}, wrapping the rope around block
|
|
||||||
* corners via {@link WormHookRope} so the swing radius shortens realistically when the player
|
|
||||||
* swings around an obstacle.
|
|
||||||
*
|
|
||||||
* A tether entry is created the moment the hook is thrown (so the rope can be rendered following
|
|
||||||
* the flying projectile) and only gains real swing physics once the hook sticks into a block.
|
|
||||||
*/
|
|
||||||
public final class WormHookTetherManager {
|
public final class WormHookTetherManager {
|
||||||
private static final double MIN_LEN = 2.0D;
|
private static final double MIN_LEN = 2.0D;
|
||||||
private static final double REEL_SPEED = 0.12D;
|
private static final double REEL_SPEED = 0.12D;
|
||||||
@@ -51,14 +42,12 @@ public final class WormHookTetherManager {
|
|||||||
return hook instanceof WormHookProjectileEntity wormHook ? wormHook : null;
|
return hook instanceof WormHookProjectileEntity wormHook ? wormHook : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Registers the hook the moment it's thrown, purely so the rope can be rendered following it. */
|
|
||||||
public static void launch(ServerPlayer player, WormHookProjectileEntity hook) {
|
public static void launch(ServerPlayer player, WormHookProjectileEntity hook) {
|
||||||
clear(player);
|
clear(player);
|
||||||
TETHERS.put(player.getUUID(), new TetherState(hook.getId()));
|
TETHERS.put(player.getUUID(), new TetherState(hook.getId()));
|
||||||
WormHookTetherSync.send(player, hook.getId());
|
WormHookTetherSync.send(player, hook.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called once the hook sticks into a block; turns the cosmetic tether into real swing physics. */
|
|
||||||
public static boolean attach(ServerPlayer player, WormHookProjectileEntity hook) {
|
public static boolean attach(ServerPlayer player, WormHookProjectileEntity hook) {
|
||||||
TetherState state = TETHERS.get(player.getUUID());
|
TetherState state = TETHERS.get(player.getUUID());
|
||||||
if (state == null || state.hookEntityId != hook.getId()) {
|
if (state == null || state.hookEntityId != hook.getId()) {
|
||||||
@@ -108,7 +97,6 @@ public final class WormHookTetherManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.rope == null) {
|
if (state.rope == null) {
|
||||||
// Hook is still flying; nothing to simulate yet, just tracking it for the render sync.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,8 +123,6 @@ public final class WormHookTetherManager {
|
|||||||
|
|
||||||
Vec3 towardPivot = toPlayer.scale(1.0D / dist);
|
Vec3 towardPivot = toPlayer.scale(1.0D / dist);
|
||||||
|
|
||||||
// Sneaking actively winds the player in toward the anchor, not just shortening
|
|
||||||
// the max length (which alone has no effect until the rope goes taut).
|
|
||||||
if (reeling && dist > MIN_LEN) {
|
if (reeling && dist > MIN_LEN) {
|
||||||
Vec3 pull = towardPivot.scale(-REEL_PULL_STRENGTH);
|
Vec3 pull = towardPivot.scale(-REEL_PULL_STRENGTH);
|
||||||
Vec3 reelMotion = player.getDeltaMovement().add(pull);
|
Vec3 reelMotion = player.getDeltaMovement().add(pull);
|
||||||
|
|||||||
+16
-6
@@ -63,7 +63,7 @@ public final class PermanentPortalTeleporter {
|
|||||||
return active.center();
|
return active.center();
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 safe = findSafeArrivalPosition(entity, destination, preferredPos);
|
Vec3 safe = findSafeArrivalPosition(entity, destination, preferredPos, type);
|
||||||
if (safe != null) {
|
if (safe != null) {
|
||||||
PermanentPortalShape nearbyActive = findActiveNearby(destination, BlockPos.containing(safe), type);
|
PermanentPortalShape nearbyActive = findActiveNearby(destination, BlockPos.containing(safe), type);
|
||||||
if (nearbyActive != null) {
|
if (nearbyActive != null) {
|
||||||
@@ -77,7 +77,11 @@ public final class PermanentPortalTeleporter {
|
|||||||
return createFallbackPortal(destination, BlockPos.containing(safe), type);
|
return createFallbackPortal(destination, BlockPos.containing(safe), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return createFallbackPortal(destination, preferredPos, type);
|
BlockPos fallbackPos = preferredPos;
|
||||||
|
if (type == PermanentPortalType.ELYTHIA && destination.hasChunkAt(preferredPos)) {
|
||||||
|
fallbackPos = destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, preferredPos);
|
||||||
|
}
|
||||||
|
return createFallbackPortal(destination, fallbackPos, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -108,14 +112,16 @@ public final class PermanentPortalTeleporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static Vec3 findSafeArrivalPosition(Entity entity, ServerLevel destination, BlockPos preferredPos) {
|
private static Vec3 findSafeArrivalPosition(Entity entity, ServerLevel destination, BlockPos preferredPos, PermanentPortalType type) {
|
||||||
int[] yRange = getDimensionYRange(destination);
|
int[] yRange = getDimensionYRange(destination, type);
|
||||||
if (yRange != null) {
|
if (yRange != null) {
|
||||||
return findSafeArrivalPositionInYRange(entity, destination, preferredPos, yRange[0], yRange[1]);
|
return findSafeArrivalPositionInYRange(entity, destination, preferredPos, yRange[0], yRange[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<BlockPos> candidates = new LinkedHashSet<>();
|
Set<BlockPos> candidates = new LinkedHashSet<>();
|
||||||
|
if (type != PermanentPortalType.ELYTHIA) {
|
||||||
addCandidate(candidates, preferredPos);
|
addCandidate(candidates, preferredPos);
|
||||||
|
}
|
||||||
|
|
||||||
for (int radius = 0; radius <= SEARCH_RADIUS; radius++) {
|
for (int radius = 0; radius <= SEARCH_RADIUS; radius++) {
|
||||||
for (int xOff = -radius; xOff <= radius; xOff++) {
|
for (int xOff = -radius; xOff <= radius; xOff++) {
|
||||||
@@ -139,6 +145,10 @@ public final class PermanentPortalTeleporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == PermanentPortalType.ELYTHIA) {
|
||||||
|
addCandidate(candidates, preferredPos);
|
||||||
|
}
|
||||||
|
|
||||||
for (BlockPos candidate : candidates) {
|
for (BlockPos candidate : candidates) {
|
||||||
Vec3 safe = tryFindSafePosition(entity, destination, candidate);
|
Vec3 safe = tryFindSafePosition(entity, destination, candidate);
|
||||||
if (safe != null) {
|
if (safe != null) {
|
||||||
@@ -277,12 +287,12 @@ public final class PermanentPortalTeleporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static int[] getDimensionYRange(ServerLevel destination) {
|
private static int[] getDimensionYRange(ServerLevel destination, PermanentPortalType type) {
|
||||||
ResourceKey<Level> dim = destination.dimension();
|
ResourceKey<Level> dim = destination.dimension();
|
||||||
if (dim == AntarchySettings.termiteDestinationDimension()) {
|
if (dim == AntarchySettings.termiteDestinationDimension()) {
|
||||||
return new int[]{100, 200};
|
return new int[]{100, 200};
|
||||||
}
|
}
|
||||||
if (dim == AntarchySettings.brownAntDestinationDimension()) {
|
if (type != PermanentPortalType.ELYTHIA && dim == AntarchySettings.brownAntDestinationDimension()) {
|
||||||
return new int[]{75, 120};
|
return new int[]{75, 120};
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ public final class TimeDilationApi {
|
|||||||
SYNCED_CLIENT_RATES.put(entityUuid, clampedRate);
|
SYNCED_CLIENT_RATES.put(entityUuid, clampedRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Clears both the authoritative entity state and any client-side UUID cache. */
|
|
||||||
public static void clearRate(Entity entity) {
|
public static void clearRate(Entity entity) {
|
||||||
if (entity instanceof TimeDilationEntityAccess access) {
|
if (entity instanceof TimeDilationEntityAccess access) {
|
||||||
boolean wasDilated = Math.abs(access.antarchy$getTimeDilationRate() - TimeDilationMath.NORMAL_RATE) > 0.001D;
|
boolean wasDilated = Math.abs(access.antarchy$getTimeDilationRate() - TimeDilationMath.NORMAL_RATE) > 0.001D;
|
||||||
|
|||||||
+40
@@ -1,6 +1,10 @@
|
|||||||
package com.craisinlord.antarchy.content.time;
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
|
import com.craisinlord.antarchy.content.AntarchyTags;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.QueenEntity;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
@@ -25,6 +29,8 @@ public class TimeDilationFieldEntity extends Entity {
|
|||||||
private int durationTicks = -1;
|
private int durationTicks = -1;
|
||||||
private int age;
|
private int age;
|
||||||
private UUID ownerId;
|
private UUID ownerId;
|
||||||
|
private UUID anchorId;
|
||||||
|
private int missingAnchorTicks;
|
||||||
private boolean visual = true;
|
private boolean visual = true;
|
||||||
|
|
||||||
public TimeDilationFieldEntity(EntityType<? extends TimeDilationFieldEntity> entityType, Level level) {
|
public TimeDilationFieldEntity(EntityType<? extends TimeDilationFieldEntity> entityType, Level level) {
|
||||||
@@ -56,6 +62,23 @@ public class TimeDilationFieldEntity extends Entity {
|
|||||||
return this.ownerId != null && entity != null && this.ownerId.equals(entity.getUUID());
|
return this.ownerId != null && entity != null && this.ownerId.equals(entity.getUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void attachTo(Entity anchor) {
|
||||||
|
this.anchorId = anchor == null ? null : anchor.getUUID();
|
||||||
|
this.missingAnchorTicks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean affects(Entity entity) {
|
||||||
|
if (entity instanceof RoyalBlackHoleEntity || this.isOwnedBy(entity)
|
||||||
|
|| this.anchorId != null && this.anchorId.equals(entity.getUUID())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.ownerId != null && this.level() instanceof ServerLevel level
|
||||||
|
&& level.getEntity(this.ownerId) instanceof QueenEntity) {
|
||||||
|
return !entity.getType().is(AntarchyTags.Entities.QUEEN_DOES_NOT_ATTACK);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isVisual() {
|
public boolean isVisual() {
|
||||||
return this.visual;
|
return this.visual;
|
||||||
}
|
}
|
||||||
@@ -72,6 +95,19 @@ public class TimeDilationFieldEntity extends Entity {
|
|||||||
if (this.level().isClientSide) {
|
if (this.level().isClientSide) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.anchorId != null && this.level() instanceof ServerLevel level) {
|
||||||
|
Entity anchor = level.getEntity(this.anchorId);
|
||||||
|
if (anchor != null && anchor.isAlive()) {
|
||||||
|
Vec3 center = anchor instanceof RoyalBlackHoleEntity blackHole
|
||||||
|
? blackHole.effectCenter()
|
||||||
|
: anchor.position();
|
||||||
|
this.setPos(center.x, center.y, center.z);
|
||||||
|
this.missingAnchorTicks = 0;
|
||||||
|
} else if (++this.missingAnchorTicks > 20) {
|
||||||
|
this.discard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.age++;
|
this.age++;
|
||||||
if (this.durationTicks >= 0 && this.age >= this.durationTicks) {
|
if (this.durationTicks >= 0 && this.age >= this.durationTicks) {
|
||||||
this.discard();
|
this.discard();
|
||||||
@@ -127,6 +163,7 @@ public class TimeDilationFieldEntity extends Entity {
|
|||||||
this.durationTicks = tag.contains(DURATION_KEY) ? tag.getInt(DURATION_KEY) : -1;
|
this.durationTicks = tag.contains(DURATION_KEY) ? tag.getInt(DURATION_KEY) : -1;
|
||||||
this.age = tag.getInt(AGE_KEY);
|
this.age = tag.getInt(AGE_KEY);
|
||||||
this.ownerId = tag.hasUUID("OwnerUuid") ? tag.getUUID("OwnerUuid") : null;
|
this.ownerId = tag.hasUUID("OwnerUuid") ? tag.getUUID("OwnerUuid") : null;
|
||||||
|
this.anchorId = tag.hasUUID("AnchorUuid") ? tag.getUUID("AnchorUuid") : null;
|
||||||
this.visual = !tag.contains("Visual") || tag.getBoolean("Visual");
|
this.visual = !tag.contains("Visual") || tag.getBoolean("Visual");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,6 +176,9 @@ public class TimeDilationFieldEntity extends Entity {
|
|||||||
if (this.ownerId != null) {
|
if (this.ownerId != null) {
|
||||||
tag.putUUID("OwnerUuid", this.ownerId);
|
tag.putUUID("OwnerUuid", this.ownerId);
|
||||||
}
|
}
|
||||||
|
if (this.anchorId != null) {
|
||||||
|
tag.putUUID("AnchorUuid", this.anchorId);
|
||||||
|
}
|
||||||
tag.putBoolean("Visual", this.visual);
|
tag.putBoolean("Visual", this.visual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -32,7 +32,7 @@ public final class TimeDilationFieldSampler {
|
|||||||
public static double sample(List<TimeDilationFieldEntity> fields, Entity entity) {
|
public static double sample(List<TimeDilationFieldEntity> fields, Entity entity) {
|
||||||
double combinedRate = TimeDilationMath.NORMAL_RATE;
|
double combinedRate = TimeDilationMath.NORMAL_RATE;
|
||||||
for (TimeDilationFieldEntity field : fields) {
|
for (TimeDilationFieldEntity field : fields) {
|
||||||
if (field.isOwnedBy(entity)) {
|
if (!field.affects(entity)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Vec3 center = field.position();
|
Vec3 center = field.position();
|
||||||
|
|||||||
+68
-7
@@ -1,7 +1,12 @@
|
|||||||
package com.craisinlord.antarchy.content.time;
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
@@ -9,33 +14,57 @@ import net.minecraft.world.entity.Entity;
|
|||||||
import net.minecraft.world.entity.projectile.Projectile;
|
import net.minecraft.world.entity.projectile.Projectile;
|
||||||
import com.craisinlord.antarchy.content.effect.DilatedMobEffect;
|
import com.craisinlord.antarchy.content.effect.DilatedMobEffect;
|
||||||
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
|
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
|
||||||
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
|
|
||||||
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
|
|
||||||
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
|
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
|
||||||
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
||||||
|
|
||||||
public final class TimeDilationManager {
|
public final class TimeDilationManager {
|
||||||
|
private static final Map<ServerLevel, TrackingState> TRACKING = new WeakHashMap<>();
|
||||||
|
|
||||||
private TimeDilationManager() {
|
private TimeDilationManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void tickServer(MinecraftServer server) {
|
public static void tickServer(MinecraftServer server) {
|
||||||
for (ServerLevel level : server.getAllLevels()) {
|
for (ServerLevel level : server.getAllLevels()) {
|
||||||
List<TimeDilationFieldEntity> fields = collectFields(level);
|
List<TimeDilationFieldEntity> fields = collectFields(level);
|
||||||
syncFieldSnapshots(level, fields);
|
TrackingState tracking = TRACKING.computeIfAbsent(level, ignored -> new TrackingState());
|
||||||
updateEntities(level, fields);
|
discoverFieldEntities(level, fields, tracking);
|
||||||
|
syncFieldSnapshots(level, fields, tracking);
|
||||||
|
updateEntities(level, fields, tracking);
|
||||||
|
if (fields.isEmpty() && tracking.entities.isEmpty()) {
|
||||||
|
TRACKING.remove(level);
|
||||||
|
}
|
||||||
if (!fields.isEmpty()) {
|
if (!fields.isEmpty()) {
|
||||||
TimeDilationParticles.spawnFieldBorders(level, fields.stream().filter(TimeDilationFieldEntity::isVisual).toList());
|
TimeDilationParticles.spawnFieldBorders(level, fields.stream().filter(TimeDilationFieldEntity::isVisual).toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void syncFieldSnapshots(ServerLevel level, List<TimeDilationFieldEntity> fields) {
|
public static void trackPotentiallyAffected(Entity entity) {
|
||||||
|
if (!(entity.level() instanceof ServerLevel level) || entity instanceof TimeDilationFieldEntity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (entity instanceof TimeDilationEntityAccess access
|
||||||
|
&& Math.abs(access.antarchy$getTimeDilationRate() - TimeDilationMath.NORMAL_RATE) < 0.001D
|
||||||
|
&& Math.abs(access.antarchy$getInheritedTimeDilationRate() - TimeDilationMath.NORMAL_RATE) < 0.001D
|
||||||
|
&& (!(entity instanceof net.minecraft.world.entity.LivingEntity living)
|
||||||
|
|| ((RoyalEffectHooks.dilatedHolder() == null || !living.hasEffect(RoyalEffectHooks.dilatedHolder()))
|
||||||
|
&& (RoyalEffectHooks.contractedHolder() == null || !living.hasEffect(RoyalEffectHooks.contractedHolder()))))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TRACKING.computeIfAbsent(level, ignored -> new TrackingState()).entities.add(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void syncFieldSnapshots(ServerLevel level, List<TimeDilationFieldEntity> fields, TrackingState tracking) {
|
||||||
List<TimeDilationFieldSnapshot> snapshots = fields.stream()
|
List<TimeDilationFieldSnapshot> snapshots = fields.stream()
|
||||||
.map(field -> new TimeDilationFieldSnapshot(
|
.map(field -> new TimeDilationFieldSnapshot(
|
||||||
field.getX(), field.getY(), field.getZ(), field.fieldRadius(), field.fieldRate(),
|
field.getX(), field.getY(), field.getZ(), field.fieldRadius(), field.fieldRate(),
|
||||||
field.fieldAge(), field.fieldDurationTicks()))
|
field.fieldAge(), field.fieldDurationTicks()))
|
||||||
.limit(128)
|
.limit(128)
|
||||||
.toList();
|
.toList();
|
||||||
|
if (level.getGameTime() % 4L != 0L && snapshots.size() == tracking.lastSnapshots.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tracking.lastSnapshots = snapshots;
|
||||||
for (ServerPlayer player : level.players()) {
|
for (ServerPlayer player : level.players()) {
|
||||||
TimeDilationApi.syncFields(player, snapshots);
|
TimeDilationApi.syncFields(player, snapshots);
|
||||||
}
|
}
|
||||||
@@ -51,8 +80,23 @@ public final class TimeDilationManager {
|
|||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void updateEntities(ServerLevel level, List<TimeDilationFieldEntity> fields) {
|
private static void discoverFieldEntities(ServerLevel level, List<TimeDilationFieldEntity> fields, TrackingState tracking) {
|
||||||
for (Entity entity : level.getAllEntities()) {
|
for (TimeDilationFieldEntity field : fields) {
|
||||||
|
double radius = field.fieldRadius();
|
||||||
|
var center = field.position();
|
||||||
|
var area = new net.minecraft.world.phys.AABB(
|
||||||
|
center.x - radius, center.y - radius, center.z - radius,
|
||||||
|
center.x + radius, center.y + radius, center.z + radius);
|
||||||
|
tracking.entities.addAll(level.getEntities(field, area,
|
||||||
|
entity -> entity.isAlive() && !(entity instanceof TimeDilationFieldEntity)
|
||||||
|
&& entity instanceof TimeDilationEntityAccess));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateEntities(ServerLevel level, List<TimeDilationFieldEntity> fields, TrackingState tracking) {
|
||||||
|
var iterator = tracking.entities.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Entity entity = iterator.next();
|
||||||
if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) {
|
if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -62,6 +106,7 @@ public final class TimeDilationManager {
|
|||||||
living.removeEffect(RoyalEffectHooks.dilatedHolder());
|
living.removeEffect(RoyalEffectHooks.dilatedHolder());
|
||||||
}
|
}
|
||||||
TimeDilationApi.clearRate(entity);
|
TimeDilationApi.clearRate(entity);
|
||||||
|
iterator.remove();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
double previousRate = access.antarchy$getTimeDilationRate();
|
double previousRate = access.antarchy$getTimeDilationRate();
|
||||||
@@ -116,7 +161,23 @@ public final class TimeDilationManager {
|
|||||||
if (Math.abs(previousRate - rate) > 0.001D) {
|
if (Math.abs(previousRate - rate) > 0.001D) {
|
||||||
TimeDilationApi.syncEntityRate(entity, rate);
|
TimeDilationApi.syncEntityRate(entity, rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean hasDilationEffect = entity instanceof net.minecraft.world.entity.LivingEntity living
|
||||||
|
&& ((RoyalEffectHooks.dilatedHolder() != null && living.hasEffect(RoyalEffectHooks.dilatedHolder()))
|
||||||
|
|| (RoyalEffectHooks.contractedHolder() != null && living.hasEffect(RoyalEffectHooks.contractedHolder())));
|
||||||
|
boolean hasInheritedRate = Math.abs(access.antarchy$getInheritedTimeDilationRate() - TimeDilationMath.NORMAL_RATE) >= 0.001D;
|
||||||
|
boolean hasActiveRate = Math.abs(access.antarchy$getTimeDilationRate() - TimeDilationMath.NORMAL_RATE) >= 0.001D;
|
||||||
|
if (!hasDilationEffect && !hasInheritedRate && !hasActiveRate
|
||||||
|
&& Math.abs(targetRate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||||
|
iterator.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tracking.entities.removeIf(entity -> !entity.isAlive() || entity.isRemoved());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class TrackingState {
|
||||||
|
private final Set<Entity> entities = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||||
|
private List<TimeDilationFieldSnapshot> lastSnapshots = List.of();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
-1
@@ -18,7 +18,6 @@ public final class TimeDilationMath {
|
|||||||
return Math.max(MIN_RATE, Math.min(MAX_RATE, rate));
|
return Math.max(MIN_RATE, Math.min(MAX_RATE, rate));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Moves an entity's effective rate toward a new effect/field target without a hard step. */
|
|
||||||
public static double transitionRate(double currentRate, double targetRate) {
|
public static double transitionRate(double currentRate, double targetRate) {
|
||||||
double current = clampRate(currentRate);
|
double current = clampRate(currentRate);
|
||||||
double target = clampRate(targetRate);
|
double target = clampRate(targetRate);
|
||||||
|
|||||||
+140
@@ -9,8 +9,10 @@ import com.mojang.serialization.Codec;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@@ -33,6 +35,13 @@ import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
||||||
|
private static final ThreadLocal<TreePlacement> ACTIVE_PLACEMENT = new ThreadLocal<>();
|
||||||
|
|
||||||
|
private static final class TreePlacement {
|
||||||
|
private final Set<BlockPos> logPositions = new LinkedHashSet<>();
|
||||||
|
private final Set<BlockPos> leafPositions = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
public OuranwoodTreeFeature(Codec<OuranwoodTreeConfiguration> codec) {
|
public OuranwoodTreeFeature(Codec<OuranwoodTreeConfiguration> codec) {
|
||||||
super(codec);
|
super(codec);
|
||||||
}
|
}
|
||||||
@@ -44,6 +53,9 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
|||||||
OuranwoodTreeConfiguration config = context.config();
|
OuranwoodTreeConfiguration config = context.config();
|
||||||
RandomSource random = context.random();
|
RandomSource random = context.random();
|
||||||
|
|
||||||
|
TreePlacement placement = new TreePlacement();
|
||||||
|
ACTIVE_PLACEMENT.set(placement);
|
||||||
|
try {
|
||||||
if (!canGrowOn(level, origin.below())) {
|
if (!canGrowOn(level, origin.below())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -87,6 +99,9 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
|||||||
this.placeFlyingSquirrelNest(level, origin, config, random, trunkRadius, height);
|
this.placeFlyingSquirrelNest(level, origin, config, random, trunkRadius, height);
|
||||||
this.placeCaterpillarChrysalis(level, origin, config, random, canopyCenter, canopyRadius, canopyDepth);
|
this.placeCaterpillarChrysalis(level, origin, config, random, canopyCenter, canopyRadius, canopyDepth);
|
||||||
return true;
|
return true;
|
||||||
|
} finally {
|
||||||
|
ACTIVE_PLACEMENT.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BlockPos resolveCanopyCenter(BlockPos origin, int height, int canopyDepth) {
|
protected BlockPos resolveCanopyCenter(BlockPos origin, int height, int canopyDepth) {
|
||||||
@@ -1044,6 +1059,28 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void pruneExposedTopLogs(WorldGenLevel level, BlockPos origin, BlockPos canopyCenter, OuranwoodTreeConfiguration config, RandomSource random, int trunkRadius, int canopyRadius, int canopyDepth, int height) {
|
protected void pruneExposedTopLogs(WorldGenLevel level, BlockPos origin, BlockPos canopyCenter, OuranwoodTreeConfiguration config, RandomSource random, int trunkRadius, int canopyRadius, int canopyDepth, int height) {
|
||||||
|
TreePlacement placement = ACTIVE_PLACEMENT.get();
|
||||||
|
if (placement != null) {
|
||||||
|
for (BlockPos pos : placement.logPositions) {
|
||||||
|
if (this.isWithinTrunkCore(origin, pos, trunkRadius, canopyCenter.getY())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BlockState state = level.getBlockState(pos);
|
||||||
|
if (!state.is(BlockTags.LOGS)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int leafNeighbors = this.countLeafNeighbors(level, pos);
|
||||||
|
int openFaces = this.countOpenFaces(level, pos);
|
||||||
|
boolean topExposed = level.getBlockState(pos.above()).isAir();
|
||||||
|
boolean lowerCanopyStray = pos.getY() <= canopyCenter.getY()
|
||||||
|
&& leafNeighbors >= 3
|
||||||
|
&& openFaces >= 2;
|
||||||
|
if ((topExposed && leafNeighbors >= 1) || lowerCanopyStray) {
|
||||||
|
this.setLeaf(level, pos, config, random);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
int horizontalRadius = canopyRadius + 6;
|
int horizontalRadius = canopyRadius + 6;
|
||||||
int minY = canopyCenter.getY() - Math.max(4, canopyDepth / 2 + 1);
|
int minY = canopyCenter.getY() - Math.max(4, canopyDepth / 2 + 1);
|
||||||
int maxY = origin.getY() + height + canopyDepth + 6;
|
int maxY = origin.getY() + height + canopyDepth + 6;
|
||||||
@@ -1077,6 +1114,23 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void coverExposedBranchSides(WorldGenLevel level, BlockPos origin, BlockPos canopyCenter, OuranwoodTreeConfiguration config, RandomSource random, int trunkRadius, int canopyRadius, int canopyDepth, int height) {
|
protected void coverExposedBranchSides(WorldGenLevel level, BlockPos origin, BlockPos canopyCenter, OuranwoodTreeConfiguration config, RandomSource random, int trunkRadius, int canopyRadius, int canopyDepth, int height) {
|
||||||
|
TreePlacement placement = ACTIVE_PLACEMENT.get();
|
||||||
|
if (placement != null) {
|
||||||
|
for (BlockPos pos : placement.logPositions) {
|
||||||
|
if (!level.getBlockState(pos).is(BlockTags.LOGS)
|
||||||
|
|| this.isWithinTrunkCore(origin, pos, trunkRadius, canopyCenter.getY())
|
||||||
|
|| this.countLeafNeighbors(level, pos) < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||||
|
BlockPos sidePos = pos.relative(direction);
|
||||||
|
if (level.getBlockState(sidePos).isAir() && this.canWrapBranchSide(level, pos, direction)) {
|
||||||
|
this.tryPlaceLeaf(level, sidePos, config, random);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
int horizontalRadius = canopyRadius + 6;
|
int horizontalRadius = canopyRadius + 6;
|
||||||
int minY = Math.max(origin.getY() + Math.max(4, height / 4), canopyCenter.getY() - canopyDepth - 3);
|
int minY = Math.max(origin.getY() + Math.max(4, height / 4), canopyCenter.getY() - canopyDepth - 3);
|
||||||
int maxY = origin.getY() + height + canopyDepth + 4;
|
int maxY = origin.getY() + height + canopyDepth + 4;
|
||||||
@@ -1112,6 +1166,11 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updateLeafDistances(WorldGenLevel level, BlockPos origin, int height, int canopyRadius, int canopyDepth) {
|
protected void updateLeafDistances(WorldGenLevel level, BlockPos origin, int height, int canopyRadius, int canopyDepth) {
|
||||||
|
TreePlacement placement = ACTIVE_PLACEMENT.get();
|
||||||
|
if (placement != null) {
|
||||||
|
this.updateLeafDistances(level, placement.leafPositions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
int horizontalRadius = canopyRadius + 2;
|
int horizontalRadius = canopyRadius + 2;
|
||||||
int minY = Math.max(level.getMinBuildHeight(), origin.getY() - 2);
|
int minY = Math.max(level.getMinBuildHeight(), origin.getY() - 2);
|
||||||
int maxY = Math.min(level.getMaxBuildHeight() - 1, origin.getY() + height + canopyDepth + 8);
|
int maxY = Math.min(level.getMaxBuildHeight() - 1, origin.getY() + height + canopyDepth + 8);
|
||||||
@@ -1200,6 +1259,78 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateLeafDistances(WorldGenLevel level, Set<BlockPos> leafPositions) {
|
||||||
|
Map<BlockPos, Integer> distances = new HashMap<>();
|
||||||
|
ArrayDeque<BlockPos> queue = new ArrayDeque<>();
|
||||||
|
|
||||||
|
for (BlockPos pos : leafPositions) {
|
||||||
|
BlockState state = level.getBlockState(pos);
|
||||||
|
IntegerProperty property = this.getLeafDistanceProperty(state);
|
||||||
|
if (property != null) {
|
||||||
|
distances.put(pos, this.getLeafDistanceLimit(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BlockPos pos : leafPositions) {
|
||||||
|
BlockState state = level.getBlockState(pos);
|
||||||
|
IntegerProperty property = this.getLeafDistanceProperty(state);
|
||||||
|
if (property == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int bestDistance = this.getLeafDistanceLimit(state);
|
||||||
|
for (Direction direction : Direction.values()) {
|
||||||
|
BlockPos neighborPos = pos.relative(direction);
|
||||||
|
BlockState neighbor = level.getBlockState(neighborPos);
|
||||||
|
if (neighbor.is(BlockTags.LOGS)) {
|
||||||
|
bestDistance = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
IntegerProperty neighborProperty = this.getLeafDistanceProperty(neighbor);
|
||||||
|
if (neighborProperty != null && !distances.containsKey(neighborPos)) {
|
||||||
|
bestDistance = Math.min(bestDistance, neighbor.getValue(neighborProperty) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bestDistance < distances.get(pos)) {
|
||||||
|
distances.put(pos, bestDistance);
|
||||||
|
queue.add(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
BlockPos pos = queue.removeFirst();
|
||||||
|
int distance = distances.get(pos);
|
||||||
|
for (Direction direction : Direction.values()) {
|
||||||
|
BlockPos neighborPos = pos.relative(direction);
|
||||||
|
Integer neighborDistance = distances.get(neighborPos);
|
||||||
|
if (neighborDistance == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BlockState neighborState = level.getBlockState(neighborPos);
|
||||||
|
int candidate = Math.min(this.getLeafDistanceLimit(neighborState), distance + 1);
|
||||||
|
if (candidate < neighborDistance) {
|
||||||
|
distances.put(neighborPos, candidate);
|
||||||
|
queue.addLast(neighborPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BlockPos pos : leafPositions) {
|
||||||
|
BlockState state = level.getBlockState(pos);
|
||||||
|
IntegerProperty property = this.getLeafDistanceProperty(state);
|
||||||
|
if (property == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int computedDistance = distances.get(pos);
|
||||||
|
if (computedDistance == state.getValue(property)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BlockState updatedState = state.getBlock() instanceof OuranwoodLeavesBlock
|
||||||
|
? OuranwoodLeavesBlock.setOuranwoodDistanceForWorldgen(state, computedDistance)
|
||||||
|
: state.setValue(property, computedDistance);
|
||||||
|
setBlock(level, pos, updatedState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void placeHangingAcorns(WorldGenLevel level, BlockPos canopyCenter, OuranwoodTreeConfiguration config, RandomSource random, int canopyRadius, int canopyDepth) {
|
protected void placeHangingAcorns(WorldGenLevel level, BlockPos canopyCenter, OuranwoodTreeConfiguration config, RandomSource random, int canopyRadius, int canopyDepth) {
|
||||||
int maxAcorns = config.juvenile() ? 12 + random.nextInt(6) : 40 + random.nextInt(20);
|
int maxAcorns = config.juvenile() ? 12 + random.nextInt(6) : 40 + random.nextInt(20);
|
||||||
int attempts = maxAcorns * 12;
|
int attempts = maxAcorns * 12;
|
||||||
@@ -1530,6 +1661,15 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
|||||||
protected void setBlock(WorldGenLevel level, BlockPos pos, BlockState state) {
|
protected void setBlock(WorldGenLevel level, BlockPos pos, BlockState state) {
|
||||||
if (canWriteAt(level, pos)) {
|
if (canWriteAt(level, pos)) {
|
||||||
setBlock((LevelWriter) level, pos, state);
|
setBlock((LevelWriter) level, pos, state);
|
||||||
|
TreePlacement placement = ACTIVE_PLACEMENT.get();
|
||||||
|
if (placement != null) {
|
||||||
|
BlockPos immutablePos = pos.immutable();
|
||||||
|
if (state.is(BlockTags.LOGS)) {
|
||||||
|
placement.logPositions.add(immutablePos);
|
||||||
|
} else if (state.is(BlockTags.LEAVES)) {
|
||||||
|
placement.leafPositions.add(immutablePos);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-6
@@ -2,6 +2,7 @@ package com.craisinlord.antarchy.content.worldgen.thoraxis;
|
|||||||
|
|
||||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.util.RandomSource;
|
import net.minecraft.util.RandomSource;
|
||||||
@@ -34,6 +35,7 @@ public final class LucidAntiwaterPoolFeature extends Feature<ThoraxisAntiwaterPo
|
|||||||
int sourceCount = Math.max(2, randomBetween(random, 2, 4));
|
int sourceCount = Math.max(2, randomBetween(random, 2, 4));
|
||||||
BlockState antiwaterSourceState = config.state().getState(random, origin);
|
BlockState antiwaterSourceState = config.state().getState(random, origin);
|
||||||
BlockState basaltState = AntarchyObjects.ANTIMETAL.get().defaultBlockState();
|
BlockState basaltState = AntarchyObjects.ANTIMETAL.get().defaultBlockState();
|
||||||
|
Long2IntOpenHashMap ceilingCache = new Long2IntOpenHashMap();
|
||||||
|
|
||||||
int floorY = findFloorY(level, origin.getX(), origin.getZ());
|
int floorY = findFloorY(level, origin.getX(), origin.getZ());
|
||||||
if (floorY <= level.getMinBuildHeight()) {
|
if (floorY <= level.getMinBuildHeight()) {
|
||||||
@@ -55,7 +57,7 @@ public final class LucidAntiwaterPoolFeature extends Feature<ThoraxisAntiwaterPo
|
|||||||
int ventBudget = sourceCount + random.nextInt(2);
|
int ventBudget = sourceCount + random.nextInt(2);
|
||||||
BasinProfile profile = BasinProfile.create(random);
|
BasinProfile profile = BasinProfile.create(random);
|
||||||
|
|
||||||
placedAny |= placeCeilingBasin(level, random, offsetX, floorY, offsetZ, lobeRadius, ceilingY, profile, basaltState, antiwaterSourceState);
|
placedAny |= placeCeilingBasin(level, random, offsetX, floorY, offsetZ, lobeRadius, ceilingY, profile, basaltState, antiwaterSourceState, ceilingCache);
|
||||||
placedAny |= placeAntiwaterSources(level, random, offsetX, floorY, offsetZ, Math.max(2, lobeRadius - 1), ventBudget, antiwaterSourceState);
|
placedAny |= placeAntiwaterSources(level, random, offsetX, floorY, offsetZ, Math.max(2, lobeRadius - 1), ventBudget, antiwaterSourceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +74,8 @@ public final class LucidAntiwaterPoolFeature extends Feature<ThoraxisAntiwaterPo
|
|||||||
int maxCeilingY,
|
int maxCeilingY,
|
||||||
BasinProfile profile,
|
BasinProfile profile,
|
||||||
BlockState basaltState,
|
BlockState basaltState,
|
||||||
BlockState antiwaterSourceState
|
BlockState antiwaterSourceState,
|
||||||
|
Long2IntOpenHashMap ceilingCache
|
||||||
) {
|
) {
|
||||||
boolean placedAny = false;
|
boolean placedAny = false;
|
||||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||||
@@ -87,7 +90,7 @@ public final class LucidAntiwaterPoolFeature extends Feature<ThoraxisAntiwaterPo
|
|||||||
|
|
||||||
int worldX = centerX + dx;
|
int worldX = centerX + dx;
|
||||||
int worldZ = centerZ + dz;
|
int worldZ = centerZ + dz;
|
||||||
int localCeilingY = findCeilingY(level, worldX, worldZ, floorY);
|
int localCeilingY = cachedCeilingY(level, worldX, worldZ, floorY, ceilingCache);
|
||||||
if (localCeilingY <= floorY + MIN_CAVITY_HEIGHT || localCeilingY > maxCeilingY + 3) {
|
if (localCeilingY <= floorY + MIN_CAVITY_HEIGHT || localCeilingY > maxCeilingY + 3) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -113,7 +116,7 @@ public final class LucidAntiwaterPoolFeature extends Feature<ThoraxisAntiwaterPo
|
|||||||
placedAny = true;
|
placedAny = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
placedAny |= placeOuterLip(level, random, worldX, worldZ, floorY, basinTopY, profile, dx, dz, radius, basaltState);
|
placedAny |= placeOuterLip(level, random, worldX, worldZ, floorY, basinTopY, profile, dx, dz, radius, basaltState, ceilingCache);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +148,8 @@ public final class LucidAntiwaterPoolFeature extends Feature<ThoraxisAntiwaterPo
|
|||||||
int dx,
|
int dx,
|
||||||
int dz,
|
int dz,
|
||||||
int radius,
|
int radius,
|
||||||
BlockState basaltState
|
BlockState basaltState,
|
||||||
|
Long2IntOpenHashMap ceilingCache
|
||||||
) {
|
) {
|
||||||
boolean placedAny = false;
|
boolean placedAny = false;
|
||||||
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||||
@@ -166,7 +170,7 @@ public final class LucidAntiwaterPoolFeature extends Feature<ThoraxisAntiwaterPo
|
|||||||
|
|
||||||
int x = centerX + stepX;
|
int x = centerX + stepX;
|
||||||
int z = centerZ + stepZ;
|
int z = centerZ + stepZ;
|
||||||
int localCeilingY = findCeilingY(level, x, z, floorY);
|
int localCeilingY = cachedCeilingY(level, x, z, floorY, ceilingCache);
|
||||||
if (localCeilingY <= floorY + MIN_CAVITY_HEIGHT) {
|
if (localCeilingY <= floorY + MIN_CAVITY_HEIGHT) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -300,6 +304,23 @@ public final class LucidAntiwaterPoolFeature extends Feature<ThoraxisAntiwaterPo
|
|||||||
return Integer.MIN_VALUE;
|
return Integer.MIN_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int cachedCeilingY(
|
||||||
|
WorldGenLevel level,
|
||||||
|
int x,
|
||||||
|
int z,
|
||||||
|
int floorY,
|
||||||
|
Long2IntOpenHashMap cache
|
||||||
|
) {
|
||||||
|
long key = BlockPos.asLong(x, 0, z);
|
||||||
|
if (cache.containsKey(key)) {
|
||||||
|
return cache.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ceilingY = findCeilingY(level, x, z, floorY);
|
||||||
|
cache.put(key, ceilingY);
|
||||||
|
return ceilingY;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isSolidSurface(BlockState state) {
|
private static boolean isSolidSurface(BlockState state) {
|
||||||
return !state.isAir() && state.blocksMotion() && state.getFluidState().isEmpty();
|
return !state.isAir() && state.blocksMotion() && state.getFluidState().isEmpty();
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -16,7 +16,6 @@ import net.minecraft.world.level.levelgen.feature.Feature;
|
|||||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||||
|
|
||||||
/** Places the complete natural-grown shape so every segment gets the body state. */
|
|
||||||
public final class NaturalDirectionalVineFeature extends Feature<NoneFeatureConfiguration> {
|
public final class NaturalDirectionalVineFeature extends Feature<NoneFeatureConfiguration> {
|
||||||
private final ResourceLocation blockId;
|
private final ResourceLocation blockId;
|
||||||
private final Direction direction;
|
private final Direction direction;
|
||||||
|
|||||||
-4
@@ -11,10 +11,6 @@ import net.minecraft.world.level.levelgen.feature.Feature;
|
|||||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills the low, open main-side Thoraxis basin with source ichor during chunk generation.
|
|
||||||
* The feature works one chunk at a time so it does not depend on runtime fluid spreading.
|
|
||||||
*/
|
|
||||||
public final class ThoraxisIchorLakeFeature extends Feature<NoneFeatureConfiguration> {
|
public final class ThoraxisIchorLakeFeature extends Feature<NoneFeatureConfiguration> {
|
||||||
private static final int LAKE_FLOOR_Y = 1;
|
private static final int LAKE_FLOOR_Y = 1;
|
||||||
private static final int LAKE_SURFACE_Y = 8;
|
private static final int LAKE_SURFACE_Y = 8;
|
||||||
|
|||||||
+13
@@ -71,6 +71,7 @@ public final class ThoraxisUndersideManager {
|
|||||||
int refreshedLiving = 0;
|
int refreshedLiving = 0;
|
||||||
int flippedItems = 0;
|
int flippedItems = 0;
|
||||||
int restoredItems = 0;
|
int restoredItems = 0;
|
||||||
|
Set<Entity> evicted = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||||
for (Entity entity : tracking.entities) {
|
for (Entity entity : tracking.entities) {
|
||||||
if (!entity.isAlive() || entity.isSpectator()) {
|
if (!entity.isAlive() || entity.isSpectator()) {
|
||||||
continue;
|
continue;
|
||||||
@@ -82,6 +83,8 @@ public final class ThoraxisUndersideManager {
|
|||||||
if (living.getY() < threshold) {
|
if (living.getY() < threshold) {
|
||||||
refreshInvertedEffect(living);
|
refreshInvertedEffect(living);
|
||||||
refreshedLiving++;
|
refreshedLiving++;
|
||||||
|
} else if (!hasEffect) {
|
||||||
|
evicted.add(entity);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -122,9 +125,12 @@ public final class ThoraxisUndersideManager {
|
|||||||
AntarchyGravityApi.setGravityDirection(entity, AntarchyGravityDirection.DOWN, false, TRANSITION);
|
AntarchyGravityApi.setGravityDirection(entity, AntarchyGravityDirection.DOWN, false, TRANSITION);
|
||||||
restoredItems++;
|
restoredItems++;
|
||||||
}
|
}
|
||||||
|
evicted.add(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracking.entities.removeAll(evicted);
|
||||||
|
tracking.forcedItems.removeAll(evicted);
|
||||||
tracking.entities.removeIf(entity -> !entity.isAlive() || entity.isRemoved());
|
tracking.entities.removeIf(entity -> !entity.isAlive() || entity.isRemoved());
|
||||||
tracking.forcedItems.removeIf(entity -> !entity.isAlive() || entity.isRemoved());
|
tracking.forcedItems.removeIf(entity -> !entity.isAlive() || entity.isRemoved());
|
||||||
tracking.lastFlipTick.entrySet().removeIf(entry -> now - entry.getValue() > FLIP_COOLDOWN_TICKS * 4L);
|
tracking.lastFlipTick.entrySet().removeIf(entry -> now - entry.getValue() > FLIP_COOLDOWN_TICKS * 4L);
|
||||||
@@ -222,4 +228,11 @@ public final class ThoraxisUndersideManager {
|
|||||||
public static boolean isAboveUndersideExit(Entity entity) {
|
public static boolean isAboveUndersideExit(Entity entity) {
|
||||||
return isThoraxis(entity.level()) && entity.getY() >= EXIT_UNDERSIDE_Y;
|
return isThoraxis(entity.level()) && entity.getY() >= EXIT_UNDERSIDE_Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** True while an entity is in the region where the underside gravity rule applies. */
|
||||||
|
public static boolean shouldInvertInUnderside(Entity entity) {
|
||||||
|
return AntarchyGravityApi.isGravityInverted(entity)
|
||||||
|
&& isThoraxis(entity.level())
|
||||||
|
&& entity.getY() < GRAVITY_FLIP_Y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+20
-17
@@ -1,16 +1,15 @@
|
|||||||
package com.craisinlord.antarchy.mixins.gravity;
|
package com.craisinlord.antarchy.mixins.gravity;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
|
||||||
|
|
||||||
@Mixin(AbstractArrow.class)
|
@Mixin(AbstractArrow.class)
|
||||||
/*
|
/*
|
||||||
@@ -18,20 +17,24 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractArrowGravityMixin {
|
public abstract class AbstractArrowGravityMixin {
|
||||||
|
|
||||||
@ModifyVariable(method = "tick", at = @At(value = "STORE"), ordinal = 0)
|
@WrapOperation(method = "tick", at = @At(
|
||||||
private Vec3 antarchy$fixArrowGravityDroop(Vec3 velocity) {
|
value = "INVOKE",
|
||||||
AbstractArrow self = (AbstractArrow) (Object) this;
|
target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;applyGravity()V"))
|
||||||
|
private void antarchy$applyArrowGravityUpward(AbstractArrow self, Operation<Void> original) {
|
||||||
Entity owner = self.getOwner();
|
Entity owner = self.getOwner();
|
||||||
if (!(owner instanceof LivingEntity living)) return velocity;
|
if (!(owner instanceof LivingEntity living)) {
|
||||||
if (owner instanceof net.minecraft.world.entity.player.Player && !AntarchySettings.invertProjectilesFromInvertedPlayers()) {
|
original.call(self);
|
||||||
return velocity;
|
return;
|
||||||
}
|
}
|
||||||
AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(living);
|
if (owner instanceof net.minecraft.world.entity.player.Player && !AntarchySettings.invertProjectilesFromInvertedPlayers()) {
|
||||||
if (!direction.isInverted()) return velocity;
|
original.call(self);
|
||||||
velocity = new Vec3(velocity.x, velocity.y + 0.05D, velocity.z);
|
return;
|
||||||
velocity = AntarchyGravityRotationUtil.vecWorldToPlayer(velocity, direction);
|
}
|
||||||
velocity = new Vec3(velocity.x, velocity.y - 0.05D, velocity.z);
|
if (!ThoraxisUndersideManager.shouldInvertInUnderside(living)) {
|
||||||
velocity = AntarchyGravityRotationUtil.vecPlayerToWorld(velocity, direction);
|
original.call(self);
|
||||||
return velocity;
|
return;
|
||||||
|
}
|
||||||
|
double gravity = self.getGravity();
|
||||||
|
self.setDeltaMovement(self.getDeltaMovement().add(0.0D, gravity, 0.0D));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-3
@@ -68,8 +68,6 @@ public abstract class BehaviorUtilsGravityMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean antarchy$shouldInvertThrownItem(LivingEntity entity) {
|
private static boolean antarchy$shouldInvertThrownItem(LivingEntity entity) {
|
||||||
return AntarchyGravityApi.isGravityInverted(entity)
|
return ThoraxisUndersideManager.shouldInvertInUnderside(entity);
|
||||||
&& ThoraxisUndersideManager.isThoraxis(entity.level())
|
|
||||||
&& entity.getY() < ThoraxisUndersideManager.GRAVITY_FLIP_Y;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-4
@@ -54,10 +54,6 @@ public abstract class BucketItemGravityMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Direction face = blockHitResult.getDirection();
|
Direction face = blockHitResult.getDirection();
|
||||||
if (face.getAxis() != Direction.Axis.Y) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockPos clickedPos = blockHitResult.getBlockPos();
|
BlockPos clickedPos = blockHitResult.getBlockPos();
|
||||||
BlockState clickedState = level.getBlockState(clickedPos);
|
BlockState clickedState = level.getBlockState(clickedPos);
|
||||||
Block clickedBlock = clickedState.getBlock();
|
Block clickedBlock = clickedState.getBlock();
|
||||||
|
|||||||
+4
-2
@@ -4,6 +4,7 @@ import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
|||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
@@ -54,7 +55,8 @@ public abstract class CrossbowItemGravityMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean antarchy$shouldFixProjectileSpawn(LivingEntity shooter) {
|
private static boolean antarchy$shouldFixProjectileSpawn(LivingEntity shooter) {
|
||||||
return !(shooter instanceof net.minecraft.world.entity.player.Player)
|
return ThoraxisUndersideManager.shouldInvertInUnderside(shooter)
|
||||||
|| AntarchySettings.invertProjectilesFromInvertedPlayers();
|
&& (!(shooter instanceof net.minecraft.world.entity.player.Player)
|
||||||
|
|| AntarchySettings.invertProjectilesFromInvertedPlayers());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+25
-3
@@ -1,19 +1,41 @@
|
|||||||
package com.craisinlord.antarchy.mixins.gravity;
|
package com.craisinlord.antarchy.mixins.gravity;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.entity.projectile.ThrowableProjectile;
|
import net.minecraft.world.entity.projectile.ThrowableProjectile;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(ThrowableProjectile.class)
|
@Mixin(ThrowableProjectile.class)
|
||||||
/*
|
/*
|
||||||
* Flips thrown projectile gravity for inverted shooters.
|
* Flips thrown projectile gravity for inverted shooters.
|
||||||
*/
|
*/
|
||||||
public abstract class ThrowableProjectileGravityMixin {
|
public abstract class ThrowableProjectileGravityMixin {
|
||||||
|
|
||||||
|
@WrapOperation(method = "tick", at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/entity/projectile/ThrowableProjectile;applyGravity()V"))
|
||||||
|
private void antarchy$applyThrownProjectileGravityUpward(ThrowableProjectile self, Operation<Void> original) {
|
||||||
|
Entity owner = self.getOwner();
|
||||||
|
if (!(owner instanceof LivingEntity living)) {
|
||||||
|
original.call(self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (owner instanceof Player && !AntarchySettings.invertProjectilesFromInvertedPlayers()) {
|
||||||
|
original.call(self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!ThoraxisUndersideManager.shouldInvertInUnderside(living)) {
|
||||||
|
original.call(self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double gravity = self.getGravity();
|
||||||
|
self.setDeltaMovement(self.getDeltaMovement().add(0.0D, gravity, 0.0D));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -21,7 +21,7 @@ public abstract class EntityDeltaMovementTimeDilationMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double rate = TimeDilationApi.getRate(entity);
|
double rate = TimeDilationApi.getRate(entity);
|
||||||
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
if (rate >= TimeDilationMath.NORMAL_RATE - 0.001D) {
|
||||||
return nextMovement;
|
return nextMovement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
@@ -58,6 +58,13 @@ public abstract class LivingEntityRendererAnimationTimeDilationMixin {
|
|||||||
return entity == null ? amount : ClientTimeDilationTicker.dilateWalkAmount(entity, amount);
|
return entity == null ? amount : ClientTimeDilationTicker.dilateWalkAmount(entity, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/WalkAnimationState;position(F)F"))
|
||||||
|
private float antarchy$scaleWalkPosition(net.minecraft.world.entity.WalkAnimationState state, float partialTick) {
|
||||||
|
LivingEntity entity = antarchy$renderingEntity.get();
|
||||||
|
float position = state.position(partialTick);
|
||||||
|
return entity == null ? position : ClientTimeDilationTicker.dilateWalkPosition(entity, position);
|
||||||
|
}
|
||||||
|
|
||||||
@org.spongepowered.asm.mixin.injection.Inject(method = "getOverlayCoords", at = @At("HEAD"), cancellable = true)
|
@org.spongepowered.asm.mixin.injection.Inject(method = "getOverlayCoords", at = @At("HEAD"), cancellable = true)
|
||||||
private static void antarchy$slowHurtOverlay(LivingEntity entity, float partialTick, CallbackInfoReturnable<Integer> cir) {
|
private static void antarchy$slowHurtOverlay(LivingEntity entity, float partialTick, CallbackInfoReturnable<Integer> cir) {
|
||||||
if (com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity) < 1.0D
|
if (com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity) < 1.0D
|
||||||
|
|||||||
+6
@@ -1,6 +1,7 @@
|
|||||||
package com.craisinlord.antarchy.mixins.time;
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationManager;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
@@ -11,6 +12,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
|
|
||||||
@Mixin(LivingEntity.class)
|
@Mixin(LivingEntity.class)
|
||||||
public abstract class LivingEntityTimeDilationMixin {
|
public abstract class LivingEntityTimeDilationMixin {
|
||||||
|
@Inject(method = "tickEffects", at = @At("HEAD"))
|
||||||
|
private void antarchy$trackTemporalEffects(CallbackInfo ci) {
|
||||||
|
TimeDilationManager.trackPotentiallyAffected((Entity) (Object) this);
|
||||||
|
}
|
||||||
|
|
||||||
@Inject(method = "updateSwingTime", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "updateSwingTime", at = @At("HEAD"), cancellable = true)
|
||||||
private void antarchy$slowSwingTime(CallbackInfo ci) {
|
private void antarchy$slowSwingTime(CallbackInfo ci) {
|
||||||
Entity entity = (Entity) (Object) this;
|
Entity entity = (Entity) (Object) this;
|
||||||
|
|||||||
@@ -543,7 +543,7 @@
|
|||||||
"item.antarchy.royal_assailant_battleaxe": "Royal Assailant Battle Axe",
|
"item.antarchy.royal_assailant_battleaxe": "Royal Assailant Battle Axe",
|
||||||
"item.antarchy.royal_assailant_staff": "Royal Assailant Staff",
|
"item.antarchy.royal_assailant_staff": "Royal Assailant Staff",
|
||||||
"tooltip.antarchy.royal_assailant_staff": "Opens paired tears that summon four allied Manticores for 30 seconds.",
|
"tooltip.antarchy.royal_assailant_staff": "Opens paired tears that summon four allied Manticores for 30 seconds.",
|
||||||
"tooltip.antarchy.royal_assailant_battleaxe.black_hole": "Use to create a Royal Black Hole",
|
"tooltip.antarchy.royal_assailant_battleaxe.black_hole": "Use to create a Black Hole",
|
||||||
"tooltip.antarchy.royal_assailant_battleaxe.dilation": "Hits apply Temporal Dilation",
|
"tooltip.antarchy.royal_assailant_battleaxe.dilation": "Hits apply Temporal Dilation",
|
||||||
"tooltip.antarchy.royal_guardian_shield.command": "Use to command the nearest mob",
|
"tooltip.antarchy.royal_guardian_shield.command": "Use to command the nearest mob",
|
||||||
"tooltip.antarchy.royal_assailant_chestplate.invert": "Press the inversion key to toggle inverted gravity on and off.",
|
"tooltip.antarchy.royal_assailant_chestplate.invert": "Press the inversion key to toggle inverted gravity on and off.",
|
||||||
@@ -1047,6 +1047,9 @@
|
|||||||
"subtitles.antarchy.king_beam_shoot": "The King fires a beam",
|
"subtitles.antarchy.king_beam_shoot": "The King fires a beam",
|
||||||
"subtitles.antarchy.king_fireball_shoot": "The King breathes fire",
|
"subtitles.antarchy.king_fireball_shoot": "The King breathes fire",
|
||||||
"subtitles.antarchy.king_decree_cast": "The King pronounces a Decree",
|
"subtitles.antarchy.king_decree_cast": "The King pronounces a Decree",
|
||||||
|
"subtitles.antarchy.king_decree": "The King issues a Decree",
|
||||||
|
"subtitles.antarchy.king_success": "The King acknowledges compliance",
|
||||||
|
"subtitles.antarchy.king_judgement": "The King passes Judgement",
|
||||||
"subtitles.antarchy.queen_idle": "The Queen murmurs",
|
"subtitles.antarchy.queen_idle": "The Queen murmurs",
|
||||||
"subtitles.antarchy.queen_walk": "The Queen's footfalls",
|
"subtitles.antarchy.queen_walk": "The Queen's footfalls",
|
||||||
"subtitles.antarchy.queen_fly_loop": "The Queen's wings beat",
|
"subtitles.antarchy.queen_fly_loop": "The Queen's wings beat",
|
||||||
|
|||||||
@@ -2825,6 +2825,30 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"king_decree": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_decree",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/decree"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_success": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_success",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/success"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_judgement": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_judgement",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/judgement"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"queen_idle": {
|
"queen_idle": {
|
||||||
"subtitle": "subtitles.antarchy.queen_idle",
|
"subtitle": "subtitles.antarchy.queen_idle",
|
||||||
"sounds": [
|
"sounds": [
|
||||||
|
|||||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 314 B |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 393 B |
Binary file not shown.
|
After Width: | Height: | Size: 227 B |
@@ -7,6 +7,15 @@
|
|||||||
{
|
{
|
||||||
"type": "minecraft:item",
|
"type": "minecraft:item",
|
||||||
"name": "antarchy:worm_tooth",
|
"name": "antarchy:worm_tooth",
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"condition": "minecraft:entity_properties",
|
||||||
|
"entity": "this",
|
||||||
|
"predicate": {
|
||||||
|
"nbt": "{GrowthStage:2}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"functions": [
|
"functions": [
|
||||||
{
|
{
|
||||||
"function": "minecraft:set_count",
|
"function": "minecraft:set_count",
|
||||||
|
|||||||
@@ -5,7 +5,18 @@
|
|||||||
"minecraft:enchanted_golden_apple",
|
"minecraft:enchanted_golden_apple",
|
||||||
"minecraft:golden_carrot",
|
"minecraft:golden_carrot",
|
||||||
"minecraft:glistering_melon_slice",
|
"minecraft:glistering_melon_slice",
|
||||||
"antarchy:king_scale",
|
"minecraft:gold_ingot",
|
||||||
"antarchy:queen_scale"
|
"minecraft:gold_nugget",
|
||||||
|
"minecraft:gold_block",
|
||||||
|
"minecraft:golden_sword",
|
||||||
|
"minecraft:golden_pickaxe",
|
||||||
|
"minecraft:golden_axe",
|
||||||
|
"minecraft:golden_shovel",
|
||||||
|
"minecraft:golden_hoe",
|
||||||
|
"minecraft:golden_helmet",
|
||||||
|
"minecraft:golden_chestplate",
|
||||||
|
"minecraft:golden_leggings",
|
||||||
|
"minecraft:golden_boots",
|
||||||
|
"minecraft:golden_horse_armor"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+1
@@ -8,6 +8,7 @@
|
|||||||
"location": "antarchy:kings_tree/kings_tree1",
|
"location": "antarchy:kings_tree/kings_tree1",
|
||||||
"processors": "antarchy:generic_processor",
|
"processors": "antarchy:generic_processor",
|
||||||
"projection": "rigid",
|
"projection": "rigid",
|
||||||
|
"ignore_bounds": true,
|
||||||
"enhanced_terrain_adaptation": {
|
"enhanced_terrain_adaptation": {
|
||||||
"type": "integrated_api:custom",
|
"type": "integrated_api:custom",
|
||||||
"carves": true,
|
"carves": true,
|
||||||
|
|||||||
+1
@@ -8,6 +8,7 @@
|
|||||||
"location": "antarchy:kings_tree/kings_tree2",
|
"location": "antarchy:kings_tree/kings_tree2",
|
||||||
"processors": "antarchy:generic_processor",
|
"processors": "antarchy:generic_processor",
|
||||||
"projection": "rigid",
|
"projection": "rigid",
|
||||||
|
"ignore_bounds": true,
|
||||||
"enhanced_terrain_adaptation": {
|
"enhanced_terrain_adaptation": {
|
||||||
"type": "integrated_api:custom",
|
"type": "integrated_api:custom",
|
||||||
"carves": true,
|
"carves": true,
|
||||||
|
|||||||
+1
@@ -8,6 +8,7 @@
|
|||||||
"location": "antarchy:kings_tree/kings_tree3",
|
"location": "antarchy:kings_tree/kings_tree3",
|
||||||
"processors": "antarchy:generic_processor",
|
"processors": "antarchy:generic_processor",
|
||||||
"projection": "rigid",
|
"projection": "rigid",
|
||||||
|
"ignore_bounds": true,
|
||||||
"enhanced_terrain_adaptation": {
|
"enhanced_terrain_adaptation": {
|
||||||
"type": "integrated_api:custom",
|
"type": "integrated_api:custom",
|
||||||
"carves": true,
|
"carves": true,
|
||||||
|
|||||||
+1
@@ -8,6 +8,7 @@
|
|||||||
"location": "antarchy:kings_tree/kings_tree4",
|
"location": "antarchy:kings_tree/kings_tree4",
|
||||||
"processors": "antarchy:generic_processor",
|
"processors": "antarchy:generic_processor",
|
||||||
"projection": "rigid",
|
"projection": "rigid",
|
||||||
|
"ignore_bounds": true,
|
||||||
"enhanced_terrain_adaptation": {
|
"enhanced_terrain_adaptation": {
|
||||||
"type": "integrated_api:custom",
|
"type": "integrated_api:custom",
|
||||||
"carves": true,
|
"carves": true,
|
||||||
|
|||||||
+3
-2
@@ -8,10 +8,11 @@
|
|||||||
"location": "antarchy:kings_tree/kings_tree_bottom",
|
"location": "antarchy:kings_tree/kings_tree_bottom",
|
||||||
"processors": "antarchy:generic_processor",
|
"processors": "antarchy:generic_processor",
|
||||||
"projection": "rigid",
|
"projection": "rigid",
|
||||||
|
"ignore_bounds": true,
|
||||||
"enhanced_terrain_adaptation": {
|
"enhanced_terrain_adaptation": {
|
||||||
"type": "integrated_api:custom",
|
"type": "integrated_api:custom",
|
||||||
"carves": true,
|
"carves": false,
|
||||||
"beards": true,
|
"beards": false,
|
||||||
"kernel_size": 35,
|
"kernel_size": 35,
|
||||||
"kernel_distance": 35
|
"kernel_distance": 35
|
||||||
},
|
},
|
||||||
|
|||||||
+5
-1
@@ -340,7 +340,10 @@ public final class AntarchyFabricContent {
|
|||||||
AntarchyFabricSounds.PRINCESS_BITE,
|
AntarchyFabricSounds.PRINCESS_BITE,
|
||||||
AntarchyFabricSounds.PRINCESS_SHOOT,
|
AntarchyFabricSounds.PRINCESS_SHOOT,
|
||||||
AntarchyFabricSounds.PRINCESS_FLY,
|
AntarchyFabricSounds.PRINCESS_FLY,
|
||||||
AntarchyFabricSounds.PRINCESS_STEP
|
AntarchyFabricSounds.PRINCESS_STEP,
|
||||||
|
AntarchyFabricSounds.KING_DECREE,
|
||||||
|
AntarchyFabricSounds.KING_SUCCESS,
|
||||||
|
AntarchyFabricSounds.KING_JUDGEMENT
|
||||||
);
|
);
|
||||||
AntarchySoundEvents.bindDimensionalTearSounds(
|
AntarchySoundEvents.bindDimensionalTearSounds(
|
||||||
AntarchyFabricSounds.DIMENSIONAL_TEAR_OPEN,
|
AntarchyFabricSounds.DIMENSIONAL_TEAR_OPEN,
|
||||||
@@ -360,6 +363,7 @@ public final class AntarchyFabricContent {
|
|||||||
AntarchyObjects.setWindVortex(() -> AntarchyFabricEntities.WIND_VORTEX.get());
|
AntarchyObjects.setWindVortex(() -> AntarchyFabricEntities.WIND_VORTEX.get());
|
||||||
AntarchyObjects.setTimeDilationField(() -> AntarchyFabricEntities.TIME_DILATION_FIELD.get());
|
AntarchyObjects.setTimeDilationField(() -> AntarchyFabricEntities.TIME_DILATION_FIELD.get());
|
||||||
AntarchyObjects.setRoyalBlackHole(() -> AntarchyFabricEntities.ROYAL_BLACK_HOLE.get());
|
AntarchyObjects.setRoyalBlackHole(() -> AntarchyFabricEntities.ROYAL_BLACK_HOLE.get());
|
||||||
|
AntarchyObjects.setRoyalAssailantBlackHole(() -> AntarchyFabricEntities.ROYAL_ASSAILANT_BLACK_HOLE.get());
|
||||||
AntarchyObjects.setVortexChargeProjectile(() -> AntarchyFabricEntities.VORTEX_CHARGE_PROJECTILE.get());
|
AntarchyObjects.setVortexChargeProjectile(() -> AntarchyFabricEntities.VORTEX_CHARGE_PROJECTILE.get());
|
||||||
AntarchyObjects.setPrince(() -> AntarchyFabricEntities.PRINCE.get());
|
AntarchyObjects.setPrince(() -> AntarchyFabricEntities.PRINCE.get());
|
||||||
AntarchyObjects.setPrincess(() -> AntarchyFabricEntities.PRINCESS.get());
|
AntarchyObjects.setPrincess(() -> AntarchyFabricEntities.PRINCESS.get());
|
||||||
|
|||||||
+1
@@ -148,6 +148,7 @@ public final class AntarchyFabricClientBootstrap {
|
|||||||
EntityRendererRegistry.register(AntarchyFabricEntities.WIND_VORTEX.get(), WindVortexRenderer::new);
|
EntityRendererRegistry.register(AntarchyFabricEntities.WIND_VORTEX.get(), WindVortexRenderer::new);
|
||||||
EntityRendererRegistry.register(AntarchyFabricEntities.TIME_DILATION_FIELD.get(), TimeDilationFieldRenderer::new);
|
EntityRendererRegistry.register(AntarchyFabricEntities.TIME_DILATION_FIELD.get(), TimeDilationFieldRenderer::new);
|
||||||
EntityRendererRegistry.register(AntarchyFabricEntities.ROYAL_BLACK_HOLE.get(), com.craisinlord.antarchy.content.client.renderer.RoyalBlackHoleRenderer::new);
|
EntityRendererRegistry.register(AntarchyFabricEntities.ROYAL_BLACK_HOLE.get(), com.craisinlord.antarchy.content.client.renderer.RoyalBlackHoleRenderer::new);
|
||||||
|
EntityRendererRegistry.register(AntarchyFabricEntities.ROYAL_ASSAILANT_BLACK_HOLE.get(), com.craisinlord.antarchy.content.client.renderer.RoyalAssailantBlackHoleRenderer::new);
|
||||||
EntityRendererRegistry.register(AntarchyFabricEntities.CRITTER_CAGE_PROJECTILE.get(), ThrownItemRenderer::new);
|
EntityRendererRegistry.register(AntarchyFabricEntities.CRITTER_CAGE_PROJECTILE.get(), ThrownItemRenderer::new);
|
||||||
EntityRendererRegistry.register(AntarchyFabricEntities.WORM_HOOK_PROJECTILE.get(), ThrownItemRenderer::new);
|
EntityRendererRegistry.register(AntarchyFabricEntities.WORM_HOOK_PROJECTILE.get(), ThrownItemRenderer::new);
|
||||||
EntityRendererRegistry.register(AntarchyFabricEntities.HUSH_PROJECTILE.get(), HushProjectileRenderer::new);
|
EntityRendererRegistry.register(AntarchyFabricEntities.HUSH_PROJECTILE.get(), HushProjectileRenderer::new);
|
||||||
|
|||||||
+3
@@ -1,4 +1,5 @@
|
|||||||
package com.craisinlord.antarchy.fabric.content.fluid;
|
package com.craisinlord.antarchy.fabric.content.fluid;
|
||||||
|
import com.craisinlord.antarchy.content.fluid.AntiwaterBubbleColumnUtil;
|
||||||
import com.craisinlord.antarchy.fabric.registry.AntarchyFabricBlocks;
|
import com.craisinlord.antarchy.fabric.registry.AntarchyFabricBlocks;
|
||||||
import com.craisinlord.antarchy.fabric.registry.AntarchyFabricItems;
|
import com.craisinlord.antarchy.fabric.registry.AntarchyFabricItems;
|
||||||
import com.craisinlord.antarchy.fabric.registry.AntarchyFabricMisc;
|
import com.craisinlord.antarchy.fabric.registry.AntarchyFabricMisc;
|
||||||
@@ -169,6 +170,8 @@ public abstract class AntiwaterFluid extends FlowingFluid {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AntiwaterBubbleColumnUtil.update(level, pos, state);
|
||||||
|
|
||||||
if (!state.isSource() && !this.isFlowingStateValid(level, pos, state)) {
|
if (!state.isSource() && !this.isFlowingStateValid(level, pos, state)) {
|
||||||
level.setBlockAndUpdate(pos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState());
|
level.setBlockAndUpdate(pos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState());
|
||||||
this.scheduleCleanup(level, pos);
|
this.scheduleCleanup(level, pos);
|
||||||
|
|||||||
+7
@@ -484,6 +484,13 @@ public final class AntarchyFabricEntities {
|
|||||||
.updateInterval(2)
|
.updateInterval(2)
|
||||||
.fireImmune()
|
.fireImmune()
|
||||||
.build("royal_black_hole"));
|
.build("royal_black_hole"));
|
||||||
|
public static final DeferredHolder<EntityType<?>, EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>> ROYAL_ASSAILANT_BLACK_HOLE = ENTITY_TYPES.register("royal_assailant_black_hole",
|
||||||
|
() -> EntityType.Builder.<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>of(com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity::new, MobCategory.MISC)
|
||||||
|
.sized(1.0F, 1.0F)
|
||||||
|
.clientTrackingRange(16)
|
||||||
|
.updateInterval(2)
|
||||||
|
.fireImmune()
|
||||||
|
.build("royal_assailant_black_hole"));
|
||||||
|
|
||||||
|
|
||||||
public static final DeferredHolder<EntityType<?>, EntityType<LucidBoltEntity>> LUCID_BOLT = ENTITY_TYPES.register("lucid_bolt",
|
public static final DeferredHolder<EntityType<?>, EntityType<LucidBoltEntity>> LUCID_BOLT = ENTITY_TYPES.register("lucid_bolt",
|
||||||
|
|||||||
+3
@@ -543,6 +543,9 @@ public final class AntarchyFabricSounds {
|
|||||||
public static final DeferredHolder<SoundEvent, SoundEvent> KING_BEAM_SHOOT = registerSoundEvent("king_beam_shoot");
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_BEAM_SHOOT = registerSoundEvent("king_beam_shoot");
|
||||||
public static final DeferredHolder<SoundEvent, SoundEvent> KING_FIREBALL_SHOOT = registerSoundEvent("king_fireball_shoot");
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_FIREBALL_SHOOT = registerSoundEvent("king_fireball_shoot");
|
||||||
public static final DeferredHolder<SoundEvent, SoundEvent> KING_DECREE_CAST = registerSoundEvent("king_decree_cast");
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_DECREE_CAST = registerSoundEvent("king_decree_cast");
|
||||||
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_DECREE = registerSoundEvent("king_decree");
|
||||||
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_SUCCESS = registerSoundEvent("king_success");
|
||||||
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_JUDGEMENT = registerSoundEvent("king_judgement");
|
||||||
|
|
||||||
public static final DeferredHolder<SoundEvent, SoundEvent> QUEEN_IDLE = registerSoundEvent("queen_idle");
|
public static final DeferredHolder<SoundEvent, SoundEvent> QUEEN_IDLE = registerSoundEvent("queen_idle");
|
||||||
public static final DeferredHolder<SoundEvent, SoundEvent> QUEEN_WALK = registerSoundEvent("queen_walk");
|
public static final DeferredHolder<SoundEvent, SoundEvent> QUEEN_WALK = registerSoundEvent("queen_walk");
|
||||||
|
|||||||
+2
-2
@@ -337,9 +337,9 @@ public final class AntarchyForgeMisc {
|
|||||||
|
|
||||||
// Biome sources
|
// Biome sources
|
||||||
public static final RegistryObject<com.mojang.serialization.Codec<ElythiaBiomeSource>> ELYTHIA_BIOME_SOURCE = BIOME_SOURCES.register("elythia_biome_source",
|
public static final RegistryObject<com.mojang.serialization.Codec<ElythiaBiomeSource>> ELYTHIA_BIOME_SOURCE = BIOME_SOURCES.register("elythia_biome_source",
|
||||||
() -> ElythiaBiomeSource.CODEC.codec());
|
() -> ElythiaBiomeSource.CODEC);
|
||||||
public static final RegistryObject<com.mojang.serialization.Codec<ThoraxisBiomeSource>> THORAXIS_BIOME_SOURCE = BIOME_SOURCES.register("thoraxis_biome_source",
|
public static final RegistryObject<com.mojang.serialization.Codec<ThoraxisBiomeSource>> THORAXIS_BIOME_SOURCE = BIOME_SOURCES.register("thoraxis_biome_source",
|
||||||
() -> ThoraxisBiomeSource.CODEC.codec());
|
() -> ThoraxisBiomeSource.CODEC);
|
||||||
|
|
||||||
// Density function
|
// Density function
|
||||||
public static final RegistryObject<com.mojang.serialization.Codec<ElythiaRiverCarveFunction>> ELYTHIA_RIVER_CARVE = DENSITY_FUNCTION_TYPES.register("elythia_river_carve",
|
public static final RegistryObject<com.mojang.serialization.Codec<ElythiaRiverCarveFunction>> ELYTHIA_RIVER_CARVE = DENSITY_FUNCTION_TYPES.register("elythia_river_carve",
|
||||||
|
|||||||
+5
@@ -159,6 +159,10 @@ public final class AntarchyConfigModuleNeoforge {
|
|||||||
AntarchySettings.setQueenBeamTracking(AntarchyMobsConfig.queenBeamTracking());
|
AntarchySettings.setQueenBeamTracking(AntarchyMobsConfig.queenBeamTracking());
|
||||||
AntarchySettings.setQueenBeamTerrainRadius(AntarchyMobsConfig.queenBeamTerrainRadius());
|
AntarchySettings.setQueenBeamTerrainRadius(AntarchyMobsConfig.queenBeamTerrainRadius());
|
||||||
AntarchySettings.setQueenBeamTerrainCap(AntarchyMobsConfig.queenBeamTerrainCap());
|
AntarchySettings.setQueenBeamTerrainCap(AntarchyMobsConfig.queenBeamTerrainCap());
|
||||||
|
AntarchySettings.setQueenBeamPhaseOneCap(AntarchyMobsConfig.queenBeamPhaseOneCap());
|
||||||
|
AntarchySettings.setQueenBeamPhaseTwoCap(AntarchyMobsConfig.queenBeamPhaseTwoCap());
|
||||||
|
AntarchySettings.setQueenBeamPhaseThreeCap(AntarchyMobsConfig.queenBeamPhaseThreeCap());
|
||||||
|
AntarchySettings.setQueenBeamPhaseThreeMaxVolleyChance(AntarchyMobsConfig.queenBeamPhaseThreeMaxVolleyChance());
|
||||||
AntarchySettings.setKingBeamDamage(AntarchyMobsConfig.kingBeamDamage());
|
AntarchySettings.setKingBeamDamage(AntarchyMobsConfig.kingBeamDamage());
|
||||||
AntarchySettings.setKingBeamRange(AntarchyMobsConfig.kingBeamRange());
|
AntarchySettings.setKingBeamRange(AntarchyMobsConfig.kingBeamRange());
|
||||||
AntarchySettings.setKingBeamMinimumRange(AntarchyMobsConfig.kingBeamMinimumRange());
|
AntarchySettings.setKingBeamMinimumRange(AntarchyMobsConfig.kingBeamMinimumRange());
|
||||||
@@ -178,6 +182,7 @@ public final class AntarchyConfigModuleNeoforge {
|
|||||||
AntarchySettings.setQueenBlackHoleRadius(AntarchyMobsConfig.queenBlackHoleRadius());
|
AntarchySettings.setQueenBlackHoleRadius(AntarchyMobsConfig.queenBlackHoleRadius());
|
||||||
AntarchySettings.setQueenBlackHoleActiveTicks(AntarchyMobsConfig.queenBlackHoleActiveTicks());
|
AntarchySettings.setQueenBlackHoleActiveTicks(AntarchyMobsConfig.queenBlackHoleActiveTicks());
|
||||||
AntarchySettings.setQueenBlackHolePullStrength(AntarchyMobsConfig.queenBlackHolePullStrength());
|
AntarchySettings.setQueenBlackHolePullStrength(AntarchyMobsConfig.queenBlackHolePullStrength());
|
||||||
|
AntarchySettings.setQueenBlackHoleBlockSuctionCap(AntarchyMobsConfig.queenBlackHoleBlockSuctionCap());
|
||||||
AntarchySettings.setQueenFinalTimeFieldRadius(AntarchyMobsConfig.queenFinalTimeFieldRadius());
|
AntarchySettings.setQueenFinalTimeFieldRadius(AntarchyMobsConfig.queenFinalTimeFieldRadius());
|
||||||
AntarchySettings.setQueenFinalTimeFieldRate(AntarchyMobsConfig.queenFinalTimeFieldRate());
|
AntarchySettings.setQueenFinalTimeFieldRate(AntarchyMobsConfig.queenFinalTimeFieldRate());
|
||||||
AntarchySettings.setQueenFinalTimeFieldDurationTicks(AntarchyMobsConfig.queenFinalTimeFieldDurationTicks());
|
AntarchySettings.setQueenFinalTimeFieldDurationTicks(AntarchyMobsConfig.queenFinalTimeFieldDurationTicks());
|
||||||
|
|||||||
+16
-4
@@ -125,7 +125,9 @@ public final class AntarchyMobsConfig {
|
|||||||
private static final ModConfigSpec.DoubleValue ROYAL_BOSS_BITE_DAMAGE_MULTIPLIER;
|
private static final ModConfigSpec.DoubleValue ROYAL_BOSS_BITE_DAMAGE_MULTIPLIER;
|
||||||
private static final ModConfigSpec.IntValue ROYAL_BOSS_BITE_COOLDOWN_TICKS;
|
private static final ModConfigSpec.IntValue ROYAL_BOSS_BITE_COOLDOWN_TICKS;
|
||||||
private static final ModConfigSpec.DoubleValue QUEEN_BEAM_DAMAGE, QUEEN_BEAM_RANGE, QUEEN_BEAM_MINIMUM_RANGE, QUEEN_BEAM_TRACKING, QUEEN_BEAM_TERRAIN_RADIUS;
|
private static final ModConfigSpec.DoubleValue QUEEN_BEAM_DAMAGE, QUEEN_BEAM_RANGE, QUEEN_BEAM_MINIMUM_RANGE, QUEEN_BEAM_TRACKING, QUEEN_BEAM_TERRAIN_RADIUS;
|
||||||
private static final ModConfigSpec.IntValue QUEEN_BEAM_DURATION_TICKS, QUEEN_BEAM_WINDUP_TICKS, QUEEN_BEAM_TRAVEL_TICKS, QUEEN_BEAM_COOLDOWN_TICKS, QUEEN_BEAM_TERRAIN_CAP;
|
private static final ModConfigSpec.IntValue QUEEN_BEAM_DURATION_TICKS, QUEEN_BEAM_WINDUP_TICKS, QUEEN_BEAM_TRAVEL_TICKS, QUEEN_BEAM_COOLDOWN_TICKS, QUEEN_BEAM_TERRAIN_CAP,
|
||||||
|
QUEEN_BEAM_PHASE_ONE_CAP, QUEEN_BEAM_PHASE_TWO_CAP, QUEEN_BEAM_PHASE_THREE_CAP;
|
||||||
|
private static final ModConfigSpec.DoubleValue QUEEN_BEAM_PHASE_THREE_MAX_VOLLEY_CHANCE;
|
||||||
private static final ModConfigSpec.DoubleValue KING_BEAM_DAMAGE, KING_BEAM_RANGE, KING_BEAM_MINIMUM_RANGE, KING_BEAM_TRACKING, KING_BEAM_TERRAIN_RADIUS;
|
private static final ModConfigSpec.DoubleValue KING_BEAM_DAMAGE, KING_BEAM_RANGE, KING_BEAM_MINIMUM_RANGE, KING_BEAM_TRACKING, KING_BEAM_TERRAIN_RADIUS;
|
||||||
private static final ModConfigSpec.IntValue KING_BEAM_DURATION_TICKS, KING_BEAM_WINDUP_TICKS, KING_BEAM_TRAVEL_TICKS, KING_BEAM_COOLDOWN_TICKS, KING_BEAM_TERRAIN_CAP;
|
private static final ModConfigSpec.IntValue KING_BEAM_DURATION_TICKS, KING_BEAM_WINDUP_TICKS, KING_BEAM_TRAVEL_TICKS, KING_BEAM_COOLDOWN_TICKS, KING_BEAM_TERRAIN_CAP;
|
||||||
private static final ModConfigSpec.IntValue ROYAL_DECREE_COOLDOWN_TICKS;
|
private static final ModConfigSpec.IntValue ROYAL_DECREE_COOLDOWN_TICKS;
|
||||||
@@ -134,7 +136,7 @@ public final class AntarchyMobsConfig {
|
|||||||
KING_ROYAL_MUSTER_DURATION_TICKS, KING_ROYAL_MUSTER_CAP;
|
KING_ROYAL_MUSTER_DURATION_TICKS, KING_ROYAL_MUSTER_CAP;
|
||||||
private static final ModConfigSpec.DoubleValue QUEEN_BLACK_HOLE_RADIUS, QUEEN_BLACK_HOLE_PULL_STRENGTH,
|
private static final ModConfigSpec.DoubleValue QUEEN_BLACK_HOLE_RADIUS, QUEEN_BLACK_HOLE_PULL_STRENGTH,
|
||||||
QUEEN_FINAL_TIME_FIELD_RADIUS, QUEEN_FINAL_TIME_FIELD_RATE;
|
QUEEN_FINAL_TIME_FIELD_RADIUS, QUEEN_FINAL_TIME_FIELD_RATE;
|
||||||
private static final ModConfigSpec.IntValue QUEEN_BLACK_HOLE_ACTIVE_TICKS,
|
private static final ModConfigSpec.IntValue QUEEN_BLACK_HOLE_ACTIVE_TICKS, QUEEN_BLACK_HOLE_BLOCK_SUCTION_CAP,
|
||||||
QUEEN_FINAL_TIME_FIELD_DURATION_TICKS, QUEEN_FINAL_TIME_FIELD_COOLDOWN_TICKS;
|
QUEEN_FINAL_TIME_FIELD_DURATION_TICKS, QUEEN_FINAL_TIME_FIELD_COOLDOWN_TICKS;
|
||||||
private static final ModConfigSpec.DoubleValue ROYAL_BOSS_SOUND_VOLUME;
|
private static final ModConfigSpec.DoubleValue ROYAL_BOSS_SOUND_VOLUME;
|
||||||
private static final ModConfigSpec.DoubleValue KING_FIREBALL_DAMAGE, KING_FIREBALL_RADIUS, KING_ICEBALL_DAMAGE, KING_ICEBALL_RADIUS, KING_ICE_SPIKE_DAMAGE;
|
private static final ModConfigSpec.DoubleValue KING_FIREBALL_DAMAGE, KING_FIREBALL_RADIUS, KING_ICEBALL_DAMAGE, KING_ICEBALL_RADIUS, KING_ICE_SPIKE_DAMAGE;
|
||||||
@@ -583,7 +585,7 @@ public final class AntarchyMobsConfig {
|
|||||||
ROYAL_BOSS_KNOCKBACK_RESISTANCE = b.comment("Base knockback resistance shared by King and Queen.").defineInRange("knockbackResistance", 1.0D, 0.0D, 1.0D);
|
ROYAL_BOSS_KNOCKBACK_RESISTANCE = b.comment("Base knockback resistance shared by King and Queen.").defineInRange("knockbackResistance", 1.0D, 0.0D, 1.0D);
|
||||||
ROYAL_BOSS_STEP_HEIGHT = b.comment("Base step height shared by King and Queen.").defineInRange("stepHeight", 3.0D, 0.0D, 32.0D);
|
ROYAL_BOSS_STEP_HEIGHT = b.comment("Base step height shared by King and Queen.").defineInRange("stepHeight", 3.0D, 0.0D, 32.0D);
|
||||||
ROYAL_BOSS_MAX_SINGLE_HIT_DAMAGE = b.comment("Maximum damage a single hit can deal to a Royal boss before later anti-burst systems are added.").defineInRange("maxSingleHitDamage", 250.0D, 1.0D, 32768.0D);
|
ROYAL_BOSS_MAX_SINGLE_HIT_DAMAGE = b.comment("Maximum damage a single hit can deal to a Royal boss before later anti-burst systems are added.").defineInRange("maxSingleHitDamage", 250.0D, 1.0D, 32768.0D);
|
||||||
ROYAL_BOSS_BITE_REACH = b.comment("Radius around each head anchor that a King or Queen bite can hit.").defineInRange("biteReach", 10.0D, 1.0D, 64.0D);
|
ROYAL_BOSS_BITE_REACH = b.comment("Radius around each head anchor that a King or Queen bite can hit.").defineInRange("biteReach", 12.0D, 1.0D, 64.0D);
|
||||||
ROYAL_BOSS_BITE_DAMAGE_MULTIPLIER = b.comment("Multiplier applied to base attack damage for King and Queen head bites.").defineInRange("biteDamageMultiplier", 1.6D, 0.0D, 32.0D);
|
ROYAL_BOSS_BITE_DAMAGE_MULTIPLIER = b.comment("Multiplier applied to base attack damage for King and Queen head bites.").defineInRange("biteDamageMultiplier", 1.6D, 0.0D, 32.0D);
|
||||||
ROYAL_BOSS_BITE_COOLDOWN_TICKS = b.comment("Base cooldown in ticks between bites for a single King or Queen head (scaled down at later phases).").defineInRange("biteCooldownTicks", 45, 1, 1200);
|
ROYAL_BOSS_BITE_COOLDOWN_TICKS = b.comment("Base cooldown in ticks between bites for a single King or Queen head (scaled down at later phases).").defineInRange("biteCooldownTicks", 45, 1, 1200);
|
||||||
QUEEN_BEAM_DAMAGE = b.defineInRange("queenBeamDamage", 45.0D, 0.0D, 1024.0D);
|
QUEEN_BEAM_DAMAGE = b.defineInRange("queenBeamDamage", 45.0D, 0.0D, 1024.0D);
|
||||||
@@ -596,6 +598,10 @@ public final class AntarchyMobsConfig {
|
|||||||
QUEEN_BEAM_TRACKING = b.defineInRange("queenBeamTracking", 0.1D, 0.0D, 1.0D);
|
QUEEN_BEAM_TRACKING = b.defineInRange("queenBeamTracking", 0.1D, 0.0D, 1.0D);
|
||||||
QUEEN_BEAM_TERRAIN_RADIUS = b.defineInRange("queenBeamTerrainRadius", 5.0D, 0.0D, 32.0D);
|
QUEEN_BEAM_TERRAIN_RADIUS = b.defineInRange("queenBeamTerrainRadius", 5.0D, 0.0D, 32.0D);
|
||||||
QUEEN_BEAM_TERRAIN_CAP = b.defineInRange("queenBeamTerrainCap", 192, 0, 4096);
|
QUEEN_BEAM_TERRAIN_CAP = b.defineInRange("queenBeamTerrainCap", 192, 0, 4096);
|
||||||
|
QUEEN_BEAM_PHASE_ONE_CAP = b.comment("Maximum simultaneous Queen beams in phase one.").defineInRange("queenBeamPhaseOneCap", 1, 1, 3);
|
||||||
|
QUEEN_BEAM_PHASE_TWO_CAP = b.comment("Maximum simultaneous Queen beams in phase two.").defineInRange("queenBeamPhaseTwoCap", 2, 1, 3);
|
||||||
|
QUEEN_BEAM_PHASE_THREE_CAP = b.comment("Maximum simultaneous Queen beams when phase three rolls a full volley.").defineInRange("queenBeamPhaseThreeCap", 3, 1, 3);
|
||||||
|
QUEEN_BEAM_PHASE_THREE_MAX_VOLLEY_CHANCE = b.comment("Chance that a new phase-three Queen beam volley may use its full configured cap; otherwise it is limited to two beams.").defineInRange("queenBeamPhaseThreeMaxVolleyChance", 0.2D, 0.0D, 1.0D);
|
||||||
KING_BEAM_DAMAGE = b.defineInRange("kingBeamDamage", 50.0D, 0.0D, 1024.0D);
|
KING_BEAM_DAMAGE = b.defineInRange("kingBeamDamage", 50.0D, 0.0D, 1024.0D);
|
||||||
KING_BEAM_RANGE = b.defineInRange("kingBeamRange", 100.0D, 1.0D, 256.0D);
|
KING_BEAM_RANGE = b.defineInRange("kingBeamRange", 100.0D, 1.0D, 256.0D);
|
||||||
KING_BEAM_MINIMUM_RANGE = b.comment("Minimum distance from the King before he may begin or maintain a beam.").defineInRange("kingBeamMinimumRange", 32.0D, 0.0D, 256.0D);
|
KING_BEAM_MINIMUM_RANGE = b.comment("Minimum distance from the King before he may begin or maintain a beam.").defineInRange("kingBeamMinimumRange", 32.0D, 0.0D, 256.0D);
|
||||||
@@ -613,8 +619,9 @@ public final class AntarchyMobsConfig {
|
|||||||
KING_ROYAL_MUSTER_RADIUS = b.comment("Radius of the King's command aura.").defineInRange("kingRoyalMusterRadius", 32.0D, 1.0D, 128.0D);
|
KING_ROYAL_MUSTER_RADIUS = b.comment("Radius of the King's command aura.").defineInRange("kingRoyalMusterRadius", 32.0D, 1.0D, 128.0D);
|
||||||
KING_ROYAL_MUSTER_CAP = b.comment("Maximum hostile mobs affected by one command pulse.").defineInRange("kingRoyalMusterCap", 12, 1, 128);
|
KING_ROYAL_MUSTER_CAP = b.comment("Maximum hostile mobs affected by one command pulse.").defineInRange("kingRoyalMusterCap", 12, 1, 128);
|
||||||
QUEEN_BLACK_HOLE_RADIUS = b.defineInRange("queenBlackHoleRadius", 14.0D, 1.0D, 64.0D);
|
QUEEN_BLACK_HOLE_RADIUS = b.defineInRange("queenBlackHoleRadius", 14.0D, 1.0D, 64.0D);
|
||||||
QUEEN_BLACK_HOLE_ACTIVE_TICKS = b.defineInRange("queenBlackHoleActiveTicks", 120, 20, 1200);
|
QUEEN_BLACK_HOLE_ACTIVE_TICKS = b.comment("Active duration for Royal Assailant axe black holes. Queen black holes always follow their 20.125-second animation.").defineInRange("queenBlackHoleActiveTicks", 120, 20, 1200);
|
||||||
QUEEN_BLACK_HOLE_PULL_STRENGTH = b.defineInRange("queenBlackHolePullStrength", 0.16D, 0.0D, 2.0D);
|
QUEEN_BLACK_HOLE_PULL_STRENGTH = b.defineInRange("queenBlackHolePullStrength", 0.16D, 0.0D, 2.0D);
|
||||||
|
QUEEN_BLACK_HOLE_BLOCK_SUCTION_CAP = b.comment("Maximum terrain blocks a single Queen black hole may pull into itself.").defineInRange("queenBlackHoleBlockSuctionCap", 160, 0, 4096);
|
||||||
QUEEN_FINAL_TIME_FIELD_RADIUS = b.defineInRange("queenFinalTimeFieldRadius", 20.0D, 1.0D, 64.0D);
|
QUEEN_FINAL_TIME_FIELD_RADIUS = b.defineInRange("queenFinalTimeFieldRadius", 20.0D, 1.0D, 64.0D);
|
||||||
QUEEN_FINAL_TIME_FIELD_RATE = b.defineInRange("queenFinalTimeFieldRate", 0.05D, 0.05D, 1.0D);
|
QUEEN_FINAL_TIME_FIELD_RATE = b.defineInRange("queenFinalTimeFieldRate", 0.05D, 0.05D, 1.0D);
|
||||||
QUEEN_FINAL_TIME_FIELD_DURATION_TICKS = b.defineInRange("queenFinalTimeFieldDurationTicks", 45, 1, 1200);
|
QUEEN_FINAL_TIME_FIELD_DURATION_TICKS = b.defineInRange("queenFinalTimeFieldDurationTicks", 45, 1, 1200);
|
||||||
@@ -1040,6 +1047,10 @@ public final class AntarchyMobsConfig {
|
|||||||
static double queenBeamTracking() { return QUEEN_BEAM_TRACKING.get(); }
|
static double queenBeamTracking() { return QUEEN_BEAM_TRACKING.get(); }
|
||||||
static double queenBeamTerrainRadius() { return QUEEN_BEAM_TERRAIN_RADIUS.get(); }
|
static double queenBeamTerrainRadius() { return QUEEN_BEAM_TERRAIN_RADIUS.get(); }
|
||||||
static int queenBeamTerrainCap() { return QUEEN_BEAM_TERRAIN_CAP.get(); }
|
static int queenBeamTerrainCap() { return QUEEN_BEAM_TERRAIN_CAP.get(); }
|
||||||
|
static int queenBeamPhaseOneCap() { return QUEEN_BEAM_PHASE_ONE_CAP.get(); }
|
||||||
|
static int queenBeamPhaseTwoCap() { return QUEEN_BEAM_PHASE_TWO_CAP.get(); }
|
||||||
|
static int queenBeamPhaseThreeCap() { return QUEEN_BEAM_PHASE_THREE_CAP.get(); }
|
||||||
|
static double queenBeamPhaseThreeMaxVolleyChance() { return QUEEN_BEAM_PHASE_THREE_MAX_VOLLEY_CHANCE.get(); }
|
||||||
static double kingBeamDamage() { return KING_BEAM_DAMAGE.get(); }
|
static double kingBeamDamage() { return KING_BEAM_DAMAGE.get(); }
|
||||||
static double kingBeamRange() { return KING_BEAM_RANGE.get(); }
|
static double kingBeamRange() { return KING_BEAM_RANGE.get(); }
|
||||||
static double kingBeamMinimumRange() { return KING_BEAM_MINIMUM_RANGE.get(); }
|
static double kingBeamMinimumRange() { return KING_BEAM_MINIMUM_RANGE.get(); }
|
||||||
@@ -1059,6 +1070,7 @@ public final class AntarchyMobsConfig {
|
|||||||
static double queenBlackHoleRadius() { return QUEEN_BLACK_HOLE_RADIUS.get(); }
|
static double queenBlackHoleRadius() { return QUEEN_BLACK_HOLE_RADIUS.get(); }
|
||||||
static int queenBlackHoleActiveTicks() { return QUEEN_BLACK_HOLE_ACTIVE_TICKS.get(); }
|
static int queenBlackHoleActiveTicks() { return QUEEN_BLACK_HOLE_ACTIVE_TICKS.get(); }
|
||||||
static double queenBlackHolePullStrength() { return QUEEN_BLACK_HOLE_PULL_STRENGTH.get(); }
|
static double queenBlackHolePullStrength() { return QUEEN_BLACK_HOLE_PULL_STRENGTH.get(); }
|
||||||
|
static int queenBlackHoleBlockSuctionCap() { return QUEEN_BLACK_HOLE_BLOCK_SUCTION_CAP.get(); }
|
||||||
static double queenFinalTimeFieldRadius() { return QUEEN_FINAL_TIME_FIELD_RADIUS.get(); }
|
static double queenFinalTimeFieldRadius() { return QUEEN_FINAL_TIME_FIELD_RADIUS.get(); }
|
||||||
static double queenFinalTimeFieldRate() { return QUEEN_FINAL_TIME_FIELD_RATE.get(); }
|
static double queenFinalTimeFieldRate() { return QUEEN_FINAL_TIME_FIELD_RATE.get(); }
|
||||||
static int queenFinalTimeFieldDurationTicks() { return QUEEN_FINAL_TIME_FIELD_DURATION_TICKS.get(); }
|
static int queenFinalTimeFieldDurationTicks() { return QUEEN_FINAL_TIME_FIELD_DURATION_TICKS.get(); }
|
||||||
|
|||||||
+5
-1
@@ -231,7 +231,10 @@ public class AntarchyNeoforge {
|
|||||||
AntarchyNeoforgeSounds.PRINCESS_BITE,
|
AntarchyNeoforgeSounds.PRINCESS_BITE,
|
||||||
AntarchyNeoforgeSounds.PRINCESS_SHOOT,
|
AntarchyNeoforgeSounds.PRINCESS_SHOOT,
|
||||||
AntarchyNeoforgeSounds.PRINCESS_FLY,
|
AntarchyNeoforgeSounds.PRINCESS_FLY,
|
||||||
AntarchyNeoforgeSounds.PRINCESS_STEP
|
AntarchyNeoforgeSounds.PRINCESS_STEP,
|
||||||
|
AntarchyNeoforgeSounds.KING_DECREE,
|
||||||
|
AntarchyNeoforgeSounds.KING_SUCCESS,
|
||||||
|
AntarchyNeoforgeSounds.KING_JUDGEMENT
|
||||||
);
|
);
|
||||||
AntarchySoundEvents.bindDimensionalTearSounds(
|
AntarchySoundEvents.bindDimensionalTearSounds(
|
||||||
AntarchyNeoforgeSounds.DIMENSIONAL_TEAR_OPEN,
|
AntarchyNeoforgeSounds.DIMENSIONAL_TEAR_OPEN,
|
||||||
@@ -430,6 +433,7 @@ public class AntarchyNeoforge {
|
|||||||
AntarchyObjects.setWindVortex(() -> AntarchyNeoforgeEntites.WIND_VORTEX.get());
|
AntarchyObjects.setWindVortex(() -> AntarchyNeoforgeEntites.WIND_VORTEX.get());
|
||||||
AntarchyObjects.setTimeDilationField(() -> AntarchyNeoforgeEntites.TIME_DILATION_FIELD.get());
|
AntarchyObjects.setTimeDilationField(() -> AntarchyNeoforgeEntites.TIME_DILATION_FIELD.get());
|
||||||
AntarchyObjects.setRoyalBlackHole(() -> AntarchyNeoforgeEntites.ROYAL_BLACK_HOLE.get());
|
AntarchyObjects.setRoyalBlackHole(() -> AntarchyNeoforgeEntites.ROYAL_BLACK_HOLE.get());
|
||||||
|
AntarchyObjects.setRoyalAssailantBlackHole(() -> AntarchyNeoforgeEntites.ROYAL_ASSAILANT_BLACK_HOLE.get());
|
||||||
AntarchyObjects.setVortexChargeProjectile(() -> AntarchyNeoforgeEntites.VORTEX_CHARGE_PROJECTILE.get());
|
AntarchyObjects.setVortexChargeProjectile(() -> AntarchyNeoforgeEntites.VORTEX_CHARGE_PROJECTILE.get());
|
||||||
AntarchyObjects.setPrince(() -> AntarchyNeoforgeEntites.PRINCE.get());
|
AntarchyObjects.setPrince(() -> AntarchyNeoforgeEntites.PRINCE.get());
|
||||||
AntarchyObjects.setPrincess(() -> AntarchyNeoforgeEntites.PRINCESS.get());
|
AntarchyObjects.setPrincess(() -> AntarchyNeoforgeEntites.PRINCESS.get());
|
||||||
|
|||||||
+8
-3
@@ -151,6 +151,7 @@ public final class AntarchyNeoForgeClient {
|
|||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.WIND_VORTEX.get(), WindVortexRenderer::new);
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.WIND_VORTEX.get(), WindVortexRenderer::new);
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.TIME_DILATION_FIELD.get(), TimeDilationFieldRenderer::new);
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.TIME_DILATION_FIELD.get(), TimeDilationFieldRenderer::new);
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.ROYAL_BLACK_HOLE.get(), com.craisinlord.antarchy.content.client.renderer.RoyalBlackHoleRenderer::new);
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.ROYAL_BLACK_HOLE.get(), com.craisinlord.antarchy.content.client.renderer.RoyalBlackHoleRenderer::new);
|
||||||
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.ROYAL_ASSAILANT_BLACK_HOLE.get(), com.craisinlord.antarchy.content.client.renderer.RoyalAssailantBlackHoleRenderer::new);
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.CRITTER_CAGE_PROJECTILE.get(), ThrownItemRenderer::new);
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.CRITTER_CAGE_PROJECTILE.get(), ThrownItemRenderer::new);
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.WORM_HOOK_PROJECTILE.get(), ThrownItemRenderer::new);
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.WORM_HOOK_PROJECTILE.get(), ThrownItemRenderer::new);
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.HUSH_PROJECTILE.get(), HushProjectileRenderer::new);
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.HUSH_PROJECTILE.get(), HushProjectileRenderer::new);
|
||||||
@@ -161,10 +162,10 @@ public final class AntarchyNeoForgeClient {
|
|||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.TORETERROR.get(), ToreterrorRenderer::new);
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.TORETERROR.get(), ToreterrorRenderer::new);
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.WATER_BOMB.get(), WaterBombRenderer::new);
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.WATER_BOMB.get(), WaterBombRenderer::new);
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.CHEEP.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.CheepRenderer(context)));
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.CHEEP.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.CheepRenderer(context)));
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.DORRIE.get(), context -> new com.craisinlord.antarchy.content.client.renderer.DorrieRenderer(context));
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.DORRIE.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.DorrieRenderer(context)));
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.OURANWOOD_DEER.get(), context -> new com.craisinlord.antarchy.content.client.renderer.OuranwoodDeerRenderer(context));
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.OURANWOOD_DEER.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.OuranwoodDeerRenderer(context)));
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.GLIMMER.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.glimmer.GlimmerRenderer(context)));
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.GLIMMER.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.glimmer.GlimmerRenderer(context)));
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.ELKA.get(), context -> new com.craisinlord.antarchy.content.client.renderer.ElkaRenderer(context));
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.ELKA.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.ElkaRenderer(context)));
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.ROLLY_POLLY.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.RollyPollyRenderer(context)));
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.ROLLY_POLLY.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.RollyPollyRenderer(context)));
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.TERMITE.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.TermiteRenderer(context)));
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.TERMITE.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.TermiteRenderer(context)));
|
||||||
event.registerEntityRenderer(AntarchyNeoforgeEntites.CREEPING_HORROR.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.CreepingHorrorRenderer(context)));
|
event.registerEntityRenderer(AntarchyNeoforgeEntites.CREEPING_HORROR.get(), context -> withParalyzedGeoLayer(new com.craisinlord.antarchy.content.client.renderer.CreepingHorrorRenderer(context)));
|
||||||
@@ -196,6 +197,8 @@ public final class AntarchyNeoForgeClient {
|
|||||||
renderer.addLayer(new TigerEyeCamouflagePlayerLayer(renderer));
|
renderer.addLayer(new TigerEyeCamouflagePlayerLayer(renderer));
|
||||||
renderer.addLayer(new GoopedLivingLayer(renderer));
|
renderer.addLayer(new GoopedLivingLayer(renderer));
|
||||||
renderer.addLayer(new GlimmeringLivingLayer(renderer));
|
renderer.addLayer(new GlimmeringLivingLayer(renderer));
|
||||||
|
renderer.addLayer(new TemporalContractionAfterimageLayer<>(renderer));
|
||||||
|
renderer.addLayer(new RoyalAssailantAxeAfterimageLayer(renderer));
|
||||||
renderer.addLayer(new BrutalflyElytraLayer(renderer));
|
renderer.addLayer(new BrutalflyElytraLayer(renderer));
|
||||||
renderer.addLayer(new com.craisinlord.antarchy.content.client.renderer.ManticoreWingsLayer(renderer));
|
renderer.addLayer(new com.craisinlord.antarchy.content.client.renderer.ManticoreWingsLayer(renderer));
|
||||||
renderer.addLayer(new FallenKingCrownLayer(renderer));
|
renderer.addLayer(new FallenKingCrownLayer(renderer));
|
||||||
@@ -235,11 +238,13 @@ public final class AntarchyNeoForgeClient {
|
|||||||
((LivingEntityRenderer) livingRenderer).addLayer(new ParalyzedStoneLivingLayer<>(livingRenderer));
|
((LivingEntityRenderer) livingRenderer).addLayer(new ParalyzedStoneLivingLayer<>(livingRenderer));
|
||||||
((LivingEntityRenderer) livingRenderer).addLayer(new GoopedLivingLayer<>(livingRenderer));
|
((LivingEntityRenderer) livingRenderer).addLayer(new GoopedLivingLayer<>(livingRenderer));
|
||||||
((LivingEntityRenderer) livingRenderer).addLayer(new GlimmeringLivingLayer<>(livingRenderer));
|
((LivingEntityRenderer) livingRenderer).addLayer(new GlimmeringLivingLayer<>(livingRenderer));
|
||||||
|
((LivingEntityRenderer) livingRenderer).addLayer(new TemporalContractionAfterimageLayer<>(livingRenderer));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends LivingEntity & GeoAnimatable> GeoEntityRenderer<T> withParalyzedGeoLayer(GeoEntityRenderer<T> renderer) {
|
private static <T extends LivingEntity & GeoAnimatable> GeoEntityRenderer<T> withParalyzedGeoLayer(GeoEntityRenderer<T> renderer) {
|
||||||
renderer.addRenderLayer(new ParalyzedStoneGeoLayer<>(renderer));
|
renderer.addRenderLayer(new ParalyzedStoneGeoLayer<>(renderer));
|
||||||
renderer.addRenderLayer(new GoopedGeoLayer<>(renderer));
|
renderer.addRenderLayer(new GoopedGeoLayer<>(renderer));
|
||||||
|
renderer.addRenderLayer(new TemporalContractionGeoLayer<>(renderer));
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -1,5 +1,6 @@
|
|||||||
package com.craisinlord.antarchy.neoforge.content.fluid;
|
package com.craisinlord.antarchy.neoforge.content.fluid;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.fluid.AntiwaterBubbleColumnUtil;
|
||||||
import com.craisinlord.antarchy.neoforge.registry.AntarchyNeoforgeBlocks;
|
import com.craisinlord.antarchy.neoforge.registry.AntarchyNeoforgeBlocks;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -173,6 +174,8 @@ public abstract class AntiwaterFluid extends BaseFlowingFluid {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AntiwaterBubbleColumnUtil.update(level, pos, state);
|
||||||
|
|
||||||
if (!state.isSource() && !this.isFlowingStateValid(level, pos, state)) {
|
if (!state.isSource() && !this.isFlowingStateValid(level, pos, state)) {
|
||||||
level.setBlockAndUpdate(pos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState());
|
level.setBlockAndUpdate(pos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState());
|
||||||
this.scheduleCleanup(level, pos);
|
this.scheduleCleanup(level, pos);
|
||||||
|
|||||||
+8
-1
@@ -393,6 +393,13 @@ public final class AntarchyNeoforgeEntites {
|
|||||||
.updateInterval(2)
|
.updateInterval(2)
|
||||||
.fireImmune()
|
.fireImmune()
|
||||||
.build("royal_black_hole"));
|
.build("royal_black_hole"));
|
||||||
|
public static final DeferredHolder<EntityType<?>, EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>> ROYAL_ASSAILANT_BLACK_HOLE = ENTITY_TYPES.register("royal_assailant_black_hole",
|
||||||
|
() -> EntityType.Builder.<com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity>of(com.craisinlord.antarchy.content.entity.royal.RoyalAssailantBlackHoleEntity::new, MobCategory.MISC)
|
||||||
|
.sized(1.0F, 1.0F)
|
||||||
|
.clientTrackingRange(16)
|
||||||
|
.updateInterval(2)
|
||||||
|
.fireImmune()
|
||||||
|
.build("royal_assailant_black_hole"));
|
||||||
public static final DeferredHolder<EntityType<?>, EntityType<TimeDilationFieldEntity>> TIME_DILATION_FIELD = ENTITY_TYPES.register("time_dilation_field",
|
public static final DeferredHolder<EntityType<?>, EntityType<TimeDilationFieldEntity>> TIME_DILATION_FIELD = ENTITY_TYPES.register("time_dilation_field",
|
||||||
() -> EntityType.Builder.<TimeDilationFieldEntity>of(TimeDilationFieldEntity::new, MobCategory.MISC)
|
() -> EntityType.Builder.<TimeDilationFieldEntity>of(TimeDilationFieldEntity::new, MobCategory.MISC)
|
||||||
.sized(0.5F, 0.5F)
|
.sized(0.5F, 0.5F)
|
||||||
@@ -497,7 +504,7 @@ public final class AntarchyNeoforgeEntites {
|
|||||||
.build("lurking_terror"));
|
.build("lurking_terror"));
|
||||||
public static final DeferredHolder<EntityType<?>, EntityType<ManticoreEntity>> MANTICORE = ENTITY_TYPES.register("manticore",
|
public static final DeferredHolder<EntityType<?>, EntityType<ManticoreEntity>> MANTICORE = ENTITY_TYPES.register("manticore",
|
||||||
() -> EntityType.Builder.of(ManticoreEntity::new, MobCategory.MONSTER)
|
() -> EntityType.Builder.of(ManticoreEntity::new, MobCategory.MONSTER)
|
||||||
.sized(1.95F, 2.0F)
|
.sized(1.95F, 2.25F)
|
||||||
.clientTrackingRange(10)
|
.clientTrackingRange(10)
|
||||||
.fireImmune()
|
.fireImmune()
|
||||||
.build("manticore"));
|
.build("manticore"));
|
||||||
|
|||||||
+3
@@ -222,6 +222,9 @@ public final class AntarchyNeoforgeSounds {
|
|||||||
public static final DeferredHolder<SoundEvent, SoundEvent> KING_BEAM_SHOOT = registerSoundEvent("king_beam_shoot");
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_BEAM_SHOOT = registerSoundEvent("king_beam_shoot");
|
||||||
public static final DeferredHolder<SoundEvent, SoundEvent> KING_FIREBALL_SHOOT = registerSoundEvent("king_fireball_shoot");
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_FIREBALL_SHOOT = registerSoundEvent("king_fireball_shoot");
|
||||||
public static final DeferredHolder<SoundEvent, SoundEvent> KING_DECREE_CAST = registerSoundEvent("king_decree_cast");
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_DECREE_CAST = registerSoundEvent("king_decree_cast");
|
||||||
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_DECREE = registerSoundEvent("king_decree");
|
||||||
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_SUCCESS = registerSoundEvent("king_success");
|
||||||
|
public static final DeferredHolder<SoundEvent, SoundEvent> KING_JUDGEMENT = registerSoundEvent("king_judgement");
|
||||||
|
|
||||||
public static final DeferredHolder<SoundEvent, SoundEvent> QUEEN_IDLE = registerSoundEvent("queen_idle");
|
public static final DeferredHolder<SoundEvent, SoundEvent> QUEEN_IDLE = registerSoundEvent("queen_idle");
|
||||||
public static final DeferredHolder<SoundEvent, SoundEvent> QUEEN_WALK = registerSoundEvent("queen_walk");
|
public static final DeferredHolder<SoundEvent, SoundEvent> QUEEN_WALK = registerSoundEvent("queen_walk");
|
||||||
|
|||||||
Reference in new issue
Block a user