diff --git a/common/src/main/java/com/craisinlord/antarchy/content/AntarchyObjects.java b/common/src/main/java/com/craisinlord/antarchy/content/AntarchyObjects.java index 01232839..f36e053f 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/AntarchyObjects.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/AntarchyObjects.java @@ -225,6 +225,8 @@ public final class AntarchyObjects { public static Supplier> HUSHWEED_BLOCK_ENTITY = (Supplier>) UNBOUND; @SuppressWarnings("unchecked") public static Supplier STINKY_GAS = (Supplier) UNBOUND; + @SuppressWarnings("unchecked") + public static Supplier STINKY_FLY = (Supplier) UNBOUND; private AntarchyObjects() { } @@ -316,6 +318,7 @@ public final class AntarchyObjects { Supplier> waspNestBlockEntity, Supplier> hushweedBlockEntity, Supplier stinkyGas, + Supplier stinkyFly, Supplier> doubleDamageChance, Supplier> bloodglassMaxHearts, Supplier> bloodglassWard @@ -406,6 +409,7 @@ public final class AntarchyObjects { WASP_NEST_BLOCK_ENTITY = waspNestBlockEntity; HUSHWEED_BLOCK_ENTITY = hushweedBlockEntity; STINKY_GAS = stinkyGas; + STINKY_FLY = stinkyFly; DOUBLE_DAMAGE_CHANCE = doubleDamageChance; BLOODGLASS_MAX_HEARTS = bloodglassMaxHearts; BLOODGLASS_WARD = bloodglassWard; diff --git a/common/src/main/java/com/craisinlord/antarchy/content/StinkyBehavior.java b/common/src/main/java/com/craisinlord/antarchy/content/StinkyBehavior.java index 2ae08064..5bdb11b1 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/StinkyBehavior.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/StinkyBehavior.java @@ -12,7 +12,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public final class StinkyBehavior { - public static final int STINKY_EFFECT_DURATION_TICKS = 60; public static final double STINK_BUG_AURA_RADIUS = 5.0D; public static final double STINKY_NAUSEA_RADIUS = 4.0D; private static final int TRAIL_INTERVAL_TICKS = 4; @@ -59,6 +58,17 @@ public final class StinkyBehavior { entity.getBbWidth() * 0.12D, 0.005D ); + serverLevel.sendParticles( + AntarchyObjects.STINKY_FLY.get(), + entity.getX(), + entity.getY(0.45D), + entity.getZ(), + 1, + entity.getBbWidth() * 0.35D, + entity.getBbHeight() * 0.2D, + entity.getBbWidth() * 0.35D, + 0.0D + ); applyNearbyNausea(entity, STINKY_NAUSEA_RADIUS, STINKY_NAUSEA_DURATION_TICKS); if (entity.tickCount % REACTION_INTERVAL_TICKS == 0) { reactToStinkySource(entity); @@ -80,6 +90,17 @@ public final class StinkyBehavior { entity.getBbWidth() * 0.35D, 0.045D ); + serverLevel.sendParticles( + AntarchyObjects.STINKY_FLY.get(), + entity.getX(), + entity.getY(0.45D), + entity.getZ(), + Math.max(2, count / 6), + entity.getBbWidth() * 0.45D, + entity.getBbHeight() * 0.25D, + entity.getBbWidth() * 0.45D, + 0.0D + ); applyNearbyNausea(entity, STINK_BUG_AURA_RADIUS, STINK_BUG_BURST_NAUSEA_DURATION_TICKS); } @@ -108,6 +129,9 @@ public final class StinkyBehavior { mob -> mob.isAlive() && mob != source )) { if (mob.getType().is(EntityTypeTags.SENSITIVE_TO_BANE_OF_ARTHROPODS)) { + if (source.getType().is(EntityTypeTags.SENSITIVE_TO_BANE_OF_ARTHROPODS)) { + continue; + } attractArthropod(mob, source); continue; } @@ -167,4 +191,5 @@ public final class StinkyBehavior { } return !mob.isAlliedTo(source); } + } diff --git a/common/src/main/java/com/craisinlord/antarchy/content/block/CreepingHorrorEggBlock.java b/common/src/main/java/com/craisinlord/antarchy/content/block/CreepingHorrorEggBlock.java index 0d21a0fa..ea6bb9b0 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/block/CreepingHorrorEggBlock.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/block/CreepingHorrorEggBlock.java @@ -2,6 +2,7 @@ package com.craisinlord.antarchy.content.block; import com.craisinlord.antarchy.content.AntarchyObjects; import com.craisinlord.antarchy.content.entity.CreepingHorrorEntity; +import com.craisinlord.antarchy.content.block.AmberMossBlock; import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -87,7 +88,7 @@ public class CreepingHorrorEggBlock extends Block { @Override protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - if (!this.shouldUpdateHatchLevel(level)) { + if (!this.shouldUpdateHatchLevel(level, pos)) { return; } @@ -174,8 +175,9 @@ public class CreepingHorrorEggBlock extends Block { level.setBlock(pos, state.setValue(EGGS, eggs - 1), 2); } - private boolean shouldUpdateHatchLevel(Level level) { - return level.random.nextInt(500) == 0; + private boolean shouldUpdateHatchLevel(Level level, BlockPos pos) { + boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock; + return level.random.nextInt(onAmberMoss ? 150 : 500) == 0; } private boolean canDestroyEgg(Level level, Entity entity) { diff --git a/common/src/main/java/com/craisinlord/antarchy/content/block/LurkingTerrorEggBlock.java b/common/src/main/java/com/craisinlord/antarchy/content/block/LurkingTerrorEggBlock.java index a3f16236..c99b4e7f 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/block/LurkingTerrorEggBlock.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/block/LurkingTerrorEggBlock.java @@ -2,6 +2,7 @@ package com.craisinlord.antarchy.content.block; import com.craisinlord.antarchy.content.AntarchyObjects; import com.craisinlord.antarchy.content.entity.LurkingTerrorEntity; +import com.craisinlord.antarchy.content.block.AmberMossBlock; import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -87,7 +88,7 @@ public class LurkingTerrorEggBlock extends Block { @Override protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { - if (!this.shouldUpdateHatchLevel(level)) { + if (!this.shouldUpdateHatchLevel(level, pos)) { return; } @@ -174,8 +175,9 @@ public class LurkingTerrorEggBlock extends Block { level.setBlock(pos, state.setValue(EGGS, eggs - 1), 2); } - private boolean shouldUpdateHatchLevel(Level level) { - return level.random.nextInt(500) == 0; + private boolean shouldUpdateHatchLevel(Level level, BlockPos pos) { + boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock; + return level.random.nextInt(onAmberMoss ? 150 : 500) == 0; } private boolean canDestroyEgg(Level level, Entity entity) { diff --git a/common/src/main/java/com/craisinlord/antarchy/content/entity/LurkingTerrorEntity.java b/common/src/main/java/com/craisinlord/antarchy/content/entity/LurkingTerrorEntity.java index 3a44ad3b..bd99d51f 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/entity/LurkingTerrorEntity.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/entity/LurkingTerrorEntity.java @@ -111,8 +111,11 @@ public class LurkingTerrorEntity extends Monster implements GeoEntity { } return state.setAndContinue(ATTACK_LAND_ANIM); } + if (!this.onGround()) { + return state.setAndContinue(FLY_ANIM); + } if (state.isMoving()) { - return state.setAndContinue(this.onGround() ? WALK_ANIM : FLY_ANIM); + return state.setAndContinue(WALK_ANIM); } return state.setAndContinue(IDLE_ANIM); } diff --git a/common/src/main/java/com/craisinlord/antarchy/content/entity/OctopusBombEntity.java b/common/src/main/java/com/craisinlord/antarchy/content/entity/OctopusBombEntity.java index 527f7513..ecc3edbe 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/entity/OctopusBombEntity.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/entity/OctopusBombEntity.java @@ -334,11 +334,18 @@ public class OctopusBombEntity extends Monster implements GeoEntity { if (--this.wanderRetargetTicks <= 0) { this.wanderRetargetTicks = 40 + this.random.nextInt(40); float angle = this.random.nextFloat() * (float) (Math.PI * 2); - this.wanderDx = Mth.cos(angle) * 0.1f; - this.wanderDy = -0.05f + this.random.nextFloat() * 0.1f; - this.wanderDz = Mth.sin(angle) * 0.1f; + this.wanderDx = Mth.cos(angle) * 0.015f; + this.wanderDz = Mth.sin(angle) * 0.015f; + this.wanderDy = -0.01f + this.random.nextFloat() * 0.01f; // slight downward bias } - this.setDeltaMovement(this.getDeltaMovement().add(this.wanderDx, this.wanderDy, this.wanderDz)); + + // Surface avoidance: if the block above is not water, push down + float dy = this.wanderDy; + if (!this.level().getFluidState(this.blockPosition().above()).is(net.minecraft.tags.FluidTags.WATER)) { + dy = -0.03f; + } + + this.setDeltaMovement(this.getDeltaMovement().add(this.wanderDx, dy, this.wanderDz)); } // ------------------------------------------------------------------------- diff --git a/common/src/main/java/com/craisinlord/antarchy/content/entity/ant/TermiteEntity.java b/common/src/main/java/com/craisinlord/antarchy/content/entity/ant/TermiteEntity.java index 70afc6ff..c90772d3 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/entity/ant/TermiteEntity.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/entity/ant/TermiteEntity.java @@ -4,6 +4,7 @@ import com.craisinlord.antarchy.content.AntarchyTags; import com.craisinlord.antarchy.config.AntarchySettings; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; import net.minecraft.resources.ResourceKey; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.EntityType; @@ -18,10 +19,21 @@ import software.bernie.geckolib.animatable.GeoEntity; public class TermiteEntity extends BaseAntEntity implements GeoEntity { private static final int WOOD_BITE_ANIMATION_TICKS = 8; - private static final int WOOD_SEARCH_INTERVAL_TICKS = 10; + private static final int WOOD_SEARCH_INTERVAL_TICKS = 20; private static final int WOOD_REPATH_INTERVAL_TICKS = 6; private static final int WOOD_SEARCH_RADIUS_HORIZONTAL = 12; private static final int WOOD_SEARCH_RADIUS_VERTICAL = 4; + private static final Vec3i[] IMMEDIATE_WOOD_OFFSETS = { + new Vec3i(0, 1, 0), + new Vec3i(0, 0, -1), + new Vec3i(0, 0, 1), + new Vec3i(1, 0, 0), + new Vec3i(-1, 0, 0), + new Vec3i(0, 1, -1), + new Vec3i(0, 1, 1), + new Vec3i(1, 1, 0), + new Vec3i(-1, 1, 0), + }; @Nullable private BlockPos targetWoodPos; private int nextWoodSearchTick; @@ -125,7 +137,9 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity { } private boolean tryEatNearbyWood() { - for (BlockPos targetPos : this.getImmediateWoodChecks()) { + BlockPos basePos = this.blockPosition(); + for (Vec3i offset : IMMEDIATE_WOOD_OFFSETS) { + BlockPos targetPos = basePos.offset(offset); BlockState targetState = this.level().getBlockState(targetPos); if (!targetState.is(AntarchyTags.Blocks.TERMITE_FOODS)) { continue; @@ -141,22 +155,6 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity { return false; } - private BlockPos[] getImmediateWoodChecks() { - BlockPos basePos = this.blockPosition(); - BlockPos abovePos = basePos.above(); - return new BlockPos[] { - basePos.above(), - basePos.north(), - basePos.south(), - basePos.east(), - basePos.west(), - abovePos.north(), - abovePos.south(), - abovePos.east(), - abovePos.west() - }; - } - @Nullable private BlockPos getCurrentWoodTarget() { if (this.targetWoodPos != null && this.isValidWoodTarget(this.targetWoodPos)) { @@ -175,20 +173,52 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity { @Nullable private BlockPos findClosestWoodTarget() { BlockPos origin = this.blockPosition(); + int ox = origin.getX(); + int oy = origin.getY(); + int oz = origin.getZ(); BlockPos bestPos = null; - double bestDistance = Double.MAX_VALUE; + double bestDistSq = Double.MAX_VALUE; + BlockPos.MutableBlockPos candidate = new BlockPos.MutableBlockPos(); - for (BlockPos pos : BlockPos.betweenClosed( - origin.offset(-WOOD_SEARCH_RADIUS_HORIZONTAL, -WOOD_SEARCH_RADIUS_VERTICAL, -WOOD_SEARCH_RADIUS_HORIZONTAL), - origin.offset(WOOD_SEARCH_RADIUS_HORIZONTAL, WOOD_SEARCH_RADIUS_VERTICAL + 2, WOOD_SEARCH_RADIUS_HORIZONTAL))) { - if (!this.isValidWoodTarget(pos)) { - continue; + for (int r = 0; r <= WOOD_SEARCH_RADIUS_HORIZONTAL; r++) { + if (bestPos != null && bestDistSq <= (double)(r * r)) { + break; } - - double distance = pos.distSqr(origin); - if (distance < bestDistance) { - bestDistance = distance; - bestPos = pos.immutable(); + for (int dy = -WOOD_SEARCH_RADIUS_VERTICAL; dy <= WOOD_SEARCH_RADIUS_VERTICAL + 2; dy++) { + if (r == 0) { + candidate.set(ox, oy + dy, oz); + if (this.isValidWoodTarget(candidate)) { + double d = candidate.distSqr(origin); + if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); } + } + continue; + } + // North/South faces (dz = ±r) + for (int dx = -r; dx <= r; dx++) { + candidate.set(ox + dx, oy + dy, oz - r); + if (this.isValidWoodTarget(candidate)) { + double d = candidate.distSqr(origin); + if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); } + } + candidate.set(ox + dx, oy + dy, oz + r); + if (this.isValidWoodTarget(candidate)) { + double d = candidate.distSqr(origin); + 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++) { + candidate.set(ox - r, oy + dy, oz + dz); + if (this.isValidWoodTarget(candidate)) { + double d = candidate.distSqr(origin); + if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); } + } + candidate.set(ox + r, oy + dy, oz + dz); + if (this.isValidWoodTarget(candidate)) { + double d = candidate.distSqr(origin); + if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); } + } + } } } @@ -222,9 +252,10 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity { } private boolean isWalkableStandPos(BlockPos pos) { - BlockState floorState = this.level().getBlockState(pos.below()); + BlockPos floor = pos.below(); + BlockState floorState = this.level().getBlockState(floor); return this.level().getBlockState(pos).isAir() && this.level().getBlockState(pos.above()).isAir() - && floorState.isFaceSturdy(this.level(), pos.below(), Direction.UP); + && floorState.isFaceSturdy(this.level(), floor, Direction.UP); } } diff --git a/common/src/main/java/com/craisinlord/antarchy/content/item/BigBerthaItem.java b/common/src/main/java/com/craisinlord/antarchy/content/item/BigBerthaItem.java index ce7d56a4..0ffc3755 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/item/BigBerthaItem.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/item/BigBerthaItem.java @@ -62,6 +62,14 @@ public class BigBerthaItem extends SwordItem implements GeoItem { private static final String SPIN_TICKS_TAG = "antarchy.big_bertha_spin_ticks"; private static final String SPIN_DIRECTION_X_TAG = "antarchy.big_bertha_spin_direction_x"; private static final String SPIN_DIRECTION_Z_TAG = "antarchy.big_bertha_spin_direction_z"; + private static final String TORETERROR_JUMPING_TAG = "antarchy.toreterror_jumping"; + private static final String TORETERROR_LAUNCHED_TAG = "antarchy.toreterror_launched"; + private static final int TORETERROR_LANDING_RADIUS = 6; + private static final int TORETERROR_COOLDOWN_TICKS = 200; + private static final int TORETERROR_SHAKE_TICKS = 25; + + /** Client-side only: how many ticks of camera shake remain from a Toreterror landing. */ + public static int clientShakeTicks = 0; private static final ResourceLocation ATTACK_RANGE_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "big_bertha_attack_range"); private final Tier tier; private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this); @@ -116,6 +124,14 @@ public class BigBerthaItem extends SwordItem implements GeoItem { return InteractionResultHolder.sidedSuccess(stack, level.isClientSide); } + if (mode == BossMode.TORETERROR) { + if (player.getCooldowns().isOnCooldown(this)) { + return InteractionResultHolder.fail(stack); + } + startToreterrorJump(level, player, stack); + return InteractionResultHolder.sidedSuccess(stack, level.isClientSide); + } + if (mode != BossMode.MOLEVORE) { return InteractionResultHolder.pass(stack); } @@ -144,7 +160,7 @@ public class BigBerthaItem extends SwordItem implements GeoItem { case LUCID -> applyLucidHit(target, player, serverLevel); case NIGHTMARE -> applyNightmareHit(target, serverLevel); case KRAKEN -> applyKrakenHit(player, target, serverLevel); - case MOLEVORE -> { + case MOLEVORE, TORETERROR -> { } } @@ -158,6 +174,32 @@ public class BigBerthaItem extends SwordItem implements GeoItem { return; } + // Toreterror jump tracking + if (isToreterrorJumping(stack) && player.getMainHandItem() == stack) { + player.fallDistance = 0.0F; // prevent fall damage during the crash-down + boolean launched = readInt(stack, TORETERROR_LAUNCHED_TAG) == 1; + if (!launched && !player.onGround()) { + CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.putInt(TORETERROR_LAUNCHED_TAG, 1)); + } + if (launched && player.onGround()) { + CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> { + tag.remove(TORETERROR_JUMPING_TAG); + tag.remove(TORETERROR_LAUNCHED_TAG); + }); + if (!level.isClientSide && player instanceof ServerPlayer serverPlayer) { + applyToreterrorLanding((ServerLevel) level, serverPlayer); + } + if (level.isClientSide) { + clientShakeTicks = TORETERROR_SHAKE_TICKS; + } + } + } + + // Tick client shake counter + if (level.isClientSide && clientShakeTicks > 0) { + clientShakeTicks--; + } + int spinTicks = getSpinTicks(stack); if (spinTicks <= 0) { return; @@ -317,6 +359,43 @@ public class BigBerthaItem extends SwordItem implements GeoItem { } } + private void startToreterrorJump(Level level, Player player, ItemStack stack) { + CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> { + tag.putInt(TORETERROR_JUMPING_TAG, 1); + tag.remove(TORETERROR_LAUNCHED_TAG); + }); + player.setDeltaMovement(player.getDeltaMovement().x, 1.5D, player.getDeltaMovement().z); + player.hasImpulse = true; + player.fallDistance = 0.0F; + player.getCooldowns().addCooldown(this, TORETERROR_COOLDOWN_TICKS); + player.awardStat(Stats.ITEM_USED.get(this)); + level.playSound(null, player.blockPosition(), SoundEvents.GENERIC_EXPLODE.value(), SoundSource.PLAYERS, 1.0F, 0.6F); + } + + private void applyToreterrorLanding(ServerLevel level, ServerPlayer player) { + ItemStack heldStack = player.getMainHandItem(); + float damage = (float) (player.getAttributeValue(Attributes.ATTACK_DAMAGE) * 2.0D); + AABB aoe = player.getBoundingBox().inflate(TORETERROR_LANDING_RADIUS, 3.0D, TORETERROR_LANDING_RADIUS); + for (LivingEntity victim : level.getEntitiesOfClass(LivingEntity.class, aoe, + e -> e.isAlive() && e != player && !e.isSpectator())) { + victim.hurt(player.damageSources().playerAttack(player), damage); + Vec3 knockDir = victim.position().subtract(player.position()).multiply(1.0D, 0.0D, 1.0D); + if (knockDir.lengthSqr() < 1.0E-4D) knockDir = player.getLookAngle().multiply(1.0D, 0.0D, 1.0D); + Vec3 normalized = knockDir.normalize(); + victim.push(normalized.x * 2.5D, 0.6D, normalized.z * 2.5D); + victim.hurtMarked = true; + } + level.playSound(null, player.blockPosition(), SoundEvents.GENERIC_EXPLODE.value(), SoundSource.PLAYERS, 1.5F, 0.75F); + level.sendParticles(ParticleTypes.EXPLOSION, player.getX(), player.getY() + 0.5D, player.getZ(), 4, 1.5D, 0.3D, 1.5D, 0.0D); + level.sendParticles(ParticleTypes.SPLASH, player.getX(), player.getY() + 0.5D, player.getZ(), 60, 3.0D, 0.5D, 3.0D, 0.2D); + level.sendParticles(ParticleTypes.CRIT, player.getX(), player.getY() + 0.5D, player.getZ(), 20, 2.0D, 0.5D, 2.0D, 0.1D); + heldStack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND); + } + + private static boolean isToreterrorJumping(ItemStack stack) { + return readInt(stack, TORETERROR_JUMPING_TAG) == 1; + } + private void tickMolevoreSpin(ServerLevel level, ServerPlayer player, ItemStack stack, int spinTicks) { Vec3 direction = getStoredSpinDirection(stack); double verticalBoost = player.onGround() ? 0.08D : Math.max(-0.08D, player.getDeltaMovement().y); @@ -505,7 +584,8 @@ public class BigBerthaItem extends SwordItem implements GeoItem { NIGHTMARE(1, "tooltip.antarchy.big_bertha.mode.nightmare", "message.antarchy.big_bertha.mode.nightmare"), KRAKEN(2, "tooltip.antarchy.big_bertha.mode.kraken", "message.antarchy.big_bertha.mode.kraken"), MOLEVORE(3, "tooltip.antarchy.big_bertha.mode.molevore", "message.antarchy.big_bertha.mode.molevore"), - LUCID(4, "tooltip.antarchy.big_bertha.mode.lucid", "message.antarchy.big_bertha.mode.lucid"); + LUCID(4, "tooltip.antarchy.big_bertha.mode.lucid", "message.antarchy.big_bertha.mode.lucid"), + TORETERROR(5, "tooltip.antarchy.big_bertha.mode.toreterror", "message.antarchy.big_bertha.mode.toreterror"); private final int id; private final String tooltipKey; @@ -523,7 +603,8 @@ public class BigBerthaItem extends SwordItem implements GeoItem { case LUCID -> NIGHTMARE; case NIGHTMARE -> KRAKEN; case KRAKEN -> MOLEVORE; - case MOLEVORE -> BASILISK; + case MOLEVORE -> TORETERROR; + case TORETERROR -> BASILISK; }; } diff --git a/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynBileCystFeature.java b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynBileCystFeature.java new file mode 100644 index 00000000..2352b44e --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynBileCystFeature.java @@ -0,0 +1,196 @@ +package com.craisinlord.antarchy.content.worldgen.cavaryn; + +import com.craisinlord.antarchy.Antarchy; +import com.mojang.serialization.Codec; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.feature.Feature; +import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; +import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; +import net.minecraft.world.level.material.FluidState; + +public final class CavarynBileCystFeature extends Feature { + private static final ResourceLocation BILE_VEIN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile_vein"); + private static final ResourceLocation BILE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile"); + private static final int SEARCH_RADIUS = 8; + private static final int SEARCH_ATTEMPTS = 20; + private static final int VERTICAL_SCAN = 10; + // Chance that each exposed vein face oozes bile liquid outward into the cave + private static final float OOZE_CHANCE = 0.22f; + + public CavarynBileCystFeature(Codec codec) { + super(codec); + } + + @Override + public boolean place(FeaturePlaceContext context) { + Block bileVeinBlock = getBlock(BILE_VEIN_ID); + Block bileBlock = getBlock(BILE_ID); + if (bileVeinBlock == null || !(bileBlock instanceof LiquidBlock)) { + return false; + } + + WorldGenLevel level = context.level(); + RandomSource random = context.random(); + + BlockPos center = findCenter(level, context.origin(), random); + if (center == null) { + return false; + } + + return placeCyst(level, center, bileVeinBlock, bileBlock, random); + } + + // Find a solid block adjacent to cave air, then step 1-2 blocks deeper into the wall + // so the cyst is embedded rather than sitting right on the surface. + private static BlockPos findCenter(WorldGenLevel level, BlockPos origin, RandomSource random) { + BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); + for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) { + int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS; + int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS; + int y = origin.getY() + random.nextInt(VERTICAL_SCAN * 2 + 1) - VERTICAL_SCAN; + y = Mth.clamp(y, level.getMinBuildHeight() + 6, level.getMaxBuildHeight() - 6); + mutable.set(x, y, z); + + if (!isSolid(level.getBlockState(mutable))) { + continue; + } + + // Need at least one open neighbor (at cave surface) + Direction openDir = null; + for (Direction dir : Direction.values()) { + if (level.getBlockState(mutable.relative(dir)).canBeReplaced()) { + openDir = dir; + break; + } + } + if (openDir == null) { + continue; + } + + // Step 1-2 blocks away from the opening so the cyst sits inside the wall + int depth = 1 + random.nextInt(2); + BlockPos candidate = mutable.immutable().relative(openDir.getOpposite(), depth); + if (isSolid(level.getBlockState(candidate))) { + return candidate; + } + } + return null; + } + + private boolean placeCyst(WorldGenLevel level, BlockPos center, Block veinBlock, Block bileBlock, RandomSource random) { + // Per-axis radii: 1.5–13.5 so the cyst diameter ranges roughly 3–27 + double rx = 1.5 + random.nextDouble() * 12.0; + double ry = 1.5 + random.nextDouble() * 12.0; + double rz = 1.5 + random.nextDouble() * 12.0; + + // Random stretch: pick one axis and scale it up 1.3–2x for elongated cysts + int stretchAxis = random.nextInt(3); + if (stretchAxis == 0) rx *= 1.3 + random.nextDouble() * 0.7; + else if (stretchAxis == 1) ry *= 1.3 + random.nextDouble() * 0.7; + else rz *= 1.3 + random.nextDouble() * 0.7; + + // Independent sine frequencies per wobble term — drives the lumpy distortion + double f1x = 0.6 + random.nextDouble() * 1.2; + double f1z = 0.6 + random.nextDouble() * 1.2; + double f2y = 0.7 + random.nextDouble() * 1.0; + double f2x = 0.5 + random.nextDouble() * 0.9; + double f3z = 0.8 + random.nextDouble() * 1.1; + double f3y = 0.5 + random.nextDouble() * 0.8; + double wobbleAmp = 0.15 + random.nextDouble() * 0.2; // surface roughness + + int maxR = (int) Math.ceil(Math.max(Math.max(rx, ry), rz)) + 2; + List placed = new ArrayList<>(); + + for (int dx = -maxR; dx <= maxR; dx++) { + for (int dy = -maxR; dy <= maxR; dy++) { + for (int dz = -maxR; dz <= maxR; dz++) { + double baseDist = Math.sqrt( + (dx * dx) / (rx * rx) + + (dy * dy) / (ry * ry) + + (dz * dz) / (rz * rz)); + + // Multi-frequency sine interference — gives lumpy, non-spherical surface + double wobble = wobbleAmp * ( + 0.4 * Math.sin(dx * f1x + dz * f1z) + + 0.35 * Math.cos(dy * f2y + dx * f2x) + + 0.25 * Math.sin(dz * f3z + dy * f3y)); + + double distorted = baseDist + wobble; + if (distorted > 1.0) { + continue; + } + + BlockPos pos = center.offset(dx, dy, dz); + BlockState existing = level.getBlockState(pos); + if (!isSolid(existing)) { + continue; + } + + if (distorted < 0.7) { + // Interior — fill with bile liquid + BlockState bileState = bileBlock.defaultBlockState(); + level.setBlock(pos, bileState, 2); + scheduleFluidTick(level, pos, bileState); + } else { + // Outer shell — bile vein blocks + level.setBlock(pos, veinBlock.defaultBlockState(), 2); + placed.add(pos.immutable()); + } + } + } + } + + if (placed.isEmpty()) { + return false; + } + + // 30% chance this cyst oozes at all + if (random.nextFloat() >= 0.30f) { + return true; + } + + // Ooze bile out of exposed faces — "popped pimple" seep + for (BlockPos cystPos : placed) { + for (Direction dir : Direction.values()) { + BlockPos adj = cystPos.relative(dir); + BlockState adjState = level.getBlockState(adj); + if ((adjState.isAir() || adjState.canBeReplaced()) && random.nextFloat() < OOZE_CHANCE) { + BlockState bileState = bileBlock.defaultBlockState(); + level.setBlock(adj, bileState, 2); + scheduleFluidTick(level, adj, bileState); + } + } + } + + return true; + } + + private static boolean isSolid(BlockState state) { + return state.blocksMotion() && !state.is(Blocks.BEDROCK) && state.getFluidState().isEmpty(); + } + + private static void scheduleFluidTick(WorldGenLevel level, BlockPos pos, BlockState state) { + FluidState fluidState = state.getFluidState(); + if (!fluidState.isEmpty()) { + level.scheduleTick(pos, fluidState.getType(), fluidState.getType().getTickDelay(level)); + } + } + + private static Block getBlock(ResourceLocation id) { + Optional block = BuiltInRegistries.BLOCK.getOptional(id); + return block.orElse(null); + } +} diff --git a/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynBilePoolFeature.java b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynBilePoolFeature.java deleted file mode 100644 index f28f4f69..00000000 --- a/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynBilePoolFeature.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.craisinlord.antarchy.content.worldgen.cavaryn; - -import com.craisinlord.antarchy.Antarchy; -import com.mojang.serialization.Codec; -import java.util.Optional; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.WorldGenLevel; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.LiquidBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.feature.Feature; -import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; -import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; -import net.minecraft.world.level.material.FluidState; - -public final class CavarynBilePoolFeature extends Feature { - private static final ResourceLocation BILE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile"); - private static final int SEARCH_RADIUS = 8; - private static final int SEARCH_ATTEMPTS = 24; - private static final int FLOOR_SCAN_RANGE = 14; - - public CavarynBilePoolFeature(Codec codec) { - super(codec); - } - - @Override - public boolean place(FeaturePlaceContext context) { - Block bileBlock = getBlock(BILE_ID); - if (!(bileBlock instanceof LiquidBlock)) { - return false; - } - - WorldGenLevel level = context.level(); - RandomSource random = context.random(); - BlockPos floorCenter = findPoolFloor(level, context.origin(), random); - if (floorCenter == null) { - return false; - } - - return placePool(level, floorCenter, bileBlock.defaultBlockState(), random); - } - - private static BlockPos findPoolFloor(WorldGenLevel level, BlockPos origin, RandomSource random) { - BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); - for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) { - int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS; - int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS; - int startY = origin.getY() + random.nextInt(FLOOR_SCAN_RANGE * 2 + 1) - FLOOR_SCAN_RANGE; - startY = Math.max(level.getMinBuildHeight() + 3, Math.min(level.getMaxBuildHeight() - 4, startY)); - - for (int y = startY; y >= Math.max(level.getMinBuildHeight() + 2, startY - FLOOR_SCAN_RANGE); y--) { - mutable.set(x, y, z); - BlockState floorState = level.getBlockState(mutable); - if (!isValidFloor(level, mutable, floorState)) { - continue; - } - - BlockState aboveState = level.getBlockState(mutable.above()); - if (!isOpenBlock(aboveState)) { - continue; - } - - if (countSolidNeighbors(level, mutable) >= 3) { - return mutable.immutable(); - } - } - } - - return null; - } - - private static boolean placePool(WorldGenLevel level, BlockPos center, BlockState bileState, RandomSource random) { - boolean placedAny = false; - int radius = 2 + random.nextInt(3); - BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); - - for (int dx = -radius; dx <= radius; dx++) { - for (int dz = -radius; dz <= radius; dz++) { - double normalized = (dx * dx + dz * dz) / (double) Math.max(1, radius * radius); - if (normalized > 1.0D + random.nextDouble() * 0.2D) { - continue; - } - - double density = 1.0D - Math.min(1.0D, normalized); - int localDepth = density > 0.45D || random.nextFloat() < 0.35F ? 2 : 1; - localDepth = Mth.clamp(localDepth, 1, 2); - - for (int depth = 0; depth < localDepth; depth++) { - mutable.set(center.getX() + dx, center.getY() - depth, center.getZ() + dz); - BlockState existing = level.getBlockState(mutable); - FluidState existingFluid = existing.getFluidState(); - if (existing.is(Blocks.BEDROCK)) { - break; - } - if (!existing.canBeReplaced() && existingFluid.isEmpty() && !existing.blocksMotion()) { - continue; - } - - level.setBlock(mutable, bileState, 2); - scheduleFluidTick(level, mutable, bileState); - placedAny = true; - } - } - } - - return placedAny; - } - - private static boolean isValidFloor(WorldGenLevel level, BlockPos pos, BlockState state) { - return !state.isAir() - && !state.is(Blocks.BEDROCK) - && state.getFluidState().isEmpty() - && state.blocksMotion() - && state.isFaceSturdy(level, pos, Direction.UP); - } - - private static boolean isOpenBlock(BlockState state) { - return state.isAir() || state.canBeReplaced() || !state.getFluidState().isEmpty(); - } - - private static int countSolidNeighbors(WorldGenLevel level, BlockPos pos) { - int solidNeighbors = 0; - BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); - for (Direction direction : Direction.Plane.HORIZONTAL) { - mutable.setWithOffset(pos, direction); - if (isValidFloor(level, mutable, level.getBlockState(mutable))) { - solidNeighbors++; - } - } - return solidNeighbors; - } - - private static void scheduleFluidTick(WorldGenLevel level, BlockPos pos, BlockState state) { - FluidState fluidState = state.getFluidState(); - if (!fluidState.isEmpty()) { - level.scheduleTick(pos, fluidState.getType(), fluidState.getType().getTickDelay(level)); - } - } - - private static Block getBlock(ResourceLocation id) { - Optional block = BuiltInRegistries.BLOCK.getOptional(id); - return block.orElse(null); - } -} diff --git a/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynBileVeinFeature.java b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynBileVeinFeature.java new file mode 100644 index 00000000..932bd883 --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynBileVeinFeature.java @@ -0,0 +1,238 @@ +package com.craisinlord.antarchy.content.worldgen.cavaryn; + +import com.craisinlord.antarchy.Antarchy; +import com.mojang.serialization.Codec; + +import java.util.*; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.feature.Feature; +import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; +import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; +import net.minecraft.world.level.material.FluidState; + +public final class CavarynBileVeinFeature extends Feature { + private static final ResourceLocation BILE_VEIN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile_vein"); + private static final ResourceLocation BILE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile"); + private static final int SEARCH_RADIUS = 10; + private static final int SEARCH_ATTEMPTS = 24; + private static final int VERTICAL_SCAN = 12; + private static final float BRANCH_CHANCE = 0.12f; + private static final float LIQUID_POCKET_CHANCE = 0.04f; + + public CavarynBileVeinFeature(Codec codec) { + super(codec); + } + + @Override + public boolean place(FeaturePlaceContext context) { + Block bileVeinBlock = getBlock(BILE_VEIN_ID); + Block bileBlock = getBlock(BILE_ID); + if (bileVeinBlock == null || !(bileBlock instanceof LiquidBlock)) { + return false; + } + + WorldGenLevel level = context.level(); + RandomSource random = context.random(); + + BlockPos start = findStart(level, context.origin(), random); + if (start == null) { + return false; + } + + return growVeinNetwork(level, start, bileVeinBlock, bileBlock, random); + } + + // Find a solid block that sits at a cave boundary + private static BlockPos findStart(WorldGenLevel level, BlockPos origin, RandomSource random) { + BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); + for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) { + int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS; + int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS; + int y = origin.getY() + random.nextInt(VERTICAL_SCAN * 2 + 1) - VERTICAL_SCAN; + y = Mth.clamp(y, level.getMinBuildHeight() + 2, level.getMaxBuildHeight() - 3); + mutable.set(x, y, z); + + if (!isVeinCandidate(level.getBlockState(mutable))) { + continue; + } + + for (Direction dir : Direction.values()) { + if (level.getBlockState(mutable.relative(dir)).canBeReplaced()) { + return mutable.immutable(); + } + } + } + return null; + } + + private boolean growVeinNetwork(WorldGenLevel level, BlockPos start, Block veinBlock, Block bileBlock, RandomSource random) { + Set visited = new HashSet<>(); + List pendingBranches = new ArrayList<>(); + boolean placedAny = false; + + Direction mainDir = Direction.values()[random.nextInt(6)]; + placedAny |= growArm(level, start, mainDir, 45 + random.nextInt(25), visited, pendingBranches, veinBlock, bileBlock, random); + + for (BranchStart branch : pendingBranches) { + Direction branchDir = perpendiculars(branch.dir())[random.nextInt(4)]; + int branchLen = 15 + random.nextInt(20); + growArm(level, branch.pos(), branchDir, branchLen, visited, null, veinBlock, bileBlock, random); + } + + return placedAny; + } + + private boolean growArm( + WorldGenLevel level, + BlockPos start, + Direction initialDir, + int maxSteps, + Set visited, + List branches, + Block veinBlock, + Block bileBlock, + RandomSource random + ) { + BlockPos current = start; + Direction dir = initialDir; + boolean placedAny = false; + + for (int step = 0; step < maxSteps; step++) { + if (visited.contains(current)) { + current = current.relative(biasedNextDir(dir, random)); + continue; + } + + BlockState state = level.getBlockState(current); + if (!isVeinCandidate(state)) { + // Try to redirect + BlockPos redirect = findSolidNeighbor(current, dir, visited, level, random); + if (redirect == null) { + break; + } + current = redirect; + state = level.getBlockState(current); + if (!isVeinCandidate(state)) { + break; + } + } + + visited.add(current); + level.setBlock(current, veinBlock.defaultBlockState(), 2); + placedAny = true; + + if (random.nextFloat() < LIQUID_POCKET_CHANCE) { + tryPlaceLiquidPocket(level, current, bileBlock, visited, random); + } + + if (branches != null && random.nextFloat() < BRANCH_CHANCE) { + Direction[] perps = perpendiculars(dir); + branches.add(new BranchStart(current, perps[random.nextInt(perps.length)])); + } + + dir = biasedNextDir(dir, random); + current = current.relative(dir); + } + + return placedAny; + } + + private static Direction biasedNextDir(Direction current, RandomSource random) { + int roll = random.nextInt(10); + if (roll < 6) { + return current; + } + return perpendiculars(current)[roll - 6]; + } + + private static BlockPos findSolidNeighbor(BlockPos from, Direction preferredDir, Set visited, WorldGenLevel level, RandomSource random) { + Direction[] perps = perpendiculars(preferredDir); + for (int i = perps.length - 1; i > 0; i--) { + int j = random.nextInt(i + 1); + Direction tmp = perps[i]; + perps[i] = perps[j]; + perps[j] = tmp; + } + for (Direction d : perps) { + BlockPos candidate = from.relative(d); + if (!visited.contains(candidate) && isVeinCandidate(level.getBlockState(candidate))) { + return candidate; + } + } + return null; + } + + private static void tryPlaceLiquidPocket(WorldGenLevel level, BlockPos veinPos, Block bileBlock, Set visited, RandomSource random) { + Direction[] dirs = Direction.values().clone(); + for (int i = dirs.length - 1; i > 0; i--) { + int j = random.nextInt(i + 1); + Direction tmp = dirs[i]; + dirs[i] = dirs[j]; + dirs[j] = tmp; + } + for (Direction d : dirs) { + BlockPos candidate = veinPos.relative(d); + if (visited.contains(candidate)) { + continue; + } + BlockState candidateState = level.getBlockState(candidate); + if (!isVeinCandidate(candidateState)) { + continue; + } + if (isEnclosed(level, candidate) || random.nextFloat() < 0.05f) { + BlockState bileState = bileBlock.defaultBlockState(); + level.setBlock(candidate, bileState, 2); + scheduleFluidTick(level, candidate, bileState); + visited.add(candidate); + return; + } + } + } + + private static boolean isEnclosed(WorldGenLevel level, BlockPos pos) { + for (Direction d : Direction.values()) { + BlockState neighbor = level.getBlockState(pos.relative(d)); + if (neighbor.isAir() || neighbor.canBeReplaced()) { + return false; + } + } + return true; + } + + private static boolean isVeinCandidate(BlockState state) { + return state.blocksMotion() && !state.is(Blocks.BEDROCK) && state.getFluidState().isEmpty(); + } + + private static Direction[] perpendiculars(Direction dir) { + return switch (dir.getAxis()) { + case X -> new Direction[]{Direction.UP, Direction.DOWN, Direction.NORTH, Direction.SOUTH}; + case Z -> new Direction[]{Direction.UP, Direction.DOWN, Direction.EAST, Direction.WEST}; + case Y -> new Direction[]{Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST}; + }; + } + + private static void scheduleFluidTick(WorldGenLevel level, BlockPos pos, BlockState state) { + FluidState fluidState = state.getFluidState(); + if (!fluidState.isEmpty()) { + level.scheduleTick(pos, fluidState.getType(), fluidState.getType().getTickDelay(level)); + } + } + + private static Block getBlock(ResourceLocation id) { + Optional block = BuiltInRegistries.BLOCK.getOptional(id); + return block.orElse(null); + } + + private record BranchStart(BlockPos pos, Direction dir) {} +} diff --git a/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynEggPatchFeature.java b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynEggPatchFeature.java index f44424c3..07b9917e 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynEggPatchFeature.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/cavaryn/CavarynEggPatchFeature.java @@ -1,23 +1,33 @@ package com.craisinlord.antarchy.content.worldgen.cavaryn; +import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.content.AntarchyObjects; import com.craisinlord.antarchy.content.block.CreepingHorrorEggBlock; import com.craisinlord.antarchy.content.block.LurkingTerrorEggBlock; import com.mojang.serialization.Codec; +import java.util.ArrayList; import java.util.List; +import java.util.Optional; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.level.WorldGenLevel; +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.levelgen.feature.Feature; import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; public final class CavarynEggPatchFeature extends Feature { + private static final ResourceLocation AMBER_MOSS_BLOCK_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "amber_moss_block"); private static final int SEARCH_RADIUS = 8; - private static final int SEARCH_ATTEMPTS = 20; - private static final int FLOOR_SCAN_RANGE = 10; + private static final int SEARCH_ATTEMPTS = 24; + private static final int VERTICAL_SCAN = 12; + private static final int MAX_RADIUS_Y = 3; public CavarynEggPatchFeature(Codec codec) { super(codec); @@ -29,77 +39,118 @@ public final class CavarynEggPatchFeature extends Feature= Math.max(level.getMinBuildHeight() + 1, startY - FLOOR_SCAN_RANGE); y--) { - mutable.set(x, y, z); - BlockState floorState = level.getBlockState(mutable); - BlockState airState = level.getBlockState(mutable.above()); - if (floorState.getFluidState().isEmpty() - && floorState.blocksMotion() - && floorState.isFaceSturdy(level, mutable, Direction.UP) - && airState.canBeReplaced()) { - return mutable.immutable(); - } + mutable.set(x, y, z); + if (isSolidEnoughForCavity(level, mutable)) { + return mutable.immutable(); } } - return null; } - private boolean placePatch(WorldGenLevel level, BlockPos center, RandomSource random, EggType eggType) { - int radius = 2 + random.nextInt(3); - boolean placedAny = false; - List eggSpots = new java.util.ArrayList<>(); + private static boolean isSolidEnoughForCavity(WorldGenLevel level, BlockPos center) { + BlockState centerState = level.getBlockState(center); + if (!centerState.blocksMotion() || centerState.is(Blocks.BEDROCK)) { + return false; + } - for (int dx = -radius; dx <= radius; dx++) { - for (int dz = -radius; dz <= radius; dz++) { - double distance = dx * dx + dz * dz; - if (distance > radius * radius + random.nextInt(2)) { - continue; + int solidCount = 0; + BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); + for (int dx = -2; dx <= 2; dx += 2) { + for (int dy = -1; dy <= 1; dy++) { + for (int dz = -2; dz <= 2; dz += 2) { + mutable.set(center.getX() + dx, center.getY() + dy, center.getZ() + dz); + if (level.getBlockState(mutable).blocksMotion()) { + solidCount++; + } } + } + } + return solidCount >= 9; + } - BlockPos floorPos = center.offset(dx, 0, dz); - BlockState floorState = level.getBlockState(floorPos); - BlockPos eggPos = floorPos.above(); - BlockState aboveState = level.getBlockState(eggPos); - if (!isValidEggFloor(level, floorPos, floorState, aboveState)) { - continue; + private boolean carveCavityAndPlaceEggs(WorldGenLevel level, BlockPos center, RandomSource random, EggType eggType, Block amberMossBlock) { + int rx = 3 + random.nextInt(3); + int ry = 2 + random.nextInt(2); + int rz = 3 + random.nextInt(3); + + for (int dx = -rx; dx <= rx; dx++) { + for (int dy = -ry; dy <= ry; dy++) { + for (int dz = -rz; dz <= rz; dz++) { + double norm = (double)(dx * dx) / (rx * rx) + + (double)(dy * dy) / (ry * ry) + + (double)(dz * dz) / (rz * rz); + if (norm > 1.0) { + continue; + } + BlockPos pos = center.offset(dx, dy, dz); + BlockState existing = level.getBlockState(pos); + if (!existing.is(Blocks.BEDROCK) && existing.blocksMotion() && existing.getFluidState().isEmpty()) { + level.setBlock(pos, Blocks.AIR.defaultBlockState(), 2); + } } - eggSpots.add(eggPos); } } - if (eggSpots.isEmpty()) { - return placedAny; + List eggPositions = new ArrayList<>(); + for (int dx = -rx; dx <= rx; dx++) { + for (int dy = -ry - 1; dy <= ry; dy++) { + for (int dz = -rz; dz <= rz; dz++) { + BlockPos pos = center.offset(dx, dy, dz); + if (!level.getBlockState(pos).isAir()) { + continue; + } + BlockPos below = pos.below(); + BlockState belowState = level.getBlockState(below); + if (belowState.blocksMotion() && !belowState.isAir() && belowState.isFaceSturdy(level, below, Direction.UP)) { + eggPositions.add(pos); + } + } + } } - int eggCount = Math.min(eggSpots.size(), 2 + random.nextInt(3)); - for (int i = 0; i < eggCount; i++) { - BlockPos eggPos = eggSpots.get(random.nextInt(eggSpots.size())); - if (!level.getBlockState(eggPos).canBeReplaced()) { + if (eggPositions.isEmpty()) { + return false; + } + + boolean placedAny = false; + for (BlockPos eggPos : eggPositions) { + if (random.nextFloat() > 0.65f) { continue; } + // Replace the floor block with amber moss so eggs hatch faster + if (amberMossBlock != null) { + BlockPos floorPos = eggPos.below(); + BlockState floorState = level.getBlockState(floorPos); + if (floorState.blocksMotion() && !floorState.is(Blocks.BEDROCK) && floorState.getFluidState().isEmpty()) { + level.setBlock(floorPos, amberMossBlock.defaultBlockState(), 2); + } + } + BlockState eggState = eggType == EggType.CREEPING_HORROR ? AntarchyObjects.CREEPING_HORROR_EGGS.get().defaultBlockState() : AntarchyObjects.LURKING_TERROR_EGGS.get().defaultBlockState(); - eggState = eggState.setValue(eggType == EggType.CREEPING_HORROR ? CreepingHorrorEggBlock.EGGS : LurkingTerrorEggBlock.EGGS, 1 + random.nextInt(4)); + eggState = eggState.setValue( + eggType == EggType.CREEPING_HORROR ? CreepingHorrorEggBlock.EGGS : LurkingTerrorEggBlock.EGGS, + 1 + random.nextInt(4)); level.setBlock(eggPos, eggState, 3); placedAny = true; } @@ -107,12 +158,9 @@ public final class CavarynEggPatchFeature extends Feature block = BuiltInRegistries.BLOCK.getOptional(id); + return block.orElse(null); } private enum EggType { diff --git a/common/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/ElythiaBiomeSource.java b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/ElythiaBiomeSource.java index 8940673d..545bfb05 100644 --- a/common/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/ElythiaBiomeSource.java +++ b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/ElythiaBiomeSource.java @@ -118,12 +118,15 @@ public class ElythiaBiomeSource extends BiomeSource { // and ambient effects work correctly above the water surface. Climate.TargetPoint target = sampler.sample(x, this.seaLevelQuartY, z); if (target.continentalness() < OCEAN_CONTINENTALNESS_THRESHOLD) { - return this.delegate.getNoiseBiome(x, this.seaLevelQuartY, z, sampler); + Holder seaLevelBiome = this.delegate.getNoiseBiome(x, this.seaLevelQuartY, z, sampler); + // MultiNoise can return a land biome at sea-level depth — force ocean if so + if (isOceanBiome(seaLevelBiome)) return seaLevelBiome; + return oceanHolder != null ? oceanHolder : seaLevelBiome; } - // Land column below or at sea level: force ocean for any biome not allowed there. - // Use <= so quart 19 (blocks 76-79, partly underwater) is covered. - if (y <= this.seaLevelQuartY && oceanHolder != null && !allowedBelowSeaLevel(biome)) { + // Land column at or below sea level: force ocean for any biome not allowed there. + // +1 quart above seaLevelQuartY so blocks 76-83 (around the waterline) are all caught. + if (y <= this.seaLevelQuartY + 1 && oceanHolder != null && !allowedBelowSeaLevel(biome)) { return oceanHolder; } diff --git a/common/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/FallenOuranwoodFeature.java b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/FallenOuranwoodFeature.java new file mode 100644 index 00000000..78ba675b --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/FallenOuranwoodFeature.java @@ -0,0 +1,144 @@ +package com.craisinlord.antarchy.content.worldgen.elythia; + +import com.craisinlord.antarchy.content.AntarchyObjects; +import com.mojang.serialization.Codec; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LeavesBlock; +import net.minecraft.world.level.block.RotatedPillarBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.feature.Feature; +import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; +import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; + +public class FallenOuranwoodFeature extends Feature { + + public FallenOuranwoodFeature(Codec codec) { + super(codec); + } + + @Override + public boolean place(FeaturePlaceContext context) { + WorldGenLevel level = context.level(); + RandomSource random = context.random(); + BlockPos origin = context.origin(); + + Direction.Axis axis = random.nextBoolean() ? Direction.Axis.X : Direction.Axis.Z; + int length = 36 + random.nextInt(44); // 36–79 blocks long + int outerRadius = 1 + random.nextInt(3); // 1–3 (cross-section up to 7-wide) + boolean hollow = outerRadius >= 2; + + Block ouranwoodLog = BuiltInRegistries.BLOCK.getOptional( + ResourceLocation.fromNamespaceAndPath("antarchy", "ouranwood_log")) + .orElse(AntarchyObjects.MOSSY_OURANWOOD_LOG.get()); + + BlockState mossyLogState = AntarchyObjects.MOSSY_OURANWOOD_LOG.get().defaultBlockState() + .setValue(RotatedPillarBlock.AXIS, axis); + BlockState freshLogState = ouranwoodLog.defaultBlockState() + .setValue(RotatedPillarBlock.AXIS, axis); + BlockState woodState = AntarchyObjects.MOSSY_OURANWOOD_WOOD.get().defaultBlockState() + .setValue(RotatedPillarBlock.AXIS, Direction.Axis.Y); + + // Pre-generate a smoothed damage profile along the length (0=solid, 1=gap) + float[] damage = new float[length]; + for (int i = 0; i < length; i++) damage[i] = random.nextFloat(); + for (int pass = 0; pass < 4; pass++) { + for (int i = 1; i < length - 1; i++) { + damage[i] = (damage[i - 1] + damage[i] * 2 + damage[i + 1]) / 4f; + } + } + // Bias upward so more sections are heavily damaged + for (int i = 0; i < length; i++) damage[i] = damage[i] * damage[i]; + + int anchorY = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, origin.getX(), origin.getZ()); + boolean placed = false; + + for (int step = 0; step < length; step++) { + int bx = axis == Direction.Axis.X ? origin.getX() + step : origin.getX(); + int bz = axis == Direction.Axis.Z ? origin.getZ() + step : origin.getZ(); + + float dmg = damage[step]; + + // Full gap sections — log has completely rotted through here + if (dmg > 0.78f) continue; + + int surfaceY = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, bx, bz); + int centerY = Math.max(anchorY, Math.min(anchorY + 2, surfaceY)) + outerRadius; + + for (int dy = -outerRadius; dy <= outerRadius; dy++) { + for (int dp = -outerRadius; dp <= outerRadius; dp++) { + double dist = Math.sqrt(dy * dy + dp * dp); + if (dist > outerRadius + 0.5) continue; + + boolean isShell = dist >= outerRadius - 0.5; + + // Hollow interior: always skip center when hollow + if (hollow && dist < outerRadius - 0.5) continue; + + // Heavy-damage sections: only keep fragments of the shell + if (dmg > 0.55f && !isShell) continue; + if (dmg > 0.55f && random.nextFloat() < (dmg - 0.55f) * 3.5f) continue; + + // All sections: random rot holes punched through the shell + if (isShell && random.nextFloat() < dmg * 0.4f) continue; + + int px = axis == Direction.Axis.X ? bx : bx + dp; + int pz = axis == Direction.Axis.Z ? bz : bz + dp; + BlockPos pos = new BlockPos(px, centerY + dy, pz); + + if (!canReplace(level.getBlockState(pos))) continue; + + // Block material mix: mostly mossy log, some fresh log patches, some moss + float r = random.nextFloat(); + BlockState toPlace; + if (r < 0.08f) { + toPlace = Blocks.MOSS_BLOCK.defaultBlockState(); + } else if (r < 0.22f) { + toPlace = freshLogState; // fresher wood, less decayed patch + } else if (r < 0.32f) { + toPlace = woodState; + } else { + toPlace = mossyLogState; + } + + level.setBlock(pos, toPlace, 2); + placed = true; + } + } + } + + // Moss patches scattered along the log's footprint + int mossCount = 20 + random.nextInt(25); + for (int i = 0; i < mossCount; i++) { + int mx = origin.getX() + random.nextInt(length + 6) - 3; + int mz = axis == Direction.Axis.X + ? origin.getZ() + random.nextInt(9) - 4 + : origin.getZ() + random.nextInt(length + 6) - 3; + int my = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, mx, mz); + BlockPos mossPos = new BlockPos(mx, my, mz); + + if (!canReplace(level.getBlockState(mossPos))) continue; + BlockState below = level.getBlockState(mossPos.below()); + if (!below.isFaceSturdy(level, mossPos.below(), Direction.UP)) continue; + + level.setBlock(mossPos, + random.nextFloat() < 0.35f + ? Blocks.MOSS_BLOCK.defaultBlockState() + : Blocks.MOSS_CARPET.defaultBlockState(), + 2); + } + + return placed; + } + + private static boolean canReplace(BlockState state) { + return state.isAir() || state.canBeReplaced() || (state.getBlock() instanceof LeavesBlock); + } +} diff --git a/common/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/FungalMushroomFeature.java b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/FungalMushroomFeature.java new file mode 100644 index 00000000..f671b975 --- /dev/null +++ b/common/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/FungalMushroomFeature.java @@ -0,0 +1,190 @@ +package com.craisinlord.antarchy.content.worldgen.elythia; + +import com.mojang.serialization.Codec; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.HugeMushroomBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.feature.Feature; +import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; +import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; + +public class FungalMushroomFeature extends Feature { + + public FungalMushroomFeature(Codec codec) { + super(codec); + } + + @Override + public boolean place(FeaturePlaceContext context) { + WorldGenLevel level = context.level(); + RandomSource random = context.random(); + BlockPos origin = context.origin(); + + boolean isRed = random.nextBoolean(); + Block capBlock = isRed ? Blocks.RED_MUSHROOM_BLOCK : Blocks.BROWN_MUSHROOM_BLOCK; + Block smallMushroom = isRed ? Blocks.RED_MUSHROOM : Blocks.BROWN_MUSHROOM; + + // 1-in-3 chance of a large mushroom (~3x the small variant) + boolean isLarge = random.nextInt(3) == 0; + + int stemSize = isLarge ? (2 + random.nextInt(3)) : (random.nextBoolean() ? 2 : 3); + int stemHeight = isLarge ? (18 + random.nextInt(19)) : (6 + random.nextInt(7)); // large: 18–36, small: 6–12 + + // Lean: stem drifts in a random horizontal direction over its height + double leanAngle = random.nextDouble() * Math.PI * 2; + double leanDX = Math.cos(leanAngle); + double leanDZ = Math.sin(leanAngle); + double maxLean = isLarge + ? (6.0 + random.nextDouble() * 10.0) // large: 6–16 block lean + : (2.0 + random.nextDouble() * 3.5); // small: 2–5.5 block lean + + int baseY = origin.getY(); + int stemOffset = stemSize == 2 ? 0 : -1; // center 3x3 on origin + + // Pore-only stem state (inner faces; sides visible from outside) + BlockState stemPore = Blocks.MUSHROOM_STEM.defaultBlockState() + .setValue(HugeMushroomBlock.NORTH, false) + .setValue(HugeMushroomBlock.SOUTH, false) + .setValue(HugeMushroomBlock.EAST, false) + .setValue(HugeMushroomBlock.WEST, false) + .setValue(HugeMushroomBlock.UP, false) + .setValue(HugeMushroomBlock.DOWN, false); + BlockState stemSide = Blocks.MUSHROOM_STEM.defaultBlockState() + .setValue(HugeMushroomBlock.NORTH, true) + .setValue(HugeMushroomBlock.SOUTH, true) + .setValue(HugeMushroomBlock.EAST, true) + .setValue(HugeMushroomBlock.WEST, true) + .setValue(HugeMushroomBlock.UP, false) + .setValue(HugeMushroomBlock.DOWN, false); + + // Place leaning stem + for (int dy = 0; dy < stemHeight; dy++) { + double leanProgress = (double) dy / stemHeight; + int leanX = (int) Math.round(leanDX * maxLean * leanProgress); + int leanZ = (int) Math.round(leanDZ * maxLean * leanProgress); + + for (int dx = 0; dx < stemSize; dx++) { + for (int dz = 0; dz < stemSize; dz++) { + BlockPos pos = new BlockPos( + origin.getX() + stemOffset + dx + leanX, + baseY + dy, + origin.getZ() + stemOffset + dz + leanZ); + if (canReplace(level.getBlockState(pos))) { + // Outer ring shows bark, interior is pores + boolean isEdge = (dx == 0 || dx == stemSize - 1 || dz == 0 || dz == stemSize - 1); + level.setBlock(pos, isEdge ? stemSide : stemPore, 2); + } + } + } + } + + // Cap: cone-shaped, follows the lean, with irregular per-block radius noise + double capCenterX = origin.getX() + (stemSize == 2 ? 0.5 : 0) + leanDX * maxLean; + double capCenterZ = origin.getZ() + (stemSize == 2 ? 0.5 : 0) + leanDZ * maxLean; + int capTopY = baseY + stemHeight; + int baseCapRadius = isLarge + ? (stemSize + 7 + random.nextInt(6)) // large: ~11–18 at base + : (stemSize + 2 + random.nextInt(2)); // small: 4–6 at base + + // Per-position radius jitter table — sampled before the loop for consistency + // Each (dx, dz) slot gets a random ±1.5 bias baked in + int jitterRange = baseCapRadius + 4; + float[][] jitter = new float[jitterRange * 2 + 1][jitterRange * 2 + 1]; + for (float[] row : jitter) { + for (int j = 0; j < row.length; j++) { + row[j] = random.nextFloat() * 3.0f - 1.5f; // ±1.5 blocks + } + } + + int capLayers = baseCapRadius + 2; + for (int cl = 0; cl < capLayers; cl++) { + int capY = capTopY + cl; + double nomRadius = baseCapRadius - cl; + if (nomRadius < 0) break; + + // The cap center also shifts slightly with lean for a drooping overhang feel + double layerCapX = capCenterX + leanDX * cl * 0.3; + double layerCapZ = capCenterZ + leanDZ * cl * 0.3; + + for (int dx = -(jitterRange); dx <= jitterRange; dx++) { + for (int dz = -(jitterRange); dz <= jitterRange; dz++) { + double dist = Math.sqrt( + (origin.getX() + dx - layerCapX) * (origin.getX() + dx - layerCapX) + + (origin.getZ() + dz - layerCapZ) * (origin.getZ() + dz - layerCapZ)); + + float j = jitter[dx + jitterRange][dz + jitterRange]; + double effectiveRadius = nomRadius + j; + + if (dist > effectiveRadius + 0.5) continue; + if (effectiveRadius < 0) continue; + + BlockPos capPos = new BlockPos(origin.getX() + dx, capY, origin.getZ() + dz); + if (!canReplace(level.getBlockState(capPos))) continue; + + boolean isOuter = dist >= effectiveRadius - 0.7; + boolean isTop = cl == capLayers - 1; + + BlockState capState = capBlock.defaultBlockState() + .setValue(HugeMushroomBlock.UP, isTop || isOuter) + .setValue(HugeMushroomBlock.NORTH, isOuter) + .setValue(HugeMushroomBlock.SOUTH, isOuter) + .setValue(HugeMushroomBlock.EAST, isOuter) + .setValue(HugeMushroomBlock.WEST, isOuter) + .setValue(HugeMushroomBlock.DOWN, false); + + level.setBlock(capPos, capState, 2); + } + } + } + + // Mycelium patches around base + int myceliumCount = isLarge ? (25 + random.nextInt(25)) : (12 + random.nextInt(12)); + for (int i = 0; i < myceliumCount; i++) { + int radius = isLarge ? (stemSize + 8 + random.nextInt(8)) : (stemSize + 3 + random.nextInt(3)); + int mx = origin.getX() + random.nextInt(radius * 2 + 1) - radius; + int mz = origin.getZ() + random.nextInt(radius * 2 + 1) - radius; + int my = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, mx, mz) - 1; + BlockPos myceliumPos = new BlockPos(mx, my, mz); + + BlockState existing = level.getBlockState(myceliumPos); + if (existing.is(Blocks.GRASS_BLOCK) || existing.is(Blocks.DIRT) + || existing.is(Blocks.MOSS_BLOCK) || existing.is(Blocks.ROOTED_DIRT)) { + level.setBlock(myceliumPos, Blocks.MYCELIUM.defaultBlockState(), 2); + } + } + + // Small mushrooms scattered around + int smallCount = isLarge ? (10 + random.nextInt(15)) : (5 + random.nextInt(8)); + for (int i = 0; i < smallCount; i++) { + int radius = isLarge ? (stemSize + 10 + random.nextInt(10)) : (stemSize + 4 + random.nextInt(4)); + int sx = origin.getX() + random.nextInt(radius * 2 + 1) - radius; + int sz = origin.getZ() + random.nextInt(radius * 2 + 1) - radius; + int sy = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, sx, sz); + BlockPos smallPos = new BlockPos(sx, sy, sz); + + if (!canReplace(level.getBlockState(smallPos))) continue; + BlockState below = level.getBlockState(smallPos.below()); + if (!below.isFaceSturdy(level, smallPos.below(), Direction.UP)) continue; + + Block plant = random.nextBoolean() ? smallMushroom + : (isRed ? Blocks.BROWN_MUSHROOM : Blocks.RED_MUSHROOM); + BlockState plantState = plant.defaultBlockState(); + if (plantState.canSurvive(level, smallPos)) { + level.setBlock(smallPos, plantState, 2); + } + } + + return true; + } + + private static boolean canReplace(BlockState state) { + return state.isAir() || state.canBeReplaced() + || (state.getBlock() instanceof net.minecraft.world.level.block.LeavesBlock); + } +} diff --git a/common/src/main/resources/assets/antarchy/blockstates/bile_vein.json b/common/src/main/resources/assets/antarchy/blockstates/bile_vein.json new file mode 100644 index 00000000..1ab1a4b4 --- /dev/null +++ b/common/src/main/resources/assets/antarchy/blockstates/bile_vein.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "antarchy:block/bile_vein" + } + } +} diff --git a/common/src/main/resources/assets/antarchy/lang/en_us.json b/common/src/main/resources/assets/antarchy/lang/en_us.json index 95dd34f6..752948e3 100644 --- a/common/src/main/resources/assets/antarchy/lang/en_us.json +++ b/common/src/main/resources/assets/antarchy/lang/en_us.json @@ -27,6 +27,7 @@ "block.antarchy.amber_moss_block": "Amber Moss Block", "block.antarchy.amber_moss_carpet": "Amber Moss Carpet", "block.antarchy.amber_lichen": "Amber Lichen", + "block.antarchy.bile_vein": "Bile Vein", "block.antarchy.duplicator_sapling": "Duplicator Sapling", "block.antarchy.creepvine": "Creepvine", "block.antarchy.duct_tape": "Duct Tape", @@ -272,6 +273,7 @@ "item.antarchy.amber_moss_block": "Amber Moss Block", "item.antarchy.amber_moss_carpet": "Amber Moss Carpet", "item.antarchy.amber_lichen": "Amber Lichen", + "item.antarchy.bile_vein": "Bile Vein", "item.antarchy.creepvine": "Creepvine", "item.antarchy.chiten": "Chiten", "item.antarchy.chiten_block": "Chiten Block", @@ -416,6 +418,7 @@ "message.antarchy.big_bertha.mode.nightmare": "Nightmare", "message.antarchy.big_bertha.mode.kraken": "Kraken", "message.antarchy.big_bertha.mode.molevore": "Molevore", + "message.antarchy.big_bertha.mode.toreterror": "Toreterror", "message.antarchy.ultimate_tool.mode_3x3": "Switched to 3x3 Mining", "message.antarchy.ultimate_tool.mode_default": "Switched to Default Mining", "advancements.antarchy.hey_listen.title": "Hey Listen", @@ -442,6 +445,7 @@ "tooltip.antarchy.big_bertha.mode.nightmare": "Players suffer Dread; hits inflict weakness.", "tooltip.antarchy.big_bertha.mode.kraken": "Hits slam targets back and call lightning.", "tooltip.antarchy.big_bertha.mode.molevore": "Right-click to spin forward and drill through Molevore blocks.", + "tooltip.antarchy.big_bertha.mode.toreterror": "Right-click to launch into the air and crash down with an AOE shockwave.", "tooltip.antarchy.ultimate_tools_3x3": "Shift-right-click to toggle 3x3 Mining.", "tooltip.antarchy.moggles.reveal": "Gives night vision and points to nearby caves.", "tooltip.antarchy.moggles.underground": "Works only while you have no sky access.", diff --git a/common/src/main/resources/assets/antarchy/models/block/bile_vein.json b/common/src/main/resources/assets/antarchy/models/block/bile_vein.json new file mode 100644 index 00000000..1bbd5a7f --- /dev/null +++ b/common/src/main/resources/assets/antarchy/models/block/bile_vein.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "antarchy:block/bile/bile_vein" + } +} diff --git a/common/src/main/resources/assets/antarchy/models/item/bile_vein.json b/common/src/main/resources/assets/antarchy/models/item/bile_vein.json new file mode 100644 index 00000000..1a1067eb --- /dev/null +++ b/common/src/main/resources/assets/antarchy/models/item/bile_vein.json @@ -0,0 +1,3 @@ +{ + "parent": "antarchy:block/bile_vein" +} diff --git a/common/src/main/resources/assets/antarchy/particles/stinky_fly.json b/common/src/main/resources/assets/antarchy/particles/stinky_fly.json new file mode 100644 index 00000000..516d8df2 --- /dev/null +++ b/common/src/main/resources/assets/antarchy/particles/stinky_fly.json @@ -0,0 +1,5 @@ +{ + "textures": [ + "antarchy:stinky_fly" + ] +} diff --git a/common/src/main/resources/assets/antarchy/textures/block/bile/bile_vein.png b/common/src/main/resources/assets/antarchy/textures/block/bile/bile_vein.png new file mode 100644 index 00000000..2a99d09c Binary files /dev/null and b/common/src/main/resources/assets/antarchy/textures/block/bile/bile_vein.png differ diff --git a/common/src/main/resources/assets/antarchy/textures/block/bile/bile_vein.png.mcmeta b/common/src/main/resources/assets/antarchy/textures/block/bile/bile_vein.png.mcmeta new file mode 100644 index 00000000..b44a2ee6 --- /dev/null +++ b/common/src/main/resources/assets/antarchy/textures/block/bile/bile_vein.png.mcmeta @@ -0,0 +1,16 @@ +{ + "animation": { + "frametime": 16, + "interpolate": true, + "frames": [ + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1 + ] + } +} diff --git a/common/src/main/resources/assets/antarchy/textures/block/broodstone/broodstone.png b/common/src/main/resources/assets/antarchy/textures/block/broodstone/broodstone.png new file mode 100644 index 00000000..19504eca Binary files /dev/null and b/common/src/main/resources/assets/antarchy/textures/block/broodstone/broodstone.png differ diff --git a/common/src/main/resources/assets/antarchy/textures/particle/stinky_fly.png b/common/src/main/resources/assets/antarchy/textures/particle/stinky_fly.png new file mode 100644 index 00000000..cad03adc Binary files /dev/null and b/common/src/main/resources/assets/antarchy/textures/particle/stinky_fly.png differ diff --git a/common/src/main/resources/data/antarchy/loot_table/blocks/bile_vein.json b/common/src/main/resources/data/antarchy/loot_table/blocks/bile_vein.json new file mode 100644 index 00000000..32eb33c8 --- /dev/null +++ b/common/src/main/resources/data/antarchy/loot_table/blocks/bile_vein.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "antarchy:bile_vein" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "antarchy:blocks/bile_vein" +} diff --git a/common/src/main/resources/data/antarchy/worldgen/biome/cavaryn.json b/common/src/main/resources/data/antarchy/worldgen/biome/cavaryn.json index 0a5093bc..723be7ad 100644 --- a/common/src/main/resources/data/antarchy/worldgen/biome/cavaryn.json +++ b/common/src/main/resources/data/antarchy/worldgen/biome/cavaryn.json @@ -37,11 +37,10 @@ [], [], [ - "antarchy:cavaryn_bile_pools", - "antarchy:cavaryn_amber_moss_patch", + "antarchy:cavaryn_bile_veins", + "antarchy:cavaryn_bile_cysts", "antarchy:cavaryn_wall_amber_moss", "antarchy:cavaryn_creepvine", - "minecraft:glow_lichen", "antarchy:cavaryn_chiten_spikes", "antarchy:cavaryn_terror_egg_patch" ], @@ -63,15 +62,16 @@ "maxCount": 5 } ], - "creature": [], - "ambient": [ + "creature": [ { - "type": "minecraft:bat", + "type": "antarchy:stink_bug", "weight": 10, - "minCount": 4, - "maxCount": 8 + "minCount": 1, + "maxCount": 3 } ], + "ambient": [ + ], "axolotls": [], "underground_water_creature": [], "water_creature": [], diff --git a/common/src/main/resources/data/antarchy/worldgen/biome/fungal_ouranwood_forest.json b/common/src/main/resources/data/antarchy/worldgen/biome/fungal_ouranwood_forest.json new file mode 100644 index 00000000..56fe8dc0 --- /dev/null +++ b/common/src/main/resources/data/antarchy/worldgen/biome/fungal_ouranwood_forest.json @@ -0,0 +1,102 @@ +{ + "has_precipitation": false, + "temperature": 0.78, + "downfall": 0.95, + "effects": { + "fog_color": 8084735, + "water_color": 5021432, + "water_fog_color": 2502722, + "sky_color": 8084735, + "foliage_color": 2867501, + "grass_color": 4304168, + "grass_color_modifier": "none", + "particle": { + "probability": 0.009, + "options": { + "type": "minecraft:spore_blossom_air" + } + }, + "mood_sound": { + "sound": "minecraft:ambient.crimson_forest.mood", + "tick_delay": 6000, + "block_search_extent": 8, + "offset": 2.0 + } + }, + "spawn_costs": {}, + "carvers": { + "air": [], + "liquid": [] + }, + "features": [ + [], + [], + [], + [], + [], + [], + [ + "minecraft:ore_coal_upper", + "minecraft:ore_coal_lower", + "minecraft:ore_iron_upper", + "minecraft:ore_iron_middle", + "minecraft:ore_iron_small", + "minecraft:ore_gold", + "minecraft:ore_gold_lower", + "minecraft:ore_redstone", + "minecraft:ore_redstone_lower", + "minecraft:ore_diamond", + "minecraft:ore_diamond_medium", + "minecraft:ore_diamond_large", + "minecraft:ore_diamond_buried", + "minecraft:ore_lapis", + "minecraft:ore_lapis_buried", + "minecraft:ore_copper" + ], + [ + "antarchy:elythia_underground", + "minecraft:large_dripstone", + "minecraft:pointed_dripstone" + ], + [], + [ + "antarchy:ouranwood_trees_sparse", + "antarchy:elythia_forest_flora", + "antarchy:elythia_brown_ant_nests", + "antarchy:fallen_ouranwood_tree", + "antarchy:fungal_mushroom" + ], + [] + ], + "creature_spawn_probability": 0.07, + "spawners": { + "monster": [], + "creature": [ + { + "type": "antarchy:caterpillar", + "weight": 5, + "minCount": 1, + "maxCount": 2 + }, + { + "type": "antarchy:flying_squirrel", + "weight": 2, + "minCount": 1, + "maxCount": 2 + } + ], + "ambient": [ + { + "type": "antarchy:butterfly", + "weight": 7, + "minCount": 1, + "maxCount": 2 + } + ], + "axolotls": [], + "underground_water_creature": [], + "water_creature": [], + "water_ambient": [], + "misc": [] + } +} diff --git a/common/src/main/resources/data/antarchy/worldgen/configured_feature/cavaryn_bile_cysts.json b/common/src/main/resources/data/antarchy/worldgen/configured_feature/cavaryn_bile_cysts.json new file mode 100644 index 00000000..1616e268 --- /dev/null +++ b/common/src/main/resources/data/antarchy/worldgen/configured_feature/cavaryn_bile_cysts.json @@ -0,0 +1,4 @@ +{ + "type": "antarchy:cavaryn_bile_cysts", + "config": {} +} diff --git a/common/src/main/resources/data/antarchy/worldgen/configured_feature/cavaryn_bile_pools.json b/common/src/main/resources/data/antarchy/worldgen/configured_feature/cavaryn_bile_pools.json deleted file mode 100644 index e5a8f052..00000000 --- a/common/src/main/resources/data/antarchy/worldgen/configured_feature/cavaryn_bile_pools.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "antarchy:cavaryn_bile_pools", - "config": {} -} diff --git a/common/src/main/resources/data/antarchy/worldgen/configured_feature/cavaryn_bile_veins.json b/common/src/main/resources/data/antarchy/worldgen/configured_feature/cavaryn_bile_veins.json new file mode 100644 index 00000000..6a2a5e5d --- /dev/null +++ b/common/src/main/resources/data/antarchy/worldgen/configured_feature/cavaryn_bile_veins.json @@ -0,0 +1,4 @@ +{ + "type": "antarchy:cavaryn_bile_veins", + "config": {} +} diff --git a/common/src/main/resources/data/antarchy/worldgen/configured_feature/fallen_ouranwood_tree.json b/common/src/main/resources/data/antarchy/worldgen/configured_feature/fallen_ouranwood_tree.json new file mode 100644 index 00000000..5c93038c --- /dev/null +++ b/common/src/main/resources/data/antarchy/worldgen/configured_feature/fallen_ouranwood_tree.json @@ -0,0 +1,4 @@ +{ + "type": "antarchy:fallen_ouranwood_tree", + "config": {} +} diff --git a/common/src/main/resources/data/antarchy/worldgen/configured_feature/fungal_mushroom.json b/common/src/main/resources/data/antarchy/worldgen/configured_feature/fungal_mushroom.json new file mode 100644 index 00000000..5c113be3 --- /dev/null +++ b/common/src/main/resources/data/antarchy/worldgen/configured_feature/fungal_mushroom.json @@ -0,0 +1,4 @@ +{ + "type": "antarchy:fungal_mushroom", + "config": {} +} diff --git a/common/src/main/resources/data/antarchy/worldgen/noise_settings/cavaryn.json b/common/src/main/resources/data/antarchy/worldgen/noise_settings/cavaryn.json index 6a197ae1..9fd2adce 100644 --- a/common/src/main/resources/data/antarchy/worldgen/noise_settings/cavaryn.json +++ b/common/src/main/resources/data/antarchy/worldgen/noise_settings/cavaryn.json @@ -2,7 +2,7 @@ "sea_level": 32, "disable_mob_generation": false, "aquifers_enabled": true, - "ore_veins_enabled": true, + "ore_veins_enabled": false, "legacy_random_source": false, "default_block": { "Name": "antarchy:myrmite" @@ -99,73 +99,9 @@ } } }, - "vein_toggle": { - "type": "minecraft:interpolated", - "argument": { - "type": "minecraft:range_choice", - "input": "minecraft:y", - "min_inclusive": 0, - "max_exclusive": 208, - "when_in_range": { - "type": "minecraft:noise", - "noise": "minecraft:ore_veininess", - "xz_scale": 1.5, - "y_scale": 1.5 - }, - "when_out_of_range": 0 - } - }, - "vein_ridged": { - "type": "minecraft:add", - "argument1": -0.07999999821186066, - "argument2": { - "type": "minecraft:max", - "argument1": { - "type": "minecraft:abs", - "argument": { - "type": "minecraft:interpolated", - "argument": { - "type": "minecraft:range_choice", - "input": "minecraft:y", - "min_inclusive": 0, - "max_exclusive": 208, - "when_in_range": { - "type": "minecraft:noise", - "noise": "minecraft:ore_vein_a", - "xz_scale": 4, - "y_scale": 4 - }, - "when_out_of_range": 0 - } - } - }, - "argument2": { - "type": "minecraft:abs", - "argument": { - "type": "minecraft:interpolated", - "argument": { - "type": "minecraft:range_choice", - "input": "minecraft:y", - "min_inclusive": 0, - "max_exclusive": 208, - "when_in_range": { - "type": "minecraft:noise", - "noise": "minecraft:ore_vein_b", - "xz_scale": 4, - "y_scale": 4 - }, - "when_out_of_range": 0 - } - } - } - } - }, - "vein_gap": { - "type": "minecraft:noise", - "noise": "minecraft:ore_gap", - "xz_scale": 1, - "y_scale": 1 - } + "vein_toggle": 0, + "vein_ridged": 0, + "vein_gap": 0 }, "spawn_target": [ { diff --git a/common/src/main/resources/data/antarchy/worldgen/noise_settings/elythia.json b/common/src/main/resources/data/antarchy/worldgen/noise_settings/elythia.json index 0b3e9e86..3c660ef9 100644 --- a/common/src/main/resources/data/antarchy/worldgen/noise_settings/elythia.json +++ b/common/src/main/resources/data/antarchy/worldgen/noise_settings/elythia.json @@ -430,7 +430,7 @@ }, "then_run": { "type": "minecraft:block", - "result_state": { "Name": "minecraft:gravel" } + "result_state": { "Name": "minecraft:sand" } } } }, @@ -511,7 +511,7 @@ }, "then_run": { "type": "minecraft:block", - "result_state": { "Name": "minecraft:gravel" } + "result_state": { "Name": "minecraft:sand" } } }, { diff --git a/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_bile_pools.json b/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_bile_cysts.json similarity index 90% rename from common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_bile_pools.json rename to common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_bile_cysts.json index f7f99b3a..4a0cdc9f 100644 --- a/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_bile_pools.json +++ b/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_bile_cysts.json @@ -1,5 +1,5 @@ { - "feature": "antarchy:cavaryn_bile_pools", + "feature": "antarchy:cavaryn_bile_cysts", "placement": [ { "type": "minecraft:count", diff --git a/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_bile_veins.json b/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_bile_veins.json new file mode 100644 index 00000000..ffd3ef6c --- /dev/null +++ b/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_bile_veins.json @@ -0,0 +1,27 @@ +{ + "feature": "antarchy:cavaryn_bile_veins", + "placement": [ + { + "type": "minecraft:count", + "count": 5 + }, + { + "type": "minecraft:in_square" + }, + { + "type": "minecraft:height_range", + "height": { + "type": "minecraft:uniform", + "min_inclusive": { + "above_bottom": 8 + }, + "max_inclusive": { + "below_top": 16 + } + } + }, + { + "type": "minecraft:biome" + } + ] +} diff --git a/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_terror_egg_patch.json b/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_terror_egg_patch.json index 053fcd8a..01c6693b 100644 --- a/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_terror_egg_patch.json +++ b/common/src/main/resources/data/antarchy/worldgen/placed_feature/cavaryn_terror_egg_patch.json @@ -3,7 +3,7 @@ "placement": [ { "type": "minecraft:count", - "count": 2 + "count": 1 }, { "type": "minecraft:in_square" diff --git a/common/src/main/resources/data/antarchy/worldgen/placed_feature/fallen_ouranwood_tree.json b/common/src/main/resources/data/antarchy/worldgen/placed_feature/fallen_ouranwood_tree.json new file mode 100644 index 00000000..de592a7f --- /dev/null +++ b/common/src/main/resources/data/antarchy/worldgen/placed_feature/fallen_ouranwood_tree.json @@ -0,0 +1,9 @@ +{ + "feature": "antarchy:fallen_ouranwood_tree", + "placement": [ + { "type": "minecraft:rarity_filter", "chance": 5 }, + { "type": "minecraft:in_square" }, + { "type": "minecraft:heightmap", "heightmap": "WORLD_SURFACE_WG" }, + { "type": "minecraft:biome" } + ] +} diff --git a/common/src/main/resources/data/antarchy/worldgen/placed_feature/fungal_mushroom.json b/common/src/main/resources/data/antarchy/worldgen/placed_feature/fungal_mushroom.json new file mode 100644 index 00000000..a720f1e1 --- /dev/null +++ b/common/src/main/resources/data/antarchy/worldgen/placed_feature/fungal_mushroom.json @@ -0,0 +1,9 @@ +{ + "feature": "antarchy:fungal_mushroom", + "placement": [ + { "type": "minecraft:rarity_filter", "chance": 4 }, + { "type": "minecraft:in_square" }, + { "type": "minecraft:heightmap", "heightmap": "WORLD_SURFACE_WG" }, + { "type": "minecraft:biome" } + ] +} diff --git a/common/src/main/resources/data/minecraft/tags/block/mineable/pickaxe.json b/common/src/main/resources/data/minecraft/tags/block/mineable/pickaxe.json index 71f8d9f6..3abcdbf5 100644 --- a/common/src/main/resources/data/minecraft/tags/block/mineable/pickaxe.json +++ b/common/src/main/resources/data/minecraft/tags/block/mineable/pickaxe.json @@ -37,6 +37,7 @@ "antarchy:nyxite_brick_slab", "antarchy:nyxite_brick_wall", "antarchy:myrmite", + "antarchy:bile_vein", "antarchy:chiten_block", "antarchy:chiten_spike", "antarchy:shellstone", diff --git a/common/src/main/resources/data/minecraft/tags/block/needs_stone_tool.json b/common/src/main/resources/data/minecraft/tags/block/needs_stone_tool.json index 05865e45..33cea4cb 100644 --- a/common/src/main/resources/data/minecraft/tags/block/needs_stone_tool.json +++ b/common/src/main/resources/data/minecraft/tags/block/needs_stone_tool.json @@ -19,6 +19,7 @@ "antarchy:shellstone_brick_stairs", "antarchy:shellstone_brick_slab", "antarchy:shellstone_brick_wall", - "antarchy:chiten_block" + "antarchy:chiten_block", + "antarchy:bile_vein" ] } diff --git a/fabric/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricContent.java b/fabric/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricContent.java index 6e6147d5..c28299ce 100644 --- a/fabric/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricContent.java +++ b/fabric/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricContent.java @@ -19,7 +19,8 @@ import com.craisinlord.antarchy.content.worldgen.ants.BrownAntNestFeature; import com.craisinlord.antarchy.content.worldgen.ants.RainbowAntNestFeature; import com.craisinlord.antarchy.content.worldgen.ants.RedAntNestFeature; import com.craisinlord.antarchy.content.worldgen.ants.TermiteNestFeature; -import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynBilePoolFeature; +import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynBileCystFeature; +import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynBileVeinFeature; import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynCreepvineFeature; import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynWallAmberMossFeature; import com.craisinlord.antarchy.content.worldgen.thoraxis.NyxiteSpikeConfiguration; @@ -612,13 +613,17 @@ public final class AntarchyFabricContent { public static final DeferredBlock AMBER_MOSS_CARPET = BLOCKS.register("amber_moss_carpet", () -> new UmbralMossCarpetBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.MOSS_CARPET).noOcclusion())); public static final DeferredBlock AMBER_LICHEN = BLOCKS.register("amber_lichen", - () -> new GlowLichenBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.GLOW_LICHEN).lightLevel(state -> 0))); + () -> new GlowLichenBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.GLOW_LICHEN).lightLevel(state -> 1))); + public static final DeferredBlock BILE_VEIN = BLOCKS.register("bile_vein", + () -> new Block(BlockBehaviour.Properties.ofFullCopy(Blocks.NETHERRACK))); public static final DeferredBlock CREEPVINE = BLOCKS.register("creepvine", () -> new VineBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.VINE))); public static final DeferredHolder, SimpleParticleType> DREAM_FIRE_FLAME = PARTICLE_TYPES.register("dream_fire_flame", () -> simpleParticleType()); public static final DeferredHolder, SimpleParticleType> STINKY_GAS = PARTICLE_TYPES.register("stinky_gas", () -> simpleParticleType()); + public static final DeferredHolder, SimpleParticleType> STINKY_FLY = PARTICLE_TYPES.register("stinky_fly", + () -> simpleParticleType()); public static final DeferredHolder, SimpleParticleType> HYPNOTIC_GAS = PARTICLE_TYPES.register("hypnotic_gas", () -> simpleParticleType()); public static final DeferredHolder, SimpleParticleType> HYPNOTIC_GAS_CLOUD = PARTICLE_TYPES.register("hypnotic_gas_cloud", @@ -1060,8 +1065,10 @@ public final class AntarchyFabricContent { () -> new NyxiteSpikeFeature(NyxiteSpikeConfiguration.CODEC)); public static final DeferredHolder, ChitenSpikeFeature> CAVARYN_CHITEN_SPIKES = FEATURES.register("cavaryn_chiten_spikes", () -> new ChitenSpikeFeature(ChitenSpikeConfiguration.CODEC)); - public static final DeferredHolder, CavarynBilePoolFeature> CAVARYN_BILE_POOLS = FEATURES.register("cavaryn_bile_pools", - () -> new CavarynBilePoolFeature(NoneFeatureConfiguration.CODEC)); + public static final DeferredHolder, CavarynBileVeinFeature> CAVARYN_BILE_VEINS = FEATURES.register("cavaryn_bile_veins", + () -> new CavarynBileVeinFeature(NoneFeatureConfiguration.CODEC)); + public static final DeferredHolder, CavarynBileCystFeature> CAVARYN_BILE_CYSTS = FEATURES.register("cavaryn_bile_cysts", + () -> new CavarynBileCystFeature(NoneFeatureConfiguration.CODEC)); public static final DeferredHolder, CavarynCreepvineFeature> CAVARYN_CREEPVINE = FEATURES.register("cavaryn_creepvine", () -> new CavarynCreepvineFeature(NoneFeatureConfiguration.CODEC)); public static final DeferredHolder, CavarynWallAmberMossFeature> CAVARYN_WALL_AMBER_MOSS = FEATURES.register("cavaryn_wall_amber_moss", @@ -1226,6 +1233,7 @@ public final class AntarchyFabricContent { public static final DeferredItem AMBER_MOSS_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(AMBER_MOSS_BLOCK); public static final DeferredItem AMBER_MOSS_CARPET_ITEM = ITEMS.registerSimpleBlockItem(AMBER_MOSS_CARPET); public static final DeferredItem AMBER_LICHEN_ITEM = ITEMS.registerSimpleBlockItem(AMBER_LICHEN); + public static final DeferredItem BILE_VEIN_ITEM = ITEMS.registerSimpleBlockItem(BILE_VEIN); public static final DeferredItem CREEPVINE_ITEM = ITEMS.registerSimpleBlockItem(CREEPVINE); public static final DeferredItem DREAM_TORCH_ITEM = ITEMS.register("dream_torch", () -> new StandingAndWallBlockItem(DREAM_TORCH.get(), DREAM_WALL_TORCH.get(), new Item.Properties(), Direction.UP)); @@ -1994,6 +2002,7 @@ public final class AntarchyFabricContent { "chiseled_titanium", "uranium_bulb", "titanium_bulb", "uranium_door", "titanium_door", "uranium_trapdoor", "titanium_trapdoor", "uranium_bars", "titanium_bars" -> 8; + case "bile_vein" -> 9; case "infested_rooted_dirt", "infested_coarse_dirt", "triffid_goo_block", "cloud_block", "creeping_horror_egg", "lurking_terror_egg" -> 9; case "dream_torch", "dream_lantern", "dream_campfire", "dream_fire", "dream_fire_ceiling" -> 10; @@ -2493,6 +2502,7 @@ public final class AntarchyFabricContent { () -> WASP_NEST_BLOCK_ENTITY.get(), () -> HUSHWEED_BLOCK_ENTITY.get(), () -> STINKY_GAS.get(), + () -> STINKY_FLY.get(), () -> attributeHolder(DOUBLE_DAMAGE_CHANCE), () -> attributeHolder(BLOODGLASS_MAX_HEARTS), () -> mobEffectHolder(BLOODGLASS_WARD) diff --git a/fabric/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java b/fabric/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java index bf0241bb..04d4786e 100644 --- a/fabric/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java +++ b/fabric/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java @@ -181,6 +181,7 @@ public final class AntarchyFabricClientBootstrap { ParticleFactoryRegistry registry = ParticleFactoryRegistry.getInstance(); registry.register(AntarchyFabricContent.DREAM_FIRE_FLAME.get(), DreamFlameParticle.Provider::new); registry.register(AntarchyFabricContent.STINKY_GAS.get(), HypnoticGasParticle.Provider::new); + registry.register(AntarchyFabricContent.STINKY_FLY.get(), FireflyParticle.Provider::new); registry.register(AntarchyFabricContent.HYPNOTIC_GAS.get(), HypnoticGasParticle.Provider::new); registry.register(AntarchyFabricContent.HYPNOTIC_GAS_DOWN.get(), sprites -> new HypnoticGasParticle.Provider(sprites, true)); registry.register(AntarchyFabricContent.HYPNOTIC_GAS_CLOUD.get(), new HypnoticGasCloudParticle.Provider()); @@ -209,6 +210,7 @@ public final class AntarchyFabricClientBootstrap { BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.UMBRAL_MOSS_CARPET.get(), RenderType.cutout()); BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.AMBER_MOSS_CARPET.get(), RenderType.cutout()); BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.AMBER_LICHEN.get(), RenderType.cutout()); + BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.BILE_VEIN.get(), RenderType.cutout()); BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.CREEPVINE.get(), RenderType.cutout()); BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.NYXITE_SPIKE.get(), RenderType.cutout()); BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricContent.CHITEN_SPIKE.get(), RenderType.cutout()); diff --git a/fabric/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntimetalScaffoldingMixin.java b/fabric/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntimetalScaffoldingMixin.java index 472d9277..c96f551f 100644 --- a/fabric/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntimetalScaffoldingMixin.java +++ b/fabric/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntimetalScaffoldingMixin.java @@ -77,7 +77,7 @@ public abstract class AntimetalScaffoldingMixin { BlockState below = level.getBlockState(cursor); int distance = 7; if (below.is((ScaffoldingBlock) (Object) this)) { - distance = below.getValue(ScaffoldingBlock.DISTANCE); + distance = below.getValue(ScaffoldingBlock.DISTANCE) + 1; } else if (below.isFaceSturdy(level, cursor, Direction.UP)) { return 0; } diff --git a/fabric/src/main/java/com/craisinlord/antarchy/fabric/mixin/client/ToreterrorCameraShakeMixin.java b/fabric/src/main/java/com/craisinlord/antarchy/fabric/mixin/client/ToreterrorCameraShakeMixin.java index 5a041348..8e2a362a 100644 --- a/fabric/src/main/java/com/craisinlord/antarchy/fabric/mixin/client/ToreterrorCameraShakeMixin.java +++ b/fabric/src/main/java/com/craisinlord/antarchy/fabric/mixin/client/ToreterrorCameraShakeMixin.java @@ -1,6 +1,7 @@ package com.craisinlord.antarchy.fabric.mixin.client; import com.craisinlord.antarchy.content.entity.ToreterrorEntity; +import com.craisinlord.antarchy.content.item.BigBerthaItem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; import net.minecraft.client.Minecraft; @@ -17,6 +18,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(GameRenderer.class) public abstract class ToreterrorCameraShakeMixin { private static final double MAX_SHAKE_RANGE = 48.0D; + private static final int TORETERROR_SHAKE_TICKS = 25; @Shadow @Final private Minecraft minecraft; @@ -37,6 +39,10 @@ public abstract class ToreterrorCameraShakeMixin { shakeStrength += (float) ((1.0D - distance / MAX_SHAKE_RANGE) * 2.0F); } + if (BigBerthaItem.clientShakeTicks > 0) { + shakeStrength += (float) BigBerthaItem.clientShakeTicks / TORETERROR_SHAKE_TICKS * 2.0F; + } + if (shakeStrength <= 0.0F) return; float time = (float) (minecraft.player.tickCount + partialTick); diff --git a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforge.java b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforge.java index b8869f66..4af30751 100644 --- a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforge.java +++ b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforge.java @@ -250,6 +250,7 @@ public class AntarchyNeoforge { () -> AntarchyNeoforgeBlocks.WASP_NEST_BLOCK_ENTITY.get(), () -> AntarchyNeoforgeBlocks.HUSHWEED_BLOCK_ENTITY.get(), () -> AntarchyNeoforgeMisc.STINKY_GAS.get(), + () -> AntarchyNeoforgeMisc.STINKY_FLY.get(), () -> AntarchyNeoforgeMisc.DOUBLE_DAMAGE_CHANCE, () -> AntarchyNeoforgeMisc.BLOODGLASS_MAX_HEARTS, () -> AntarchyNeoforgeMisc.BLOODGLASS_WARD diff --git a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java index aa9aba07..f6fda2b9 100644 --- a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java +++ b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java @@ -200,6 +200,7 @@ public final class AntarchyNeoForgeClient { public static void registerParticleProviders(RegisterParticleProvidersEvent event) { event.registerSpriteSet(AntarchyNeoforgeMisc.DREAM_FIRE_FLAME.get(), DreamFlameParticle.Provider::new); event.registerSpriteSet(AntarchyNeoforgeMisc.STINKY_GAS.get(), HypnoticGasParticle.Provider::new); + event.registerSpriteSet(AntarchyNeoforgeMisc.STINKY_FLY.get(), FireflyParticle.Provider::new); event.registerSpriteSet(AntarchyNeoforgeMisc.HYPNOTIC_GAS.get(), HypnoticGasParticle.Provider::new); event.registerSpriteSet(AntarchyNeoforgeMisc.HYPNOTIC_GAS_DOWN.get(), sprites -> new HypnoticGasParticle.Provider(sprites, true)); event.registerSpecial(AntarchyNeoforgeMisc.HYPNOTIC_GAS_CLOUD.get(), new HypnoticGasCloudParticle.Provider()); @@ -397,6 +398,7 @@ public final class AntarchyNeoForgeClient { ItemBlockRenderTypes.setRenderLayer(AntarchyNeoforgeBlocks.UMBRAL_MOSS_CARPET.get(), RenderType.cutout()); ItemBlockRenderTypes.setRenderLayer(AntarchyNeoforgeBlocks.AMBER_MOSS_CARPET.get(), RenderType.cutout()); ItemBlockRenderTypes.setRenderLayer(AntarchyNeoforgeBlocks.AMBER_LICHEN.get(), RenderType.cutout()); + ItemBlockRenderTypes.setRenderLayer(AntarchyNeoforgeBlocks.BILE_VEIN.get(), RenderType.cutout()); ItemBlockRenderTypes.setRenderLayer(AntarchyNeoforgeBlocks.CREEPVINE.get(), RenderType.cutout()); ItemBlockRenderTypes.setRenderLayer(AntarchyNeoforgeBlocks.NYXITE_SPIKE.get(), RenderType.cutout()); ItemBlockRenderTypes.setRenderLayer(AntarchyNeoforgeBlocks.CHITEN_SPIKE.get(), RenderType.cutout()); diff --git a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/ToreterrorCameraShakeHandler.java b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/ToreterrorCameraShakeHandler.java index 31759cc0..480428cc 100644 --- a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/ToreterrorCameraShakeHandler.java +++ b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/client/ToreterrorCameraShakeHandler.java @@ -2,6 +2,7 @@ package com.craisinlord.antarchy.neoforge.client; import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.content.entity.ToreterrorEntity; +import com.craisinlord.antarchy.content.item.BigBerthaItem; import net.minecraft.client.Minecraft; import net.minecraft.util.Mth; import net.minecraft.world.phys.Vec3; @@ -13,6 +14,7 @@ import net.neoforged.neoforge.client.event.ViewportEvent; @EventBusSubscriber(modid = Antarchy.MODID, value = Dist.CLIENT) public final class ToreterrorCameraShakeHandler { private static final double MAX_SHAKE_RANGE = 48.0D; + private static final int TORETERROR_SHAKE_TICKS = 25; private ToreterrorCameraShakeHandler() { } @@ -35,6 +37,10 @@ public final class ToreterrorCameraShakeHandler { shakeStrength += (float) ((1.0D - distance / MAX_SHAKE_RANGE) * 2.0D); } + if (BigBerthaItem.clientShakeTicks > 0) { + shakeStrength += (float) BigBerthaItem.clientShakeTicks / TORETERROR_SHAKE_TICKS * 2.0F; + } + if (shakeStrength <= 0.0F) return; float time = (float) (mc.player.tickCount + event.getPartialTick()); diff --git a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeBlocks.java b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeBlocks.java index 4f6cd7a1..22abf3e2 100644 --- a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeBlocks.java +++ b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeBlocks.java @@ -194,7 +194,9 @@ public final class AntarchyNeoforgeBlocks { public static final DeferredBlock AMBER_MOSS_CARPET = BLOCKS.register("amber_moss_carpet", () -> new UmbralMossCarpetBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.MOSS_CARPET).noOcclusion())); public static final DeferredBlock AMBER_LICHEN = BLOCKS.register("amber_lichen", - () -> new GlowLichenBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.GLOW_LICHEN).lightLevel(state -> 0))); + () -> new GlowLichenBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.GLOW_LICHEN).lightLevel(state -> 1))); + public static final DeferredBlock BILE_VEIN = BLOCKS.register("bile_vein", + () -> new Block(BlockBehaviour.Properties.ofFullCopy(Blocks.NETHERRACK))); public static final DeferredBlock CREEPVINE = BLOCKS.register("creepvine", () -> new VineBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.VINE))); public static final DeferredBlock DREAM_TORCH = BLOCKS.register("dream_torch", diff --git a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeCreativeModeTabs.java b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeCreativeModeTabs.java index e81c6828..249350ac 100644 --- a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeCreativeModeTabs.java +++ b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeCreativeModeTabs.java @@ -245,6 +245,7 @@ public class AntarchyNeoforgeCreativeModeTabs { event.accept(AntarchyNeoforgeItems.MEDIUM_BLOOD_CRYSTAL_BUD_ITEM.get()); event.accept(AntarchyNeoforgeItems.LARGE_BLOOD_CRYSTAL_BUD_ITEM.get()); event.accept(AntarchyNeoforgeItems.MYRMITE_ITEM.get()); + event.accept(AntarchyNeoforgeItems.BILE_VEIN_ITEM.get()); event.accept(AntarchyNeoforgeItems.CHITEN_BLOCK_ITEM.get()); event.accept(AntarchyNeoforgeItems.CHITEN_SPIKE_ITEM.get()); event.accept(AntarchyNeoforgeItems.AMBER_MOSS_BLOCK_ITEM.get()); @@ -388,7 +389,7 @@ public class AntarchyNeoforgeCreativeModeTabs { case "duplicator_sapling", "ouranwood_acorn" -> 10; // 11 - Plants and flowers - case "orange_milkweed", "pink_milkweed", "torchflower_bush", "hushweed", "amber_lichen", "creepvine", + case "orange_milkweed", "pink_milkweed", "torchflower_bush", "hushweed", "amber_lichen", "bile_vein", "creepvine", "triffid_goo_block", "wasp_nest", "red_ant_nest", "brown_ant_nest", "rainbow_ant_nest", "termite_nest" -> 11; diff --git a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeItems.java b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeItems.java index d099b76b..efa03b38 100644 --- a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeItems.java +++ b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeItems.java @@ -272,6 +272,7 @@ public final class AntarchyNeoforgeItems { public static final DeferredItem AMBER_MOSS_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(AntarchyNeoforgeBlocks.AMBER_MOSS_BLOCK); public static final DeferredItem AMBER_MOSS_CARPET_ITEM = ITEMS.registerSimpleBlockItem(AntarchyNeoforgeBlocks.AMBER_MOSS_CARPET); public static final DeferredItem AMBER_LICHEN_ITEM = ITEMS.registerSimpleBlockItem(AntarchyNeoforgeBlocks.AMBER_LICHEN); + public static final DeferredItem BILE_VEIN_ITEM = ITEMS.registerSimpleBlockItem(AntarchyNeoforgeBlocks.BILE_VEIN); public static final DeferredItem CREEPVINE_ITEM = ITEMS.registerSimpleBlockItem(AntarchyNeoforgeBlocks.CREEPVINE); public static final DeferredItem DREAM_TORCH_ITEM = ITEMS.register("dream_torch", () -> new StandingAndWallBlockItem(AntarchyNeoforgeBlocks.DREAM_TORCH.get(), AntarchyNeoforgeBlocks.DREAM_WALL_TORCH.get(), new Item.Properties(), net.minecraft.core.Direction.UP)); diff --git a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeMisc.java b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeMisc.java index 85643a47..43f507fd 100644 --- a/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeMisc.java +++ b/neoforge/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeMisc.java @@ -13,7 +13,8 @@ import com.craisinlord.antarchy.content.worldgen.ants.BrownAntNestFeature; import com.craisinlord.antarchy.content.worldgen.ants.RainbowAntNestFeature; import com.craisinlord.antarchy.content.worldgen.ants.RedAntNestFeature; import com.craisinlord.antarchy.content.worldgen.ants.TermiteNestFeature; -import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynBilePoolFeature; +import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynBileCystFeature; +import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynBileVeinFeature; import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynCreepvineFeature; import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynEggPatchFeature; import com.craisinlord.antarchy.content.worldgen.cavaryn.CavarynWallAmberMossFeature; @@ -164,6 +165,8 @@ public final class AntarchyNeoforgeMisc { () -> new SimpleParticleType(true)); public static final DeferredHolder, SimpleParticleType> STINKY_GAS = PARTICLE_TYPES.register("stinky_gas", () -> new SimpleParticleType(true)); + public static final DeferredHolder, SimpleParticleType> STINKY_FLY = PARTICLE_TYPES.register("stinky_fly", + () -> new SimpleParticleType(true)); public static final DeferredHolder, SimpleParticleType> HYPNOTIC_GAS = PARTICLE_TYPES.register("hypnotic_gas", () -> new SimpleParticleType(true)); public static final DeferredHolder, SimpleParticleType> HYPNOTIC_GAS_CLOUD = PARTICLE_TYPES.register("hypnotic_gas_cloud", @@ -250,8 +253,10 @@ public final class AntarchyNeoforgeMisc { () -> new NyxiteSpikeFeature(NyxiteSpikeConfiguration.CODEC)); public static final DeferredHolder, ChitenSpikeFeature> CAVARYN_CHITEN_SPIKES = FEATURES.register("cavaryn_chiten_spikes", () -> new ChitenSpikeFeature(ChitenSpikeConfiguration.CODEC)); - public static final DeferredHolder, CavarynBilePoolFeature> CAVARYN_BILE_POOLS = FEATURES.register("cavaryn_bile_pools", - () -> new CavarynBilePoolFeature(NoneFeatureConfiguration.CODEC)); + public static final DeferredHolder, CavarynBileVeinFeature> CAVARYN_BILE_VEINS = FEATURES.register("cavaryn_bile_veins", + () -> new CavarynBileVeinFeature(NoneFeatureConfiguration.CODEC)); + public static final DeferredHolder, CavarynBileCystFeature> CAVARYN_BILE_CYSTS = FEATURES.register("cavaryn_bile_cysts", + () -> new CavarynBileCystFeature(NoneFeatureConfiguration.CODEC)); public static final DeferredHolder, CavarynCreepvineFeature> CAVARYN_CREEPVINE = FEATURES.register("cavaryn_creepvine", () -> new CavarynCreepvineFeature(NoneFeatureConfiguration.CODEC)); public static final DeferredHolder, CavarynWallAmberMossFeature> CAVARYN_WALL_AMBER_MOSS = FEATURES.register("cavaryn_wall_amber_moss",