From 82cea4c293fb58459f7b0d7ee23bb8918f3d8873 Mon Sep 17 00:00:00 2001 From: craisinlord Date: Wed, 16 Sep 2026 00:05:20 -0500 Subject: [PATCH] undertrial sounds inverted squidzooka, rpo king and queen tweaks fix attidue adjustor bug --- .../content/entity/royal/KingEntity.java | 332 ++++++++++++++---- .../content/entity/royal/QueenEntity.java | 324 ++++++++++++++++- .../content/entity/royal/RoyalBossEntity.java | 77 +++- .../entity/royal/decree/KneelDecree.java | 18 +- .../resources/assets/antarchy/lang/en_us.json | 4 + .../message/bloxiclean_queen_clean.json | 4 +- .../antmail/message/bloxiclean_sparkle.json | 2 +- .../antarchy/antmail/message/welcome_day.json | 2 +- 8 files changed, 676 insertions(+), 87 deletions(-) diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/KingEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/KingEntity.java index 16c7f2ef..e59619e5 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/KingEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/KingEntity.java @@ -67,7 +67,9 @@ import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackLane; import java.util.EnumMap; import java.util.List; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.UUID; public class KingEntity extends RoyalBossEntity { @@ -102,6 +104,9 @@ public class KingEntity extends RoyalBossEntity { private static final int GROUND_ASSAULT_TICKS = 200; private static final int GROUND_ASSAULT_COOLDOWN_MIN = 600; private static final int GROUND_ASSAULT_COOLDOWN_VARIANCE = 300; + private static final int LANDING_TELEGRAPH_TICKS = 24; + private static final int LANDING_IMPACT_TICKS = 18; + private static final int TAKEOFF_TICKS = 30; private static final int COMBAT_WAYPOINT_MIN_TICKS = 45; private static final int COMBAT_WAYPOINT_VARIANCE = 35; @@ -130,12 +135,13 @@ public class KingEntity extends RoyalBossEntity { private boolean decreeRetreatPressure; @Nullable private String lastDecreeKey; - private boolean closeQuartersEntered; - private int closeQuartersOutsideTicks; + private final Set closeQuartersEntered = new HashSet<>(); + private final Map closeQuartersOutsideTicks = new HashMap<>(); + private final Set decreeRecipients = new HashSet<>(); private int projectilePressure; private int groundAssaultCooldownTicks = 400; - private int groundAssaultTicks; - private boolean kingLandingForCombat; + private KingLandingStage kingLandingStage = KingLandingStage.AERIAL; + private int kingLandingStageTicks; @Nullable private Vec3 kingLandingWaypoint; @Nullable @@ -174,6 +180,15 @@ public class KingEntity extends RoyalBossEntity { new StandTallDecree(), new StandYourGroundDecree(), new HandsOffTheCrownDecree(), new ShowNoMercyDecree()); + private enum KingLandingStage { + AERIAL, + TELEGRAPH, + DESCENT, + IMPACT, + GROUND_COMBAT, + TAKEOFF + } + public KingEntity(EntityType entityType, Level level) { super(entityType, level); } @@ -188,6 +203,60 @@ public class KingEntity extends RoyalBossEntity { return phase.maxConcurrentHeadAttacks(); } + @Override + protected boolean blocksRoyalAttacksForMovement() { + return this.kingLandingStage == KingLandingStage.TELEGRAPH + || this.kingLandingStage == KingLandingStage.DESCENT + || this.kingLandingStage == KingLandingStage.IMPACT + || this.kingLandingStage == KingLandingStage.TAKEOFF; + } + + @Override + protected void onRoyalPhaseTransitionStarted(Phase previousPhase, Phase nextPhase) { + if (this.activeDecree != null) { + this.endDecree(null); + } + this.resetKingCombatMovement(); + this.setRoyalFlying(true); + this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.25D, 0.0D)); + this.getNavigation().stop(); + this.setDeltaMovement(this.getDeltaMovement().scale(0.35D)); + this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), nextPhase == Phase.THREE ? 0.72F : 0.88F); + if (this.level() instanceof ServerLevel level) { + Component title = Component.translatable(nextPhase == Phase.TWO + ? "boss.antarchy.king.phase_two" : "boss.antarchy.king.phase_three") + .withStyle(style -> style.withColor(nextPhase == Phase.TWO + ? ChatFormatting.GOLD : ChatFormatting.DARK_PURPLE).withBold(true)); + for (ServerPlayer player : this.royalEncounterPlayers(level)) { + player.connection.send(new ClientboundSetTitlesAnimationPacket(5, 45, 10)); + player.connection.send(new ClientboundSetTitleTextPacket(title)); + } + } + } + + @Override + protected void tickRoyalPhaseTransition(Phase nextPhase, int elapsedTicks, int remainingTicks) { + this.getNavigation().stop(); + this.setDeltaMovement(this.getDeltaMovement().scale(0.7D)); + if (this.level() instanceof ServerLevel level && elapsedTicks % 3 == 0) { + level.sendParticles(nextPhase == Phase.THREE ? ParticleTypes.WITCH : ParticleTypes.ENCHANT, + this.getX(), this.getY() + this.getBbHeight() * 0.55D, this.getZ(), + 18, this.getBbWidth() * 0.25D, this.getBbHeight() * 0.25D, + this.getBbWidth() * 0.25D, 0.08D); + } + } + + @Override + protected void onRoyalPhaseTransitionCompleted(Phase nextPhase) { + this.decreeCooldownTicks = 0; + this.groundAssaultCooldownTicks = nextPhase == Phase.THREE ? 0 : Math.min(this.groundAssaultCooldownTicks, 100); + if (nextPhase == Phase.THREE) { + this.fireballCooldownTicks = 0; + this.iceballCooldownTicks = 0; + this.iceSpikeCooldownTicks = 0; + } + } + @Override protected boolean managesOwnCombatLocomotion() { return true; @@ -432,12 +501,17 @@ public class KingEntity extends RoyalBossEntity { if (this.tickCount % 20 == 0 && this.getArrowCount() > 6) { this.setArrowCount(6); } + if (this.isRoyalPhaseTransitionActive()) { + return; + } LivingEntity target = this.getTarget(); if (target != null && !this.isDeadOrDying() && this.level() instanceof ServerLevel level) { this.trackBehavior(target); this.tickDecree(level, target); - this.tickKingWholeBody(level, target); this.tickKingCombatMovement(target); + if (!this.blocksRoyalAttacksForMovement()) { + this.tickKingWholeBody(level, target); + } this.stabilizeKingRotation(); return; } @@ -627,53 +701,82 @@ public class KingEntity extends RoyalBossEntity { private void tickKingCombatMovement(LivingEntity target) { boolean closeQuarters = this.activeDecree instanceof CloseQuartersDecree; - if (closeQuarters && this.isRoyalFlying() && !this.kingLandingForCombat) { + if (closeQuarters && this.isRoyalFlying() && this.kingLandingStage == KingLandingStage.AERIAL) { this.beginKingLanding(target); - } else if (!closeQuarters && this.isRoyalFlying() && !this.kingLandingForCombat + } else if (!closeQuarters && this.isRoyalFlying() && this.kingLandingStage == KingLandingStage.AERIAL && this.groundAssaultCooldownTicks-- <= 0 && target.onGround()) { this.beginKingLanding(target); } - if (this.kingLandingForCombat) { - if (!target.onGround() && !closeQuarters) { - this.kingLandingForCombat = false; - this.kingLandingWaypoint = null; - this.groundAssaultCooldownTicks = 160; + switch (this.kingLandingStage) { + case TELEGRAPH -> { + this.getNavigation().stop(); + this.setDeltaMovement(this.getDeltaMovement().scale(0.72D)); + this.tickKingLandingIndicator(); + if (--this.kingLandingStageTicks <= 0) { + this.kingLandingStage = KingLandingStage.DESCENT; + this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.72F); + } return; } - if (this.kingLandingWaypoint == null) { - this.kingLandingWaypoint = this.findKingLandingPoint(target); - } - Vec3 landing = this.kingLandingWaypoint; - if (landing != null) { + case DESCENT -> { + Vec3 landing = this.kingLandingWaypoint; + if (landing == null) { + this.resetKingCombatMovement(); + return; + } this.setRoyalFlying(true); this.getMoveControl().setWantedPosition(landing.x, landing.y, landing.z, 1.35D); - if (this.onGround() || this.getY() <= landing.y + 1.25D) { + this.tickKingLandingIndicator(); + boolean reachedLanding = this.onGround() + || this.position().distanceToSqr(landing) <= 2.25D + || this.getY() <= landing.y + 1.25D; + if (reachedLanding) { this.setRoyalFlying(false); - this.kingLandingForCombat = false; - this.kingLandingWaypoint = null; - this.groundAssaultTicks = closeQuarters + this.setPos(this.getX(), landing.y, this.getZ()); + this.kingLandingStage = KingLandingStage.IMPACT; + this.kingLandingStageTicks = LANDING_IMPACT_TICKS; + this.triggerAnim("body_action", "stomp"); + this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 0.68F); + if (this.level() instanceof ServerLevel level) { + this.performStomp(level, target); + } + } + return; + } + case IMPACT -> { + this.getNavigation().stop(); + this.setDeltaMovement(Vec3.ZERO); + if (--this.kingLandingStageTicks <= 0) { + this.kingLandingStage = KingLandingStage.GROUND_COMBAT; + this.kingLandingStageTicks = closeQuarters ? Math.max(GROUND_ASSAULT_TICKS, this.activeDecreeTicks + 20) : GROUND_ASSAULT_TICKS; + this.kingLandingWaypoint = null; } + return; } - return; - } - - if (!this.isRoyalFlying()) { - if (closeQuarters) { - this.groundAssaultTicks = Math.max(this.groundAssaultTicks, this.activeDecreeTicks + 20); + case GROUND_COMBAT -> { + if (closeQuarters) { + this.kingLandingStageTicks = Math.max(this.kingLandingStageTicks, this.activeDecreeTicks + 20); + } + this.getMoveControl().setWantedPosition(target.getX(), target.getY(), target.getZ(), 1.25D); + if (--this.kingLandingStageTicks <= 0 && !closeQuarters) { + this.beginKingTakeoff(target); + } + return; } - this.getMoveControl().setWantedPosition(target.getX(), target.getY(), target.getZ(), 1.25D); - if (--this.groundAssaultTicks <= 0 && !closeQuarters) { - this.setRoyalFlying(true); - this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.42D, 0.0D)); - this.hasImpulse = true; - this.groundAssaultCooldownTicks = GROUND_ASSAULT_COOLDOWN_MIN - + this.random.nextInt(GROUND_ASSAULT_COOLDOWN_VARIANCE + 1); - this.kingCombatWaypoint = null; + case TAKEOFF -> { + if (--this.kingLandingStageTicks <= 0) { + this.kingLandingStage = KingLandingStage.AERIAL; + this.groundAssaultCooldownTicks = GROUND_ASSAULT_COOLDOWN_MIN + + this.random.nextInt(GROUND_ASSAULT_COOLDOWN_VARIANCE + 1); + this.kingCombatWaypoint = null; + } + return; + } + case AERIAL -> { } - return; } if (this.kingCombatWaypoint != null && ++this.kingCombatProgressTicks >= 40) { @@ -700,13 +803,46 @@ public class KingEntity extends RoyalBossEntity { private void beginKingLanding(LivingEntity target) { this.kingLandingWaypoint = this.findKingLandingPoint(target); if (this.kingLandingWaypoint != null) { - this.kingLandingForCombat = true; + this.kingLandingStage = KingLandingStage.TELEGRAPH; + this.kingLandingStageTicks = LANDING_TELEGRAPH_TICKS; this.kingCombatWaypoint = null; + this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 1.12F); } else { this.groundAssaultCooldownTicks = 100; } } + private void beginKingTakeoff(LivingEntity target) { + this.kingLandingStage = KingLandingStage.TAKEOFF; + this.kingLandingStageTicks = TAKEOFF_TICKS; + this.triggerAnim("wing_action", "wing_gust"); + this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.92F); + if (this.level() instanceof ServerLevel level) { + this.performWingGust(level, target); + } + this.setRoyalFlying(true); + this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.42D, 0.0D)); + this.hasImpulse = true; + } + + private void tickKingLandingIndicator() { + if (!(this.level() instanceof ServerLevel level) || this.kingLandingWaypoint == null + || this.tickCount % 2 != 0) { + return; + } + double progress = this.kingLandingStage == KingLandingStage.TELEGRAPH + ? 1.0D - this.kingLandingStageTicks / (double) LANDING_TELEGRAPH_TICKS : 1.0D; + double radius = Mth.lerp(progress, 4.0D, STOMP_RADIUS); + for (int index = 0; index < 36; index++) { + double angle = Mth.TWO_PI * index / 36.0D; + level.sendParticles(ParticleTypes.ENCHANT, + this.kingLandingWaypoint.x + Math.cos(angle) * radius, + this.kingLandingWaypoint.y + 0.2D, + this.kingLandingWaypoint.z + Math.sin(angle) * radius, + 1, 0.0D, 0.02D, 0.0D, 0.0D); + } + } + @Nullable private Vec3 findKingLandingPoint(LivingEntity target) { Vec3 away = this.position().subtract(target.position()).multiply(1.0D, 0.0D, 1.0D); @@ -765,36 +901,39 @@ public class KingEntity extends RoyalBossEntity { } private void resetKingCombatMovement() { - this.kingLandingForCombat = false; + this.kingLandingStage = KingLandingStage.AERIAL; + this.kingLandingStageTicks = 0; this.kingLandingWaypoint = null; this.kingCombatWaypoint = null; this.kingCombatProgressPosition = null; this.kingCombatWaypointTicks = 0; this.kingCombatProgressTicks = 0; - this.groundAssaultTicks = 0; if (this.groundAssaultCooldownTicks <= 0) { this.groundAssaultCooldownTicks = 400; } } public void requestCloseQuartersAssault(LivingEntity target) { - if (target != null && target.isAlive() && this.isRoyalFlying() && !this.kingLandingForCombat) { + if (target != null && target.isAlive() && this.isRoyalFlying() + && this.kingLandingStage == KingLandingStage.AERIAL) { this.beginKingLanding(target); } } public RoyalDecree.Evaluation evaluateCloseQuarters(LivingEntity target) { + UUID targetId = target.getUUID(); double distanceSquared = target.distanceToSqr(this); if (distanceSquared <= CLOSE_QUARTERS_RADIUS * CLOSE_QUARTERS_RADIUS) { - this.closeQuartersEntered = true; - this.closeQuartersOutsideTicks = 0; + this.closeQuartersEntered.add(targetId); + this.closeQuartersOutsideTicks.remove(targetId); return RoyalDecree.Evaluation.COMPLIANT; } - if (!this.closeQuartersEntered) { + if (!this.closeQuartersEntered.contains(targetId)) { return 300 - this.activeDecreeTicks >= CLOSE_QUARTERS_APPROACH_TICKS ? RoyalDecree.Evaluation.VIOLATED : RoyalDecree.Evaluation.COMPLIANT; } - return ++this.closeQuartersOutsideTicks > CLOSE_QUARTERS_EXIT_GRACE_TICKS + int outsideTicks = this.closeQuartersOutsideTicks.merge(targetId, 1, Integer::sum); + return outsideTicks > CLOSE_QUARTERS_EXIT_GRACE_TICKS ? RoyalDecree.Evaluation.VIOLATED : RoyalDecree.Evaluation.COMPLIANT; } @@ -1009,10 +1148,11 @@ public class KingEntity extends RoyalBossEntity { this.activeDecree = decree; this.activeDecreeTicks = 300; this.decreeCooldownTicks = 0; - this.closeQuartersEntered = false; - this.closeQuartersOutsideTicks = 0; + this.closeQuartersEntered.clear(); + this.closeQuartersOutsideTicks.clear(); + this.decreeRecipients.clear(); this.projectRoyalSound(AntarchySoundEvents.KING_DECREE.get(), 4.0F, 1.0F, target); - this.sendDecreeTitle(target); + this.broadcastActiveDecree((ServerLevel) this.level()); return true; } } @@ -1342,7 +1482,8 @@ public class KingEntity extends RoyalBossEntity { if (this.isRoyalRecoveryActive() && this.activeDecree == null) { return; } - if (!(target instanceof ServerPlayer player) || !target.isAlive() || target.level() != level) { + List participants = this.royalEncounterPlayers(level); + if (participants.isEmpty()) { if (this.activeDecree != null) { this.endDecree(target); } @@ -1355,28 +1496,49 @@ public class KingEntity extends RoyalBossEntity { if (this.decreeCooldownTicks-- > 0) { return; } + int decreeCooldown = this.decreeCooldownForPhase(); if (!this.beginRoyalAttack("decree", RoyalAttackLane.DECREE, - AntarchySettings.royalDecreeCooldownTicks(), 300)) { + decreeCooldown, 300)) { return; } this.activeDecreeTicks = 300; this.activeDecree = this.pickDecree(target); this.decreeRetreatPressure = false; - this.closeQuartersEntered = false; - this.closeQuartersOutsideTicks = 0; + this.closeQuartersEntered.clear(); + this.closeQuartersOutsideTicks.clear(); + this.decreeRecipients.clear(); 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.projectRoyalSound(AntarchySoundEvents.KING_DECREE.get(), 4.0F, 1.0F, target); - this.sendDecreeTitle(player); + this.broadcastActiveDecree(level); } - int countdown = this.activeDecree.countdownTicks(target); - if (countdown > 0 && countdown <= 100 && this.tickCount % 20 == 0) { - level.playSound(null, target.blockPosition(), SoundEvents.BELL_BLOCK, SoundSource.HOSTILE, 0.8F, 1.0F + countdown / 500.0F); + this.broadcastActiveDecree(level); + boolean hasCompletableParticipants = false; + boolean everyParticipantComplete = true; + for (ServerPlayer participant : participants) { + int countdown = this.activeDecree.countdownTicks(participant); + if (countdown > 0 && countdown <= 100 && this.tickCount % 20 == 0) { + level.playSound(null, participant.blockPosition(), SoundEvents.BELL_BLOCK, + SoundSource.HOSTILE, 0.8F, 1.0F + countdown / 500.0F); + } + this.activeDecree.apply(level, this, participant); + if (this.activeDecree == null) { + return; + } + RoyalDecree.Evaluation evaluation = this.activeDecree.evaluate(level, this, participant); + if (evaluation == RoyalDecree.Evaluation.VIOLATED) { + this.failActiveDecree(participant); + return; + } + if (evaluation == RoyalDecree.Evaluation.COMPLETE) { + hasCompletableParticipants = true; + } else { + everyParticipantComplete = false; + } } - this.activeDecree.apply(level, this, target); - if (this.activeDecree != null - && this.activeDecree.evaluate(level, this, target) == RoyalDecree.Evaluation.VIOLATED) { - this.failActiveDecree(target); + if (this.activeDecree != null && hasCompletableParticipants && everyParticipantComplete) { + this.projectRoyalSound(AntarchySoundEvents.KING_SUCCESS.get(), 4.0F, 1.0F, target); + this.endDecree(target); return; } if (this.activeDecree != null && --this.activeDecreeTicks <= 0) { @@ -1420,9 +1582,34 @@ public class KingEntity extends RoyalBossEntity { .withStyle(style -> style.withColor(ChatFormatting.WHITE)))); } + private void broadcastActiveDecree(ServerLevel level) { + if (this.activeDecree == null) { + return; + } + for (ServerPlayer participant : this.royalEncounterPlayers(level)) { + if (this.decreeRecipients.add(participant.getUUID())) { + this.sendDecreeTitle(participant); + } + } + } + + private int decreeCooldownForPhase() { + double scale = switch (this.phase()) { + case ONE -> 1.0D; + case TWO -> 0.82D; + case THREE -> 0.65D; + }; + return Math.max(200, Mth.floor(AntarchySettings.royalDecreeCooldownTicks() * scale)); + } + private void endDecree(@Nullable LivingEntity target) { - if (target instanceof ServerPlayer player) { - player.connection.send(new ClientboundClearTitlesPacket(false)); + if (this.level() instanceof ServerLevel level) { + for (UUID recipientId : this.decreeRecipients) { + Player recipientPlayer = level.getPlayerByUUID(recipientId); + if (recipientPlayer instanceof ServerPlayer recipient) { + recipient.connection.send(new ClientboundClearTitlesPacket(false)); + } + } } if (this.activeDecree != null) { this.lastDecreeKey = this.activeDecree.translationKey(); @@ -1431,9 +1618,10 @@ public class KingEntity extends RoyalBossEntity { this.activeDecree = null; this.activeDecreeTicks = 0; this.decreeRetreatPressure = false; - this.closeQuartersEntered = false; - this.closeQuartersOutsideTicks = 0; - this.decreeCooldownTicks = AntarchySettings.royalDecreeCooldownTicks(); + this.closeQuartersEntered.clear(); + this.closeQuartersOutsideTicks.clear(); + this.decreeRecipients.clear(); + this.decreeCooldownTicks = this.decreeCooldownForPhase(); this.startRoyalRecovery(40); } @@ -1544,12 +1732,16 @@ public class KingEntity extends RoyalBossEntity { } } } - if (this.activeDecree instanceof CloseQuartersDecree && projectile) { - this.failActiveDecree(attacker); - } else if (this.activeDecree instanceof ComeNoCloserDecree && !projectile) { - this.failActiveDecree(attacker); - } else if (this.activeDecree instanceof HandsOffTheCrownDecree) { - this.failActiveDecree(attacker); + boolean decreeApplies = attacker instanceof ServerPlayer + && this.decreeRecipients.contains(attacker.getUUID()); + if (decreeApplies) { + if (this.activeDecree instanceof CloseQuartersDecree && projectile) { + this.failActiveDecree(attacker); + } else if (this.activeDecree instanceof ComeNoCloserDecree && !projectile) { + this.failActiveDecree(attacker); + } else if (this.activeDecree instanceof HandsOffTheCrownDecree) { + this.failActiveDecree(attacker); + } } } return super.hurt(source, amount); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/QueenEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/QueenEntity.java index d620b41d..3dbee60a 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/QueenEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/QueenEntity.java @@ -17,9 +17,16 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.particles.DustParticleOptions; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.ChatFormatting; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.BossEvent; @@ -68,6 +75,13 @@ public class QueenEntity extends RoyalBossEntity { private static final int ACCELERATION_DURATION = 140; private static final int BLACK_HOLE_COOLDOWN = 340; private static final double QUEEN_BITE_COOLDOWN_MULTIPLIER = 1.5D; + private static final int MOMENTUM_LOCK_TELEGRAPH_TICKS = 40; + private static final int LANDING_TELEGRAPH_TICKS = 30; + private static final int LANDING_IMPACT_TICKS = 18; + private static final int GROUND_COMBAT_TICKS = 140; + private static final int TAKEOFF_TICKS = 30; + private static final int LANDING_COOLDOWN_MIN = 360; + private static final int LANDING_COOLDOWN_VARIANCE = 240; private int manticoreSummonCooldownTicks; private int gravityStompCooldownTicks; @@ -75,6 +89,14 @@ public class QueenEntity extends RoyalBossEntity { private int crushingGravityCooldownTicks; private int accelerationCooldownTicks; private int blackHoleCooldownTicks; + private int momentumLockTelegraphTicks; + private int queenLandingCooldownTicks = 300; + private int queenLandingStageTicks; + private QueenLandingStage queenLandingStage = QueenLandingStage.AERIAL; + @Nullable + private Vec3 queenLandingWaypoint; + @Nullable + private Phase pendingPhaseSignature; private final int[] dreamFireballCooldownTicks = new int[3]; private int idleWanderCooldownTicks; private boolean manticoreAnimationPending; @@ -84,6 +106,15 @@ public class QueenEntity extends RoyalBossEntity { @Nullable private BlockPos naturalTrailHome; + private enum QueenLandingStage { + AERIAL, + TELEGRAPH, + DESCENT, + IMPACT, + GROUND_COMBAT, + TAKEOFF + } + public QueenEntity(EntityType entityType, Level level) { super(entityType, level); } @@ -107,6 +138,64 @@ public class QueenEntity extends RoyalBossEntity { return 0.72D; } + @Override + protected boolean managesOwnCombatLocomotion() { + return true; + } + + @Override + protected boolean blocksRoyalAttacksForMovement() { + return this.queenLandingStage == QueenLandingStage.TELEGRAPH + || this.queenLandingStage == QueenLandingStage.DESCENT + || this.queenLandingStage == QueenLandingStage.IMPACT + || this.queenLandingStage == QueenLandingStage.TAKEOFF; + } + + @Override + protected void onRoyalPhaseTransitionStarted(Phase previousPhase, Phase nextPhase) { + this.resetQueenLandingSequence(); + this.momentumLockTelegraphTicks = 0; + this.pendingPhaseSignature = null; + this.getNavigation().stop(); + this.setDeltaMovement(this.getDeltaMovement().scale(0.35D)); + this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), nextPhase == Phase.THREE ? 0.66F : 0.82F); + if (this.level() instanceof ServerLevel level) { + Component title = Component.translatable(nextPhase == Phase.TWO + ? "boss.antarchy.queen.phase_two" : "boss.antarchy.queen.phase_three") + .withStyle(style -> style.withColor(nextPhase == Phase.TWO + ? ChatFormatting.DARK_PURPLE : ChatFormatting.RED).withBold(true)); + for (ServerPlayer player : this.royalEncounterPlayers(level)) { + player.connection.send(new ClientboundSetTitlesAnimationPacket(5, 45, 10)); + player.connection.send(new ClientboundSetTitleTextPacket(title)); + } + } + } + + @Override + protected void tickRoyalPhaseTransition(Phase nextPhase, int elapsedTicks, int remainingTicks) { + this.getNavigation().stop(); + this.setDeltaMovement(this.getDeltaMovement().scale(0.7D)); + if (this.level() instanceof ServerLevel level && elapsedTicks % 3 == 0) { + level.sendParticles(nextPhase == Phase.THREE ? ACCEL_DUST : ParticleTypes.REVERSE_PORTAL, + this.getX(), this.getY() + this.getBbHeight() * 0.55D, this.getZ(), + 20, this.getBbWidth() * 0.25D, this.getBbHeight() * 0.25D, + this.getBbWidth() * 0.25D, 0.08D); + } + } + + @Override + protected void onRoyalPhaseTransitionCompleted(Phase nextPhase) { + if (nextPhase == Phase.TWO) { + this.momentumLockCooldownTicks = 0; + this.pendingPhaseSignature = Phase.TWO; + this.queenLandingCooldownTicks = Math.min(this.queenLandingCooldownTicks, 100); + } else if (nextPhase == Phase.THREE) { + this.accelerationCooldownTicks = 0; + this.startRoyalAcceleration(); + this.queenLandingCooldownTicks = 0; + } + } + @Override protected double biteApproachSpeed() { return 1.55D; @@ -239,9 +328,21 @@ public class QueenEntity extends RoyalBossEntity { if (this.level().isClientSide || this.isDeadOrDying()) { return; } + if (this.isRoyalPhaseTransitionActive()) { + this.royalEffects.tick(); + return; + } LivingEntity target = this.getTarget(); if (target == null || !target.isAlive() || !this.canAttack(target)) { + this.resetQueenLandingSequence(); this.tickIdleWander(); + } else { + this.tickQueenLandingSequence(target); + } + this.tickMomentumLockTelegraph(); + if (this.blocksRoyalAttacksForMovement()) { + this.royalEffects.tick(); + return; } this.tickManticoreSummon(); this.tickPendingManticoreAnimation(); @@ -251,6 +352,150 @@ public class QueenEntity extends RoyalBossEntity { this.royalEffects.tick(); } + private void tickQueenLandingSequence(LivingEntity target) { + if (this.queenLandingStage == QueenLandingStage.AERIAL && this.isRoyalFlying() + && this.queenLandingCooldownTicks-- <= 0 && target.onGround()) { + this.beginQueenLanding(target); + } + + switch (this.queenLandingStage) { + case TELEGRAPH -> { + this.getNavigation().stop(); + this.setDeltaMovement(this.getDeltaMovement().scale(0.72D)); + this.tickQueenLandingIndicator(); + if (--this.queenLandingStageTicks <= 0) { + this.queenLandingStage = QueenLandingStage.DESCENT; + this.playRoyalSound(AntarchySoundEvents.QUEEN_FLY_LOOP.get(), 0.72F); + } + } + case DESCENT -> { + Vec3 landing = this.queenLandingWaypoint; + if (landing == null) { + this.resetQueenLandingSequence(); + return; + } + this.setRoyalFlying(true); + this.getMoveControl().setWantedPosition(landing.x, landing.y, landing.z, 1.15D); + this.tickQueenLandingIndicator(); + boolean reachedLanding = this.onGround() || this.position().distanceToSqr(landing) <= 2.25D; + if (reachedLanding) { + this.setRoyalFlying(false); + this.queenLandingStage = QueenLandingStage.IMPACT; + this.queenLandingStageTicks = LANDING_IMPACT_TICKS; + this.performGravityStomp((ServerLevel) this.level(), target); + } + } + case IMPACT -> { + this.getNavigation().stop(); + this.setDeltaMovement(Vec3.ZERO); + if (--this.queenLandingStageTicks <= 0) { + this.queenLandingStage = QueenLandingStage.GROUND_COMBAT; + this.queenLandingStageTicks = GROUND_COMBAT_TICKS; + this.queenLandingWaypoint = null; + } + } + case GROUND_COMBAT -> { + if (--this.queenLandingStageTicks <= 0) { + this.beginQueenTakeoff(); + } + } + case TAKEOFF -> { + if (--this.queenLandingStageTicks <= 0) { + this.queenLandingStage = QueenLandingStage.AERIAL; + this.queenLandingCooldownTicks = LANDING_COOLDOWN_MIN + + this.random.nextInt(LANDING_COOLDOWN_VARIANCE + 1); + } + } + case AERIAL -> { + } + } + } + + private void beginQueenLanding(LivingEntity target) { + this.queenLandingWaypoint = this.findQueenLandingPoint(target); + if (this.queenLandingWaypoint == null) { + this.queenLandingCooldownTicks = 100; + return; + } + this.queenLandingStage = QueenLandingStage.TELEGRAPH; + this.queenLandingStageTicks = LANDING_TELEGRAPH_TICKS; + this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 1.08F); + } + + @Nullable + private Vec3 findQueenLandingPoint(LivingEntity target) { + Vec3 away = this.position().subtract(target.position()).multiply(1.0D, 0.0D, 1.0D); + double baseAngle = away.lengthSqr() > 1.0E-4D + ? Math.atan2(away.z, away.x) : this.random.nextDouble() * Mth.TWO_PI; + boolean inverted = AntarchyGravityApi.isGravityInverted(this); + double[] radii = {10.0D, 14.0D, 18.0D, 7.0D}; + for (int angleIndex = 0; angleIndex < 12; angleIndex++) { + double angle = baseAngle + angleIndex * Mth.TWO_PI / 12.0D; + for (double radius : radii) { + double x = target.getX() + Math.cos(angle) * radius; + double z = target.getZ() + Math.sin(angle) * radius; + double y = inverted + ? target.getY() + target.getBbHeight() - this.getBbHeight() + : this.groundYBelow(x, z) + 0.1D; + Vec3 candidate = new Vec3(x, y, z); + AABB box = this.getBoundingBox().move( + candidate.x - this.getX(), candidate.y - this.getY(), candidate.z - this.getZ()); + if (this.level().noCollision(this, box)) { + return candidate; + } + } + } + return null; + } + + private void tickQueenLandingIndicator() { + if (!(this.level() instanceof ServerLevel level) || this.queenLandingWaypoint == null + || this.tickCount % 2 != 0) { + return; + } + double progress = this.queenLandingStage == QueenLandingStage.TELEGRAPH + ? 1.0D - this.queenLandingStageTicks / (double) LANDING_TELEGRAPH_TICKS : 1.0D; + double radius = Mth.lerp(progress, 4.0D, 18.0D); + double indicatorY = this.queenLandingWaypoint.y + + (AntarchyGravityApi.isGravityInverted(this) ? this.getBbHeight() : 0.2D); + for (int index = 0; index < 40; index++) { + double angle = Mth.TWO_PI * index / 40.0D; + level.sendParticles(ParticleTypes.REVERSE_PORTAL, + this.queenLandingWaypoint.x + Math.cos(angle) * radius, + indicatorY, + this.queenLandingWaypoint.z + Math.sin(angle) * radius, + 1, 0.0D, 0.0D, 0.0D, 0.0D); + } + } + + private void beginQueenTakeoff() { + this.queenLandingStage = QueenLandingStage.TAKEOFF; + this.queenLandingStageTicks = TAKEOFF_TICKS; + this.triggerAnim("wing_action", "wing_gust"); + this.playRoyalSound(AntarchySoundEvents.QUEEN_FLY_LOOP.get(), 0.9F); + if (this.level() instanceof ServerLevel level) { + level.sendParticles(ParticleTypes.REVERSE_PORTAL, + this.getX(), this.getY() + this.getBbHeight() * 0.4D, this.getZ(), + 60, 7.0D, 1.0D, 7.0D, 0.12D); + } + this.setRoyalFlying(true); + double lift = AntarchyGravityApi.isGravityInverted(this) ? -0.42D : 0.42D; + this.setDeltaMovement(this.getDeltaMovement().add(0.0D, lift, 0.0D)); + this.hasImpulse = true; + } + + private void resetQueenLandingSequence() { + if (this.queenLandingStage != QueenLandingStage.AERIAL) { + this.setRoyalFlying(true); + } + this.queenLandingStage = QueenLandingStage.AERIAL; + this.queenLandingStageTicks = 0; + this.queenLandingWaypoint = null; + if (this.queenLandingCooldownTicks <= 0) { + this.queenLandingCooldownTicks = 100; + } + } + private void tickDreamFireballs() { if (this.isRoyalRecoveryActive()) return; if (!(this.level() instanceof ServerLevel level)) return; @@ -478,14 +723,17 @@ public class QueenEntity extends RoyalBossEntity { String[] candidates = phase == Phase.ONE && !this.isMomentumLockAvailableEarly() ? new String[] {"gravity_stomp", "black_hole"} : new String[] {"gravity_stomp", "black_hole", "momentum_lock", "crushing_gravity", "acceleration"}; - String selected = this.attackScheduler.chooseWeighted(candidates, id -> { - if (!this.queenAttackReady(id, phase, majorBusy, allowOverlap)) return 0; - return switch (id) { - case "black_hole", "crushing_gravity" -> phase == Phase.THREE ? 5 : 3; - case "momentum_lock", "acceleration" -> phase == Phase.THREE ? 4 : 2; - default -> 4; - }; - }, this.random); + String selected = this.pendingPhaseSignature == Phase.TWO + && this.queenAttackReady("momentum_lock", phase, majorBusy, allowOverlap) + ? "momentum_lock" + : this.attackScheduler.chooseWeighted(candidates, id -> { + if (!this.queenAttackReady(id, phase, majorBusy, allowOverlap)) return 0; + return switch (id) { + case "black_hole", "crushing_gravity" -> phase == Phase.THREE ? 5 : 3; + case "momentum_lock", "acceleration" -> phase == Phase.THREE ? 4 : 2; + default -> 4; + }; + }, this.random); if (selected == null) return; int cooldown = switch (selected) { case "gravity_stomp" -> GRAVITY_STOMP_COOLDOWN; @@ -495,7 +743,7 @@ public class QueenEntity extends RoyalBossEntity { default -> ACCELERATION_COOLDOWN; }; RoyalAttackLane lane = "black_hole".equals(selected) ? RoyalAttackLane.CENTER_HEAD : RoyalAttackLane.HAZARD; - int actionWindup = 10; + int actionWindup = "momentum_lock".equals(selected) ? MOMENTUM_LOCK_TELEGRAPH_TICKS : 10; int actionRecovery = "momentum_lock".equals(selected) ? this.animationRecovery(55, actionWindup, 1, 14) : this.animationRecovery(25, actionWindup, 1, 14); @@ -506,12 +754,17 @@ public class QueenEntity extends RoyalBossEntity { QueenEntity.this.triggerAnim("body_action", "stomp"); } else if ("momentum_lock".equals(selected)) { QueenEntity.this.triggerAnim("wing_action", "wing_gust"); + QueenEntity.this.momentumLockTelegraphTicks = MOMENTUM_LOCK_TELEGRAPH_TICKS; + QueenEntity.this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 0.58F); } 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) { + if ("momentum_lock".equals(selected)) { + QueenEntity.this.momentumLockTelegraphTicks = 0; + } QueenEntity.this.performSelectedQueenAttack(selected, cooldown, level, target); } @Override public void onComplete() { @@ -520,6 +773,9 @@ public class QueenEntity extends RoyalBossEntity { } } })) return; + if ("momentum_lock".equals(selected)) { + this.pendingPhaseSignature = null; + } } private void performSelectedQueenAttack(String selected, int cooldown, @@ -599,6 +855,51 @@ public class QueenEntity extends RoyalBossEntity { 30, 0.6D, 0.6D, 0.6D, 0.25D); } + private void tickMomentumLockTelegraph() { + if (this.momentumLockTelegraphTicks <= 0 || !(this.level() instanceof ServerLevel level)) { + return; + } + this.getNavigation().stop(); + this.setDeltaMovement(Vec3.ZERO); + int elapsed = MOMENTUM_LOCK_TELEGRAPH_TICKS - this.momentumLockTelegraphTicks; + if (this.tickCount % 2 == 0) { + double inwardRadius = Mth.lerp(elapsed / (double) MOMENTUM_LOCK_TELEGRAPH_TICKS, + MOMENTUM_LOCK_RADIUS, 2.0D); + for (int index = 0; index < 48; index++) { + double angle = Mth.TWO_PI * index / 48.0D; + double cos = Math.cos(angle); + double sin = Math.sin(angle); + level.sendParticles(ParticleTypes.END_ROD, + this.getX() + cos * MOMENTUM_LOCK_RADIUS, + this.getY() + this.getBbHeight() * 0.45D, + this.getZ() + sin * MOMENTUM_LOCK_RADIUS, + 1, 0.0D, 0.0D, 0.0D, 0.0D); + if (index % 2 == 0) { + level.sendParticles(ParticleTypes.REVERSE_PORTAL, + this.getX() + cos * inwardRadius, + this.getY() + this.getBbHeight() * 0.45D, + this.getZ() + sin * inwardRadius, + 1, 0.0D, 0.0D, 0.0D, 0.0D); + } + } + } + if (this.momentumLockTelegraphTicks <= 10) { + for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, + this.getBoundingBox().inflate(MOMENTUM_LOCK_RADIUS), this::canDamageWithRoyalAttack)) { + level.sendParticles(ParticleTypes.END_ROD, + living.getX(), living.getY() + living.getBbHeight() * 0.5D, living.getZ(), + 2, 0.25D, 0.35D, 0.25D, 0.0D); + } + } + if (this.momentumLockTelegraphTicks == 40 || this.momentumLockTelegraphTicks == 20 + || this.momentumLockTelegraphTicks == 10 || this.momentumLockTelegraphTicks == 4) { + float pitch = 0.65F + elapsed / (float) MOMENTUM_LOCK_TELEGRAPH_TICKS; + level.playSound(null, this.blockPosition(), SoundEvents.BEACON_POWER_SELECT, + SoundSource.HOSTILE, 2.0F, pitch); + } + this.momentumLockTelegraphTicks--; + } + private void startMomentumLock(ServerLevel level) { this.momentumLockCooldownTicks = MOMENTUM_LOCK_COOLDOWN; this.royalEffects.start("momentum_lock", MOMENTUM_LOCK_DURATION, () -> { @@ -755,8 +1056,11 @@ public class QueenEntity extends RoyalBossEntity { super.addAdditionalSaveData(tag); tag.putInt(SUMMON_COOLDOWN_KEY, this.manticoreSummonCooldownTicks); tag.putInt("GravityStompCooldownTicks", this.gravityStompCooldownTicks); + tag.putInt("MomentumLockCooldownTicks", this.momentumLockCooldownTicks); + tag.putInt("CrushingGravityCooldownTicks", this.crushingGravityCooldownTicks); tag.putInt("AccelerationCooldownTicks", this.accelerationCooldownTicks); tag.putInt("BlackHoleCooldownTicks", this.blackHoleCooldownTicks); + tag.putInt("QueenLandingCooldownTicks", this.queenLandingCooldownTicks); if (this.naturalTrailHome != null) { tag.putLong("NaturalTrailSiteId", this.naturalTrailSiteId); tag.putLong("NaturalTrailHome", this.naturalTrailHome.asLong()); @@ -772,6 +1076,8 @@ public class QueenEntity extends RoyalBossEntity { this.crushingGravityCooldownTicks = Math.max(0, tag.getInt("CrushingGravityCooldownTicks")); this.accelerationCooldownTicks = Math.max(0, tag.getInt("AccelerationCooldownTicks")); this.blackHoleCooldownTicks = Math.max(0, tag.getInt("BlackHoleCooldownTicks")); + this.queenLandingCooldownTicks = tag.contains("QueenLandingCooldownTicks") + ? Math.max(0, tag.getInt("QueenLandingCooldownTicks")) : 300; if (tag.contains("NaturalTrailHome")) { this.naturalTrailSiteId = tag.getLong("NaturalTrailSiteId"); this.naturalTrailHome = BlockPos.of(tag.getLong("NaturalTrailHome")); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBossEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBossEntity.java index ba279b3e..75cd9140 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBossEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBossEntity.java @@ -15,6 +15,7 @@ import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil; import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager; import java.util.Arrays; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.UUID; @@ -186,6 +187,10 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult private Vec3 aerialCombatAnchor; private int aerialCombatAnchorTicks; private int recoveryWindowTicks; + @Nullable + private Phase trackedPhase; + private int phaseTransitionTicks; + private int phaseTransitionDuration; private boolean multiplayerScalingInitialized; private final Set encounterParticipants = new HashSet<>(); private double royalDamageMultiplier = 1.0D; @@ -297,6 +302,24 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult return 1.3D; } + /** Prevents normal head/body scheduling while a bespoke movement sequence owns the boss. */ + protected boolean blocksRoyalAttacksForMovement() { + return false; + } + + protected int royalPhaseTransitionDuration(Phase nextPhase) { + return 50; + } + + protected void onRoyalPhaseTransitionStarted(Phase previousPhase, Phase nextPhase) { + } + + protected void tickRoyalPhaseTransition(Phase nextPhase, int elapsedTicks, int remainingTicks) { + } + + protected void onRoyalPhaseTransitionCompleted(Phase nextPhase) { + } + /** Allows a boss to tune its head-bite concurrency without changing the other royal boss. */ protected int maxConcurrentHeadAttacks(Phase phase) { return phase.maxConcurrentHeadAttacks(); @@ -462,7 +485,8 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult if (this.level().isClientSide) { return; } - if (this.isRoyalFlying() && !this.isDeadOrDying() && !this.landingForCombat) { + if (this.isRoyalFlying() && !this.isDeadOrDying() && !this.landingForCombat + && !this.blocksRoyalAttacksForMovement()) { this.tickFlyingAltitude(); } @@ -480,6 +504,23 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult return; } + Phase currentPhase = this.phase(); + if (this.trackedPhase == null) { + this.trackedPhase = currentPhase; + } else if (currentPhase != this.trackedPhase) { + Phase previousPhase = this.trackedPhase; + this.trackedPhase = currentPhase; + this.startRoyalPhaseTransition(previousPhase, currentPhase); + } + if (this.phaseTransitionTicks > 0) { + int elapsedTicks = this.phaseTransitionDuration - this.phaseTransitionTicks; + this.tickRoyalPhaseTransition(this.trackedPhase, elapsedTicks, this.phaseTransitionTicks); + if (--this.phaseTransitionTicks == 0) { + this.onRoyalPhaseTransitionCompleted(this.trackedPhase); + } + return; + } + LivingEntity primaryTarget = this.getTarget(); if (primaryTarget == null || !primaryTarget.isAlive() || !this.canAttack(primaryTarget)) { for (RoyalHead head : this.heads) { @@ -491,6 +532,9 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult this.initializeMultiplayerScaling(primaryTarget); this.tickCombatLocomotionMode(primaryTarget); + if (this.blocksRoyalAttacksForMovement()) { + return; + } boolean aeriallyStabilized = this.steerTowardTarget(primaryTarget); if (!aeriallyStabilized) { this.getLookControl().setLookAt(primaryTarget, 30.0F, 30.0F); @@ -642,6 +686,37 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult this.recoveryWindowTicks = Math.max(this.recoveryWindowTicks, ticks); } + protected final boolean isRoyalPhaseTransitionActive() { + return this.phaseTransitionTicks > 0; + } + + private void startRoyalPhaseTransition(Phase previousPhase, Phase nextPhase) { + this.phaseTransitionDuration = Math.max(1, this.royalPhaseTransitionDuration(nextPhase)); + this.phaseTransitionTicks = this.phaseTransitionDuration; + for (RoyalAttackLane lane : RoyalAttackLane.values()) { + this.attackScheduler.cancel(lane); + } + for (RoyalHead head : this.heads) { + if (head.beamActive() || head.shooting()) { + this.stopRoyalBeam(head); + } + } + this.getNavigation().stop(); + this.onRoyalPhaseTransitionStarted(previousPhase, nextPhase); + } + + /** Returns the live players currently participating in the encounter. */ + protected final List royalEncounterPlayers(ServerLevel level) { + double range = Math.max(32.0D, this.getAttributeValue(Attributes.FOLLOW_RANGE)); + LinkedHashSet players = new LinkedHashSet<>(this.bossEvent.getPlayers()); + players.addAll(level.getPlayers(player -> player.isAlive() + && !player.isSpectator() + && player.distanceToSqr(this) <= range * range)); + players.removeIf(player -> !player.isAlive() || player.isSpectator() || player.level() != level + || player.distanceToSqr(this) > range * range); + return List.copyOf(players); + } + private void initializeMultiplayerScaling(LivingEntity target) { if (this.multiplayerScalingInitialized || !(this.level() instanceof ServerLevel level)) { return; diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KneelDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KneelDecree.java index 2f817a00..aded72fe 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KneelDecree.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KneelDecree.java @@ -10,13 +10,25 @@ public final class KneelDecree implements RoyalDecree { public String translationKey() { return "decree.antarchy.kneel"; } public void apply(ServerLevel level, KingEntity king, LivingEntity target) { UUID id = target.getUUID(); - if (target.isCrouching()) { deadlines.remove(id); king.clearActiveDecree(target); return; } - int deadline = deadlines.computeIfAbsent(id, ignored -> target.tickCount + 100); - if (target.tickCount >= deadline) { king.failActiveDecree(target); } + deadlines.computeIfAbsent(id, ignored -> target.tickCount + 100); + } + + @Override + public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) { + if (target.isCrouching()) { + return Evaluation.COMPLETE; + } + int deadline = deadlines.computeIfAbsent(target.getUUID(), ignored -> target.tickCount + 100); + return target.tickCount >= deadline ? Evaluation.VIOLATED : Evaluation.COMPLIANT; } @Override public int countdownTicks(LivingEntity target) { return this.deadlines.getOrDefault(target.getUUID(), target.tickCount + 100) - target.tickCount; } + + @Override + public void onEnded() { + this.deadlines.clear(); + } } diff --git a/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json b/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json index 9ae1fb91..8be5aa82 100644 --- a/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json +++ b/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json @@ -1245,6 +1245,10 @@ "entity.antarchy.princess": "Princess", "entity.antarchy.king": "The King", "entity.antarchy.queen": "The Queen", + "boss.antarchy.king.phase_two": "THE LAW TIGHTENS", + "boss.antarchy.king.phase_three": "ROYAL JUDGMENT", + "boss.antarchy.queen.phase_two": "GRAVITY DOMINION", + "boss.antarchy.queen.phase_three": "TEMPORAL COLLAPSE", "entity.antarchy.manticore": "Manticore", "entity.antarchy.royal_black_hole": "Singularity", "entity.antarchy.royal_bolt": "Royal Bolt", diff --git a/common-1.21.1/src/main/resources/data/antarchy/antmail/message/bloxiclean_queen_clean.json b/common-1.21.1/src/main/resources/data/antarchy/antmail/message/bloxiclean_queen_clean.json index 4fb9213f..cc0b94d7 100644 --- a/common-1.21.1/src/main/resources/data/antarchy/antmail/message/bloxiclean_queen_clean.json +++ b/common-1.21.1/src/main/resources/data/antarchy/antmail/message/bloxiclean_queen_clean.json @@ -1,7 +1,7 @@ { "sender": "bloxiclean@antmail.com", - "subject": "IS YOUR HIVE QUEEN DUSTY?", - "body": "Bloxiclean now offers premium royal-area cleaning. We remove ash, ichor, bloodglass dust, and other difficult stains. Queen not included. Prices may vary by dimension.", + "subject": "IS YOUR CARPET DIRTY?", + "body": "Bloxiclean now offers premium royal-area cleaning. We remove ash, ichor, bloodglass dust, and other difficult stains. Prices may vary by dimension.", "trigger": { "type": "random", "value": 0.01 diff --git a/common-1.21.1/src/main/resources/data/antarchy/antmail/message/bloxiclean_sparkle.json b/common-1.21.1/src/main/resources/data/antarchy/antmail/message/bloxiclean_sparkle.json index 054dcbd8..b67aca46 100644 --- a/common-1.21.1/src/main/resources/data/antarchy/antmail/message/bloxiclean_sparkle.json +++ b/common-1.21.1/src/main/resources/data/antarchy/antmail/message/bloxiclean_sparkle.json @@ -1,7 +1,7 @@ { "sender": "bloxiclean@antmail.com", "subject": "BLOXICLEAN: WE MAKE BLOCKS SPARKLE", - "body": "Cobwebs? Sculk? Suspicious residue? Bloxiclean removes nearly anything from nearly anywhere. Book your complimentary pressure-wash before the stains become lore.", + "body": "Cobwebs? Sculk? Suspicious residue? Bloxiclean removes nearly anything from nearly anywhere. Book your complimentary pressure-wash before the stains become ancient history.", "trigger": { "type": "random", "value": 0.01 diff --git a/common-1.21.1/src/main/resources/data/antarchy/antmail/message/welcome_day.json b/common-1.21.1/src/main/resources/data/antarchy/antmail/message/welcome_day.json index 19ad2161..44b9f4a3 100644 --- a/common-1.21.1/src/main/resources/data/antarchy/antmail/message/welcome_day.json +++ b/common-1.21.1/src/main/resources/data/antarchy/antmail/message/welcome_day.json @@ -1,5 +1,5 @@ { - "sender": "dr_traeoris@antmail.com", + "sender": "noreply@antmail.com", "subject": "WELCOME TO ANTMAIL", "body": "Your address has been registered. If this message arrived late, the network probably had ants in it.", "trigger": {