undertrial sounds
inverted squidzooka, rpo king and queen tweaks fix attidue adjustor bug
This commit is contained in:
1 parent
fc5028a15b
commit
aefbfb9f32
25 files changed
+674
-66
No files matched your search
@@ -578,7 +578,7 @@ public final class AntarchySettings {
|
||||
private static double kingBeamTracking = 0.1D;
|
||||
private static double kingBeamTerrainRadius = 5.0D;
|
||||
private static int kingBeamTerrainCap = 192;
|
||||
private static int royalDecreeCooldownTicks = 1200;
|
||||
private static int royalDecreeCooldownTicks = 700;
|
||||
private static int kingRoyalMusterCooldownTicks = 500;
|
||||
private static int kingRoyalMusterWindupTicks = 30;
|
||||
private static int kingRoyalMusterDurationTicks = 600;
|
||||
|
||||
+25
-5
@@ -68,12 +68,32 @@ public final class QueenTrailSpawnMarkerBlockEntity extends BlockEntity {
|
||||
level.getChunk(chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
QueenEntity queen = QueenEntity.spawnFromUndersideTrail(level, marker.spawnPos, marker.homePos, marker.siteId, marker.yaw);
|
||||
if (queen != null) {
|
||||
marker.consumed = true;
|
||||
marker.queenUuid = queen.getUUID();
|
||||
marker.setChanged();
|
||||
marker.spawnNow(level);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public QueenEntity spawnNow(ServerLevel level) {
|
||||
if (!this.configured) {
|
||||
return null;
|
||||
}
|
||||
if (this.consumed) {
|
||||
if (this.queenUuid != null && level.getEntity(this.queenUuid) instanceof QueenEntity queen) {
|
||||
return queen;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
for (int chunkX = (this.spawnPos.getX() - 16) >> 4; chunkX <= (this.spawnPos.getX() + 16) >> 4; chunkX++) {
|
||||
for (int chunkZ = (this.spawnPos.getZ() - 16) >> 4; chunkZ <= (this.spawnPos.getZ() + 16) >> 4; chunkZ++) {
|
||||
level.getChunk(chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
QueenEntity queen = QueenEntity.spawnFromUndersideTrail(level, this.spawnPos, this.homePos, this.siteId, this.yaw);
|
||||
if (queen != null) {
|
||||
this.consumed = true;
|
||||
this.queenUuid = queen.getUUID();
|
||||
this.setChanged();
|
||||
}
|
||||
return queen;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
@@ -92,6 +92,10 @@ public final class UndertrialSpawnerBlockEntity extends BlockEntity implements T
|
||||
pos.getZ() + 0.5D + (level.random.nextDouble() - 0.5D) * 0.7D, 0.0D, 0.01D, 0.0D);
|
||||
}
|
||||
} else if (currentState == TrialSpawnerState.WAITING_FOR_PLAYERS && blockEntity.previousClientState != currentState) {
|
||||
ResourceLocation detectionSound = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID,
|
||||
level.random.nextBoolean() ? "undertrial_detect_player1" : "undertrial_detect_player2");
|
||||
level.playSound(null, pos, BuiltInRegistries.SOUND_EVENT.get(detectionSound),
|
||||
net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
for (int i = 0; i < 12; i++) {
|
||||
level.addParticle(blockEntity.particle("undertrial_spawner_detection"), pos.getX() + 0.5D + (level.random.nextDouble() - 0.5D) * 1.4D,
|
||||
pos.getY() + 0.15D + level.random.nextDouble() * 0.7D,
|
||||
|
||||
+5
@@ -3,6 +3,7 @@ package com.craisinlord.antarchy.content.command;
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.block.entity.QueenTrailSpawnMarkerBlockEntity;
|
||||
import com.craisinlord.antarchy.content.worldgen.thoraxis.QueenTrailGrid;
|
||||
import com.craisinlord.antarchy.content.entity.royal.QueenEntity;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import java.util.ArrayList;
|
||||
@@ -67,7 +68,11 @@ public final class QueenLocateCommand {
|
||||
if (marker == null) {
|
||||
continue;
|
||||
}
|
||||
QueenEntity queen = marker.spawnNow(thoraxis);
|
||||
BlockPos spawn = marker.getSpawnPos();
|
||||
if (queen != null) {
|
||||
spawn = BlockPos.containing(queen.position());
|
||||
}
|
||||
int distance = Mth.floor(Math.sqrt(distanceSquared(originX, originZ, site)));
|
||||
String coordinates = "[" + spawn.getX() + ", " + spawn.getY() + ", " + spawn.getZ() + "]";
|
||||
String teleportCommand = "/execute in " + THORAXIS.location() + " run tp @s "
|
||||
|
||||
+4
@@ -6,6 +6,7 @@ import com.craisinlord.antarchy.content.entity.kraken.KrakenEntity;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@@ -412,6 +413,9 @@ public class MissileSquidEntity extends Monster implements GeoEntity {
|
||||
this.launchOwnerUuid = owner != null ? owner.getUUID() : null;
|
||||
this.setTarget(null);
|
||||
this.setNoGravity(false);
|
||||
if (owner != null && AntarchyGravityApi.isGravityInverted(owner)) {
|
||||
AntarchyGravityApi.setAirborneGravityDirection(this, AntarchyGravityApi.getGravityDirection(owner), true, AntarchyGravityTransition.INSTANT);
|
||||
}
|
||||
this.setDeltaMovement(velocity);
|
||||
this.hasImpulse = true;
|
||||
this.updateAnimationState();
|
||||
|
||||
+8
@@ -357,6 +357,14 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
|
||||
public void launchAsExplosiveProjectile(net.minecraft.world.entity.Entity launcher, Vec3 velocity) {
|
||||
this.explosiveImpact = true;
|
||||
this.explosiveLauncherId = launcher != null ? launcher.getUUID() : null;
|
||||
if (launcher != null && com.craisinlord.antarchy.content.gravity.AntarchyGravityApi.isGravityInverted(launcher)) {
|
||||
com.craisinlord.antarchy.content.gravity.AntarchyGravityApi.setAirborneGravityDirection(
|
||||
this,
|
||||
com.craisinlord.antarchy.content.gravity.AntarchyGravityApi.getGravityDirection(launcher),
|
||||
true,
|
||||
com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition.INSTANT
|
||||
);
|
||||
}
|
||||
this.setDeltaMovement(velocity);
|
||||
this.hasImpulse = true;
|
||||
}
|
||||
|
||||
+130
-5
@@ -1,6 +1,7 @@
|
||||
package com.craisinlord.antarchy.content.entity.ant;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.portal.PermanentPortalType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
@@ -9,8 +10,8 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.PlayerRespawnLogic;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@@ -37,6 +38,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class AntTeleportHelper {
|
||||
private static final double COMPANION_FOLLOW_RADIUS = 16.0D;
|
||||
private static final int ARRIVAL_SEARCH_RADIUS = 24;
|
||||
private static final int ARRIVAL_VERTICAL_SEARCH = 24;
|
||||
|
||||
private AntTeleportHelper() {
|
||||
}
|
||||
@@ -256,11 +259,12 @@ public final class AntTeleportHelper {
|
||||
return safeArrivalPos;
|
||||
}
|
||||
|
||||
return createEmergencyArrivalPlatform(destination, preferredPos);
|
||||
return createEmergencyArrivalPlatform(destination, findEmergencyPlatformPosition(destination, preferredPos));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Vec3 findSafeArrivalPosition(ServerPlayer player, ServerLevel destination, BlockPos preferredPos) {
|
||||
loadArrivalSearchArea(destination, preferredPos);
|
||||
int[] yRange = getDimensionYRange(destination);
|
||||
if (yRange != null) {
|
||||
return findSafeArrivalPositionInYRange(player, destination, preferredPos, yRange[0], yRange[1]);
|
||||
@@ -277,7 +281,7 @@ public final class AntTeleportHelper {
|
||||
addArrivalCandidate(candidates, PlayerRespawnLogic.getSpawnPosInChunk(destination, new ChunkPos(adjustedPreferredPos)));
|
||||
}
|
||||
|
||||
for (int radius = 0; radius <= 4; radius++) {
|
||||
for (int radius = 0; radius <= ARRIVAL_SEARCH_RADIUS; radius++) {
|
||||
for (int xOffset = -radius; xOffset <= radius; xOffset++) {
|
||||
for (int zOffset = -radius; zOffset <= radius; zOffset++) {
|
||||
if (radius > 0 && Math.abs(xOffset) != radius && Math.abs(zOffset) != radius) {
|
||||
@@ -303,9 +307,27 @@ public final class AntTeleportHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Arrival validation needs neighboring chunks for collision checks. Load a
|
||||
* bounded area up front so unloaded terrain is not mistaken for an unsafe
|
||||
* destination and sent straight to the emergency-platform path.
|
||||
*/
|
||||
private static void loadArrivalSearchArea(ServerLevel destination, BlockPos preferredPos) {
|
||||
ChunkPos center = new ChunkPos(preferredPos);
|
||||
int chunkRadius = (ARRIVAL_SEARCH_RADIUS >> 4) + 1;
|
||||
for (int chunkX = center.x - chunkRadius; chunkX <= center.x + chunkRadius; chunkX++) {
|
||||
for (int chunkZ = center.z - chunkRadius; chunkZ <= center.z + chunkRadius; chunkZ++) {
|
||||
destination.getChunk(chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static int[] getDimensionYRange(ServerLevel destination) {
|
||||
ResourceKey<Level> dim = destination.dimension();
|
||||
if (dim == PermanentPortalType.ELYTHIA.primaryDimension()) {
|
||||
return new int[]{64, 240};
|
||||
}
|
||||
if (dim == AntarchySettings.termiteDestinationDimension()) {
|
||||
return new int[]{100, 200};
|
||||
}
|
||||
@@ -320,7 +342,48 @@ public final class AntTeleportHelper {
|
||||
|
||||
@Nullable
|
||||
private static Vec3 findSafeArrivalPositionInYRange(ServerPlayer player, ServerLevel destination, BlockPos preferredPos, int minY, int maxY) {
|
||||
for (int radius = 0; radius <= 8; radius++) {
|
||||
Set<BlockPos> surfaceCandidates = new LinkedHashSet<>();
|
||||
for (int radius = 0; radius <= ARRIVAL_SEARCH_RADIUS; radius++) {
|
||||
for (int xOff = -radius; xOff <= radius; xOff++) {
|
||||
for (int zOff = -radius; zOff <= radius; zOff++) {
|
||||
if (radius > 0 && Math.abs(xOff) != radius && Math.abs(zOff) != radius) {
|
||||
continue;
|
||||
}
|
||||
int x = preferredPos.getX() + xOff;
|
||||
int z = preferredPos.getZ() + zOff;
|
||||
BlockPos column = new BlockPos(x, preferredPos.getY(), z);
|
||||
if (!destination.hasChunkAt(column)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockPos surface = destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, column);
|
||||
addArrivalCandidate(surfaceCandidates, surface);
|
||||
addArrivalCandidate(surfaceCandidates, destination.getHeightmapPos(Heightmap.Types.WORLD_SURFACE, column));
|
||||
|
||||
for (int yOffset = 1; yOffset <= ARRIVAL_VERTICAL_SEARCH; yOffset++) {
|
||||
surfaceCandidates.add(surface.above(yOffset));
|
||||
surfaceCandidates.add(surface.below(yOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer actual generated surfaces. This is especially important in
|
||||
// Elythia, where the configured spawn height is not necessarily the
|
||||
// playable surface.
|
||||
for (BlockPos candidate : surfaceCandidates) {
|
||||
if (candidate.getY() < minY || candidate.getY() > maxY) {
|
||||
continue;
|
||||
}
|
||||
Vec3 safePos = tryFindSafeDismount(player, destination, candidate);
|
||||
if (safePos != null && safePos.y >= minY && safePos.y <= maxY) {
|
||||
return safePos;
|
||||
}
|
||||
}
|
||||
|
||||
// Heightmaps can be stale or unsuitable around structures, so retain a
|
||||
// bounded exhaustive search as a final generated-terrain attempt.
|
||||
for (int radius = 0; radius <= ARRIVAL_SEARCH_RADIUS; radius++) {
|
||||
for (int xOff = -radius; xOff <= radius; xOff++) {
|
||||
for (int zOff = -radius; zOff <= radius; zOff++) {
|
||||
if (radius > 0 && Math.abs(xOff) != radius && Math.abs(zOff) != radius) {
|
||||
@@ -412,6 +475,49 @@ public final class AntTeleportHelper {
|
||||
return new BlockPos(preferredPos.getX(), Mth.clamp(preferredPos.getY(), minY, maxY), preferredPos.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep the emergency platform grounded in generated terrain when possible.
|
||||
* A configured/shared spawn can be an arbitrary coordinate in a custom
|
||||
* dimension, so using its Y directly can strand the player in the sky.
|
||||
*/
|
||||
private static BlockPos findEmergencyPlatformPosition(ServerLevel destination, BlockPos preferredPos) {
|
||||
BlockPos best = null;
|
||||
int bestDistance = Integer.MAX_VALUE;
|
||||
int minY = destination.getMinBuildHeight() + 1;
|
||||
int maxY = destination.getMaxBuildHeight() - 2;
|
||||
|
||||
for (int radius = 0; radius <= 8; radius++) {
|
||||
for (int xOffset = -radius; xOffset <= radius; xOffset++) {
|
||||
for (int zOffset = -radius; zOffset <= radius; zOffset++) {
|
||||
if (radius > 0 && Math.abs(xOffset) != radius && Math.abs(zOffset) != radius) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockPos searchPos = preferredPos.offset(xOffset, 0, zOffset);
|
||||
if (!destination.hasChunkAt(searchPos)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockPos surface = destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, searchPos);
|
||||
if (surface.getY() < minY || surface.getY() > maxY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int distance = Math.abs(xOffset) + Math.abs(zOffset);
|
||||
if (distance < bestDistance) {
|
||||
best = surface;
|
||||
bestDistance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (best != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return best != null ? best : getClampedFallbackPosition(destination, preferredPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Last-resort landing location for custom dimensions whose generated spawn
|
||||
* area has no valid player-sized space. The normal search always runs first;
|
||||
@@ -424,7 +530,7 @@ public final class AntTeleportHelper {
|
||||
center = new BlockPos(center.getX(), Mth.clamp(center.getY(), minY, maxY), center.getZ());
|
||||
|
||||
destination.getChunkAt(center);
|
||||
BlockState platformState = Blocks.STONE.defaultBlockState();
|
||||
BlockState platformState = emergencyPlatformState(destination);
|
||||
|
||||
for (int xOffset = -2; xOffset <= 2; xOffset++) {
|
||||
for (int zOffset = -2; zOffset <= 2; zOffset++) {
|
||||
@@ -438,4 +544,23 @@ public final class AntTeleportHelper {
|
||||
|
||||
return Vec3.atBottomCenterOf(center);
|
||||
}
|
||||
|
||||
private static BlockState emergencyPlatformState(ServerLevel destination) {
|
||||
if (destination.dimension() == PermanentPortalType.ELYTHIA.primaryDimension()) {
|
||||
return PermanentPortalType.ELYTHIA.platformBlock().defaultBlockState();
|
||||
}
|
||||
if (destination.dimension() == PermanentPortalType.THORAXIS.primaryDimension()) {
|
||||
return PermanentPortalType.THORAXIS.platformBlock().defaultBlockState();
|
||||
}
|
||||
if (destination.dimension() == PermanentPortalType.CAVARYN.primaryDimension()) {
|
||||
return PermanentPortalType.CAVARYN.platformBlock().defaultBlockState();
|
||||
}
|
||||
if (destination.dimension() == Level.NETHER) {
|
||||
return Blocks.NETHERRACK.defaultBlockState();
|
||||
}
|
||||
if (destination.dimension() == Level.END) {
|
||||
return Blocks.END_STONE.defaultBlockState();
|
||||
}
|
||||
return Blocks.DIRT.defaultBlockState();
|
||||
}
|
||||
}
|
||||
+365
-21
@@ -34,6 +34,7 @@ import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.entity.projectile.Arrow;
|
||||
import net.minecraft.commands.arguments.EntityAnchorArgument;
|
||||
import net.minecraft.world.entity.projectile.Projectile;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.item.ArmorItem;
|
||||
@@ -93,6 +94,16 @@ public class KingEntity extends RoyalBossEntity {
|
||||
private static final double COME_NO_CLOSER_RADIUS = 16.0D;
|
||||
private static final int COME_NO_CLOSER_PARTICLE_INTERVAL = 4;
|
||||
private static final int COME_NO_CLOSER_PARTICLE_COUNT = 40;
|
||||
private static final double CLOSE_QUARTERS_RADIUS = 16.0D;
|
||||
private static final int CLOSE_QUARTERS_APPROACH_TICKS = 120;
|
||||
private static final int CLOSE_QUARTERS_EXIT_GRACE_TICKS = 40;
|
||||
private static final int PROJECTILE_PRESSURE_MAX = 60;
|
||||
private static final int PROJECTILE_PRESSURE_PER_HIT = 10;
|
||||
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 COMBAT_WAYPOINT_MIN_TICKS = 45;
|
||||
private static final int COMBAT_WAYPOINT_VARIANCE = 35;
|
||||
|
||||
@Nullable
|
||||
private Vec3 patrolCenter;
|
||||
@@ -105,6 +116,10 @@ public class KingEntity extends RoyalBossEntity {
|
||||
private double treePatrolAngle;
|
||||
private boolean treePatrolBound;
|
||||
private int patrolCooldownTicks;
|
||||
@Nullable
|
||||
private Vec3 treePatrolProgressPosition;
|
||||
private int treePatrolProgressTicks;
|
||||
private int treePatrolFailures;
|
||||
private int decreeCooldownTicks;
|
||||
private int activeDecreeTicks;
|
||||
private int stompCooldownTicks;
|
||||
@@ -113,6 +128,23 @@ public class KingEntity extends RoyalBossEntity {
|
||||
private int iceballCooldownTicks = 120;
|
||||
private int iceSpikeCooldownTicks = 160;
|
||||
private boolean decreeRetreatPressure;
|
||||
@Nullable
|
||||
private String lastDecreeKey;
|
||||
private boolean closeQuartersEntered;
|
||||
private int closeQuartersOutsideTicks;
|
||||
private int projectilePressure;
|
||||
private int groundAssaultCooldownTicks = 400;
|
||||
private int groundAssaultTicks;
|
||||
private boolean kingLandingForCombat;
|
||||
@Nullable
|
||||
private Vec3 kingLandingWaypoint;
|
||||
@Nullable
|
||||
private Vec3 kingCombatWaypoint;
|
||||
@Nullable
|
||||
private Vec3 kingCombatProgressPosition;
|
||||
private int kingCombatWaypointTicks;
|
||||
private int kingCombatProgressTicks;
|
||||
private int kingStrafeDirection = 1;
|
||||
private int royalBoundaryGraceTicks;
|
||||
@Nullable
|
||||
private ServerPlayer exileTarget;
|
||||
@@ -156,12 +188,20 @@ public class KingEntity extends RoyalBossEntity {
|
||||
return phase.maxConcurrentHeadAttacks();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean managesOwnCombatLocomotion() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setTreePatrolHome(Vec3 center, double minimumY, double maximumY, double angle) {
|
||||
this.treePatrolCenter = center;
|
||||
this.treePatrolMinimumY = minimumY;
|
||||
this.treePatrolMaximumY = maximumY;
|
||||
this.treePatrolAngle = angle;
|
||||
this.treePatrolWaypoint = null;
|
||||
this.treePatrolProgressPosition = null;
|
||||
this.treePatrolProgressTicks = 0;
|
||||
this.treePatrolFailures = 0;
|
||||
this.treePatrolBound = true;
|
||||
}
|
||||
|
||||
@@ -383,11 +423,22 @@ public class KingEntity extends RoyalBossEntity {
|
||||
ServerLevel serverLevel = (ServerLevel) this.level();
|
||||
this.iceBuildup.entrySet().removeIf(entry -> serverLevel.getEntity(entry.getKey()) == null);
|
||||
if (this.iceBuildup.size() > 16) this.iceBuildup.clear();
|
||||
if (this.tickCount % 10 == 0 && this.projectilePressure > 0) {
|
||||
this.projectilePressure--;
|
||||
}
|
||||
if (this.tickCount % 40 == 0) {
|
||||
this.bumpBehavior(Behavior.RANGED, -1);
|
||||
}
|
||||
if (this.tickCount % 20 == 0 && this.getArrowCount() > 6) {
|
||||
this.setArrowCount(6);
|
||||
}
|
||||
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);
|
||||
this.stabilizeKingRotation();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -395,6 +446,7 @@ public class KingEntity extends RoyalBossEntity {
|
||||
return;
|
||||
}
|
||||
this.setRoyalFlying(true);
|
||||
this.resetKingCombatMovement();
|
||||
this.decreeRetreatPressure = false;
|
||||
if (this.treePatrolBound && this.treePatrolCenter != null) {
|
||||
this.tickTreePatrol();
|
||||
@@ -416,16 +468,20 @@ public class KingEntity extends RoyalBossEntity {
|
||||
}
|
||||
|
||||
private void tickComeNoCloserIndicator() {
|
||||
if (!(this.activeDecree instanceof ComeNoCloserDecree)
|
||||
boolean keepOut = this.activeDecree instanceof ComeNoCloserDecree;
|
||||
boolean closeQuarters = this.activeDecree instanceof CloseQuartersDecree;
|
||||
if ((!keepOut && !closeQuarters)
|
||||
|| this.tickCount % COME_NO_CLOSER_PARTICLE_INTERVAL != 0
|
||||
|| !(this.level() instanceof ServerLevel serverLevel)) {
|
||||
return;
|
||||
}
|
||||
double radius = keepOut ? COME_NO_CLOSER_RADIUS : CLOSE_QUARTERS_RADIUS;
|
||||
for (int index = 0; index < COME_NO_CLOSER_PARTICLE_COUNT; index++) {
|
||||
double angle = (Math.PI * 2.0D * index) / COME_NO_CLOSER_PARTICLE_COUNT;
|
||||
double x = this.getX() + Math.cos(angle) * COME_NO_CLOSER_RADIUS;
|
||||
double z = this.getZ() + Math.sin(angle) * COME_NO_CLOSER_RADIUS;
|
||||
serverLevel.sendParticles(ParticleTypes.END_ROD, x, this.getY() + 0.25D, z,
|
||||
double x = this.getX() + Math.cos(angle) * radius;
|
||||
double z = this.getZ() + Math.sin(angle) * radius;
|
||||
serverLevel.sendParticles(keepOut ? ParticleTypes.END_ROD : ParticleTypes.ENCHANT,
|
||||
x, this.getY() + 0.25D, z,
|
||||
1, 0.0D, 0.0D, 0.0D, 0.0D);
|
||||
}
|
||||
}
|
||||
@@ -440,9 +496,25 @@ public class KingEntity extends RoyalBossEntity {
|
||||
this.treePatrolAngle -= Math.PI * 2.0D;
|
||||
}
|
||||
Vec3 waypoint = this.treePatrolWaypoint;
|
||||
if (waypoint != null && ++this.treePatrolProgressTicks >= 40) {
|
||||
if (this.treePatrolProgressPosition != null
|
||||
&& this.position().distanceToSqr(this.treePatrolProgressPosition) < 1.0D
|
||||
&& this.position().distanceToSqr(waypoint) > 36.0D) {
|
||||
this.treePatrolWaypoint = null;
|
||||
waypoint = null;
|
||||
this.treePatrolFailures++;
|
||||
this.treePatrolAngle += 0.35D;
|
||||
} else {
|
||||
this.treePatrolFailures = Math.max(0, this.treePatrolFailures - 1);
|
||||
}
|
||||
this.treePatrolProgressPosition = this.position();
|
||||
this.treePatrolProgressTicks = 0;
|
||||
}
|
||||
if (waypoint == null || this.position().distanceToSqr(waypoint) < 36.0D) {
|
||||
waypoint = this.findTreePatrolWaypoint(center, this.treePatrolAngle);
|
||||
this.treePatrolWaypoint = waypoint;
|
||||
this.treePatrolProgressPosition = this.position();
|
||||
this.treePatrolProgressTicks = 0;
|
||||
}
|
||||
if (waypoint != null) {
|
||||
this.getMoveControl().setWantedPosition(waypoint.x, waypoint.y, waypoint.z, 1.0D);
|
||||
@@ -503,18 +575,40 @@ public class KingEntity extends RoyalBossEntity {
|
||||
|
||||
@Nullable
|
||||
private Vec3 findTreePatrolWaypoint(Vec3 center, double angle) {
|
||||
for (int attempt = 0; attempt < 10; attempt++) {
|
||||
double candidateAngle = angle + attempt * 0.22D;
|
||||
double x = center.x + Math.cos(candidateAngle) * TREE_ORBIT_RADIUS;
|
||||
double z = center.z + Math.sin(candidateAngle) * TREE_ORBIT_RADIUS;
|
||||
double vertical = 0.5D + 0.5D * Math.sin(candidateAngle);
|
||||
double y = this.treePatrolMinimumY
|
||||
+ (this.treePatrolMaximumY - this.treePatrolMinimumY) * vertical;
|
||||
Vec3 candidate = new Vec3(x, y, z);
|
||||
if (this.clearTreePatrolPath(candidate)) {
|
||||
return candidate;
|
||||
double currentAngle = Math.atan2(this.getZ() - center.z, this.getX() - center.x);
|
||||
double baseAngle = Double.isFinite(currentAngle) ? currentAngle + 0.24D : angle;
|
||||
double[] radii = {TREE_ORBIT_RADIUS, TREE_ORBIT_RADIUS + 20.0D, TREE_ORBIT_RADIUS - 20.0D};
|
||||
double[] heightOffsets = {0.0D, 16.0D, -12.0D, 30.0D};
|
||||
for (int angleAttempt = 0; angleAttempt < 8; angleAttempt++) {
|
||||
double candidateAngle = baseAngle + angleAttempt * 0.16D;
|
||||
for (double radius : radii) {
|
||||
double x = center.x + Math.cos(candidateAngle) * radius;
|
||||
double z = center.z + Math.sin(candidateAngle) * radius;
|
||||
double vertical = 0.5D + 0.5D * Math.sin(candidateAngle);
|
||||
double baseY = this.treePatrolMinimumY
|
||||
+ (this.treePatrolMaximumY - this.treePatrolMinimumY) * vertical;
|
||||
for (double heightOffset : heightOffsets) {
|
||||
double y = Mth.clamp(baseY + heightOffset,
|
||||
this.treePatrolMinimumY + 8.0D, this.treePatrolMaximumY - 8.0D);
|
||||
Vec3 candidate = new Vec3(x, y, z);
|
||||
if (this.clearTreePatrolPath(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vec3 outward = this.position().subtract(center).multiply(1.0D, 0.0D, 1.0D);
|
||||
if (outward.lengthSqr() < 1.0E-4D) {
|
||||
outward = new Vec3(Math.cos(angle), 0.0D, Math.sin(angle));
|
||||
}
|
||||
Vec3 tangent = new Vec3(-outward.z, 0.0D, outward.x).normalize();
|
||||
Vec3 recovery = this.position().add(tangent.scale(24.0D)).add(0.0D,
|
||||
this.treePatrolFailures >= 2 ? 18.0D : 8.0D, 0.0D);
|
||||
recovery = new Vec3(recovery.x,
|
||||
Mth.clamp(recovery.y, this.treePatrolMinimumY + 8.0D, this.treePatrolMaximumY - 8.0D), recovery.z);
|
||||
if (this.clearTreePatrolPath(recovery)) {
|
||||
return recovery;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -531,6 +625,179 @@ public class KingEntity extends RoyalBossEntity {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void tickKingCombatMovement(LivingEntity target) {
|
||||
boolean closeQuarters = this.activeDecree instanceof CloseQuartersDecree;
|
||||
if (closeQuarters && this.isRoyalFlying() && !this.kingLandingForCombat) {
|
||||
this.beginKingLanding(target);
|
||||
} else if (!closeQuarters && this.isRoyalFlying() && !this.kingLandingForCombat
|
||||
&& this.groundAssaultCooldownTicks-- <= 0 && target.onGround()) {
|
||||
this.beginKingLanding(target);
|
||||
}
|
||||
|
||||
if (this.kingLandingForCombat) {
|
||||
if (!target.onGround() && !closeQuarters) {
|
||||
this.kingLandingForCombat = false;
|
||||
this.kingLandingWaypoint = null;
|
||||
this.groundAssaultCooldownTicks = 160;
|
||||
return;
|
||||
}
|
||||
if (this.kingLandingWaypoint == null) {
|
||||
this.kingLandingWaypoint = this.findKingLandingPoint(target);
|
||||
}
|
||||
Vec3 landing = this.kingLandingWaypoint;
|
||||
if (landing != null) {
|
||||
this.setRoyalFlying(true);
|
||||
this.getMoveControl().setWantedPosition(landing.x, landing.y, landing.z, 1.35D);
|
||||
if (this.onGround() || this.getY() <= landing.y + 1.25D) {
|
||||
this.setRoyalFlying(false);
|
||||
this.kingLandingForCombat = false;
|
||||
this.kingLandingWaypoint = null;
|
||||
this.groundAssaultTicks = closeQuarters
|
||||
? Math.max(GROUND_ASSAULT_TICKS, this.activeDecreeTicks + 20)
|
||||
: GROUND_ASSAULT_TICKS;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.isRoyalFlying()) {
|
||||
if (closeQuarters) {
|
||||
this.groundAssaultTicks = Math.max(this.groundAssaultTicks, this.activeDecreeTicks + 20);
|
||||
}
|
||||
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;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.kingCombatWaypoint != null && ++this.kingCombatProgressTicks >= 40) {
|
||||
if (this.kingCombatProgressPosition != null
|
||||
&& this.position().distanceToSqr(this.kingCombatProgressPosition) < 1.0D
|
||||
&& this.position().distanceToSqr(this.kingCombatWaypoint) > 16.0D) {
|
||||
this.kingCombatWaypoint = null;
|
||||
this.kingStrafeDirection *= -1;
|
||||
}
|
||||
this.kingCombatProgressPosition = this.position();
|
||||
this.kingCombatProgressTicks = 0;
|
||||
}
|
||||
if (this.kingCombatWaypoint == null || --this.kingCombatWaypointTicks <= 0
|
||||
|| this.position().distanceToSqr(this.kingCombatWaypoint) < 16.0D) {
|
||||
this.selectKingCombatWaypoint(target);
|
||||
}
|
||||
if (this.kingCombatWaypoint != null) {
|
||||
double speed = this.projectilePressure >= 30 ? 1.4D : 1.15D;
|
||||
this.getMoveControl().setWantedPosition(this.kingCombatWaypoint.x,
|
||||
this.kingCombatWaypoint.y, this.kingCombatWaypoint.z, speed);
|
||||
}
|
||||
}
|
||||
|
||||
private void beginKingLanding(LivingEntity target) {
|
||||
this.kingLandingWaypoint = this.findKingLandingPoint(target);
|
||||
if (this.kingLandingWaypoint != null) {
|
||||
this.kingLandingForCombat = true;
|
||||
this.kingCombatWaypoint = null;
|
||||
} else {
|
||||
this.groundAssaultCooldownTicks = 100;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Vec3 findKingLandingPoint(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;
|
||||
double[] radii = {9.0D, 13.0D, 17.0D, 6.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 = 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 selectKingCombatWaypoint(LivingEntity target) {
|
||||
Vec3 radial = this.position().subtract(target.position()).multiply(1.0D, 0.0D, 1.0D);
|
||||
if (radial.lengthSqr() < 1.0E-4D) {
|
||||
radial = new Vec3(1.0D, 0.0D, 0.0D);
|
||||
}
|
||||
radial = radial.normalize();
|
||||
Vec3 tangent = new Vec3(-radial.z * this.kingStrafeDirection, 0.0D,
|
||||
radial.x * this.kingStrafeDirection);
|
||||
double range = this.activeDecree instanceof ComeNoCloserDecree || this.projectilePressure >= 30
|
||||
? 40.0D : 34.0D;
|
||||
Vec3 horizontal = target.position().add(radial.scale(range)).add(tangent.scale(12.0D));
|
||||
double groundY = this.groundYBelow(horizontal.x, horizontal.z);
|
||||
double y = Mth.clamp(target.getY() + 8.0D, groundY + FLYING_MIN_HOVER,
|
||||
groundY + FLYING_MAX_HOVER_ABOVE_GROUND);
|
||||
this.kingCombatWaypoint = new Vec3(horizontal.x, y, horizontal.z);
|
||||
this.kingCombatWaypointTicks = COMBAT_WAYPOINT_MIN_TICKS
|
||||
+ this.random.nextInt(COMBAT_WAYPOINT_VARIANCE + 1);
|
||||
this.kingCombatProgressPosition = this.position();
|
||||
this.kingCombatProgressTicks = 0;
|
||||
if (this.random.nextInt(4) == 0) {
|
||||
this.kingStrafeDirection *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void stabilizeKingRotation() {
|
||||
Vec3 movement = this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D);
|
||||
if (movement.lengthSqr() < 0.0025D) {
|
||||
return;
|
||||
}
|
||||
float desiredYaw = (float) (Mth.atan2(movement.z, movement.x) * 180.0D / Math.PI) - 90.0F;
|
||||
float turn = Mth.clamp(Mth.wrapDegrees(desiredYaw - this.getYRot()), -7.0F, 7.0F);
|
||||
this.setYRot(this.getYRot() + turn);
|
||||
this.yBodyRot = this.getYRot();
|
||||
}
|
||||
|
||||
private void resetKingCombatMovement() {
|
||||
this.kingLandingForCombat = false;
|
||||
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) {
|
||||
this.beginKingLanding(target);
|
||||
}
|
||||
}
|
||||
|
||||
public RoyalDecree.Evaluation evaluateCloseQuarters(LivingEntity target) {
|
||||
double distanceSquared = target.distanceToSqr(this);
|
||||
if (distanceSquared <= CLOSE_QUARTERS_RADIUS * CLOSE_QUARTERS_RADIUS) {
|
||||
this.closeQuartersEntered = true;
|
||||
this.closeQuartersOutsideTicks = 0;
|
||||
return RoyalDecree.Evaluation.COMPLIANT;
|
||||
}
|
||||
if (!this.closeQuartersEntered) {
|
||||
return 300 - this.activeDecreeTicks >= CLOSE_QUARTERS_APPROACH_TICKS
|
||||
? RoyalDecree.Evaluation.VIOLATED : RoyalDecree.Evaluation.COMPLIANT;
|
||||
}
|
||||
return ++this.closeQuartersOutsideTicks > CLOSE_QUARTERS_EXIT_GRACE_TICKS
|
||||
? RoyalDecree.Evaluation.VIOLATED : RoyalDecree.Evaluation.COMPLIANT;
|
||||
}
|
||||
|
||||
private void tickRoyalPunishment() {
|
||||
if (this.exileTarget == null && this.titheTarget == null && this.targetShotPlayer == null && this.sealedTarget == null) {
|
||||
return;
|
||||
@@ -742,6 +1009,8 @@ public class KingEntity extends RoyalBossEntity {
|
||||
this.activeDecree = decree;
|
||||
this.activeDecreeTicks = 300;
|
||||
this.decreeCooldownTicks = 0;
|
||||
this.closeQuartersEntered = false;
|
||||
this.closeQuartersOutsideTicks = 0;
|
||||
this.projectRoyalSound(AntarchySoundEvents.KING_DECREE.get(), 4.0F, 1.0F, target);
|
||||
this.sendDecreeTitle(target);
|
||||
return true;
|
||||
@@ -1093,6 +1362,8 @@ public class KingEntity extends RoyalBossEntity {
|
||||
this.activeDecreeTicks = 300;
|
||||
this.activeDecree = this.pickDecree(target);
|
||||
this.decreeRetreatPressure = false;
|
||||
this.closeQuartersEntered = false;
|
||||
this.closeQuartersOutsideTicks = 0;
|
||||
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);
|
||||
@@ -1115,10 +1386,19 @@ public class KingEntity extends RoyalBossEntity {
|
||||
}
|
||||
|
||||
private RoyalDecree pickDecree(LivingEntity target) {
|
||||
if ((this.projectilePressure >= 20 || this.behaviorScore(Behavior.RANGED) >= 6)
|
||||
&& !"decree.antarchy.close_quarters".equals(this.lastDecreeKey)) {
|
||||
return DECREES.stream()
|
||||
.filter(CloseQuartersDecree.class::isInstance)
|
||||
.findFirst()
|
||||
.orElse(DECREES.get(0));
|
||||
}
|
||||
int totalWeight = 0;
|
||||
int[] weights = new int[DECREES.size()];
|
||||
for (int i = 0; i < DECREES.size(); i++) {
|
||||
weights[i] = Math.max(1, DECREES.get(i).contextWeight(this, target));
|
||||
RoyalDecree decree = DECREES.get(i);
|
||||
weights[i] = decree.translationKey().equals(this.lastDecreeKey)
|
||||
? 0 : Math.max(1, decree.contextWeight(this, target));
|
||||
totalWeight += weights[i];
|
||||
}
|
||||
int roll = this.random.nextInt(totalWeight);
|
||||
@@ -1145,11 +1425,14 @@ public class KingEntity extends RoyalBossEntity {
|
||||
player.connection.send(new ClientboundClearTitlesPacket(false));
|
||||
}
|
||||
if (this.activeDecree != null) {
|
||||
this.lastDecreeKey = this.activeDecree.translationKey();
|
||||
this.activeDecree.onEnded();
|
||||
}
|
||||
this.activeDecree = null;
|
||||
this.activeDecreeTicks = 0;
|
||||
this.decreeRetreatPressure = false;
|
||||
this.closeQuartersEntered = false;
|
||||
this.closeQuartersOutsideTicks = 0;
|
||||
this.decreeCooldownTicks = AntarchySettings.royalDecreeCooldownTicks();
|
||||
this.startRoyalRecovery(40);
|
||||
}
|
||||
@@ -1166,13 +1449,63 @@ public class KingEntity extends RoyalBossEntity {
|
||||
if (this.activeDecree == null || target == null || !target.isAlive()) {
|
||||
return;
|
||||
}
|
||||
if (target instanceof ServerPlayer player) {
|
||||
this.projectRoyalSound(AntarchySoundEvents.KING_JUDGEMENT.get(), 4.0F, 1.0F, target);
|
||||
this.debugTriggerPunishment(RoyalPunishmentType.ROYAL_EXILE, player);
|
||||
} else {
|
||||
this.invokeJudgment(target);
|
||||
}
|
||||
this.attackScheduler.cancel(RoyalAttackLane.DECREE);
|
||||
this.attackScheduler.cancel(RoyalAttackLane.HAZARD);
|
||||
this.endDecree(target);
|
||||
this.projectRoyalSound(AntarchySoundEvents.KING_JUDGEMENT.get(), 4.0F, 1.0F, target);
|
||||
if (target instanceof ServerPlayer player) {
|
||||
this.sendDecreeViolationTitle(player);
|
||||
}
|
||||
this.startRoyalJudgmentBarrage(target);
|
||||
}
|
||||
|
||||
private void sendDecreeViolationTitle(ServerPlayer player) {
|
||||
player.connection.send(new ClientboundSetTitlesAnimationPacket(5, 45, 10));
|
||||
player.connection.send(new ClientboundSetTitleTextPacket(Component.translatable("decree.antarchy.violated")
|
||||
.withStyle(style -> style.withColor(ChatFormatting.DARK_PURPLE).withBold(true))));
|
||||
player.connection.send(new ClientboundSetSubtitleTextPacket(Component.translatable("decree.antarchy.violated.subtitle")
|
||||
.withStyle(style -> style.withColor(ChatFormatting.LIGHT_PURPLE))));
|
||||
}
|
||||
|
||||
private void startRoyalJudgmentBarrage(LivingEntity target) {
|
||||
if (!(this.level() instanceof ServerLevel level)) {
|
||||
return;
|
||||
}
|
||||
this.beginRoyalAttack("royal_judgment", RoyalAttackLane.HAZARD, 80,
|
||||
20, 9, 12, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||
@Override
|
||||
public void onStart() {
|
||||
for (RoyalHead.Slot slot : RoyalHead.Slot.values()) {
|
||||
KingEntity.this.triggerAnim(slot.controllerName(), "shoot");
|
||||
}
|
||||
level.sendParticles(ParticleTypes.WITCH,
|
||||
KingEntity.this.getX(), KingEntity.this.getY() + KingEntity.this.getBbHeight() * 0.7D,
|
||||
KingEntity.this.getZ(), 70, 4.0D, 3.0D, 4.0D, 0.12D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActive(int elapsedTicks) {
|
||||
if (elapsedTicks % 4 == 0 && target.isAlive() && target.level() == level) {
|
||||
KingEntity.this.fireRoyalJudgmentWave(level, target);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fireRoyalJudgmentWave(ServerLevel level, LivingEntity target) {
|
||||
Vec3 predicted = target.getEyePosition().add(target.getDeltaMovement().scale(4.0D));
|
||||
for (RoyalHead.Slot slot : RoyalHead.Slot.values()) {
|
||||
RoyalHead head = this.royalHead(slot);
|
||||
Vec3 origin = this.headAnchor(head);
|
||||
Vec3 direction = predicted.subtract(origin).normalize();
|
||||
RoyalBoltEntity bolt = new RoyalBoltEntity(AntarchyObjects.ROYAL_BOLT.get(), level);
|
||||
bolt.setOwner(this);
|
||||
bolt.setElement(RoyalBeamElement.QUEEN_PURPLE);
|
||||
bolt.setPos(origin.x, origin.y, origin.z);
|
||||
bolt.shoot(direction.x, direction.y, direction.z, 1.55F, 1.0F);
|
||||
level.addFreshEntity(bolt);
|
||||
}
|
||||
this.playRoyalSound(AntarchySoundEvents.KING_BEAM_SHOOT.get(), 1.15F);
|
||||
}
|
||||
|
||||
public boolean blocksHealing() {
|
||||
@@ -1200,6 +1533,17 @@ public class KingEntity extends RoyalBossEntity {
|
||||
this.lastPlayerDamageTime.put(attacker.getUUID(), this.level().getGameTime());
|
||||
boolean projectile = source.getDirectEntity() instanceof Projectile;
|
||||
this.bumpBehavior(projectile ? Behavior.RANGED : Behavior.HUGGING, 2);
|
||||
if (projectile) {
|
||||
this.projectilePressure = Math.min(PROJECTILE_PRESSURE_MAX,
|
||||
this.projectilePressure + PROJECTILE_PRESSURE_PER_HIT);
|
||||
if (this.isRoyalFlying() && !(this.activeDecree instanceof CloseQuartersDecree)) {
|
||||
if (this.projectilePressure >= 40) {
|
||||
amount *= 0.55F;
|
||||
} else if (this.projectilePressure >= 20) {
|
||||
amount *= 0.75F;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.activeDecree instanceof CloseQuartersDecree && projectile) {
|
||||
this.failActiveDecree(attacker);
|
||||
} else if (this.activeDecree instanceof ComeNoCloserDecree && !projectile) {
|
||||
|
||||
+6
-1
@@ -284,6 +284,11 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
return 0.35D;
|
||||
}
|
||||
|
||||
/** Lets a boss provide a bespoke air/ground cadence without changing the other royal encounter. */
|
||||
protected boolean managesOwnCombatLocomotion() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean shouldClearObstruction() {
|
||||
return true;
|
||||
}
|
||||
@@ -799,7 +804,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
}
|
||||
|
||||
private void tickCombatLocomotionMode(LivingEntity target) {
|
||||
if (!this.isFlyingBoss()) {
|
||||
if (!this.isFlyingBoss() || this.managesOwnCombatLocomotion()) {
|
||||
return;
|
||||
}
|
||||
boolean inverted = AntarchyGravityApi.isGravityInverted(this);
|
||||
|
||||
+7
-1
@@ -4,7 +4,13 @@ import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
public final class CloseQuartersDecree implements RoyalDecree {
|
||||
public String translationKey() { return "decree.antarchy.close_quarters"; }
|
||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { }
|
||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||
king.requestCloseQuartersAssault(target);
|
||||
}
|
||||
@Override
|
||||
public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||
return king.evaluateCloseQuarters(target);
|
||||
}
|
||||
@Override
|
||||
public int contextWeight(KingEntity king, LivingEntity target) {
|
||||
return 4 + king.behaviorScore(KingEntity.Behavior.RANGED);
|
||||
|
||||
+7
-3
@@ -23,6 +23,7 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.projectile.Projectile;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
@@ -104,7 +105,7 @@ public final class AttitudeAdjusterSlamManager {
|
||||
if (player.onGround() || player.isInWaterOrBubble() || player.isInLava() || player.isFallFlying() || player.getAbilities().flying || PLAYER_SLAMS.containsKey(player.getUUID())) {
|
||||
return false;
|
||||
}
|
||||
PLAYER_SLAMS.put(player.getUUID(), new PlayerSlamState(player.getUUID(), player.serverLevel().dimension().location().toString(), player.serverLevel().getGameTime() + SLAM_TIMEOUT_TICKS, player.fallDistance));
|
||||
PLAYER_SLAMS.put(player.getUUID(), new PlayerSlamState(player.getUUID(), hand, player.serverLevel().dimension().location().toString(), player.serverLevel().getGameTime() + SLAM_TIMEOUT_TICKS, player.fallDistance));
|
||||
AntarchyGravityDirection gravityDirection = AntarchyGravityRotationUtil.getGravityDownDirection(player) == Direction.UP ? AntarchyGravityDirection.UP : AntarchyGravityDirection.DOWN;
|
||||
Vec3 motion = player.getDeltaMovement();
|
||||
Vec3 localMotion = AntarchyGravityRotationUtil.vecWorldToPlayer(motion, gravityDirection);
|
||||
@@ -194,7 +195,8 @@ public final class AttitudeAdjusterSlamManager {
|
||||
if (AntarchySettings.attitudeAdjusterBreaksBlocks()) {
|
||||
breakBlocks(level, player, groundPos, gravityDown);
|
||||
}
|
||||
if (player.getMainHandItem().getItem() instanceof AttitudeAdjusterItem item) {
|
||||
ItemStack slamStack = player.getItemInHand(state.hand);
|
||||
if (slamStack.getItem() instanceof AttitudeAdjusterItem item) {
|
||||
player.getCooldowns().addCooldown(item, PLAYER_SLAM_COOLDOWN_TICKS);
|
||||
}
|
||||
iterator.remove();
|
||||
@@ -319,12 +321,14 @@ public final class AttitudeAdjusterSlamManager {
|
||||
|
||||
private static final class PlayerSlamState {
|
||||
private final UUID playerId;
|
||||
private final net.minecraft.world.InteractionHand hand;
|
||||
private final String dimensionId;
|
||||
private final long expiresAt;
|
||||
private final float startFallDistance;
|
||||
|
||||
private PlayerSlamState(UUID playerId, String dimensionId, long expiresAt, float startFallDistance) {
|
||||
private PlayerSlamState(UUID playerId, net.minecraft.world.InteractionHand hand, String dimensionId, long expiresAt, float startFallDistance) {
|
||||
this.playerId = playerId;
|
||||
this.hand = hand;
|
||||
this.dimensionId = dimensionId;
|
||||
this.expiresAt = expiresAt;
|
||||
this.startFallDistance = startFallDistance;
|
||||
|
||||
+9
-9
@@ -6,6 +6,9 @@ import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||
import com.craisinlord.antarchy.content.client.model.ResourceBackedGeoItemModel;
|
||||
import com.craisinlord.antarchy.content.client.renderer.AnimatedHeldItemRenderer;
|
||||
import com.craisinlord.antarchy.content.entity.OctopusBombEntity;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
@@ -161,15 +164,12 @@ public class RpoLauncherItem extends ProjectileWeaponItem implements GeoItem {
|
||||
}
|
||||
|
||||
float yaw = player.getYRot() + yawOffset;
|
||||
Vec3 direction = Vec3.directionFromRotation(new Vec2(player.getXRot(), yaw));
|
||||
projectileBomb.moveTo(
|
||||
player.getX(),
|
||||
player.getEyeY() + 0.15D,
|
||||
player.getZ(),
|
||||
yaw,
|
||||
player.getXRot()
|
||||
);
|
||||
projectileBomb.launchAsExplosiveProjectile(player, direction.scale(AntarchySettings.rpoLauncherLaunchVelocity()).add(player.getDeltaMovement()));
|
||||
Vec3 localDirection = Vec3.directionFromRotation(new Vec2(player.getXRot(), yaw));
|
||||
AntarchyGravityDirection gravity = AntarchyGravityApi.getGravityDirection(player);
|
||||
Vec3 direction = AntarchyGravityRotationUtil.vecPlayerToWorld(localDirection, gravity).normalize();
|
||||
Vec3 spawn = player.getEyePosition().add(direction.scale(0.55D));
|
||||
projectileBomb.moveTo(spawn.x, spawn.y, spawn.z, yaw, player.getXRot());
|
||||
projectileBomb.launchAsExplosiveProjectile(player, direction.scale(AntarchySettings.rpoLauncherLaunchVelocity()).add(AntarchyGravityApi.deltaMovement(player)));
|
||||
level.addFreshEntity(projectileBomb);
|
||||
}
|
||||
|
||||
|
||||
+9
-9
@@ -5,6 +5,9 @@ import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||
import com.craisinlord.antarchy.content.client.model.ResourceBackedGeoItemModel;
|
||||
import com.craisinlord.antarchy.content.entity.MissileSquidEntity;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
@@ -162,15 +165,12 @@ public class SquidzookaItem extends ProjectileWeaponItem implements GeoItem {
|
||||
}
|
||||
|
||||
float yaw = player.getYRot() + yawOffset;
|
||||
Vec3 direction = Vec3.directionFromRotation(new Vec2(player.getXRot(), yaw));
|
||||
projectileSquid.moveTo(
|
||||
player.getX(),
|
||||
player.getEyeY() - 0.2D,
|
||||
player.getZ(),
|
||||
yaw,
|
||||
player.getXRot()
|
||||
);
|
||||
projectileSquid.launchAsProjectile(player, direction.scale(AntarchySettings.squidzookaLaunchVelocity()).add(player.getDeltaMovement()));
|
||||
Vec3 localDirection = Vec3.directionFromRotation(new Vec2(player.getXRot(), yaw));
|
||||
AntarchyGravityDirection gravity = AntarchyGravityApi.getGravityDirection(player);
|
||||
Vec3 direction = AntarchyGravityRotationUtil.vecPlayerToWorld(localDirection, gravity).normalize();
|
||||
Vec3 spawn = player.getEyePosition().add(direction.scale(0.45D));
|
||||
projectileSquid.moveTo(spawn.x, spawn.y, spawn.z, yaw, player.getXRot());
|
||||
projectileSquid.launchAsProjectile(player, direction.scale(AntarchySettings.squidzookaLaunchVelocity()).add(AntarchyGravityApi.deltaMovement(player)));
|
||||
level.addFreshEntity(projectileSquid);
|
||||
}
|
||||
|
||||
|
||||
+30
-2
@@ -147,14 +147,42 @@ public final class KingsTreeGridFeature extends Feature<NoneFeatureConfiguration
|
||||
// Start near the lower trunk so players on the ground can reliably engage the King.
|
||||
// The patrol bounds remain unchanged, allowing him to retreat upward through the tree.
|
||||
double spawnY = minimumY + 48.0D;
|
||||
// Start just outside the central trunk, inside the tree's authored footprint.
|
||||
king.moveTo(centerX + 48.5D, spawnY, centerZ + 0.5D, 90.0F, 0.0F);
|
||||
Vec3 spawn = findSafeKingSpawn(serverLevel, king, centerX, centerZ, spawnY);
|
||||
king.moveTo(spawn.x, spawn.y, spawn.z,
|
||||
(float) (Math.atan2(centerZ + 0.5D - spawn.z, centerX + 0.5D - spawn.x)
|
||||
* 180.0D / Math.PI) - 90.0F,
|
||||
0.0F);
|
||||
king.setTreePatrolHome(treeCenter, minimumY, maximumY, 0.0D);
|
||||
king.setPersistenceRequired();
|
||||
serverLevel.addFreshEntity(king);
|
||||
}
|
||||
}
|
||||
|
||||
private static Vec3 findSafeKingSpawn(ServerLevel level, KingEntity king,
|
||||
int centerX, int centerZ, double spawnY) {
|
||||
double[] radii = {96.0D, 80.0D, 64.0D};
|
||||
double[] heightOffsets = {0.0D, 18.0D, -12.0D, 32.0D};
|
||||
for (double radius : radii) {
|
||||
for (int angleIndex = 0; angleIndex < 16; angleIndex++) {
|
||||
double angle = angleIndex * Math.PI * 2.0D / 16.0D;
|
||||
double x = centerX + 0.5D + Math.cos(angle) * radius;
|
||||
double z = centerZ + 0.5D + Math.sin(angle) * radius;
|
||||
for (double heightOffset : heightOffsets) {
|
||||
Vec3 candidate = new Vec3(x, spawnY + heightOffset, z);
|
||||
BlockPos blockPos = BlockPos.containing(candidate);
|
||||
if (!level.hasChunksAt(blockPos.offset(-8, -8, -8), blockPos.offset(8, 16, 8))) {
|
||||
continue;
|
||||
}
|
||||
king.moveTo(candidate.x, candidate.y, candidate.z, 0.0F, 0.0F);
|
||||
if (level.noCollision(king, king.getBoundingBox())) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Vec3(centerX + 64.5D, spawnY + 32.0D, centerZ + 0.5D);
|
||||
}
|
||||
|
||||
private static ResourceLocation tileLocation(int tileX, int tileZ) {
|
||||
return ResourceLocation.fromNamespaceAndPath(
|
||||
Antarchy.MODID,
|
||||
|
||||
+10
-2
@@ -1,5 +1,6 @@
|
||||
package com.craisinlord.antarchy.mixins.gravity;
|
||||
|
||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.projectile.Projectile;
|
||||
@@ -18,8 +19,15 @@ public abstract class EntityProjectileGravityMixin {
|
||||
@Inject(method = "applyGravity", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$applyProjectileGravityUpward(CallbackInfo ci) {
|
||||
Entity self = (Entity) (Object) this;
|
||||
if (!(self instanceof Projectile projectile)
|
||||
|| !ThoraxisUndersideManager.isInUnderside(projectile)) {
|
||||
if (!(self instanceof Projectile projectile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean inverted = AntarchyGravityApi.isGravityInverted(projectile);
|
||||
if (!inverted && projectile.getOwner() != null) {
|
||||
inverted = AntarchyGravityApi.isGravityInverted(projectile.getOwner());
|
||||
}
|
||||
if (!inverted && !ThoraxisUndersideManager.isInUnderside(projectile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ public abstract class ProjectileGravityMixin {
|
||||
@Local(argsOnly = true) Entity shooter
|
||||
) {
|
||||
Vec3 direction = new Vec3(x, y, z);
|
||||
if (ThoraxisUndersideManager.shouldInvertInUnderside(shooter)) {
|
||||
if (AntarchyGravityApi.isGravityInverted(shooter)) {
|
||||
direction = AntarchyGravityRotationUtil.vecPlayerToWorld(
|
||||
direction,
|
||||
AntarchyGravityApi.getGravityDirection(shooter)
|
||||
|
||||
@@ -905,6 +905,7 @@
|
||||
"tooltip.antarchy.lucid_pearl": "Throws an inverted-gravity projectile.",
|
||||
"tooltip.antarchy.lucid_pearl.detail": "Teleports you to where it lands and applies Inverted.",
|
||||
"subtitles.antarchy.squidzooka_fire": "Squidzooka fires",
|
||||
"subtitles.antarchy.undertrial_detect_player": "Undertrial spawner detects player",
|
||||
"subtitles.antarchy.size_ray_charge": "Size Ray charges",
|
||||
"subtitles.antarchy.size_ray_fire": "Size Ray fires",
|
||||
"subtitles.antarchy.ant_ambient": "Ants chirp",
|
||||
@@ -1418,7 +1419,9 @@
|
||||
,"decree.antarchy.kneel": "KNEEL"
|
||||
,"decree.antarchy.kneel.subtitle": "Crouch within five seconds."
|
||||
,"decree.antarchy.close_quarters": "CLOSE QUARTERS"
|
||||
,"decree.antarchy.close_quarters.subtitle": "Projectiles are forbidden."
|
||||
,"decree.antarchy.close_quarters.subtitle": "Enter the royal circle. Projectiles are forbidden."
|
||||
,"decree.antarchy.violated": "DECREE VIOLATED"
|
||||
,"decree.antarchy.violated.subtitle": "Face the King's judgment."
|
||||
,"decree.antarchy.come_no_closer": "COME NO CLOSER"
|
||||
,"decree.antarchy.come_no_closer.subtitle": "Keep out of the King's inner radius."
|
||||
,"decree.antarchy.fight_me_coward": "FIGHT ME, COWARD!"
|
||||
|
||||
@@ -17,6 +17,18 @@
|
||||
{ "name": "antarchy:thoraxis_lucid_pools_additions", "type": "event" }
|
||||
]
|
||||
},
|
||||
"undertrial_detect_player1": {
|
||||
"subtitle": "subtitles.antarchy.undertrial_detect_player",
|
||||
"sounds": [
|
||||
{ "name": "antarchy:block/undertrial/undertrial_detect_player1" }
|
||||
]
|
||||
},
|
||||
"undertrial_detect_player2": {
|
||||
"subtitle": "subtitles.antarchy.undertrial_detect_player",
|
||||
"sounds": [
|
||||
{ "name": "antarchy:block/undertrial/undertrial_detect_player2" }
|
||||
]
|
||||
},
|
||||
"squidzooka_fire": {
|
||||
"subtitle": "subtitles.antarchy.squidzooka_fire",
|
||||
"sounds": [
|
||||
@@ -1106,10 +1118,6 @@
|
||||
"name": "antarchy:inversion_layer",
|
||||
"type": "event",
|
||||
"stream": true
|
||||
},
|
||||
{
|
||||
"name": "antarchy:music/game/thoraxis/assimilation",
|
||||
"stream": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Reference in new issue
Block a user