fix various issues and add adaptive creeper fuse
This commit is contained in:
@@ -31,15 +31,15 @@ Mob-specific tiers can rise further when players repeatedly kill the same mob ty
|
|||||||
|
|
||||||
At the highest default tier, eligible hostile mobs receive:
|
At the highest default tier, eligible hostile mobs receive:
|
||||||
|
|
||||||
- `+75%` max health.
|
- `+95%` max health.
|
||||||
- `+45%` attack damage when the mob has an attack damage attribute.
|
- `+60%` attack damage when the mob has an attack damage attribute.
|
||||||
- `+5%` movement speed.
|
- `+7%` movement speed.
|
||||||
- `+25%` follow range.
|
- `+25%` follow range.
|
||||||
- `+4` armor.
|
- `+6` armor.
|
||||||
- `+0.10` knockback resistance.
|
- `+0.18` knockback resistance.
|
||||||
- A heal to the new maximum health after scaling is applied.
|
- A heal to the new maximum health after scaling is applied.
|
||||||
|
|
||||||
Spawn pressure is also at its highest default value: natural and chunk-generation hostile spawns have a `25%` chance to add one extra mob of the same type nearby. Extra spawns are capped at one per spawn event, obey normal spawn/collision checks, cannot recursively trigger more extras, and are skipped when the local hostile density cap is already reached.
|
Spawn pressure is also at its highest default value: natural and chunk-generation hostile spawns have a `40%` chance to add one extra mob of the same type nearby. Extra spawns are capped at one per spawn event, obey normal spawn/collision checks, cannot recursively trigger more extras, and are skipped when the local hostile density cap is already reached.
|
||||||
|
|
||||||
## Mob-Specific Tier 5 Behavior
|
## Mob-Specific Tier 5 Behavior
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.fretux.adaptivemobs.ai;
|
package net.fretux.adaptivemobs.ai;
|
||||||
|
|
||||||
import net.fretux.adaptivemobs.ai.goals.AdaptiveCreeperPressureGoal;
|
import net.fretux.adaptivemobs.ai.goals.AdaptiveCreeperPressureGoal;
|
||||||
|
import net.fretux.adaptivemobs.ai.goals.AdaptiveCreeperFuseGoal;
|
||||||
import net.fretux.adaptivemobs.ai.goals.AdaptiveAirbornePositioningGoal;
|
import net.fretux.adaptivemobs.ai.goals.AdaptiveAirbornePositioningGoal;
|
||||||
import net.fretux.adaptivemobs.ai.goals.AdaptiveAntiCheeseGoal;
|
import net.fretux.adaptivemobs.ai.goals.AdaptiveAntiCheeseGoal;
|
||||||
import net.fretux.adaptivemobs.ai.goals.AdaptiveBiomeTacticsGoal;
|
import net.fretux.adaptivemobs.ai.goals.AdaptiveBiomeTacticsGoal;
|
||||||
@@ -109,7 +110,7 @@ public final class AdaptiveGoalInjector {
|
|||||||
// otherwise it can never take over while the zombie is already fighting.
|
// otherwise it can never take over while the zombie is already fighting.
|
||||||
mob.goalSelector.addGoal(1, new AdaptiveZombiePackTacticsGoal((Zombie) mob, tier));
|
mob.goalSelector.addGoal(1, new AdaptiveZombiePackTacticsGoal((Zombie) mob, tier));
|
||||||
} else if (pathfinder != null && mob instanceof Creeper creeper) {
|
} else if (pathfinder != null && mob instanceof Creeper creeper) {
|
||||||
creeper.maxSwell = creeperFuseTicks(tier.getAsInt());
|
mob.goalSelector.addGoal(0, new AdaptiveCreeperFuseGoal(creeper, tier));
|
||||||
mob.goalSelector.addGoal(2, new AdaptiveCreeperPressureGoal(creeper, tier));
|
mob.goalSelector.addGoal(2, new AdaptiveCreeperPressureGoal(creeper, tier));
|
||||||
mob.goalSelector.addGoal(4, new AdaptiveFlankGoal(pathfinder, tier, 2, 3.0D, 1.0D, false));
|
mob.goalSelector.addGoal(4, new AdaptiveFlankGoal(pathfinder, tier, 2, 3.0D, 1.0D, false));
|
||||||
} else if (pathfinder != null && mob instanceof Spider) {
|
} else if (pathfinder != null && mob instanceof Spider) {
|
||||||
@@ -351,10 +352,6 @@ public final class AdaptiveGoalInjector {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int creeperFuseTicks(int tier) {
|
|
||||||
return Math.max(18, 30 - Math.max(0, tier - 1) * 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean conservativeMelee(Mob mob) {
|
private static boolean conservativeMelee(Mob mob) {
|
||||||
return mob instanceof PiglinBrute || mob instanceof Ravager || mob instanceof Warden || mob instanceof ElderGuardian;
|
return mob instanceof PiglinBrute || mob instanceof Ravager || mob instanceof Warden || mob instanceof ElderGuardian;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package net.fretux.adaptivemobs.ai;
|
|||||||
import net.fretux.adaptivemobs.config.AMConfig;
|
import net.fretux.adaptivemobs.config.AMConfig;
|
||||||
import net.fretux.adaptivemobs.difficulty.AdaptiveDifficultyManager;
|
import net.fretux.adaptivemobs.difficulty.AdaptiveDifficultyManager;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
@@ -48,10 +49,13 @@ import net.minecraft.world.entity.projectile.Projectile;
|
|||||||
import net.minecraft.world.entity.projectile.ShulkerBullet;
|
import net.minecraft.world.entity.projectile.ShulkerBullet;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraftforge.event.TickEvent;
|
import net.minecraftforge.event.TickEvent;
|
||||||
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
|
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
|
||||||
import net.minecraftforge.event.entity.living.LivingHurtEvent;
|
import net.minecraftforge.event.entity.living.LivingHurtEvent;
|
||||||
|
import net.minecraftforge.common.util.BlockSnapshot;
|
||||||
|
import net.minecraftforge.event.ForgeEventFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@@ -139,8 +143,8 @@ public final class AdaptiveSpecialAbilities {
|
|||||||
if (level == null || level.getGameTime() < block.expireTick) {
|
if (level == null || level.getGameTime() < block.expireTick) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (level.getBlockState(block.pos).is(Blocks.COBWEB)) {
|
if (level.getBlockState(block.pos).equals(block.placedState)) {
|
||||||
level.removeBlock(block.pos, false);
|
block.replaced.restore(true, false);
|
||||||
}
|
}
|
||||||
blockIterator.remove();
|
blockIterator.remove();
|
||||||
}
|
}
|
||||||
@@ -186,7 +190,7 @@ public final class AdaptiveSpecialAbilities {
|
|||||||
AdaptiveAIGoalUtils.debug(mob, () -> tier, "zombified piglin blood call");
|
AdaptiveAIGoalUtils.debug(mob, () -> tier, "zombified piglin blood call");
|
||||||
}
|
}
|
||||||
if (tier >= 4 && mob instanceof Spider && ready(mob, "web_retreat", 600)) {
|
if (tier >= 4 && mob instanceof Spider && ready(mob, "web_retreat", 600)) {
|
||||||
placeTemporaryCobweb(level, attacker.blockPosition(), level.getGameTime() + 100 + mob.getRandom().nextInt(61));
|
placeTemporaryCobweb(level, mob, attacker.blockPosition(), level.getGameTime() + 100 + mob.getRandom().nextInt(61));
|
||||||
}
|
}
|
||||||
if (tier >= 4 && mob instanceof EnderMan enderman && directEntity == attacker && ready(mob, "backstep_ambush", tier >= 5 ? 80 : 130)) {
|
if (tier >= 4 && mob instanceof EnderMan enderman && directEntity == attacker && ready(mob, "backstep_ambush", tier >= 5 ? 80 : 130)) {
|
||||||
Vec3 behind = attacker.position().subtract(attacker.getLookAngle().normalize().scale(2.2D));
|
Vec3 behind = attacker.position().subtract(attacker.getLookAngle().normalize().scale(2.2D));
|
||||||
@@ -244,7 +248,7 @@ public final class AdaptiveSpecialAbilities {
|
|||||||
shove(player, mob.position(), tier >= 5 ? 0.55D : 0.35D, 0.08D);
|
shove(player, mob.position(), tier >= 5 ? 0.55D : 0.35D, 0.08D);
|
||||||
}
|
}
|
||||||
if (mob instanceof Spider && tier >= 4 && ready(mob, "web_hit", mob instanceof CaveSpider ? 400 : 600)) {
|
if (mob instanceof Spider && tier >= 4 && ready(mob, "web_hit", mob instanceof CaveSpider ? 400 : 600)) {
|
||||||
placeTemporaryCobweb(level, player.blockPosition(), level.getGameTime() + 100 + mob.getRandom().nextInt(61));
|
placeTemporaryCobweb(level, mob, player.blockPosition(), level.getGameTime() + 100 + mob.getRandom().nextInt(61));
|
||||||
}
|
}
|
||||||
if (mob instanceof CaveSpider && tier >= 3
|
if (mob instanceof CaveSpider && tier >= 3
|
||||||
&& (AdaptiveAIGoalUtils.isUsingRangedWeapon(player) || player.isUsingItem())) {
|
&& (AdaptiveAIGoalUtils.isUsingRangedWeapon(player) || player.isUsingItem())) {
|
||||||
@@ -330,13 +334,22 @@ public final class AdaptiveSpecialAbilities {
|
|||||||
target.hurtMarked = true;
|
target.hurtMarked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void placeTemporaryCobweb(ServerLevel level, BlockPos requestedPos, long expireTick) {
|
private static void placeTemporaryCobweb(ServerLevel level, Mob spider, BlockPos requestedPos, long expireTick) {
|
||||||
BlockPos pos = level.getFluidState(requestedPos).is(FluidTags.WATER) ? requestedPos.above() : requestedPos;
|
BlockPos pos = level.getFluidState(requestedPos).is(FluidTags.WATER) ? requestedPos.above() : requestedPos;
|
||||||
if (!level.getBlockState(pos).isAir() || !level.getWorldBorder().isWithinBounds(pos)) {
|
if (!ForgeEventFactory.getMobGriefingEvent(level, spider)
|
||||||
|
|| !level.getBlockState(pos).isAir() || !level.getWorldBorder().isWithinBounds(pos)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
level.setBlock(pos, Blocks.COBWEB.defaultBlockState(), 3);
|
BlockSnapshot replaced = BlockSnapshot.create(level.dimension(), level, pos);
|
||||||
TEMPORARY_BLOCKS.add(new TemporaryBlock(level.getServer(), level.dimension(), pos.immutable(), expireTick));
|
if (ForgeEventFactory.onBlockPlace(spider, replaced, Direction.UP)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BlockState placedState = Blocks.COBWEB.defaultBlockState();
|
||||||
|
if (!level.setBlock(pos, placedState, 3)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TEMPORARY_BLOCKS.add(new TemporaryBlock(level.getServer(), level.dimension(), pos.immutable(),
|
||||||
|
expireTick, replaced, placedState));
|
||||||
level.playSound(null, pos, SoundEvents.SPIDER_AMBIENT, SoundSource.HOSTILE, 0.6F, 1.25F);
|
level.playSound(null, pos, SoundEvents.SPIDER_AMBIENT, SoundSource.HOSTILE, 0.6F, 1.25F);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,8 +398,8 @@ public final class AdaptiveSpecialAbilities {
|
|||||||
if (block.server != level.getServer() || block.dimension != level.dimension()) {
|
if (block.server != level.getServer() || block.dimension != level.dimension()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (level.getBlockState(block.pos).is(Blocks.COBWEB)) {
|
if (level.getBlockState(block.pos).equals(block.placedState)) {
|
||||||
level.removeBlock(block.pos, false);
|
block.replaced.restore(true, false);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -399,8 +412,8 @@ public final class AdaptiveSpecialAbilities {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ServerLevel level = server.getLevel(block.dimension);
|
ServerLevel level = server.getLevel(block.dimension);
|
||||||
if (level != null && level.getBlockState(block.pos).is(Blocks.COBWEB)) {
|
if (level != null && level.getBlockState(block.pos).equals(block.placedState)) {
|
||||||
level.removeBlock(block.pos, false);
|
block.replaced.restore(true, false);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -413,7 +426,7 @@ public final class AdaptiveSpecialAbilities {
|
|||||||
|
|
||||||
private record TemporaryBlock(net.minecraft.server.MinecraftServer server,
|
private record TemporaryBlock(net.minecraft.server.MinecraftServer server,
|
||||||
net.minecraft.resources.ResourceKey<net.minecraft.world.level.Level> dimension,
|
net.minecraft.resources.ResourceKey<net.minecraft.world.level.Level> dimension,
|
||||||
BlockPos pos, long expireTick) {
|
BlockPos pos, long expireTick, BlockSnapshot replaced, BlockState placedState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private record DelayedReappear(net.minecraft.server.MinecraftServer server,
|
private record DelayedReappear(net.minecraft.server.MinecraftServer server,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import net.minecraft.world.item.Items;
|
|||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraftforge.common.ForgeHooks;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
@@ -260,6 +261,9 @@ public class AdaptiveAntiCheeseGoal extends Goal {
|
|||||||
if (mob instanceof Zombie && !AMConfig.ALLOW_ZOMBIE_BLOCK_BREAK.get()) {
|
if (mob instanceof Zombie && !AMConfig.ALLOW_ZOMBIE_BLOCK_BREAK.get()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!ForgeHooks.canEntityDestroy(mob.level(), pos, mob)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (state.is(Blocks.COBWEB)) {
|
if (state.is(Blocks.COBWEB)) {
|
||||||
Block.popResource(mob.level(), pos, new ItemStack(Items.STRING));
|
Block.popResource(mob.level(), pos, new ItemStack(Items.STRING));
|
||||||
} else if (state.is(Blocks.SWEET_BERRY_BUSH)) {
|
} else if (state.is(Blocks.SWEET_BERRY_BUSH)) {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package net.fretux.adaptivemobs.ai.goals;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.ai.goal.Goal;
|
||||||
|
import net.minecraft.world.entity.monster.Creeper;
|
||||||
|
|
||||||
|
import java.util.function.IntSupplier;
|
||||||
|
|
||||||
|
/** Keeps the creeper fuse synchronized with the current config-gated adaptive tier. */
|
||||||
|
public final class AdaptiveCreeperFuseGoal extends Goal {
|
||||||
|
private final Creeper creeper;
|
||||||
|
private final IntSupplier tierSupplier;
|
||||||
|
private int updateCooldown;
|
||||||
|
|
||||||
|
public AdaptiveCreeperFuseGoal(Creeper creeper, IntSupplier tierSupplier) {
|
||||||
|
this.creeper = creeper;
|
||||||
|
this.tierSupplier = tierSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canUse() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canContinueToUse() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (--updateCooldown > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateCooldown = 20;
|
||||||
|
int tier = tierSupplier.getAsInt();
|
||||||
|
creeper.maxSwell = tier <= 0 ? 30 : Math.max(18, 30 - Math.max(0, tier - 1) * 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||||||
import net.minecraft.world.level.gameevent.GameEvent;
|
import net.minecraft.world.level.gameevent.GameEvent;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraftforge.common.util.BlockSnapshot;
|
import net.minecraftforge.common.util.BlockSnapshot;
|
||||||
|
import net.minecraftforge.common.ForgeHooks;
|
||||||
import net.minecraftforge.event.ForgeEventFactory;
|
import net.minecraftforge.event.ForgeEventFactory;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
@@ -341,7 +342,8 @@ public class AdaptiveEndermanTacticsGoal extends Goal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean pickUpBlock(ServerLevel level, BlockPos pos, String debugMessage) {
|
private boolean pickUpBlock(ServerLevel level, BlockPos pos, String debugMessage) {
|
||||||
if (enderman.getCarriedBlock() != null || !isMovableBlock(level, pos)) {
|
if (enderman.getCarriedBlock() != null || !isMovableBlock(level, pos)
|
||||||
|
|| !ForgeHooks.canEntityDestroy(level, pos, enderman)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
BlockState state = level.getBlockState(pos);
|
BlockState state = level.getBlockState(pos);
|
||||||
|
|||||||
@@ -59,8 +59,9 @@ public class AdaptiveSlimeTacticsGoal extends Goal {
|
|||||||
public void start() {
|
public void start() {
|
||||||
int tier = tierSupplier.getAsInt();
|
int tier = tierSupplier.getAsInt();
|
||||||
if (recombinePartner != null && recombinePartner.isAlive()) {
|
if (recombinePartner != null && recombinePartner.isAlive()) {
|
||||||
tryRecombine(recombinePartner);
|
if (tryRecombine(recombinePartner)) {
|
||||||
recombinePartner = null;
|
recombinePartner = null;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cooldown = Math.max(16, 52 - tier * 5) + slime.getRandom().nextInt(25);
|
cooldown = Math.max(16, 52 - tier * 5) + slime.getRandom().nextInt(25);
|
||||||
@@ -84,6 +85,25 @@ public class AdaptiveSlimeTacticsGoal extends Goal {
|
|||||||
AdaptiveAIGoalUtils.debug(slime, tierSupplier, "slime angled jump pressure");
|
AdaptiveAIGoalUtils.debug(slime, tierSupplier, "slime angled jump pressure");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canContinueToUse() {
|
||||||
|
return recombinePartner != null && recombinePartner.isAlive()
|
||||||
|
&& slime.isAlive() && tierSupplier.getAsInt() >= 5
|
||||||
|
&& slime.getSize() < MAX_RECOMBINE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (recombinePartner != null && tryRecombine(recombinePartner)) {
|
||||||
|
recombinePartner = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
recombinePartner = null;
|
||||||
|
}
|
||||||
|
|
||||||
private Slime findRecombinePartner() {
|
private Slime findRecombinePartner() {
|
||||||
boolean magma = slime instanceof MagmaCube;
|
boolean magma = slime instanceof MagmaCube;
|
||||||
List<Slime> candidates = slime.level().getEntitiesOfClass(Slime.class,
|
List<Slime> candidates = slime.level().getEntitiesOfClass(Slime.class,
|
||||||
@@ -94,11 +114,11 @@ public class AdaptiveSlimeTacticsGoal extends Goal {
|
|||||||
return candidates.stream().min(Comparator.comparingDouble(slime::distanceToSqr)).orElse(null);
|
return candidates.stream().min(Comparator.comparingDouble(slime::distanceToSqr)).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryRecombine(Slime partner) {
|
private boolean tryRecombine(Slime partner) {
|
||||||
if (slime.distanceToSqr(partner) > RECOMBINE_DISTANCE_SQR) {
|
if (slime.distanceToSqr(partner) > RECOMBINE_DISTANCE_SQR) {
|
||||||
slime.getLookControl().setLookAt(partner, 30.0F, 30.0F);
|
slime.getLookControl().setLookAt(partner, 30.0F, 30.0F);
|
||||||
slime.getMoveControl().setWantedPosition(partner.getX(), partner.getY(), partner.getZ(), 1.2D);
|
slime.getMoveControl().setWantedPosition(partner.getX(), partner.getY(), partner.getZ(), 1.2D);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
LivingEntity inheritedTarget = AdaptiveAIGoalUtils.isValidAdaptiveTarget(slime.getTarget())
|
LivingEntity inheritedTarget = AdaptiveAIGoalUtils.isValidAdaptiveTarget(slime.getTarget())
|
||||||
? slime.getTarget() : partner.getTarget();
|
? slime.getTarget() : partner.getTarget();
|
||||||
@@ -110,6 +130,7 @@ public class AdaptiveSlimeTacticsGoal extends Goal {
|
|||||||
scheduleRecombine(200 + slime.getRandom().nextInt(101));
|
scheduleRecombine(200 + slime.getRandom().nextInt(101));
|
||||||
AdaptiveAIGoalUtils.debug(slime, tierSupplier,
|
AdaptiveAIGoalUtils.debug(slime, tierSupplier,
|
||||||
slime instanceof MagmaCube ? "magma cube recombined" : "slime recombined");
|
slime instanceof MagmaCube ? "magma cube recombined" : "slime recombined");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleRecombine(int delayTicks) {
|
private void scheduleRecombine(int delayTicks) {
|
||||||
|
|||||||
@@ -78,8 +78,11 @@ public class AdaptiveSavedData extends SavedData {
|
|||||||
// --- Mutators (mark dirty) --------------------------------------------
|
// --- Mutators (mark dirty) --------------------------------------------
|
||||||
|
|
||||||
public void addKill(String typeKey) {
|
public void addKill(String typeKey) {
|
||||||
totalHostileKills++;
|
if (totalHostileKills < Long.MAX_VALUE) {
|
||||||
killsByType.merge(typeKey, 1, Integer::sum);
|
totalHostileKills++;
|
||||||
|
}
|
||||||
|
killsByType.compute(typeKey, (key, current) ->
|
||||||
|
current == null ? 1 : current < Integer.MAX_VALUE ? current + 1 : Integer.MAX_VALUE);
|
||||||
setDirty();
|
setDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ displayName="${mod_name}" #mandatory
|
|||||||
#credits="" #optional
|
#credits="" #optional
|
||||||
# A text field displayed in the mod UI
|
# A text field displayed in the mod UI
|
||||||
authors="${mod_authors}" #optional
|
authors="${mod_authors}" #optional
|
||||||
|
displayTest="IGNORE_SERVER_VERSION"
|
||||||
# Display Test controls the display for your mod in the server connection screen
|
# Display Test controls the display for your mod in the server connection screen
|
||||||
# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod.
|
# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod.
|
||||||
# IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod.
|
# IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod.
|
||||||
|
|||||||
Reference in New Issue
Block a user