time dilation and contraction effects, various fixes
This commit is contained in:
1 parent
68eba61022
commit
89d41dd7e1
192 files changed
+2962
-1981
No files matched your search
@@ -550,6 +550,7 @@ public final class AntarchySettings {
|
||||
private static double queenManticoreSummonRange = 24.0D;
|
||||
private static double queenBeamDamage = 45.0D;
|
||||
private static double queenBeamRange = 100.0D;
|
||||
private static double queenBeamMinimumRange = 22.0D;
|
||||
private static int queenBeamDurationTicks = 30;
|
||||
private static int queenBeamWindupTicks = 20;
|
||||
private static int queenBeamTravelTicks = 12;
|
||||
@@ -559,6 +560,7 @@ public final class AntarchySettings {
|
||||
private static int queenBeamTerrainCap = 192;
|
||||
private static double kingBeamDamage = 50.0D;
|
||||
private static double kingBeamRange = 100.0D;
|
||||
private static double kingBeamMinimumRange = 32.0D;
|
||||
private static int kingBeamDurationTicks = 30;
|
||||
private static int kingBeamWindupTicks = 20;
|
||||
private static int kingBeamTravelTicks = 12;
|
||||
@@ -567,6 +569,11 @@ public final class AntarchySettings {
|
||||
private static double kingBeamTerrainRadius = 5.0D;
|
||||
private static int kingBeamTerrainCap = 192;
|
||||
private static int royalDecreeCooldownTicks = 1200;
|
||||
private static int kingRoyalMusterCooldownTicks = 500;
|
||||
private static int kingRoyalMusterWindupTicks = 30;
|
||||
private static int kingRoyalMusterDurationTicks = 600;
|
||||
private static double kingRoyalMusterRadius = 32.0D;
|
||||
private static int kingRoyalMusterCap = 12;
|
||||
private static double jerryInfantHealth = 20.0D;
|
||||
private static double jerryInfantAttackDamage = 2.0D;
|
||||
private static double jerryMatureHealth = 40.0D;
|
||||
@@ -2887,6 +2894,8 @@ public final class AntarchySettings {
|
||||
public static void setQueenBeamDamage(double v) { queenBeamDamage = v; }
|
||||
public static double queenBeamRange() { return queenBeamRange; }
|
||||
public static void setQueenBeamRange(double v) { queenBeamRange = v; }
|
||||
public static double queenBeamMinimumRange() { return queenBeamMinimumRange; }
|
||||
public static void setQueenBeamMinimumRange(double v) { queenBeamMinimumRange = v; }
|
||||
public static int queenBeamDurationTicks() { return queenBeamDurationTicks; }
|
||||
public static void setQueenBeamDurationTicks(int v) { queenBeamDurationTicks = v; }
|
||||
public static int queenBeamWindupTicks() { return queenBeamWindupTicks; }
|
||||
@@ -2905,6 +2914,8 @@ public final class AntarchySettings {
|
||||
public static void setKingBeamDamage(double v) { kingBeamDamage = v; }
|
||||
public static double kingBeamRange() { return kingBeamRange; }
|
||||
public static void setKingBeamRange(double v) { kingBeamRange = v; }
|
||||
public static double kingBeamMinimumRange() { return kingBeamMinimumRange; }
|
||||
public static void setKingBeamMinimumRange(double v) { kingBeamMinimumRange = v; }
|
||||
public static int kingBeamDurationTicks() { return kingBeamDurationTicks; }
|
||||
public static void setKingBeamDurationTicks(int v) { kingBeamDurationTicks = v; }
|
||||
public static int kingBeamWindupTicks() { return kingBeamWindupTicks; }
|
||||
@@ -2921,6 +2932,16 @@ public final class AntarchySettings {
|
||||
public static void setKingBeamTerrainCap(int v) { kingBeamTerrainCap = v; }
|
||||
public static int royalDecreeCooldownTicks() { return royalDecreeCooldownTicks; }
|
||||
public static void setRoyalDecreeCooldownTicks(int v) { royalDecreeCooldownTicks = v; }
|
||||
public static int kingRoyalMusterCooldownTicks() { return kingRoyalMusterCooldownTicks; }
|
||||
public static void setKingRoyalMusterCooldownTicks(int v) { kingRoyalMusterCooldownTicks = v; }
|
||||
public static int kingRoyalMusterWindupTicks() { return kingRoyalMusterWindupTicks; }
|
||||
public static void setKingRoyalMusterWindupTicks(int v) { kingRoyalMusterWindupTicks = v; }
|
||||
public static int kingRoyalMusterDurationTicks() { return kingRoyalMusterDurationTicks; }
|
||||
public static void setKingRoyalMusterDurationTicks(int v) { kingRoyalMusterDurationTicks = v; }
|
||||
public static double kingRoyalMusterRadius() { return kingRoyalMusterRadius; }
|
||||
public static void setKingRoyalMusterRadius(double v) { kingRoyalMusterRadius = v; }
|
||||
public static int kingRoyalMusterCap() { return kingRoyalMusterCap; }
|
||||
public static void setKingRoyalMusterCap(int v) { kingRoyalMusterCap = v; }
|
||||
public static double jerryInfantHealth() { return jerryInfantHealth; }
|
||||
public static void setJerryInfantHealth(double v) { jerryInfantHealth = v; }
|
||||
public static double jerryInfantAttackDamage() { return jerryInfantAttackDamage; }
|
||||
|
||||
@@ -206,6 +206,8 @@ public final class AntarchyObjects {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Supplier<MenuType<com.craisinlord.antarchy.content.menu.DorrieInventoryMenu>> DORRIE_INVENTORY_MENU = (Supplier<MenuType<com.craisinlord.antarchy.content.menu.DorrieInventoryMenu>>) UNBOUND;
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Supplier<MenuType<com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu>> ROYAL_JUDGMENT_MENU = (Supplier<MenuType<com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu>>) UNBOUND;
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Supplier<net.minecraft.world.item.Item> CHEEP_ITEM = (Supplier<net.minecraft.world.item.Item>) UNBOUND;
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Supplier<Block> DUPLICATOR_LOG = (Supplier<Block>) UNBOUND;
|
||||
@@ -893,6 +895,10 @@ public final class AntarchyObjects {
|
||||
DORRIE_INVENTORY_MENU = supplier;
|
||||
}
|
||||
|
||||
public static void setRoyalJudgmentMenu(Supplier<MenuType<com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu>> supplier) {
|
||||
ROYAL_JUDGMENT_MENU = supplier;
|
||||
}
|
||||
|
||||
public static void setAmericanComponent(Supplier<net.minecraft.core.component.DataComponentType<net.minecraft.util.Unit>> supplier) {
|
||||
AMERICAN_COMPONENT = supplier;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.craisinlord.antarchy.content.block;
|
||||
|
||||
import com.craisinlord.antarchy.content.entity.WormEntity;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -18,9 +19,9 @@ import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
public class MucusBlock extends GlowLichenBlock {
|
||||
public static final MapCodec<MucusBlock> CODEC = simpleCodec(MucusBlock::new);
|
||||
private static final VoxelShape DOWN_COLLISION_SHAPE = Shapes.box(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D);
|
||||
private static final double SLIDE_ACCELERATION = 0.025D;
|
||||
private static final double SLIDE_MAX_SPEED = 0.6D;
|
||||
private static final double SLIDE_MIN_SPEED = 0.02D;
|
||||
private static final double SLIDE_ACCELERATION = 0.045D;
|
||||
private static final double SLIDE_MAX_SPEED = 1.2D;
|
||||
private static final double SLIDE_MIN_SPEED = 0.01D;
|
||||
|
||||
public MucusBlock(BlockBehaviour.Properties properties) {
|
||||
super(properties);
|
||||
@@ -37,9 +38,12 @@ public class MucusBlock extends GlowLichenBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
|
||||
super.entityInside(state, level, pos, entity);
|
||||
if (level.isClientSide || !state.getValue(MultifaceBlock.getFaceProperty(Direction.DOWN))) {
|
||||
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
|
||||
super.stepOn(level, pos, state, entity);
|
||||
if (level.isClientSide
|
||||
|| entity instanceof WormEntity
|
||||
|| entity.isShiftKeyDown()
|
||||
|| !state.getValue(MultifaceBlock.getFaceProperty(Direction.DOWN))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
-7
@@ -10,7 +10,6 @@ import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public final class ClientTimeDilationTicker {
|
||||
@@ -32,12 +31,6 @@ public final class ClientTimeDilationTicker {
|
||||
ANIMATION_CLOCKS.clear();
|
||||
com.craisinlord.antarchy.content.time.TimeDilationApi.clearSyncedClientRates();
|
||||
}
|
||||
// Entity rates come from the server. Field snapshots are used only for local effects.
|
||||
for (Player player : level.players()) {
|
||||
if (player.isDeadOrDying() || rateAt(player.getX(), player.getY(), player.getZ()) >= TimeDilationMath.NORMAL_RATE) {
|
||||
com.craisinlord.antarchy.content.time.TimeDilationApi.clearRate(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float dilateAnimationTime(Entity entity, float vanillaTime) {
|
||||
|
||||
+64
@@ -2,10 +2,25 @@ package com.craisinlord.antarchy.content.client.model;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
|
||||
import com.craisinlord.antarchy.content.entity.royal.RoyalHead;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import software.bernie.geckolib.animation.AnimationState;
|
||||
import software.bernie.geckolib.cache.object.GeoBone;
|
||||
import software.bernie.geckolib.model.GeoModel;
|
||||
|
||||
public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
|
||||
private static final String[] BEAM_ANCHORS = {
|
||||
"beam_anchor_left", "beam_anchor_center", "beam_anchor_right"
|
||||
};
|
||||
private static final String[][] AIM_CHAINS = {
|
||||
{"L_neck", "L_neck2", "L_neck3"},
|
||||
{"neck", "neck3", "neck4"},
|
||||
{"R_neck", "R_neck2", "R_neck3"}
|
||||
};
|
||||
|
||||
@Override
|
||||
public ResourceLocation getModelResource(RoyalBossEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/" + animatable.geoNameForRender() + ".geo.json");
|
||||
@@ -21,4 +36,53 @@ public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
|
||||
public ResourceLocation getAnimationResource(RoyalBossEntity animatable) {
|
||||
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/" + animatable.geoNameForRender() + ".animation.json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomAnimations(RoyalBossEntity animatable, long instanceId,
|
||||
AnimationState<RoyalBossEntity> animationState) {
|
||||
super.setCustomAnimations(animatable, instanceId, animationState);
|
||||
for (String anchor : BEAM_ANCHORS) {
|
||||
this.getBone(anchor).ifPresent(bone -> bone.setTrackingMatrices(true));
|
||||
}
|
||||
|
||||
RoyalHead.Slot slot = animatable.getRoyalBeamHeadSlot();
|
||||
Vec3 beamEnd = animatable.getRoyalBeamEndPosition();
|
||||
if (!animatable.isFiringRoyalBeam() || slot == null || beamEnd == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
float partialTick = animationState.getPartialTick();
|
||||
Vec3 origin = animatable.getRoyalBeamShootFrom(partialTick);
|
||||
Vec3 direction = beamEnd.subtract(origin);
|
||||
double horizontal = Math.sqrt(direction.x * direction.x + direction.z * direction.z);
|
||||
if (direction.lengthSqr() < 1.0E-6D || horizontal < 1.0E-4D) {
|
||||
return;
|
||||
}
|
||||
|
||||
float desiredYaw = (float) (Mth.atan2(-direction.x, direction.z) * Mth.RAD_TO_DEG);
|
||||
float bodyYaw = Mth.rotLerp(partialTick, animatable.yRotO, animatable.getYRot());
|
||||
float relativeYaw = Mth.clamp(Mth.wrapDegrees(desiredYaw - bodyYaw), -55.0F, 55.0F) * Mth.DEG_TO_RAD;
|
||||
float pitch = Mth.clamp((float) -Mth.atan2(direction.y, horizontal) * Mth.RAD_TO_DEG,
|
||||
-45.0F, 45.0F) * Mth.DEG_TO_RAD;
|
||||
|
||||
String[] chain = AIM_CHAINS[slot.ordinal()];
|
||||
float yawPerBone = relativeYaw / chain.length;
|
||||
float pitchPerBone = pitch / chain.length;
|
||||
for (String boneName : chain) {
|
||||
this.getBone(boneName).ifPresent(bone -> {
|
||||
bone.setRotY(bone.getRotY() + yawPerBone);
|
||||
bone.setRotX(bone.getRotX() + pitchPerBone);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Vec3 getTrackedBeamAnchor(RoyalHead.Slot slot) {
|
||||
GeoBone bone = this.getBone(BEAM_ANCHORS[slot.ordinal()]).orElse(null);
|
||||
if (bone == null || !bone.isTrackingMatrices()) {
|
||||
return null;
|
||||
}
|
||||
org.joml.Vector3d position = bone.getWorldPosition();
|
||||
return new Vec3(position.x, position.y, position.z);
|
||||
}
|
||||
}
|
||||
+9
-3
@@ -3,6 +3,7 @@ package com.craisinlord.antarchy.content.client.renderer;
|
||||
import com.craisinlord.antarchy.content.client.model.RoyalBossModel;
|
||||
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
|
||||
import com.craisinlord.antarchy.content.entity.royal.KingEntity;
|
||||
import com.craisinlord.antarchy.content.entity.royal.RoyalHead;
|
||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
@@ -58,8 +59,8 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
||||
this.shadowRadius = 8.0F * RoyalBossEntity.MODEL_RENDER_SCALE;
|
||||
}
|
||||
|
||||
private static final float BEAM_OUTER_RADIUS = 1.10F;
|
||||
private static final float BEAM_INNER_RADIUS = 0.52F;
|
||||
private static final float BEAM_OUTER_RADIUS = 0.55F;
|
||||
private static final float BEAM_INNER_RADIUS = 0.32F;
|
||||
private static final float BEAM_TILE_BLOCKS = 3.0F;
|
||||
private static final float BEAM_SCROLL_SPEED = 0.32F;
|
||||
|
||||
@@ -74,7 +75,12 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
||||
double x = Mth.lerp(partialTick, entity.xo, entity.getX());
|
||||
double y = Mth.lerp(partialTick, entity.yo, entity.getY());
|
||||
double z = Mth.lerp(partialTick, entity.zo, entity.getZ());
|
||||
Vec3 start = entity.getRoyalBeamShootFrom(partialTick).subtract(x, y, z);
|
||||
RoyalHead.Slot beamHead = entity.getRoyalBeamHeadSlot();
|
||||
Vec3 trackedAnchor = beamHead == null
|
||||
? null
|
||||
: ((RoyalBossModel) this.getGeoModel()).getTrackedBeamAnchor(beamHead);
|
||||
Vec3 start = (trackedAnchor != null ? trackedAnchor : entity.getRoyalBeamShootFrom(partialTick))
|
||||
.subtract(x, y, z);
|
||||
Vec3 finish = end.subtract(x, y, z);
|
||||
Vec3 axis = finish.subtract(start);
|
||||
double length = axis.length();
|
||||
|
||||
+12
-36
@@ -13,7 +13,6 @@ import org.joml.Matrix4f;
|
||||
|
||||
public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
|
||||
private static final int RINGS = 11;
|
||||
private static final int SQUARES_PER_SIDE = 3;
|
||||
private static final float BASE_RADIUS = 0.35F;
|
||||
|
||||
public WindVortexRenderer(EntityRendererProvider.Context context) {
|
||||
@@ -44,11 +43,11 @@ public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
|
||||
float ringSpin = spinDirection * age * (0.13F + progress * 0.045F) + ring * 0.47F;
|
||||
float alpha = alphaMultiplier;
|
||||
float halfSide = radius * 0.92F;
|
||||
float tileSize = Math.max(0.035F, radius * 0.12F);
|
||||
float lineThickness = 0.055F + progress * 0.018F;
|
||||
int red = push ? 70 : 64;
|
||||
int green = push ? 220 : 255;
|
||||
int blue = push ? 255 : 56;
|
||||
drawSquareRing(consumer, pose, basis, halfSide, axisDistance, tileSize, ringSpin,
|
||||
drawSquareRing(consumer, pose, basis, halfSide, axisDistance, lineThickness, ringSpin,
|
||||
alpha, red, green, blue);
|
||||
}
|
||||
|
||||
@@ -56,47 +55,24 @@ public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
|
||||
}
|
||||
|
||||
private static void drawSquareRing(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis,
|
||||
float halfSide, float axisDistance, float tileSize, float rotation, float alpha,
|
||||
float halfSide, float axisDistance, float lineThickness, float rotation, float alpha,
|
||||
int red, int green, int blue) {
|
||||
for (int side = 0; side < 4; side++) {
|
||||
for (int tile = 0; tile < SQUARES_PER_SIDE; tile++) {
|
||||
float start = -halfSide + (tile + 0.18F) * (2.0F * halfSide / SQUARES_PER_SIDE);
|
||||
float end = -halfSide + (tile + 0.82F) * (2.0F * halfSide / SQUARES_PER_SIDE);
|
||||
float sideAngle = rotation + side * (Mth.TWO_PI / 4.0F);
|
||||
addSquareTile(consumer, pose, basis, halfSide, axisDistance, tileSize,
|
||||
sideAngle, start, end, alpha, red, green, blue);
|
||||
}
|
||||
float sideAngle = rotation + side * (Mth.TWO_PI / 4.0F);
|
||||
addSquareSide(consumer, pose, basis, halfSide, axisDistance, lineThickness,
|
||||
sideAngle, alpha, red, green, blue);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addSquareTile(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis,
|
||||
float halfSide, float axisDistance, float tileSize, float sideAngle, float start, float end,
|
||||
private static void addSquareSide(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis,
|
||||
float halfSide, float axisDistance, float lineThickness, float sideAngle,
|
||||
float alpha, int red, int green, int blue) {
|
||||
org.joml.Vector3f center = squarePoint(basis, halfSide, axisDistance, sideAngle, (start + end) * 0.5F);
|
||||
org.joml.Vector3f tangent = new org.joml.Vector3f(
|
||||
(float) (-basis.sideA.x * Mth.sin(sideAngle) + basis.sideB.x * Mth.cos(sideAngle)),
|
||||
(float) (-basis.sideA.y * Mth.sin(sideAngle) + basis.sideB.y * Mth.cos(sideAngle)),
|
||||
(float) (-basis.sideA.z * Mth.sin(sideAngle) + basis.sideB.z * Mth.cos(sideAngle)));
|
||||
org.joml.Vector3f start = squarePoint(basis, halfSide, axisDistance, sideAngle, -halfSide);
|
||||
org.joml.Vector3f end = squarePoint(basis, halfSide, axisDistance, sideAngle, halfSide);
|
||||
org.joml.Vector3f axisOffset = new org.joml.Vector3f(
|
||||
(float) basis.axis.x, (float) basis.axis.y, (float) basis.axis.z).mul(tileSize * 0.5F);
|
||||
tangent.mul(tileSize * 0.5F);
|
||||
(float) basis.axis.x, (float) basis.axis.y, (float) basis.axis.z).mul(lineThickness);
|
||||
int a = Mth.clamp((int) (alpha * 255.0F), 0, 255);
|
||||
addVertex(consumer, pose, center.x - tangent.x - axisOffset.x, center.y - tangent.y - axisOffset.y,
|
||||
center.z - tangent.z - axisOffset.z, red, green, blue, a);
|
||||
addVertex(consumer, pose, center.x + tangent.x - axisOffset.x, center.y + tangent.y - axisOffset.y,
|
||||
center.z + tangent.z - axisOffset.z, red, green, blue, a);
|
||||
addVertex(consumer, pose, center.x + tangent.x + axisOffset.x, center.y + tangent.y + axisOffset.y,
|
||||
center.z + tangent.z + axisOffset.z, red, green, blue, a);
|
||||
addVertex(consumer, pose, center.x - tangent.x + axisOffset.x, center.y - tangent.y + axisOffset.y,
|
||||
center.z - tangent.z + axisOffset.z, red, green, blue, a);
|
||||
addVertex(consumer, pose, center.x - tangent.x + axisOffset.x, center.y - tangent.y + axisOffset.y,
|
||||
center.z - tangent.z + axisOffset.z, red, green, blue, a);
|
||||
addVertex(consumer, pose, center.x + tangent.x + axisOffset.x, center.y + tangent.y + axisOffset.y,
|
||||
center.z + tangent.z + axisOffset.z, red, green, blue, a);
|
||||
addVertex(consumer, pose, center.x + tangent.x - axisOffset.x, center.y + tangent.y - axisOffset.y,
|
||||
center.z + tangent.z - axisOffset.z, red, green, blue, a);
|
||||
addVertex(consumer, pose, center.x - tangent.x - axisOffset.x, center.y - tangent.y - axisOffset.y,
|
||||
center.z - tangent.z - axisOffset.z, red, green, blue, a);
|
||||
addQuad(consumer, pose, start, end, axisOffset, red, green, blue, a);
|
||||
}
|
||||
|
||||
private static org.joml.Vector3f squarePoint(WindVortexEntity.Basis basis, float halfSide,
|
||||
|
||||
+1
-1
@@ -595,7 +595,7 @@ public final class CreativeTabContents {
|
||||
"dread", "long_dread", "inversion", "long_inversion", "stinky", "long_stinky",
|
||||
"paralysis", "long_paralysis", "haste", "strong_haste", "shrinking",
|
||||
"strong_shrinking", "extreme_shrinking", "growing", "strong_growing", "extreme_growing",
|
||||
"command", "long_command", "time_dilation", "long_time_dilation"
|
||||
"command", "long_command", "time_dilation", "long_time_dilation", "time_contraction", "long_time_contraction"
|
||||
);
|
||||
|
||||
private static final Map<String, Integer> ORDER_INDEX = createOrderIndex();
|
||||
|
||||
+69
-12
@@ -1,11 +1,11 @@
|
||||
package com.craisinlord.antarchy.content.effect;
|
||||
|
||||
import java.util.UUID;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
|
||||
public final class CommandedBehavior {
|
||||
private CommandedBehavior() {
|
||||
@@ -20,23 +20,39 @@ public final class CommandedBehavior {
|
||||
clear(mob);
|
||||
return;
|
||||
}
|
||||
ServerPlayer commander = mob.level().getServer().getPlayerList().getPlayer(commanderUuid);
|
||||
Entity commander = mob.level() instanceof ServerLevel level ? level.getEntity(commanderUuid) : null;
|
||||
if (commander == null || commander.level() != mob.level() || !RoyalEffectEligibility.canApplyCommanded(mob)) {
|
||||
mob.removeEffect(RoyalEffectHooks.commandedHolder());
|
||||
clear(mob);
|
||||
return;
|
||||
}
|
||||
if (mob.tickCount % 10 == 0) {
|
||||
LivingEntity commandedCandidate = findCommanderTarget(mob, commander);
|
||||
if (commandedCandidate != null) {
|
||||
mob.setTarget(commandedCandidate);
|
||||
access.antarchy$setCommandedTargetOwned(true);
|
||||
}
|
||||
}
|
||||
LivingEntity target = mob.getTarget();
|
||||
if (target != null && isProtectedAlly(mob, target)) {
|
||||
mob.setTarget(null);
|
||||
target = null;
|
||||
}
|
||||
if (target != null) {
|
||||
tryPassiveCommandedAttack(mob, target);
|
||||
}
|
||||
if (mob.tickCount % 10 != 0 || target != null) {
|
||||
return;
|
||||
}
|
||||
LivingEntity candidate = commander.getLastHurtByMob();
|
||||
LivingEntity candidate = commander instanceof Mob commanderMob ? commanderMob.getTarget() : null;
|
||||
if (!isValidTarget(mob, commander, candidate)) {
|
||||
candidate = commander.getLastHurtMob();
|
||||
candidate = commander instanceof net.minecraft.world.entity.player.Player player ? player.getLastHurtByMob() : null;
|
||||
}
|
||||
if (!isValidTarget(mob, commander, candidate)) {
|
||||
candidate = mob.getLastHurtByMob();
|
||||
}
|
||||
if (!isValidTarget(mob, commander, candidate)) {
|
||||
candidate = commander instanceof net.minecraft.world.entity.player.Player player ? player.getLastHurtMob() : null;
|
||||
}
|
||||
if (!isValidTarget(mob, commander, candidate)) {
|
||||
candidate = mob.getLastHurtByMob();
|
||||
@@ -72,18 +88,59 @@ public final class CommandedBehavior {
|
||||
if (entity instanceof LivingEntity living && living.isAlliedTo(mob)) {
|
||||
return true;
|
||||
}
|
||||
if (mob.level().getServer() != null
|
||||
&& mob.level().getServer().getPlayerList().getPlayer(commanderUuid) instanceof Player commander
|
||||
&& entity instanceof LivingEntity living) {
|
||||
return living.isAlliedTo(commander);
|
||||
if (entity instanceof LivingEntity living && commanderEntity(mob) instanceof LivingEntity livingCommander) {
|
||||
return living.isAlliedTo(livingCommander);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isValidTarget(Mob mob, ServerPlayer commander, LivingEntity target) {
|
||||
private static boolean isValidTarget(Mob mob, Entity commander, LivingEntity target) {
|
||||
return target != null && target.isAlive() && target != mob && target != commander
|
||||
&& !isProtectedAlly(mob, target) && !target.isAlliedTo(commander)
|
||||
&& mob.canAttack(target);
|
||||
&& !isProtectedAlly(mob, target) && !target.isAlliedTo(commander);
|
||||
}
|
||||
|
||||
private static LivingEntity findCommanderTarget(Mob mob, Entity commander) {
|
||||
LivingEntity target = commander instanceof Mob commanderMob ? commanderMob.getTarget() : null;
|
||||
if (isValidTarget(mob, commander, target)) {
|
||||
return target;
|
||||
}
|
||||
if (commander instanceof net.minecraft.world.entity.player.Player player) {
|
||||
target = player.getLastHurtMob();
|
||||
if (isValidTarget(mob, commander, target)) {
|
||||
return target;
|
||||
}
|
||||
target = player.getLastHurtByMob();
|
||||
if (isValidTarget(mob, commander, target)) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
return mob.level().getEntitiesOfClass(Mob.class, mob.getBoundingBox().inflate(32.0D),
|
||||
other -> other != mob && other != commander && commander.equals(other.getTarget())
|
||||
&& isValidTarget(mob, commander, other)).stream()
|
||||
.min((a, b) -> Double.compare(mob.distanceToSqr(a), mob.distanceToSqr(b)))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static void tryPassiveCommandedAttack(Mob mob, LivingEntity target) {
|
||||
if (mob.getAttribute(Attributes.ATTACK_DAMAGE) != null
|
||||
&& mob.getAttributeValue(Attributes.ATTACK_DAMAGE) > 0.0D) {
|
||||
return;
|
||||
}
|
||||
mob.getNavigation().moveTo(target, 1.0D);
|
||||
if (mob.tickCount % 20 != 0 || mob.distanceToSqr(target) > 4.0D) {
|
||||
return;
|
||||
}
|
||||
if (target.hurt(mob.damageSources().mobAttack(mob), 1.0F)) {
|
||||
mob.swing(net.minecraft.world.InteractionHand.MAIN_HAND);
|
||||
}
|
||||
}
|
||||
|
||||
private static Entity commanderEntity(Mob mob) {
|
||||
if (!(mob instanceof CommandedEntityAccess access) || mob.level().getServer() == null) {
|
||||
return null;
|
||||
}
|
||||
UUID uuid = access.antarchy$getCommanderUuid();
|
||||
return uuid == null || !(mob.level() instanceof ServerLevel level) ? null : level.getEntity(uuid);
|
||||
}
|
||||
|
||||
public static void clear(Mob mob) {
|
||||
|
||||
+5
@@ -6,6 +6,7 @@ import net.minecraft.world.entity.LivingEntity;
|
||||
|
||||
public final class DilatedMobEffect extends MobEffect {
|
||||
public static final double RATE = 0.35D;
|
||||
public static final double STRONG_RATE = 0.2D;
|
||||
|
||||
public DilatedMobEffect() {
|
||||
super(MobEffectCategory.HARMFUL, 0x6C4AB6);
|
||||
@@ -20,4 +21,8 @@ public final class DilatedMobEffect extends MobEffect {
|
||||
public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static double rateForAmplifier(int amplifier) {
|
||||
return amplifier > 0 ? STRONG_RATE : RATE;
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -8,6 +8,7 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
|
||||
|
||||
public final class RoyalEffectEligibility {
|
||||
private RoyalEffectEligibility() {
|
||||
@@ -21,6 +22,10 @@ public final class RoyalEffectEligibility {
|
||||
return RoyalEffectHooks.dilatedHolder() != null && instance.is(RoyalEffectHooks.dilatedHolder());
|
||||
}
|
||||
|
||||
public static boolean isContracted(MobEffectInstance instance) {
|
||||
return RoyalEffectHooks.contractedHolder() != null && instance.is(RoyalEffectHooks.contractedHolder());
|
||||
}
|
||||
|
||||
public static boolean canApplyCommanded(LivingEntity entity) {
|
||||
return entity instanceof Mob mob
|
||||
&& !(entity instanceof Player)
|
||||
@@ -52,6 +57,6 @@ public final class RoyalEffectEligibility {
|
||||
}
|
||||
|
||||
public static boolean canUseCommandSource(Entity source) {
|
||||
return source instanceof Player;
|
||||
return source instanceof Player || source instanceof RoyalBossEntity;
|
||||
}
|
||||
}
|
||||
+6
@@ -13,6 +13,8 @@ public final class RoyalEffectHooks {
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "commanded"));
|
||||
private static final ResourceKey<MobEffect> DILATED_KEY = ResourceKey.create(Registries.MOB_EFFECT,
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dilated"));
|
||||
private static final ResourceKey<MobEffect> CONTRACTED_KEY = ResourceKey.create(Registries.MOB_EFFECT,
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "contracted"));
|
||||
|
||||
private RoyalEffectHooks() {
|
||||
}
|
||||
@@ -24,4 +26,8 @@ public final class RoyalEffectHooks {
|
||||
public static Holder<MobEffect> dilatedHolder() {
|
||||
return BuiltInRegistries.MOB_EFFECT.getHolder(DILATED_KEY).orElse(null);
|
||||
}
|
||||
|
||||
public static Holder<MobEffect> contractedHolder() {
|
||||
return BuiltInRegistries.MOB_EFFECT.getHolder(CONTRACTED_KEY).orElse(null);
|
||||
}
|
||||
}
|
||||
+61
-7
@@ -24,12 +24,16 @@ import net.minecraft.world.level.block.RailBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.RailShape;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DiamondMinecartEntity extends Minecart {
|
||||
private static final long INPUT_TIMEOUT_TICKS = 5L;
|
||||
private static final long COLLISION_COOLDOWN_TICKS = 10L;
|
||||
private static final EntityDataAccessor<Float> SYNCED_SPEED =
|
||||
SynchedEntityData.defineId(DiamondMinecartEntity.class, EntityDataSerializers.FLOAT);
|
||||
private static final EntityDataAccessor<Integer> SYNCED_FACING =
|
||||
@@ -41,6 +45,7 @@ public class DiamondMinecartEntity extends Minecart {
|
||||
private Direction facingDir = Direction.SOUTH;
|
||||
private BlockPos lastBlockPos = null;
|
||||
private boolean railWarningCooldown = false;
|
||||
private final Map<Integer, Long> collisionCooldowns = new HashMap<>();
|
||||
|
||||
private final Item dropItem;
|
||||
|
||||
@@ -134,6 +139,7 @@ public class DiamondMinecartEntity extends Minecart {
|
||||
this.inputFlags = 0;
|
||||
this.lastInputGameTime = Long.MIN_VALUE;
|
||||
this.currentSpeed = 0.0F;
|
||||
this.collisionCooldowns.clear();
|
||||
this.entityData.set(SYNCED_SPEED, 0.0F);
|
||||
this.setDeltaMovement(0.0D, this.getDeltaMovement().y, 0.0D);
|
||||
return;
|
||||
@@ -146,6 +152,11 @@ public class DiamondMinecartEntity extends Minecart {
|
||||
Player rider = this.getRidingPlayer();
|
||||
boolean hasRider = rider != null;
|
||||
|
||||
if (!hasRider) {
|
||||
this.inputFlags = 0;
|
||||
this.lastInputGameTime = Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
if (this.lastBlockPos == null) {
|
||||
if (rider != null) {
|
||||
this.facingDir = getLookFacing(rider, Direction.SOUTH);
|
||||
@@ -212,10 +223,10 @@ public class DiamondMinecartEntity extends Minecart {
|
||||
|
||||
private void onEnteredNewBlock(BlockPos currentPos, @Nullable Player rider) {
|
||||
Direction previousFacing = this.facingDir;
|
||||
if (rider != null && (this.inputFlags & 0x01) != 0) {
|
||||
Direction lookedFacing = getLookFacing(rider, this.facingDir);
|
||||
if (lookedFacing != this.facingDir.getOpposite()) {
|
||||
this.facingDir = lookedFacing;
|
||||
if (rider != null) {
|
||||
Direction steeredFacing = getSteeredFacing(rider, this.facingDir);
|
||||
if (steeredFacing != this.facingDir.getOpposite()) {
|
||||
this.facingDir = steeredFacing;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,7 +391,10 @@ public class DiamondMinecartEntity extends Minecart {
|
||||
}
|
||||
|
||||
private boolean canPlaceRailAt(BlockPos pos, BlockState existing) {
|
||||
if (!isWithinRailBuildHeight(pos) || !this.level().getBlockState(pos.below()).isSolid()) {
|
||||
if (!isWithinRailBuildHeight(pos)
|
||||
|| !this.level().hasChunkAt(pos)
|
||||
|| !this.level().getWorldBorder().isWithinBounds(pos)
|
||||
|| !this.level().getBlockState(pos.below()).isSolid()) {
|
||||
return false;
|
||||
}
|
||||
return BaseRailBlock.isRail(existing) || existing.isAir() || existing.canBeReplaced();
|
||||
@@ -390,16 +404,44 @@ public class DiamondMinecartEntity extends Minecart {
|
||||
double maxDamage = AntarchySettings.diamondMinecartMaxMobDamage();
|
||||
double maxSpeed = AntarchySettings.diamondMinecartMaxSpeed();
|
||||
float damage = maxSpeed <= 0.0D ? 0.0F : (float) (maxDamage * (this.currentSpeed / maxSpeed));
|
||||
if (damage <= 0.0F) {
|
||||
return;
|
||||
}
|
||||
|
||||
long gameTime = this.level().getGameTime();
|
||||
this.collisionCooldowns.entrySet().removeIf(entry -> entry.getValue() <= gameTime);
|
||||
Vec3 horizontalVelocity = new Vec3(this.getDeltaMovement().x, 0.0D, this.getDeltaMovement().z);
|
||||
double velocityLength = horizontalVelocity.length();
|
||||
if (velocityLength < 1.0E-4D) {
|
||||
return;
|
||||
}
|
||||
Vec3 movementDirection = horizontalVelocity.scale(1.0D / velocityLength);
|
||||
|
||||
DamageSource source = this.level().damageSources().generic();
|
||||
AABB hitBox = this.getBoundingBox().inflate(0.2D, 0.0D, 0.2D);
|
||||
List<LivingEntity> nearby = this.level().getEntitiesOfClass(LivingEntity.class, hitBox,
|
||||
entity -> !(entity instanceof Player player && this.hasPassenger(player)));
|
||||
entity -> !(entity instanceof Player player && this.hasPassenger(player))
|
||||
&& !entity.isInvulnerable());
|
||||
|
||||
for (LivingEntity mob : nearby) {
|
||||
mob.hurt(source, damage);
|
||||
if (this.collisionCooldowns.containsKey(mob.getId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double dx = mob.getX() - this.getX();
|
||||
double dz = mob.getZ() - this.getZ();
|
||||
double distance = Math.sqrt(dx * dx + dz * dz);
|
||||
if (distance > 1.0E-4D) {
|
||||
Vec3 toMob = new Vec3(dx / distance, 0.0D, dz / distance);
|
||||
if (movementDirection.dot(toMob) < -0.2D) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mob.hurt(source, damage)) {
|
||||
continue;
|
||||
}
|
||||
this.collisionCooldowns.put(mob.getId(), gameTime + COLLISION_COOLDOWN_TICKS);
|
||||
double len = Math.sqrt(dx * dx + dz * dz);
|
||||
if (len > 0.001D) {
|
||||
mob.setDeltaMovement(mob.getDeltaMovement().add(
|
||||
@@ -426,6 +468,18 @@ public class DiamondMinecartEntity extends Minecart {
|
||||
return direction.getAxis() == Direction.Axis.Y ? fallback : direction;
|
||||
}
|
||||
|
||||
private Direction getSteeredFacing(Player rider, Direction fallback) {
|
||||
boolean left = (this.inputFlags & 0x04) != 0;
|
||||
boolean right = (this.inputFlags & 0x08) != 0;
|
||||
if (left != right) {
|
||||
return left ? fallback.getCounterClockWise() : fallback.getClockWise();
|
||||
}
|
||||
if ((this.inputFlags & 0x01) != 0) {
|
||||
return getLookFacing(rider, fallback);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private static int facingDirectionIndex(Direction dir) {
|
||||
return switch (dir) {
|
||||
case NORTH -> 0;
|
||||
|
||||
+6
@@ -25,6 +25,7 @@ import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.MoverType;
|
||||
import net.minecraft.world.entity.PathfinderMob;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@@ -66,6 +67,11 @@ public class HoverboardEntity extends PathfinderMob implements GeoEntity {
|
||||
this.setPersistenceRequired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeAffected(MobEffectInstance effectInstance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static AttributeSupplier.Builder createAttributes() {
|
||||
return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
package com.craisinlord.antarchy.content.entity;
|
||||
|
||||
import com.craisinlord.antarchy.Antarchy;
|
||||
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||
import java.util.Optional;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.MobSpawnType;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
||||
@@ -21,6 +30,11 @@ import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
|
||||
import net.minecraft.world.entity.monster.Monster;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.ServerLevelAccessor;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.MultifaceBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
@@ -34,6 +48,14 @@ import software.bernie.geckolib.animation.RawAnimation;
|
||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||
|
||||
public class WormEntity extends Monster implements GeoEntity {
|
||||
private static final ResourceKey<Biome> WORMY_CAVES = ResourceKey.create(
|
||||
Registries.BIOME,
|
||||
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "wormy_caves")
|
||||
);
|
||||
private static final ResourceLocation LOAM_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "loam");
|
||||
private static final ResourceLocation MUCUS_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "mucus");
|
||||
private static final int MUCUS_TRAIL_INTERVAL = 6;
|
||||
private static final double MUCUS_TRAIL_MIN_DISTANCE_SQR = 0.36D;
|
||||
private static final EntityDataAccessor<Integer> ANIMATION_STATE = SynchedEntityData.defineId(WormEntity.class, EntityDataSerializers.INT);
|
||||
private static final int ANIM_INGROUND = 0;
|
||||
private static final int ANIM_CRAWL = 1;
|
||||
@@ -43,6 +65,8 @@ public class WormEntity extends Monster implements GeoEntity {
|
||||
private static final RawAnimation ATTACK_ANIM = RawAnimation.begin().thenPlay("attack");
|
||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||
private int attackAnimationTicks;
|
||||
private int mucusTrailCooldown;
|
||||
private Vec3 lastMucusTrailPosition;
|
||||
|
||||
public WormEntity(EntityType<? extends WormEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -58,6 +82,23 @@ public class WormEntity extends Monster implements GeoEntity {
|
||||
.add(Attributes.KNOCKBACK_RESISTANCE, 0.45D);
|
||||
}
|
||||
|
||||
public static boolean canSpawn(EntityType<WormEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
|
||||
if ((spawnReason == MobSpawnType.NATURAL || spawnReason == MobSpawnType.CHUNK_GENERATION)
|
||||
&& !level.getBiome(pos).is(WORMY_CAVES)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Optional<Block> loam = BuiltInRegistries.BLOCK.getOptional(LOAM_ID);
|
||||
BlockState floor = level.getBlockState(pos.below());
|
||||
if (!floor.is(Blocks.MUD) && (loam.isEmpty() || !floor.is(loam.get()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return level.getBlockState(pos.above()).getCollisionShape(level, pos.above()).isEmpty()
|
||||
&& level.getBlockState(pos.above(2)).getCollisionShape(level, pos.above(2)).isEmpty()
|
||||
&& Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||
super.defineSynchedData(builder);
|
||||
@@ -112,12 +153,96 @@ public class WormEntity extends Monster implements GeoEntity {
|
||||
if (this.level().isClientSide) {
|
||||
return;
|
||||
}
|
||||
this.tickMucusTrail();
|
||||
if (this.attackAnimationTicks > 0) {
|
||||
this.attackAnimationTicks--;
|
||||
}
|
||||
this.updateAnimationState();
|
||||
}
|
||||
|
||||
private void tickMucusTrail() {
|
||||
if (this.mucusTrailCooldown > 0) {
|
||||
this.mucusTrailCooldown--;
|
||||
}
|
||||
|
||||
Vec3 velocity = this.getDeltaMovement();
|
||||
if (this.mucusTrailCooldown > 0
|
||||
|| !this.isAlive()
|
||||
|| !this.onGround()
|
||||
|| this.isInWaterOrBubble()
|
||||
|| this.isPassenger()
|
||||
|| velocity.horizontalDistanceSqr() < 0.0025D) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 currentPosition = this.position();
|
||||
if (this.lastMucusTrailPosition != null
|
||||
&& this.lastMucusTrailPosition.distanceToSqr(currentPosition) < MUCUS_TRAIL_MIN_DISTANCE_SQR) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastMucusTrailPosition = currentPosition;
|
||||
this.mucusTrailCooldown = MUCUS_TRAIL_INTERVAL;
|
||||
|
||||
Vec3 horizontalDirection = new Vec3(velocity.x, 0.0D, velocity.z).normalize();
|
||||
BlockPos trailPos = BlockPos.containing(
|
||||
this.getX() - horizontalDirection.x * 0.45D,
|
||||
this.getBoundingBox().minY + 0.01D,
|
||||
this.getZ() - horizontalDirection.z * 0.45D
|
||||
);
|
||||
boolean placed = this.placeFloorMucus(trailPos);
|
||||
|
||||
if (placed && this.random.nextFloat() < 0.35F) {
|
||||
Vec3 side = new Vec3(-horizontalDirection.z, 0.0D, horizontalDirection.x);
|
||||
double sideOffset = this.random.nextBoolean() ? 0.55D : -0.55D;
|
||||
this.placeFloorMucus(BlockPos.containing(
|
||||
trailPos.getX() + 0.5D + side.x * sideOffset,
|
||||
trailPos.getY(),
|
||||
trailPos.getZ() + 0.5D + side.z * sideOffset
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean placeFloorMucus(BlockPos pos) {
|
||||
Optional<Block> mucus = BuiltInRegistries.BLOCK.getOptional(MUCUS_ID);
|
||||
if (mucus.isEmpty() || !(mucus.get() instanceof MultifaceBlock mucusBlock)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockState existing = this.level().getBlockState(pos);
|
||||
var floorFace = MultifaceBlock.getFaceProperty(Direction.DOWN);
|
||||
if (existing.is(mucusBlock)) {
|
||||
if (existing.getValue(floorFace)) {
|
||||
return true;
|
||||
}
|
||||
BlockState merged = existing.setValue(floorFace, true);
|
||||
if (merged.canSurvive(this.level(), pos)) {
|
||||
this.level().setBlock(pos, merged, Block.UPDATE_ALL);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!existing.isAir()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockPos supportPos = pos.below();
|
||||
BlockState support = this.level().getBlockState(supportPos);
|
||||
if (!support.isFaceSturdy(this.level(), supportPos, Direction.UP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockState mucusState = mucusBlock.defaultBlockState().setValue(floorFace, true);
|
||||
if (!mucusState.canSurvive(this.level(), pos)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.level().setBlock(pos, mucusState, Block.UPDATE_ALL);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateAnimationState() {
|
||||
if (this.attackAnimationTicks > 0) {
|
||||
this.entityData.set(ANIMATION_STATE, ANIM_ATTACK);
|
||||
|
||||
+357
-8
@@ -3,6 +3,8 @@ package com.craisinlord.antarchy.content.entity.royal;
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
|
||||
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
@@ -20,10 +22,19 @@ import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LightningBolt;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.MobCategory;
|
||||
import net.minecraft.world.entity.monster.Enemy;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.Pose;
|
||||
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.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.item.ArmorItem;
|
||||
import net.minecraft.world.item.ArmorMaterials;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
@@ -36,6 +47,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamSettings;
|
||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamTerrainMode;
|
||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
||||
import com.craisinlord.antarchy.content.menu.RoyalJudgmentMenu;
|
||||
import com.craisinlord.antarchy.content.menu.RoyalJudgmentState;
|
||||
import com.craisinlord.antarchy.content.entity.royal.decree.CloseQuartersDecree;
|
||||
import com.craisinlord.antarchy.content.entity.royal.decree.ComeNoCloserDecree;
|
||||
import com.craisinlord.antarchy.content.entity.royal.decree.DoNotRunDecree;
|
||||
@@ -85,6 +98,21 @@ public class KingEntity extends RoyalBossEntity {
|
||||
private int iceballCooldownTicks = 120;
|
||||
private int iceSpikeCooldownTicks = 160;
|
||||
private boolean decreeRetreatPressure;
|
||||
@Nullable
|
||||
private ServerPlayer exileTarget;
|
||||
private int exileTicks;
|
||||
@Nullable
|
||||
private ServerPlayer titheTarget;
|
||||
private int titheTicks;
|
||||
@Nullable
|
||||
private ServerPlayer targetShotPlayer;
|
||||
@Nullable
|
||||
private ServerPlayer targetShotVictim;
|
||||
private int targetShotTicks;
|
||||
@Nullable
|
||||
private ServerPlayer sealedTarget;
|
||||
private int sealedTicks;
|
||||
private long sealUntil;
|
||||
private final Map<UUID, Long> judgmentCooldowns = new HashMap<>();
|
||||
private final Map<UUID, Long> lastPlayerDamageTime = new HashMap<>();
|
||||
private final Map<UUID, Integer> iceBuildup = new HashMap<>();
|
||||
@@ -178,6 +206,11 @@ public class KingEntity extends RoyalBossEntity {
|
||||
return RoyalBeamTerrainMode.BUILD_ICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double royalBeamMinimumRange() {
|
||||
return AntarchySettings.kingBeamMinimumRange();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RoyalBeamTerrainMode royalBeamTerrainMode(@Nullable RoyalHead head) {
|
||||
return head != null && head.slot() == RoyalHead.Slot.RIGHT ? RoyalBeamTerrainMode.BUILD_ICE : RoyalBeamTerrainMode.NONE;
|
||||
@@ -298,6 +331,7 @@ public class KingEntity extends RoyalBossEntity {
|
||||
if (this.level().isClientSide) {
|
||||
return;
|
||||
}
|
||||
this.tickRoyalPunishment();
|
||||
if (this.iceBuildup.size() > 16) {
|
||||
this.iceBuildup.clear();
|
||||
}
|
||||
@@ -328,6 +362,262 @@ public class KingEntity extends RoyalBossEntity {
|
||||
}
|
||||
}
|
||||
|
||||
private void tickRoyalPunishment() {
|
||||
if (this.exileTarget == null && this.titheTarget == null && this.targetShotPlayer == null && this.sealedTarget == null) {
|
||||
return;
|
||||
}
|
||||
if (this.exileTarget != null) {
|
||||
this.tickRoyalExile();
|
||||
}
|
||||
if (this.titheTarget != null) {
|
||||
this.tickRoyalTithe();
|
||||
}
|
||||
if (this.targetShotPlayer != null) {
|
||||
this.tickRoyalTargetShot();
|
||||
}
|
||||
if (this.sealedTarget != null) {
|
||||
this.tickRoyalSeal();
|
||||
}
|
||||
}
|
||||
|
||||
private void tickRoyalExile() {
|
||||
if (this.exileTicks-- <= 0 || !this.exileTarget.isAlive() || this.exileTarget.level() != this.level()
|
||||
|| this.isDeadOrDying()) {
|
||||
this.clearExile();
|
||||
return;
|
||||
}
|
||||
this.exileTarget.lookAt(EntityAnchorArgument.Anchor.EYES, this.getEyePosition());
|
||||
this.exileTarget.setPose(Pose.CROUCHING);
|
||||
this.exileTarget.setShiftKeyDown(true);
|
||||
if (this.exileTicks == 1) {
|
||||
Vec3 away = this.exileTarget.position().subtract(this.position()).multiply(1.0D, 0.0D, 1.0D);
|
||||
if (away.lengthSqr() < 1.0E-4D) {
|
||||
away = this.getLookAngle().multiply(-1.0D, 0.0D, -1.0D);
|
||||
}
|
||||
away = away.normalize();
|
||||
this.exileTarget.setDeltaMovement(away.x * 2.6D, 1.35D, away.z * 2.6D);
|
||||
this.exileTarget.hasImpulse = true;
|
||||
this.triggerAnim("body_action", "wing_gust");
|
||||
this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.82F);
|
||||
}
|
||||
}
|
||||
|
||||
private void tickRoyalTithe() {
|
||||
if (!this.titheTarget.isAlive() || this.titheTarget.level() != this.level()
|
||||
|| this.isDeadOrDying() || !(this.titheTarget.containerMenu instanceof RoyalJudgmentMenu)) {
|
||||
this.clearTithe();
|
||||
return;
|
||||
}
|
||||
if (--this.titheTicks <= 0) {
|
||||
for (int slot = 0; slot < this.titheTarget.getInventory().getContainerSize(); slot++) {
|
||||
ItemStack stack = this.titheTarget.getInventory().getItem(slot);
|
||||
if (stack.isEmpty() || !isRoyalTitheItem(stack)) continue;
|
||||
ItemStack thrown = stack.split(1);
|
||||
this.titheTarget.getInventory().setChanged();
|
||||
this.titheTarget.drop(thrown, true);
|
||||
this.clearTithe();
|
||||
return;
|
||||
}
|
||||
this.clearTithe();
|
||||
}
|
||||
}
|
||||
|
||||
private void tickRoyalTargetShot() {
|
||||
if (!this.targetShotPlayer.isAlive() || this.targetShotVictim == null || !this.targetShotVictim.isAlive()
|
||||
|| this.targetShotPlayer.level() != this.level() || this.isDeadOrDying()
|
||||
|| !(this.targetShotPlayer.containerMenu instanceof RoyalJudgmentMenu)) {
|
||||
this.clearTargetShot();
|
||||
return;
|
||||
}
|
||||
this.targetShotPlayer.lookAt(EntityAnchorArgument.Anchor.EYES, this.targetShotVictim.getEyePosition());
|
||||
if (--this.targetShotTicks <= 0) {
|
||||
ItemStack ranged = findRoyalRangedItem(this.targetShotPlayer);
|
||||
if (!ranged.isEmpty()) {
|
||||
Arrow arrow = new Arrow((ServerLevel) this.level(), this.targetShotPlayer, ItemStack.EMPTY, ItemStack.EMPTY);
|
||||
arrow.setPos(this.targetShotPlayer.getX(), this.targetShotPlayer.getEyeY() - 0.1D, this.targetShotPlayer.getZ());
|
||||
Vec3 direction = this.targetShotVictim.getEyePosition().subtract(arrow.position()).normalize();
|
||||
arrow.setDeltaMovement(direction.scale(3.0D));
|
||||
arrow.setBaseDamage(2.0D);
|
||||
((ServerLevel) this.level()).addFreshEntity(arrow);
|
||||
this.targetShotPlayer.displayClientMessage(Component.literal("The King takes your shot."), true);
|
||||
}
|
||||
this.clearTargetShot();
|
||||
}
|
||||
}
|
||||
|
||||
private void tickRoyalSeal() {
|
||||
if (!this.sealedTarget.isAlive() || this.sealedTarget.level() != this.level() || this.isDeadOrDying()
|
||||
|| !(this.sealedTarget.containerMenu instanceof RoyalJudgmentMenu) || --this.sealedTicks <= 0) {
|
||||
this.clearSeal();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearExile() {
|
||||
if (this.exileTarget != null && this.exileTarget.isAlive()) {
|
||||
this.exileTarget.setShiftKeyDown(false);
|
||||
this.exileTarget.setPose(Pose.STANDING);
|
||||
}
|
||||
this.exileTarget = null;
|
||||
this.exileTicks = 0;
|
||||
}
|
||||
|
||||
private void clearTithe() {
|
||||
if (this.titheTarget != null && this.titheTarget.containerMenu instanceof RoyalJudgmentMenu) {
|
||||
this.titheTarget.closeContainer();
|
||||
}
|
||||
this.titheTarget = null;
|
||||
this.titheTicks = 0;
|
||||
}
|
||||
|
||||
private void clearTargetShot() {
|
||||
if (this.targetShotPlayer != null && this.targetShotPlayer.containerMenu instanceof RoyalJudgmentMenu) {
|
||||
this.targetShotPlayer.closeContainer();
|
||||
}
|
||||
this.targetShotPlayer = null;
|
||||
this.targetShotVictim = null;
|
||||
this.targetShotTicks = 0;
|
||||
}
|
||||
|
||||
private void clearSeal() {
|
||||
if (this.sealedTarget != null) {
|
||||
RoyalJudgmentState.clear(this.sealedTarget.getUUID());
|
||||
if (this.sealedTarget.containerMenu instanceof RoyalJudgmentMenu) {
|
||||
this.sealedTarget.closeContainer();
|
||||
}
|
||||
}
|
||||
this.sealedTarget = null;
|
||||
this.sealedTicks = 0;
|
||||
}
|
||||
|
||||
private void startTithe(ServerPlayer target) {
|
||||
this.clearTithe();
|
||||
this.titheTarget = target;
|
||||
this.titheTicks = 20;
|
||||
target.openMenu(new MenuProvider() {
|
||||
@Override
|
||||
public Component getDisplayName() {
|
||||
return Component.translatable("menu.antarchy.royal_judgment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int containerId, net.minecraft.world.entity.player.Inventory inventory,
|
||||
Player player) {
|
||||
return new RoyalJudgmentMenu(containerId, inventory);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void startTargetShot(ServerPlayer target, ServerPlayer victim) {
|
||||
this.clearTargetShot();
|
||||
this.targetShotPlayer = target;
|
||||
this.targetShotVictim = victim;
|
||||
this.targetShotTicks = 20;
|
||||
target.openMenu(new MenuProvider() {
|
||||
@Override
|
||||
public Component getDisplayName() {
|
||||
return Component.translatable("menu.antarchy.royal_judgment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int containerId, net.minecraft.world.entity.player.Inventory inventory,
|
||||
Player player) {
|
||||
return new RoyalJudgmentMenu(containerId, inventory);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void startSeal(ServerPlayer target) {
|
||||
this.clearSeal();
|
||||
java.util.Set<Integer> slots = new java.util.HashSet<>();
|
||||
for (int slot = 9; slot < 18; slot++) slots.add(slot);
|
||||
RoyalJudgmentState.seal(target.getUUID(), slots);
|
||||
this.sealedTarget = target;
|
||||
this.sealedTicks = 100;
|
||||
target.openMenu(new MenuProvider() {
|
||||
@Override
|
||||
public Component getDisplayName() {
|
||||
return Component.translatable("menu.antarchy.royal_judgment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int containerId, net.minecraft.world.entity.player.Inventory inventory,
|
||||
Player player) {
|
||||
return new RoyalJudgmentMenu(containerId, inventory);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean debugActivateDecree(String id, ServerPlayer target) {
|
||||
for (RoyalDecree decree : DECREES) {
|
||||
String decreeId = decree.translationKey().substring(decree.translationKey().lastIndexOf('.') + 1);
|
||||
if (decreeId.equalsIgnoreCase(id.replace('-', '_'))) {
|
||||
this.endDecree(this.getTarget());
|
||||
this.activeDecree = decree;
|
||||
this.activeDecreeTicks = 300;
|
||||
this.decreeCooldownTicks = 0;
|
||||
this.sendDecreeTitle(target);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean debugTriggerPunishment(RoyalPunishmentType type, ServerPlayer target) {
|
||||
if (!(this.level() instanceof ServerLevel level) || !target.isAlive() || target.level() != level) {
|
||||
return false;
|
||||
}
|
||||
switch (type) {
|
||||
case ROYAL_EXILE -> {
|
||||
this.clearExile();
|
||||
this.exileTarget = target;
|
||||
this.exileTicks = 25;
|
||||
return true;
|
||||
}
|
||||
case ROYAL_TITHE -> {
|
||||
this.startTithe(target);
|
||||
return true;
|
||||
}
|
||||
case KINGS_TARGET -> {
|
||||
ServerPlayer victim = level.players().stream()
|
||||
.filter(candidate -> candidate != target && candidate.isAlive() && candidate.distanceToSqr(target) <= 4096.0D)
|
||||
.min((left, right) -> Double.compare(left.distanceToSqr(target), right.distanceToSqr(target)))
|
||||
.orElse(null);
|
||||
if (victim == null) return false;
|
||||
ItemStack ranged = findRoyalRangedItem(target);
|
||||
if (ranged.isEmpty()) return false;
|
||||
target.displayClientMessage(Component.literal("The King chooses your target."), true);
|
||||
this.startTargetShot(target, victim);
|
||||
return true;
|
||||
}
|
||||
case KINGS_SEAL -> {
|
||||
this.sealUntil = level.getGameTime() + 100L;
|
||||
target.displayClientMessage(Component.literal("The King seals your inventory."), true);
|
||||
level.sendParticles(ParticleTypes.ENCHANT, target.getX(), target.getY() + 1.0D, target.getZ(),
|
||||
30, 0.6D, 1.0D, 0.6D, 0.1D);
|
||||
this.startSeal(target);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isRoyalTitheItem(ItemStack stack) {
|
||||
return stack.is(net.minecraft.world.item.Items.ARROW)
|
||||
|| stack.is(net.minecraft.world.item.Items.BREAD)
|
||||
|| stack.is(net.minecraft.world.item.Items.COBBLESTONE)
|
||||
|| stack.is(net.minecraft.world.item.Items.POTION);
|
||||
}
|
||||
|
||||
private static ItemStack findRoyalRangedItem(ServerPlayer player) {
|
||||
for (ItemStack stack : player.getInventory().items) {
|
||||
if (stack.getItem() instanceof net.minecraft.world.item.BowItem
|
||||
|| stack.getItem() instanceof net.minecraft.world.item.CrossbowItem) {
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
private void trackBehavior(LivingEntity target) {
|
||||
double distance = target.distanceTo(this);
|
||||
this.bumpBehavior(Behavior.AIRBORNE, !target.onGround() && !target.isPassenger() ? 1 : -1);
|
||||
@@ -389,6 +679,27 @@ public class KingEntity extends RoyalBossEntity {
|
||||
KingEntity.this.performWingGust(level, target);
|
||||
}
|
||||
})) {
|
||||
} else if (this.attackScheduler.ready("royal_muster", RoyalAttackLane.BODY)
|
||||
&& !this.findRoyalMusterTargets(level).isEmpty()
|
||||
&& (forceFar || this.random.nextInt(4) == 0)
|
||||
&& this.beginRoyalAttack("royal_muster", RoyalAttackLane.BODY,
|
||||
AntarchySettings.kingRoyalMusterCooldownTicks(),
|
||||
AntarchySettings.kingRoyalMusterWindupTicks(), 1, 20,
|
||||
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||
@Override public void onStart() {
|
||||
KingEntity.this.triggerAnim("body_action", "minion_spawn");
|
||||
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 0.72F);
|
||||
level.sendParticles(ParticleTypes.ENCHANT,
|
||||
KingEntity.this.getX(), KingEntity.this.getY() + 2.0D, KingEntity.this.getZ(),
|
||||
36, 5.0D, 2.0D, 5.0D, 0.12D);
|
||||
}
|
||||
@Override public void onActive(int elapsedTicks) {
|
||||
KingEntity.this.performRoyalMuster(level);
|
||||
}
|
||||
@Override public void onComplete() {
|
||||
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 0.62F);
|
||||
}
|
||||
})) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,6 +714,37 @@ public class KingEntity extends RoyalBossEntity {
|
||||
this.tickKingElementalProjectiles(level, target);
|
||||
}
|
||||
|
||||
private List<Mob> findRoyalMusterTargets(ServerLevel level) {
|
||||
double radius = AntarchySettings.kingRoyalMusterRadius();
|
||||
return level.getEntitiesOfClass(Mob.class, this.getBoundingBox().inflate(radius), mob ->
|
||||
mob.isAlive() && mob != this
|
||||
&& (mob.getType().getCategory() == MobCategory.MONSTER || mob instanceof Enemy)
|
||||
&& !(mob instanceof RoyalBossEntity)
|
||||
&& RoyalEffectEligibility.canApplyCommanded(mob));
|
||||
}
|
||||
|
||||
private void performRoyalMuster(ServerLevel level) {
|
||||
var commanded = RoyalEffectHooks.commandedHolder();
|
||||
if (commanded == null) {
|
||||
return;
|
||||
}
|
||||
int applied = 0;
|
||||
for (Mob mob : this.findRoyalMusterTargets(level)) {
|
||||
if (applied >= AntarchySettings.kingRoyalMusterCap()) {
|
||||
break;
|
||||
}
|
||||
if (mob.addEffect(new MobEffectInstance(commanded, AntarchySettings.kingRoyalMusterDurationTicks()), this)) {
|
||||
applied++;
|
||||
level.sendParticles(ParticleTypes.HAPPY_VILLAGER,
|
||||
mob.getX(), mob.getY() + mob.getBbHeight() + 0.3D, mob.getZ(),
|
||||
5, 0.3D, 0.2D, 0.3D, 0.02D);
|
||||
}
|
||||
}
|
||||
if (applied > 0) {
|
||||
this.playRoyalSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 0.95F);
|
||||
}
|
||||
}
|
||||
|
||||
private void tickKingElementalProjectiles(ServerLevel level, LivingEntity target) {
|
||||
if (this.fireballCooldownTicks > 0) this.fireballCooldownTicks--;
|
||||
if (this.iceballCooldownTicks > 0) this.iceballCooldownTicks--;
|
||||
@@ -549,13 +891,7 @@ public class KingEntity extends RoyalBossEntity {
|
||||
this.decreeRetreatPressure = false;
|
||||
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);
|
||||
if (target instanceof ServerPlayer player) {
|
||||
player.connection.send(new ClientboundSetTitlesAnimationPacket(5, 300, 10));
|
||||
player.connection.send(new ClientboundSetTitleTextPacket(Component.translatable(this.activeDecree.translationKey())
|
||||
.withStyle(style -> style.withColor(ChatFormatting.GOLD).withBold(true))));
|
||||
player.connection.send(new ClientboundSetSubtitleTextPacket(Component.translatable(this.activeDecree.instructionKey())
|
||||
.withStyle(style -> style.withColor(ChatFormatting.WHITE))));
|
||||
}
|
||||
if (target instanceof ServerPlayer player) this.sendDecreeTitle(player);
|
||||
}
|
||||
int countdown = this.activeDecree.countdownTicks(target);
|
||||
if (countdown > 0 && countdown <= 100 && this.tickCount % 20 == 0) {
|
||||
@@ -589,6 +925,15 @@ public class KingEntity extends RoyalBossEntity {
|
||||
return DECREES.get(this.random.nextInt(DECREES.size()));
|
||||
}
|
||||
|
||||
private void sendDecreeTitle(ServerPlayer player) {
|
||||
if (this.activeDecree == null) return;
|
||||
player.connection.send(new ClientboundSetTitlesAnimationPacket(5, 300, 10));
|
||||
player.connection.send(new ClientboundSetTitleTextPacket(Component.translatable(this.activeDecree.translationKey())
|
||||
.withStyle(style -> style.withColor(ChatFormatting.GOLD).withBold(true))));
|
||||
player.connection.send(new ClientboundSetSubtitleTextPacket(Component.translatable(this.activeDecree.instructionKey())
|
||||
.withStyle(style -> style.withColor(ChatFormatting.WHITE))));
|
||||
}
|
||||
|
||||
private void endDecree(@Nullable LivingEntity target) {
|
||||
if (target instanceof ServerPlayer player) {
|
||||
player.connection.send(new ClientboundClearTitlesPacket(false));
|
||||
@@ -615,7 +960,11 @@ public class KingEntity extends RoyalBossEntity {
|
||||
if (this.activeDecree == null || target == null || !target.isAlive()) {
|
||||
return;
|
||||
}
|
||||
this.invokeJudgment(target);
|
||||
if (target instanceof ServerPlayer player) {
|
||||
this.debugTriggerPunishment(RoyalPunishmentType.ROYAL_EXILE, player);
|
||||
} else {
|
||||
this.invokeJudgment(target);
|
||||
}
|
||||
this.endDecree(target);
|
||||
}
|
||||
|
||||
|
||||
+14
-1
@@ -37,6 +37,7 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
||||
private static final String OWNER_KEY = "OwnerUuid";
|
||||
private static final String AGE_KEY = "Age";
|
||||
private static final String ACTIVE_KEY = "ActiveTicks";
|
||||
private static final String ASSAILANT_KEY = "AssailantVariant";
|
||||
|
||||
private static final double DEFAULT_RADIUS = 14.0D;
|
||||
private static final int DEFAULT_ACTIVE_TICKS = 120;
|
||||
@@ -46,6 +47,7 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
||||
private UUID ownerId;
|
||||
private int age;
|
||||
private int activeTicks = DEFAULT_ACTIVE_TICKS;
|
||||
private boolean assailantVariant;
|
||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||
|
||||
public RoyalBlackHoleEntity(EntityType<? extends RoyalBlackHoleEntity> entityType, Level level) {
|
||||
@@ -67,6 +69,12 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
||||
return create(level, center, AntarchySettings.queenBlackHoleRadius(), AntarchySettings.queenBlackHoleActiveTicks(), ownerId);
|
||||
}
|
||||
|
||||
public static RoyalBlackHoleEntity createAssailant(ServerLevel level, Vec3 center, @Nullable UUID ownerId) {
|
||||
RoyalBlackHoleEntity hole = create(level, center, AntarchySettings.queenBlackHoleRadius(), AntarchySettings.queenBlackHoleActiveTicks(), ownerId);
|
||||
hole.assailantVariant = true;
|
||||
return hole;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||
builder.define(RADIUS, (float) DEFAULT_RADIUS);
|
||||
@@ -94,9 +102,12 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
||||
}
|
||||
this.age++;
|
||||
if (!this.isCollapsing()) {
|
||||
if (this.assailantVariant) {
|
||||
this.setPos(this.getX(), this.getY() + 0.035D, this.getZ());
|
||||
}
|
||||
this.applyPull();
|
||||
if (this.age % 10 == 0 && this.level() instanceof ServerLevel level) {
|
||||
TimeDilationApi.createField(level, this.position(), Math.max(2.0D, this.radius() * 0.55D), 0.18D, 14);
|
||||
TimeDilationApi.createField(level, this.position(), Math.max(2.0D, this.radius() * 0.55D), 0.18D, 14, this.ownerId, !this.assailantVariant);
|
||||
if (this.age % 20 == 0 && level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
||||
RoyalBlockDestruction.destroySphere(level, this, this.position(), Math.min(2.0D, this.radius() * 0.2D), 8, 30.0D, 0.0F);
|
||||
}
|
||||
@@ -207,6 +218,7 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
||||
this.age = tag.getInt(AGE_KEY);
|
||||
this.activeTicks = tag.contains(ACTIVE_KEY) ? tag.getInt(ACTIVE_KEY) : DEFAULT_ACTIVE_TICKS;
|
||||
this.ownerId = tag.hasUUID(OWNER_KEY) ? tag.getUUID(OWNER_KEY) : null;
|
||||
this.assailantVariant = tag.getBoolean(ASSAILANT_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -217,6 +229,7 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
||||
if (this.ownerId != null) {
|
||||
tag.putUUID(OWNER_KEY, this.ownerId);
|
||||
}
|
||||
tag.putBoolean(ASSAILANT_KEY, this.assailantVariant);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+67
-12
@@ -98,6 +98,13 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
private static final int OBSTRUCTION_CLEAR_MAX_BLOCKS = 24;
|
||||
private static final double OBSTRUCTION_CLEAR_MAX_RESISTANCE = 60.0D;
|
||||
private static final float OBSTRUCTION_CLEAR_DROP_CHANCE = 0.1F;
|
||||
// Keep visual muzzle points separate from the centered multipart hitboxes.
|
||||
// Geo mouth fronts are near z=-219, with side heads centered at x=+/-21. At 2x render scale,
|
||||
// one model pixel is 1/8 block.
|
||||
private static final double BEAM_MUZZLE_FORWARD = 27.375D;
|
||||
private static final double BEAM_MUZZLE_CENTER_Y = 11.5D;
|
||||
private static final double BEAM_MUZZLE_SIDE_Y = 10.25D;
|
||||
private static final double BEAM_MUZZLE_LATERAL = 2.625D;
|
||||
|
||||
protected static final double FLYING_MIN_HOVER = 2.5D;
|
||||
protected static final double FLYING_PREFERRED_HOVER = 6.0D;
|
||||
@@ -111,6 +118,8 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN);
|
||||
private static final EntityDataAccessor<Integer> BEAM_ELEMENT =
|
||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.INT);
|
||||
private static final EntityDataAccessor<Integer> BEAM_HEAD_SLOT =
|
||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.INT);
|
||||
private static final EntityDataAccessor<Float> BEAM_END_X =
|
||||
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT);
|
||||
private static final EntityDataAccessor<Float> BEAM_END_Y =
|
||||
@@ -260,6 +269,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
builder.define(HAS_BEAM_END, false);
|
||||
builder.define(ACCELERATED, false);
|
||||
builder.define(BEAM_ELEMENT, RoyalBeamElement.GENERIC.ordinal());
|
||||
builder.define(BEAM_HEAD_SLOT, -1);
|
||||
builder.define(BEAM_END_X, 0.0F);
|
||||
builder.define(BEAM_END_Y, 0.0F);
|
||||
builder.define(BEAM_END_Z, 0.0F);
|
||||
@@ -396,7 +406,8 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
|
||||
if (this.activeBeamHead != null) {
|
||||
LivingEntity beamTarget = this.activeBeamHead.target(this.level());
|
||||
if (!this.activeBeamHead.shooting() || beamTarget == null || !beamTarget.isAlive()) {
|
||||
if (!this.activeBeamHead.shooting() || beamTarget == null || !beamTarget.isAlive()
|
||||
|| this.distanceTo(beamTarget) < this.royalBeamMinimumRange()) {
|
||||
this.stopRoyalBeam();
|
||||
} else if (!this.beamStarted) {
|
||||
return;
|
||||
@@ -406,14 +417,14 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
this.playRoyalSound(this.royalBeamLoopSound(), 1.0F);
|
||||
}
|
||||
this.beamController.tick(
|
||||
this.headAnchor(this.activeBeamHead),
|
||||
this.beamAnchor(this.activeBeamHead),
|
||||
beamTarget,
|
||||
this.royalBeamSettings(),
|
||||
this.royalBeamTerrainMode(this.activeBeamHead),
|
||||
this::setRoyalBeamEndPosition);
|
||||
Vec3 beamEnd = this.beamController.beamEndPosition();
|
||||
if (beamEnd != null) {
|
||||
this.tickRoyalBeamEffects(this.activeBeamHead, this.headAnchor(this.activeBeamHead), beamEnd);
|
||||
this.tickRoyalBeamEffects(this.activeBeamHead, this.beamAnchor(this.activeBeamHead), beamEnd);
|
||||
}
|
||||
if (!this.beamController.isFiring()) {
|
||||
this.stopRoyalBeam();
|
||||
@@ -431,6 +442,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
LivingEntity target = head.target(this.level());
|
||||
if (!head.readyToAttack() || this.attackScheduler.laneBusy(this.headLane(head))
|
||||
|| target == null || !this.canAttack(target)
|
||||
|| this.distanceTo(target) < this.royalBeamMinimumRange()
|
||||
|| this.headWithinBiteReach(head, target)) {
|
||||
continue;
|
||||
}
|
||||
@@ -456,8 +468,9 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
}
|
||||
RoyalBossEntity.this.beamStarted = true;
|
||||
RoyalBossEntity.this.beamController.start(
|
||||
RoyalBossEntity.this.headAnchor(head), committedTarget.getEyePosition(), duration);
|
||||
RoyalBossEntity.this.beamAnchor(head), committedTarget.getEyePosition(), duration);
|
||||
RoyalBossEntity.this.entityData.set(BEAM_ELEMENT, RoyalBossEntity.this.royalBeamElement(head).ordinal());
|
||||
RoyalBossEntity.this.entityData.set(BEAM_HEAD_SLOT, head.slot().ordinal());
|
||||
RoyalBossEntity.this.setFiringRoyalBeam(true);
|
||||
RoyalBossEntity.this.triggerAnim(head.slot().controllerName(), "shoot");
|
||||
RoyalBossEntity.this.beamLoopSoundTicks = 20;
|
||||
@@ -493,6 +506,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
this.attackScheduler.cancel(this.beamLane());
|
||||
this.beamController.stop();
|
||||
this.entityData.set(BEAM_ELEMENT, RoyalBeamElement.GENERIC.ordinal());
|
||||
this.entityData.set(BEAM_HEAD_SLOT, -1);
|
||||
this.playRoyalSound(this.royalBeamEndSound(), 1.0F);
|
||||
this.setFiringRoyalBeam(false);
|
||||
this.setRoyalBeamEndPosition(null);
|
||||
@@ -708,6 +722,30 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
this.getZ() + forward.z * spec.forwardOffset() + right.z * spec.lateralOffset());
|
||||
}
|
||||
|
||||
protected Vec3 beamAnchor(RoyalHead head) {
|
||||
return beamAnchor(head.slot(), this.getX(), this.getY(), this.getZ(), this.getYRot());
|
||||
}
|
||||
|
||||
private Vec3 beamAnchor(RoyalHead.Slot slot, double x, double y, double z, float yaw) {
|
||||
double yawRadians = yaw * Mth.DEG_TO_RAD;
|
||||
Vec3 forward = new Vec3(-Math.sin(yawRadians), 0.0D, Math.cos(yawRadians));
|
||||
Vec3 right = new Vec3(forward.z, 0.0D, -forward.x);
|
||||
double lateral = switch (slot) {
|
||||
case LEFT -> -BEAM_MUZZLE_LATERAL;
|
||||
case CENTER -> 0.0D;
|
||||
case RIGHT -> BEAM_MUZZLE_LATERAL;
|
||||
};
|
||||
double vertical = slot == RoyalHead.Slot.CENTER ? BEAM_MUZZLE_CENTER_Y : BEAM_MUZZLE_SIDE_Y;
|
||||
return new Vec3(
|
||||
x + forward.x * BEAM_MUZZLE_FORWARD + right.x * lateral,
|
||||
y + vertical,
|
||||
z + forward.z * BEAM_MUZZLE_FORWARD + right.z * lateral);
|
||||
}
|
||||
|
||||
protected double royalBeamMinimumRange() {
|
||||
return AntarchySettings.queenBeamMinimumRange();
|
||||
}
|
||||
|
||||
protected RoyalHead royalHead(RoyalHead.Slot slot) {
|
||||
return this.heads[slot.ordinal()];
|
||||
}
|
||||
@@ -826,8 +864,15 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
}
|
||||
|
||||
public Vec3 getRoyalBeamShootFrom(float partialTicks) {
|
||||
if (this.activeBeamHead != null) {
|
||||
return this.headAnchor(this.activeBeamHead);
|
||||
int slotIndex = this.activeBeamHead != null
|
||||
? this.activeBeamHead.slot().ordinal()
|
||||
: this.entityData.get(BEAM_HEAD_SLOT);
|
||||
if (slotIndex >= 0 && slotIndex < RoyalHead.Slot.values().length) {
|
||||
double x = Mth.lerp(partialTicks, this.xo, this.getX());
|
||||
double y = Mth.lerp(partialTicks, this.yo, this.getY());
|
||||
double z = Mth.lerp(partialTicks, this.zo, this.getZ());
|
||||
float yaw = Mth.rotLerp(partialTicks, this.yRotO, this.getYRot());
|
||||
return this.beamAnchor(RoyalHead.Slot.values()[slotIndex], x, y, z, yaw);
|
||||
}
|
||||
double x = Mth.lerp(partialTicks, this.xo, this.getX());
|
||||
double y = Mth.lerp(partialTicks, this.yo, this.getY()) + this.getBbHeight() * 0.72D;
|
||||
@@ -842,18 +887,28 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
||||
: RoyalBeamElement.GENERIC;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RoyalHead.Slot getRoyalBeamHeadSlot() {
|
||||
int slotIndex = this.activeBeamHead != null
|
||||
? this.activeBeamHead.slot().ordinal()
|
||||
: this.entityData.get(BEAM_HEAD_SLOT);
|
||||
return slotIndex >= 0 && slotIndex < RoyalHead.Slot.values().length
|
||||
? RoyalHead.Slot.values()[slotIndex]
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||
controllers.add(new AnimationController<>(this, "locomotion", 4, this::locomotionPredicate));
|
||||
controllers.add(new AnimationController<>(this, "head_left", 0, RoyalBossEntity::headIdle)
|
||||
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_1"))
|
||||
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_1")));
|
||||
controllers.add(new AnimationController<>(this, "head_center", 0, RoyalBossEntity::headIdle)
|
||||
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_2"))
|
||||
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_2")));
|
||||
controllers.add(new AnimationController<>(this, "head_right", 0, RoyalBossEntity::headIdle)
|
||||
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_3"))
|
||||
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_3")));
|
||||
controllers.add(new AnimationController<>(this, "head_center", 0, RoyalBossEntity::headIdle)
|
||||
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_1"))
|
||||
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_1")));
|
||||
controllers.add(new AnimationController<>(this, "head_right", 0, RoyalBossEntity::headIdle)
|
||||
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_2"))
|
||||
.triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_2")));
|
||||
controllers.add(new AnimationController<>(this, "body_action", 0, this::bodyActionPredicate)
|
||||
.triggerableAnim("stomp", RawAnimation.begin().thenPlay("stomp"))
|
||||
.triggerableAnim("wing_gust", RawAnimation.begin().thenPlay("wing_gust"))
|
||||
|
||||
+3
-3
@@ -9,11 +9,11 @@ public final class RoyalBossMultipartLayout implements MultipartLayout {
|
||||
public static final MultipartPartDefinition BODY = new MultipartPartDefinition(
|
||||
"body", 20.0F, 24.0F, 1.00F, 0.0D, 3.0D, 0.0D, true);
|
||||
public static final MultipartPartDefinition LEFT_HEAD = new MultipartPartDefinition(
|
||||
"left_head", 4.0F, 4.0F, 1.30F, 12.0D, 20.0D, -7.0D, true);
|
||||
"left_head", 4.0F, 4.0F, 1.30F, 24.75D, 8.5D, -2.625D, true);
|
||||
public static final MultipartPartDefinition CENTER_HEAD = new MultipartPartDefinition(
|
||||
"center_head", 4.5F, 4.5F, 1.20F, 13.0D, 22.0D, 0.0D, true);
|
||||
"center_head", 4.5F, 4.5F, 1.20F, 24.75D, 9.5D, 0.0D, true);
|
||||
public static final MultipartPartDefinition RIGHT_HEAD = new MultipartPartDefinition(
|
||||
"right_head", 4.0F, 4.0F, 1.30F, 12.0D, 20.0D, 7.0D, true);
|
||||
"right_head", 4.0F, 4.0F, 1.30F, 24.75D, 8.5D, 2.625D, true);
|
||||
public static final MultipartPartDefinition LEFT_WING = new MultipartPartDefinition(
|
||||
"left_wing", 14.0F, 16.0F, 0.85F, -2.0D, 14.0D, -13.0D, true);
|
||||
public static final MultipartPartDefinition RIGHT_WING = new MultipartPartDefinition(
|
||||
|
||||
+3
-3
@@ -6,9 +6,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class RoyalHead {
|
||||
public enum Slot {
|
||||
LEFT(1, "head_left", "bite_1", "shoot_1"),
|
||||
CENTER(2, "head_center", "bite_2", "shoot_2"),
|
||||
RIGHT(3, "head_right", "bite_3", "shoot_3");
|
||||
LEFT(1, "head_left", "bite_3", "shoot_3"),
|
||||
CENTER(2, "head_center", "bite_1", "shoot_1"),
|
||||
RIGHT(3, "head_right", "bite_2", "shoot_2");
|
||||
|
||||
private final int partIndex;
|
||||
private final String controllerName;
|
||||
|
||||
+8
-9
@@ -22,8 +22,9 @@ import software.bernie.geckolib.animation.RawAnimation;
|
||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||
|
||||
public class RoyalIceSpikeEntity extends Entity implements GeoEntity {
|
||||
private static final RawAnimation EMERGE_ANIMATION = RawAnimation.begin().thenPlay("ice_spike");
|
||||
private static final RawAnimation IMPACT_ANIMATION = RawAnimation.begin().thenPlay("ice_spike_impact");
|
||||
// The exported asset contains one coordinated animation for all four spike groups.
|
||||
private static final RawAnimation SPIKE_ANIMATION = RawAnimation.begin().thenPlay("animation");
|
||||
private static final String ANIMATION_CONTROLLER = "ice_spike";
|
||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||
private boolean impacted;
|
||||
|
||||
@@ -46,15 +47,14 @@ public class RoyalIceSpikeEntity extends Entity implements GeoEntity {
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if (!this.level().isClientSide && this.tickCount == 1) {
|
||||
this.triggerAnim("ice_spike", "emerge");
|
||||
if (this.tickCount == 1) {
|
||||
this.triggerAnim(ANIMATION_CONTROLLER, "emerge");
|
||||
}
|
||||
if (!this.level().isClientSide && this.tickCount == 6 && !this.impacted) {
|
||||
this.impacted = true;
|
||||
this.impact((ServerLevel) this.level());
|
||||
this.triggerAnim("ice_spike", "impact");
|
||||
}
|
||||
if (!this.level().isClientSide && this.tickCount > 45) {
|
||||
if (!this.level().isClientSide && this.tickCount > 110) {
|
||||
this.discard();
|
||||
}
|
||||
if (this.level().isClientSide && this.tickCount < 10) {
|
||||
@@ -86,9 +86,8 @@ public class RoyalIceSpikeEntity extends Entity implements GeoEntity {
|
||||
|
||||
@Override
|
||||
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||
controllers.add(new AnimationController<>(this, "ice_spike", 0, state -> PlayState.STOP)
|
||||
.triggerableAnim("emerge", EMERGE_ANIMATION)
|
||||
.triggerableAnim("impact", IMPACT_ANIMATION));
|
||||
controllers.add(new AnimationController<>(this, ANIMATION_CONTROLLER, 0, state -> PlayState.STOP)
|
||||
.triggerableAnim("emerge", SPIKE_ANIMATION));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+15
-7
@@ -75,6 +75,7 @@ public class WindVortexEntity extends Entity {
|
||||
private static final double FALL_ACCELERATION = 0.006D;
|
||||
private static final double MAX_FALL_SPEED = 0.08D;
|
||||
private static final double MINIMUM_DOWNWARD_DRIFT = 0.012D;
|
||||
private static final double ENTITY_FORCE_SPEED_SCALE = 0.5D;
|
||||
private static final int FADE_OUT_TICKS = 8;
|
||||
|
||||
public enum VortexMode {
|
||||
@@ -509,12 +510,14 @@ public class WindVortexEntity extends Entity {
|
||||
case GATHER_RETURN -> (0.05D + progress * 0.08D) * massScale;
|
||||
} * playerScale;
|
||||
if (mode == VortexMode.UPWARD && entity.onGround()) {
|
||||
axialSpeed = Math.max(axialSpeed, entity instanceof Player ? 0.38D : 0.3D);
|
||||
axialSpeed = Math.max(axialSpeed,
|
||||
(entity instanceof Player ? 0.38D : 0.3D) * ENTITY_FORCE_SPEED_SCALE);
|
||||
}
|
||||
|
||||
Vec3 wanted = radial.scale(radialError * pull)
|
||||
.add(tangent.scale(spin))
|
||||
.add(basis.axis.scale(axialSpeed));
|
||||
.add(basis.axis.scale(axialSpeed))
|
||||
.scale(ENTITY_FORCE_SPEED_SCALE);
|
||||
Vec3 current = entity.getDeltaMovement();
|
||||
Vec3 updatedMovement = new Vec3(
|
||||
Mth.lerp(0.72D, current.x, wanted.x),
|
||||
@@ -522,10 +525,13 @@ public class WindVortexEntity extends Entity {
|
||||
Mth.lerp(0.72D, current.z, wanted.z)
|
||||
);
|
||||
if (this.travelling) {
|
||||
updatedMovement = updatedMovement.add(this.travelVelocity.x * 0.8D, 0.0D, this.travelVelocity.z * 0.8D);
|
||||
updatedMovement = updatedMovement.add(
|
||||
this.travelVelocity.x * 0.8D * ENTITY_FORCE_SPEED_SCALE,
|
||||
0.0D,
|
||||
this.travelVelocity.z * 0.8D * ENTITY_FORCE_SPEED_SCALE);
|
||||
}
|
||||
if (mode == VortexMode.UPWARD && entity.onGround()) {
|
||||
double minRise = entity instanceof Player ? 0.38D : 0.3D;
|
||||
double minRise = (entity instanceof Player ? 0.38D : 0.3D) * ENTITY_FORCE_SPEED_SCALE;
|
||||
updatedMovement = new Vec3(updatedMovement.x, Math.max(updatedMovement.y, minRise), updatedMovement.z);
|
||||
entity.setOnGround(false);
|
||||
}
|
||||
@@ -543,7 +549,9 @@ public class WindVortexEntity extends Entity {
|
||||
Vec3 radial = radialVector.lengthSqr() < 1.0E-6D ? basis.sideA : radialVector.scale(1.0D / horizontal);
|
||||
Vec3 tangent = basis.axis.cross(radial).normalize();
|
||||
double scale = this.launchStrength * Mth.clamp(this.getVortexHeight() / 5.0D, 0.5D, 2.5D);
|
||||
entity.setDeltaMovement(tangent.scale(0.72D * scale).add(radial.scale(0.34D * scale)).add(basis.axis.scale((0.78D + progress * 0.28D) * scale)));
|
||||
entity.setDeltaMovement(tangent.scale(0.72D * scale * ENTITY_FORCE_SPEED_SCALE)
|
||||
.add(radial.scale(0.34D * scale * ENTITY_FORCE_SPEED_SCALE))
|
||||
.add(basis.axis.scale((0.78D + progress * 0.28D) * scale * ENTITY_FORCE_SPEED_SCALE)));
|
||||
entity.hasImpulse = true;
|
||||
this.syncPlayerMotion(entity);
|
||||
}
|
||||
@@ -575,8 +583,8 @@ public class WindVortexEntity extends Entity {
|
||||
Vec3 toOwner = target.subtract(entity.position());
|
||||
double distance = toOwner.length();
|
||||
Vec3 direction = distance < 1.0E-4D ? new Vec3(0.0D, 1.0D, 0.0D) : toOwner.scale(1.0D / distance);
|
||||
double arc = Mth.clamp(distance * 0.06D, 0.25D, 1.1D);
|
||||
double power = this.launchStrength * Mth.clamp(distance / 6.0D, 0.6D, 2.0D);
|
||||
double arc = Mth.clamp(distance * 0.06D, 0.25D, 1.1D) * ENTITY_FORCE_SPEED_SCALE;
|
||||
double power = this.launchStrength * Mth.clamp(distance / 6.0D, 0.6D, 2.0D) * ENTITY_FORCE_SPEED_SCALE;
|
||||
entity.setDeltaMovement(direction.scale(power).add(0.0D, arc, 0.0D));
|
||||
entity.fallDistance = 0.0F;
|
||||
entity.hasImpulse = true;
|
||||
|
||||
+8
@@ -47,6 +47,7 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
||||
private static final String IDLE_CONTROLLER = "idle_controller";
|
||||
private static final String IDLE_ANIMATION = "spinning_idle";
|
||||
private static final Map<UUID, Long> LAST_UPDRAFT_TICK = new ConcurrentHashMap<>();
|
||||
private static final Map<UUID, Long> LAST_SURGE_TICK = new ConcurrentHashMap<>();
|
||||
private static final float SURGE_PROJECTILE_SPEED = 0.65F;
|
||||
|
||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||
@@ -108,6 +109,13 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
||||
return;
|
||||
}
|
||||
|
||||
long now = level.getGameTime();
|
||||
Long last = LAST_SURGE_TICK.get(player.getUUID());
|
||||
if (last != null && now - last < AntarchySettings.eyeOfTheStormSurgeCooldownTicks()) {
|
||||
return;
|
||||
}
|
||||
LAST_SURGE_TICK.put(player.getUUID(), now);
|
||||
|
||||
Vec3 look = player.getViewVector(1.0F);
|
||||
launchStormVortex(level, player.getEyePosition().add(look), look, player);
|
||||
|
||||
|
||||
+55
@@ -1,6 +1,11 @@
|
||||
package com.craisinlord.antarchy.content.item;
|
||||
|
||||
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
||||
import com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity;
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import java.util.List;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.EquipmentSlotGroup;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||
@@ -9,9 +14,19 @@ import net.minecraft.world.item.AxeItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Tier;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.component.ItemAttributeModifiers;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public class RoyalAssailantBattleAxeItem extends AxeItem {
|
||||
private static final int BLACK_HOLE_COOLDOWN_TICKS = 20 * 20;
|
||||
private static final int DILATED_DURATION_TICKS = 100;
|
||||
private static final ResourceLocation REACH_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "royal_assailant_battleaxe_reach");
|
||||
private static final ResourceLocation KNOCKBACK_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "royal_assailant_battleaxe_knockback");
|
||||
private final Tier tier;
|
||||
@@ -46,4 +61,44 @@ public class RoyalAssailantBattleAxeItem extends AxeItem {
|
||||
public int getEnchantmentValue() {
|
||||
return AntarchySettings.royalWeaponEnchantability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
||||
tooltipComponents.add(Component.translatable("tooltip.antarchy.royal_assailant_battleaxe.black_hole")
|
||||
.withStyle(ChatFormatting.GOLD));
|
||||
tooltipComponents.add(Component.translatable("tooltip.antarchy.royal_assailant_battleaxe.dilation")
|
||||
.withStyle(ChatFormatting.GOLD));
|
||||
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
if (player.getCooldowns().isOnCooldown(this)) {
|
||||
return InteractionResultHolder.fail(stack);
|
||||
}
|
||||
if (level.isClientSide) {
|
||||
return InteractionResultHolder.sidedSuccess(stack, true);
|
||||
}
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
RoyalBlackHoleEntity blackHole = RoyalBlackHoleEntity.createAssailant(
|
||||
serverLevel,
|
||||
player.position().add(player.getLookAngle().normalize().scale(2.0D)).add(0.0D, 2.0D, 0.0D),
|
||||
player.getUUID());
|
||||
serverLevel.addFreshEntity(blackHole);
|
||||
player.getCooldowns().addCooldown(this, BLACK_HOLE_COOLDOWN_TICKS);
|
||||
return InteractionResultHolder.success(stack);
|
||||
}
|
||||
return InteractionResultHolder.pass(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) {
|
||||
boolean hurt = super.hurtEnemy(stack, target, attacker);
|
||||
if (hurt && attacker instanceof Player player && !attacker.level().isClientSide
|
||||
&& RoyalEffectHooks.dilatedHolder() != null) {
|
||||
target.addEffect(new MobEffectInstance(RoyalEffectHooks.dilatedHolder(), DILATED_DURATION_TICKS), player);
|
||||
}
|
||||
return hurt;
|
||||
}
|
||||
}
|
||||
+52
@@ -1,13 +1,32 @@
|
||||
package com.craisinlord.antarchy.content.item;
|
||||
|
||||
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
|
||||
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import java.util.List;
|
||||
import java.util.Comparator;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.ShieldItem;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
||||
public class RoyalGuardianShieldItem extends ShieldItem {
|
||||
private static final int COMMAND_COOLDOWN_TICKS = 20 * 15;
|
||||
private static final int COMMAND_DURATION_TICKS = 20 * 30;
|
||||
private static final double COMMAND_RANGE = 16.0D;
|
||||
private final Supplier<Ingredient> repairIngredient;
|
||||
|
||||
public RoyalGuardianShieldItem(Item.Properties properties, Supplier<Ingredient> repairIngredient) {
|
||||
@@ -24,4 +43,37 @@ public class RoyalGuardianShieldItem extends ShieldItem {
|
||||
public int getEnchantmentValue() {
|
||||
return AntarchySettings.royalWeaponEnchantability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
||||
tooltipComponents.add(Component.translatable("tooltip.antarchy.royal_guardian_shield.command")
|
||||
.withStyle(ChatFormatting.GOLD));
|
||||
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
if (player.getCooldowns().isOnCooldown(this)) {
|
||||
return InteractionResultHolder.fail(stack);
|
||||
}
|
||||
if (level.isClientSide) {
|
||||
return InteractionResultHolder.sidedSuccess(stack, true);
|
||||
}
|
||||
Holder<MobEffect> commanded = RoyalEffectHooks.commandedHolder();
|
||||
if (commanded == null) {
|
||||
return InteractionResultHolder.fail(stack);
|
||||
}
|
||||
Mob target = level.getEntitiesOfClass(Mob.class,
|
||||
new AABB(player.blockPosition()).inflate(COMMAND_RANGE),
|
||||
mob -> RoyalEffectEligibility.canApplyCommanded(mob))
|
||||
.stream()
|
||||
.min(Comparator.comparingDouble((Mob mob) -> player.distanceToSqr(mob)).thenComparingInt(Mob::getId))
|
||||
.orElse(null);
|
||||
if (target == null || !target.addEffect(new MobEffectInstance(commanded, COMMAND_DURATION_TICKS), player)) {
|
||||
return InteractionResultHolder.fail(stack);
|
||||
}
|
||||
player.getCooldowns().addCooldown(this, COMMAND_COOLDOWN_TICKS);
|
||||
return InteractionResultHolder.success(stack);
|
||||
}
|
||||
}
|
||||
+39
-1
@@ -1,6 +1,9 @@
|
||||
package com.craisinlord.antarchy.content.item;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.craisinlord.antarchy.content.client.model.ResourceBackedGeoItemModel;
|
||||
import com.craisinlord.antarchy.content.client.renderer.AnimatedHeldItemRenderer;
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.EquipmentSlotGroup;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||
@@ -10,15 +13,25 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.SwordItem;
|
||||
import net.minecraft.world.item.Tier;
|
||||
import net.minecraft.world.item.component.ItemAttributeModifiers;
|
||||
import software.bernie.geckolib.animatable.GeoItem;
|
||||
import software.bernie.geckolib.animatable.client.GeoRenderProvider;
|
||||
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||
import software.bernie.geckolib.animation.AnimatableManager;
|
||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||
|
||||
public class RoyalGuardianSwordItem extends SwordItem {
|
||||
public class RoyalGuardianSwordItem extends SwordItem implements GeoItem {
|
||||
private static final ResourceLocation MODEL_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "geo/royal_guardian_sword.geo.json");
|
||||
private static final ResourceLocation TEXTURE_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/item/royal_guardian/royal_guardian_sword.png");
|
||||
private static final ResourceLocation ANIMATION_LOCATION = ResourceLocation.fromNamespaceAndPath("antarchy", "animations/static_item.animation.json");
|
||||
private static final ResourceLocation REACH_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "royal_guardian_sword_reach");
|
||||
private static final ResourceLocation KNOCKBACK_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "royal_guardian_sword_knockback");
|
||||
private final Tier tier;
|
||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||
|
||||
public RoyalGuardianSwordItem(Tier tier, Item.Properties properties) {
|
||||
super(tier, properties);
|
||||
this.tier = tier;
|
||||
GeoItem.registerSyncedAnimatable(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,4 +59,29 @@ public class RoyalGuardianSwordItem extends SwordItem {
|
||||
public int getEnchantmentValue() {
|
||||
return AntarchySettings.royalWeaponEnchantability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||
return this.geoCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createGeoRenderer(Consumer<GeoRenderProvider> consumer) {
|
||||
consumer.accept(new GeoRenderProvider() {
|
||||
private AnimatedHeldItemRenderer<RoyalGuardianSwordItem> renderer;
|
||||
|
||||
@Override
|
||||
public net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer getGeoItemRenderer() {
|
||||
if (this.renderer == null) {
|
||||
this.renderer = new AnimatedHeldItemRenderer<>(new ResourceBackedGeoItemModel<>(MODEL_LOCATION, TEXTURE_LOCATION, ANIMATION_LOCATION));
|
||||
}
|
||||
|
||||
return this.renderer;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+36
-4
@@ -16,6 +16,7 @@ public final class TimeDilationApi {
|
||||
private static BiConsumer<ServerPlayer, List<TimeDilationFieldSnapshot>> fieldSyncDispatcher = (player, fields) -> {
|
||||
};
|
||||
private static final Map<UUID, Double> SYNCED_CLIENT_RATES = new ConcurrentHashMap<>();
|
||||
private static final ThreadLocal<Integer> ROTATION_BYPASS_DEPTH = ThreadLocal.withInitial(() -> 0);
|
||||
|
||||
private TimeDilationApi() {
|
||||
}
|
||||
@@ -31,7 +32,15 @@ public final class TimeDilationApi {
|
||||
}
|
||||
|
||||
public static TimeDilationFieldEntity createField(ServerLevel level, Vec3 center, double radius, double rate, int durationTicks) {
|
||||
TimeDilationFieldEntity field = TimeDilationFieldEntity.create(level, center, radius, rate, durationTicks);
|
||||
return createField(level, center, radius, rate, durationTicks, null);
|
||||
}
|
||||
|
||||
public static TimeDilationFieldEntity createField(ServerLevel level, Vec3 center, double radius, double rate, int durationTicks, UUID ownerId) {
|
||||
return createField(level, center, radius, rate, durationTicks, ownerId, true);
|
||||
}
|
||||
|
||||
public static TimeDilationFieldEntity createField(ServerLevel level, Vec3 center, double radius, double rate, int durationTicks, UUID ownerId, boolean visual) {
|
||||
TimeDilationFieldEntity field = TimeDilationFieldEntity.create(level, center, radius, rate, durationTicks, ownerId, visual);
|
||||
level.addFreshEntity(field);
|
||||
return field;
|
||||
}
|
||||
@@ -53,6 +62,29 @@ public final class TimeDilationApi {
|
||||
return getRate(entity) < TimeDilationMath.NORMAL_RATE;
|
||||
}
|
||||
|
||||
public static void enterRotationBypass() {
|
||||
ROTATION_BYPASS_DEPTH.set(ROTATION_BYPASS_DEPTH.get() + 1);
|
||||
}
|
||||
|
||||
public static void exitRotationBypass() {
|
||||
int depth = ROTATION_BYPASS_DEPTH.get() - 1;
|
||||
if (depth <= 0) {
|
||||
ROTATION_BYPASS_DEPTH.remove();
|
||||
} else {
|
||||
ROTATION_BYPASS_DEPTH.set(depth);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isRotationBypassed() {
|
||||
return ROTATION_BYPASS_DEPTH.get() > 0;
|
||||
}
|
||||
|
||||
public static void setInheritedRate(Entity entity, double rate) {
|
||||
if (entity instanceof TimeDilationEntityAccess access) {
|
||||
access.antarchy$setInheritedTimeDilationRate(rate);
|
||||
}
|
||||
}
|
||||
|
||||
public static void applySyncedRate(Entity entity, double rate) {
|
||||
applySyncedRate(entity.getUUID(), rate);
|
||||
if (entity instanceof TimeDilationEntityAccess access) {
|
||||
@@ -68,7 +100,7 @@ public final class TimeDilationApi {
|
||||
/** Clears both the authoritative entity state and any client-side UUID cache. */
|
||||
public static void clearRate(Entity entity) {
|
||||
if (entity instanceof TimeDilationEntityAccess access) {
|
||||
boolean wasDilated = access.antarchy$getTimeDilationRate() < TimeDilationMath.NORMAL_RATE;
|
||||
boolean wasDilated = Math.abs(access.antarchy$getTimeDilationRate() - TimeDilationMath.NORMAL_RATE) > 0.001D;
|
||||
access.antarchy$setTimeDilationRate(TimeDilationMath.NORMAL_RATE);
|
||||
if (wasDilated) {
|
||||
syncEntityRate(entity, TimeDilationMath.NORMAL_RATE);
|
||||
@@ -91,7 +123,7 @@ public final class TimeDilationApi {
|
||||
|
||||
public static boolean consumeTick(Entity entity, String timerKey) {
|
||||
double rate = getRate(entity);
|
||||
if (rate >= TimeDilationMath.NORMAL_RATE || !(entity instanceof TimeDilationEntityAccess access)) {
|
||||
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D || !(entity instanceof TimeDilationEntityAccess access)) {
|
||||
return true;
|
||||
}
|
||||
return access.antarchy$consumeTimeDilationTick(timerKey, rate);
|
||||
@@ -99,7 +131,7 @@ public final class TimeDilationApi {
|
||||
|
||||
public static int scaleCooldownTicks(Entity entity, int ticks) {
|
||||
double rate = getRate(entity);
|
||||
if (ticks <= 0 || rate >= TimeDilationMath.NORMAL_RATE) {
|
||||
if (ticks <= 0 || Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||
return ticks;
|
||||
}
|
||||
return (int) Math.ceil(ticks / Math.max(TimeDilationMath.MIN_RATE, rate));
|
||||
|
||||
+4
@@ -5,6 +5,10 @@ public interface TimeDilationEntityAccess {
|
||||
|
||||
void antarchy$setTimeDilationRate(double rate);
|
||||
|
||||
double antarchy$getInheritedTimeDilationRate();
|
||||
|
||||
void antarchy$setInheritedTimeDilationRate(double rate);
|
||||
|
||||
boolean antarchy$consumeTimeDilationTick(String timerKey, double rate);
|
||||
|
||||
boolean antarchy$isInTimeDilationMove();
|
||||
|
||||
+27
@@ -9,6 +9,7 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import java.util.UUID;
|
||||
|
||||
public class TimeDilationFieldEntity extends Entity {
|
||||
private static final EntityDataAccessor<Float> RADIUS =
|
||||
@@ -23,6 +24,8 @@ public class TimeDilationFieldEntity extends Entity {
|
||||
|
||||
private int durationTicks = -1;
|
||||
private int age;
|
||||
private UUID ownerId;
|
||||
private boolean visual = true;
|
||||
|
||||
public TimeDilationFieldEntity(EntityType<? extends TimeDilationFieldEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -31,14 +34,32 @@ public class TimeDilationFieldEntity extends Entity {
|
||||
}
|
||||
|
||||
public static TimeDilationFieldEntity create(Level level, Vec3 center, double radius, double rate, int durationTicks) {
|
||||
return create(level, center, radius, rate, durationTicks, null);
|
||||
}
|
||||
|
||||
public static TimeDilationFieldEntity create(Level level, Vec3 center, double radius, double rate, int durationTicks, UUID ownerId) {
|
||||
return create(level, center, radius, rate, durationTicks, ownerId, true);
|
||||
}
|
||||
|
||||
public static TimeDilationFieldEntity create(Level level, Vec3 center, double radius, double rate, int durationTicks, UUID ownerId, boolean visual) {
|
||||
TimeDilationFieldEntity field = new TimeDilationFieldEntity(AntarchyObjects.TIME_DILATION_FIELD.get(), level);
|
||||
field.setPos(center.x, center.y, center.z);
|
||||
field.setFieldRadius(radius);
|
||||
field.setFieldRate(rate);
|
||||
field.durationTicks = durationTicks;
|
||||
field.ownerId = ownerId;
|
||||
field.visual = visual;
|
||||
return field;
|
||||
}
|
||||
|
||||
public boolean isOwnedBy(Entity entity) {
|
||||
return this.ownerId != null && entity != null && this.ownerId.equals(entity.getUUID());
|
||||
}
|
||||
|
||||
public boolean isVisual() {
|
||||
return this.visual;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||
builder.define(RADIUS, 8.0F);
|
||||
@@ -105,6 +126,8 @@ public class TimeDilationFieldEntity extends Entity {
|
||||
this.setFieldRate(tag.getDouble(RATE_KEY));
|
||||
this.durationTicks = tag.contains(DURATION_KEY) ? tag.getInt(DURATION_KEY) : -1;
|
||||
this.age = tag.getInt(AGE_KEY);
|
||||
this.ownerId = tag.hasUUID("OwnerUuid") ? tag.getUUID("OwnerUuid") : null;
|
||||
this.visual = !tag.contains("Visual") || tag.getBoolean("Visual");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,5 +136,9 @@ public class TimeDilationFieldEntity extends Entity {
|
||||
tag.putDouble(RATE_KEY, this.fieldRate());
|
||||
tag.putInt(DURATION_KEY, this.durationTicks);
|
||||
tag.putInt(AGE_KEY, this.age);
|
||||
if (this.ownerId != null) {
|
||||
tag.putUUID("OwnerUuid", this.ownerId);
|
||||
}
|
||||
tag.putBoolean("Visual", this.visual);
|
||||
}
|
||||
}
|
||||
+20
@@ -1,6 +1,7 @@
|
||||
package com.craisinlord.antarchy.content.time;
|
||||
|
||||
import java.util.List;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public final class TimeDilationFieldSampler {
|
||||
@@ -27,4 +28,23 @@ public final class TimeDilationFieldSampler {
|
||||
}
|
||||
return TimeDilationMath.clampRate(combinedRate);
|
||||
}
|
||||
|
||||
public static double sample(List<TimeDilationFieldEntity> fields, Entity entity) {
|
||||
double combinedRate = TimeDilationMath.NORMAL_RATE;
|
||||
for (TimeDilationFieldEntity field : fields) {
|
||||
if (field.isOwnedBy(entity)) {
|
||||
continue;
|
||||
}
|
||||
Vec3 center = field.position();
|
||||
double dx = center.x - entity.getX();
|
||||
double dy = center.y - entity.getY();
|
||||
double dz = center.z - entity.getZ();
|
||||
double distanceSqr = dx * dx + dy * dy + dz * dz;
|
||||
if (distanceSqr < field.fieldRadiusSqr()) {
|
||||
double falloff = TimeDilationMath.gaussianFalloff(Math.sqrt(distanceSqr), field.fieldRadius());
|
||||
combinedRate *= TimeDilationMath.localFieldRate(field.effectiveFieldRate(), falloff);
|
||||
}
|
||||
}
|
||||
return TimeDilationMath.clampRate(combinedRate);
|
||||
}
|
||||
}
|
||||
+50
-9
@@ -6,7 +6,11 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.projectile.Projectile;
|
||||
import com.craisinlord.antarchy.content.effect.DilatedMobEffect;
|
||||
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
|
||||
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
|
||||
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
|
||||
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
|
||||
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
||||
|
||||
@@ -20,7 +24,7 @@ public final class TimeDilationManager {
|
||||
syncFieldSnapshots(level, fields);
|
||||
updateEntities(level, fields);
|
||||
if (!fields.isEmpty()) {
|
||||
TimeDilationParticles.spawnFieldBorders(level, fields);
|
||||
TimeDilationParticles.spawnFieldBorders(level, fields.stream().filter(TimeDilationFieldEntity::isVisual).toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,18 +65,55 @@ public final class TimeDilationManager {
|
||||
continue;
|
||||
}
|
||||
double previousRate = access.antarchy$getTimeDilationRate();
|
||||
double fieldRate = TimeDilationFieldSampler.sample(fields, entity.position());
|
||||
double effectRate = RoyalEffectHooks.dilatedHolder() != null
|
||||
&& entity instanceof net.minecraft.world.entity.LivingEntity living
|
||||
&& living.hasEffect(RoyalEffectHooks.dilatedHolder())
|
||||
? DilatedMobEffect.RATE : TimeDilationMath.NORMAL_RATE;
|
||||
double rate = Math.min(fieldRate, effectRate);
|
||||
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||
double fieldRate = TimeDilationFieldSampler.sample(fields, entity);
|
||||
double effectRate = TimeDilationMath.NORMAL_RATE;
|
||||
if (RoyalEffectHooks.dilatedHolder() != null
|
||||
&& entity instanceof net.minecraft.world.entity.LivingEntity living) {
|
||||
var effect = living.getEffect(RoyalEffectHooks.dilatedHolder());
|
||||
if (effect != null) {
|
||||
effectRate = DilatedMobEffect.rateForAmplifier(effect.getAmplifier());
|
||||
}
|
||||
}
|
||||
if (RoyalEffectHooks.contractedHolder() != null
|
||||
&& entity instanceof net.minecraft.world.entity.LivingEntity living) {
|
||||
var effect = living.getEffect(RoyalEffectHooks.contractedHolder());
|
||||
if (effect != null) {
|
||||
effectRate = Math.max(effectRate, ContractedMobEffect.rateForAmplifier(effect.getAmplifier()));
|
||||
}
|
||||
}
|
||||
double inheritedRate = access.antarchy$getInheritedTimeDilationRate();
|
||||
if (entity instanceof Projectile projectile && projectile.getOwner() != null) {
|
||||
double ownerRate = TimeDilationApi.getRate(projectile.getOwner());
|
||||
inheritedRate = ownerRate < TimeDilationMath.NORMAL_RATE
|
||||
? Math.min(inheritedRate, ownerRate)
|
||||
: Math.max(inheritedRate, ownerRate);
|
||||
}
|
||||
double slowRate = TimeDilationMath.NORMAL_RATE;
|
||||
double fastRate = TimeDilationMath.NORMAL_RATE;
|
||||
if (fieldRate < TimeDilationMath.NORMAL_RATE) {
|
||||
slowRate = Math.min(slowRate, fieldRate);
|
||||
} else {
|
||||
fastRate = Math.max(fastRate, fieldRate);
|
||||
}
|
||||
if (effectRate < TimeDilationMath.NORMAL_RATE) {
|
||||
slowRate = Math.min(slowRate, effectRate);
|
||||
} else {
|
||||
fastRate = Math.max(fastRate, effectRate);
|
||||
}
|
||||
if (inheritedRate < TimeDilationMath.NORMAL_RATE) {
|
||||
slowRate = Math.min(slowRate, inheritedRate);
|
||||
} else {
|
||||
fastRate = Math.max(fastRate, inheritedRate);
|
||||
}
|
||||
double targetRate = slowRate < TimeDilationMath.NORMAL_RATE ? slowRate : fastRate;
|
||||
double rate = TimeDilationMath.transitionRate(previousRate, targetRate);
|
||||
if (Math.abs(targetRate - TimeDilationMath.NORMAL_RATE) < 0.001D
|
||||
&& Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||
TimeDilationApi.clearRate(entity);
|
||||
} else {
|
||||
access.antarchy$setTimeDilationRate(rate);
|
||||
}
|
||||
if (rate < TimeDilationMath.NORMAL_RATE && Math.abs(previousRate - rate) > 0.001D) {
|
||||
if (Math.abs(previousRate - rate) > 0.001D) {
|
||||
TimeDilationApi.syncEntityRate(entity, rate);
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -3,7 +3,9 @@ package com.craisinlord.antarchy.content.time;
|
||||
public final class TimeDilationMath {
|
||||
public static final double MIN_RATE = 0.05D;
|
||||
public static final double NORMAL_RATE = 1.0D;
|
||||
public static final double MAX_RATE = 3.0D;
|
||||
public static final int FIELD_TRANSITION_TICKS = 20;
|
||||
public static final int EFFECT_TRANSITION_TICKS = 20;
|
||||
private static final double GAUSSIAN_EDGE_EXPONENT = -4.5D;
|
||||
|
||||
private TimeDilationMath() {
|
||||
@@ -13,7 +15,16 @@ public final class TimeDilationMath {
|
||||
if (Double.isNaN(rate) || Double.isInfinite(rate)) {
|
||||
return NORMAL_RATE;
|
||||
}
|
||||
return Math.max(MIN_RATE, Math.min(NORMAL_RATE, rate));
|
||||
return Math.max(MIN_RATE, Math.min(MAX_RATE, rate));
|
||||
}
|
||||
|
||||
/** Moves an entity's effective rate toward a new effect/field target without a hard step. */
|
||||
public static double transitionRate(double currentRate, double targetRate) {
|
||||
double current = clampRate(currentRate);
|
||||
double target = clampRate(targetRate);
|
||||
double maximumStep = (MAX_RATE - MIN_RATE) / EFFECT_TRANSITION_TICKS;
|
||||
double delta = Math.max(-maximumStep, Math.min(maximumStep, target - current));
|
||||
return clampRate(current + delta);
|
||||
}
|
||||
|
||||
public static double gaussianFalloff(double distance, double radius) {
|
||||
|
||||
+10
-13
@@ -2,6 +2,7 @@ package com.craisinlord.antarchy.mixins;
|
||||
|
||||
import com.craisinlord.antarchy.content.effect.CommandedEntityAccess;
|
||||
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
|
||||
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@@ -37,19 +38,19 @@ public abstract class LivingEntityRoyalEffectsMixin {
|
||||
cir.setReturnValue(false);
|
||||
return;
|
||||
}
|
||||
PlayerSource playerSource = antarchy$resolvePlayer(source);
|
||||
if (playerSource == null) {
|
||||
Entity commander = antarchy$resolveCommander(source);
|
||||
if (commander == null) {
|
||||
cir.setReturnValue(false);
|
||||
return;
|
||||
}
|
||||
CommandedEntityAccess access = (CommandedEntityAccess) mob;
|
||||
UUID current = access.antarchy$getCommanderUuid();
|
||||
if (current != null && !current.equals(playerSource.player().getUUID())) {
|
||||
if (current != null && !current.equals(commander.getUUID())) {
|
||||
cir.setReturnValue(false);
|
||||
return;
|
||||
}
|
||||
antarchy$previousCommander = current;
|
||||
access.antarchy$setCommanderUuid(playerSource.player().getUUID());
|
||||
access.antarchy$setCommanderUuid(commander.getUUID());
|
||||
}
|
||||
|
||||
@Inject(method = "addEffect(Lnet/minecraft/world/effect/MobEffectInstance;Lnet/minecraft/world/entity/Entity;)Z", at = @At("RETURN"))
|
||||
@@ -71,20 +72,16 @@ public abstract class LivingEntityRoyalEffectsMixin {
|
||||
}
|
||||
|
||||
@Unique
|
||||
private PlayerSource antarchy$resolvePlayer(Entity source) {
|
||||
private Entity antarchy$resolveCommander(Entity source) {
|
||||
if (source instanceof net.minecraft.world.entity.player.Player player) {
|
||||
return new PlayerSource(player);
|
||||
return player;
|
||||
}
|
||||
if (source instanceof Projectile projectile && projectile.getOwner() instanceof net.minecraft.world.entity.player.Player player) {
|
||||
return new PlayerSource(player);
|
||||
return player;
|
||||
}
|
||||
if (source instanceof AreaEffectCloud cloud && cloud.getOwner() instanceof net.minecraft.world.entity.player.Player player) {
|
||||
return new PlayerSource(player);
|
||||
return player;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private record PlayerSource(net.minecraft.world.entity.player.Player player) {
|
||||
return source instanceof RoyalBossEntity ? source : null;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -13,13 +13,13 @@ public abstract class AbstractArrowMovementTimeDilationMixin {
|
||||
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/Vec3;add(Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3;"))
|
||||
private Vec3 antarchy$slowCollisionPath(Vec3 position, Vec3 movement) {
|
||||
double rate = TimeDilationApi.getRate((AbstractArrow) (Object) this);
|
||||
return position.add(rate >= TimeDilationMath.NORMAL_RATE ? movement : movement.scale(rate));
|
||||
return position.add(Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D ? movement : movement.scale(rate));
|
||||
}
|
||||
|
||||
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;setPos(DDD)V"))
|
||||
private void antarchy$slowPosition(AbstractArrow arrow, double x, double y, double z) {
|
||||
double rate = Math.max(TimeDilationMath.MIN_RATE, TimeDilationApi.getRate(arrow));
|
||||
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||
arrow.setPos(x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ public abstract class EntityDeltaMovementTimeDilationMixin {
|
||||
}
|
||||
|
||||
double rate = TimeDilationApi.getRate(entity);
|
||||
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||
return nextMovement;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ public abstract class EntityMoveTimeDilationMixin {
|
||||
private Vec3 antarchy$scaleTimeDilatedMovement(Vec3 movement) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
double rate = TimeDilationApi.getRate(entity);
|
||||
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||
return movement;
|
||||
}
|
||||
return movement.scale(rate);
|
||||
|
||||
+6
@@ -13,6 +13,9 @@ public abstract class EntityRotationTimeDilationMixin {
|
||||
@ModifyVariable(method = "setYRot", at = @At("HEAD"), argsOnly = true)
|
||||
private float antarchy$slowYaw(float nextYaw) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
if (TimeDilationApi.isRotationBypassed()) {
|
||||
return nextYaw;
|
||||
}
|
||||
double rate = TimeDilationApi.getRate(entity);
|
||||
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||
return nextYaw;
|
||||
@@ -23,6 +26,9 @@ public abstract class EntityRotationTimeDilationMixin {
|
||||
@ModifyVariable(method = "setXRot", at = @At("HEAD"), argsOnly = true)
|
||||
private float antarchy$slowPitch(float nextPitch) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
if (TimeDilationApi.isRotationBypassed()) {
|
||||
return nextPitch;
|
||||
}
|
||||
double rate = TimeDilationApi.getRate(entity);
|
||||
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||
return nextPitch;
|
||||
|
||||
+13
-1
@@ -13,6 +13,8 @@ public abstract class EntityTimeDilationStateMixin implements TimeDilationEntity
|
||||
@Unique
|
||||
private double antarchy$timeDilationRate = TimeDilationMath.NORMAL_RATE;
|
||||
@Unique
|
||||
private double antarchy$inheritedTimeDilationRate = TimeDilationMath.NORMAL_RATE;
|
||||
@Unique
|
||||
private final Map<String, Double> antarchy$timeDilationTimerProgress = new HashMap<>();
|
||||
@Unique
|
||||
private boolean antarchy$inTimeDilationMove;
|
||||
@@ -32,10 +34,20 @@ public abstract class EntityTimeDilationStateMixin implements TimeDilationEntity
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double antarchy$getInheritedTimeDilationRate() {
|
||||
return this.antarchy$inheritedTimeDilationRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void antarchy$setInheritedTimeDilationRate(double rate) {
|
||||
this.antarchy$inheritedTimeDilationRate = TimeDilationMath.clampRate(rate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean antarchy$consumeTimeDilationTick(String timerKey, double rate) {
|
||||
double clampedRate = TimeDilationMath.clampRate(rate);
|
||||
if (clampedRate >= TimeDilationMath.NORMAL_RATE) {
|
||||
if (Math.abs(clampedRate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ public abstract class HurtingProjectileMovementTimeDilationMixin {
|
||||
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractHurtingProjectile;setPos(DDD)V"))
|
||||
private void antarchy$slowPosition(AbstractHurtingProjectile projectile, double x, double y, double z) {
|
||||
double rate = Math.max(TimeDilationMath.MIN_RATE, TimeDilationApi.getRate(projectile));
|
||||
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||
projectile.setPos(x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
-24
@@ -4,7 +4,6 @@ import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@@ -20,22 +19,6 @@ public abstract class LivingEntityTimeDilationMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tickEffects", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$slowEffectTicks(CallbackInfo ci) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
if (!TimeDilationApi.consumeTick(entity, "living_effects")) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "updatingUsingItem", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$slowUsingItem(CallbackInfo ci) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
if (!TimeDilationApi.consumeTick(entity, "living_using_item")) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "swing(Lnet/minecraft/world/InteractionHand;Z)V", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$slowSwingStart(InteractionHand hand, boolean updateSelf, CallbackInfo ci) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
@@ -44,11 +27,4 @@ public abstract class LivingEntityTimeDilationMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "updateUsingItem", at = @At("HEAD"), cancellable = true)
|
||||
private void antarchy$slowItemUseProgress(ItemStack stack, CallbackInfo ci) {
|
||||
Entity entity = (Entity) (Object) this;
|
||||
if (!TimeDilationApi.consumeTick(entity, "living_item_use_progress")) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
-1
@@ -1,10 +1,18 @@
|
||||
package com.craisinlord.antarchy.mixins.time;
|
||||
|
||||
import com.craisinlord.antarchy.content.client.ClientTimeDilationTicker;
|
||||
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||
import com.craisinlord.antarchy.content.time.TimeDilationMath;
|
||||
import com.craisinlord.antarchy.content.effect.ContractedMobEffect;
|
||||
import com.craisinlord.antarchy.content.effect.DilatedMobEffect;
|
||||
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
||||
import com.craisinlord.antarchy.mixins.client.EntityBoundSoundInstanceAccessor;
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@@ -13,9 +21,40 @@ public abstract class SoundEngineTimeDilationMixin {
|
||||
@ModifyReturnValue(method = "calculatePitch", at = @At("RETURN"))
|
||||
private float antarchy$dilatePitch(float pitch, SoundInstance sound) {
|
||||
double rate = ClientTimeDilationTicker.rateAt(sound.getX(), sound.getY(), sound.getZ());
|
||||
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||
if (sound instanceof EntityBoundSoundInstanceAccessor accessor) {
|
||||
double entityRate = rateForEntity(accessor.antarchy$getEntity());
|
||||
rate = combineRates(rate, entityRate);
|
||||
}
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
if (minecraft.player != null) {
|
||||
double listenerRate = rateForEntity(minecraft.player);
|
||||
rate = combineRates(rate, listenerRate);
|
||||
}
|
||||
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||
return pitch;
|
||||
}
|
||||
return (float) (pitch * Math.max(TimeDilationMath.MIN_RATE, rate));
|
||||
}
|
||||
|
||||
private static double combineRates(double first, double second) {
|
||||
if (first < TimeDilationMath.NORMAL_RATE || second < TimeDilationMath.NORMAL_RATE) {
|
||||
return Math.min(first, second);
|
||||
}
|
||||
return Math.max(first, second);
|
||||
}
|
||||
|
||||
private static double rateForEntity(Entity entity) {
|
||||
double rate = TimeDilationApi.getRate(entity);
|
||||
if (entity instanceof LivingEntity living) {
|
||||
if (RoyalEffectHooks.dilatedHolder() != null && living.hasEffect(RoyalEffectHooks.dilatedHolder())) {
|
||||
rate = Math.min(rate, DilatedMobEffect.rateForAmplifier(
|
||||
living.getEffect(RoyalEffectHooks.dilatedHolder()).getAmplifier()));
|
||||
}
|
||||
if (RoyalEffectHooks.contractedHolder() != null && living.hasEffect(RoyalEffectHooks.contractedHolder())) {
|
||||
rate = combineRates(rate, ContractedMobEffect.rateForAmplifier(
|
||||
living.getEffect(RoyalEffectHooks.contractedHolder()).getAmplifier()));
|
||||
}
|
||||
}
|
||||
return rate;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@ public abstract class ThrowableProjectileMovementTimeDilationMixin {
|
||||
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ThrowableProjectile;setPos(DDD)V"))
|
||||
private void antarchy$slowPosition(ThrowableProjectile projectile, double x, double y, double z) {
|
||||
double rate = Math.max(TimeDilationMath.MIN_RATE, TimeDilationApi.getRate(projectile));
|
||||
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||
projectile.setPos(x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
"time.EntityMoveTimeDilationMixin",
|
||||
"time.EntityTimeDilationStateMixin",
|
||||
"time.EntityRotationTimeDilationMixin",
|
||||
"time.EntityCrouchTimeDilationMixin",
|
||||
"time.LivingEntityKnockbackTimeDilationMixin",
|
||||
"time.CreeperTimeDilationMixin",
|
||||
"time.EndCrystalTimeDilationMixin",
|
||||
@@ -101,9 +102,11 @@
|
||||
"time.AbstractArrowMovementTimeDilationMixin",
|
||||
"time.ThrowableProjectileMovementTimeDilationMixin",
|
||||
"time.HurtingProjectileMovementTimeDilationMixin",
|
||||
"time.ProjectileTimeDilationMixin",
|
||||
"time.AbstractArrowActionTimeDilationMixin",
|
||||
"time.RangedAttackGoalTimeDilationMixin",
|
||||
"time.RangedBowAttackGoalTimeDilationMixin"
|
||||
"time.RangedBowAttackGoalTimeDilationMixin",
|
||||
"time.GeckoLibAnimationControllerTimeDilationMixin"
|
||||
],
|
||||
"client": [
|
||||
"client.AbstractMinecartRendererMixin",
|
||||
@@ -117,6 +120,8 @@
|
||||
"client.ElytraModelAccessor",
|
||||
"client.FrogRendererElythiaMixin",
|
||||
"client.GameRendererSwingThroughGrassMixin",
|
||||
"client.EntityBoundSoundInstanceAccessor",
|
||||
"client.InventoryScreenRotationBypassMixin",
|
||||
"client.ExperimentalSettingsPopupMixin",
|
||||
"client.KrakensGraspChargePoseMixin",
|
||||
"client.LightningBoltRendererMixin",
|
||||
|
||||
@@ -2,40 +2,35 @@
|
||||
"variants": {
|
||||
"thickness=base,vertical_direction=down": {
|
||||
"model": "antarchy:block/typhonite_spike_down_base",
|
||||
"x": 180,
|
||||
"uvlock": true
|
||||
"x": 180
|
||||
},
|
||||
"thickness=base,vertical_direction=up": {
|
||||
"model": "antarchy:block/typhonite_spike_up_base"
|
||||
},
|
||||
"thickness=frustum,vertical_direction=down": {
|
||||
"model": "antarchy:block/typhonite_spike_down_frustum",
|
||||
"x": 180,
|
||||
"uvlock": true
|
||||
"x": 180
|
||||
},
|
||||
"thickness=frustum,vertical_direction=up": {
|
||||
"model": "antarchy:block/typhonite_spike_up_frustum"
|
||||
},
|
||||
"thickness=middle,vertical_direction=down": {
|
||||
"model": "antarchy:block/typhonite_spike_down_middle",
|
||||
"x": 180,
|
||||
"uvlock": true
|
||||
"x": 180
|
||||
},
|
||||
"thickness=middle,vertical_direction=up": {
|
||||
"model": "antarchy:block/typhonite_spike_up_middle"
|
||||
},
|
||||
"thickness=tip,vertical_direction=down": {
|
||||
"model": "antarchy:block/typhonite_spike_down_tip",
|
||||
"x": 180,
|
||||
"uvlock": true
|
||||
"x": 180
|
||||
},
|
||||
"thickness=tip,vertical_direction=up": {
|
||||
"model": "antarchy:block/typhonite_spike_up_tip"
|
||||
},
|
||||
"thickness=tip_merge,vertical_direction=down": {
|
||||
"model": "antarchy:block/typhonite_spike_down_tip_merge",
|
||||
"x": 180,
|
||||
"uvlock": true
|
||||
"x": 180
|
||||
},
|
||||
"thickness=tip_merge,vertical_direction=up": {
|
||||
"model": "antarchy:block/typhonite_spike_up_tip_merge"
|
||||
|
||||
@@ -494,8 +494,23 @@
|
||||
{"origin": [19, 0, 13], "size": [5, 6, 7], "uv": [466, 173], "mirror": true},
|
||||
{"origin": [24, 0, 9], "size": [6, 10, 13], "inflate": 0.01, "uv": [38, 249], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "beam_anchor_center",
|
||||
"parent": "head",
|
||||
"pivot": [0, 91.5, -219]
|
||||
},
|
||||
{
|
||||
"name": "beam_anchor_left",
|
||||
"parent": "L_head",
|
||||
"pivot": [21, 82.5, -219]
|
||||
},
|
||||
{
|
||||
"name": "beam_anchor_right",
|
||||
"parent": "R_head",
|
||||
"pivot": [-21, 82.5, -219]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -473,8 +473,23 @@
|
||||
{"origin": [19, 0, 13], "size": [5, 6, 7], "uv": [466, 173], "mirror": true},
|
||||
{"origin": [24, 0, 9], "size": [6, 10, 13], "inflate": 0.01, "uv": [38, 249], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "beam_anchor_center",
|
||||
"parent": "head",
|
||||
"pivot": [0, 91.5, -219]
|
||||
},
|
||||
{
|
||||
"name": "beam_anchor_left",
|
||||
"parent": "L_head",
|
||||
"pivot": [21, 82.5, -219]
|
||||
},
|
||||
{
|
||||
"name": "beam_anchor_right",
|
||||
"parent": "R_head",
|
||||
"pivot": [-21, 82.5, -219]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -533,6 +533,8 @@
|
||||
"effect.antarchy.paralyzed.description": "Verhindert, dass sich Ziele bewegen.",
|
||||
"effect.antarchy.inverted": "Umgekehrt",
|
||||
"effect.antarchy.inverted.description": "Kehrt die Schwerkraft des Ziels um.",
|
||||
"effect.antarchy.commanded.description": "Kämpft für den Spieler, der das Ziel kommandiert hat.",
|
||||
"effect.antarchy.dilated.description": "Verlangsamt den Zeitablauf für das betroffene Wesen.",
|
||||
"effect.antarchy.stinky": "Stinkend",
|
||||
"effect.antarchy.stinky.description": "Vertreibt passive und neutrale Kreaturen und zieht Gliederfüßer an.",
|
||||
"effect.antarchy.gooped.description": "Verlangsamt Bewegung und Angriffsgeschwindigkeit.",
|
||||
|
||||
@@ -543,6 +543,9 @@
|
||||
"item.antarchy.royal_assailant_battleaxe": "Royal Assailant Battle Axe",
|
||||
"item.antarchy.royal_assailant_staff": "Royal Assailant Staff",
|
||||
"tooltip.antarchy.royal_assailant_staff": "Opens paired tears that summon four allied Manticores for 30 seconds.",
|
||||
"tooltip.antarchy.royal_assailant_battleaxe.black_hole": "Use to create a Royal Black Hole",
|
||||
"tooltip.antarchy.royal_assailant_battleaxe.dilation": "Hits apply Temporal Dilation",
|
||||
"tooltip.antarchy.royal_guardian_shield.command": "Use to command the nearest mob",
|
||||
"tooltip.antarchy.royal_assailant_chestplate.invert": "Press the inversion key to toggle inverted gravity on and off.",
|
||||
"tooltip.antarchy.royal_assailant_boots.fall": "Cancels fall damage while falling upward.",
|
||||
"item.antarchy.mantis_claw": "Mantis Claw",
|
||||
@@ -753,8 +756,10 @@
|
||||
"effect.antarchy.inverted.description": "Inverts the target's gravity.",
|
||||
"effect.antarchy.commanded": "Commanded",
|
||||
"effect.antarchy.commanded.description": "Fights for the player who commanded it.",
|
||||
"effect.antarchy.dilated": "Dilated",
|
||||
"effect.antarchy.dilated": "Temporal Dilation",
|
||||
"effect.antarchy.dilated.description": "Slows the passage of time for the affected entity.",
|
||||
"effect.antarchy.contracted": "Temporal Contraction",
|
||||
"effect.antarchy.contracted.description": "Speeds the passage of time for the affected entity.",
|
||||
"effect.antarchy.stinky": "Stinky",
|
||||
"effect.antarchy.stinky.description": "Repels passive and neutral mobs, attracts arthropods.",
|
||||
"effect.antarchy.gooped": "Gooped",
|
||||
@@ -1084,14 +1089,22 @@
|
||||
"item.minecraft.lingering_potion.effect.long_command": "Lingering Potion of Command",
|
||||
"item.minecraft.tipped_arrow.effect.command": "Arrow of Command",
|
||||
"item.minecraft.tipped_arrow.effect.long_command": "Arrow of Command",
|
||||
"item.minecraft.potion.effect.time_dilation": "Potion of Time Dilation",
|
||||
"item.minecraft.potion.effect.long_time_dilation": "Potion of Time Dilation",
|
||||
"item.minecraft.splash_potion.effect.time_dilation": "Splash Potion of Time Dilation",
|
||||
"item.minecraft.splash_potion.effect.long_time_dilation": "Splash Potion of Time Dilation",
|
||||
"item.minecraft.lingering_potion.effect.time_dilation": "Lingering Potion of Time Dilation",
|
||||
"item.minecraft.lingering_potion.effect.long_time_dilation": "Lingering Potion of Time Dilation",
|
||||
"item.minecraft.tipped_arrow.effect.time_dilation": "Arrow of Time Dilation",
|
||||
"item.minecraft.tipped_arrow.effect.long_time_dilation": "Arrow of Time Dilation",
|
||||
"item.minecraft.potion.effect.time_dilation": "Potion of Temporal Dilation",
|
||||
"item.minecraft.potion.effect.long_time_dilation": "Potion of Strong Temporal Dilation",
|
||||
"item.minecraft.splash_potion.effect.time_dilation": "Splash Potion of Temporal Dilation",
|
||||
"item.minecraft.splash_potion.effect.long_time_dilation": "Splash Potion of Strong Temporal Dilation",
|
||||
"item.minecraft.lingering_potion.effect.time_dilation": "Lingering Potion of Temporal Dilation",
|
||||
"item.minecraft.lingering_potion.effect.long_time_dilation": "Lingering Potion of Strong Temporal Dilation",
|
||||
"item.minecraft.tipped_arrow.effect.time_dilation": "Arrow of Temporal Dilation",
|
||||
"item.minecraft.tipped_arrow.effect.long_time_dilation": "Arrow of Strong Temporal Dilation",
|
||||
"item.minecraft.potion.effect.time_contraction": "Potion of Temporal Contraction",
|
||||
"item.minecraft.splash_potion.effect.time_contraction": "Splash Potion of Temporal Contraction",
|
||||
"item.minecraft.lingering_potion.effect.time_contraction": "Lingering Potion of Temporal Contraction",
|
||||
"item.minecraft.tipped_arrow.effect.time_contraction": "Arrow of Temporal Contraction",
|
||||
"item.minecraft.potion.effect.long_time_contraction": "Potion of Strong Temporal Contraction",
|
||||
"item.minecraft.splash_potion.effect.long_time_contraction": "Splash Potion of Strong Temporal Contraction",
|
||||
"item.minecraft.lingering_potion.effect.long_time_contraction": "Lingering Potion of Strong Temporal Contraction",
|
||||
"item.minecraft.tipped_arrow.effect.long_time_contraction": "Arrow of Strong Temporal Contraction",
|
||||
"item.minecraft.potion.effect.paralysis": "Potion of Paralysis",
|
||||
"item.minecraft.potion.effect.long_paralysis": "Potion of Paralysis",
|
||||
"item.minecraft.splash_potion.effect.paralysis": "Splash Potion of Paralysis",
|
||||
@@ -1150,6 +1163,12 @@
|
||||
"item.minecraft.tipped_arrow.effect.strong_haste": "Arrow of Haste II",
|
||||
"advancements.antarchy.cancel_out.title": "1 - 1 = ?",
|
||||
"advancements.antarchy.cancel_out.description": "Have Growth and Shrinking active at the same time.",
|
||||
"advancements.antarchy.enter_the_speed_force.title": "Enter the speed force",
|
||||
"advancements.antarchy.enter_the_speed_force.description": "Gain Temporal Contraction.",
|
||||
"advancements.antarchy.probably_wondering_how_i_got_here.title": "You're probably wondering how I got here",
|
||||
"advancements.antarchy.probably_wondering_how_i_got_here.description": "Gain Temporal Dilation.",
|
||||
"advancements.antarchy.temporal_contradiction.title": "Temporal Contradiction",
|
||||
"advancements.antarchy.temporal_contradiction.description": "Have Temporal Dilation and Temporal Contraction active at the same time.",
|
||||
"entity.antarchy.cheep": "Cheep",
|
||||
"item.antarchy.cheep": "Cheep",
|
||||
"item.antarchy.cheep_spawn_egg": "Cheep Spawn Egg",
|
||||
@@ -1187,6 +1206,7 @@
|
||||
"advancements.antarchy.mucus_obtained.description": "Obtain some Mucus.",
|
||||
"block.antarchy.cavaryn_portal": "Cavaryn Portal",
|
||||
"biome.antarchy.cavaryn_moleworm_caves": "Moleworm Caves",
|
||||
"biome.antarchy.wormy_caves": "Wormy Caves",
|
||||
"block.antarchy.termite_nest": "Termite Nest",
|
||||
"block.antarchy.chitin_spike": "Chitin Spike",
|
||||
"block.antarchy.chitin_block": "Chitin Block",
|
||||
@@ -1196,7 +1216,7 @@
|
||||
"block.antarchy.amber_moss_carpet": "Amber Moss Carpet",
|
||||
"block.antarchy.amber_lichen": "Amber Lichen",
|
||||
"block.antarchy.mucus": "Mucus",
|
||||
"tooltip.antarchy.mucus_slippery": "Makes the block it's on slippery like ice",
|
||||
"tooltip.antarchy.mucus_slippery": "Makes the block it's on even more slippery than ice",
|
||||
"block.antarchy.bile_vein": "Bile Vein",
|
||||
"block.antarchy.creepvine": "Creepvine",
|
||||
"block.antarchy.creeping_horror_egg": "Creeping Horror Egg",
|
||||
@@ -1408,4 +1428,5 @@
|
||||
,"decree.antarchy.advance.subtitle": "Close on the King or be judged."
|
||||
,"decree.antarchy.show_no_mercy": "SHOW NO MERCY"
|
||||
,"decree.antarchy.show_no_mercy.subtitle": "Keep dealing damage."
|
||||
,"menu.antarchy.royal_judgment": "Royal Judgment"
|
||||
}
|
||||
@@ -533,6 +533,8 @@
|
||||
"effect.antarchy.paralyzed.description": "Impide que los objetivos se muevan.",
|
||||
"effect.antarchy.inverted": "Invertido",
|
||||
"effect.antarchy.inverted.description": "Invierte la gravedad del objetivo.",
|
||||
"effect.antarchy.commanded.description": "Lucha por el jugador que lo comandó.",
|
||||
"effect.antarchy.dilated.description": "Ralentiza el paso del tiempo para la criatura afectada.",
|
||||
"effect.antarchy.stinky": "Apestoso",
|
||||
"effect.antarchy.stinky.description": "Ahuyenta a las criaturas pasivas y neutrales, y atrae a los artrópodos.",
|
||||
"effect.antarchy.gooped.description": "Reduce la velocidad de movimiento y de ataque.",
|
||||
|
||||
@@ -533,6 +533,8 @@
|
||||
"effect.antarchy.paralyzed.description": "Empêche les cibles de se déplacer.",
|
||||
"effect.antarchy.inverted": "Inversé",
|
||||
"effect.antarchy.inverted.description": "Inverse la gravité de la cible.",
|
||||
"effect.antarchy.commanded.description": "Combat pour le joueur qui l’a commandé.",
|
||||
"effect.antarchy.dilated.description": "Ralentit le passage du temps pour l’entité affectée.",
|
||||
"effect.antarchy.stinky": "Puant",
|
||||
"effect.antarchy.stinky.description": "Repousse les créatures passives et neutres, et attire les arthropodes.",
|
||||
"effect.antarchy.gooped.description": "Ralentit la vitesse de déplacement et d'attaque.",
|
||||
|
||||
@@ -533,6 +533,8 @@
|
||||
"effect.antarchy.paralyzed.description": "Impedisce ai bersagli di muoversi.",
|
||||
"effect.antarchy.inverted": "Invertito",
|
||||
"effect.antarchy.inverted.description": "Inverte la gravità del bersaglio.",
|
||||
"effect.antarchy.commanded.description": "Combatte per il giocatore che lo ha comandato.",
|
||||
"effect.antarchy.dilated.description": "Rallenta il passare del tempo per l’entità colpita.",
|
||||
"effect.antarchy.stinky": "Puzzolente",
|
||||
"effect.antarchy.stinky.description": "Respinge le creature passive e neutrali e attira gli artropodi.",
|
||||
"effect.antarchy.gooped.description": "Riduce la velocità di movimento e di attacco.",
|
||||
|
||||
@@ -533,6 +533,8 @@
|
||||
"effect.antarchy.paralyzed.description": "対象が動けなくなります。",
|
||||
"effect.antarchy.inverted": "重力反転",
|
||||
"effect.antarchy.inverted.description": "対象の重力を反転させます。",
|
||||
"effect.antarchy.commanded.description": "命令したプレイヤーのために戦います。",
|
||||
"effect.antarchy.dilated.description": "影響を受けたエンティティの時間の流れを遅くします。",
|
||||
"effect.antarchy.stinky": "悪臭",
|
||||
"effect.antarchy.stinky.description": "友好的および中立のMobを遠ざけ、節足動物を引き寄せます。",
|
||||
"effect.antarchy.gooped.description": "移動速度と攻撃速度を低下させます。",
|
||||
|
||||
@@ -533,6 +533,8 @@
|
||||
"effect.antarchy.paralyzed.description": "대상이 움직이지 못하게 합니다.",
|
||||
"effect.antarchy.inverted": "반전",
|
||||
"effect.antarchy.inverted.description": "대상의 중력을 반전시킵니다.",
|
||||
"effect.antarchy.commanded.description": "명령한 플레이어를 위해 싸웁니다.",
|
||||
"effect.antarchy.dilated.description": "영향받은 개체의 시간 흐름을 늦춥니다.",
|
||||
"effect.antarchy.stinky": "악취",
|
||||
"effect.antarchy.stinky.description": "수동적 및 중립적 몹을 쫓아내고 절지동물을 끌어들입니다.",
|
||||
"effect.antarchy.gooped.description": "이동 속도와 공격 속도를 늦춥니다.",
|
||||
|
||||
@@ -533,6 +533,8 @@
|
||||
"effect.antarchy.paralyzed.description": "Impede que os alvos se movam.",
|
||||
"effect.antarchy.inverted": "Invertido",
|
||||
"effect.antarchy.inverted.description": "Inverte a gravidade do alvo.",
|
||||
"effect.antarchy.commanded.description": "Luta pelo jogador que o comandou.",
|
||||
"effect.antarchy.dilated.description": "Diminui a passagem do tempo para a entidade afetada.",
|
||||
"effect.antarchy.stinky": "Fedido",
|
||||
"effect.antarchy.stinky.description": "Afasta mobs passivos e neutros e atrai artrópodes.",
|
||||
"effect.antarchy.gooped.description": "Reduz a velocidade de movimento e de ataque.",
|
||||
|
||||
@@ -504,6 +504,8 @@
|
||||
"effect.antarchy.paralyzed.description": "Не дает целям двигаться.",
|
||||
"effect.antarchy.inverted": "Инверсия",
|
||||
"effect.antarchy.inverted.description": "Инвертирует гравитацию цели.",
|
||||
"effect.antarchy.commanded.description": "Сражается за игрока, который им командует.",
|
||||
"effect.antarchy.dilated.description": "Замедляет течение времени для существа под действием эффекта.",
|
||||
"effect.antarchy.stinky": "Вонючесть",
|
||||
"effect.antarchy.stinky.description": "Отпугивает мирных и нейтральных мобов, но притягивает членистоногих.",
|
||||
"effect.antarchy.gooped.description": "Замедляет движение и скорость атаки.",
|
||||
|
||||
@@ -533,6 +533,8 @@
|
||||
"effect.antarchy.paralyzed.description": "阻止目标移动。",
|
||||
"effect.antarchy.inverted": "反转",
|
||||
"effect.antarchy.inverted.description": "反转目标的重力。",
|
||||
"effect.antarchy.commanded.description": "为命令它的玩家而战。",
|
||||
"effect.antarchy.dilated.description": "减缓受影响生物的时间流逝。",
|
||||
"effect.antarchy.stinky": "臭气",
|
||||
"effect.antarchy.stinky.description": "驱赶被动和中立生物,吸引节肢生物。",
|
||||
"effect.antarchy.gooped.description": "减缓移动速度和攻击速度。",
|
||||
|
||||
@@ -533,6 +533,8 @@
|
||||
"effect.antarchy.paralyzed.description": "阻止目標移動。",
|
||||
"effect.antarchy.inverted": "反轉",
|
||||
"effect.antarchy.inverted.description": "反轉目標的重力。",
|
||||
"effect.antarchy.commanded.description": "為命令它的玩家而戰。",
|
||||
"effect.antarchy.dilated.description": "減緩受影響生物的時間流逝。",
|
||||
"effect.antarchy.stinky": "臭氣",
|
||||
"effect.antarchy.stinky.description": "驅趕被動與中立生物,吸引節肢生物。",
|
||||
"effect.antarchy.gooped.description": "降低移動速度與攻擊速度。",
|
||||
|
||||
+1
-138
@@ -1,138 +1 @@
|
||||
{
|
||||
"parent": "builtin/entity",
|
||||
"display": {
|
||||
"thirdperson_righthand": {
|
||||
"rotation": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"translation": [
|
||||
-5.25,
|
||||
2.0,
|
||||
-5
|
||||
],
|
||||
"scale": [
|
||||
0.8,
|
||||
0.8,
|
||||
0.8
|
||||
]
|
||||
},
|
||||
"thirdperson_lefthand": {
|
||||
"rotation": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"translation": [
|
||||
-5.25,
|
||||
2.0,
|
||||
-5
|
||||
],
|
||||
"scale": [
|
||||
0.8,
|
||||
0.8,
|
||||
0.8
|
||||
]
|
||||
},
|
||||
"firstperson_righthand": {
|
||||
"rotation": [
|
||||
10,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"translation": [
|
||||
-1,
|
||||
2.0,
|
||||
0.5
|
||||
],
|
||||
"scale": [
|
||||
0.6,
|
||||
0.6,
|
||||
0.6
|
||||
]
|
||||
},
|
||||
"firstperson_lefthand": {
|
||||
"rotation": [
|
||||
10,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"translation": [
|
||||
-1,
|
||||
2.0,
|
||||
0.5
|
||||
],
|
||||
"scale": [
|
||||
0.6,
|
||||
0.6,
|
||||
0.6
|
||||
]
|
||||
},
|
||||
"ground": {
|
||||
"translation": [
|
||||
0,
|
||||
2,
|
||||
0
|
||||
],
|
||||
"scale": [
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
]
|
||||
},
|
||||
"gui": {
|
||||
"rotation": [
|
||||
30,
|
||||
-135,
|
||||
0
|
||||
],
|
||||
"translation": [
|
||||
0.25,
|
||||
-4.75,
|
||||
0
|
||||
],
|
||||
"scale": [
|
||||
0.85,
|
||||
0.85,
|
||||
0.85
|
||||
]
|
||||
},
|
||||
"head": {
|
||||
"translation": [
|
||||
0,
|
||||
0,
|
||||
-8.25
|
||||
]
|
||||
},
|
||||
"fixed": {
|
||||
"rotation": [
|
||||
90,
|
||||
45,
|
||||
90
|
||||
],
|
||||
"translation": [
|
||||
5.25,
|
||||
3.75,
|
||||
0
|
||||
]
|
||||
},
|
||||
"on_shelf": {
|
||||
"rotation": [
|
||||
90,
|
||||
0,
|
||||
90
|
||||
],
|
||||
"translation": [
|
||||
8.25,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"scale": [
|
||||
1.3,
|
||||
1.3,
|
||||
1.3
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
{"parent":"builtin/entity"}
|
||||
+1
-1225
File diff suppressed because it is too large.
Load diff
@@ -9,7 +9,7 @@
|
||||
},
|
||||
"display": {
|
||||
"announce_to_chat": true,
|
||||
"background": "antarchy:textures/block/myrmite/myrmite",
|
||||
"background": "antarchy:textures/block/myrmite/myrmite.png",
|
||||
"description": {
|
||||
"translate": "advancements.antarchy.visit_cavaryn.description"
|
||||
},
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
},
|
||||
"display": {
|
||||
"announce_to_chat": true,
|
||||
"background": "antarchy:textures/block/ouranwood/mossy_ouranwood_log",
|
||||
"background": "antarchy:textures/block/ouranwood/mossy_ouranwood_log.png",
|
||||
"description": {
|
||||
"translate": "advancements.antarchy.visit_elythia.description"
|
||||
},
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
},
|
||||
"display": {
|
||||
"announce_to_chat": true,
|
||||
"background": "antarchy:textures/block/nyxite",
|
||||
"background": "antarchy:textures/block/nyxite.png",
|
||||
"description": {
|
||||
"translate": "advancements.antarchy.visit_thoraxis.description"
|
||||
},
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
],
|
||||
"humidity": [
|
||||
-0.15,
|
||||
1.0
|
||||
0.45
|
||||
],
|
||||
"continentalness": [
|
||||
-1.0,
|
||||
@@ -186,6 +186,36 @@
|
||||
},
|
||||
"biome": "antarchy:cavaryn_moleworm_caves"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"temperature": [
|
||||
-1.0,
|
||||
1.0
|
||||
],
|
||||
"humidity": [
|
||||
0.45,
|
||||
1.0
|
||||
],
|
||||
"continentalness": [
|
||||
-1.0,
|
||||
1.0
|
||||
],
|
||||
"erosion": [
|
||||
-1.0,
|
||||
1.0
|
||||
],
|
||||
"weirdness": [
|
||||
-0.6,
|
||||
0.9
|
||||
],
|
||||
"depth": [
|
||||
0.15,
|
||||
2.0
|
||||
],
|
||||
"offset": 0.0
|
||||
},
|
||||
"biome": "antarchy:wormy_caves"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"temperature": [
|
||||
|
||||
@@ -57,12 +57,12 @@
|
||||
{
|
||||
"biome": "antarchy:butterfly_fields",
|
||||
"parameters": {
|
||||
"temperature": [0.55, 0.8],
|
||||
"humidity": [0.82, 1.0],
|
||||
"continentalness": [-0.93, 0.25],
|
||||
"erosion": [-1.0, 0.65],
|
||||
"weirdness": [0.75, 1.0],
|
||||
"depth": [0.0, 0.25],
|
||||
"temperature": [0.68, 0.78],
|
||||
"humidity": [0.9, 1.0],
|
||||
"continentalness": [0.05, 0.2],
|
||||
"erosion": [0.05, 0.35],
|
||||
"weirdness": [0.85, 1.0],
|
||||
"depth": [0.0, 0.2],
|
||||
"offset": 0.0
|
||||
}
|
||||
},
|
||||
@@ -74,7 +74,7 @@
|
||||
"continentalness": [0.25, 0.72],
|
||||
"erosion": [-0.5, 0.55],
|
||||
"weirdness": [-0.55, 0.62],
|
||||
"depth": [0.0, 0.35],
|
||||
"depth": [0.0, 1.0],
|
||||
"offset": 0.0
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3,24 +3,38 @@
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:match_tool",
|
||||
"predicate": {
|
||||
"components": {
|
||||
"minecraft:enchantments": {
|
||||
"levels": {
|
||||
"minecraft:silk_touch": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:star_coral"
|
||||
"type": "minecraft:alternatives",
|
||||
"children": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:match_tool",
|
||||
"predicate": {
|
||||
"components": {
|
||||
"minecraft:enchantments": {
|
||||
"levels": {
|
||||
"minecraft:silk_touch": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "antarchy:star_coral"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
],
|
||||
"name": "antarchy:star_coral"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
],
|
||||
"name": "antarchy:dead_star_coral_block"
|
||||
"name": "antarchy:star_coral_block"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+30
-16
@@ -3,24 +3,38 @@
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:match_tool",
|
||||
"predicate": {
|
||||
"components": {
|
||||
"minecraft:enchantments": {
|
||||
"levels": {
|
||||
"minecraft:silk_touch": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:star_coral_fan"
|
||||
"type": "minecraft:alternatives",
|
||||
"children": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:match_tool",
|
||||
"predicate": {
|
||||
"components": {
|
||||
"minecraft:enchantments": {
|
||||
"levels": {
|
||||
"minecraft:silk_touch": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "antarchy:star_coral_fan"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
],
|
||||
"name": "antarchy:star_coral_fan"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+30
-16
@@ -3,24 +3,38 @@
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:match_tool",
|
||||
"predicate": {
|
||||
"components": {
|
||||
"minecraft:enchantments": {
|
||||
"levels": {
|
||||
"minecraft:silk_touch": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:star_coral_fan"
|
||||
"type": "minecraft:alternatives",
|
||||
"children": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:match_tool",
|
||||
"predicate": {
|
||||
"components": {
|
||||
"minecraft:enchantments": {
|
||||
"levels": {
|
||||
"minecraft:silk_touch": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "antarchy:star_coral_fan"
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
],
|
||||
"name": "antarchy:star_coral_fan"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"values": [
|
||||
"antarchy:cavaryn",
|
||||
"antarchy:cavaryn_moleworm_caves",
|
||||
"antarchy:wormy_caves",
|
||||
"antarchy:glowcap_caves",
|
||||
"antarchy:biowart_caves",
|
||||
"antarchy:brooding_tunnels",
|
||||
|
||||
@@ -203,6 +203,59 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:biome",
|
||||
"biome_is": ["antarchy:wormy_caves"]
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:sequence",
|
||||
"sequence": [
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:stone_depth",
|
||||
"offset": 0,
|
||||
"surface_type": "floor",
|
||||
"add_surface_depth": false,
|
||||
"secondary_depth_range": 0
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:noise_threshold",
|
||||
"noise": "antarchy:surface_blend",
|
||||
"min_threshold": -0.28,
|
||||
"max_threshold": 0.18
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:block",
|
||||
"result_state": {
|
||||
"Name": "minecraft:mud"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
"type": "minecraft:stone_depth",
|
||||
"offset": 0,
|
||||
"surface_type": "floor",
|
||||
"add_surface_depth": true,
|
||||
"secondary_depth_range": 0
|
||||
},
|
||||
"then_run": {
|
||||
"type": "minecraft:block",
|
||||
"result_state": {
|
||||
"Name": "antarchy:loam"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
|
||||
Reference in new issue
Block a user