2.2.9
This commit is contained in:
craisinlord authored and GitHub committed 2026-10-26 16:53:02 -05:00
commit c4e157671f
222 files changed
+2741 -1458

No files matched your search

-10
View File
@@ -10,9 +10,6 @@ allprojects {
group = rootProject.maven_group group = rootProject.maven_group
repositories { repositories {
// CurseForge Maven artifacts must be resolved from CurseMaven. The
// Fabric repository does not proxy these coordinates reliably and can
// prevent Gradle from reaching the working repository.
maven { maven {
name = "CurseMaven" name = "CurseMaven"
url = "https://www.cursemaven.com" url = "https://www.cursemaven.com"
@@ -63,13 +60,10 @@ allprojects {
} }
// Don't build the root project itself.
tasks.named('jar') { tasks.named('jar') {
enabled = false enabled = false
} }
// Delegate forge-1.20.1 tasks to its own Gradle 8.8 wrapper. ForgeGradle 6 can't run
// on Gradle 9 and includeBuild can't mix Gradle versions, so we shell out instead.
def forge1201Dir = file('forge-1.20.1') def forge1201Dir = file('forge-1.20.1')
def forge1201Wrapper = providers.systemProperty('os.name').get().toLowerCase().contains('win') def forge1201Wrapper = providers.systemProperty('os.name').get().toLowerCase().contains('win')
? new File(forge1201Dir, 'gradlew.bat') ? new File(forge1201Dir, 'gradlew.bat')
@@ -84,10 +78,6 @@ def forge1201Wrapper = providers.systemProperty('os.name').get().toLowerCase().c
} }
} }
// Delegate fabric-1.20.1 tasks to its own standalone Gradle wrapper. Fabric Loom's
// build-wide tinyRemapperService isn't classloader-safe across two loom projects
// targeting different Minecraft versions in the same Gradle invocation, so
// fabric-1.20.1 can't be a normal included subproject alongside fabric-1.21.1.
def fabric120Dir = file('fabric-1.20.1') def fabric120Dir = file('fabric-1.20.1')
def fabric120Wrapper = providers.systemProperty('os.name').get().toLowerCase().contains('win') def fabric120Wrapper = providers.systemProperty('os.name').get().toLowerCase().contains('win')
? new File(fabric120Dir, 'gradlew.bat') ? new File(fabric120Dir, 'gradlew.bat')
-1
View File
@@ -6,7 +6,6 @@ base {
archivesName = "${mod_id}-common-1.20.1" archivesName = "${mod_id}-common-1.20.1"
} }
// Source-only module — each loader module compiles these sources itself.
tasks.named('compileJava').configure { tasks.named('compileJava').configure {
enabled = false enabled = false
} }
@@ -107,6 +107,9 @@ public final class AntarchySettings {
private static int ultimateCrossbowEnchantability = 20; private static int ultimateCrossbowEnchantability = 20;
private static int ultimateMaceEnchantability = 20; private static int ultimateMaceEnchantability = 20;
private static boolean ultimateToolsThreeByThreeEnabled = true; private static boolean ultimateToolsThreeByThreeEnabled = true;
private static boolean ultimateToolsVeinMiningEnabled = true;
private static int ultimateToolsVeinMiningMaxBlocks = 64;
private static int ultimateToolsTreeFellingMaxLogs = 128;
private static boolean ultimateArmorComesEnchanted = true; private static boolean ultimateArmorComesEnchanted = true;
private static int ultimateHelmetArmorValue = 6; private static int ultimateHelmetArmorValue = 6;
private static int ultimateChestplateArmorValue = 11; private static int ultimateChestplateArmorValue = 11;
@@ -299,6 +302,7 @@ public final class AntarchySettings {
private static double royalBossKnockbackResistance = 1.0D; private static double royalBossKnockbackResistance = 1.0D;
private static double royalBossStepHeight = 3.0D; private static double royalBossStepHeight = 3.0D;
private static double royalBossMaxSingleHitDamage = 250.0D; private static double royalBossMaxSingleHitDamage = 250.0D;
private static double royalBossHitOverflowRate = 0.25D;
private static double royalBossBiteReach = 12.0D; private static double royalBossBiteReach = 12.0D;
private static double royalBossBiteDamageMultiplier = 1.6D; private static double royalBossBiteDamageMultiplier = 1.6D;
private static int royalBossBiteCooldownTicks = 45; private static int royalBossBiteCooldownTicks = 45;
@@ -974,6 +978,18 @@ public final class AntarchySettings {
return ultimateToolsThreeByThreeEnabled; return ultimateToolsThreeByThreeEnabled;
} }
public static boolean ultimateToolsVeinMiningEnabled() {
return ultimateToolsVeinMiningEnabled;
}
public static int ultimateToolsVeinMiningMaxBlocks() {
return ultimateToolsVeinMiningMaxBlocks;
}
public static int ultimateToolsTreeFellingMaxLogs() {
return ultimateToolsTreeFellingMaxLogs;
}
public static boolean ultimateArmorComesEnchanted() { public static boolean ultimateArmorComesEnchanted() {
return ultimateArmorComesEnchanted; return ultimateArmorComesEnchanted;
} }
@@ -1624,6 +1640,18 @@ public final class AntarchySettings {
ultimateToolsThreeByThreeEnabled = value; ultimateToolsThreeByThreeEnabled = value;
} }
public static void setUltimateToolsVeinMiningEnabled(boolean value) {
ultimateToolsVeinMiningEnabled = value;
}
public static void setUltimateToolsVeinMiningMaxBlocks(int value) {
ultimateToolsVeinMiningMaxBlocks = value;
}
public static void setUltimateToolsTreeFellingMaxLogs(int value) {
ultimateToolsTreeFellingMaxLogs = value;
}
public static void setUltimateArmorComesEnchanted(boolean value) { public static void setUltimateArmorComesEnchanted(boolean value) {
ultimateArmorComesEnchanted = value; ultimateArmorComesEnchanted = value;
} }
@@ -2229,6 +2257,9 @@ public final class AntarchySettings {
public static double royalBossMaxSingleHitDamage() { return royalBossMaxSingleHitDamage; } public static double royalBossMaxSingleHitDamage() { return royalBossMaxSingleHitDamage; }
public static void setRoyalBossMaxSingleHitDamage(double v) { royalBossMaxSingleHitDamage = v; } public static void setRoyalBossMaxSingleHitDamage(double v) { royalBossMaxSingleHitDamage = v; }
public static double royalBossHitOverflowRate() { return royalBossHitOverflowRate; }
public static void setRoyalBossHitOverflowRate(double v) { royalBossHitOverflowRate = v; }
public static double royalBossBiteReach() { return royalBossBiteReach; } public static double royalBossBiteReach() { return royalBossBiteReach; }
public static void setRoyalBossBiteReach(double v) { royalBossBiteReach = v; } public static void setRoyalBossBiteReach(double v) { royalBossBiteReach = v; }
@@ -11,6 +11,7 @@ import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluid;
public final class AntarchyTags { public final class AntarchyTags {
@@ -157,4 +158,11 @@ public final class AntarchyTags {
private Biomes() { private Biomes() {
} }
} }
public static final class DimensionTypes {
public static final TagKey<DimensionType> NO_MANTIS_CLIMB = TagKey.create(Registries.DIMENSION_TYPE, id("no_mantis_climb"));
private DimensionTypes() {
}
}
} }
@@ -17,7 +17,6 @@ public final class MoonSkyTracker {
private static final long MAX_AGE_MILLIS = 1500L; private static final long MAX_AGE_MILLIS = 1500L;
private static final double AIM_COSINE = Math.cos(Math.toRadians(PortalGunMoonMath.AIM_TOLERANCE_DEGREES)); private static final double AIM_COSINE = Math.cos(Math.toRadians(PortalGunMoonMath.AIM_TOLERANCE_DEGREES));
private static Vec3 direction; private static Vec3 direction;
// Weak so a dimension change or logout doesn't pin the old client world in memory.
private static WeakReference<ClientLevel> level = new WeakReference<>(null); private static WeakReference<ClientLevel> level = new WeakReference<>(null);
private static long recordedAt; private static long recordedAt;
private static Consumer<PortalGunMoonAimPayload> sender = payload -> {}; private static Consumer<PortalGunMoonAimPayload> sender = payload -> {};
@@ -20,7 +20,6 @@ public final class PortalGunCrosshairRenderer {
private static final int HALF_WIDTH = 17; private static final int HALF_WIDTH = 17;
private static final float MISSING_BRIGHTNESS = 0.3F; private static final float MISSING_BRIGHTNESS = 0.3F;
private static final float MISSING_ALPHA = 0.75F; private static final float MISSING_ALPHA = 0.75F;
// Weak so a dimension change or logout doesn't pin the old client world in memory.
private static WeakReference<ClientLevel> cachedLevel = new WeakReference<>(null); private static WeakReference<ClientLevel> cachedLevel = new WeakReference<>(null);
private static long cachedGameTime = Long.MIN_VALUE; private static long cachedGameTime = Long.MIN_VALUE;
private static UUID cachedGunId; private static UUID cachedGunId;
@@ -12,7 +12,6 @@ import net.minecraft.client.multiplayer.ClientLevel;
public final class PortalGunIndicatorClientState { public final class PortalGunIndicatorClientState {
private static final Map<UUID, PortalGunIndicatorPayload> STATES = new HashMap<>(); private static final Map<UUID, PortalGunIndicatorPayload> STATES = new HashMap<>();
// Weak so a dimension change or logout doesn't pin the old client world in memory.
private static WeakReference<ClientLevel> level = new WeakReference<>(null); private static WeakReference<ClientLevel> level = new WeakReference<>(null);
private static long lastRequestTick = Long.MIN_VALUE; private static long lastRequestTick = Long.MIN_VALUE;
private static UUID lastRequestedGun; private static UUID lastRequestedGun;
@@ -11,6 +11,12 @@ import software.bernie.geckolib.model.GeoModel;
public class RoyalMountModel extends GeoModel<RoyalMountEntity> { public class RoyalMountModel extends GeoModel<RoyalMountEntity> {
private static final String[] HEADS = {"head_left", "head", "head_right"}; private static final String[] HEADS = {"head_left", "head", "head_right"};
private static final String[] RIDDEN_NECK_CHAIN = {
"neck", "neck2", "neck3", "head",
"neck_left", "neck_left2", "neck_left3", "head_left",
"neck_right", "neck_right2", "neck_right3", "head_right"
};
private static final float RIDDEN_NECK_RAISE = 0.35F;
@Override @Override
public ResourceLocation getModelResource(RoyalMountEntity animatable) { public ResourceLocation getModelResource(RoyalMountEntity animatable) {
@@ -31,6 +37,11 @@ public class RoyalMountModel extends GeoModel<RoyalMountEntity> {
public void setCustomAnimations(RoyalMountEntity animatable, long instanceId, public void setCustomAnimations(RoyalMountEntity animatable, long instanceId,
AnimationState<RoyalMountEntity> animationState) { AnimationState<RoyalMountEntity> animationState) {
super.setCustomAnimations(animatable, instanceId, animationState); super.setCustomAnimations(animatable, instanceId, animationState);
if (animatable.isVehicle()) {
for (String name : RIDDEN_NECK_CHAIN) {
this.getBone(name).ifPresent(bone -> bone.setRotX(bone.getRotX() * RIDDEN_NECK_RAISE));
}
}
for (String head : HEADS) { for (String head : HEADS) {
this.getBone(head).ifPresent(bone -> bone.setTrackingMatrices(true)); this.getBone(head).ifPresent(bone -> bone.setTrackingMatrices(true));
} }
@@ -21,6 +21,7 @@ public final class BloodglassWardEffect extends MobEffect {
public void addAttributeModifiers(net.minecraft.world.entity.LivingEntity livingEntity, AttributeMap attributeMap, int amplifier) { public void addAttributeModifiers(net.minecraft.world.entity.LivingEntity livingEntity, AttributeMap attributeMap, int amplifier) {
AttributeInstance instance = attributeMap.getInstance(AntarchyObjects.BLOODGLASS_MAX_HEARTS.get()); AttributeInstance instance = attributeMap.getInstance(AntarchyObjects.BLOODGLASS_MAX_HEARTS.get());
if (instance == null) return; if (instance == null) return;
instance.removeModifier(MODIFIER_ID);
instance.addTransientModifier( instance.addTransientModifier(
new AttributeModifier(MODIFIER_ID, "bloodglass_ward_hearts", amplifier + 1, AttributeModifier.Operation.ADDITION) new AttributeModifier(MODIFIER_ID, "bloodglass_ward_hearts", amplifier + 1, AttributeModifier.Operation.ADDITION)
); );
@@ -392,6 +392,9 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
if (this.isKnockedDown()) { if (this.isKnockedDown()) {
this.tickKnockedDown(); this.tickKnockedDown();
} else if (this.isLeashed()) { } else if (this.isLeashed()) {
if (this.chargeTicksRemaining > 0 || this.isChargeAnimationActive()) {
this.endChargeState();
}
this.getNavigation().stop(); this.getNavigation().stop();
this.setTarget(null); this.setTarget(null);
this.updateAmbientAnimation(); this.updateAmbientAnimation();
@@ -484,6 +487,10 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
} }
private void tickCharge() { private void tickCharge() {
if (this.chargeTicksRemaining <= 0) {
this.endChargeState();
return;
}
if (this.getAnimationState() != ANIM_CHARGE) { if (this.getAnimationState() != ANIM_CHARGE) {
this.setAnimationState(ANIM_CHARGE); this.setAnimationState(ANIM_CHARGE);
} }
@@ -910,6 +917,9 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
if (!this.isFlying() && !mountedCharge) { if (!this.isFlying() && !mountedCharge) {
this.pendingChargeStart = true; this.pendingChargeStart = true;
this.requestFlightStart(); this.requestFlightStart();
if (this.getAnimationState() != ANIM_OPEN_WINGS) {
this.pendingChargeStart = false;
}
return; return;
} }
this.beginChargeStart(this.chargeDirection, this.pendingChargeDuration, mountedCharge); this.beginChargeStart(this.chargeDirection, this.pendingChargeDuration, mountedCharge);
@@ -979,11 +989,21 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
serverLevel.sendParticles(ParticleTypes.CRIT, this.getX(), this.getY() + 0.8D, this.getZ(), 20, 2.0D, 0.6D, 2.0D, 0.08D); serverLevel.sendParticles(ParticleTypes.CRIT, this.getX(), this.getY() + 0.8D, this.getZ(), 20, 2.0D, 0.6D, 2.0D, 0.08D);
this.broadcastImpactShake(serverLevel); this.broadcastImpactShake(serverLevel);
if (this.onGround()) { this.endChargeState();
this.requestFlightStop();
} else {
this.updateAmbientAnimation();
} }
private void endChargeState() {
this.chargeTicksRemaining = 0;
this.groundedMountedCharge = false;
this.noPhysics = false;
this.setAnimationState(this.isFlying() ? ANIM_FLY : ANIM_IDLE);
if (!this.isVehicle() && this.isFlying() && this.hasGroundBelow()) {
this.requestFlightStop();
}
}
private boolean hasGroundBelow() {
return !this.level().noCollision(this, this.getBoundingBox().move(this.toWorld(0.0D, -0.2D, 0.0D)));
} }
private void breakBlocksForChargeImpact(ServerLevel level) { private void breakBlocksForChargeImpact(ServerLevel level) {
@@ -1424,6 +1444,9 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
this.chargeCooldown = tag.getInt("ChargeCooldown"); this.chargeCooldown = tag.getInt("ChargeCooldown");
this.attackCooldown = tag.getInt("AttackCooldown"); this.attackCooldown = tag.getInt("AttackCooldown");
this.combatCryDone = tag.getBoolean("CombatCryDone"); this.combatCryDone = tag.getBoolean("CombatCryDone");
if (this.isChargeAnimationActive()) {
this.setAnimationState(this.isFlying() ? ANIM_FLY : ANIM_IDLE);
}
if (this.isKnockedDown() && this.getAnimationState() != ANIM_KNOCKED_DOWN_IDLE) { if (this.isKnockedDown() && this.getAnimationState() != ANIM_KNOCKED_DOWN_IDLE) {
this.setAnimationState(ANIM_KNOCKED_DOWN_IDLE); this.setAnimationState(ANIM_KNOCKED_DOWN_IDLE);
} }
@@ -40,6 +40,8 @@ import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation; import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
import net.minecraft.world.entity.ai.navigation.PathNavigation; import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@@ -85,7 +87,7 @@ public class BrutalflyEntity extends Monster implements GeoEntity {
private static final int SPIT_WINDUP_TICKS = 16; private static final int SPIT_WINDUP_TICKS = 16;
private static final int SWIPE_TICKS = 18; private static final int SWIPE_TICKS = 18;
private static final float SWIPE_KNOCKBACK = 2.8F; private static final float SWIPE_KNOCKBACK = 2.8F;
private static final int COCOON_HIT_THRESHOLD = 3; private static final int COCOON_HIT_THRESHOLD = 5;
private static final int COCOON_HIT_COOLDOWN_TICKS = 60; private static final int COCOON_HIT_COOLDOWN_TICKS = 60;
private static final int COCOON_HIT_ANIM_TICKS = 30; private static final int COCOON_HIT_ANIM_TICKS = 30;
private static final int COCOON_HATCH_ANIM_TICKS = 40; private static final int COCOON_HATCH_ANIM_TICKS = 40;
@@ -337,6 +339,12 @@ public class BrutalflyEntity extends Monster implements GeoEntity {
if (nearbyPlayer != null && !nearbyPlayer.isCreative() && !nearbyPlayer.isSpectator()) { if (nearbyPlayer != null && !nearbyPlayer.isCreative() && !nearbyPlayer.isSpectator()) {
this.setTarget(nearbyPlayer); this.setTarget(nearbyPlayer);
} }
this.spitCooldown = 0;
}
public float getDamageScale() {
double base = AntarchySettings.brutalflySwipeDamage();
return base <= 0.0D ? 1.0F : (float) (this.getAttributeValue(Attributes.ATTACK_DAMAGE) / base);
} }
public boolean isCocooned() { public boolean isCocooned() {
@@ -514,6 +522,11 @@ public class BrutalflyEntity extends Monster implements GeoEntity {
this.playSound(AntarchySoundEvents.BRUTALFLY_SPIT.get(), 1.0F, 0.9F + this.random.nextFloat() * 0.2F); this.playSound(AntarchySoundEvents.BRUTALFLY_SPIT.get(), 1.0F, 0.9F + this.random.nextFloat() * 0.2F);
switch (this.getFightPhase()) { switch (this.getFightPhase()) {
case PHASE_THREE -> { case PHASE_THREE -> {
this.launchOrb(serverLevel, origin, target, BrutalflyOrbEntity.OrbVariant.POISON, -14.0F);
this.launchOrb(serverLevel, origin, target, BrutalflyOrbEntity.OrbVariant.STICKY, 0.0F);
this.launchOrb(serverLevel, origin, target, BrutalflyOrbEntity.OrbVariant.POISON, 14.0F);
}
case PHASE_TWO -> {
this.launchOrb(serverLevel, origin, target, BrutalflyOrbEntity.OrbVariant.POISON, -8.0F); this.launchOrb(serverLevel, origin, target, BrutalflyOrbEntity.OrbVariant.POISON, -8.0F);
this.launchOrb(serverLevel, origin, target, BrutalflyOrbEntity.OrbVariant.STICKY, 8.0F); this.launchOrb(serverLevel, origin, target, BrutalflyOrbEntity.OrbVariant.STICKY, 8.0F);
} }
@@ -586,7 +599,8 @@ public class BrutalflyEntity extends Monster implements GeoEntity {
} }
private void performSwipeHit() { private void performSwipeHit() {
float swipeDamage = (float) AntarchySettings.brutalflySwipeDamage(); float swipeDamage = (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE);
boolean finalPhase = this.getFightPhase() == FightPhase.PHASE_THREE;
AABB attackBox = this.getBoundingBox().inflate(4.8D, 2.4D, 4.8D).expandTowards(0.0D, -2.5D, 0.0D); AABB attackBox = this.getBoundingBox().inflate(4.8D, 2.4D, 4.8D).expandTowards(0.0D, -2.5D, 0.0D);
for (LivingEntity target : this.level().getEntitiesOfClass( for (LivingEntity target : this.level().getEntitiesOfClass(
LivingEntity.class, LivingEntity.class,
@@ -598,6 +612,9 @@ public class BrutalflyEntity extends Monster implements GeoEntity {
} }
target.hurt(this.damageSources().mobAttack(this), swipeDamage); target.hurt(this.damageSources().mobAttack(this), swipeDamage);
if (finalPhase) {
target.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 60, 1, false, true));
}
double dx = target.getX() - this.getX(); double dx = target.getX() - this.getX();
double dz = target.getZ() - this.getZ(); double dz = target.getZ() - this.getZ();
@@ -162,6 +162,9 @@ public class BrutalflyOrbEntity extends ThrowableItemProjectile {
if (!this.level().isClientSide && result.getEntity() instanceof LivingEntity livingTarget) { if (!this.level().isClientSide && result.getEntity() instanceof LivingEntity livingTarget) {
float directHitDamage = (float) AntarchySettings.brutalflySpitDamage(); float directHitDamage = (float) AntarchySettings.brutalflySpitDamage();
Entity owner = this.getOwner(); Entity owner = this.getOwner();
if (owner instanceof BrutalflyEntity brutalfly) {
directHitDamage *= brutalfly.getDamageScale();
}
if (owner instanceof LivingEntity livingOwner) { if (owner instanceof LivingEntity livingOwner) {
livingTarget.hurt(this.damageSources().mobProjectile(this, livingOwner), directHitDamage); livingTarget.hurt(this.damageSources().mobProjectile(this, livingOwner), directHitDamage);
} else { } else {
@@ -3,13 +3,31 @@ package com.craisinlord.antarchy.content.entity.royal;
import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyObjects; import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchySoundEvents; import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement; import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
import java.util.Comparator;
import java.util.List;
import net.minecraft.core.particles.DustParticleOptions;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.Mth;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.monster.Enemy;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
public class PrinceEntity extends RoyalMountEntity { public class PrinceEntity extends RoyalMountEntity {
private static final DustParticleOptions COMMAND_DUST = new DustParticleOptions(new Vector3f(1.0F, 0.75F, 0.15F), 1.6F);
public PrinceEntity(EntityType<? extends PrinceEntity> entityType, Level level) { public PrinceEntity(EntityType<? extends PrinceEntity> entityType, Level level) {
super(entityType, level); super(entityType, level);
} }
@@ -40,6 +58,117 @@ public class PrinceEntity extends RoyalMountEntity {
}; };
} }
@Override
protected ParticleOptions beamWindupParticle() {
return switch (this.getBeamElement()) {
case FIRE -> ParticleTypes.FLAME;
case ICE -> ParticleTypes.SNOWFLAKE;
default -> ParticleTypes.ELECTRIC_SPARK;
};
}
@Override
protected float beamBaseDamage() {
return 12.0F;
}
@Override
public boolean prefersAerialCombat() {
return false;
}
@Override
public double preferredCombatRange() {
return 0.0D;
}
@Override
protected float biteWeight() {
return 3.0F;
}
@Override
protected float spitWeight() {
return 1.0F;
}
@Override
protected float beamWeight() {
return 1.2F;
}
@Override
protected float signatureWeight() {
return 4.0F;
}
@Override
protected int signatureCooldownTicks() {
return 360;
}
private double commandRadius() {
return 14.0D + 2.0D * this.getGrowthScale();
}
private int commandLimit() {
return 3 + Mth.floor(this.getGrowthScale());
}
private List<Mob> commandCandidates(Vec3 center) {
double radius = this.commandRadius();
return this.level().getEntitiesOfClass(Mob.class, this.getBoundingBox().inflate(radius), mob ->
mob != this && mob.isAlive() && mob instanceof Enemy && !mob.isAlliedTo(this)
&& !(mob instanceof RoyalBossEntity) && RoyalEffectEligibility.canApplyCommanded(mob)
&& RoyalEffectHooks.commandedHolder() != null
&& !mob.hasEffect(RoyalEffectHooks.commandedHolder())
&& mob.distanceToSqr(center) <= radius * radius);
}
@Override
protected boolean isSignatureUseful(LivingEntity target) {
return RoyalEffectHooks.commandedHolder() != null && this.commandCandidates(this.position()).size() >= 2;
}
@Override
protected void signatureTelegraph(ServerLevel level, int tick, @Nullable LivingEntity target, @Nullable Vec3 aimPoint) {
if (tick % 3 != 0) {
return;
}
double radius = (this.getBbWidth() * 0.5D + 1.0D) + tick * 0.25D * this.getGrowthScale();
for (int i = 0; i < 16; i++) {
double angle = i * Mth.TWO_PI / 16.0D + tick * 0.1D;
level.sendParticles(COMMAND_DUST, this.getX() + Math.cos(angle) * radius, this.getY() + 0.3D,
this.getZ() + Math.sin(angle) * radius, 1, 0.0D, 0.05D, 0.0D, 0.0D);
}
if (tick == 3) {
level.sendParticles(ParticleTypes.ENCHANTED_HIT, this.getX(), this.getY() + this.getBbHeight(), this.getZ(),
20, this.getBbWidth() * 0.3D, 0.3D, this.getBbWidth() * 0.3D, 0.1D);
}
}
@Override
protected boolean performSignature(ServerLevel level, @Nullable LivingEntity target, @Nullable Vec3 aimPoint, boolean ridden) {
if (RoyalEffectHooks.commandedHolder() == null) {
return false;
}
Vec3 center = this.position();
List<Mob> candidates = this.commandCandidates(center);
candidates.sort(Comparator.comparingDouble(mob -> mob.distanceToSqr(center)));
int applied = 0;
for (Mob mob : candidates) {
if (applied >= this.commandLimit()) {
break;
}
if (mob.addEffect(new MobEffectInstance(RoyalEffectHooks.commandedHolder(), 300 + 20 * Mth.floor(this.getGrowthScale())), this)) {
applied++;
level.sendParticles(COMMAND_DUST, mob.getX(), mob.getY() + mob.getBbHeight() + 0.3D, mob.getZ(), 8, 0.25D, 0.2D, 0.25D, 0.0D);
}
}
level.sendParticles(ParticleTypes.SONIC_BOOM, this.getX(), this.getY() + this.getBbHeight() * 0.6D, this.getZ(), 1, 0.0D, 0.0D, 0.0D, 0.0D);
return applied > 0;
}
@Override @Override
protected String geoName() { protected String geoName() {
return "prince"; return "prince";
@@ -4,10 +4,18 @@ import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyObjects; import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchySoundEvents; import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement; import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
import com.craisinlord.anthology.time.TimeDilationApi;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
public class PrincessEntity extends RoyalMountEntity { public class PrincessEntity extends RoyalMountEntity {
public PrincessEntity(EntityType<? extends PrincessEntity> entityType, Level level) { public PrincessEntity(EntityType<? extends PrincessEntity> entityType, Level level) {
@@ -24,11 +32,120 @@ public class PrincessEntity extends RoyalMountEntity {
@Override @Override
protected RoyalBeamElement boltElement(int lateralIndex) { protected RoyalBeamElement boltElement(int lateralIndex) {
return switch (lateralIndex) { return RoyalBeamElement.GENERIC;
case -1 -> RoyalBeamElement.FIRE; }
case 1 -> RoyalBeamElement.ICE;
default -> RoyalBeamElement.LIGHTNING; @Override
}; protected Vec3 boltOrigin(int lateralIndex) {
float scale = this.getGrowthScale();
Vec3 forward = Vec3.directionFromRotation(0.0F, this.getYRot());
Vec3 side = new Vec3(-forward.z, 0.0D, forward.x);
return this.position()
.add(0.0D, (lateralIndex == 0 ? 0.4D : 0.33D) * scale, 0.0D)
.add(forward.scale((lateralIndex == 0 ? 0.32D : 0.23D) * scale + this.getBbWidth() * 0.15D))
.add(side.scale(lateralIndex * 0.24D * scale));
}
@Override
protected int nextBeamHead(int previous) {
return 1;
}
@Override
protected ParticleOptions beamWindupParticle() {
return ParticleTypes.REVERSE_PORTAL;
}
@Override
protected float beamBaseDamage() {
return 10.0F;
}
@Override
public boolean prefersAerialCombat() {
return this.canFly();
}
@Override
public double preferredCombatRange() {
return 8.0D + 1.5D * this.getGrowthScale();
}
@Override
protected float biteWeight() {
return 1.0F;
}
@Override
protected float spitWeight() {
return 2.5F;
}
@Override
protected float beamWeight() {
return 1.6F;
}
@Override
protected float signatureWeight() {
return 2.5F;
}
@Override
protected int signatureCooldownTicks() {
return 300;
}
private double fieldRadius() {
return 5.0D + 0.8D * this.getGrowthScale();
}
private boolean ownerInside(Vec3 center) {
LivingEntity owner = this.getOwner();
if (owner == null || owner.level() != this.level() || this.hasPassenger(owner)) {
return false;
}
double clearance = this.fieldRadius() + 1.5D;
return owner.position().distanceToSqr(center) < clearance * clearance;
}
@Override
protected boolean isSignatureUseful(LivingEntity target) {
return this.combatGap(target) < 10.0D + 1.5D * this.getGrowthScale() && !this.ownerInside(target.position());
}
private Vec3 fieldCenter(@Nullable LivingEntity target, @Nullable Vec3 aimPoint) {
if (target != null && target.isAlive()) {
return target.position();
}
return aimPoint != null ? aimPoint : this.position().add(Vec3.directionFromRotation(0.0F, this.getYRot()).scale(this.getBbWidth() + 6.0D));
}
@Override
protected void signatureTelegraph(ServerLevel level, int tick, @Nullable LivingEntity target, @Nullable Vec3 aimPoint) {
if (tick % 2 != 0) {
return;
}
Vec3 center = this.fieldCenter(target, aimPoint);
double radius = this.fieldRadius() * (1.0D - tick / 24.0D) + 0.5D;
for (int i = 0; i < 12; i++) {
double angle = i * Mth.TWO_PI / 12.0D - tick * 0.15D;
level.sendParticles(ParticleTypes.REVERSE_PORTAL, center.x + Math.cos(angle) * radius, center.y + 0.2D,
center.z + Math.sin(angle) * radius, 1, 0.0D, 0.05D, 0.0D, 0.0D);
}
Vec3 orb = this.boltOrigin(0);
level.sendParticles(ParticleTypes.END_ROD, orb.x, orb.y, orb.z, 2, 0.1D, 0.1D, 0.1D, 0.01D);
}
@Override
protected boolean performSignature(ServerLevel level, @Nullable LivingEntity target, @Nullable Vec3 aimPoint, boolean ridden) {
Vec3 center = this.fieldCenter(target, aimPoint);
if (this.ownerInside(center)) {
return false;
}
TimeDilationApi.createField(level, center, this.fieldRadius(), 0.35D, 100 + 10 * Mth.floor(this.getGrowthScale()), this.getUUID());
level.sendParticles(ParticleTypes.END_ROD, center.x, center.y + 0.5D, center.z, 36, this.fieldRadius() * 0.3D, 0.6D, this.fieldRadius() * 0.3D, 0.03D);
return true;
} }
@Override @Override
@@ -86,6 +86,14 @@ public class RoyalBoltEntity extends AbstractHurtingProjectile {
}; };
} }
@Override
protected boolean canHitEntity(Entity target) {
if (this.getOwner() instanceof RoyalMountEntity mount && mount.isFriendlyTo(target)) {
return false;
}
return super.canHitEntity(target);
}
@Override @Override
protected void onHitEntity(EntityHitResult result) { protected void onHitEntity(EntityHitResult result) {
super.onHitEntity(result); super.onHitEntity(result);
@@ -101,7 +109,13 @@ public class RoyalBoltEntity extends AbstractHurtingProjectile {
&& royal.isTame() && other.isTame()) { && royal.isTame() && other.isTame()) {
return; return;
} }
if (owner instanceof RoyalMountEntity mount && mount.isFriendlyTo(target)) {
return;
}
float damage = (float) AntarchySettings.royalBoltDamage(); float damage = (float) AntarchySettings.royalBoltDamage();
if (owner instanceof RoyalMountEntity mount) {
damage *= mount.projectileDamageMultiplier();
}
target.hurt(this.damageSources().mobProjectile(this, owner instanceof LivingEntity le ? le : null), damage); target.hurt(this.damageSources().mobProjectile(this, owner instanceof LivingEntity le ? le : null), damage);
if (target instanceof LivingEntity living) { if (target instanceof LivingEntity living) {
living.knockback(0.35D, this.getX() - target.getX(), this.getZ() - target.getZ()); living.knockback(0.35D, this.getX() - target.getX(), this.getZ() - target.getZ());
@@ -125,6 +139,9 @@ public class RoyalBoltEntity extends AbstractHurtingProjectile {
} }
} }
case GENERIC -> { case GENERIC -> {
if (owner instanceof PrincessEntity) {
living.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 60, 1), owner);
}
} }
} }
} }
@@ -2006,7 +2006,8 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
if (source.is(DamageTypes.GENERIC_KILL)) { if (source.is(DamageTypes.GENERIC_KILL)) {
return super.hurt(source, amount); return super.hurt(source, amount);
} }
float cappedAmount = (float) Math.min(amount, AntarchySettings.royalBossMaxSingleHitDamage()); float cap = (float) AntarchySettings.royalBossMaxSingleHitDamage();
float cappedAmount = amount <= cap ? amount : cap + (amount - cap) * (float) AntarchySettings.royalBossHitOverflowRate();
return super.hurt(source, cappedAmount); return super.hurt(source, cappedAmount);
} }
@@ -0,0 +1,239 @@
package com.craisinlord.antarchy.content.entity.royal;
import java.util.EnumSet;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.phys.Vec3;
public class RoyalMountCombatGoal extends Goal {
private static final int FLIGHT_DECISION_INTERVAL = 40;
private final RoyalMountEntity mount;
private LivingEntity target;
private int repathTicks;
private int flightDecisionTicks;
private boolean wantsFlight;
private int stuckTicks;
private Vec3 lastCheckPosition = Vec3.ZERO;
private float orbitAngle;
private int orbitDirection = 1;
private int diveTicks;
private int unseenTicks;
public RoyalMountCombatGoal(RoyalMountEntity mount) {
this.mount = mount;
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
}
@Override
public boolean canUse() {
LivingEntity candidate = this.mount.getTarget();
if (!this.isValid(candidate)) {
return false;
}
this.target = candidate;
return true;
}
@Override
public boolean canContinueToUse() {
LivingEntity current = this.mount.getTarget();
if (current != this.target || !this.isValid(current)) {
return false;
}
double range = this.mount.getAttributeValue(net.minecraft.world.entity.ai.attributes.Attributes.FOLLOW_RANGE) * 1.2D;
return this.mount.distanceToSqr(current) < range * range && this.unseenTicks < 200;
}
private boolean isValid(LivingEntity candidate) {
return candidate != null && candidate.isAlive() && !this.mount.isVehicle() && !this.mount.isOrderedToSit()
&& candidate.level() == this.mount.level() && this.mount.canAttack(candidate);
}
@Override
public void start() {
this.repathTicks = 0;
this.flightDecisionTicks = 0;
this.wantsFlight = false;
this.stuckTicks = 0;
this.unseenTicks = 0;
this.diveTicks = 0;
this.lastCheckPosition = this.mount.position();
Vec3 offset = this.mount.position().subtract(this.target.position());
this.orbitAngle = (float) Mth.atan2(offset.z, offset.x);
this.orbitDirection = this.mount.getRandom().nextBoolean() ? 1 : -1;
}
@Override
public void stop() {
this.target = null;
this.mount.getNavigation().stop();
}
@Override
public boolean requiresUpdateEveryTick() {
return true;
}
@Override
public void tick() {
LivingEntity current = this.target;
if (current == null) {
return;
}
boolean canSee = this.mount.getSensing().hasLineOfSight(current);
this.unseenTicks = canSee ? 0 : this.unseenTicks + 1;
double gap = this.mount.combatGap(current);
this.mount.getLookControl().setLookAt(current, 30.0F, 30.0F);
this.trackStuck();
this.updateFlightDecision(current, gap);
if (this.mount.isActing()) {
this.holdDuringAction(current);
return;
}
int chosen = this.mount.chooseCombatAction(current, gap, canSee);
if (chosen != RoyalMountEntity.ACTION_NONE && this.isFacing(current, this.facingTolerance(chosen))) {
if (this.mount.startAction(chosen, current, current.getEyePosition(), false)) {
this.diveTicks = 0;
this.holdDuringAction(current);
return;
}
}
if (chosen != RoyalMountEntity.ACTION_NONE) {
this.mount.turnTowards(current.position(), 18.0F);
}
if (this.mount.isFlying()) {
this.tickAerial(current, gap);
} else {
this.tickGround(current, gap, canSee);
}
}
private float facingTolerance(int action) {
return switch (action) {
case RoyalMountEntity.ACTION_BITE -> 50.0F;
case RoyalMountEntity.ACTION_SIGNATURE -> 180.0F;
default -> 120.0F;
};
}
private boolean isFacing(LivingEntity current, float tolerance) {
Vec3 toTarget = current.position().subtract(this.mount.position());
float desired = (float) (Mth.atan2(toTarget.z, toTarget.x) * Mth.RAD_TO_DEG) - 90.0F;
return Math.abs(Mth.wrapDegrees(desired - this.mount.getYRot())) <= tolerance;
}
private void holdDuringAction(LivingEntity current) {
this.mount.getNavigation().stop();
if (this.mount.isFlying()) {
this.mount.claimFlight();
if (this.mount.currentAction() == RoyalMountEntity.ACTION_BITE) {
this.mount.getMoveControl().setWantedPosition(current.getX(), current.getY() + current.getBbHeight() * 0.5D, current.getZ(), 0.6D);
} else {
this.mount.getMoveControl().setWantedPosition(this.mount.getX(), this.mount.getY(), this.mount.getZ(), 0.4D);
}
} else if (this.mount.currentAction() != RoyalMountEntity.ACTION_BITE) {
this.mount.setDeltaMovement(this.mount.getDeltaMovement().multiply(0.5D, 1.0D, 0.5D));
}
}
private void trackStuck() {
if (this.mount.tickCount % 20 != 0) {
return;
}
Vec3 position = this.mount.position();
boolean trying = !this.mount.getNavigation().isDone() || this.mount.isFlying();
if (trying && position.distanceToSqr(this.lastCheckPosition) < 1.0D) {
this.stuckTicks += 20;
} else {
this.stuckTicks = 0;
}
this.lastCheckPosition = position;
}
private void updateFlightDecision(LivingEntity current, double gap) {
if (!this.mount.canFly()) {
this.wantsFlight = false;
return;
}
if (--this.flightDecisionTicks <= 0 || this.stuckTicks >= 40) {
this.flightDecisionTicks = FLIGHT_DECISION_INTERVAL;
boolean targetAbove = current.getY() - this.mount.getY() > 4.0D + this.mount.getBbHeight() * 0.25D;
boolean targetAirborne = !current.onGround() && !current.isInWater() && RoyalMountEntity.isAirborne(current) || targetAbove;
boolean groundBlocked = !this.mount.isFlying() && (this.stuckTicks >= 40
|| this.mount.getNavigation().isDone() && gap > 4.0D && this.mount.getNavigation().createPath(current, 0) == null);
boolean prefersAir = this.mount.prefersAerialCombat() && gap > 3.0D;
this.wantsFlight = targetAirborne || groundBlocked || prefersAir || (this.mount.isFlying() && this.diveTicks > 0);
if (this.stuckTicks >= 40) {
this.stuckTicks = 0;
}
}
if (this.wantsFlight) {
this.mount.claimFlight();
}
}
private void tickAerial(LivingEntity current, double gap) {
if (!this.wantsFlight) {
return;
}
this.mount.claimFlight();
float scale = this.mount.getGrowthScale();
boolean wantsBite = this.mount.isActionAvailable(RoyalMountEntity.ACTION_BITE)
&& (!this.mount.prefersAerialCombat() || gap < this.mount.preferredCombatRange() * 0.5D || this.diveTicks > 0);
if (wantsBite && this.mount.isActionReady()) {
this.diveTicks++;
Vec3 approach = current.position().subtract(this.mount.position()).multiply(1.0D, 0.0D, 1.0D);
Vec3 offset = approach.lengthSqr() > 1.0E-4D ? approach.normalize().scale(-(this.mount.getBbWidth() * 0.5D + 0.6D * scale)) : Vec3.ZERO;
this.mount.getMoveControl().setWantedPosition(current.getX() + offset.x, current.getY() + 0.2D, current.getZ() + offset.z, 1.4D);
if (this.diveTicks > 80) {
this.diveTicks = 0;
this.orbitDirection = -this.orbitDirection;
}
return;
}
this.diveTicks = 0;
double radius = Math.max(6.0D + 1.5D * scale, this.mount.preferredCombatRange()) + this.mount.getBbWidth() * 0.5D;
this.orbitAngle += this.orbitDirection * (float) Math.min(0.08D, 1.2D / radius);
double x = current.getX() + Math.cos(this.orbitAngle) * radius;
double z = current.getZ() + Math.sin(this.orbitAngle) * radius;
double y = current.getY() + 3.0D + 0.8D * scale;
if (!this.mount.canOccupy(x, y, z)) {
this.orbitDirection = -this.orbitDirection;
y += 2.0D + scale;
}
this.mount.getMoveControl().setWantedPosition(x, y, z, 1.1D);
}
private void tickGround(LivingEntity current, double gap, boolean canSee) {
double preferred = this.mount.preferredCombatRange();
boolean ranged = preferred > 0.0D && this.mount.canSpit();
if (ranged && canSee && gap < preferred * 0.5D && !this.mount.isActionAvailable(RoyalMountEntity.ACTION_BITE)) {
Vec3 away = this.mount.position().subtract(current.position()).multiply(1.0D, 0.0D, 1.0D);
if (away.lengthSqr() > 1.0E-4D && --this.repathTicks <= 0) {
this.repathTicks = 10;
Vec3 destination = this.mount.position().add(away.normalize().scale(4.0D + this.mount.getBbWidth() * 0.5D));
this.mount.getNavigation().moveTo(destination.x, destination.y, destination.z, 1.2D);
}
return;
}
if (ranged && canSee && gap <= preferred && gap >= preferred * 0.5D && !this.mount.isActionAvailable(RoyalMountEntity.ACTION_BITE)) {
this.mount.getNavigation().stop();
this.mount.turnTowards(current.position(), 12.0F);
return;
}
if (this.mount.canBiteReach(current)) {
this.mount.getNavigation().stop();
this.mount.turnTowards(current.position(), 18.0F);
return;
}
if (--this.repathTicks <= 0) {
this.repathTicks = 6 + this.mount.getRandom().nextInt(6);
this.mount.getNavigation().moveTo(current, 1.2D);
}
}
}
@@ -0,0 +1,175 @@
package com.craisinlord.antarchy.content.entity.royal;
import java.util.EnumSet;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.phys.Vec3;
public class RoyalMountCompanionGoal extends Goal {
private static final double MAX_OWNER_DISTANCE = 40.0D;
private final RoyalMountEntity mount;
private LivingEntity owner;
private int side = 1;
private float orbitAngle;
private int repathTicks;
private int settledTicks;
private int cooldown;
private Vec3 spot;
public RoyalMountCompanionGoal(RoyalMountEntity mount) {
this.mount = mount;
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
}
private boolean isEligible(LivingEntity candidate) {
return candidate != null && candidate.isAlive() && !candidate.isSpectator()
&& candidate.level() == this.mount.level()
&& this.mount.isTame() && !this.mount.isVehicle() && !this.mount.isOrderedToSit()
&& !this.mount.isLeashed() && this.mount.getTarget() == null && !this.mount.isActing()
&& this.mount.distanceToSqr(candidate) < MAX_OWNER_DISTANCE * MAX_OWNER_DISTANCE;
}
private double settleDistance() {
return 4.0D + this.mount.getBbWidth() * 0.6D;
}
private boolean needsToReposition(LivingEntity candidate) {
if (this.mount.canFly() && RoyalMountEntity.isAirborne(candidate)) {
return true;
}
if (this.mount.isFlying()) {
return true;
}
double settle = this.settleDistance() + 2.0D;
return this.mount.distanceToSqr(candidate) > settle * settle;
}
@Override
public boolean canUse() {
if (this.cooldown > 0) {
this.cooldown--;
return false;
}
LivingEntity candidate = this.mount.getOwner();
if (!this.isEligible(candidate) || !this.needsToReposition(candidate)) {
return false;
}
this.owner = candidate;
return true;
}
@Override
public boolean canContinueToUse() {
return this.isEligible(this.owner) && this.owner == this.mount.getOwner() && this.settledTicks < 40;
}
@Override
public void start() {
this.side = this.mount.getRandom().nextBoolean() ? 1 : -1;
this.repathTicks = 0;
this.settledTicks = 0;
this.spot = null;
Vec3 offset = this.mount.position().subtract(this.owner.position());
this.orbitAngle = (float) Mth.atan2(offset.z, offset.x);
}
@Override
public void stop() {
this.owner = null;
this.spot = null;
this.cooldown = 20;
this.mount.getNavigation().stop();
}
@Override
public boolean requiresUpdateEveryTick() {
return true;
}
@Override
public void tick() {
float scale = this.mount.getGrowthScale();
if (this.mount.canFly() && RoyalMountEntity.isAirborne(this.owner)) {
this.settledTicks = 0;
this.spot = null;
this.mount.claimFlight();
this.circleOwner(scale);
return;
}
if (--this.repathTicks <= 0 || this.spot == null) {
this.repathTicks = 20;
this.spot = this.pickSpotBesideOwner();
}
if (this.mount.isFlying()) {
this.settledTicks = 0;
this.mount.getLookControl().setLookAt(this.owner, 10.0F, this.mount.getMaxHeadXRot());
if (this.mount.onGround() || this.mount.isInWater()) {
this.mount.setFlying(false);
return;
}
this.mount.claimFlight();
Vec3 target = this.spot != null ? this.spot : this.owner.position();
double horizontal = Math.sqrt(Mth.square(target.x - this.mount.getX()) + Mth.square(target.z - this.mount.getZ()));
double y = horizontal > 3.0D + scale ? Math.max(target.y + 1.5D * scale, this.mount.getY() - 2.0D) : target.y - 0.5D;
this.mount.getMoveControl().setWantedPosition(target.x, y, target.z, 1.0D);
return;
}
double settle = this.settleDistance();
boolean nearOwner = this.mount.distanceToSqr(this.owner) <= settle * settle;
boolean nearSpot = this.spot != null && this.mount.position().distanceToSqr(this.spot) <= Mth.square(1.5D + 0.5D * scale);
if (nearOwner || nearSpot) {
this.mount.getNavigation().stop();
if (this.settledTicks == 0) {
this.mount.turnTowards(this.mount.position().add(this.owner.getLookAngle().multiply(1.0D, 0.0D, 1.0D)), 30.0F);
if (this.mount.getRandom().nextInt(4) == 0) {
this.mount.triggerQuirk();
}
}
this.mount.getLookControl().setLookAt(this.owner, 10.0F, this.mount.getMaxHeadXRot());
this.settledTicks++;
return;
}
this.settledTicks = 0;
this.mount.getLookControl().setLookAt(this.owner, 10.0F, this.mount.getMaxHeadXRot());
if (this.repathTicks == 20) {
Vec3 destination = this.spot != null ? this.spot : this.owner.position();
if (!this.mount.getNavigation().moveTo(destination.x, destination.y, destination.z, 1.0D)) {
this.mount.getNavigation().moveTo(this.owner, 1.0D);
}
}
}
private void circleOwner(float scale) {
double radius = 5.0D + this.mount.getBbWidth() * 0.75D;
this.orbitAngle += this.side * (float) Math.min(0.07D, 1.0D / radius);
double x = this.owner.getX() + Math.cos(this.orbitAngle) * radius;
double z = this.owner.getZ() + Math.sin(this.orbitAngle) * radius;
double y = this.owner.getY() + 2.0D + 0.6D * scale;
if (!this.mount.canOccupy(x, y, z)) {
y += 2.0D + scale;
}
this.mount.getMoveControl().setWantedPosition(x, y, z, 1.2D);
this.mount.getLookControl().setLookAt(this.owner, 10.0F, this.mount.getMaxHeadXRot());
}
private Vec3 pickSpotBesideOwner() {
Vec3 facing = Vec3.directionFromRotation(0.0F, this.owner.getYRot());
Vec3 right = new Vec3(-facing.z, 0.0D, facing.x);
double distance = this.mount.getBbWidth() * 0.5D + 1.5D;
for (int attempt = 0; attempt < 2; attempt++) {
int currentSide = attempt == 0 ? this.side : -this.side;
Vec3 base = this.owner.position().add(right.scale(currentSide * distance));
double ground = this.mount.findGroundY(base.x, this.owner.getY() + 3.0D, base.z, 10);
if (!Double.isNaN(ground) && this.mount.canOccupy(base.x, ground, base.z)) {
this.side = currentSide;
return new Vec3(base.x, ground, base.z);
}
}
return null;
}
}
@@ -1,81 +1,76 @@
package com.craisinlord.antarchy.content.entity.royal; package com.craisinlord.antarchy.content.entity.royal;
import net.minecraft.core.BlockPos; import java.util.EnumSet;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal; import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public class RoyalMountFollowOwnerGoal extends Goal { public class RoyalMountFollowOwnerGoal extends Goal {
private static final double START_DISTANCE = 12.0D;
private static final double STOP_DISTANCE = 6.0D;
private static final double TELEPORT_DISTANCE = 48.0D;
private final RoyalMountEntity mount; private final RoyalMountEntity mount;
private LivingEntity owner; private LivingEntity owner;
private int recalcTimer; private int recalcTimer;
private int stuckTicks;
private int teleportCooldown;
private Vec3 lastCheckPosition = Vec3.ZERO;
public RoyalMountFollowOwnerGoal(RoyalMountEntity mount) { public RoyalMountFollowOwnerGoal(RoyalMountEntity mount) {
this.mount = mount; this.mount = mount;
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
}
private double startDistance() {
return 14.0D + 2.0D * this.mount.getGrowthScale();
}
private double stopDistance() {
return 6.0D + 1.5D * this.mount.getGrowthScale();
}
private double teleportDistance() {
return 48.0D + 4.0D * this.mount.getGrowthScale();
}
private boolean canFollow(LivingEntity candidate) {
return candidate != null && candidate.isAlive() && !candidate.isSpectator()
&& candidate.level() == this.mount.level()
&& this.mount.isTame() && !this.mount.isVehicle() && !this.mount.isOrderedToSit()
&& !this.mount.isLeashed() && this.mount.getTarget() == null;
} }
@Override @Override
public boolean canUse() { public boolean canUse() {
if (!this.mount.isTame() || this.mount.isVehicle() || this.mount.isOrderedToSit()) { LivingEntity candidate = this.mount.getOwner();
if (!this.canFollow(candidate)) {
return false; return false;
} }
LivingEntity potentialOwner = this.mount.getOwner(); double start = this.startDistance();
if (potentialOwner == null || potentialOwner.isSpectator()) { if (this.mount.distanceToSqr(candidate) < start * start) {
return false; return false;
} }
if (this.mount.distanceToSqr(potentialOwner) < START_DISTANCE * START_DISTANCE) { this.owner = candidate;
return false;
}
this.owner = potentialOwner;
return true; return true;
} }
@Override @Override
public boolean canContinueToUse() { public boolean canContinueToUse() {
return !this.mount.getNavigation().isDone() if (!this.canFollow(this.owner) || this.owner != this.mount.getOwner()) {
&& this.mount.distanceToSqr(this.owner) > STOP_DISTANCE * STOP_DISTANCE return false;
&& !this.mount.isOrderedToSit(); }
double stop = this.stopDistance();
return this.mount.distanceToSqr(this.owner) > stop * stop;
} }
@Override @Override
public void start() { public void start() {
this.recalcTimer = 0; this.recalcTimer = 0;
this.stuckTicks = 0;
this.lastCheckPosition = this.mount.position();
} }
@Override @Override
public void stop() { public void stop() {
this.owner = null; this.owner = null;
this.mount.getNavigation().stop(); this.mount.getNavigation().stop();
this.mount.setFlying(false);
}
@Override
public void tick() {
this.mount.getLookControl().setLookAt(this.owner, 10.0F, this.mount.getMaxHeadXRot());
double distanceSqr = this.mount.distanceToSqr(this.owner);
if (distanceSqr > TELEPORT_DISTANCE * TELEPORT_DISTANCE) {
this.trySafeTeleport();
return;
}
boolean ownerAirborne = !this.owner.onGround() || (this.owner.getY() - this.mount.getY()) > 3.0D;
this.mount.setFlying(ownerAirborne || distanceSqr > 24.0D * 24.0D);
if (--this.recalcTimer <= 0) {
this.recalcTimer = 10;
if (this.mount.isFlying()) {
Vec3 to = this.owner.position().subtract(this.mount.position());
Vec3 step = this.mount.position().add(to.normalize().scale(Math.min(to.length(), 8.0D)));
this.mount.getMoveControl().setWantedPosition(step.x, step.y + 1.0D, step.z, 1.2D);
} else {
this.mount.getNavigation().moveTo(this.owner, 1.1D);
}
}
} }
@Override @Override
@@ -83,28 +78,57 @@ public class RoyalMountFollowOwnerGoal extends Goal {
return true; return true;
} }
private void trySafeTeleport() { @Override
Vec3 ownerPosition = this.owner.position(); public void tick() {
BlockPos ownerBlock = this.owner.blockPosition(); this.mount.getLookControl().setLookAt(this.owner, 10.0F, this.mount.getMaxHeadXRot());
for (int radius = 0; radius <= 2; radius++) { if (this.teleportCooldown > 0) {
for (int dx = -radius; dx <= radius; dx++) { this.teleportCooldown--;
for (int dz = -radius; dz <= radius; dz++) {
for (int dy = -1; dy <= 2; dy++) {
double x = ownerPosition.x + dx + 0.5D;
double y = ownerBlock.getY() + dy;
double z = ownerPosition.z + dz + 0.5D;
BlockPos floor = BlockPos.containing(x, y - 0.1D, z);
var destination = this.mount.getBoundingBox().move(x - this.mount.getX(), y - this.mount.getY(), z - this.mount.getZ());
if (!this.mount.level().noCollision(this.mount, destination)) {
continue;
} }
if (this.mount.isFlying() || !this.mount.level().getBlockState(floor).getCollisionShape(this.mount.level(), floor).isEmpty()) { this.trackStuck();
this.mount.teleportTo(x, y, z);
double distance = this.mount.distanceTo(this.owner);
if ((distance > this.teleportDistance() || this.stuckTicks >= 100 && distance > 24.0D) && this.teleportCooldown <= 0) {
this.teleportCooldown = 20;
if (this.mount.tryTeleportNear(this.owner)) {
this.stuckTicks = 0;
return; return;
} }
} }
boolean ownerAirborne = RoyalMountEntity.isAirborne(this.owner);
boolean wantsFlight = this.mount.canFly() && (ownerAirborne || distance > 24.0D + this.mount.getBbWidth()
|| this.stuckTicks >= 40 || this.owner.getY() - this.mount.getY() > 4.0D);
if (wantsFlight && this.mount.claimFlight()) {
if (--this.recalcTimer <= 0) {
this.recalcTimer = 5;
float scale = this.mount.getGrowthScale();
Vec3 destination = this.owner.position().add(0.0D, 2.0D + 0.6D * scale, 0.0D);
Vec3 to = destination.subtract(this.mount.position());
double stepLength = Math.min(to.length(), 12.0D + 2.0D * scale);
Vec3 step = to.lengthSqr() > 1.0E-4D ? this.mount.position().add(to.normalize().scale(stepLength)) : destination;
this.mount.getMoveControl().setWantedPosition(step.x, step.y, step.z, 1.3D);
}
return;
}
if (this.mount.isFlying()) {
return;
}
if (--this.recalcTimer <= 0) {
this.recalcTimer = 10;
this.mount.getNavigation().moveTo(this.owner, 1.2D);
} }
} }
}
private void trackStuck() {
if (this.mount.tickCount % 20 != 0) {
return;
}
Vec3 position = this.mount.position();
if (position.distanceToSqr(this.lastCheckPosition) < 1.0D) {
this.stuckTicks += 20;
} else {
this.stuckTicks = 0;
}
this.lastCheckPosition = position;
} }
} }
@@ -1,49 +0,0 @@
package com.craisinlord.antarchy.content.entity.royal;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;
public class RoyalMountSpitGoal extends Goal {
private final RoyalMountEntity mount;
private int cooldown;
public RoyalMountSpitGoal(RoyalMountEntity mount) {
this.mount = mount;
}
@Override
public boolean canUse() {
if (this.mount.isVehicle() || this.mount.isOrderedToSit()) {
return false;
}
LivingEntity target = this.mount.getTarget();
if (target == null || !target.isAlive() || !this.mount.canAttack(target)) {
return false;
}
double distance = this.mount.distanceTo(target);
return distance > 5.0D && distance < 20.0D && this.mount.hasLineOfSight(target);
}
@Override
public void start() {
this.cooldown = 20;
}
@Override
public void tick() {
LivingEntity target = this.mount.getTarget();
if (target == null || !this.mount.canAttack(target)) {
return;
}
this.mount.getLookControl().setLookAt(target, 30.0F, 30.0F);
if (this.cooldown-- <= 0) {
this.mount.startSpitVolley(target);
this.cooldown = 60;
}
}
@Override
public boolean requiresUpdateEveryTick() {
return true;
}
}
@@ -29,6 +29,14 @@ public class AttitudeAdjusterItem extends SwordItem {
this.tier = tier; this.tier = tier;
} }
@Override
public com.google.common.collect.Multimap<net.minecraft.world.entity.ai.attributes.Attribute, net.minecraft.world.entity.ai.attributes.AttributeModifier> getDefaultAttributeModifiers(net.minecraft.world.entity.EquipmentSlot slot) {
if (slot != net.minecraft.world.entity.EquipmentSlot.MAINHAND) {
return super.getDefaultAttributeModifiers(slot);
}
return com.craisinlord.antarchy.compat.item.WeaponAttributes.base(this.tier, (float) Math.round(AntarchySettings.attitudeAdjusterBaseDamage()), ATTACK_SPEED).build();
}
@Override @Override
public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) { public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
tooltipComponents.add(Component.translatable("tooltip.antarchy.attitude_adjuster.grounded").withStyle(ChatFormatting.DARK_GRAY)); tooltipComponents.add(Component.translatable("tooltip.antarchy.attitude_adjuster.grounded").withStyle(ChatFormatting.DARK_GRAY));
@@ -21,6 +21,14 @@ public class BasiliskDaggerItem extends SwordItem {
this.attackSpeed = attackSpeed; this.attackSpeed = attackSpeed;
} }
@Override
public com.google.common.collect.Multimap<net.minecraft.world.entity.ai.attributes.Attribute, net.minecraft.world.entity.ai.attributes.AttributeModifier> getDefaultAttributeModifiers(net.minecraft.world.entity.EquipmentSlot slot) {
if (slot != net.minecraft.world.entity.EquipmentSlot.MAINHAND) {
return super.getDefaultAttributeModifiers(slot);
}
return com.craisinlord.antarchy.compat.item.WeaponAttributes.base(this.tier, (float) Math.round(AntarchySettings.basiliskDaggerAttackDamage()), (float) AntarchySettings.basiliskDaggerAttackSpeed()).build();
}
@Override @Override
public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) {
boolean didHurt = super.hurtEnemy(stack, target, attacker); boolean didHurt = super.hurtEnemy(stack, target, attacker);
@@ -2,13 +2,23 @@ package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.client.model.ResourceBackedGeoItemModel; import com.craisinlord.antarchy.content.client.model.ResourceBackedGeoItemModel;
import com.craisinlord.antarchy.content.item.ultimate.UltimateToolHelper;
import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.DoubleSupplier; import java.util.function.DoubleSupplier;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.AxeItem; import net.minecraft.world.item.AxeItem;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Tier; import net.minecraft.world.item.Tier;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import software.bernie.geckolib.animatable.GeoItem; import software.bernie.geckolib.animatable.GeoItem;
import com.craisinlord.antarchy.content.client.AntarchyGeoItemRenderer; import com.craisinlord.antarchy.content.client.AntarchyGeoItemRenderer;
import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache;
@@ -34,6 +44,33 @@ public class BattleAxeItem extends AxeItem implements GeoItem, com.craisinlord.a
GeoItem.registerSyncedAnimatable(this); GeoItem.registerSyncedAnimatable(this);
} }
@Override
public com.google.common.collect.Multimap<net.minecraft.world.entity.ai.attributes.Attribute, net.minecraft.world.entity.ai.attributes.AttributeModifier> getDefaultAttributeModifiers(net.minecraft.world.entity.EquipmentSlot slot) {
if (slot != net.minecraft.world.entity.EquipmentSlot.MAINHAND) {
return super.getDefaultAttributeModifiers(slot);
}
return com.craisinlord.antarchy.compat.item.WeaponAttributes.base(this.tier, (float) this.attackDamage.getAsDouble(), (float) AntarchySettings.battleAxeAttackSpeed()).build();
}
@Override
public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
super.appendHoverText(stack, level, tooltipComponents, tooltipFlag);
if (AntarchySettings.ultimateToolsVeinMiningEnabled()) {
tooltipComponents.add(Component.translatable("tooltip.antarchy.battle_axe_tree_felling").withStyle(ChatFormatting.GRAY));
}
}
@Override
public boolean mineBlock(ItemStack stack, Level level, BlockState state, BlockPos pos, LivingEntity miningEntity) {
boolean result = super.mineBlock(stack, level, state, pos, miningEntity);
if (AntarchySettings.ultimateToolsVeinMiningEnabled()
&& miningEntity instanceof ServerPlayer player
&& !player.isShiftKeyDown()) {
UltimateToolHelper.mineTree(stack, level, state, pos, player, AntarchySettings.ultimateToolsTreeFellingMaxLogs());
}
return result;
}
@Override @Override
public boolean isEnchantable(ItemStack stack) { public boolean isEnchantable(ItemStack stack) {
return stack.getCount() == 1; return stack.getCount() == 1;
@@ -31,10 +31,18 @@ public class UltimateAxeItem extends AxeItem {
this.attackSpeed = attackSpeed; this.attackSpeed = attackSpeed;
} }
@Override
public com.google.common.collect.Multimap<net.minecraft.world.entity.ai.attributes.Attribute, net.minecraft.world.entity.ai.attributes.AttributeModifier> getDefaultAttributeModifiers(net.minecraft.world.entity.EquipmentSlot slot) {
if (slot != net.minecraft.world.entity.EquipmentSlot.MAINHAND) {
return super.getDefaultAttributeModifiers(slot);
}
return com.craisinlord.antarchy.compat.item.WeaponAttributes.base(this.tier, (float) this.attackDamage.getAsDouble(), (float) AntarchySettings.ultimateAxeAttackSpeed()).build();
}
@Override @Override
public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) { public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
super.appendHoverText(stack, level, tooltipComponents, tooltipFlag); super.appendHoverText(stack, level, tooltipComponents, tooltipFlag);
UltimateToolHelper.appendThreeByThreeTooltip(tooltipComponents); UltimateToolHelper.appendModeTooltip(UltimateToolHelper.ToolKind.AXE, tooltipComponents);
} }
@Override @Override
@@ -31,10 +31,18 @@ public class UltimateHoeItem extends HoeItem {
this.attackSpeed = attackSpeed; this.attackSpeed = attackSpeed;
} }
@Override
public com.google.common.collect.Multimap<net.minecraft.world.entity.ai.attributes.Attribute, net.minecraft.world.entity.ai.attributes.AttributeModifier> getDefaultAttributeModifiers(net.minecraft.world.entity.EquipmentSlot slot) {
if (slot != net.minecraft.world.entity.EquipmentSlot.MAINHAND) {
return super.getDefaultAttributeModifiers(slot);
}
return com.craisinlord.antarchy.compat.item.WeaponAttributes.base(this.tier, (float) Math.round(this.attackDamage.getAsDouble()), (float) AntarchySettings.ultimateHoeAttackSpeed()).build();
}
@Override @Override
public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) { public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
super.appendHoverText(stack, level, tooltipComponents, tooltipFlag); super.appendHoverText(stack, level, tooltipComponents, tooltipFlag);
UltimateToolHelper.appendThreeByThreeTooltip(tooltipComponents); UltimateToolHelper.appendModeTooltip(UltimateToolHelper.ToolKind.HOE, tooltipComponents);
} }
@Override @Override
@@ -31,10 +31,18 @@ public class UltimatePickaxeItem extends PickaxeItem {
this.attackSpeed = attackSpeed; this.attackSpeed = attackSpeed;
} }
@Override
public com.google.common.collect.Multimap<net.minecraft.world.entity.ai.attributes.Attribute, net.minecraft.world.entity.ai.attributes.AttributeModifier> getDefaultAttributeModifiers(net.minecraft.world.entity.EquipmentSlot slot) {
if (slot != net.minecraft.world.entity.EquipmentSlot.MAINHAND) {
return super.getDefaultAttributeModifiers(slot);
}
return com.craisinlord.antarchy.compat.item.WeaponAttributes.base(this.tier, (float) Math.round(this.attackDamage.getAsDouble()), (float) AntarchySettings.ultimatePickaxeAttackSpeed()).build();
}
@Override @Override
public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) { public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
super.appendHoverText(stack, level, tooltipComponents, tooltipFlag); super.appendHoverText(stack, level, tooltipComponents, tooltipFlag);
UltimateToolHelper.appendThreeByThreeTooltip(tooltipComponents); UltimateToolHelper.appendModeTooltip(UltimateToolHelper.ToolKind.PICKAXE, tooltipComponents);
} }
@Override @Override
@@ -19,6 +19,14 @@ public class UltimateSwordItem extends SwordItem {
this.attackSpeed = attackSpeed; this.attackSpeed = attackSpeed;
} }
@Override
public com.google.common.collect.Multimap<net.minecraft.world.entity.ai.attributes.Attribute, net.minecraft.world.entity.ai.attributes.AttributeModifier> getDefaultAttributeModifiers(net.minecraft.world.entity.EquipmentSlot slot) {
if (slot != net.minecraft.world.entity.EquipmentSlot.MAINHAND) {
return super.getDefaultAttributeModifiers(slot);
}
return com.craisinlord.antarchy.compat.item.WeaponAttributes.base(this.tier, (float) Math.round(this.attackDamage.getAsDouble()), (float) AntarchySettings.ultimateSwordAttackSpeed()).build();
}
@Override @Override
public boolean isEnchantable(ItemStack stack) { public boolean isEnchantable(ItemStack stack) {
return stack.getCount() == 1; return stack.getCount() == 1;
@@ -3,12 +3,16 @@ package com.craisinlord.antarchy.content.item.ultimate;
import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.item.GiantFryingPanItem; import com.craisinlord.antarchy.content.item.GiantFryingPanItem;
import com.craisinlord.antarchy.content.item.GiantFryingPanToolHelper; import com.craisinlord.antarchy.content.item.GiantFryingPanToolHelper;
import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
@@ -23,12 +27,16 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Tier; import net.minecraft.world.item.Tier;
import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public final class UltimateToolHelper { public final class UltimateToolHelper {
private static final String THREE_BY_THREE_TAG = "antarchy.ultimate_three_by_three"; private static final String THREE_BY_THREE_TAG = "antarchy.ultimate_three_by_three";
private static final String MINING_MODE_TAG = "antarchy.ultimate_mining_mode";
private static final ThreadLocal<Boolean> BREAKING_EXTRA_BLOCKS = ThreadLocal.withInitial(() -> false); private static final ThreadLocal<Boolean> BREAKING_EXTRA_BLOCKS = ThreadLocal.withInitial(() -> false);
private static final float GENERAL_MINING_MULTIPLIER = 1.1F; private static final float GENERAL_MINING_MULTIPLIER = 1.1F;
private static final float ULTIMATE_SHOVEL_MINING_SPEED = 24.0F; private static final float ULTIMATE_SHOVEL_MINING_SPEED = 24.0F;
@@ -38,26 +46,43 @@ public final class UltimateToolHelper {
public static InteractionResultHolder<ItemStack> handleToggleUse(Level level, Player player, InteractionHand hand) { public static InteractionResultHolder<ItemStack> handleToggleUse(Level level, Player player, InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand); ItemStack stack = player.getItemInHand(hand);
if (!AntarchySettings.ultimateToolsThreeByThreeEnabled() || !player.isShiftKeyDown()) { if (!player.isShiftKeyDown() || availableModes(toolKindOf(stack.getItem())).size() < 2) {
return InteractionResultHolder.pass(stack); return InteractionResultHolder.pass(stack);
} }
toggleThreeByThree(level, player, stack); cycleMiningMode(level, player, stack);
return InteractionResultHolder.sidedSuccess(stack, level.isClientSide); return InteractionResultHolder.sidedSuccess(stack, level.isClientSide);
} }
public static InteractionResult handleToggleUseOn(UseOnContext context) { public static InteractionResult handleToggleUseOn(UseOnContext context) {
Player player = context.getPlayer(); Player player = context.getPlayer();
if (!AntarchySettings.ultimateToolsThreeByThreeEnabled() || player == null || !player.isShiftKeyDown()) { if (player == null || !player.isShiftKeyDown() || availableModes(toolKindOf(context.getItemInHand().getItem())).size() < 2) {
return InteractionResult.PASS; return InteractionResult.PASS;
} }
toggleThreeByThree(context.getLevel(), player, context.getItemInHand()); cycleMiningMode(context.getLevel(), player, context.getItemInHand());
return InteractionResult.sidedSuccess(context.getLevel().isClientSide); return InteractionResult.sidedSuccess(context.getLevel().isClientSide);
} }
public static boolean isThreeByThreeEnabled(ItemStack stack) { public static boolean isThreeByThreeEnabled(ItemStack stack) {
return stack.hasTag() && stack.getTag().getBoolean(THREE_BY_THREE_TAG); return getMiningMode(stack) == MiningMode.THREE_BY_THREE;
}
public static boolean isVeinEnabled(ItemStack stack) {
return getMiningMode(stack) == MiningMode.VEIN;
}
public static MiningMode getMiningMode(ItemStack stack) {
CompoundTag tag = stack.getTag();
if (tag == null) {
return MiningMode.DEFAULT;
}
if (tag.contains(MINING_MODE_TAG)) {
int index = tag.getByte(MINING_MODE_TAG);
MiningMode[] modes = MiningMode.values();
return index >= 0 && index < modes.length ? modes[index] : MiningMode.DEFAULT;
}
return tag.getBoolean(THREE_BY_THREE_TAG) ? MiningMode.THREE_BY_THREE : MiningMode.DEFAULT;
} }
public static float getDestroySpeed(ToolKind toolKind, Tier tier, ItemStack stack, BlockState state, float defaultSpeed) { public static float getDestroySpeed(ToolKind toolKind, Tier tier, ItemStack stack, BlockState state, float defaultSpeed) {
@@ -74,23 +99,127 @@ public final class UltimateToolHelper {
return defaultSpeed * GENERAL_MINING_MULTIPLIER; return defaultSpeed * GENERAL_MINING_MULTIPLIER;
} }
public static void appendThreeByThreeTooltip(List<Component> tooltip) { public static void appendModeTooltip(ToolKind toolKind, List<Component> tooltip) {
if (!AntarchySettings.ultimateToolsThreeByThreeEnabled()) { List<MiningMode> modes = availableModes(toolKind);
boolean area = modes.contains(MiningMode.THREE_BY_THREE);
boolean vein = modes.contains(MiningMode.VEIN);
String key;
if (area && vein) {
key = "tooltip.antarchy.ultimate_tools_3x3_vein";
} else if (area) {
key = "tooltip.antarchy.ultimate_tools_3x3";
} else if (vein) {
key = "tooltip.antarchy.ultimate_tools_vein";
} else {
return; return;
} }
tooltip.add(Component.translatable("tooltip.antarchy.ultimate_tools_3x3").withStyle(ChatFormatting.GRAY)); tooltip.add(Component.translatable(key).withStyle(ChatFormatting.GRAY));
} }
public static void handleAreaMining(ToolKind toolKind, ItemStack stack, Level level, BlockState originState, BlockPos origin, LivingEntity entity) { public static void handleAreaMining(ToolKind toolKind, ItemStack stack, Level level, BlockState originState, BlockPos origin, LivingEntity entity) {
if (!AntarchySettings.ultimateToolsThreeByThreeEnabled() if (level.isClientSide
|| level.isClientSide
|| BREAKING_EXTRA_BLOCKS.get() || BREAKING_EXTRA_BLOCKS.get()
|| !isThreeByThreeEnabled(stack)
|| !(entity instanceof ServerPlayer player)) { || !(entity instanceof ServerPlayer player)) {
return; return;
} }
MiningMode mode = getMiningMode(stack);
if (mode == MiningMode.DEFAULT || !availableModes(toolKind).contains(mode)) {
return;
}
if (mode == MiningMode.THREE_BY_THREE) {
mineArea(toolKind, stack, level, originState, origin, player, 1); mineArea(toolKind, stack, level, originState, origin, player, 1);
} else {
mineVein(toolKind, stack, level, originState, origin, player, veinLimit(originState));
}
}
public static int veinLimit(BlockState state) {
return state.is(BlockTags.LOGS)
? AntarchySettings.ultimateToolsTreeFellingMaxLogs()
: AntarchySettings.ultimateToolsVeinMiningMaxBlocks();
}
public static void mineVein(ToolKind toolKind, ItemStack stack, Level level, BlockState originState, BlockPos origin, ServerPlayer player, int maxBlocks) {
if (level.isClientSide || BREAKING_EXTRA_BLOCKS.get() || maxBlocks <= 0 || !matchesToolKind(toolKind, originState)) {
return;
}
breakAll(toolKind, stack, level, player, collectConnected(level, origin, originState.getBlock(), maxBlocks, false));
}
public static void mineTree(ItemStack stack, Level level, BlockState originState, BlockPos origin, ServerPlayer player, int maxBlocks) {
if (level.isClientSide || BREAKING_EXTRA_BLOCKS.get() || maxBlocks <= 0 || !originState.is(BlockTags.LOGS)) {
return;
}
breakAll(ToolKind.AXE, stack, level, player, collectConnected(level, origin, originState.getBlock(), maxBlocks, true));
}
private static void breakAll(ToolKind toolKind, ItemStack stack, Level level, ServerPlayer player, List<BlockPos> targets) {
if (targets.isEmpty()) {
return;
}
BREAKING_EXTRA_BLOCKS.set(true);
try {
for (BlockPos targetPos : targets) {
if (!canBreak(toolKind, player, stack, level, targetPos, level.getBlockState(targetPos))) {
continue;
}
player.gameMode.destroyBlock(targetPos);
if (stack.isEmpty()) {
break;
}
}
} finally {
BREAKING_EXTRA_BLOCKS.set(false);
}
}
private static List<BlockPos> collectConnected(Level level, BlockPos origin, Block block, int maxBlocks, boolean requireFoliage) {
List<BlockPos> found = new ArrayList<>();
Set<BlockPos> visited = new HashSet<>();
ArrayDeque<BlockPos> queue = new ArrayDeque<>();
visited.add(origin);
queue.add(origin);
boolean foliage = false;
while (!queue.isEmpty() && found.size() < maxBlocks) {
BlockPos current = queue.poll();
for (int dx = -1; dx <= 1 && found.size() < maxBlocks; dx++) {
for (int dy = -1; dy <= 1 && found.size() < maxBlocks; dy++) {
for (int dz = -1; dz <= 1 && found.size() < maxBlocks; dz++) {
if (dx == 0 && dy == 0 && dz == 0) {
continue;
}
BlockPos next = current.offset(dx, dy, dz);
if (!visited.add(next) || !level.isLoaded(next)) {
continue;
}
BlockState state = level.getBlockState(next);
if (state.is(block)) {
found.add(next);
queue.add(next);
} else if (requireFoliage && !foliage && isNaturalFoliage(state)) {
foliage = true;
}
}
}
}
}
return requireFoliage && !foliage ? List.of() : found;
}
private static boolean isNaturalFoliage(BlockState state) {
if (state.is(BlockTags.LEAVES)) {
return !state.hasProperty(BlockStateProperties.PERSISTENT) || !state.getValue(BlockStateProperties.PERSISTENT);
}
return state.is(BlockTags.WART_BLOCKS) || state.is(Blocks.SHROOMLIGHT);
} }
public static void mineArea(ToolKind toolKind, ItemStack stack, Level level, BlockState originState, BlockPos origin, ServerPlayer player, int radius) { public static void mineArea(ToolKind toolKind, ItemStack stack, Level level, BlockState originState, BlockPos origin, ServerPlayer player, int radius) {
@@ -211,23 +340,50 @@ public final class UltimateToolHelper {
HOE HOE
} }
private static void toggleThreeByThree(Level level, Player player, ItemStack stack) { public enum MiningMode {
boolean enabled = !isThreeByThreeEnabled(stack); DEFAULT,
if (enabled) { THREE_BY_THREE,
stack.getOrCreateTag().putBoolean(THREE_BY_THREE_TAG, true); VEIN
} else if (stack.hasTag()) { }
stack.getTag().remove(THREE_BY_THREE_TAG);
private static List<MiningMode> availableModes(ToolKind toolKind) {
List<MiningMode> modes = new ArrayList<>(3);
if (toolKind == null) {
return modes;
}
modes.add(MiningMode.DEFAULT);
if (AntarchySettings.ultimateToolsThreeByThreeEnabled()) {
modes.add(MiningMode.THREE_BY_THREE);
}
if (AntarchySettings.ultimateToolsVeinMiningEnabled() && (toolKind == ToolKind.PICKAXE || toolKind == ToolKind.AXE)) {
modes.add(MiningMode.VEIN);
}
return modes;
}
private static void cycleMiningMode(Level level, Player player, ItemStack stack) {
List<MiningMode> modes = availableModes(toolKindOf(stack.getItem()));
int current = modes.indexOf(getMiningMode(stack));
MiningMode next = modes.get((current + 1) % modes.size());
if (next == MiningMode.DEFAULT) {
CompoundTag tag = stack.getTag();
if (tag != null) {
tag.remove(THREE_BY_THREE_TAG);
tag.remove(MINING_MODE_TAG);
}
} else {
CompoundTag tag = stack.getOrCreateTag();
tag.remove(THREE_BY_THREE_TAG);
tag.putByte(MINING_MODE_TAG, (byte) next.ordinal());
} }
if (!level.isClientSide) { if (!level.isClientSide) {
player.displayClientMessage( String key = switch (next) {
Component.translatable( case DEFAULT -> "message.antarchy.ultimate_tool.mode_default";
enabled case THREE_BY_THREE -> "message.antarchy.ultimate_tool.mode_3x3";
? "message.antarchy.ultimate_tool.mode_3x3" case VEIN -> "message.antarchy.ultimate_tool.mode_vein";
: "message.antarchy.ultimate_tool.mode_default" };
), player.displayClientMessage(Component.translatable(key), true);
true
);
} }
} }
@@ -34,10 +34,18 @@ public class UtlimateShovelItem extends ShovelItem {
this.attackSpeed = attackSpeed; this.attackSpeed = attackSpeed;
} }
@Override
public com.google.common.collect.Multimap<net.minecraft.world.entity.ai.attributes.Attribute, net.minecraft.world.entity.ai.attributes.AttributeModifier> getDefaultAttributeModifiers(net.minecraft.world.entity.EquipmentSlot slot) {
if (slot != net.minecraft.world.entity.EquipmentSlot.MAINHAND) {
return super.getDefaultAttributeModifiers(slot);
}
return com.craisinlord.antarchy.compat.item.WeaponAttributes.base(this.tier, (float) this.attackDamage.getAsDouble(), (float) AntarchySettings.ultimateShovelAttackSpeed()).build();
}
@Override @Override
public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) { public void appendHoverText(ItemStack stack, Level level, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
super.appendHoverText(stack, level, tooltipComponents, tooltipFlag); super.appendHoverText(stack, level, tooltipComponents, tooltipFlag);
UltimateToolHelper.appendThreeByThreeTooltip(tooltipComponents); UltimateToolHelper.appendModeTooltip(UltimateToolHelper.ToolKind.SHOVEL, tooltipComponents);
} }
@Override @Override
@@ -12,6 +12,8 @@ public record RoyalMountActionPayload(int action) implements CustomPacketPayload
public static final int BITE = 1; public static final int BITE = 1;
public static final int SPIT = 2; public static final int SPIT = 2;
public static final int MOUNT = 3; public static final int MOUNT = 3;
public static final int BEAM = 4;
public static final int SIGNATURE = 5;
public static final Type<RoyalMountActionPayload> TYPE = public static final Type<RoyalMountActionPayload> TYPE =
new Type<>(new ResourceLocation(Antarchy.MODID, "royal_mount_action")); new Type<>(new ResourceLocation(Antarchy.MODID, "royal_mount_action"));
@@ -34,7 +34,7 @@ public class TermiteNestFeature extends SurfaceAntNestFeature {
protected BlockPos resolveNestPos(WorldGenLevel level, BlockPos origin) { protected BlockPos resolveNestPos(WorldGenLevel level, BlockPos origin) {
int x = origin.getX(); int x = origin.getX();
int z = origin.getZ(); int z = origin.getZ();
int startY = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, x, z) - 1; int startY = Math.min(origin.getY(), level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, x, z) - 1);
int minY = level.getMinBuildHeight() + 1; int minY = level.getMinBuildHeight() + 1;
for (int y = startY; y >= minY; y--) { for (int y = startY; y >= minY; y--) {
@@ -1,5 +1,6 @@
package com.craisinlord.antarchy.mixins; package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.item.MantisClawItem; import com.craisinlord.antarchy.content.item.MantisClawItem;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
@@ -91,6 +92,7 @@ public abstract class MantisClawWallClimbMixin extends LivingEntity {
Player player = (Player) (Object) this; Player player = (Player) (Object) this;
return MantisClawItem.isDualWielding(player) return MantisClawItem.isDualWielding(player)
&& this.horizontalCollision && this.horizontalCollision
&& !this.level().dimensionTypeRegistration().is(AntarchyTags.DimensionTypes.NO_MANTIS_CLIMB)
&& !this.onGround() && !this.onGround()
&& !this.isInWaterOrBubble() && !this.isInWaterOrBubble()
&& !this.isPassenger() && !this.isPassenger()
@@ -1,6 +1,7 @@
package com.craisinlord.antarchy.mixins.client; package com.craisinlord.antarchy.mixins.client;
import com.craisinlord.antarchy.content.entity.HerculesBeetleEntity; import com.craisinlord.antarchy.content.entity.HerculesBeetleEntity;
import com.craisinlord.antarchy.content.entity.royal.RoyalMountEntity;
import net.minecraft.client.Camera; import net.minecraft.client.Camera;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
@@ -10,6 +11,7 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Camera.class) @Mixin(Camera.class)
@@ -23,6 +25,18 @@ public abstract class MountedVehicleCameraMixin {
@Shadow @Shadow
protected abstract void setPosition(Vec3 position); protected abstract void setPosition(Vec3 position);
@ModifyArg(
method = "setup",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;getMaxZoom(D)D"),
index = 0
)
private double antarchy$extendRoyalMountZoom(double distance) {
if (this.entity != null && this.entity.getVehicle() instanceof RoyalMountEntity mount) {
return distance + mount.thirdPersonCameraBonus();
}
return distance;
}
@Inject(method = "setup", at = @At("RETURN")) @Inject(method = "setup", at = @At("RETURN"))
private void antarchy$adjustMountedCamera( private void antarchy$adjustMountedCamera(
BlockGetter level, BlockGetter level,
@@ -32,6 +46,11 @@ public abstract class MountedVehicleCameraMixin {
float partialTick, float partialTick,
CallbackInfo ci CallbackInfo ci
) { ) {
if (this.detached && this.entity != null && this.entity.getVehicle() instanceof RoyalMountEntity mount) {
Camera camera = (Camera) (Object) this;
this.setPosition(camera.getPosition().add(new Vec3(camera.getUpVector()).scale(mount.thirdPersonCameraLift())));
return;
}
if (!this.antarchy$ridingHerculesBeetle()) { if (!this.antarchy$ridingHerculesBeetle()) {
return; return;
} }
@@ -517,6 +517,7 @@
"message.antarchy.big_bertha.mode.molevore": "Molevore", "message.antarchy.big_bertha.mode.molevore": "Molevore",
"message.antarchy.big_bertha.mode.toreterror": "Toreterror", "message.antarchy.big_bertha.mode.toreterror": "Toreterror",
"message.antarchy.ultimate_tool.mode_3x3": "Auf 3x3-Abbau umgeschaltet", "message.antarchy.ultimate_tool.mode_3x3": "Auf 3x3-Abbau umgeschaltet",
"message.antarchy.ultimate_tool.mode_vein": "Auf Adernabbau umgeschaltet",
"message.antarchy.ultimate_tool.mode_default": "Auf normalen Abbau umgeschaltet", "message.antarchy.ultimate_tool.mode_default": "Auf normalen Abbau umgeschaltet",
"advancements.antarchy.hey_listen.title": "Hey, hör zu!", "advancements.antarchy.hey_listen.title": "Hey, hör zu!",
"advancements.antarchy.hey_listen.description": "Eine Reverie hat sich dir angeschlossen.", "advancements.antarchy.hey_listen.description": "Eine Reverie hat sich dir angeschlossen.",
@@ -549,6 +550,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "Rechtsklick, um dich drehend nach vorn zu bohren und Molevore-Blöcke zu durchdringen.", "tooltip.antarchy.big_bertha.mode.molevore": "Rechtsklick, um dich drehend nach vorn zu bohren und Molevore-Blöcke zu durchdringen.",
"tooltip.antarchy.big_bertha.mode.toreterror": "Rechtsklick, um in die Luft zu springen und mit einer Flächenschockwelle herabzustürzen.", "tooltip.antarchy.big_bertha.mode.toreterror": "Rechtsklick, um in die Luft zu springen und mit einer Flächenschockwelle herabzustürzen.",
"tooltip.antarchy.ultimate_tools_3x3": "Umschalt-Rechtsklick, um 3x3-Abbau umzuschalten.", "tooltip.antarchy.ultimate_tools_3x3": "Umschalt-Rechtsklick, um 3x3-Abbau umzuschalten.",
"tooltip.antarchy.ultimate_tools_vein": "Umschalt-Rechtsklick, um Adernabbau umzuschalten.",
"tooltip.antarchy.ultimate_tools_3x3_vein": "Umschalt-Rechtsklick wechselt zwischen 3x3-Abbau und Adernabbau.",
"tooltip.antarchy.battle_axe_tree_felling": "Fällt ganze Bäume. Schleichen, um einen einzelnen Stamm zu hacken.",
"tooltip.antarchy.moggles.reveal": "Gewährt Nachtsicht und weist auf nahe Höhlen hin.", "tooltip.antarchy.moggles.reveal": "Gewährt Nachtsicht und weist auf nahe Höhlen hin.",
"tooltip.antarchy.moggles.underground": "Funktioniert nur, wenn du keinen freien Blick zum Himmel hast.", "tooltip.antarchy.moggles.underground": "Funktioniert nur, wenn du keinen freien Blick zum Himmel hast.",
"tooltip.antarchy.cornea_ear.vision": "Gewährt %s Sekunden lang Nachtsicht.", "tooltip.antarchy.cornea_ear.vision": "Gewährt %s Sekunden lang Nachtsicht.",
@@ -604,6 +604,16 @@
"message.antarchy.royal_boundary.activated": "Royal Boundary raised", "message.antarchy.royal_boundary.activated": "Royal Boundary raised",
"message.antarchy.royal_boundary.recharging": "Royal Boundary is recharging", "message.antarchy.royal_boundary.recharging": "Royal Boundary is recharging",
"key.antarchy.mount_flight_toggle": "Mount: Toggle Flight", "key.antarchy.mount_flight_toggle": "Mount: Toggle Flight",
"key.antarchy.mount_beam": "Royal Mount: Beam",
"key.antarchy.mount_signature": "Royal Mount: Command / Time Field",
"entity.antarchy.royal_mount.stage.hatchling": "Hatchling",
"entity.antarchy.royal_mount.stage.juvenile": "Juvenile",
"entity.antarchy.royal_mount.stage.adult": "Adult",
"message.antarchy.royal_mount.stage_up": "%s has reached the %s stage!",
"message.antarchy.royal_mount.growth": "%s: %s, %s%% grown",
"message.antarchy.royal_mount.too_young_ride": "%s must reach the %s stage before it can be ridden",
"message.antarchy.royal_mount.too_young_fly": "%s must reach the %s stage before it can fly",
"message.antarchy.royal_mount.too_young_ability": "%s must reach the %s stage to use that",
"item.antarchy.springbug_leg": "Springbug Leg", "item.antarchy.springbug_leg": "Springbug Leg",
"item.antarchy.springy_boots": "Springy Boots", "item.antarchy.springy_boots": "Springy Boots",
"tooltip.antarchy.springy_boots": "Sneak to charge, then jump to spring upward.", "tooltip.antarchy.springy_boots": "Sneak to charge, then jump to spring upward.",
@@ -791,6 +801,7 @@
"message.antarchy.big_bertha.mode.molevore": "Molevore", "message.antarchy.big_bertha.mode.molevore": "Molevore",
"message.antarchy.big_bertha.mode.toreterror": "Toreterror", "message.antarchy.big_bertha.mode.toreterror": "Toreterror",
"message.antarchy.ultimate_tool.mode_3x3": "Switched to 3x3 Mining", "message.antarchy.ultimate_tool.mode_3x3": "Switched to 3x3 Mining",
"message.antarchy.ultimate_tool.mode_vein": "Switched to Vein Mining",
"message.antarchy.ultimate_tool.mode_default": "Switched to Default Mining", "message.antarchy.ultimate_tool.mode_default": "Switched to Default Mining",
"advancements.antarchy.hey_listen.title": "Hey Listen", "advancements.antarchy.hey_listen.title": "Hey Listen",
"advancements.antarchy.hey_listen.description": "A Reverie has joined you.", "advancements.antarchy.hey_listen.description": "A Reverie has joined you.",
@@ -829,6 +840,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "Use to spin forward and drill through Molevore blocks.", "tooltip.antarchy.big_bertha.mode.molevore": "Use to spin forward and drill through Molevore blocks.",
"tooltip.antarchy.big_bertha.mode.toreterror": "Use to launch into the air and crash down with an AOE shockwave.", "tooltip.antarchy.big_bertha.mode.toreterror": "Use to launch into the air and crash down with an AOE shockwave.",
"tooltip.antarchy.ultimate_tools_3x3": "Shift + use to toggle 3x3 Mining.", "tooltip.antarchy.ultimate_tools_3x3": "Shift + use to toggle 3x3 Mining.",
"tooltip.antarchy.ultimate_tools_vein": "Shift + use to toggle Vein Mining.",
"tooltip.antarchy.ultimate_tools_3x3_vein": "Shift + use to cycle 3x3 and Vein Mining.",
"tooltip.antarchy.battle_axe_tree_felling": "Fells whole trees. Sneak to chop a single log.",
"tooltip.antarchy.moggles.reveal": "Gives night vision and points to nearby caves.", "tooltip.antarchy.moggles.reveal": "Gives night vision and points to nearby caves.",
"tooltip.antarchy.moggles.underground": "Works only while you have no sky access.", "tooltip.antarchy.moggles.underground": "Works only while you have no sky access.",
"tooltip.antarchy.cornea_ear.vision": "Grants Night Vision for %s seconds.", "tooltip.antarchy.cornea_ear.vision": "Grants Night Vision for %s seconds.",
@@ -1644,12 +1658,12 @@
,"guide.antarchy.entry.queen.description6": "In her final phase she also casts her own time dilation field, slowing anyone caught inside it." ,"guide.antarchy.entry.queen.description6": "In her final phase she also casts her own time dilation field, slowing anyone caught inside it."
,"guide.antarchy.entry.prince.title": "Prince" ,"guide.antarchy.entry.prince.title": "Prince"
,"guide.antarchy.entry.prince.subtitle": "Royal mount record" ,"guide.antarchy.entry.prince.subtitle": "Royal mount record"
,"guide.antarchy.entry.prince.description": "Prince Eggs hatch into small Princes that grow when fed golden items." ,"guide.antarchy.entry.prince.description": "Prince Eggs hatch into Hatchlings bonded to whoever placed the egg. Golden apples grow them a little and enchanted golden apples grow them a lot: Juveniles can be ridden and spit bolts, and Adults can fly, fire beams, and use their signature ability."
,"guide.antarchy.entry.prince.description2": "A grown Prince can be tamed and saddled for flight, fires elemental bolts at your enemies, and can command nearby hostile mobs. Feed responsibly; you are raising a small flying warlord." ,"guide.antarchy.entry.prince.description2": "The Prince is a ground brawler: he closes in to bite with all three heads, spits fire, ice, and lightning, and as an Adult commands nearby hostile mobs to fight for him. Feed responsibly; you are raising a small flying warlord."
,"guide.antarchy.entry.princess.title": "Princess" ,"guide.antarchy.entry.princess.title": "Princess"
,"guide.antarchy.entry.princess.subtitle": "Royal mount record" ,"guide.antarchy.entry.princess.subtitle": "Royal mount record"
,"guide.antarchy.entry.princess.description": "Princess Eggs hatch into small Princesses that grow when fed golden items." ,"guide.antarchy.entry.princess.description": "Princess Eggs hatch into Hatchlings bonded to whoever placed the egg. Golden apples grow them a little and enchanted golden apples grow them a lot: Juveniles can be ridden and spit bolts, and Adults can fly, fire beams, and use their signature ability."
,"guide.antarchy.entry.princess.description2": "A grown Princess can be tamed and saddled for flight, fires elemental bolts, and creates time-dilation fields around enemies." ,"guide.antarchy.entry.princess.description2": "The Princess fights at range: she keeps her distance, fires slowing bolts from her orbs, and as an Adult hovers above her foes and traps them in time-dilation fields."
,"subtitles.antarchy.hoverboard_mount": "Hoverboard starts" ,"subtitles.antarchy.hoverboard_mount": "Hoverboard starts"
,"subtitles.antarchy.hoverboard_dismount": "Hoverboard stops" ,"subtitles.antarchy.hoverboard_dismount": "Hoverboard stops"
,"subtitles.antarchy.hoverboard_idle": "Hoverboard hums" ,"subtitles.antarchy.hoverboard_idle": "Hoverboard hums"
@@ -517,6 +517,7 @@
"message.antarchy.big_bertha.mode.molevore": "Molevore", "message.antarchy.big_bertha.mode.molevore": "Molevore",
"message.antarchy.big_bertha.mode.toreterror": "Toreterror", "message.antarchy.big_bertha.mode.toreterror": "Toreterror",
"message.antarchy.ultimate_tool.mode_3x3": "Cambiado a minería 3x3", "message.antarchy.ultimate_tool.mode_3x3": "Cambiado a minería 3x3",
"message.antarchy.ultimate_tool.mode_vein": "Cambiado a minería de vetas",
"message.antarchy.ultimate_tool.mode_default": "Cambiado a minería normal", "message.antarchy.ultimate_tool.mode_default": "Cambiado a minería normal",
"advancements.antarchy.hey_listen.title": "¡Oye, escucha!", "advancements.antarchy.hey_listen.title": "¡Oye, escucha!",
"advancements.antarchy.hey_listen.description": "Una Reverie se ha unido a ti.", "advancements.antarchy.hey_listen.description": "Una Reverie se ha unido a ti.",
@@ -549,6 +550,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "Clic derecho para girar hacia delante y perforar bloques de Molevore.", "tooltip.antarchy.big_bertha.mode.molevore": "Clic derecho para girar hacia delante y perforar bloques de Molevore.",
"tooltip.antarchy.big_bertha.mode.toreterror": "Clic derecho para lanzarte al aire y caer con una onda de choque en área.", "tooltip.antarchy.big_bertha.mode.toreterror": "Clic derecho para lanzarte al aire y caer con una onda de choque en área.",
"tooltip.antarchy.ultimate_tools_3x3": "Mayús + clic derecho para alternar la minería 3x3.", "tooltip.antarchy.ultimate_tools_3x3": "Mayús + clic derecho para alternar la minería 3x3.",
"tooltip.antarchy.ultimate_tools_vein": "Mayús + clic derecho para alternar la minería de vetas.",
"tooltip.antarchy.ultimate_tools_3x3_vein": "Mayús + clic derecho para alternar entre minería 3x3 y de vetas.",
"tooltip.antarchy.battle_axe_tree_felling": "Tala árboles enteros. Agáchate para cortar un solo tronco.",
"tooltip.antarchy.moggles.reveal": "Otorga Visión nocturna y señala cuevas cercanas.", "tooltip.antarchy.moggles.reveal": "Otorga Visión nocturna y señala cuevas cercanas.",
"tooltip.antarchy.moggles.underground": "Solo funciona cuando no tienes acceso al cielo.", "tooltip.antarchy.moggles.underground": "Solo funciona cuando no tienes acceso al cielo.",
"tooltip.antarchy.cornea_ear.vision": "Otorga Visión nocturna durante %s segundos.", "tooltip.antarchy.cornea_ear.vision": "Otorga Visión nocturna durante %s segundos.",
@@ -517,6 +517,7 @@
"message.antarchy.big_bertha.mode.molevore": "Molevore", "message.antarchy.big_bertha.mode.molevore": "Molevore",
"message.antarchy.big_bertha.mode.toreterror": "Toreterror", "message.antarchy.big_bertha.mode.toreterror": "Toreterror",
"message.antarchy.ultimate_tool.mode_3x3": "Mode minage 3x3 activé", "message.antarchy.ultimate_tool.mode_3x3": "Mode minage 3x3 activé",
"message.antarchy.ultimate_tool.mode_vein": "Mode minage de filons activé",
"message.antarchy.ultimate_tool.mode_default": "Mode minage normal activé", "message.antarchy.ultimate_tool.mode_default": "Mode minage normal activé",
"advancements.antarchy.hey_listen.title": "Hé, écoute !", "advancements.antarchy.hey_listen.title": "Hé, écoute !",
"advancements.antarchy.hey_listen.description": "Une Reverie vous a rejoint.", "advancements.antarchy.hey_listen.description": "Une Reverie vous a rejoint.",
@@ -549,6 +550,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "Clic droit pour tournoyer vers l’avant et forer les blocs de Molevore.", "tooltip.antarchy.big_bertha.mode.molevore": "Clic droit pour tournoyer vers l’avant et forer les blocs de Molevore.",
"tooltip.antarchy.big_bertha.mode.toreterror": "Clic droit pour bondir dans les airs et retomber avec une onde de choc de zone.", "tooltip.antarchy.big_bertha.mode.toreterror": "Clic droit pour bondir dans les airs et retomber avec une onde de choc de zone.",
"tooltip.antarchy.ultimate_tools_3x3": "Maj + clic droit pour activer ou désactiver le minage 3x3.", "tooltip.antarchy.ultimate_tools_3x3": "Maj + clic droit pour activer ou désactiver le minage 3x3.",
"tooltip.antarchy.ultimate_tools_vein": "Maj + clic droit pour activer ou désactiver le minage de filons.",
"tooltip.antarchy.ultimate_tools_3x3_vein": "Maj + clic droit pour alterner entre minage 3x3 et minage de filons.",
"tooltip.antarchy.battle_axe_tree_felling": "Abat des arbres entiers. Accroupis-toi pour couper une seule bûche.",
"tooltip.antarchy.moggles.reveal": "Accorde Vision nocturne et indique les grottes proches.", "tooltip.antarchy.moggles.reveal": "Accorde Vision nocturne et indique les grottes proches.",
"tooltip.antarchy.moggles.underground": "Fonctionne uniquement lorsque vous n’avez pas accès au ciel.", "tooltip.antarchy.moggles.underground": "Fonctionne uniquement lorsque vous n’avez pas accès au ciel.",
"tooltip.antarchy.cornea_ear.vision": "Accorde Vision nocturne pendant %s secondes.", "tooltip.antarchy.cornea_ear.vision": "Accorde Vision nocturne pendant %s secondes.",
@@ -517,6 +517,7 @@
"message.antarchy.big_bertha.mode.molevore": "Molevore", "message.antarchy.big_bertha.mode.molevore": "Molevore",
"message.antarchy.big_bertha.mode.toreterror": "Toreterror", "message.antarchy.big_bertha.mode.toreterror": "Toreterror",
"message.antarchy.ultimate_tool.mode_3x3": "Scavo 3×3 attivato", "message.antarchy.ultimate_tool.mode_3x3": "Scavo 3×3 attivato",
"message.antarchy.ultimate_tool.mode_vein": "Scavo di vene attivato",
"message.antarchy.ultimate_tool.mode_default": "Scavo normale attivato", "message.antarchy.ultimate_tool.mode_default": "Scavo normale attivato",
"advancements.antarchy.hey_listen.title": "Ehi, ascolta!", "advancements.antarchy.hey_listen.title": "Ehi, ascolta!",
"advancements.antarchy.hey_listen.description": "Una Reverie si è unita a te.", "advancements.antarchy.hey_listen.description": "Una Reverie si è unita a te.",
@@ -549,6 +550,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "Fai clic destro per ruotare in avanti e perforare i blocchi di Molevore.", "tooltip.antarchy.big_bertha.mode.molevore": "Fai clic destro per ruotare in avanti e perforare i blocchi di Molevore.",
"tooltip.antarchy.big_bertha.mode.toreterror": "Fai clic destro per balzare in aria e schiantarti con un’onda d’urto ad area.", "tooltip.antarchy.big_bertha.mode.toreterror": "Fai clic destro per balzare in aria e schiantarti con un’onda d’urto ad area.",
"tooltip.antarchy.ultimate_tools_3x3": "Maiusc + clic destro per attivare o disattivare lo scavo 3×3.", "tooltip.antarchy.ultimate_tools_3x3": "Maiusc + clic destro per attivare o disattivare lo scavo 3×3.",
"tooltip.antarchy.ultimate_tools_vein": "Maiusc + clic destro per attivare o disattivare lo scavo di vene.",
"tooltip.antarchy.ultimate_tools_3x3_vein": "Maiusc + clic destro per alternare scavo 3×3 e scavo di vene.",
"tooltip.antarchy.battle_axe_tree_felling": "Abbatte alberi interi. Accovacciati per tagliare un solo tronco.",
"tooltip.antarchy.moggles.reveal": "Fornisce Visione notturna e indica le grotte vicine.", "tooltip.antarchy.moggles.reveal": "Fornisce Visione notturna e indica le grotte vicine.",
"tooltip.antarchy.moggles.underground": "Funziona solo quando non puoi vedere il cielo.", "tooltip.antarchy.moggles.underground": "Funziona solo quando non puoi vedere il cielo.",
"tooltip.antarchy.cornea_ear.vision": "Conferisce Visione notturna per %s secondi.", "tooltip.antarchy.cornea_ear.vision": "Conferisce Visione notturna per %s secondi.",
@@ -517,6 +517,7 @@
"message.antarchy.big_bertha.mode.molevore": "モールヴォア", "message.antarchy.big_bertha.mode.molevore": "モールヴォア",
"message.antarchy.big_bertha.mode.toreterror": "トアテラー", "message.antarchy.big_bertha.mode.toreterror": "トアテラー",
"message.antarchy.ultimate_tool.mode_3x3": "3×3採掘に切り替えました", "message.antarchy.ultimate_tool.mode_3x3": "3×3採掘に切り替えました",
"message.antarchy.ultimate_tool.mode_vein": "鉱脈採掘に切り替えました",
"message.antarchy.ultimate_tool.mode_default": "通常採掘に切り替えました", "message.antarchy.ultimate_tool.mode_default": "通常採掘に切り替えました",
"advancements.antarchy.hey_listen.title": "ねえ、聞いて!", "advancements.antarchy.hey_listen.title": "ねえ、聞いて!",
"advancements.antarchy.hey_listen.description": "レヴェリーが仲間になりました。", "advancements.antarchy.hey_listen.description": "レヴェリーが仲間になりました。",
@@ -549,6 +550,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "右クリックで回転しながら前進し、モールヴォアブロックを掘り抜きます。", "tooltip.antarchy.big_bertha.mode.molevore": "右クリックで回転しながら前進し、モールヴォアブロックを掘り抜きます。",
"tooltip.antarchy.big_bertha.mode.toreterror": "右クリックで空中へ飛び上がり、範囲衝撃波とともに落下します。", "tooltip.antarchy.big_bertha.mode.toreterror": "右クリックで空中へ飛び上がり、範囲衝撃波とともに落下します。",
"tooltip.antarchy.ultimate_tools_3x3": "シフトキー+右クリックで3×3採掘を切り替えます。", "tooltip.antarchy.ultimate_tools_3x3": "シフトキー+右クリックで3×3採掘を切り替えます。",
"tooltip.antarchy.ultimate_tools_vein": "シフトキー+右クリックで鉱脈採掘を切り替えます。",
"tooltip.antarchy.ultimate_tools_3x3_vein": "シフトキー+右クリックで3×3採掘と鉱脈採掘を切り替えます。",
"tooltip.antarchy.battle_axe_tree_felling": "木を丸ごと伐採します。スニーク中は原木を1つだけ切ります。",
"tooltip.antarchy.moggles.reveal": "暗視を付与し、近くの洞窟を示します。", "tooltip.antarchy.moggles.reveal": "暗視を付与し、近くの洞窟を示します。",
"tooltip.antarchy.moggles.underground": "空が見えない場所でのみ機能します。", "tooltip.antarchy.moggles.underground": "空が見えない場所でのみ機能します。",
"tooltip.antarchy.cornea_ear.vision": "%s秒間暗視を付与します。", "tooltip.antarchy.cornea_ear.vision": "%s秒間暗視を付与します。",
@@ -792,6 +792,7 @@
"message.antarchy.big_bertha.mode.molevore": "몰레보어", "message.antarchy.big_bertha.mode.molevore": "몰레보어",
"message.antarchy.big_bertha.mode.toreterror": "토레테러", "message.antarchy.big_bertha.mode.toreterror": "토레테러",
"message.antarchy.ultimate_tool.mode_3x3": "3x3 채굴 모드로 전환됨", "message.antarchy.ultimate_tool.mode_3x3": "3x3 채굴 모드로 전환됨",
"message.antarchy.ultimate_tool.mode_vein": "광맥 채굴 모드로 전환됨",
"message.antarchy.ultimate_tool.mode_default": "기본 채굴 모드로 전환됨", "message.antarchy.ultimate_tool.mode_default": "기본 채굴 모드로 전환됨",
"advancements.antarchy.hey_listen.title": "야, 들어봐!", "advancements.antarchy.hey_listen.title": "야, 들어봐!",
"advancements.antarchy.hey_listen.description": "레버리가 당신과 함께합니다.", "advancements.antarchy.hey_listen.description": "레버리가 당신과 함께합니다.",
@@ -830,6 +831,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "공격 시 추가 피해를 입히고 대상을 공중 높이 띄웁니다.", "tooltip.antarchy.big_bertha.mode.molevore": "공격 시 추가 피해를 입히고 대상을 공중 높이 띄웁니다.",
"tooltip.antarchy.big_bertha.mode.toreterror": "사용하여 앞으로 회전하며 몰레보어 블록을 뚫고 나아갑니다.", "tooltip.antarchy.big_bertha.mode.toreterror": "사용하여 앞으로 회전하며 몰레보어 블록을 뚫고 나아갑니다.",
"tooltip.antarchy.ultimate_tools_3x3": "Shift + 사용: 3x3 채굴을 켜거나 끕니다.", "tooltip.antarchy.ultimate_tools_3x3": "Shift + 사용: 3x3 채굴을 켜거나 끕니다.",
"tooltip.antarchy.ultimate_tools_vein": "Shift + 사용: 광맥 채굴을 켜거나 끕니다.",
"tooltip.antarchy.ultimate_tools_3x3_vein": "Shift + 사용: 3x3 채굴과 광맥 채굴을 전환합니다.",
"tooltip.antarchy.battle_axe_tree_felling": "나무 전체를 벱니다. 웅크리면 통나무 하나만 벱니다.",
"tooltip.antarchy.moggles.reveal": "야간 시야를 부여하고 근처 동굴을 가리킵니다.", "tooltip.antarchy.moggles.reveal": "야간 시야를 부여하고 근처 동굴을 가리킵니다.",
"tooltip.antarchy.moggles.underground": "하늘이 가려진 곳에서만 작동합니다.", "tooltip.antarchy.moggles.underground": "하늘이 가려진 곳에서만 작동합니다.",
"tooltip.antarchy.cornea_ear.vision": "%s초 동안 야간 시야를 부여합니다.", "tooltip.antarchy.cornea_ear.vision": "%s초 동안 야간 시야를 부여합니다.",
@@ -517,6 +517,7 @@
"message.antarchy.big_bertha.mode.molevore": "Molevore", "message.antarchy.big_bertha.mode.molevore": "Molevore",
"message.antarchy.big_bertha.mode.toreterror": "Toreterror", "message.antarchy.big_bertha.mode.toreterror": "Toreterror",
"message.antarchy.ultimate_tool.mode_3x3": "Alternado para Mineração 3x3", "message.antarchy.ultimate_tool.mode_3x3": "Alternado para Mineração 3x3",
"message.antarchy.ultimate_tool.mode_vein": "Alternado para Mineração de Veios",
"message.antarchy.ultimate_tool.mode_default": "Alternado para Mineração Padrão", "message.antarchy.ultimate_tool.mode_default": "Alternado para Mineração Padrão",
"advancements.antarchy.hey_listen.title": "Ei, Escute!", "advancements.antarchy.hey_listen.title": "Ei, Escute!",
"advancements.antarchy.hey_listen.description": "Uma Reverie se juntou a você.", "advancements.antarchy.hey_listen.description": "Uma Reverie se juntou a você.",
@@ -549,6 +550,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "Clique com o botão direito para girar para a frente e perfurar blocos de Molevore.", "tooltip.antarchy.big_bertha.mode.molevore": "Clique com o botão direito para girar para a frente e perfurar blocos de Molevore.",
"tooltip.antarchy.big_bertha.mode.toreterror": "Clique com o botão direito para se lançar ao ar e cair com uma onda de choque em área.", "tooltip.antarchy.big_bertha.mode.toreterror": "Clique com o botão direito para se lançar ao ar e cair com uma onda de choque em área.",
"tooltip.antarchy.ultimate_tools_3x3": "Shift + clique com o botão direito para alternar a Mineração 3x3.", "tooltip.antarchy.ultimate_tools_3x3": "Shift + clique com o botão direito para alternar a Mineração 3x3.",
"tooltip.antarchy.ultimate_tools_vein": "Shift + clique com o botão direito para alternar a Mineração de Veios.",
"tooltip.antarchy.ultimate_tools_3x3_vein": "Shift + clique com o botão direito para alternar entre Mineração 3x3 e de Veios.",
"tooltip.antarchy.battle_axe_tree_felling": "Derruba árvores inteiras. Agache para cortar um único tronco.",
"tooltip.antarchy.moggles.reveal": "Concede Visão Noturna e aponta para cavernas próximas.", "tooltip.antarchy.moggles.reveal": "Concede Visão Noturna e aponta para cavernas próximas.",
"tooltip.antarchy.moggles.underground": "Funciona apenas quando você não tem acesso ao céu.", "tooltip.antarchy.moggles.underground": "Funciona apenas quando você não tem acesso ao céu.",
"tooltip.antarchy.cornea_ear.vision": "Concede Visão Noturna por %s segundos.", "tooltip.antarchy.cornea_ear.vision": "Concede Visão Noturna por %s segundos.",
@@ -488,6 +488,7 @@
"message.antarchy.big_bertha.mode.molevore": "Кротожор", "message.antarchy.big_bertha.mode.molevore": "Кротожор",
"message.antarchy.big_bertha.mode.toreterror": "Тортеррор", "message.antarchy.big_bertha.mode.toreterror": "Тортеррор",
"message.antarchy.ultimate_tool.mode_3x3": "Включено копание 3x3", "message.antarchy.ultimate_tool.mode_3x3": "Включено копание 3x3",
"message.antarchy.ultimate_tool.mode_vein": "Включена добыча жил",
"message.antarchy.ultimate_tool.mode_default": "Включено обычное копание", "message.antarchy.ultimate_tool.mode_default": "Включено обычное копание",
"advancements.antarchy.hey_listen.title": "Эй, послушай", "advancements.antarchy.hey_listen.title": "Эй, послушай",
"advancements.antarchy.hey_listen.description": "К вам присоединилась грёза.", "advancements.antarchy.hey_listen.description": "К вам присоединилась грёза.",
@@ -520,6 +521,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "ПКМ для рывка вперёд и бурения сквозь блоки кротожора.", "tooltip.antarchy.big_bertha.mode.molevore": "ПКМ для рывка вперёд и бурения сквозь блоки кротожора.",
"tooltip.antarchy.big_bertha.mode.toreterror": "ПКМ запускает вас в воздух и обрушивает вниз с ударной волной по площади.", "tooltip.antarchy.big_bertha.mode.toreterror": "ПКМ запускает вас в воздух и обрушивает вниз с ударной волной по площади.",
"tooltip.antarchy.ultimate_tools_3x3": "Shift + ПКМ для переключения режима копания 3x3.", "tooltip.antarchy.ultimate_tools_3x3": "Shift + ПКМ для переключения режима копания 3x3.",
"tooltip.antarchy.ultimate_tools_vein": "Shift + ПКМ для переключения добычи жил.",
"tooltip.antarchy.ultimate_tools_3x3_vein": "Shift + ПКМ переключает копание 3x3 и добычу жил.",
"tooltip.antarchy.battle_axe_tree_felling": "Срубает дерево целиком. Присядьте, чтобы срубить одно бревно.",
"tooltip.antarchy.moggles.reveal": "Дают ночное зрение и указывают на ближайшие пещеры.", "tooltip.antarchy.moggles.reveal": "Дают ночное зрение и указывают на ближайшие пещеры.",
"tooltip.antarchy.moggles.underground": "Работает только если над вами нет открытого неба.", "tooltip.antarchy.moggles.underground": "Работает только если над вами нет открытого неба.",
"tooltip.antarchy.cornea_ear.vision": "Даёт Ночное зрение на %s секунд.", "tooltip.antarchy.cornea_ear.vision": "Даёт Ночное зрение на %s секунд.",
@@ -517,6 +517,7 @@
"message.antarchy.big_bertha.mode.molevore": "莫尔沃尔", "message.antarchy.big_bertha.mode.molevore": "莫尔沃尔",
"message.antarchy.big_bertha.mode.toreterror": "托尔泰罗尔", "message.antarchy.big_bertha.mode.toreterror": "托尔泰罗尔",
"message.antarchy.ultimate_tool.mode_3x3": "已切换至3×3挖掘", "message.antarchy.ultimate_tool.mode_3x3": "已切换至3×3挖掘",
"message.antarchy.ultimate_tool.mode_vein": "已切换至连锁挖矿",
"message.antarchy.ultimate_tool.mode_default": "已切换至默认挖掘", "message.antarchy.ultimate_tool.mode_default": "已切换至默认挖掘",
"advancements.antarchy.hey_listen.title": "嘿,听着!", "advancements.antarchy.hey_listen.title": "嘿,听着!",
"advancements.antarchy.hey_listen.description": "一只雷弗里加入了你。", "advancements.antarchy.hey_listen.description": "一只雷弗里加入了你。",
@@ -549,6 +550,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "右键旋转向前并钻穿莫尔沃尔方块。", "tooltip.antarchy.big_bertha.mode.molevore": "右键旋转向前并钻穿莫尔沃尔方块。",
"tooltip.antarchy.big_bertha.mode.toreterror": "右键跃向空中并以范围冲击波砸落。", "tooltip.antarchy.big_bertha.mode.toreterror": "右键跃向空中并以范围冲击波砸落。",
"tooltip.antarchy.ultimate_tools_3x3": "潜行键+右键切换3×3挖掘。", "tooltip.antarchy.ultimate_tools_3x3": "潜行键+右键切换3×3挖掘。",
"tooltip.antarchy.ultimate_tools_vein": "潜行键+右键切换连锁挖矿。",
"tooltip.antarchy.ultimate_tools_3x3_vein": "潜行键+右键在3×3挖掘与连锁挖矿之间切换。",
"tooltip.antarchy.battle_axe_tree_felling": "一次砍倒整棵树。潜行时只砍一块原木。",
"tooltip.antarchy.moggles.reveal": "获得夜视并指向附近洞穴。", "tooltip.antarchy.moggles.reveal": "获得夜视并指向附近洞穴。",
"tooltip.antarchy.moggles.underground": "仅在无法接触天空时生效。", "tooltip.antarchy.moggles.underground": "仅在无法接触天空时生效。",
"tooltip.antarchy.cornea_ear.vision": "获得%s秒夜视。", "tooltip.antarchy.cornea_ear.vision": "获得%s秒夜视。",
@@ -517,6 +517,7 @@
"message.antarchy.big_bertha.mode.molevore": "莫爾沃爾", "message.antarchy.big_bertha.mode.molevore": "莫爾沃爾",
"message.antarchy.big_bertha.mode.toreterror": "托爾泰羅爾", "message.antarchy.big_bertha.mode.toreterror": "托爾泰羅爾",
"message.antarchy.ultimate_tool.mode_3x3": "已切換至3×3挖掘", "message.antarchy.ultimate_tool.mode_3x3": "已切換至3×3挖掘",
"message.antarchy.ultimate_tool.mode_vein": "已切換至連鎖挖礦",
"message.antarchy.ultimate_tool.mode_default": "已切換至預設挖掘", "message.antarchy.ultimate_tool.mode_default": "已切換至預設挖掘",
"advancements.antarchy.hey_listen.title": "嘿,聽著!", "advancements.antarchy.hey_listen.title": "嘿,聽著!",
"advancements.antarchy.hey_listen.description": "一隻雷弗里加入了你。", "advancements.antarchy.hey_listen.description": "一隻雷弗里加入了你。",
@@ -549,6 +550,9 @@
"tooltip.antarchy.big_bertha.mode.molevore": "右鍵旋轉向前並鑽穿莫爾沃爾方塊。", "tooltip.antarchy.big_bertha.mode.molevore": "右鍵旋轉向前並鑽穿莫爾沃爾方塊。",
"tooltip.antarchy.big_bertha.mode.toreterror": "右鍵躍向空中並以範圍衝擊波砸落。", "tooltip.antarchy.big_bertha.mode.toreterror": "右鍵躍向空中並以範圍衝擊波砸落。",
"tooltip.antarchy.ultimate_tools_3x3": "潛行鍵+右鍵切換3×3挖掘。", "tooltip.antarchy.ultimate_tools_3x3": "潛行鍵+右鍵切換3×3挖掘。",
"tooltip.antarchy.ultimate_tools_vein": "潛行鍵+右鍵切換連鎖挖礦。",
"tooltip.antarchy.ultimate_tools_3x3_vein": "潛行鍵+右鍵在3×3挖掘與連鎖挖礦之間切換。",
"tooltip.antarchy.battle_axe_tree_felling": "一次砍倒整棵樹。潛行時只砍一塊原木。",
"tooltip.antarchy.moggles.reveal": "獲得夜視並指向附近洞穴。", "tooltip.antarchy.moggles.reveal": "獲得夜視並指向附近洞穴。",
"tooltip.antarchy.moggles.underground": "僅在無法接觸天空時生效。", "tooltip.antarchy.moggles.underground": "僅在無法接觸天空時生效。",
"tooltip.antarchy.cornea_ear.vision": "獲得%s秒夜視。", "tooltip.antarchy.cornea_ear.vision": "獲得%s秒夜視。",
@@ -55,7 +55,8 @@
], ],
[ [
"antarchy:moleworm_caves_creepvine", "antarchy:moleworm_caves_creepvine",
"antarchy:moleworm_caves_hanging_creeproots" "antarchy:moleworm_caves_hanging_creeproots",
"antarchy:termite_nest"
], ],
[] []
], ],
@@ -52,7 +52,8 @@
"antarchy:wormy_caves_creepvine", "antarchy:wormy_caves_creepvine",
"antarchy:wormy_caves_hanging_creeproots", "antarchy:wormy_caves_hanging_creeproots",
"antarchy:wormy_caves_molting_vines", "antarchy:wormy_caves_molting_vines",
"antarchy:wormy_caves_ground_molting_vines" "antarchy:wormy_caves_ground_molting_vines",
"antarchy:termite_nest"
], ],
[] []
], ],
@@ -3,7 +3,7 @@
"placement": [ "placement": [
{ {
"type": "minecraft:rarity_filter", "type": "minecraft:rarity_filter",
"chance": 24 "chance": 8
}, },
{ {
"type": "minecraft:in_square" "type": "minecraft:in_square"
@@ -3,7 +3,7 @@
"placement": [ "placement": [
{ {
"type": "minecraft:rarity_filter", "type": "minecraft:rarity_filter",
"chance": 24 "chance": 8
}, },
{ {
"type": "minecraft:in_square" "type": "minecraft:in_square"
@@ -3,14 +3,22 @@
"placement": [ "placement": [
{ {
"type": "minecraft:rarity_filter", "type": "minecraft:rarity_filter",
"chance": 88 "chance": 24
}, },
{ {
"type": "minecraft:in_square" "type": "minecraft:in_square"
}, },
{ {
"type": "minecraft:heightmap", "type": "minecraft:height_range",
"heightmap": "WORLD_SURFACE_WG" "height": {
"type": "minecraft:uniform",
"min_inclusive": {
"absolute": 8
},
"max_inclusive": {
"absolute": 190
}
}
}, },
{ {
"type": "minecraft:biome" "type": "minecraft:biome"
@@ -3,14 +3,22 @@
"placement": [ "placement": [
{ {
"type": "minecraft:rarity_filter", "type": "minecraft:rarity_filter",
"chance": 44 "chance": 16
}, },
{ {
"type": "minecraft:in_square" "type": "minecraft:in_square"
}, },
{ {
"type": "minecraft:heightmap", "type": "minecraft:height_range",
"heightmap": "WORLD_SURFACE_WG" "height": {
"type": "minecraft:uniform",
"min_inclusive": {
"absolute": 8
},
"max_inclusive": {
"absolute": 190
}
}
}, },
{ {
"type": "minecraft:biome" "type": "minecraft:biome"
@@ -31,11 +31,6 @@ public interface InfinityCompatBridge {
return InfinityWarpResult.REJECTED; return InfinityWarpResult.REJECTED;
} }
/**
* Converts an already-ignited vanilla Nether portal frame at {@code anyPortalBlockPos} into a real, permanent
* Infinite Dimensions portal to {@code dimensionId}, generating the dimension first if it doesn't exist yet.
* Mirrors what Infinity itself does when a written book is thrown into a lit portal.
*/
default boolean createPhysicalPortal(ServerLevel level, BlockPos anyPortalBlockPos, ResourceLocation dimensionId) { default boolean createPhysicalPortal(ServerLevel level, BlockPos anyPortalBlockPos, ResourceLocation dimensionId) {
return false; return false;
} }
@@ -107,6 +107,9 @@ public final class AntarchySettings {
private static int ultimateCrossbowEnchantability = 20; private static int ultimateCrossbowEnchantability = 20;
private static int ultimateMaceEnchantability = 20; private static int ultimateMaceEnchantability = 20;
private static boolean ultimateToolsThreeByThreeEnabled = true; private static boolean ultimateToolsThreeByThreeEnabled = true;
private static boolean ultimateToolsVeinMiningEnabled = true;
private static int ultimateToolsVeinMiningMaxBlocks = 64;
private static int ultimateToolsTreeFellingMaxLogs = 128;
private static boolean ultimateArmorComesEnchanted = true; private static boolean ultimateArmorComesEnchanted = true;
private static int ultimateHelmetArmorValue = 6; private static int ultimateHelmetArmorValue = 6;
private static int ultimateChestplateArmorValue = 11; private static int ultimateChestplateArmorValue = 11;
@@ -299,6 +302,7 @@ public final class AntarchySettings {
private static double royalBossKnockbackResistance = 1.0D; private static double royalBossKnockbackResistance = 1.0D;
private static double royalBossStepHeight = 3.0D; private static double royalBossStepHeight = 3.0D;
private static double royalBossMaxSingleHitDamage = 250.0D; private static double royalBossMaxSingleHitDamage = 250.0D;
private static double royalBossHitOverflowRate = 0.25D;
private static double royalBossBiteReach = 12.0D; private static double royalBossBiteReach = 12.0D;
private static double royalBossBiteDamageMultiplier = 1.6D; private static double royalBossBiteDamageMultiplier = 1.6D;
private static int royalBossBiteCooldownTicks = 45; private static int royalBossBiteCooldownTicks = 45;
@@ -563,7 +567,6 @@ public final class AntarchySettings {
private static int bloodCrystalAppleDurationTicks = 2400; private static int bloodCrystalAppleDurationTicks = 2400;
private static int bloodCrystalAppleShieldRechargeTicks = 600; private static int bloodCrystalAppleShieldRechargeTicks = 600;
private static int bloodCrystalHardMaxShields = 10; private static int bloodCrystalHardMaxShields = 10;
// Armor stats (iron defense, gold durability, 0 toughness by default)
private static int bloodCrystalHelmetDefense = 3; private static int bloodCrystalHelmetDefense = 3;
private static int bloodCrystalChestplateDefense = 7; private static int bloodCrystalChestplateDefense = 7;
private static int bloodCrystalLeggingsDefense = 6; private static int bloodCrystalLeggingsDefense = 6;
@@ -975,6 +978,18 @@ public final class AntarchySettings {
return ultimateToolsThreeByThreeEnabled; return ultimateToolsThreeByThreeEnabled;
} }
public static boolean ultimateToolsVeinMiningEnabled() {
return ultimateToolsVeinMiningEnabled;
}
public static int ultimateToolsVeinMiningMaxBlocks() {
return ultimateToolsVeinMiningMaxBlocks;
}
public static int ultimateToolsTreeFellingMaxLogs() {
return ultimateToolsTreeFellingMaxLogs;
}
public static boolean ultimateArmorComesEnchanted() { public static boolean ultimateArmorComesEnchanted() {
return ultimateArmorComesEnchanted; return ultimateArmorComesEnchanted;
} }
@@ -1625,6 +1640,18 @@ public final class AntarchySettings {
ultimateToolsThreeByThreeEnabled = value; ultimateToolsThreeByThreeEnabled = value;
} }
public static void setUltimateToolsVeinMiningEnabled(boolean value) {
ultimateToolsVeinMiningEnabled = value;
}
public static void setUltimateToolsVeinMiningMaxBlocks(int value) {
ultimateToolsVeinMiningMaxBlocks = value;
}
public static void setUltimateToolsTreeFellingMaxLogs(int value) {
ultimateToolsTreeFellingMaxLogs = value;
}
public static void setUltimateArmorComesEnchanted(boolean value) { public static void setUltimateArmorComesEnchanted(boolean value) {
ultimateArmorComesEnchanted = value; ultimateArmorComesEnchanted = value;
} }
@@ -2230,6 +2257,9 @@ public final class AntarchySettings {
public static double royalBossMaxSingleHitDamage() { return royalBossMaxSingleHitDamage; } public static double royalBossMaxSingleHitDamage() { return royalBossMaxSingleHitDamage; }
public static void setRoyalBossMaxSingleHitDamage(double v) { royalBossMaxSingleHitDamage = v; } public static void setRoyalBossMaxSingleHitDamage(double v) { royalBossMaxSingleHitDamage = v; }
public static double royalBossHitOverflowRate() { return royalBossHitOverflowRate; }
public static void setRoyalBossHitOverflowRate(double v) { royalBossHitOverflowRate = v; }
public static double royalBossBiteReach() { return royalBossBiteReach; } public static double royalBossBiteReach() { return royalBossBiteReach; }
public static void setRoyalBossBiteReach(double v) { royalBossBiteReach = v; } public static void setRoyalBossBiteReach(double v) { royalBossBiteReach = v; }
@@ -2499,7 +2529,6 @@ public final class AntarchySettings {
public static int reverieDuplicationCooldownTicks() { return reverieDuplicationCooldownTicks; } public static int reverieDuplicationCooldownTicks() { return reverieDuplicationCooldownTicks; }
public static void setReverieDuplicationCooldownTicks(int v){ reverieDuplicationCooldownTicks = v; } public static void setReverieDuplicationCooldownTicks(int v){ reverieDuplicationCooldownTicks = v; }
// Hardcoded AI tuning — getters only, no config wiring
public static double reveriePreferredFollowMinDistance() { return reveriePreferredFollowMinDistance; } public static double reveriePreferredFollowMinDistance() { return reveriePreferredFollowMinDistance; }
public static double reveriePreferredFollowMaxDistance() { return reveriePreferredFollowMaxDistance; } public static double reveriePreferredFollowMaxDistance() { return reveriePreferredFollowMaxDistance; }
public static double reverieCatchUpDistance() { return reverieCatchUpDistance; } public static double reverieCatchUpDistance() { return reverieCatchUpDistance; }
@@ -11,6 +11,7 @@ import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluid;
public final class AntarchyTags { public final class AntarchyTags {
@@ -157,4 +158,11 @@ public final class AntarchyTags {
private Biomes() { private Biomes() {
} }
} }
public static final class DimensionTypes {
public static final TagKey<DimensionType> NO_MANTIS_CLIMB = TagKey.create(Registries.DIMENSION_TYPE, id("no_mantis_climb"));
private DimensionTypes() {
}
}
} }
@@ -30,11 +30,6 @@ public final class AntarchyAdvancementTriggers {
register((id, trigger) -> CriteriaTriggers.register(id.toString(), trigger)); register((id, trigger) -> CriteriaTriggers.register(id.toString(), trigger));
} }
/**
* Registers these triggers through the active loader's lifecycle hook.
* NeoForge calls this from its trigger-type RegisterEvent; Fabric can call
* the no-argument overload during its initializer.
*/
public static void register(BiConsumer<ResourceLocation, CriterionTrigger<?>> registrar) { public static void register(BiConsumer<ResourceLocation, CriterionTrigger<?>> registrar) {
registrar.accept(ResourceLocation.fromNamespaceAndPath("antarchy", "crossed_gravity_throat"), CROSSING); registrar.accept(ResourceLocation.fromNamespaceAndPath("antarchy", "crossed_gravity_throat"), CROSSING);
registrar.accept(ResourceLocation.fromNamespaceAndPath("antarchy", "horde_phase_changed"), HORDE_PHASE); registrar.accept(ResourceLocation.fromNamespaceAndPath("antarchy", "horde_phase_changed"), HORDE_PHASE);
@@ -25,7 +25,6 @@ public final class DuplicatorTreeLogic {
private static final int LOG_SEARCH_BELOW = 5; private static final int LOG_SEARCH_BELOW = 5;
private static final int LOG_SEARCH_ABOVE = 1; private static final int LOG_SEARCH_ABOVE = 1;
// Cache center log pos per chunk. WeakHashMap lets levels be GC'd when unloaded.
private static final WeakHashMap<ServerLevel, HashMap<Long, BlockPos>> CENTER_LOG_CACHE = new WeakHashMap<>(); private static final WeakHashMap<ServerLevel, HashMap<Long, BlockPos>> CENTER_LOG_CACHE = new WeakHashMap<>();
private DuplicatorTreeLogic() { private DuplicatorTreeLogic() {
@@ -20,7 +20,6 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
/** A two-block-tall, light-emitting reed found around Lumen pools. */
public final class GlimmeringReedBlock extends DoublePlantBlock implements BonemealableBlock { public final class GlimmeringReedBlock extends DoublePlantBlock implements BonemealableBlock {
public static final MapCodec<GlimmeringReedBlock> CODEC = Block.simpleCodec(GlimmeringReedBlock::new); public static final MapCodec<GlimmeringReedBlock> CODEC = Block.simpleCodec(GlimmeringReedBlock::new);
@@ -25,12 +25,6 @@ import net.minecraft.world.level.material.Fluids;
public class OuranwoodLeavesBlock extends LeavesBlock implements BonemealableBlock { public class OuranwoodLeavesBlock extends LeavesBlock implements BonemealableBlock {
public static final MapCodec<OuranwoodLeavesBlock> CODEC = Block.simpleCodec(OuranwoodLeavesBlock::new); public static final MapCodec<OuranwoodLeavesBlock> CODEC = Block.simpleCodec(OuranwoodLeavesBlock::new);
/*
* We still include vanilla LeavesBlock.DISTANCE in the state definition because
* LeavesBlock's constructor sets it.
*
* This is the real Ouranwood decay distance.
*/
public static final IntegerProperty OURANWOOD_DISTANCE = IntegerProperty.create("ouranwood_distance", 1, 17); public static final IntegerProperty OURANWOOD_DISTANCE = IntegerProperty.create("ouranwood_distance", 1, 17);
public static final BooleanProperty PERSISTENT = LeavesBlock.PERSISTENT; public static final BooleanProperty PERSISTENT = LeavesBlock.PERSISTENT;
@@ -13,12 +13,6 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.block.state.properties.IntegerProperty;
/**
* Invisible world-gen-only marker placed inside a flying squirrel hollow.
* Schedules itself to replace with COARSE_DIRT and spawn squirrels shortly
* after the chunk loads, so entity creation never blocks the gen thread.
* No BlockItem is registered, so this block never appears in creative or JEI.
*/
public class OuranwoodSquirrelNestBlock extends Block { public class OuranwoodSquirrelNestBlock extends Block {
public static final IntegerProperty SQUIRREL_COUNT = IntegerProperty.create("squirrels", 1, 3); public static final IntegerProperty SQUIRREL_COUNT = IntegerProperty.create("squirrels", 1, 3);
@@ -168,11 +168,6 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
} }
} }
/**
* Vanilla FallingBlockEntity always falls in world-down direction, so an
* unsupported egg placed with inverted underside gravity is stepped
* upward toward its support instead of being handed to that entity.
*/
private void tickInvertedFall(BlockState state, ServerLevel level, BlockPos pos) { private void tickInvertedFall(BlockState state, ServerLevel level, BlockPos pos) {
BlockPos above = pos.above(); BlockPos above = pos.above();
if (!FallingBlock.isFree(level.getBlockState(above)) || above.getY() > level.getMaxBuildHeight()) { if (!FallingBlock.isFree(level.getBlockState(above)) || above.getY() > level.getMaxBuildHeight()) {
@@ -65,8 +65,6 @@ public final class QueenTrailSpawnMarkerBlockEntity extends BlockEntity {
if (!nearbyPlayer) { if (!nearbyPlayer) {
return; return;
} }
// The Queen is large enough to span several chunks. Ensure the area around
// the arrival point is available before checking its collision box.
for (int chunkX = (marker.spawnPos.getX() - 16) >> 4; chunkX <= (marker.spawnPos.getX() + 16) >> 4; chunkX++) { for (int chunkX = (marker.spawnPos.getX() - 16) >> 4; chunkX <= (marker.spawnPos.getX() + 16) >> 4; chunkX++) {
for (int chunkZ = (marker.spawnPos.getZ() - 16) >> 4; chunkZ <= (marker.spawnPos.getZ() + 16) >> 4; chunkZ++) { for (int chunkZ = (marker.spawnPos.getZ() - 16) >> 4; chunkZ <= (marker.spawnPos.getZ() + 16) >> 4; chunkZ++) {
level.getChunk(chunkX, chunkZ); level.getChunk(chunkX, chunkZ);
@@ -47,9 +47,6 @@ public final class UnderVaultBlockEntity extends BlockEntity {
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, UnderVaultBlockEntity blockEntity) { public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, UnderVaultBlockEntity blockEntity) {
blockEntity.vaultData.setLevel(level); blockEntity.vaultData.setLevel(level);
// The vanilla vault detector can miss this ceiling-mounted wrapper because its
// block state has a separate render-facing property. Keep the state synchronized
// with the same four-block activation range before running vanilla's state machine.
boolean playerNearby = !level.getEntitiesOfClass(Player.class, new AABB(pos).inflate(4.0D), player -> !player.isSpectator()).isEmpty(); boolean playerNearby = !level.getEntitiesOfClass(Player.class, new AABB(pos).inflate(4.0D), player -> !player.isSpectator()).isEmpty();
if (state.getValue(UnderVaultBlock.STATE) == VaultState.INACTIVE && playerNearby && !blockEntity.playerWasNearby) { if (state.getValue(UnderVaultBlock.STATE) == VaultState.INACTIVE && playerNearby && !blockEntity.playerWasNearby) {
state = state.setValue(UnderVaultBlock.STATE, VaultState.ACTIVE); state = state.setValue(UnderVaultBlock.STATE, VaultState.ACTIVE);
@@ -1,10 +1,5 @@
package com.craisinlord.antarchy.content.block.entity; package com.craisinlord.antarchy.content.block.entity;
/**
* Identifies spawn-rule checks made by an Undertrial spawner's vanilla
* TrialSpawner tick. The context is scoped to the current server-thread call
* so ordinary trial spawners and all other spawn paths retain vanilla rules.
*/
public final class UndertrialSpawnContext implements AutoCloseable { public final class UndertrialSpawnContext implements AutoCloseable {
private static final ThreadLocal<Integer> DEPTH = ThreadLocal.withInitial(() -> 0); private static final ThreadLocal<Integer> DEPTH = ThreadLocal.withInitial(() -> 0);
@@ -190,8 +190,6 @@ public final class UndertrialSpawnerBlockEntity extends BlockEntity implements T
if (this.level == null) { if (this.level == null) {
return; return;
} }
// Match vanilla Trial Spawner interaction: override the next mob's entity id while
// preserving weighted potentials, ominous settings, and the trial's reward configuration.
this.trialSpawner.getData().setEntityId(this.trialSpawner, this.level.random, entityType); this.trialSpawner.getData().setEntityId(this.trialSpawner, this.level.random, entityType);
this.markUpdated(); this.markUpdated();
} }
@@ -6,7 +6,6 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
/** Client state for Antarchy-owned games hosted by AntOS. */
public final class AntarchyGameClientState { public final class AntarchyGameClientState {
private static final Map<String, String> GAME_STATES = new ConcurrentHashMap<>(); private static final Map<String, String> GAME_STATES = new ConcurrentHashMap<>();
@@ -17,7 +17,6 @@ public final class MoonSkyTracker {
private static final long MAX_AGE_MILLIS = 1500L; private static final long MAX_AGE_MILLIS = 1500L;
private static final double AIM_COSINE = Math.cos(Math.toRadians(PortalGunMoonMath.AIM_TOLERANCE_DEGREES)); private static final double AIM_COSINE = Math.cos(Math.toRadians(PortalGunMoonMath.AIM_TOLERANCE_DEGREES));
private static Vec3 direction; private static Vec3 direction;
// Weak so a dimension change or logout doesn't pin the old client world in memory.
private static WeakReference<ClientLevel> level = new WeakReference<>(null); private static WeakReference<ClientLevel> level = new WeakReference<>(null);
private static long recordedAt; private static long recordedAt;
private static Consumer<PortalGunMoonAimPayload> sender = payload -> {}; private static Consumer<PortalGunMoonAimPayload> sender = payload -> {};
@@ -20,7 +20,6 @@ public final class PortalGunCrosshairRenderer {
private static final int HALF_WIDTH = 17; private static final int HALF_WIDTH = 17;
private static final float MISSING_BRIGHTNESS = 0.3F; private static final float MISSING_BRIGHTNESS = 0.3F;
private static final float MISSING_ALPHA = 0.75F; private static final float MISSING_ALPHA = 0.75F;
// Weak so a dimension change or logout doesn't pin the old client world in memory.
private static WeakReference<ClientLevel> cachedLevel = new WeakReference<>(null); private static WeakReference<ClientLevel> cachedLevel = new WeakReference<>(null);
private static long cachedGameTime = Long.MIN_VALUE; private static long cachedGameTime = Long.MIN_VALUE;
private static UUID cachedGunId; private static UUID cachedGunId;
@@ -12,7 +12,6 @@ import net.minecraft.client.multiplayer.ClientLevel;
public final class PortalGunIndicatorClientState { public final class PortalGunIndicatorClientState {
private static final Map<UUID, PortalGunIndicatorPayload> STATES = new HashMap<>(); private static final Map<UUID, PortalGunIndicatorPayload> STATES = new HashMap<>();
// Weak so a dimension change or logout doesn't pin the old client world in memory.
private static WeakReference<ClientLevel> level = new WeakReference<>(null); private static WeakReference<ClientLevel> level = new WeakReference<>(null);
private static long lastRequestTick = Long.MIN_VALUE; private static long lastRequestTick = Long.MIN_VALUE;
private static UUID lastRequestedGun; private static UUID lastRequestedGun;
@@ -8,14 +8,11 @@ import net.minecraft.resources.ResourceLocation;
import java.util.function.IntPredicate; import java.util.function.IntPredicate;
import java.util.function.Predicate; import java.util.function.Predicate;
/** Registers Antarchy's native games with the AntOS Games app. */
public final class AntarchyComputerGames { public final class AntarchyComputerGames {
private AntarchyComputerGames() {} private AntarchyComputerGames() {}
public static void register() { public static void register() {
registerIfMissing(game("basilisk", "BASILISK", () -> { registerIfMissing(game("basilisk", "BASILISK", () -> {
// AntOS 1.2.1 creates game sessions without passing the computer position.
// Keep Basilisk playable without a position-bound score callback.
BasiliskProgram program = new BasiliskProgram(true, 0, 0, score -> {}); BasiliskProgram program = new BasiliskProgram(true, 0, 0, score -> {});
return new GameSession(program::tick, program::render, program::keyPressed, ignored -> false); return new GameSession(program::tick, program::render, program::keyPressed, ignored -> false);
})); }));
@@ -8,11 +8,6 @@ import net.minecraft.client.model.FrogModel;
import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
/**
* Reuses vanilla Frog geometry ({@link FrogModel}/{@code ModelLayers.FROG}) for the Frog
* Glimmer variant instead of an ill-fitting GeckoLib placeholder mesh, with a simplified
* walk/idle animation (GlimmerEntity has no Frog-specific jump/tongue state).
*/
public class GlimmerFrogModel extends EntityModel<GlimmerEntity> { public class GlimmerFrogModel extends EntityModel<GlimmerEntity> {
private final ModelPart root; private final ModelPart root;
private final ModelPart head; private final ModelPart head;
@@ -9,7 +9,6 @@ public class AlphaMantisRenderer extends GeoEntityRenderer<AlphaMantisEntity> {
public AlphaMantisRenderer(EntityRendererProvider.Context context) { public AlphaMantisRenderer(EntityRendererProvider.Context context) {
super(context, new AlphaMantisModel()); super(context, new AlphaMantisModel());
this.shadowRadius = 1.5F; this.shadowRadius = 1.5F;
// Mantis renders at 1.25x; the alpha is 1.5x bigger overall
this.withScale(1.875F); this.withScale(1.875F);
} }
} }
@@ -74,7 +74,6 @@ public final class ElythiaSkyRenderer {
float starBrightness = level.getStarBrightness(partialTick) * (1.0F - rainLevel); float starBrightness = level.getStarBrightness(partialTick) * (1.0F - rainLevel);
double timeDegrees = (level.getDayTime() + partialTick) * (360.0D / 24000.0D); double timeDegrees = (level.getDayTime() + partialTick) * (360.0D / 24000.0D);
// Blend in a dark purple when it's night (starBrightness > 0)
float nightPurpleR = 0.055F; float nightPurpleR = 0.055F;
float nightPurpleG = 0.010F; float nightPurpleG = 0.010F;
float nightPurpleB = 0.120F; float nightPurpleB = 0.120F;
@@ -169,10 +168,10 @@ public final class ElythiaSkyRenderer {
private static float[] pickStarColor(Random random) { private static float[] pickStarColor(Random random) {
float roll = random.nextFloat(); float roll = random.nextFloat();
if (roll < 0.80F) return new float[]{1.0F, 1.0F, 1.0F}; // white if (roll < 0.80F) return new float[]{1.0F, 1.0F, 1.0F};
if (roll < 0.87F) return new float[]{0.85F, 0.60F, 1.00F}; // light purple if (roll < 0.87F) return new float[]{0.85F, 0.60F, 1.00F};
if (roll < 0.94F) return new float[]{1.00F, 0.95F, 0.50F}; // yellow if (roll < 0.94F) return new float[]{1.00F, 0.95F, 0.50F};
return new float[]{1.0F, 0.45F, 0.45F}; // red return new float[]{1.0F, 0.45F, 0.45F};
} }
private static void renderSunrise(PoseStack poseStack, Matrix4f projectionMatrix, ClientLevel level, float partialTick, float rainLevel) { private static void renderSunrise(PoseStack poseStack, Matrix4f projectionMatrix, ClientLevel level, float partialTick, float rainLevel) {
@@ -212,22 +211,18 @@ public final class ElythiaSkyRenderer {
private static void renderCelestialBodies(Matrix4f modelViewMatrix, Matrix4f projectionMatrix, double timeDegrees, float rainLevel) { private static void renderCelestialBodies(Matrix4f modelViewMatrix, Matrix4f projectionMatrix, double timeDegrees, float rainLevel) {
// Purple sun
float sun1Orbit = orbitAngle(timeDegrees, 1.0D, 0.0D); float sun1Orbit = orbitAngle(timeDegrees, 1.0D, 0.0D);
renderBodyGlow(modelViewMatrix, projectionMatrix, sun1Orbit, 0.0F, 0xD06BFF, rainLevel, 70.0F); renderBodyGlow(modelViewMatrix, projectionMatrix, sun1Orbit, 0.0F, 0xD06BFF, rainLevel, 70.0F);
renderTexturedBody(modelViewMatrix, projectionMatrix, sun1Orbit, 0.0F, 38.0F, 0xD06BFF, 1.0F, SUN_TEXTURE, false, 0, orbitAngle(timeDegrees, 0.8D, 0.0D)); renderTexturedBody(modelViewMatrix, projectionMatrix, sun1Orbit, 0.0F, 38.0F, 0xD06BFF, 1.0F, SUN_TEXTURE, false, 0, orbitAngle(timeDegrees, 0.8D, 0.0D));
// Orange sub
float sun2Orbit = orbitAngle(timeDegrees, 0.73D, 54.0D); float sun2Orbit = orbitAngle(timeDegrees, 0.73D, 54.0D);
renderBodyGlow(modelViewMatrix, projectionMatrix, sun2Orbit, -14.0F, 0xFF9A33, rainLevel, 70.0F); renderBodyGlow(modelViewMatrix, projectionMatrix, sun2Orbit, -14.0F, 0xFF9A33, rainLevel, 70.0F);
renderTexturedBody(modelViewMatrix, projectionMatrix, sun2Orbit, -14.0F, 16.0F, 0xFF9A33, 1.0F, SUN_TEXTURE, false, 0, orbitAngle(timeDegrees, -0.5D, 0.0D)); renderTexturedBody(modelViewMatrix, projectionMatrix, sun2Orbit, -14.0F, 16.0F, 0xFF9A33, 1.0F, SUN_TEXTURE, false, 0, orbitAngle(timeDegrees, -0.5D, 0.0D));
// Dark green moon
float moon2Orbit = orbitAngle(timeDegrees, 1.27D, 228.0D); float moon2Orbit = orbitAngle(timeDegrees, 1.27D, 228.0D);
renderBodyGlow(modelViewMatrix, projectionMatrix, moon2Orbit, 36.0F, 0x4FD84D, rainLevel, 78.0F); renderBodyGlow(modelViewMatrix, projectionMatrix, moon2Orbit, 36.0F, 0x4FD84D, rainLevel, 78.0F);
renderTexturedBody(modelViewMatrix, projectionMatrix, moon2Orbit, 36.0F, 14.0F, 0x4FD84D, 1.0F, MOON_TEXTURE, true, 1, orbitAngle(timeDegrees, 0.3D, 0.0D)); renderTexturedBody(modelViewMatrix, projectionMatrix, moon2Orbit, 36.0F, 14.0F, 0x4FD84D, 1.0F, MOON_TEXTURE, true, 1, orbitAngle(timeDegrees, 0.3D, 0.0D));
// Light green moon
float moon3Orbit = orbitAngle(timeDegrees, 0.38D, 122.0D); float moon3Orbit = orbitAngle(timeDegrees, 0.38D, 122.0D);
renderBodyGlow(modelViewMatrix, projectionMatrix, moon3Orbit, -34.0F, 0xA3FF8F, rainLevel, 78.0F); renderBodyGlow(modelViewMatrix, projectionMatrix, moon3Orbit, -34.0F, 0xA3FF8F, rainLevel, 78.0F);
renderTexturedBody(modelViewMatrix, projectionMatrix, moon3Orbit, -34.0F, 12.0F, 0xA3FF8F, 1.0F, MOON_TEXTURE, true, 2, orbitAngle(timeDegrees, -0.6D, 0.0D)); renderTexturedBody(modelViewMatrix, projectionMatrix, moon3Orbit, -34.0F, 12.0F, 0xA3FF8F, 1.0F, MOON_TEXTURE, true, 2, orbitAngle(timeDegrees, -0.6D, 0.0D));
@@ -193,9 +193,6 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
float outerV = -time * 0.25F; float outerV = -time * 0.25F;
float innerV = -time * 0.25F * 0.5F; float innerV = -time * 0.25F * 0.5F;
// Tremorzilla renders the beam in local +Z space. Keeping the mesh in that
// space is important: the beam textures are authored for these exact face
// coordinates and are not interchangeable with a world-space billboard.
float yaw = (float) Math.atan2(dir.z, dir.x); float yaw = (float) Math.atan2(dir.z, dir.x);
float pitch = (float) Math.acos(dir.y); float pitch = (float) Math.acos(dir.y);
poseStack.pushPose(); poseStack.pushPose();
@@ -79,8 +79,6 @@ public final class RoyalIndicatorRenderer {
out.addVertex(pose, right, top, depth).setUv(1.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, 1.0F); out.addVertex(pose, right, top, depth).setUv(1.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, 1.0F);
out.addVertex(pose, left, top, depth).setUv(0.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, 1.0F); out.addVertex(pose, left, top, depth).setUv(0.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, 1.0F);
// Emit the reverse winding as well. The crown is viewed from every angle, and
// a single-sided quad can vanish when the renderer's culling state rejects it.
out.addVertex(pose, left, top, depth).setUv(0.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, -1.0F); out.addVertex(pose, left, top, depth).setUv(0.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, -1.0F);
out.addVertex(pose, right, top, depth).setUv(1.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, -1.0F); out.addVertex(pose, right, top, depth).setUv(1.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, -1.0F);
out.addVertex(pose, right, bottom, depth).setUv(1.0F, 1.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, -1.0F); out.addVertex(pose, right, bottom, depth).setUv(1.0F, 1.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, -1.0F);
@@ -22,9 +22,6 @@ import net.minecraft.world.level.block.state.BlockState;
public final class TigerEyeCamouflageTextureResolver { public final class TigerEyeCamouflageTextureResolver {
public record ResolvedTexture(ResourceLocation texture, int argbTint) {} public record ResolvedTexture(ResourceLocation texture, int argbTint) {}
// PlayerModel's skin layout is always laid out on a 64x64 canvas, regardless of the
// block texture's actual size, so the generated overlay texture must match that grid
// for every body part to sample the block texture at the same pixel density.
private static final int SKIN_SIZE = 64; private static final int SKIN_SIZE = 64;
private static final Map<Integer, ResolvedTexture> CACHE = new ConcurrentHashMap<>(); private static final Map<Integer, ResolvedTexture> CACHE = new ConcurrentHashMap<>();
private static final ResourceLocation FALLBACK_TEXTURE = ResourceLocation.withDefaultNamespace("textures/block/stone.png"); private static final ResourceLocation FALLBACK_TEXTURE = ResourceLocation.withDefaultNamespace("textures/block/stone.png");
@@ -102,7 +99,6 @@ public final class TigerEyeCamouflageTextureResolver {
try (NativeImage sourceImage = NativeImage.read(stream)) { try (NativeImage sourceImage = NativeImage.read(stream)) {
int tileWidth = sourceImage.getWidth(); int tileWidth = sourceImage.getWidth();
// Animated block textures stack frames vertically below a square first frame.
int tileHeight = tileWidth <= sourceImage.getHeight() ? tileWidth : sourceImage.getHeight(); int tileHeight = tileWidth <= sourceImage.getHeight() ? tileWidth : sourceImage.getHeight();
NativeImage canvas = new NativeImage(SKIN_SIZE, SKIN_SIZE, false); NativeImage canvas = new NativeImage(SKIN_SIZE, SKIN_SIZE, false);
@@ -94,9 +94,6 @@ public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
addVertex(consumer, pose, end.x + offset.x, end.y + offset.y, end.z + offset.z, red, green, blue, alpha); addVertex(consumer, pose, end.x + offset.x, end.y + offset.y, end.z + offset.z, red, green, blue, alpha);
addVertex(consumer, pose, start.x + offset.x, start.y + offset.y, start.z + offset.z, red, green, blue, alpha); addVertex(consumer, pose, start.x + offset.x, start.y + offset.y, start.z + offset.z, red, green, blue, alpha);
// The lightning render type can cull one winding from some camera
// angles. Emit the opposite winding as well so every ribbon is
// visible from both sides.
addVertex(consumer, pose, start.x + offset.x, start.y + offset.y, start.z + offset.z, red, green, blue, alpha); addVertex(consumer, pose, start.x + offset.x, start.y + offset.y, start.z + offset.z, red, green, blue, alpha);
addVertex(consumer, pose, end.x + offset.x, end.y + offset.y, end.z + offset.z, red, green, blue, alpha); addVertex(consumer, pose, end.x + offset.x, end.y + offset.y, end.z + offset.z, red, green, blue, alpha);
addVertex(consumer, pose, end.x - offset.x, end.y - offset.y, end.z - offset.z, red, green, blue, alpha); addVertex(consumer, pose, end.x - offset.x, end.y - offset.y, end.z - offset.z, red, green, blue, alpha);
@@ -48,9 +48,6 @@ public class GlimmerRenderer extends GeoEntityRenderer<GlimmerEntity> {
float growth = entity.getGrowthScale(); float growth = entity.getGrowthScale();
poseStack.scale(growth, growth, growth); poseStack.scale(growth, growth, growth);
// Compute body yaw directly from the entity's own tracked fields rather than trusting
// the ambient entityYaw parameter, so the body pose and the head-offset math below stay
// self-consistent.
float bodyYaw = Mth.rotLerp(partialTick, entity.yBodyRotO, entity.yBodyRot); float bodyYaw = Mth.rotLerp(partialTick, entity.yBodyRotO, entity.yBodyRot);
poseStack.mulPose(Axis.YP.rotationDegrees(180.0F - bodyYaw)); poseStack.mulPose(Axis.YP.rotationDegrees(180.0F - bodyYaw));
poseStack.scale(-1.0F, -1.0F, 1.0F); poseStack.scale(-1.0F, -1.0F, 1.0F);
@@ -82,7 +82,6 @@ public final class QueenLocateCommand {
return 0; return 0;
} }
/** Finds the nearest generated Queen spawn site without spawning her. Loads (and may generate) the checked chunks. */
public static NearestSite findNearestSite(ServerLevel thoraxis, int originX, int originZ) { public static NearestSite findNearestSite(ServerLevel thoraxis, int originX, int originZ) {
int cellX = Math.floorDiv(originX, QueenTrailGrid.SPACING); int cellX = Math.floorDiv(originX, QueenTrailGrid.SPACING);
int cellZ = Math.floorDiv(originZ, QueenTrailGrid.SPACING); int cellZ = Math.floorDiv(originZ, QueenTrailGrid.SPACING);
@@ -10,7 +10,6 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
/** Archive coordinate lookups for royals that live on grids rather than in vanilla structures. */
public final class AntarchyArchiveLocators { public final class AntarchyArchiveLocators {
private AntarchyArchiveLocators() { private AntarchyArchiveLocators() {
} }
@@ -10,7 +10,6 @@ import net.minecraft.nbt.ListTag;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.saveddata.SavedData; import net.minecraft.world.level.saveddata.SavedData;
/** Persistent Antarchy game progress keyed by AntOS computer location. */
public final class AntarchyGameSavedData extends SavedData { public final class AntarchyGameSavedData extends SavedData {
private static final String ID = "antarchy_computer_games"; private static final String ID = "antarchy_computer_games";
private final Map<String, GameState> games = new HashMap<>(); private final Map<String, GameState> games = new HashMap<>();
@@ -21,7 +21,7 @@ public final class BloodglassWardEffect extends MobEffect {
public void addAttributeModifiers(AttributeMap attributeMap, int amplifier) { public void addAttributeModifiers(AttributeMap attributeMap, int amplifier) {
AttributeInstance instance = attributeMap.getInstance(AntarchyObjects.BLOODGLASS_MAX_HEARTS.get()); AttributeInstance instance = attributeMap.getInstance(AntarchyObjects.BLOODGLASS_MAX_HEARTS.get());
if (instance == null) return; if (instance == null) return;
instance.addTransientModifier( instance.addOrUpdateTransientModifier(
new AttributeModifier(MODIFIER_ID, amplifier + 1, AttributeModifier.Operation.ADD_VALUE) new AttributeModifier(MODIFIER_ID, amplifier + 1, AttributeModifier.Operation.ADD_VALUE)
); );
} }
@@ -23,7 +23,7 @@ public final class GrowthMobEffect extends MobEffect {
AttributeInstance instance = attributeMap.getInstance(Attributes.SCALE); AttributeInstance instance = attributeMap.getInstance(Attributes.SCALE);
if (instance == null) return; if (instance == null) return;
double amount = AntarchySettings.growthPotionDelta() * (amplifier + 1); double amount = AntarchySettings.growthPotionDelta() * (amplifier + 1);
instance.addTransientModifier( instance.addOrUpdateTransientModifier(
new AttributeModifier(MODIFIER_ID, amount, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL) new AttributeModifier(MODIFIER_ID, amount, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)
); );
} }
@@ -1,6 +1,5 @@
package com.craisinlord.antarchy.content.effect; package com.craisinlord.antarchy.content.effect;
/** Synchronized, presentation-only state for the short-lived Royal Judgment mark. */
public interface JudgmentMarkAccess { public interface JudgmentMarkAccess {
boolean antarchy$isJudgmentMarked(); boolean antarchy$isJudgmentMarked();
@@ -14,14 +14,12 @@ import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
/** Server-owned, player-specific Judgment marks. The visible bit is synchronized by vanilla entity data. */
public final class JudgmentMarkManager { public final class JudgmentMarkManager {
private static final Map<ServerLevel, MarkBook> MARKS = new WeakHashMap<>(); private static final Map<ServerLevel, MarkBook> MARKS = new WeakHashMap<>();
private JudgmentMarkManager() { private JudgmentMarkManager() {
} }
/** Returns true when this owner had already marked this target before the current hit. */
public static boolean recordSuccessfulHit(Player owner, LivingEntity target) { public static boolean recordSuccessfulHit(Player owner, LivingEntity target) {
if (!(owner instanceof ServerPlayer serverPlayer) || !(target.level() instanceof ServerLevel level) if (!(owner instanceof ServerPlayer serverPlayer) || !(target.level() instanceof ServerLevel level)
|| owner.level() != target.level() || !hasGuardianArmor(owner) || !target.isAlive()) { || owner.level() != target.level() || !hasGuardianArmor(owner) || !target.isAlive()) {
@@ -66,7 +64,6 @@ public final class JudgmentMarkManager {
return entity instanceof LivingEntity living && living.isAlive() ? living : null; return entity instanceof LivingEntity living && living.isAlive() ? living : null;
} }
/** Prunes marks from this target and updates the vanilla-synchronized render bit. */
public static void tickTarget(LivingEntity target) { public static void tickTarget(LivingEntity target) {
if (!(target.level() instanceof ServerLevel level)) { if (!(target.level() instanceof ServerLevel level)) {
return; return;
@@ -23,7 +23,6 @@ import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.joml.Vector3f; import org.joml.Vector3f;
/** Server-authoritative Royal Guardian chestplate field and temporary projectile arrest state. */
public final class RoyalBoundaryManager { public final class RoyalBoundaryManager {
private static final int ALLY_REFRESH_INTERVAL = 10; private static final int ALLY_REFRESH_INTERVAL = 10;
private static final DustParticleOptions ROYAL_GOLD = new DustParticleOptions(new Vector3f(1.0F, 0.72F, 0.12F), 1.15F); private static final DustParticleOptions ROYAL_GOLD = new DustParticleOptions(new Vector3f(1.0F, 0.72F, 0.12F), 1.15F);
@@ -51,7 +50,6 @@ public final class RoyalBoundaryManager {
return true; return true;
} }
/** Called from ServerPlayer.tick; ends fields immediately when their owner can no longer sustain them. */
public static void tickOwner(ServerPlayer owner) { public static void tickOwner(ServerPlayer owner) {
if (!(owner.level() instanceof ServerLevel level)) return; if (!(owner.level() instanceof ServerLevel level)) return;
UUID ownerId = owner.getUUID(); UUID ownerId = owner.getUUID();
@@ -92,7 +90,6 @@ public final class RoyalBoundaryManager {
} }
} }
/** Predicts this tick's movement so a fast projectile is arrested before its own collision pass. */
public static void prepareProjectile(Projectile projectile) { public static void prepareProjectile(Projectile projectile) {
if (!(projectile.level() instanceof ServerLevel level) || projectile.isRemoved()) return; if (!(projectile.level() instanceof ServerLevel level) || projectile.isRemoved()) return;
Map<UUID, ArrestedProjectile> arrested = ARRESTED.get(level); Map<UUID, ArrestedProjectile> arrested = ARRESTED.get(level);
@@ -111,7 +108,6 @@ public final class RoyalBoundaryManager {
} }
} }
/** Swept fallback for unusual projectiles and arrest-state progression. */
public static void tickProjectile(Projectile projectile) { public static void tickProjectile(Projectile projectile) {
if (!(projectile.level() instanceof ServerLevel level)) return; if (!(projectile.level() instanceof ServerLevel level)) return;
Map<UUID, ArrestedProjectile> arrested = ARRESTED.get(level); Map<UUID, ArrestedProjectile> arrested = ARRESTED.get(level);
@@ -21,7 +21,7 @@ public final class RoyalVitalityPenaltyEffect extends MobEffect {
public void addAttributeModifiers(AttributeMap attributeMap, int amplifier) { public void addAttributeModifiers(AttributeMap attributeMap, int amplifier) {
AttributeInstance maxHealth = attributeMap.getInstance(Attributes.MAX_HEALTH); AttributeInstance maxHealth = attributeMap.getInstance(Attributes.MAX_HEALTH);
if (maxHealth == null) return; if (maxHealth == null) return;
maxHealth.addTransientModifier(new AttributeModifier( maxHealth.addOrUpdateTransientModifier(new AttributeModifier(
MODIFIER_ID, -0.5D, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)); MODIFIER_ID, -0.5D, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL));
} }
@@ -23,7 +23,7 @@ public final class ShrinkMobEffect extends MobEffect {
AttributeInstance instance = attributeMap.getInstance(Attributes.SCALE); AttributeInstance instance = attributeMap.getInstance(Attributes.SCALE);
if (instance == null) return; if (instance == null) return;
double amount = -(AntarchySettings.shrinkingPotionDelta() * (amplifier + 1)); double amount = -(AntarchySettings.shrinkingPotionDelta() * (amplifier + 1));
instance.addTransientModifier( instance.addOrUpdateTransientModifier(
new AttributeModifier(MODIFIER_ID, amount, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL) new AttributeModifier(MODIFIER_ID, amount, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)
); );
} }
@@ -408,10 +408,6 @@ public class FlytrapEntity extends Monster implements GeoEntity {
continue; continue;
} }
// Put the entity on cooldown before hurting it, regardless of hurt()'s result: a
// shield or armor effect can absorb the damage and make hurt() return false without
// granting the vanilla invulnerability window, which would otherwise let this attack
// re-attempt damage on the same entity every single tick of the active window.
this.sweepHitCooldowns.put(candidate.getUUID(), AntarchySettings.flytrapSweepHitCooldownTicks()); this.sweepHitCooldowns.put(candidate.getUUID(), AntarchySettings.flytrapSweepHitCooldownTicks());
candidate.hurt(AntarchyDamageSources.flytrapMauling(serverLevel, this), (float) AntarchySettings.flytrapAttackDamage()); candidate.hurt(AntarchyDamageSources.flytrapMauling(serverLevel, this), (float) AntarchySettings.flytrapAttackDamage());
} }
@@ -391,6 +391,9 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
if (this.isKnockedDown()) { if (this.isKnockedDown()) {
this.tickKnockedDown(); this.tickKnockedDown();
} else if (this.isLeashed()) { } else if (this.isLeashed()) {
if (this.chargeTicksRemaining > 0 || this.isChargeAnimationActive()) {
this.endChargeState();
}
this.getNavigation().stop(); this.getNavigation().stop();
this.setTarget(null); this.setTarget(null);
this.updateAmbientAnimation(); this.updateAmbientAnimation();
@@ -483,6 +486,10 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
} }
private void tickCharge() { private void tickCharge() {
if (this.chargeTicksRemaining <= 0) {
this.endChargeState();
return;
}
if (this.getAnimationState() != ANIM_CHARGE) { if (this.getAnimationState() != ANIM_CHARGE) {
this.setAnimationState(ANIM_CHARGE); this.setAnimationState(ANIM_CHARGE);
} }
@@ -909,6 +916,9 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
if (!this.isFlying() && !mountedCharge) { if (!this.isFlying() && !mountedCharge) {
this.pendingChargeStart = true; this.pendingChargeStart = true;
this.requestFlightStart(); this.requestFlightStart();
if (this.getAnimationState() != ANIM_OPEN_WINGS) {
this.pendingChargeStart = false;
}
return; return;
} }
this.beginChargeStart(this.chargeDirection, this.pendingChargeDuration, mountedCharge); this.beginChargeStart(this.chargeDirection, this.pendingChargeDuration, mountedCharge);
@@ -978,11 +988,21 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
serverLevel.sendParticles(ParticleTypes.CRIT, this.getX(), this.getY() + 0.8D, this.getZ(), 20, 2.0D, 0.6D, 2.0D, 0.08D); serverLevel.sendParticles(ParticleTypes.CRIT, this.getX(), this.getY() + 0.8D, this.getZ(), 20, 2.0D, 0.6D, 2.0D, 0.08D);
this.broadcastImpactShake(serverLevel); this.broadcastImpactShake(serverLevel);
if (this.onGround()) { this.endChargeState();
this.requestFlightStop();
} else {
this.updateAmbientAnimation();
} }
private void endChargeState() {
this.chargeTicksRemaining = 0;
this.groundedMountedCharge = false;
this.noPhysics = false;
this.setAnimationState(this.isFlying() ? ANIM_FLY : ANIM_IDLE);
if (!this.isVehicle() && this.isFlying() && this.hasGroundBelow()) {
this.requestFlightStop();
}
}
private boolean hasGroundBelow() {
return !this.level().noCollision(this, this.getBoundingBox().move(this.toWorld(0.0D, -0.2D, 0.0D)));
} }
private void breakBlocksForChargeImpact(ServerLevel level) { private void breakBlocksForChargeImpact(ServerLevel level) {
@@ -1423,6 +1443,9 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
this.chargeCooldown = tag.getInt("ChargeCooldown"); this.chargeCooldown = tag.getInt("ChargeCooldown");
this.attackCooldown = tag.getInt("AttackCooldown"); this.attackCooldown = tag.getInt("AttackCooldown");
this.combatCryDone = tag.getBoolean("CombatCryDone"); this.combatCryDone = tag.getBoolean("CombatCryDone");
if (this.isChargeAnimationActive()) {
this.setAnimationState(this.isFlying() ? ANIM_FLY : ANIM_IDLE);
}
if (this.isKnockedDown() && this.getAnimationState() != ANIM_KNOCKED_DOWN_IDLE) { if (this.isKnockedDown() && this.getAnimationState() != ANIM_KNOCKED_DOWN_IDLE) {
this.setAnimationState(ANIM_KNOCKED_DOWN_IDLE); this.setAnimationState(ANIM_KNOCKED_DOWN_IDLE);
} }
@@ -149,12 +149,10 @@ public class MantisEntity extends Monster implements GeoEntity {
boolean ignoreLightLevel = AntarchySettings.mantisIgnoreLightLevel(); boolean ignoreLightLevel = AntarchySettings.mantisIgnoreLightLevel();
// Daytime overworld spawns can't pass the vanilla darkness check, so no light gate here
if (level.getLevel().isDay() && level.getBiome(pos).is(AntarchyTags.Biomes.MANTIS_OVERWORLD_SPAWN_BIOMES)) { if (level.getLevel().isDay() && level.getBiome(pos).is(AntarchyTags.Biomes.MANTIS_OVERWORLD_SPAWN_BIOMES)) {
return atSurface && level.canSeeSky(pos); return atSurface && level.canSeeSky(pos);
} }
// Elythia meadow (and any future mantis_spawn_biomes): nighttime, no sky-access requirement
if (level.getLevel().isNight() && level.getBiome(pos).is(AntarchyTags.Biomes.MANTIS_SPAWN_BIOMES)) { if (level.getLevel().isNight() && level.getBiome(pos).is(AntarchyTags.Biomes.MANTIS_SPAWN_BIOMES)) {
return atSurface && (ignoreLightLevel || Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random)); return atSurface && (ignoreLightLevel || Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random));
} }
@@ -184,7 +182,6 @@ public class MantisEntity extends Monster implements GeoEntity {
HurtByTargetGoal hurtByTargetGoal = new HurtByTargetGoal(this); HurtByTargetGoal hurtByTargetGoal = new HurtByTargetGoal(this);
this.targetSelector.addGoal(1, hurtByTargetGoal); this.targetSelector.addGoal(1, hurtByTargetGoal);
// randomInterval lowered from default 10 to 5 for faster re-acquisition
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 5, true, false, null)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 5, true, false, null));
} }
@@ -88,7 +88,6 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
private boolean spawnedByKraken; private boolean spawnedByKraken;
// Explosive impact (fired from the R.P.O. Launcher)
private boolean explosiveImpact; private boolean explosiveImpact;
private java.util.UUID explosiveLauncherId; private java.util.UUID explosiveLauncherId;
private int explosiveArmTicks; private int explosiveArmTicks;
@@ -140,9 +139,7 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 20.0F)); this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 20.0F));
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
// Only retaliate when hit — neutral otherwise
this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
// When spawned by Kraken and flying, target nearest player
this.targetSelector.addGoal(2, new KrakenSummonTargetGoal(this)); this.targetSelector.addGoal(2, new KrakenSummonTargetGoal(this));
} }
@@ -215,7 +212,6 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
if (this.attackCooldown > 0) this.attackCooldown--; if (this.attackCooldown > 0) this.attackCooldown--;
if (this.inkSprayCooldown > 0) this.inkSprayCooldown--; if (this.inkSprayCooldown > 0) this.inkSprayCooldown--;
// Ink spray — always active regardless of aggro state
this.tickInkSpray(); this.tickInkSpray();
LivingEntity target = this.getTarget(); LivingEntity target = this.getTarget();
@@ -375,10 +371,9 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
float angle = this.random.nextFloat() * (float) (Math.PI * 2); float angle = this.random.nextFloat() * (float) (Math.PI * 2);
this.wanderDx = Mth.cos(angle) * 0.015f; this.wanderDx = Mth.cos(angle) * 0.015f;
this.wanderDz = Mth.sin(angle) * 0.015f; this.wanderDz = Mth.sin(angle) * 0.015f;
this.wanderDy = -0.01f + this.random.nextFloat() * 0.01f; // slight downward bias this.wanderDy = -0.01f + this.random.nextFloat() * 0.01f;
} }
// Surface avoidance: if the block above is not water, push down
float dy = this.wanderDy; float dy = this.wanderDy;
if (!this.level().getFluidState(this.blockPosition().above()).is(net.minecraft.tags.FluidTags.WATER)) { if (!this.level().getFluidState(this.blockPosition().above()).is(net.minecraft.tags.FluidTags.WATER)) {
dy = -0.03f; dy = -0.03f;
@@ -663,10 +658,6 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
} }
} }
// -------------------------------------------------------------------------
// Inner goal: only target players when spawned by Kraken in fly mode
// -------------------------------------------------------------------------
private static final class KrakenSummonTargetGoal extends NearestAttackableTargetGoal<Player> { private static final class KrakenSummonTargetGoal extends NearestAttackableTargetGoal<Player> {
private final OctopusBombEntity octopus; private final OctopusBombEntity octopus;
@@ -84,7 +84,6 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
private static final int ANIM_ROLL_UP = 2; private static final int ANIM_ROLL_UP = 2;
private static final int ANIM_UNROLL = 4; private static final int ANIM_UNROLL = 4;
// wheel_mode is 0.75s, normal_mode is ~0.42s
private static final int ROLL_UP_TICKS = 15; private static final int ROLL_UP_TICKS = 15;
private static final int UNROLL_TICKS = 9; private static final int UNROLL_TICKS = 9;
private static final int DEFENSIVE_CURL_TICKS = 100; private static final int DEFENSIVE_CURL_TICKS = 100;
@@ -156,7 +155,6 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D) { this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D) {
@Override @Override
public boolean canUse() { public boolean canUse() {
// Curled-up or tamed rolly pollies stand their ground
return !RollyPollyEntity.this.isRolled() && !RollyPollyEntity.this.isTame() && super.canUse(); return !RollyPollyEntity.this.isRolled() && !RollyPollyEntity.this.isTame() && super.canUse();
} }
}); });
@@ -318,7 +316,6 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
amount *= 0.25F; amount *= 0.25F;
} }
boolean hurt = super.hurt(source, amount); boolean hurt = super.hurt(source, amount);
// Wild rolly pollies curl up defensively when attacked
if (hurt && !this.level().isClientSide && !this.isTame() && this.isAlive() if (hurt && !this.level().isClientSide && !this.isTame() && this.isAlive()
&& !this.isRolled() && this.rollTransitionTicks <= 0) { && !this.isRolled() && this.rollTransitionTicks <= 0) {
this.defensiveCurlTicks = DEFENSIVE_CURL_TICKS; this.defensiveCurlTicks = DEFENSIVE_CURL_TICKS;
@@ -111,9 +111,6 @@ public class ScorpionEntity extends Monster implements GeoEntity {
|| spawnReason == MobSpawnType.COMMAND) { || spawnReason == MobSpawnType.COMMAND) {
return true; return true;
} }
// The Dream Dunes biome is the entire underside below Y=0. Its higher
// spawn weight is therefore targeted there without doubling the small
// surface-side Dream Dunes band as well.
if (pos.getY() >= 0 && level.getBiome(pos).is(DREAM_DUNES) && random.nextBoolean()) { if (pos.getY() >= 0 && level.getBiome(pos).is(DREAM_DUNES) && random.nextBoolean()) {
return false; return false;
} }
@@ -356,8 +353,6 @@ public class ScorpionEntity extends Monster implements GeoEntity {
ScorpionEntity.this.getNavigation().stop(); ScorpionEntity.this.getNavigation().stop();
return; return;
} }
// This goal overrides MeleeAttackGoal.tick, so the gravity mixin on the
// vanilla method cannot supply the inverted movement frame here.
LivingEntity target = ScorpionEntity.this.getTarget(); LivingEntity target = ScorpionEntity.this.getTarget();
if (target != null && ThoraxisUndersideManager.shouldInvertInUnderside(ScorpionEntity.this)) { if (target != null && ThoraxisUndersideManager.shouldInvertInUnderside(ScorpionEntity.this)) {
ScorpionEntity.this.getNavigation().stop(); ScorpionEntity.this.getNavigation().stop();
@@ -379,9 +374,6 @@ public class ScorpionEntity extends Monster implements GeoEntity {
if (ScorpionEntity.this.isAttackLocked()) { if (ScorpionEntity.this.isAttackLocked()) {
return; return;
} }
// Inverted melee tick handling replaces vanilla MeleeAttackGoal.tick,
// so vanilla's internal attack timer is not advanced. The Scorpion's
// own cooldown already covers its wind-up and hit timing.
if (this.canPerformAttack(enemy) && ScorpionEntity.this.attackCooldownTicks <= 0) { if (this.canPerformAttack(enemy) && ScorpionEntity.this.attackCooldownTicks <= 0) {
ScorpionEntity.this.beginAttack(enemy); ScorpionEntity.this.beginAttack(enemy);
return; return;
@@ -774,11 +774,9 @@ public class ToreterrorEntity extends Monster implements GeoEntity {
double dh = Math.sqrt(diff.x * diff.x + diff.z * diff.z); double dh = Math.sqrt(diff.x * diff.x + diff.z * diff.z);
double dy = diff.y; double dy = diff.y;
double gravity = AntarchySettings.waterBombGravity(); double gravity = AntarchySettings.waterBombGravity();
// Choose travel time based on horizontal distance at minSpeed, minimum 8 ticks
double t = Math.max(8.0, dh / minSpeed); double t = Math.max(8.0, dh / minSpeed);
double vx = diff.x / t; double vx = diff.x / t;
double vz = diff.z / t; double vz = diff.z / t;
// Compensate for gravity accumulating over t ticks
double vy = dy / t + 0.5 * gravity * t; double vy = dy / t + 0.5 * gravity * t;
return new Vec3(vx, vy, vz); return new Vec3(vx, vy, vz);
} }
@@ -46,10 +46,6 @@ public class UpwardFallingBlockEntity extends Entity {
public UpwardFallingBlockEntity(EntityType<UpwardFallingBlockEntity> type, Level level) { public UpwardFallingBlockEntity(EntityType<UpwardFallingBlockEntity> type, Level level) {
super(type, level); super(type, level);
// This entity has its own simple upward-flight and landing checks below. Do not
// send it through the normal entity collision solver: Thoraxis can create many of
// these at once while chunks are loading, and swept entity collision is needlessly
// expensive for a block that only collides with the block directly above it.
this.noPhysics = true; this.noPhysics = true;
} }
@@ -148,8 +144,6 @@ public class UpwardFallingBlockEntity extends Entity {
BlockPos headPos = BlockPos.containing(getX(), getBoundingBox().maxY, getZ()); BlockPos headPos = BlockPos.containing(getX(), getBoundingBox().maxY, getZ());
BlockState above = level().getBlockState(headPos); BlockState above = level().getBlockState(headPos);
// Leaves block the entity but can't hold scaffolding — drop as item, unless this
// instance is allowed to land on leaves like a normal falling block would
if (above.is(BlockTags.LEAVES) && this.breaksOnLeaves) { if (above.is(BlockTags.LEAVES) && this.breaksOnLeaves) {
dropAndRemove(blockState); dropAndRemove(blockState);
return; return;
@@ -15,10 +15,6 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
/**
* Thrown out by the worm hook item. Sticks into the first block it hits and stays there,
* anchoring a swing rope back to the thrower until the player detaches.
*/
public class WormHookProjectileEntity extends ThrowableItemProjectile { public class WormHookProjectileEntity extends ThrowableItemProjectile {
private boolean stuck = false; private boolean stuck = false;
@@ -302,8 +302,6 @@ public final class AntTeleportHelper {
return safePos; return safePos;
} }
// The bounded search can fail near rough or sparsely-generated terrain.
// Retry once with a wider radius before giving up.
loadArrivalSearchArea(destination, preferredPos, EXPANDED_ARRIVAL_SEARCH_RADIUS); loadArrivalSearchArea(destination, preferredPos, EXPANDED_ARRIVAL_SEARCH_RADIUS);
Vec3 expandedSafePos = findSafeArrivalPositionInYRange( Vec3 expandedSafePos = findSafeArrivalPositionInYRange(
player, destination, preferredPos, yRange[0], yRange[1], player, destination, preferredPos, yRange[0], yRange[1],
@@ -393,11 +391,6 @@ public final class AntTeleportHelper {
return null; return null;
} }
/**
* Arrival validation needs neighboring chunks for collision checks. Load a
* bounded area up front so unloaded terrain is not mistaken for an unsafe
* destination and rejected prematurely.
*/
public static void loadArrivalSearchArea(ServerLevel destination, BlockPos preferredPos, int searchRadius) { public static void loadArrivalSearchArea(ServerLevel destination, BlockPos preferredPos, int searchRadius) {
ChunkPos center = new ChunkPos(preferredPos); ChunkPos center = new ChunkPos(preferredPos);
int chunkRadius = (searchRadius >> 4) + 1; int chunkRadius = (searchRadius >> 4) + 1;
@@ -462,9 +455,6 @@ public final class AntTeleportHelper {
} }
} }
// Prefer actual generated surfaces. This is especially important in
// Elythia, where the configured spawn height is not necessarily the
// playable surface.
for (BlockPos candidate : surfaceCandidates) { for (BlockPos candidate : surfaceCandidates) {
if (candidate.getY() < minY || candidate.getY() > maxY) { if (candidate.getY() < minY || candidate.getY() > maxY) {
continue; continue;
@@ -475,15 +465,10 @@ public final class AntTeleportHelper {
} }
} }
// Elythia arrivals must stay on the generated surface; a vertical scan
// can otherwise select an underground cave floor after a surface miss.
if (elythia) { if (elythia) {
return null; return null;
} }
// Heightmaps can be stale or unsuitable around structures, so retain a
// bounded exhaustive search as a final generated-terrain attempt in
// dimensions whose configured arrival ranges intentionally allow it.
for (int radius = 0; radius <= searchRadius; radius++) { for (int radius = 0; radius <= searchRadius; radius++) {
for (int xOff = -radius; xOff <= radius; xOff++) { for (int xOff = -radius; xOff <= radius; xOff++) {
for (int zOff = -radius; zOff <= radius; zOff++) { for (int zOff = -radius; zOff <= radius; zOff++) {
@@ -78,11 +78,6 @@ public class RainbowAntEntity extends BaseAntEntity implements GeoEntity {
return this.hasActiveInfinityDestination() || super.requiresCustomPersistence(); return this.hasActiveInfinityDestination() || super.requiresCustomPersistence();
} }
/**
* Called on death. If this ant has already been activated (fed its reagent) and Infinity integration is
* enabled, looks for a nearby unlit obsidian Nether-portal frame and, if found, ignites it as a permanent
* physical Infinity Dimensions portal to this ant's assigned dimension.
*/
public boolean tryIgniteInfinityPortalOnDeath() { public boolean tryIgniteInfinityPortalOnDeath() {
if (!this.infinityActivated) { if (!this.infinityActivated) {
return false; return false;
@@ -260,7 +260,6 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity {
} }
continue; continue;
} }
// North/South faces (dz = ±r)
for (int dx = -r; dx <= r; dx++) { for (int dx = -r; dx <= r; dx++) {
candidate.set(ox + dx, oy + dy, oz - r); candidate.set(ox + dx, oy + dy, oz - r);
if (this.isValidWoodTarget(candidate)) { if (this.isValidWoodTarget(candidate)) {
@@ -273,7 +272,6 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity {
if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); } if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); }
} }
} }
// East/West faces (dx = ±r, corners already covered above)
for (int dz = -r + 1; dz <= r - 1; dz++) { for (int dz = -r + 1; dz <= r - 1; dz++) {
candidate.set(ox - r, oy + dy, oz + dz); candidate.set(ox - r, oy + dy, oz + dz);
if (this.isValidWoodTarget(candidate)) { if (this.isValidWoodTarget(candidate)) {
@@ -669,13 +669,11 @@ public class BasiliskEntity extends Monster implements GeoEntity {
this.stopActiveMovement(); this.stopActiveMovement();
} }
/** Scales turn rate by intended movement speed so the long body pivots tighter when slow and wider when fast. */
private static final class BasiliskMoveControl extends MoveControl { private static final class BasiliskMoveControl extends MoveControl {
private BasiliskMoveControl(Mob mob) { private BasiliskMoveControl(Mob mob) {
super(mob); super(mob);
} }
/** Call this to prevent the move control from reapplying speed this tick. */
public void halt() { public void halt() {
this.operation = MoveControl.Operation.WAIT; this.operation = MoveControl.Operation.WAIT;
} }
@@ -735,7 +733,6 @@ public class BasiliskEntity extends Monster implements GeoEntity {
BasiliskEntity.this.getLookControl().setLookAt(target, 30.0F, 30.0F); BasiliskEntity.this.getLookControl().setLookAt(target, 30.0F, 30.0F);
} }
// super handles path recalc and cooldown timer
super.tick(); super.tick();
if (target != null && BasiliskEntity.this.isWithinMeleeAttackRange(target)) { if (target != null && BasiliskEntity.this.isWithinMeleeAttackRange(target)) {
Loaded 100 of 222 files, more files were not shown because too many files have changed in this diff. Show more