undertrial sounds
inverted squidzooka, rpo king and queen tweaks fix attidue adjustor bug
This commit is contained in:
1 parent
aefbfb9f32
commit
82cea4c293
8 files changed
+676
-87
No files matched your search
+262
-70
@@ -67,7 +67,9 @@ import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackLane;
|
|||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class KingEntity extends RoyalBossEntity {
|
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_TICKS = 200;
|
||||||
private static final int GROUND_ASSAULT_COOLDOWN_MIN = 600;
|
private static final int GROUND_ASSAULT_COOLDOWN_MIN = 600;
|
||||||
private static final int GROUND_ASSAULT_COOLDOWN_VARIANCE = 300;
|
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_MIN_TICKS = 45;
|
||||||
private static final int COMBAT_WAYPOINT_VARIANCE = 35;
|
private static final int COMBAT_WAYPOINT_VARIANCE = 35;
|
||||||
|
|
||||||
@@ -130,12 +135,13 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
private boolean decreeRetreatPressure;
|
private boolean decreeRetreatPressure;
|
||||||
@Nullable
|
@Nullable
|
||||||
private String lastDecreeKey;
|
private String lastDecreeKey;
|
||||||
private boolean closeQuartersEntered;
|
private final Set<UUID> closeQuartersEntered = new HashSet<>();
|
||||||
private int closeQuartersOutsideTicks;
|
private final Map<UUID, Integer> closeQuartersOutsideTicks = new HashMap<>();
|
||||||
|
private final Set<UUID> decreeRecipients = new HashSet<>();
|
||||||
private int projectilePressure;
|
private int projectilePressure;
|
||||||
private int groundAssaultCooldownTicks = 400;
|
private int groundAssaultCooldownTicks = 400;
|
||||||
private int groundAssaultTicks;
|
private KingLandingStage kingLandingStage = KingLandingStage.AERIAL;
|
||||||
private boolean kingLandingForCombat;
|
private int kingLandingStageTicks;
|
||||||
@Nullable
|
@Nullable
|
||||||
private Vec3 kingLandingWaypoint;
|
private Vec3 kingLandingWaypoint;
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -174,6 +180,15 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
new StandTallDecree(), new StandYourGroundDecree(),
|
new StandTallDecree(), new StandYourGroundDecree(),
|
||||||
new HandsOffTheCrownDecree(), new ShowNoMercyDecree());
|
new HandsOffTheCrownDecree(), new ShowNoMercyDecree());
|
||||||
|
|
||||||
|
private enum KingLandingStage {
|
||||||
|
AERIAL,
|
||||||
|
TELEGRAPH,
|
||||||
|
DESCENT,
|
||||||
|
IMPACT,
|
||||||
|
GROUND_COMBAT,
|
||||||
|
TAKEOFF
|
||||||
|
}
|
||||||
|
|
||||||
public KingEntity(EntityType<? extends KingEntity> entityType, Level level) {
|
public KingEntity(EntityType<? extends KingEntity> entityType, Level level) {
|
||||||
super(entityType, level);
|
super(entityType, level);
|
||||||
}
|
}
|
||||||
@@ -188,6 +203,60 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
return phase.maxConcurrentHeadAttacks();
|
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
|
@Override
|
||||||
protected boolean managesOwnCombatLocomotion() {
|
protected boolean managesOwnCombatLocomotion() {
|
||||||
return true;
|
return true;
|
||||||
@@ -432,12 +501,17 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
if (this.tickCount % 20 == 0 && this.getArrowCount() > 6) {
|
if (this.tickCount % 20 == 0 && this.getArrowCount() > 6) {
|
||||||
this.setArrowCount(6);
|
this.setArrowCount(6);
|
||||||
}
|
}
|
||||||
|
if (this.isRoyalPhaseTransitionActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
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);
|
||||||
this.tickDecree(level, target);
|
this.tickDecree(level, target);
|
||||||
this.tickKingWholeBody(level, target);
|
|
||||||
this.tickKingCombatMovement(target);
|
this.tickKingCombatMovement(target);
|
||||||
|
if (!this.blocksRoyalAttacksForMovement()) {
|
||||||
|
this.tickKingWholeBody(level, target);
|
||||||
|
}
|
||||||
this.stabilizeKingRotation();
|
this.stabilizeKingRotation();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -627,53 +701,82 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
|
|
||||||
private void tickKingCombatMovement(LivingEntity target) {
|
private void tickKingCombatMovement(LivingEntity target) {
|
||||||
boolean closeQuarters = this.activeDecree instanceof CloseQuartersDecree;
|
boolean closeQuarters = this.activeDecree instanceof CloseQuartersDecree;
|
||||||
if (closeQuarters && this.isRoyalFlying() && !this.kingLandingForCombat) {
|
if (closeQuarters && this.isRoyalFlying() && this.kingLandingStage == KingLandingStage.AERIAL) {
|
||||||
this.beginKingLanding(target);
|
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.groundAssaultCooldownTicks-- <= 0 && target.onGround()) {
|
||||||
this.beginKingLanding(target);
|
this.beginKingLanding(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.kingLandingForCombat) {
|
switch (this.kingLandingStage) {
|
||||||
if (!target.onGround() && !closeQuarters) {
|
case TELEGRAPH -> {
|
||||||
this.kingLandingForCombat = false;
|
this.getNavigation().stop();
|
||||||
this.kingLandingWaypoint = null;
|
this.setDeltaMovement(this.getDeltaMovement().scale(0.72D));
|
||||||
this.groundAssaultCooldownTicks = 160;
|
this.tickKingLandingIndicator();
|
||||||
|
if (--this.kingLandingStageTicks <= 0) {
|
||||||
|
this.kingLandingStage = KingLandingStage.DESCENT;
|
||||||
|
this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.72F);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.kingLandingWaypoint == null) {
|
case DESCENT -> {
|
||||||
this.kingLandingWaypoint = this.findKingLandingPoint(target);
|
Vec3 landing = this.kingLandingWaypoint;
|
||||||
}
|
if (landing == null) {
|
||||||
Vec3 landing = this.kingLandingWaypoint;
|
this.resetKingCombatMovement();
|
||||||
if (landing != null) {
|
return;
|
||||||
|
}
|
||||||
this.setRoyalFlying(true);
|
this.setRoyalFlying(true);
|
||||||
this.getMoveControl().setWantedPosition(landing.x, landing.y, landing.z, 1.35D);
|
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.setRoyalFlying(false);
|
||||||
this.kingLandingForCombat = false;
|
this.setPos(this.getX(), landing.y, this.getZ());
|
||||||
this.kingLandingWaypoint = null;
|
this.kingLandingStage = KingLandingStage.IMPACT;
|
||||||
this.groundAssaultTicks = closeQuarters
|
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)
|
? Math.max(GROUND_ASSAULT_TICKS, this.activeDecreeTicks + 20)
|
||||||
: GROUND_ASSAULT_TICKS;
|
: GROUND_ASSAULT_TICKS;
|
||||||
|
this.kingLandingWaypoint = null;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
case GROUND_COMBAT -> {
|
||||||
}
|
if (closeQuarters) {
|
||||||
|
this.kingLandingStageTicks = Math.max(this.kingLandingStageTicks, this.activeDecreeTicks + 20);
|
||||||
if (!this.isRoyalFlying()) {
|
}
|
||||||
if (closeQuarters) {
|
this.getMoveControl().setWantedPosition(target.getX(), target.getY(), target.getZ(), 1.25D);
|
||||||
this.groundAssaultTicks = Math.max(this.groundAssaultTicks, this.activeDecreeTicks + 20);
|
if (--this.kingLandingStageTicks <= 0 && !closeQuarters) {
|
||||||
|
this.beginKingTakeoff(target);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
this.getMoveControl().setWantedPosition(target.getX(), target.getY(), target.getZ(), 1.25D);
|
case TAKEOFF -> {
|
||||||
if (--this.groundAssaultTicks <= 0 && !closeQuarters) {
|
if (--this.kingLandingStageTicks <= 0) {
|
||||||
this.setRoyalFlying(true);
|
this.kingLandingStage = KingLandingStage.AERIAL;
|
||||||
this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.42D, 0.0D));
|
this.groundAssaultCooldownTicks = GROUND_ASSAULT_COOLDOWN_MIN
|
||||||
this.hasImpulse = true;
|
+ this.random.nextInt(GROUND_ASSAULT_COOLDOWN_VARIANCE + 1);
|
||||||
this.groundAssaultCooldownTicks = GROUND_ASSAULT_COOLDOWN_MIN
|
this.kingCombatWaypoint = null;
|
||||||
+ this.random.nextInt(GROUND_ASSAULT_COOLDOWN_VARIANCE + 1);
|
}
|
||||||
this.kingCombatWaypoint = null;
|
return;
|
||||||
|
}
|
||||||
|
case AERIAL -> {
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.kingCombatWaypoint != null && ++this.kingCombatProgressTicks >= 40) {
|
if (this.kingCombatWaypoint != null && ++this.kingCombatProgressTicks >= 40) {
|
||||||
@@ -700,13 +803,46 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
private void beginKingLanding(LivingEntity target) {
|
private void beginKingLanding(LivingEntity target) {
|
||||||
this.kingLandingWaypoint = this.findKingLandingPoint(target);
|
this.kingLandingWaypoint = this.findKingLandingPoint(target);
|
||||||
if (this.kingLandingWaypoint != null) {
|
if (this.kingLandingWaypoint != null) {
|
||||||
this.kingLandingForCombat = true;
|
this.kingLandingStage = KingLandingStage.TELEGRAPH;
|
||||||
|
this.kingLandingStageTicks = LANDING_TELEGRAPH_TICKS;
|
||||||
this.kingCombatWaypoint = null;
|
this.kingCombatWaypoint = null;
|
||||||
|
this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 1.12F);
|
||||||
} else {
|
} else {
|
||||||
this.groundAssaultCooldownTicks = 100;
|
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
|
@Nullable
|
||||||
private Vec3 findKingLandingPoint(LivingEntity target) {
|
private Vec3 findKingLandingPoint(LivingEntity target) {
|
||||||
Vec3 away = this.position().subtract(target.position()).multiply(1.0D, 0.0D, 1.0D);
|
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() {
|
private void resetKingCombatMovement() {
|
||||||
this.kingLandingForCombat = false;
|
this.kingLandingStage = KingLandingStage.AERIAL;
|
||||||
|
this.kingLandingStageTicks = 0;
|
||||||
this.kingLandingWaypoint = null;
|
this.kingLandingWaypoint = null;
|
||||||
this.kingCombatWaypoint = null;
|
this.kingCombatWaypoint = null;
|
||||||
this.kingCombatProgressPosition = null;
|
this.kingCombatProgressPosition = null;
|
||||||
this.kingCombatWaypointTicks = 0;
|
this.kingCombatWaypointTicks = 0;
|
||||||
this.kingCombatProgressTicks = 0;
|
this.kingCombatProgressTicks = 0;
|
||||||
this.groundAssaultTicks = 0;
|
|
||||||
if (this.groundAssaultCooldownTicks <= 0) {
|
if (this.groundAssaultCooldownTicks <= 0) {
|
||||||
this.groundAssaultCooldownTicks = 400;
|
this.groundAssaultCooldownTicks = 400;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestCloseQuartersAssault(LivingEntity target) {
|
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);
|
this.beginKingLanding(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RoyalDecree.Evaluation evaluateCloseQuarters(LivingEntity target) {
|
public RoyalDecree.Evaluation evaluateCloseQuarters(LivingEntity target) {
|
||||||
|
UUID targetId = target.getUUID();
|
||||||
double distanceSquared = target.distanceToSqr(this);
|
double distanceSquared = target.distanceToSqr(this);
|
||||||
if (distanceSquared <= CLOSE_QUARTERS_RADIUS * CLOSE_QUARTERS_RADIUS) {
|
if (distanceSquared <= CLOSE_QUARTERS_RADIUS * CLOSE_QUARTERS_RADIUS) {
|
||||||
this.closeQuartersEntered = true;
|
this.closeQuartersEntered.add(targetId);
|
||||||
this.closeQuartersOutsideTicks = 0;
|
this.closeQuartersOutsideTicks.remove(targetId);
|
||||||
return RoyalDecree.Evaluation.COMPLIANT;
|
return RoyalDecree.Evaluation.COMPLIANT;
|
||||||
}
|
}
|
||||||
if (!this.closeQuartersEntered) {
|
if (!this.closeQuartersEntered.contains(targetId)) {
|
||||||
return 300 - this.activeDecreeTicks >= CLOSE_QUARTERS_APPROACH_TICKS
|
return 300 - this.activeDecreeTicks >= CLOSE_QUARTERS_APPROACH_TICKS
|
||||||
? RoyalDecree.Evaluation.VIOLATED : RoyalDecree.Evaluation.COMPLIANT;
|
? 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;
|
? RoyalDecree.Evaluation.VIOLATED : RoyalDecree.Evaluation.COMPLIANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1009,10 +1148,11 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
this.activeDecree = decree;
|
this.activeDecree = decree;
|
||||||
this.activeDecreeTicks = 300;
|
this.activeDecreeTicks = 300;
|
||||||
this.decreeCooldownTicks = 0;
|
this.decreeCooldownTicks = 0;
|
||||||
this.closeQuartersEntered = false;
|
this.closeQuartersEntered.clear();
|
||||||
this.closeQuartersOutsideTicks = 0;
|
this.closeQuartersOutsideTicks.clear();
|
||||||
|
this.decreeRecipients.clear();
|
||||||
this.projectRoyalSound(AntarchySoundEvents.KING_DECREE.get(), 4.0F, 1.0F, target);
|
this.projectRoyalSound(AntarchySoundEvents.KING_DECREE.get(), 4.0F, 1.0F, target);
|
||||||
this.sendDecreeTitle(target);
|
this.broadcastActiveDecree((ServerLevel) this.level());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1342,7 +1482,8 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
if (this.isRoyalRecoveryActive() && this.activeDecree == null) {
|
if (this.isRoyalRecoveryActive() && this.activeDecree == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(target instanceof ServerPlayer player) || !target.isAlive() || target.level() != level) {
|
List<ServerPlayer> participants = this.royalEncounterPlayers(level);
|
||||||
|
if (participants.isEmpty()) {
|
||||||
if (this.activeDecree != null) {
|
if (this.activeDecree != null) {
|
||||||
this.endDecree(target);
|
this.endDecree(target);
|
||||||
}
|
}
|
||||||
@@ -1355,28 +1496,49 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
if (this.decreeCooldownTicks-- > 0) {
|
if (this.decreeCooldownTicks-- > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
int decreeCooldown = this.decreeCooldownForPhase();
|
||||||
if (!this.beginRoyalAttack("decree", RoyalAttackLane.DECREE,
|
if (!this.beginRoyalAttack("decree", RoyalAttackLane.DECREE,
|
||||||
AntarchySettings.royalDecreeCooldownTicks(), 300)) {
|
decreeCooldown, 300)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.activeDecreeTicks = 300;
|
this.activeDecreeTicks = 300;
|
||||||
this.activeDecree = this.pickDecree(target);
|
this.activeDecree = this.pickDecree(target);
|
||||||
this.decreeRetreatPressure = false;
|
this.decreeRetreatPressure = false;
|
||||||
this.closeQuartersEntered = false;
|
this.closeQuartersEntered.clear();
|
||||||
this.closeQuartersOutsideTicks = 0;
|
this.closeQuartersOutsideTicks.clear();
|
||||||
|
this.decreeRecipients.clear();
|
||||||
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);
|
this.projectRoyalSound(AntarchySoundEvents.KING_DECREE.get(), 4.0F, 1.0F, target);
|
||||||
this.sendDecreeTitle(player);
|
this.broadcastActiveDecree(level);
|
||||||
}
|
}
|
||||||
int countdown = this.activeDecree.countdownTicks(target);
|
this.broadcastActiveDecree(level);
|
||||||
if (countdown > 0 && countdown <= 100 && this.tickCount % 20 == 0) {
|
boolean hasCompletableParticipants = false;
|
||||||
level.playSound(null, target.blockPosition(), SoundEvents.BELL_BLOCK, SoundSource.HOSTILE, 0.8F, 1.0F + countdown / 500.0F);
|
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 && hasCompletableParticipants && everyParticipantComplete) {
|
||||||
if (this.activeDecree != null
|
this.projectRoyalSound(AntarchySoundEvents.KING_SUCCESS.get(), 4.0F, 1.0F, target);
|
||||||
&& this.activeDecree.evaluate(level, this, target) == RoyalDecree.Evaluation.VIOLATED) {
|
this.endDecree(target);
|
||||||
this.failActiveDecree(target);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.activeDecree != null && --this.activeDecreeTicks <= 0) {
|
if (this.activeDecree != null && --this.activeDecreeTicks <= 0) {
|
||||||
@@ -1420,9 +1582,34 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
.withStyle(style -> style.withColor(ChatFormatting.WHITE))));
|
.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) {
|
private void endDecree(@Nullable LivingEntity target) {
|
||||||
if (target instanceof ServerPlayer player) {
|
if (this.level() instanceof ServerLevel level) {
|
||||||
player.connection.send(new ClientboundClearTitlesPacket(false));
|
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) {
|
if (this.activeDecree != null) {
|
||||||
this.lastDecreeKey = this.activeDecree.translationKey();
|
this.lastDecreeKey = this.activeDecree.translationKey();
|
||||||
@@ -1431,9 +1618,10 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
this.activeDecree = null;
|
this.activeDecree = null;
|
||||||
this.activeDecreeTicks = 0;
|
this.activeDecreeTicks = 0;
|
||||||
this.decreeRetreatPressure = false;
|
this.decreeRetreatPressure = false;
|
||||||
this.closeQuartersEntered = false;
|
this.closeQuartersEntered.clear();
|
||||||
this.closeQuartersOutsideTicks = 0;
|
this.closeQuartersOutsideTicks.clear();
|
||||||
this.decreeCooldownTicks = AntarchySettings.royalDecreeCooldownTicks();
|
this.decreeRecipients.clear();
|
||||||
|
this.decreeCooldownTicks = this.decreeCooldownForPhase();
|
||||||
this.startRoyalRecovery(40);
|
this.startRoyalRecovery(40);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1544,12 +1732,16 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.activeDecree instanceof CloseQuartersDecree && projectile) {
|
boolean decreeApplies = attacker instanceof ServerPlayer
|
||||||
this.failActiveDecree(attacker);
|
&& this.decreeRecipients.contains(attacker.getUUID());
|
||||||
} else if (this.activeDecree instanceof ComeNoCloserDecree && !projectile) {
|
if (decreeApplies) {
|
||||||
this.failActiveDecree(attacker);
|
if (this.activeDecree instanceof CloseQuartersDecree && projectile) {
|
||||||
} else if (this.activeDecree instanceof HandsOffTheCrownDecree) {
|
this.failActiveDecree(attacker);
|
||||||
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);
|
return super.hurt(source, amount);
|
||||||
|
|||||||
+315
-9
@@ -17,9 +17,16 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.core.particles.DustParticleOptions;
|
import net.minecraft.core.particles.DustParticleOptions;
|
||||||
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.chat.Component;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.sounds.SoundEvent;
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.BossEvent;
|
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 ACCELERATION_DURATION = 140;
|
||||||
private static final int BLACK_HOLE_COOLDOWN = 340;
|
private static final int BLACK_HOLE_COOLDOWN = 340;
|
||||||
private static final double QUEEN_BITE_COOLDOWN_MULTIPLIER = 1.5D;
|
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 manticoreSummonCooldownTicks;
|
||||||
private int gravityStompCooldownTicks;
|
private int gravityStompCooldownTicks;
|
||||||
@@ -75,6 +89,14 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
private int crushingGravityCooldownTicks;
|
private int crushingGravityCooldownTicks;
|
||||||
private int accelerationCooldownTicks;
|
private int accelerationCooldownTicks;
|
||||||
private int blackHoleCooldownTicks;
|
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 final int[] dreamFireballCooldownTicks = new int[3];
|
||||||
private int idleWanderCooldownTicks;
|
private int idleWanderCooldownTicks;
|
||||||
private boolean manticoreAnimationPending;
|
private boolean manticoreAnimationPending;
|
||||||
@@ -84,6 +106,15 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private BlockPos naturalTrailHome;
|
private BlockPos naturalTrailHome;
|
||||||
|
|
||||||
|
private enum QueenLandingStage {
|
||||||
|
AERIAL,
|
||||||
|
TELEGRAPH,
|
||||||
|
DESCENT,
|
||||||
|
IMPACT,
|
||||||
|
GROUND_COMBAT,
|
||||||
|
TAKEOFF
|
||||||
|
}
|
||||||
|
|
||||||
public QueenEntity(EntityType<? extends QueenEntity> entityType, Level level) {
|
public QueenEntity(EntityType<? extends QueenEntity> entityType, Level level) {
|
||||||
super(entityType, level);
|
super(entityType, level);
|
||||||
}
|
}
|
||||||
@@ -107,6 +138,64 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
return 0.72D;
|
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
|
@Override
|
||||||
protected double biteApproachSpeed() {
|
protected double biteApproachSpeed() {
|
||||||
return 1.55D;
|
return 1.55D;
|
||||||
@@ -239,9 +328,21 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
if (this.level().isClientSide || this.isDeadOrDying()) {
|
if (this.level().isClientSide || this.isDeadOrDying()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.isRoyalPhaseTransitionActive()) {
|
||||||
|
this.royalEffects.tick();
|
||||||
|
return;
|
||||||
|
}
|
||||||
LivingEntity target = this.getTarget();
|
LivingEntity target = this.getTarget();
|
||||||
if (target == null || !target.isAlive() || !this.canAttack(target)) {
|
if (target == null || !target.isAlive() || !this.canAttack(target)) {
|
||||||
|
this.resetQueenLandingSequence();
|
||||||
this.tickIdleWander();
|
this.tickIdleWander();
|
||||||
|
} else {
|
||||||
|
this.tickQueenLandingSequence(target);
|
||||||
|
}
|
||||||
|
this.tickMomentumLockTelegraph();
|
||||||
|
if (this.blocksRoyalAttacksForMovement()) {
|
||||||
|
this.royalEffects.tick();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
this.tickManticoreSummon();
|
this.tickManticoreSummon();
|
||||||
this.tickPendingManticoreAnimation();
|
this.tickPendingManticoreAnimation();
|
||||||
@@ -251,6 +352,150 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
this.royalEffects.tick();
|
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() {
|
private void tickDreamFireballs() {
|
||||||
if (this.isRoyalRecoveryActive()) return;
|
if (this.isRoyalRecoveryActive()) return;
|
||||||
if (!(this.level() instanceof ServerLevel level)) return;
|
if (!(this.level() instanceof ServerLevel level)) return;
|
||||||
@@ -478,14 +723,17 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
String[] candidates = phase == Phase.ONE && !this.isMomentumLockAvailableEarly()
|
String[] candidates = phase == Phase.ONE && !this.isMomentumLockAvailableEarly()
|
||||||
? new String[] {"gravity_stomp", "black_hole"}
|
? new String[] {"gravity_stomp", "black_hole"}
|
||||||
: new String[] {"gravity_stomp", "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.pendingPhaseSignature == Phase.TWO
|
||||||
if (!this.queenAttackReady(id, phase, majorBusy, allowOverlap)) return 0;
|
&& this.queenAttackReady("momentum_lock", phase, majorBusy, allowOverlap)
|
||||||
return switch (id) {
|
? "momentum_lock"
|
||||||
case "black_hole", "crushing_gravity" -> phase == Phase.THREE ? 5 : 3;
|
: this.attackScheduler.chooseWeighted(candidates, id -> {
|
||||||
case "momentum_lock", "acceleration" -> phase == Phase.THREE ? 4 : 2;
|
if (!this.queenAttackReady(id, phase, majorBusy, allowOverlap)) return 0;
|
||||||
default -> 4;
|
return switch (id) {
|
||||||
};
|
case "black_hole", "crushing_gravity" -> phase == Phase.THREE ? 5 : 3;
|
||||||
}, this.random);
|
case "momentum_lock", "acceleration" -> phase == Phase.THREE ? 4 : 2;
|
||||||
|
default -> 4;
|
||||||
|
};
|
||||||
|
}, this.random);
|
||||||
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;
|
||||||
@@ -495,7 +743,7 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
default -> ACCELERATION_COOLDOWN;
|
default -> ACCELERATION_COOLDOWN;
|
||||||
};
|
};
|
||||||
RoyalAttackLane lane = "black_hole".equals(selected) ? RoyalAttackLane.CENTER_HEAD : RoyalAttackLane.HAZARD;
|
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)
|
int actionRecovery = "momentum_lock".equals(selected)
|
||||||
? this.animationRecovery(55, actionWindup, 1, 14)
|
? this.animationRecovery(55, actionWindup, 1, 14)
|
||||||
: this.animationRecovery(25, actionWindup, 1, 14);
|
: this.animationRecovery(25, actionWindup, 1, 14);
|
||||||
@@ -506,12 +754,17 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
QueenEntity.this.triggerAnim("body_action", "stomp");
|
QueenEntity.this.triggerAnim("body_action", "stomp");
|
||||||
} else if ("momentum_lock".equals(selected)) {
|
} else if ("momentum_lock".equals(selected)) {
|
||||||
QueenEntity.this.triggerAnim("wing_action", "wing_gust");
|
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)) {
|
} else if ("black_hole".equals(selected)) {
|
||||||
QueenEntity.this.royalHead(RoyalHead.Slot.CENTER).startShoot();
|
QueenEntity.this.royalHead(RoyalHead.Slot.CENTER).startShoot();
|
||||||
QueenEntity.this.triggerAnim(RoyalHead.Slot.CENTER.controllerName(), "shoot");
|
QueenEntity.this.triggerAnim(RoyalHead.Slot.CENTER.controllerName(), "shoot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override public void onActive(int elapsedTicks) {
|
@Override public void onActive(int elapsedTicks) {
|
||||||
|
if ("momentum_lock".equals(selected)) {
|
||||||
|
QueenEntity.this.momentumLockTelegraphTicks = 0;
|
||||||
|
}
|
||||||
QueenEntity.this.performSelectedQueenAttack(selected, cooldown, level, target);
|
QueenEntity.this.performSelectedQueenAttack(selected, cooldown, level, target);
|
||||||
}
|
}
|
||||||
@Override public void onComplete() {
|
@Override public void onComplete() {
|
||||||
@@ -520,6 +773,9 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})) return;
|
})) return;
|
||||||
|
if ("momentum_lock".equals(selected)) {
|
||||||
|
this.pendingPhaseSignature = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performSelectedQueenAttack(String selected, int cooldown,
|
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);
|
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) {
|
private void startMomentumLock(ServerLevel level) {
|
||||||
this.momentumLockCooldownTicks = MOMENTUM_LOCK_COOLDOWN;
|
this.momentumLockCooldownTicks = MOMENTUM_LOCK_COOLDOWN;
|
||||||
this.royalEffects.start("momentum_lock", MOMENTUM_LOCK_DURATION, () -> {
|
this.royalEffects.start("momentum_lock", MOMENTUM_LOCK_DURATION, () -> {
|
||||||
@@ -755,8 +1056,11 @@ 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("MomentumLockCooldownTicks", this.momentumLockCooldownTicks);
|
||||||
|
tag.putInt("CrushingGravityCooldownTicks", this.crushingGravityCooldownTicks);
|
||||||
tag.putInt("AccelerationCooldownTicks", this.accelerationCooldownTicks);
|
tag.putInt("AccelerationCooldownTicks", this.accelerationCooldownTicks);
|
||||||
tag.putInt("BlackHoleCooldownTicks", this.blackHoleCooldownTicks);
|
tag.putInt("BlackHoleCooldownTicks", this.blackHoleCooldownTicks);
|
||||||
|
tag.putInt("QueenLandingCooldownTicks", this.queenLandingCooldownTicks);
|
||||||
if (this.naturalTrailHome != null) {
|
if (this.naturalTrailHome != null) {
|
||||||
tag.putLong("NaturalTrailSiteId", this.naturalTrailSiteId);
|
tag.putLong("NaturalTrailSiteId", this.naturalTrailSiteId);
|
||||||
tag.putLong("NaturalTrailHome", this.naturalTrailHome.asLong());
|
tag.putLong("NaturalTrailHome", this.naturalTrailHome.asLong());
|
||||||
@@ -772,6 +1076,8 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
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"));
|
||||||
this.blackHoleCooldownTicks = Math.max(0, tag.getInt("BlackHoleCooldownTicks"));
|
this.blackHoleCooldownTicks = Math.max(0, tag.getInt("BlackHoleCooldownTicks"));
|
||||||
|
this.queenLandingCooldownTicks = tag.contains("QueenLandingCooldownTicks")
|
||||||
|
? Math.max(0, tag.getInt("QueenLandingCooldownTicks")) : 300;
|
||||||
if (tag.contains("NaturalTrailHome")) {
|
if (tag.contains("NaturalTrailHome")) {
|
||||||
this.naturalTrailSiteId = tag.getLong("NaturalTrailSiteId");
|
this.naturalTrailSiteId = tag.getLong("NaturalTrailSiteId");
|
||||||
this.naturalTrailHome = BlockPos.of(tag.getLong("NaturalTrailHome"));
|
this.naturalTrailHome = BlockPos.of(tag.getLong("NaturalTrailHome"));
|
||||||
|
|||||||
+76
-1
@@ -15,6 +15,7 @@ import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
|||||||
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -186,6 +187,10 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
private Vec3 aerialCombatAnchor;
|
private Vec3 aerialCombatAnchor;
|
||||||
private int aerialCombatAnchorTicks;
|
private int aerialCombatAnchorTicks;
|
||||||
private int recoveryWindowTicks;
|
private int recoveryWindowTicks;
|
||||||
|
@Nullable
|
||||||
|
private Phase trackedPhase;
|
||||||
|
private int phaseTransitionTicks;
|
||||||
|
private int phaseTransitionDuration;
|
||||||
private boolean multiplayerScalingInitialized;
|
private boolean multiplayerScalingInitialized;
|
||||||
private final Set<UUID> encounterParticipants = new HashSet<>();
|
private final Set<UUID> encounterParticipants = new HashSet<>();
|
||||||
private double royalDamageMultiplier = 1.0D;
|
private double royalDamageMultiplier = 1.0D;
|
||||||
@@ -297,6 +302,24 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
return 1.3D;
|
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. */
|
/** Allows a boss to tune its head-bite concurrency without changing the other royal boss. */
|
||||||
protected int maxConcurrentHeadAttacks(Phase phase) {
|
protected int maxConcurrentHeadAttacks(Phase phase) {
|
||||||
return phase.maxConcurrentHeadAttacks();
|
return phase.maxConcurrentHeadAttacks();
|
||||||
@@ -462,7 +485,8 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
if (this.level().isClientSide) {
|
if (this.level().isClientSide) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.isRoyalFlying() && !this.isDeadOrDying() && !this.landingForCombat) {
|
if (this.isRoyalFlying() && !this.isDeadOrDying() && !this.landingForCombat
|
||||||
|
&& !this.blocksRoyalAttacksForMovement()) {
|
||||||
this.tickFlyingAltitude();
|
this.tickFlyingAltitude();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,6 +504,23 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
return;
|
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();
|
LivingEntity primaryTarget = this.getTarget();
|
||||||
if (primaryTarget == null || !primaryTarget.isAlive() || !this.canAttack(primaryTarget)) {
|
if (primaryTarget == null || !primaryTarget.isAlive() || !this.canAttack(primaryTarget)) {
|
||||||
for (RoyalHead head : this.heads) {
|
for (RoyalHead head : this.heads) {
|
||||||
@@ -491,6 +532,9 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
this.initializeMultiplayerScaling(primaryTarget);
|
this.initializeMultiplayerScaling(primaryTarget);
|
||||||
|
|
||||||
this.tickCombatLocomotionMode(primaryTarget);
|
this.tickCombatLocomotionMode(primaryTarget);
|
||||||
|
if (this.blocksRoyalAttacksForMovement()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
boolean aeriallyStabilized = this.steerTowardTarget(primaryTarget);
|
boolean aeriallyStabilized = this.steerTowardTarget(primaryTarget);
|
||||||
if (!aeriallyStabilized) {
|
if (!aeriallyStabilized) {
|
||||||
this.getLookControl().setLookAt(primaryTarget, 30.0F, 30.0F);
|
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);
|
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<ServerPlayer> royalEncounterPlayers(ServerLevel level) {
|
||||||
|
double range = Math.max(32.0D, this.getAttributeValue(Attributes.FOLLOW_RANGE));
|
||||||
|
LinkedHashSet<ServerPlayer> 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) {
|
private void initializeMultiplayerScaling(LivingEntity target) {
|
||||||
if (this.multiplayerScalingInitialized || !(this.level() instanceof ServerLevel level)) {
|
if (this.multiplayerScalingInitialized || !(this.level() instanceof ServerLevel level)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+15
-3
@@ -10,13 +10,25 @@ public final class KneelDecree implements RoyalDecree {
|
|||||||
public String translationKey() { return "decree.antarchy.kneel"; }
|
public String translationKey() { return "decree.antarchy.kneel"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
UUID id = target.getUUID();
|
UUID id = target.getUUID();
|
||||||
if (target.isCrouching()) { deadlines.remove(id); king.clearActiveDecree(target); return; }
|
deadlines.computeIfAbsent(id, ignored -> target.tickCount + 100);
|
||||||
int deadline = deadlines.computeIfAbsent(id, ignored -> target.tickCount + 100);
|
}
|
||||||
if (target.tickCount >= deadline) { king.failActiveDecree(target); }
|
|
||||||
|
@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
|
@Override
|
||||||
public int countdownTicks(LivingEntity target) {
|
public int countdownTicks(LivingEntity target) {
|
||||||
return this.deadlines.getOrDefault(target.getUUID(), target.tickCount + 100) - target.tickCount;
|
return this.deadlines.getOrDefault(target.getUUID(), target.tickCount + 100) - target.tickCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnded() {
|
||||||
|
this.deadlines.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1245,6 +1245,10 @@
|
|||||||
"entity.antarchy.princess": "Princess",
|
"entity.antarchy.princess": "Princess",
|
||||||
"entity.antarchy.king": "The King",
|
"entity.antarchy.king": "The King",
|
||||||
"entity.antarchy.queen": "The Queen",
|
"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.manticore": "Manticore",
|
||||||
"entity.antarchy.royal_black_hole": "Singularity",
|
"entity.antarchy.royal_black_hole": "Singularity",
|
||||||
"entity.antarchy.royal_bolt": "Royal Bolt",
|
"entity.antarchy.royal_bolt": "Royal Bolt",
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"sender": "bloxiclean@antmail.com",
|
"sender": "bloxiclean@antmail.com",
|
||||||
"subject": "IS YOUR HIVE QUEEN DUSTY?",
|
"subject": "IS YOUR CARPET DIRTY?",
|
||||||
"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.",
|
"body": "Bloxiclean now offers premium royal-area cleaning. We remove ash, ichor, bloodglass dust, and other difficult stains. Prices may vary by dimension.",
|
||||||
"trigger": {
|
"trigger": {
|
||||||
"type": "random",
|
"type": "random",
|
||||||
"value": 0.01
|
"value": 0.01
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"sender": "bloxiclean@antmail.com",
|
"sender": "bloxiclean@antmail.com",
|
||||||
"subject": "BLOXICLEAN: WE MAKE BLOCKS SPARKLE",
|
"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": {
|
"trigger": {
|
||||||
"type": "random",
|
"type": "random",
|
||||||
"value": 0.01
|
"value": 0.01
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"sender": "dr_traeoris@antmail.com",
|
"sender": "noreply@antmail.com",
|
||||||
"subject": "WELCOME TO ANTMAIL",
|
"subject": "WELCOME TO ANTMAIL",
|
||||||
"body": "Your address has been registered. If this message arrived late, the network probably had ants in it.",
|
"body": "Your address has been registered. If this message arrived late, the network probably had ants in it.",
|
||||||
"trigger": {
|
"trigger": {
|
||||||
|
|||||||
Reference in new issue
Block a user