diff --git a/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveTargetingUtils.java b/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveTargetingUtils.java index 3b82d28..465fc95 100644 --- a/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveTargetingUtils.java +++ b/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveTargetingUtils.java @@ -16,6 +16,10 @@ public final class AdaptiveTargetingUtils { private AdaptiveTargetingUtils() { } + public static boolean areCombatAllies(Mob first, Mob second) { + return first.isAlliedTo(second) || second.isAlliedTo(first) || first.getType() == second.getType(); + } + public static List nearbyHostiles(Mob mob, double radius, Predicate predicate) { AABB box = mob.getBoundingBox().inflate(radius); List found = mob.level().getEntitiesOfClass(Mob.class, box, @@ -46,7 +50,8 @@ public final class AdaptiveTargetingUtils { return false; } List allies = nearbyHostiles(mob, Math.min(16.0D, Math.sqrt(lenSqr) + 2.0D), - other -> other.getTarget() == target || other.getTarget() == null); + other -> areCombatAllies(mob, other) + && (other.getTarget() == target || other.getTarget() == null)); for (Mob ally : allies) { Vec3 toAlly = ally.position().add(0.0D, ally.getBbHeight() * 0.5D, 0.0D).subtract(start); double t = toAlly.dot(line) / lenSqr; diff --git a/src/main/java/net/fretux/adaptivemobs/ai/goals/AdaptiveSlimeTacticsGoal.java b/src/main/java/net/fretux/adaptivemobs/ai/goals/AdaptiveSlimeTacticsGoal.java index 43de8aa..a84578e 100644 --- a/src/main/java/net/fretux/adaptivemobs/ai/goals/AdaptiveSlimeTacticsGoal.java +++ b/src/main/java/net/fretux/adaptivemobs/ai/goals/AdaptiveSlimeTacticsGoal.java @@ -3,6 +3,7 @@ package net.fretux.adaptivemobs.ai.goals; import net.fretux.adaptivemobs.ai.AdaptiveAIGoalUtils; import net.fretux.adaptivemobs.ai.AdaptivePositioningUtils; import net.fretux.adaptivemobs.config.AMConfig; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.goal.Goal; import net.minecraft.world.entity.monster.MagmaCube; @@ -147,6 +148,7 @@ public class AdaptiveSlimeTacticsGoal extends Goal { LivingEntity inheritedTarget = AdaptiveAIGoalUtils.isValidAdaptiveTarget(slime.getTarget()) ? slime.getTarget() : partner.getTarget(); float healthFraction = slime.getHealth() / slime.getMaxHealth(); + absorbPartnerState(partner); partner.discard(); slime.setSize(Math.min(MAX_RECOMBINE_SIZE, slime.getSize() * 2), false); slime.setHealth(Math.max(1.0F, Math.min(slime.getMaxHealth(), slime.getMaxHealth() * healthFraction))); @@ -159,6 +161,29 @@ public class AdaptiveSlimeTacticsGoal extends Goal { return true; } + private void absorbPartnerState(Slime partner) { + if (!slime.hasCustomName() && partner.hasCustomName()) { + slime.setCustomName(partner.getCustomName()); + slime.setCustomNameVisible(partner.isCustomNameVisible()); + } + if (partner.isPersistenceRequired()) { + slime.setPersistenceRequired(); + } + partner.getActiveEffects().forEach(effect -> + slime.addEffect(new net.minecraft.world.effect.MobEffectInstance(effect))); + for (EquipmentSlot slot : EquipmentSlot.values()) { + if (slime.getItemBySlot(slot).isEmpty() && !partner.getItemBySlot(slot).isEmpty()) { + slime.setItemSlot(slot, partner.getItemBySlot(slot).copy()); + } + } + slime.getPersistentData().merge(partner.getPersistentData().copy()); + slime.getPersistentData().remove(RECOMBINE_CLAIM_KEY); + slime.getPersistentData().remove(RECOMBINE_CLAIM_EXPIRES_KEY); + if (partner.isLeashed() && partner.getLeashHolder() != null) { + slime.setLeashedTo(partner.getLeashHolder(), true); + } + } + private boolean validPartner(Slime partner, boolean requireClaim) { if (partner == null || partner == slime || !partner.isAlive() || !slime.isAlive() || tierSupplier.getAsInt() < 5 || slime.getSize() >= MAX_RECOMBINE_SIZE @@ -203,8 +228,6 @@ public class AdaptiveSlimeTacticsGoal extends Goal { private void scheduleRecombine(int delayTicks) { if (slime.getPersistentData().getLong(RECOMBINE_READY_AT_KEY) == 0L) { slime.getPersistentData().putLong(RECOMBINE_READY_AT_KEY, slime.level().getGameTime() + delayTicks); - } else if (slime.getSize() > 1) { - slime.getPersistentData().putLong(RECOMBINE_READY_AT_KEY, slime.level().getGameTime() + delayTicks); } } } diff --git a/src/main/java/net/fretux/adaptivemobs/event/AdaptiveMobsEvents.java b/src/main/java/net/fretux/adaptivemobs/event/AdaptiveMobsEvents.java index 60ed41d..0ef0de1 100644 --- a/src/main/java/net/fretux/adaptivemobs/event/AdaptiveMobsEvents.java +++ b/src/main/java/net/fretux/adaptivemobs/event/AdaptiveMobsEvents.java @@ -50,7 +50,9 @@ public class AdaptiveMobsEvents { @SubscribeEvent public void onLivingDeath(LivingDeathEvent event) { LivingEntity killed = event.getEntity(); - if (!(event.getSource().getEntity() instanceof ServerPlayer player)) { + ServerPlayer player = event.getSource().getEntity() instanceof ServerPlayer directPlayer + ? directPlayer : killed.getKillCredit() instanceof ServerPlayer creditedPlayer ? creditedPlayer : null; + if (player == null) { return; } AdaptiveDifficultyManager.recordKill(player, killed); @@ -77,7 +79,7 @@ public class AdaptiveMobsEvents { return; } int tier = AdaptiveDifficultyManager.getMobTier(level, victim.getType()); - if (!attacker.isAlliedTo(victim) && !victim.isAlliedTo(attacker)) { + if (!net.fretux.adaptivemobs.ai.AdaptiveTargetingUtils.areCombatAllies(attacker, victim)) { return; } if (tier < 2 || !AMConfig.isMobEnabled(victim.getType())) { @@ -165,8 +167,7 @@ public class AdaptiveMobsEvents { } Entity entity = event.getEntity(); if (AMConfig.enabled && entity instanceof Mob mob && mob instanceof Enemy - && AMConfig.isMobEnabled(mob.getType()) - && mob.getPersistentData().getBoolean(PENDING_SPAWN_PROCESSING_KEY)) { + && AMConfig.isMobEnabled(mob.getType())) { mob.getPersistentData().remove(PENDING_SPAWN_PROCESSING_KEY); int tier = AdaptiveDifficultyManager.getMobTier(level, mob.getType()); MobStatScaler.applyScaling(mob, tier); @@ -204,6 +205,18 @@ public class AdaptiveMobsEvents { @SubscribeEvent public void onServerTick(TickEvent.ServerTickEvent event) { AdaptiveSpecialAbilities.onServerTick(event); + if (event.phase == TickEvent.Phase.END && AMConfig.enabled + && event.getServer().getTickCount() % 100 == 0) { + for (ServerLevel level : event.getServer().getAllLevels()) { + for (Entity entity : level.getAllEntities()) { + if (entity instanceof Mob mob && mob instanceof Enemy && AMConfig.isMobEnabled(mob.getType())) { + int tier = AdaptiveDifficultyManager.getMobTier(level, mob.getType()); + MobStatScaler.applyScaling(mob, tier); + GearScaler.applyGear(mob, tier); + } + } + } + } } @SubscribeEvent diff --git a/src/main/java/net/fretux/adaptivemobs/gear/GearScaler.java b/src/main/java/net/fretux/adaptivemobs/gear/GearScaler.java index c44ea0e..1cc5bf0 100644 --- a/src/main/java/net/fretux/adaptivemobs/gear/GearScaler.java +++ b/src/main/java/net/fretux/adaptivemobs/gear/GearScaler.java @@ -37,10 +37,10 @@ public final class GearScaler { if (mob.getPersistentData().getBoolean(GEAR_APPLIED_KEY)) { return; } - mob.getPersistentData().putBoolean(GEAR_APPLIED_KEY, true); if (!AMConfig.GEAR_SCALING_ENABLED.get() || tier <= 0) { return; } + mob.getPersistentData().putBoolean(GEAR_APPLIED_KEY, true); RandomSource random = mob.getRandom(); if (mob instanceof AbstractSkeleton skeleton) { diff --git a/src/main/java/net/fretux/adaptivemobs/scaling/MobStatScaler.java b/src/main/java/net/fretux/adaptivemobs/scaling/MobStatScaler.java index 2a4e09c..4c64a8f 100644 --- a/src/main/java/net/fretux/adaptivemobs/scaling/MobStatScaler.java +++ b/src/main/java/net/fretux/adaptivemobs/scaling/MobStatScaler.java @@ -32,7 +32,6 @@ public final class MobStatScaler { */ public static void applyScaling(Mob mob, int tier) { if (!AMConfig.STAT_SCALING_ENABLED.get() || tier <= 0) { - AdaptiveMobData.markScaled(mob, Math.max(tier, 0)); return; } if (AdaptiveMobData.isScaled(mob)) {