diff --git a/src/main/java/pokecube/adventures/ai/tasks/AITrainerBase.java b/src/main/java/pokecube/adventures/ai/tasks/AITrainerBase.java index 569a88be80..5c227038f4 100644 --- a/src/main/java/pokecube/adventures/ai/tasks/AITrainerBase.java +++ b/src/main/java/pokecube/adventures/ai/tasks/AITrainerBase.java @@ -10,7 +10,7 @@ import pokecube.adventures.capabilities.CapabilityNPCAIStates.IHasNPCAIStates; import pokecube.adventures.capabilities.CapabilityNPCMessages.IHasMessages; import pokecube.adventures.capabilities.TrainerCaps; -import pokecube.core.ai.tasks.AIBase.IRunnable; +import pokecube.core.ai.tasks.IRunnable; import thut.api.entity.ai.IAIRunnable; public class AITrainerBase implements IAIRunnable diff --git a/src/main/java/pokecube/adventures/blocks/daycare/DaycareTile.java b/src/main/java/pokecube/adventures/blocks/daycare/DaycareTile.java index 541c53c082..b48beebf06 100644 --- a/src/main/java/pokecube/adventures/blocks/daycare/DaycareTile.java +++ b/src/main/java/pokecube/adventures/blocks/daycare/DaycareTile.java @@ -144,8 +144,7 @@ public void tick() applied = true; this.power -= needed; if (gainExp) pokemob.setExp(pokemob.getExp() + exp_out, true); - if (PokecubeAdv.config.dayCareBreedSpeedup) pokemob.setLoveTimer(pokemob.getLoveTimer() - + PokecubeAdv.config.dayCareBreedAmount); + if (PokecubeAdv.config.dayCareBreedSpeedup) pokemob.tickBreedDelay(PokecubeAdv.config.dayCareBreedAmount); } if (applied) this.getWorld().playSound(null, this.getPos(), SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.BLOCKS, 0.25f, 1); diff --git a/src/main/java/pokecube/core/ai/brain/BrainUtils.java b/src/main/java/pokecube/core/ai/brain/BrainUtils.java index f5cb517253..590ebdc5a9 100644 --- a/src/main/java/pokecube/core/ai/brain/BrainUtils.java +++ b/src/main/java/pokecube/core/ai/brain/BrainUtils.java @@ -3,6 +3,7 @@ import java.util.List; import java.util.Optional; +import net.minecraft.entity.AgeableEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.MobEntity; import net.minecraft.entity.ai.brain.Brain; @@ -10,6 +11,11 @@ import net.minecraft.entity.ai.brain.memory.MemoryModuleType; import net.minecraft.entity.ai.brain.sensor.Sensor; import net.minecraft.entity.ai.brain.sensor.SensorType; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.util.math.IPosWrapper; +import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; +import thut.api.entity.ai.VectorPosWrapper; +import thut.api.maths.Vector3; public class BrainUtils { @@ -34,14 +40,116 @@ public static void setAttackTarget(final LivingEntity mobIn, final LivingEntity if (mobIn instanceof MobEntity) ((MobEntity) mobIn).setAttackTarget(target); } + public static void setHuntTarget(final LivingEntity mobIn, final LivingEntity target) + { + Brain brain = mobIn.getBrain(); + if (brain.hasMemory(MemoryModules.HUNTTARGET, MemoryModuleStatus.REGISTERED)) brain.setMemory( + MemoryModules.HUNTTARGET, target); + BrainUtils.setAttackTarget(mobIn, target); + if (target != null) + { + brain = target.getBrain(); + if (brain.hasMemory(MemoryModules.HUNTED_BY, MemoryModuleStatus.REGISTERED)) brain.setMemory( + MemoryModules.HUNTED_BY, mobIn); + } + } + public static LivingEntity getHuntTarget(final LivingEntity mobIn) { final Brain brain = mobIn.getBrain(); - if (brain.hasMemory(MemoryModules.ATTACKTARGET)) return brain.getMemory(MemoryModules.ATTACKTARGET).get(); + if (brain.hasMemory(MemoryModules.HUNTTARGET)) return brain.getMemory(MemoryModules.HUNTTARGET).get(); else if (mobIn instanceof MobEntity) return ((MobEntity) mobIn).getAttackTarget(); else return null; } + public static boolean hasHuntTarget(final LivingEntity mobIn) + { + return BrainUtils.getHuntTarget(mobIn) != null; + } + + public static AgeableEntity getMateTarget(final AgeableEntity mobIn) + { + final Brain brain = mobIn.getBrain(); + if (brain.hasMemory(MemoryModules.MATE_TARGET)) return brain.getMemory(MemoryModules.MATE_TARGET).get(); + else return null; + } + + public static boolean hasMateTarget(final AgeableEntity mobIn) + { + return BrainUtils.getMateTarget(mobIn) != null; + } + + public static void setMateTarget(final AgeableEntity mobIn, final AgeableEntity target) + { + final Brain brain = mobIn.getBrain(); + if (brain.hasMemory(MemoryModules.MATE_TARGET, MemoryModuleStatus.REGISTERED)) brain.setMemory( + MemoryModules.MATE_TARGET, target); + } + + public static void lookAt(final LivingEntity entityIn, final double x, final double y, final double z) + { + BrainUtils.lookAt(entityIn, Vector3.getNewVector().set(x, y, z)); + } + + public static void lookAt(final LivingEntity entityIn, final Vector3 vec) + { + entityIn.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, new VectorPosWrapper(vec)); + } + + public static void setMoveUseTarget(final LivingEntity mobIn, final Vector3 pos) + { + BrainUtils.setMoveUseTarget(mobIn, new VectorPosWrapper(pos)); + } + + public static void setMoveUseTarget(final LivingEntity mobIn, final IPosWrapper pos) + { + final Brain brain = mobIn.getBrain(); + brain.setMemory(MemoryModules.MOVE_TARGET, pos); + } + + public static void clearMoveUseTarget(final LivingEntity mobIn) + { + final Brain brain = mobIn.getBrain(); + brain.removeMemory(MemoryModules.MOVE_TARGET); + } + + public static boolean hasMoveUseTarget(final LivingEntity mobIn) + { + return BrainUtils.getMoveUseTarget(mobIn) != null; + } + + public static IPosWrapper getMoveUseTarget(final LivingEntity mobIn) + { + final Brain brain = mobIn.getBrain(); + final Optional pos = brain.getMemory(MemoryModules.MOVE_TARGET); + if (pos == null || !pos.isPresent()) return null; + return pos.get(); + } + + public static List getNearBlocks(final LivingEntity mobIn) + { + final Brain brain = mobIn.getBrain(); + final Optional> pos = brain.getMemory(MemoryModules.VISIBLE_BLOCKS); + if (pos == null || !pos.isPresent()) return null; + return pos.get(); + } + + public static List getNearItems(final LivingEntity mobIn) + { + final Brain brain = mobIn.getBrain(); + final Optional> pos = brain.getMemory(MemoryModules.VISIBLE_ITEMS); + if (pos == null || !pos.isPresent()) return null; + return pos.get(); + } + + public static List getMates(final AgeableEntity entity) + { + final Brain brain = entity.getBrain(); + final Optional> pos = brain.getMemory(MemoryModules.POSSIBLE_MATES); + if (pos == null || !pos.isPresent()) return null; + return pos.get(); + } + public static void addToBrain(final Brain brain, final List> MEMORY_TYPES, final List> SENSOR_TYPES) { diff --git a/src/main/java/pokecube/core/ai/brain/MemoryModules.java b/src/main/java/pokecube/core/ai/brain/MemoryModules.java index a42e5db021..7af433dfd8 100644 --- a/src/main/java/pokecube/core/ai/brain/MemoryModules.java +++ b/src/main/java/pokecube/core/ai/brain/MemoryModules.java @@ -1,27 +1,53 @@ package pokecube.core.ai.brain; +import java.util.List; import java.util.Optional; +import net.minecraft.entity.AgeableEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.ai.brain.memory.MemoryModuleType; import net.minecraft.entity.ai.brain.memory.WalkTarget; +import net.minecraft.entity.item.ItemEntity; import net.minecraft.pathfinding.Path; +import net.minecraft.util.math.IPosWrapper; import net.minecraftforge.event.RegistryEvent.Register; import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; public class MemoryModules { // Used for combat public static final MemoryModuleType ATTACKTARGET = new MemoryModuleType<>(Optional.empty()); public static final MemoryModuleType HUNTTARGET = new MemoryModuleType<>(Optional.empty()); + public static final MemoryModuleType MOVE_TARGET = new MemoryModuleType<>(Optional.empty()); + public static final MemoryModuleType HUNTED_BY = new MemoryModuleType<>(Optional.empty()); // Used for pathing - public static final MemoryModuleType PATH = MemoryModuleType.PATH; - public static final MemoryModuleType WALK_TARGET = MemoryModuleType.WALK_TARGET; + public static final MemoryModuleType PATH = MemoryModuleType.PATH; + public static final MemoryModuleType WALK_TARGET = MemoryModuleType.WALK_TARGET; + public static final MemoryModuleType NOT_FOUND_PATH = MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE; + + // Misc + public static final MemoryModuleType LOOK_TARGET = MemoryModuleType.LOOK_TARGET; + + public static final MemoryModuleType> VISIBLE_BLOCKS = new MemoryModuleType<>(Optional.empty()); + public static final MemoryModuleType> VISIBLE_ITEMS = new MemoryModuleType<>(Optional.empty()); + + public static final MemoryModuleType> POSSIBLE_MATES = new MemoryModuleType<>(Optional.empty()); + public static final MemoryModuleType MATE_TARGET = new MemoryModuleType<>(Optional.empty()); public static void register(final Register> event) { event.getRegistry().register(MemoryModules.ATTACKTARGET.setRegistryName(PokecubeCore.MODID, "attack_target")); event.getRegistry().register(MemoryModules.HUNTTARGET.setRegistryName(PokecubeCore.MODID, "hunt_target")); + event.getRegistry().register(MemoryModules.HUNTED_BY.setRegistryName(PokecubeCore.MODID, "hunted_by")); + event.getRegistry().register(MemoryModules.MOVE_TARGET.setRegistryName(PokecubeCore.MODID, "move_target")); + + event.getRegistry().register(MemoryModules.VISIBLE_BLOCKS.setRegistryName(PokecubeCore.MODID, + "visible_blocks")); + event.getRegistry().register(MemoryModules.VISIBLE_ITEMS.setRegistryName(PokecubeCore.MODID, "visible_items")); + + event.getRegistry().register(MemoryModules.POSSIBLE_MATES.setRegistryName(PokecubeCore.MODID, "mate_options")); + event.getRegistry().register(MemoryModules.MATE_TARGET.setRegistryName(PokecubeCore.MODID, "mate_choice")); } } diff --git a/src/main/java/pokecube/core/ai/brain/Sensors.java b/src/main/java/pokecube/core/ai/brain/Sensors.java index 072523b41a..b95d004cec 100644 --- a/src/main/java/pokecube/core/ai/brain/Sensors.java +++ b/src/main/java/pokecube/core/ai/brain/Sensors.java @@ -2,13 +2,22 @@ import net.minecraft.entity.ai.brain.sensor.SensorType; import net.minecraftforge.event.RegistryEvent.Register; +import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.sensors.NearBlocks; +import pokecube.core.ai.brain.sensors.NearItems; +import pokecube.core.ai.brain.sensors.PossibleMates; public class Sensors { + public static final SensorType VISIBLE_BLOCKS = new SensorType<>(NearBlocks::new); + public static final SensorType VISIBLE_ITEMS = new SensorType<>(NearItems::new); + public static final SensorType VALID_MATES = new SensorType<>(PossibleMates::new); public static void register(final Register> event) { - + event.getRegistry().register(Sensors.VISIBLE_BLOCKS.setRegistryName(PokecubeCore.MODID, "visible_blocks")); + event.getRegistry().register(Sensors.VISIBLE_ITEMS.setRegistryName(PokecubeCore.MODID, "visible_items")); + event.getRegistry().register(Sensors.VALID_MATES.setRegistryName(PokecubeCore.MODID, "valid_mates")); } } diff --git a/src/main/java/pokecube/core/ai/brain/sensors/NearBlocks.java b/src/main/java/pokecube/core/ai/brain/sensors/NearBlocks.java new file mode 100644 index 0000000000..03c9b4218d --- /dev/null +++ b/src/main/java/pokecube/core/ai/brain/sensors/NearBlocks.java @@ -0,0 +1,100 @@ +package pokecube.core.ai.brain.sensors; + +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.brain.Brain; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.entity.ai.brain.sensor.Sensor; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.server.ServerWorld; +import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.brain.MemoryModules; +import thut.api.maths.Cruncher; +import thut.api.maths.Vector3; + +public class NearBlocks extends Sensor +{ + public static class NearBlock + { + private final BlockState state; + private final BlockPos pos; + + public NearBlock(final BlockState state, final BlockPos pos) + { + this.state = state; + this.pos = pos; + } + + public BlockPos getPos() + { + return this.pos; + } + + public BlockState getState() + { + return this.state; + } + } + + private static final int[][] indexArr = new int[32 * 32 * 32][3]; + + static + { + final Vector3 r = Vector3.getNewVector(); + for (int i = 0; i < NearBlocks.indexArr.length; i++) + { + Cruncher.indexToVals(i, r); + if (Math.abs(r.y) <= 4) + { + NearBlocks.indexArr[i][0] = r.intX(); + NearBlocks.indexArr[i][1] = r.intY(); + NearBlocks.indexArr[i][2] = r.intZ(); + } + else NearBlocks.indexArr[i] = null; + } + } + + long lastUpdate = 0; + + @Override + protected void update(final ServerWorld worldIn, final LivingEntity entityIn) + { + if (BrainUtils.hasAttackTarget(entityIn)) return; + if (BrainUtils.hasMoveUseTarget(entityIn)) return; + + final Vector3 r = Vector3.getNewVector(), rAbs = Vector3.getNewVector(); + final Vector3 origin = Vector3.getNewVector(); + origin.set(entityIn); + final List list = Lists.newArrayList(); + final int size = 8; + for (int i = 0; i < size * size * size; i++) + { + final int[] pos = NearBlocks.indexArr[i]; + if (pos == null) continue; + r.set(pos); + rAbs.set(r).addTo(origin); + if (rAbs.isAir(worldIn)) continue; + final BlockPos bpos = new BlockPos(rAbs.getPos()); + final BlockState state = worldIn.getBlockState(bpos); + list.add(new NearBlock(state, bpos)); + } + final BlockPos o0 = entityIn.getPosition(); + list.sort((o1, o2) -> (int) (o1.getPos().distanceSq(o0) - o1.getPos().distanceSq(o0))); + final Brain brain = entityIn.getBrain(); + if (!list.isEmpty()) brain.setMemory(MemoryModules.VISIBLE_BLOCKS, list); + else brain.removeMemory(MemoryModules.VISIBLE_BLOCKS); + } + + @Override + public Set> getUsedMemories() + { + return ImmutableSet.of(MemoryModules.VISIBLE_BLOCKS); + } + +} diff --git a/src/main/java/pokecube/core/ai/brain/sensors/NearItems.java b/src/main/java/pokecube/core/ai/brain/sensors/NearItems.java new file mode 100644 index 0000000000..0ff7641b15 --- /dev/null +++ b/src/main/java/pokecube/core/ai/brain/sensors/NearItems.java @@ -0,0 +1,41 @@ +package pokecube.core.ai.brain.sensors; + +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.brain.Brain; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.entity.ai.brain.sensor.Sensor; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.world.server.ServerWorld; +import pokecube.core.ai.brain.MemoryModules; + +public class NearItems extends Sensor +{ + long lastUpdate = 0; + + @Override + protected void update(final ServerWorld worldIn, final LivingEntity entityIn) + { + final List list = worldIn.getEntitiesWithinAABB(ItemEntity.class, entityIn.getBoundingBox().grow( + 16.0D, 16.0D, 16.0D), (item) -> + { + return item.isAlive() && entityIn.canEntityBeSeen(item); + }); + list.sort(Comparator.comparingDouble(entityIn::getDistanceSq)); + final Brain brain = entityIn.getBrain(); + if (!list.isEmpty()) brain.setMemory(MemoryModules.VISIBLE_ITEMS, list); + else brain.removeMemory(MemoryModules.VISIBLE_ITEMS); + } + + @Override + public Set> getUsedMemories() + { + return ImmutableSet.of(MemoryModules.VISIBLE_ITEMS); + } + +} diff --git a/src/main/java/pokecube/core/ai/brain/sensors/PossibleMates.java b/src/main/java/pokecube/core/ai/brain/sensors/PossibleMates.java new file mode 100644 index 0000000000..7591b277e8 --- /dev/null +++ b/src/main/java/pokecube/core/ai/brain/sensors/PossibleMates.java @@ -0,0 +1,53 @@ +package pokecube.core.ai.brain.sensors; + +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; + +import net.minecraft.entity.AgeableEntity; +import net.minecraft.entity.ai.brain.Brain; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.entity.ai.brain.sensor.Sensor; +import net.minecraft.world.server.ServerWorld; +import pokecube.core.ai.brain.MemoryModules; +import thut.api.entity.BreedableCaps; +import thut.api.entity.IBreedingMob; + +public class PossibleMates extends Sensor +{ + long lastUpdate = 0; + + private boolean isValid(final AgeableEntity entityIn, final AgeableEntity otherAnimal) + { + final IBreedingMob us = BreedableCaps.getBreedable(entityIn); + if (entityIn == otherAnimal) return false; + if (us != null) return us.canMate(otherAnimal); + return false; + } + + @Override + protected void update(final ServerWorld worldIn, final AgeableEntity entityIn) + { + final double dh = 8; + final double dv = 4; + final List list = worldIn.getEntitiesWithinAABB(AgeableEntity.class, entityIn.getBoundingBox() + .grow(dh, dv, dh), (otherAnimal) -> + { + return otherAnimal.isAlive() && entityIn.canEntityBeSeen(otherAnimal) && this.isValid(entityIn, + otherAnimal); + }); + list.sort(Comparator.comparingDouble(entityIn::getDistanceSq)); + final Brain brain = entityIn.getBrain(); + if (!list.isEmpty()) brain.setMemory(MemoryModules.POSSIBLE_MATES, list); + else brain.removeMemory(MemoryModules.POSSIBLE_MATES); + } + + @Override + public Set> getUsedMemories() + { + return ImmutableSet.of(MemoryModules.POSSIBLE_MATES); + } + +} diff --git a/src/main/java/pokecube/core/ai/logic/LogicMiscUpdate.java b/src/main/java/pokecube/core/ai/logic/LogicMiscUpdate.java index 3122625fc2..fab3914e14 100644 --- a/src/main/java/pokecube/core/ai/logic/LogicMiscUpdate.java +++ b/src/main/java/pokecube/core/ai/logic/LogicMiscUpdate.java @@ -110,13 +110,6 @@ else if (!angry && this.reset) this.reset = false; } - if (this.pokemob.getSexe() != IPokemob.MALE) - { - int diff = 1 * PokecubeCore.getConfig().mateMultiplier; - if (this.pokemob.getLoveTimer() > 0) diff = 1; - this.pokemob.setLoveTimer(this.pokemob.getLoveTimer() + diff); - } - // If not angry, and not been so for a while, reset stat modifiers. if (!angry) { @@ -130,13 +123,12 @@ else if (!angry && this.reset) else /** Angry pokemobs shouldn't decide to walk around. */ this.pokemob.setRoutineState(AIRoutine.AIRBORNE, true); + this.pokemob.tickBreedDelay(PokecubeCore.getConfig().mateMultiplier); + // Reset tamed state for things with no owner. if (this.pokemob.getGeneralState(GeneralStates.TAMED) && this.pokemob.getOwnerId() == null) this.pokemob .setGeneralState(GeneralStates.TAMED, false); - // Ensure cap on love timer. - if (this.pokemob.getLoveTimer() > 600) this.pokemob.resetLoveStatus(); - // Check exit cube state. if (this.entity.ticksExisted > LogicMiscUpdate.EXITCUBEDURATION && this.pokemob.getGeneralState( GeneralStates.EXITINGCUBE)) this.pokemob.setGeneralState(GeneralStates.EXITINGCUBE, false); diff --git a/src/main/java/pokecube/core/ai/logic/LogicMovesUpdates.java b/src/main/java/pokecube/core/ai/logic/LogicMovesUpdates.java index 70bfc05cf4..f91737c92a 100644 --- a/src/main/java/pokecube/core/ai/logic/LogicMovesUpdates.java +++ b/src/main/java/pokecube/core/ai/logic/LogicMovesUpdates.java @@ -121,12 +121,8 @@ public void tick(final World world) if (num > 0 && this.pokemob.getActiveMove() == null) this.pokemob.setAttackCooldown(num - 1); // Revert transform if not in battle or breeding. - if (this.pokemob.getTransformedTo() != null && !BrainUtils.hasAttackTarget(this.entity) && !(this.pokemob - .getGeneralState(GeneralStates.MATING) || this.pokemob.getLover() != null)) this.pokemob - .setTransformedTo(null); - // apply transform if breeding and applicable. - if (this.pokemob.getTransformedTo() == null && this.pokemob.getLover() != null && this.hasMove( - IMoveNames.MOVE_TRANSFORM)) this.pokemob.setTransformedTo(this.pokemob.getLover()); + if (this.pokemob.getTransformedTo() != null && !BrainUtils.hasAttackTarget(this.entity) && !this.pokemob + .getGeneralState(GeneralStates.MATING)) this.pokemob.setTransformedTo(null); // Update abilities. if (this.pokemob.getAbility() != null && this.entity.isServerWorld()) this.pokemob.getAbility().onUpdate( diff --git a/src/main/java/pokecube/core/ai/routes/GuardAICapability.java b/src/main/java/pokecube/core/ai/routes/GuardAICapability.java index 8a93837788..e382b57cd2 100644 --- a/src/main/java/pokecube/core/ai/routes/GuardAICapability.java +++ b/src/main/java/pokecube/core/ai/routes/GuardAICapability.java @@ -10,14 +10,15 @@ import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.ai.attributes.AttributeModifier.Operation; -import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.entity.ai.brain.memory.WalkTarget; import net.minecraft.nbt.INBT; import net.minecraft.nbt.ListNBT; -import net.minecraft.pathfinding.PathPoint; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.server.ServerWorld; +import pokecube.core.ai.brain.MemoryModules; import pokecube.core.utils.TimePeriod; public class GuardAICapability implements IGuardAICapability @@ -43,46 +44,17 @@ public GuardTask() @Override public void continueTask(final MobEntity entity) { - boolean hasPath = !entity.getNavigator().noPath(); final BlockPos newPos = entity.getPosition(); - - if (hasPath) entity.getBrain().setMemory(MemoryModuleType.PATH, entity.getNavigator().getPath()); - this.lastPathedCounter--; + final double speed = entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); + this.path(entity, speed); if (this.lastPathedCounter > 0) return; - - if (hasPath) if (this.lastPos != null && this.lastPos.equals(newPos)) + if (this.lastPos != null && this.lastPos.equals(newPos)) { - if (this.lastPosCounter-- >= 0) - { - - } - else - { - this.lastPosCounter = 10; - hasPath = false; - } + if (this.lastPosCounter-- >= 0) this.pathFail(entity); + else this.lastPosCounter = 10; } else this.lastPosCounter = 10; - - if (!hasPath) - { - final double speed = entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); - if (!this.path(entity, speed)) this.pathFail(entity); - } - else - { - final PathPoint end = entity.getNavigator().getPath().getFinalPathPoint(); - final BlockPos endPos = new BlockPos(end.x, end.y, end.z); - double maxDist = this.getRoamDistance() * this.getRoamDistance(); - maxDist = Math.max(maxDist, 0.75); - maxDist = Math.max(maxDist, entity.getWidth()); - if (endPos.distanceSq(this.getPos()) > maxDist) - { - final double speed = entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); - if (!this.path(entity, speed)) this.pathFail(entity); - } - } this.lastPos = newPos; } @@ -90,7 +62,6 @@ public void continueTask(final MobEntity entity) public void endTask(final MobEntity entity) { entity.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).removeModifier(this.executingGuardTask); - entity.getBrain().removeMemory(MemoryModuleType.PATH); } @Override @@ -157,21 +128,21 @@ private void pathFail(final MobEntity entity) private boolean path(final MobEntity entity, final double speed) { - if (this.lastPathedCounter < 0) - { - // Limit how often this can path. - this.lastPathedCounter = 10; - return entity.getNavigator().tryMoveToXYZ(this.getPos().getX() + 0.5, this.getPos().getY(), this - .getPos().getZ() + 0.5, speed); - } - return false; + final Vec3d pos = new Vec3d(this.getPos().getX() + 0.5, this.getPos().getY(), this.getPos().getZ() + 0.5); + this.setWalkTo(entity, pos, speed, 0); + return true; } + protected void setWalkTo(final MobEntity entity, final Vec3d pos, final double speed, final int dist) + { + entity.getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(pos, (float) speed, dist)); + } } - private GuardState state = GuardState.IDLE; private final List tasks = Lists.newArrayList(new GuardTask()); - private IGuardTask activeTask; + + private GuardState state = GuardState.IDLE; + private IGuardTask activeTask; @Override public IGuardTask getActiveTask() diff --git a/src/main/java/pokecube/core/ai/routes/WalkToTask.java b/src/main/java/pokecube/core/ai/routes/WalkToTask.java new file mode 100644 index 0000000000..93d4455a7c --- /dev/null +++ b/src/main/java/pokecube/core/ai/routes/WalkToTask.java @@ -0,0 +1,153 @@ +package pokecube.core.ai.routes; + +import java.util.Optional; + +import javax.annotation.Nullable; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import net.minecraft.entity.CreatureEntity; +import net.minecraft.entity.MobEntity; +import net.minecraft.entity.ai.RandomPositionGenerator; +import net.minecraft.entity.ai.brain.Brain; +import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.entity.ai.brain.memory.WalkTarget; +import net.minecraft.entity.ai.brain.task.Task; +import net.minecraft.pathfinding.Path; +import net.minecraft.pathfinding.PathNavigator; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.server.ServerWorld; +import pokecube.core.ai.tasks.TaskBase; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.capabilities.CapabilityPokemob; + +public class WalkToTask extends Task +{ + + @Nullable + private Path currentPath; + @Nullable + private BlockPos field_220489_b; + private float speed; + private int field_220491_d; + + public WalkToTask(final int duration) + { + super(ImmutableMap.of(MemoryModuleType.PATH, MemoryModuleStatus.VALUE_ABSENT, MemoryModuleType.WALK_TARGET, + MemoryModuleStatus.VALUE_PRESENT), duration); + } + + @Override + protected boolean shouldExecute(final ServerWorld worldIn, final MobEntity owner) + { + final Brain brain = owner.getBrain(); + final WalkTarget walktarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get(); + + final IPokemob pokemob = CapabilityPokemob.getPokemobFor(owner); + if (pokemob != null && !TaskBase.canMove(pokemob)) return false; + + if (!this.hasReachedTarget(owner, walktarget) && this.func_220487_a(owner, walktarget, worldIn.getGameTime())) + { + this.field_220489_b = walktarget.getTarget().getBlockPos(); + return true; + } + else + { + brain.removeMemory(MemoryModuleType.WALK_TARGET); + return false; + } + } + + @Override + protected boolean shouldContinueExecuting(final ServerWorld worldIn, final MobEntity entityIn, + final long gameTimeIn) + { + if (this.currentPath != null && this.field_220489_b != null) + { + final Optional optional = entityIn.getBrain().getMemory(MemoryModuleType.WALK_TARGET); + final PathNavigator pathnavigator = entityIn.getNavigator(); + return !pathnavigator.noPath() && optional.isPresent() && !this.hasReachedTarget(entityIn, optional.get()); + } + else return false; + } + + @Override + protected void resetTask(final ServerWorld worldIn, final MobEntity entityIn, final long gameTimeIn) + { + entityIn.getNavigator().clearPath(); + entityIn.getBrain().removeMemory(MemoryModuleType.WALK_TARGET); + entityIn.getBrain().removeMemory(MemoryModuleType.PATH); + this.currentPath = null; + } + + @Override + protected void startExecuting(final ServerWorld worldIn, final MobEntity entityIn, final long gameTimeIn) + { + entityIn.getBrain().setMemory(MemoryModuleType.PATH, this.currentPath); + entityIn.getNavigator().setPath(this.currentPath, this.speed); + this.field_220491_d = worldIn.getRandom().nextInt(10); + } + + @Override + protected void updateTask(final ServerWorld worldIn, final MobEntity owner, final long gameTime) + { + --this.field_220491_d; + if (this.field_220491_d <= 0) + { + final Path path = owner.getNavigator().getPath(); + final Brain brain = owner.getBrain(); + if (this.currentPath != path) + { + this.currentPath = path; + brain.setMemory(MemoryModuleType.PATH, path); + } + + if (path != null && this.field_220489_b != null) + { + final WalkTarget walktarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get(); + if (walktarget.getTarget().getBlockPos().distanceSq(this.field_220489_b) > 4.0D && this.func_220487_a( + owner, walktarget, worldIn.getGameTime())) + { + this.field_220489_b = walktarget.getTarget().getBlockPos(); + this.startExecuting(worldIn, owner, gameTime); + } + + } + } + } + + private boolean func_220487_a(final MobEntity mob, final WalkTarget target, final long gametime) + { + final BlockPos blockpos = target.getTarget().getBlockPos(); + this.currentPath = mob.getNavigator().func_225464_a(ImmutableSet.of(blockpos), 16, false, 0); + this.speed = target.getSpeed(); + if (!this.hasReachedTarget(mob, target)) + { + final Brain brain = mob.getBrain(); + final boolean flag = this.currentPath != null && this.currentPath.func_224771_h(); + if (flag) brain.setMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, Optional.empty()); + else if (!brain.hasMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)) brain.setMemory( + MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, gametime); + + if (this.currentPath != null) return true; + + final Vec3d vec3d = RandomPositionGenerator.findRandomTargetBlockTowards((CreatureEntity) mob, 10, 7, + new Vec3d(blockpos)); + if (vec3d != null) + { + this.currentPath = mob.getNavigator().func_225466_a(vec3d.x, vec3d.y, vec3d.z, 0); + return this.currentPath != null; + } + } + + return false; + } + + private boolean hasReachedTarget(final MobEntity mob, final WalkTarget target) + { + return target.getTarget().getBlockPos().manhattanDistance(new BlockPos(mob)) <= target.getDistance(); + } +} diff --git a/src/main/java/pokecube/core/ai/tasks/AIBase.java b/src/main/java/pokecube/core/ai/tasks/AIBase.java deleted file mode 100644 index 980aaf0594..0000000000 --- a/src/main/java/pokecube/core/ai/tasks/AIBase.java +++ /dev/null @@ -1,260 +0,0 @@ -package pokecube.core.ai.tasks; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; - -import net.minecraft.entity.Entity; -import net.minecraft.entity.MobEntity; -import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; -import net.minecraft.entity.ai.brain.memory.MemoryModuleType; -import net.minecraft.entity.ai.brain.memory.WalkTarget; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.pathfinding.Path; -import net.minecraft.pathfinding.PathPoint; -import net.minecraft.util.SoundCategory; -import net.minecraft.util.SoundEvent; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraft.world.dimension.DimensionType; -import net.minecraft.world.server.ServerWorld; -import pokecube.core.interfaces.IPokemob; -import pokecube.core.interfaces.capabilities.CapabilityPokemob; -import pokecube.core.interfaces.pokemob.ai.CombatStates; -import pokecube.core.interfaces.pokemob.ai.GeneralStates; -import pokecube.core.interfaces.pokemob.ai.LogicStates; -import thut.api.entity.ai.IAIRunnable; -import thut.api.entity.ai.ITask; -import thut.api.maths.Vector3; -import thut.api.terrain.TerrainManager; -import thut.lib.ItemStackTools; - -public abstract class AIBase implements ITask -{ - /** Thread safe inventory setting for pokemobs. */ - public static class InventoryChange implements IRunnable - { - public final int entity; - public final int slot; - public final int minSlot; - public final ItemStack stack; - - public InventoryChange(final Entity entity, final int slot, final ItemStack stack, final boolean min) - { - this.entity = entity.getEntityId(); - this.stack = stack; - if (min) - { - this.minSlot = slot; - this.slot = -1; - } - else - { - this.slot = slot; - this.minSlot = 0; - } - } - - @Override - public boolean run(final World world) - { - final Entity e = world.getEntityByID(this.entity); - final IPokemob pokemob = CapabilityPokemob.getPokemobFor(e); - if (e == null || pokemob == null) return false; - if (this.slot > 0) pokemob.getInventory().setInventorySlotContents(this.slot, this.stack); - else if (!ItemStackTools.addItemStackToInventory(this.stack, pokemob.getInventory(), this.minSlot)) e - .entityDropItem(this.stack, 0); - return true; - } - - } - - public static interface IRunnable - { - /** - * @param world - * @return task ran sucessfully - */ - boolean run(World world); - } - - /** Thread safe sound playing. */ - public static class PlaySound implements IRunnable - { - final DimensionType dim; - final Vector3 loc; - final SoundEvent sound; - final SoundCategory cat; - final float volume; - final float pitch; - - public PlaySound(final DimensionType dim, final Vector3 loc, final SoundEvent sound, final SoundCategory cat, - final float volume, final float pitch) - { - this.dim = dim; - this.sound = sound; - this.volume = volume; - this.loc = loc; - this.pitch = pitch; - this.cat = cat; - } - - @Override - public boolean run(final World world) - { - if (this.dim != world.getDimension().getType()) return false; - world.playSound(null, this.loc.x, this.loc.y, this.loc.z, this.sound, this.cat, this.volume, this.pitch); - return true; - } - - } - - protected final IPokemob pokemob; - protected final MobEntity entity; - protected final ServerWorld world; - - protected List toRun = Lists.newArrayList(); - - final Map, MemoryModuleStatus> neededMems; - - int priority = 0; - int mutex = 0; - - public AIBase(final IPokemob pokemob) - { - this.pokemob = pokemob; - this.entity = pokemob.getEntity(); - if (this.entity.getEntityWorld() instanceof ServerWorld) this.world = (ServerWorld) this.entity - .getEntityWorld(); - else this.world = null; - // Empty map for old version that does not wrap this. - this.neededMems = ImmutableMap.of(); - } - - public AIBase(final IPokemob pokemob, final Map, MemoryModuleStatus> neededMems) - { - this.pokemob = pokemob; - this.entity = pokemob.getEntity(); - if (this.entity.getEntityWorld() instanceof ServerWorld) this.world = (ServerWorld) this.entity - .getEntityWorld(); - else this.world = null; - this.neededMems = ImmutableMap.copyOf(neededMems); - } - - protected boolean addEntityPath(final MobEntity entity, final Path path, final double speed) - { - if (path == null) entity.getBrain().removeMemory(MemoryModuleType.WALK_TARGET); - else - { - final PathPoint end = path.getFinalPathPoint(); - final WalkTarget target = new WalkTarget(new BlockPos(end.x, end.y, end.z), (float) speed, 10); - entity.getBrain().setMemory(MemoryModuleType.WALK_TARGET, target); - } - entity.getBrain().setMemory(MemoryModuleType.PATH, path); - return entity.getNavigator().setPath(path, speed); - } - - protected void addMoveInfo(final IPokemob attacker, final Entity targetEnt, final Vector3 target, - final float distance) - { - attacker.executeMove(targetEnt, target, distance); - } - - protected boolean canMove() - { - // TODO in here, check things like being bound. - return true; - } - - @Override - public void finish() - { - this.toRun.forEach(w -> w.run(this.world)); - this.toRun.clear(); - } - - protected List getEntitiesWithinDistance(final Entity source, final float distance, - final Class clazz, final Class... targetClass) - { - if (!TerrainManager.isAreaLoaded(source.getEntityWorld(), source.getPosition(), distance)) return Collections - .emptyList(); - return this.getEntitiesWithinDistance(source.getEntityWorld(), source.getPosition(), distance, clazz, - targetClass); - } - - protected List getEntitiesWithinDistance(final World world, final BlockPos pos, - final float distance, final Class clazz, final Class... targetClass) - { - if (!TerrainManager.isAreaLoaded(world, pos, distance)) return Collections.emptyList(); - return world.getEntitiesWithinAABB(clazz, new AxisAlignedBB(pos).grow(distance), e -> - { - if (clazz.isInstance(e)) return true; - for (final Class c : targetClass) - if (c.isInstance(e)) return true; - return false; - }); - } - - @Override - public int getMutex() - { - return this.mutex; - } - - protected PlayerEntity getNearestPlayer(final Entity source, final float distance) - { - return source.getEntityWorld().getClosestPlayer(source, distance); - } - - @Override - public int getPriority() - { - return this.priority; - } - - protected void setCombatState(final IPokemob pokemob, final CombatStates state, final boolean value) - { - pokemob.setCombatState(state, value); - } - - protected void setGeneralState(final IPokemob pokemob, final GeneralStates state, final boolean value) - { - pokemob.setGeneralState(state, value); - } - - protected void setLogicState(final IPokemob pokemob, final LogicStates state, final boolean value) - { - pokemob.setLogicState(state, value); - } - - @Override - public IAIRunnable setMutex(final int mutex) - { - this.mutex = mutex; - return this; - } - - @Override - public IAIRunnable setPriority(final int prior) - { - this.priority = prior; - return this; - } - - @Override - public void tick() - { - } - - @Override - public Map, MemoryModuleStatus> getNeededMemories() - { - return this.neededMems; - } - -} diff --git a/src/main/java/pokecube/core/ai/tasks/AIFollowOwner.java b/src/main/java/pokecube/core/ai/tasks/AIFollowOwner.java index 3b8c138215..66262ae71b 100644 --- a/src/main/java/pokecube/core/ai/tasks/AIFollowOwner.java +++ b/src/main/java/pokecube/core/ai/tasks/AIFollowOwner.java @@ -1,16 +1,22 @@ package pokecube.core.ai.tasks; +import java.util.Map; + +import com.google.common.collect.Maps; + import net.minecraft.entity.LivingEntity; import net.minecraft.entity.MobEntity; -import net.minecraft.pathfinding.Path; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.brain.BrainUtil; +import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.pathfinding.PathNavigator; -import net.minecraft.util.math.Vec3d; import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.brain.MemoryModules; import pokecube.core.interfaces.IMoveConstants.AIRoutine; import pokecube.core.interfaces.IPokemob; -import pokecube.core.interfaces.pokemob.ai.CombatStates; import pokecube.core.interfaces.pokemob.ai.GeneralStates; -import pokecube.core.interfaces.pokemob.ai.LogicStates; import thut.api.maths.Vector3; /** @@ -20,23 +26,34 @@ */ public class AIFollowOwner extends TaskBase { + private static final Map, MemoryModuleStatus> mems = Maps.newHashMap(); + static + { + // Dont run if have a combat target + AIFollowOwner.mems.put(MemoryModules.ATTACKTARGET, MemoryModuleStatus.VALUE_ABSENT); + // Don't run if have a target location for moves + AIFollowOwner.mems.put(MemoryModules.MOVE_TARGET, MemoryModuleStatus.VALUE_ABSENT); + } + public static double speedMult = 2; private LivingEntity theOwner; - private double speed; private PathNavigator petPathfinder; - private int cooldown; - private boolean pathing = false; - float maxDist; - float minDist; - Vector3 ownerPos = Vector3.getNewVector(); - Vector3 v = Vector3.getNewVector(); - Vector3 v1 = Vector3.getNewVector(); + + private double speed; + private boolean pathing = false; + + float maxDist; + float minDist; + + Vector3 ownerPos = Vector3.getNewVector(); + Vector3 v = Vector3.getNewVector(); + Vector3 v1 = Vector3.getNewVector(); public AIFollowOwner(final IPokemob entity, final float min, final float max) { - super(entity); + super(entity, AIFollowOwner.mems); this.minDist = min; this.maxDist = max; this.speed = entity.getMovementSpeed(); @@ -57,13 +74,11 @@ public void run() if (this.theOwner == null) { this.theOwner = this.pokemob.getOwner(); - this.cooldown = 0; this.ownerPos.set(this.theOwner); this.pathing = true; } // Look at owner. - if (Vector3.isVisibleEntityFromEntity(this.entity, this.theOwner)) this.entity.getLookController() - .setLookPositionWithEntity(this.theOwner, 10.0F, this.entity.getVerticalFaceSpeed()); + if (BrainUtil.canSee(this.entity.getBrain(), this.theOwner)) BrainUtil.lookAt(this.entity, this.theOwner); else if (!this.petPathfinder.noPath() && this.petPathfinder.getPath().getCurrentPathIndex() < this.petPathfinder .getPath().getCurrentPathLength() - 3) { @@ -74,52 +89,51 @@ else if (!this.petPathfinder.noPath() && this.petPathfinder.getPath().getCurrent + 1).y + 0.5; z = this.petPathfinder.getPath().getPathPointFromIndex(this.petPathfinder.getPath().getCurrentPathIndex() + 1).z + 0.5; - this.entity.getLookController().setLookPosition(x, y, z, 10, this.entity.getVerticalFaceSpeed()); + // Or look at path location + BrainUtils.lookAt(this.entity, x, y, z); } - // Only path every couple ticks, or when owner has moved. - if (--this.cooldown <= 0) + + double dl = this.v.set(this.theOwner).distToSq(this.ownerPos); + if (dl < 1 && !this.petPathfinder.noPath()) return; + dl = this.v.set(this.entity).distTo(this.ownerPos); + this.ownerPos.set(this.theOwner); + double ownerSpeed = this.theOwner.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); + + if (this.theOwner instanceof PlayerEntity) { - this.cooldown = 2; - double dl = this.v.set(this.theOwner).distToSq(this.ownerPos); - if (dl < 1 && !this.petPathfinder.noPath()) return; - dl = this.v.set(this.entity).distTo(this.ownerPos); - this.ownerPos.set(this.theOwner); - final Vec3d v = this.theOwner.getMotion(); - double ownerSpeed = Math.sqrt(v.x * v.x + v.z * v.z); - if (ownerSpeed == 0) ownerSpeed = this.pokemob.getMovementSpeed(); - double dist_speed = ownerSpeed; - if (dl > 3) dist_speed *= 1 + (dl - 3) / 10; - this.speed = dist_speed; - this.speed *= AIFollowOwner.speedMult; - this.speed = Math.max(this.pokemob.getMovementSpeed(), this.speed); - final Path path = this.petPathfinder.getPathToEntityLiving(this.theOwner, 0); - if (path != null) this.addEntityPath(this.entity, path, this.speed); + final PlayerEntity player = (PlayerEntity) this.theOwner; + ownerSpeed = player.abilities.getWalkSpeed(); + if (player.abilities.isFlying) ownerSpeed = player.abilities.getFlySpeed(); + ownerSpeed *= 6; } + + if (ownerSpeed == 0) ownerSpeed = this.pokemob.getMovementSpeed(); + double dist_speed = ownerSpeed; + if (dl > 3) dist_speed *= 1 + (dl - 3) / 10; + this.speed = dist_speed; + this.speed *= AIFollowOwner.speedMult; + this.speed = Math.max(this.pokemob.getMovementSpeed(), this.speed); + this.speed = Math.min(1.5, this.speed); + + System.out.println(this.speed + " " + this.pokemob.getMovementSpeed() + " " + ownerSpeed + " " + this.theOwner); + + this.setWalkTo(this.ownerPos, this.speed, 0); } @Override public boolean shouldRun() { if (!this.pokemob.isRoutineEnabled(AIRoutine.FOLLOW)) return false; + if (!TaskBase.canMove(this.pokemob)) return false; final LivingEntity LivingEntity = this.pokemob.getOwner(); this.petPathfinder = this.entity.getNavigator(); // Nothing to follow if (LivingEntity == null) return false; - else if (this.pokemob.getLogicState(LogicStates.SITTING)) return false; else if (this.pokemob.getGeneralState(GeneralStates.STAYING)) return false; else if (this.pathing && this.entity.getDistanceSq(LivingEntity) > this.maxDist * this.maxDist) return true; - else if (BrainUtils.hasAttackTarget(this.entity) || this.pokemob.getCombatState(CombatStates.EXECUTINGMOVE)) - return false; else if (this.entity.getDistanceSq(LivingEntity) < this.minDist * this.minDist) return false; else if (Vector3.getNewVector().set(LivingEntity).distToSq(this.ownerPos) < this.minDist * this.minDist) return false; - else if (!this.petPathfinder.noPath()) - { - final Vector3 p = this.v1.set(this.petPathfinder.getPath().getFinalPathPoint()); - this.v.set(LivingEntity); - if (p.distToSq(this.v) <= 2) return false; - return true; - } // Follow owner. else return true; } diff --git a/src/main/java/pokecube/core/ai/tasks/IRunnable.java b/src/main/java/pokecube/core/ai/tasks/IRunnable.java new file mode 100644 index 0000000000..499bfab97f --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/IRunnable.java @@ -0,0 +1,12 @@ +package pokecube.core.ai.tasks; + +import net.minecraft.world.World; + +public interface IRunnable +{ + /** + * @param world + * @return task ran sucessfully + */ + boolean run(World world); +} diff --git a/src/main/java/pokecube/core/ai/tasks/TaskBase.java b/src/main/java/pokecube/core/ai/tasks/TaskBase.java index 39f488bb29..c5a76dd3cd 100644 --- a/src/main/java/pokecube/core/ai/tasks/TaskBase.java +++ b/src/main/java/pokecube/core/ai/tasks/TaskBase.java @@ -1,11 +1,8 @@ package pokecube.core.ai.tasks; -import java.util.Collections; -import java.util.List; import java.util.Map; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; import net.minecraft.entity.Entity; @@ -15,26 +12,23 @@ import net.minecraft.entity.ai.brain.memory.MemoryModuleType; import net.minecraft.entity.ai.brain.memory.WalkTarget; import net.minecraft.entity.ai.brain.task.Task; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.pathfinding.Path; -import net.minecraft.pathfinding.PathPoint; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; -import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.EntityPosWrapper; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.server.ServerWorld; +import pokecube.core.ai.brain.MemoryModules; +import pokecube.core.interfaces.IMoveConstants; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.capabilities.CapabilityPokemob; -import pokecube.core.interfaces.pokemob.ai.CombatStates; -import pokecube.core.interfaces.pokemob.ai.GeneralStates; import pokecube.core.interfaces.pokemob.ai.LogicStates; import thut.api.entity.ai.IAIRunnable; import thut.api.entity.ai.ITask; import thut.api.maths.Vector3; -import thut.api.terrain.TerrainManager; import thut.lib.ItemStackTools; public abstract class TaskBase extends Task implements ITask @@ -77,15 +71,6 @@ else if (!ItemStackTools.addItemStackToInventory(this.stack, pokemob.getInventor } - public static interface IRunnable - { - /** - * @param world - * @return task ran sucessfully - */ - boolean run(World world); - } - /** Thread safe sound playing. */ public static class PlaySound implements IRunnable { @@ -117,6 +102,16 @@ public boolean run(final World world) } + public static boolean canMove(final IPokemob pokemob) + { + final boolean sitting = pokemob.getLogicState(LogicStates.SITTING); + final boolean sleeping = pokemob.getLogicState(LogicStates.SLEEPING) || (pokemob.getStatus() + & IMoveConstants.STATUS_SLP) > 0; + final boolean frozen = (pokemob.getStatus() & IMoveConstants.STATUS_FRZ) > 0; + // DOLATER add other checks for things like bind, etc + return !(sitting || sleeping || frozen); + } + public static Map, MemoryModuleStatus> merge( final Map, MemoryModuleStatus> mems2, final Map, MemoryModuleStatus> mems3) @@ -127,11 +122,10 @@ public static Map, MemoryModuleStatus> merge( return ImmutableMap.copyOf(mems3); } - protected final IPokemob pokemob; - protected final MobEntity entity; - protected final ServerWorld world; + protected final IPokemob pokemob; + protected final MobEntity entity; - protected List toRun = Lists.newArrayList(); + protected final ServerWorld world; final Map, MemoryModuleStatus> neededMems; @@ -154,58 +148,31 @@ public TaskBase(final IPokemob pokemob, final Map, MemoryMod this.neededMems = ImmutableMap.copyOf(neededMems); } - protected boolean addEntityPath(final MobEntity entity, final Path path, final double speed) + protected void setWalkTo(final Vector3 pos, final double speed, final int dist) { - if (path == null) entity.getBrain().removeMemory(MemoryModuleType.WALK_TARGET); - else - { - final PathPoint end = path.getFinalPathPoint(); - final WalkTarget target = new WalkTarget(new BlockPos(end.x, end.y, end.z), (float) speed, 10); - entity.getBrain().setMemory(MemoryModuleType.WALK_TARGET, target); - } - entity.getBrain().setMemory(MemoryModuleType.PATH, path); - return entity.getNavigator().setPath(path, speed); + this.setWalkTo(pos.toVec3d(), speed, dist); } - protected void addMoveInfo(final IPokemob attacker, final Entity targetEnt, final Vector3 target, - final float distance) + protected void setWalkTo(final Vec3d pos, final double speed, final int dist) { - attacker.executeMove(targetEnt, target, distance); + this.entity.getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(pos, (float) speed, dist)); } - protected boolean canMove() + protected void setWalkTo(final BlockPos pos, final double speed, final int dist) { - // TODO in here, check things like being bound. - return true; + this.entity.getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(pos, (float) speed, dist)); } - @Override - public void finish() + protected void setWalkTo(final Entity mobIn, final double speed, final int dist) { - this.toRun.forEach(w -> w.run(this.world)); - this.toRun.clear(); + this.entity.getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(new EntityPosWrapper(mobIn), + (float) speed, dist)); } - protected List getEntitiesWithinDistance(final Entity source, final float distance, - final Class clazz, final Class... targetClass) + @Override + public void finish() { - if (!TerrainManager.isAreaLoaded(source.getEntityWorld(), source.getPosition(), distance)) return Collections - .emptyList(); - return this.getEntitiesWithinDistance(source.getEntityWorld(), source.getPosition(), distance, clazz, - targetClass); - } - protected List getEntitiesWithinDistance(final World world, final BlockPos pos, - final float distance, final Class clazz, final Class... targetClass) - { - if (!TerrainManager.isAreaLoaded(world, pos, distance)) return Collections.emptyList(); - return world.getEntitiesWithinAABB(clazz, new AxisAlignedBB(pos).grow(distance), e -> - { - if (clazz.isInstance(e)) return true; - for (final Class c : targetClass) - if (c.isInstance(e)) return true; - return false; - }); } @Override @@ -214,32 +181,12 @@ public int getMutex() return this.mutex; } - protected PlayerEntity getNearestPlayer(final Entity source, final float distance) - { - return source.getEntityWorld().getClosestPlayer(source, distance); - } - @Override public int getPriority() { return this.priority; } - protected void setCombatState(final IPokemob pokemob, final CombatStates state, final boolean value) - { - pokemob.setCombatState(state, value); - } - - protected void setGeneralState(final IPokemob pokemob, final GeneralStates state, final boolean value) - { - pokemob.setGeneralState(state, value); - } - - protected void setLogicState(final IPokemob pokemob, final LogicStates state, final boolean value) - { - pokemob.setLogicState(state, value); - } - @Override public IAIRunnable setMutex(final int mutex) { diff --git a/src/main/java/pokecube/core/ai/tasks/Tasks.java b/src/main/java/pokecube/core/ai/tasks/Tasks.java index e99d8b2d20..8f492c8ff4 100644 --- a/src/main/java/pokecube/core/ai/tasks/Tasks.java +++ b/src/main/java/pokecube/core/ai/tasks/Tasks.java @@ -15,15 +15,19 @@ import net.minecraft.entity.ai.brain.sensor.SensorType; import net.minecraft.entity.ai.brain.task.DummyTask; import net.minecraft.entity.ai.brain.task.FirstShuffledTask; +import net.minecraft.entity.ai.brain.task.FleeTask; import net.minecraft.entity.ai.brain.task.LookAtEntityTask; +import net.minecraft.entity.ai.brain.task.LookTask; import net.minecraft.entity.ai.brain.task.Task; import net.minecraft.entity.item.ItemEntity; import pokecube.core.ai.brain.BrainUtils; import pokecube.core.ai.brain.MemoryModules; +import pokecube.core.ai.brain.Sensors; import pokecube.core.ai.routes.GuardAI; import pokecube.core.ai.routes.GuardAI.ShouldRun; import pokecube.core.ai.routes.GuardTask; import pokecube.core.ai.routes.IGuardAICapability; +import pokecube.core.ai.routes.WalkToTask; import pokecube.core.ai.tasks.combat.AIAttack; import pokecube.core.ai.tasks.combat.AICombatMovement; import pokecube.core.ai.tasks.combat.AIDodge; @@ -47,10 +51,13 @@ public class Tasks { public static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModules.ATTACKTARGET, - MemoryModules.HUNTTARGET, MemoryModules.PATH, MemoryModules.WALK_TARGET); + MemoryModules.HUNTTARGET, MemoryModules.HUNTED_BY, MemoryModules.MOVE_TARGET, MemoryModules.PATH, + MemoryModules.MATE_TARGET, MemoryModules.WALK_TARGET, MemoryModules.LOOK_TARGET, + MemoryModules.NOT_FOUND_PATH); public static final List> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, - SensorType.NEAREST_PLAYERS, SensorType.INTERACTABLE_DOORS, SensorType.HURT_BY); + SensorType.NEAREST_PLAYERS, SensorType.INTERACTABLE_DOORS, SensorType.HURT_BY, Sensors.VISIBLE_BLOCKS, + Sensors.VISIBLE_ITEMS, Sensors.VALID_MATES); public static void initBrain(final Brain brain) { @@ -97,10 +104,20 @@ public boolean shouldRun() final Pair> pair = Pair.of(0, new GuardTask<>(guardai)); list.add(pair); - pokemob.getTasks().addAll(aiList); + + Task task = new LookTask(45, 90); + list.add(Pair.of(1, (Task)task)); + + task = new WalkToTask(200); + list.add(Pair.of(1, (Task)task)); + + task = new FleeTask(MemoryModules.HUNTED_BY, (float) (pokemob.getMovementSpeed()*1.5f)); + list.add(Pair.of(1, (Task)task)); list.add(Tasks.lookAtMany()); list.add(Tasks.lookAtPlayerOrVillager()); + + pokemob.getTasks().addAll(aiList); for (final IAIRunnable run : aiList) { Task toAdd = null; @@ -135,19 +152,12 @@ public boolean shouldRun() final List>> list = Lists.newArrayList(); - final IGuardAICapability guardCap = pokemob.getEntity().getCapability(CapHolders.GUARDAI_CAP).orElse(null); - final GuardAI guardai = new GuardAI(pokemob.getEntity(),guardCap); - guardai.shouldRun = new ShouldRun() - { - @Override - public boolean shouldRun() - { - if (!pokemob.getGeneralState(GeneralStates.TAMED)) return true; - return pokemob.getGeneralState(GeneralStates.STAYING); - } - }; - final Pair> pair = Pair.of(0, new GuardTask<>(guardai)); - list.add(pair); + Task task = new LookTask(45, 90); + list.add(Pair.of(1, (Task)task)); + + task = new FleeTask(MemoryModules.HUNTED_BY, (float) (pokemob.getMovementSpeed()*1.5f)); + list.add(Pair.of(1, (Task)task)); + pokemob.getTasks().addAll(aiList); for (final IAIRunnable run : aiList) { @@ -190,6 +200,16 @@ public boolean shouldRun() }; final Pair> pair = Pair.of(0, new GuardTask<>(guardai)); list.add(pair); + + Task task = new LookTask(45, 90); + list.add(Pair.of(1, (Task)task)); + + task = new WalkToTask(200); + list.add(Pair.of(1, (Task)task)); + + task = new FleeTask(MemoryModules.HUNTED_BY, (float) (pokemob.getMovementSpeed()*1.5f)); + list.add(Pair.of(1, (Task)task)); + pokemob.getTasks().addAll(aiList); for (final IAIRunnable run : aiList) { diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AIAttack.java b/src/main/java/pokecube/core/ai/tasks/combat/AIAttack.java index 8b7a025879..ff673ca582 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/AIAttack.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/AIAttack.java @@ -7,7 +7,6 @@ import net.minecraft.entity.ai.brain.BrainUtil; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.pathfinding.Path; import net.minecraft.util.Hand; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TranslationTextComponent; @@ -21,7 +20,6 @@ import pokecube.core.interfaces.capabilities.CapabilityPokemob; import pokecube.core.interfaces.pokemob.ai.CombatStates; import pokecube.core.interfaces.pokemob.ai.GeneralStates; -import pokecube.core.interfaces.pokemob.ai.LogicStates; import pokecube.core.items.pokecubes.EntityPokecubeBase; import pokecube.core.moves.MovesUtils; import thut.api.entity.ai.IAICombat; @@ -83,7 +81,7 @@ public boolean continueExecuting() if (mobB != null) { - if (mobB.getLogicState(LogicStates.FAINTED)) return false; + if (mobB.getCombatState(CombatStates.FAINTED)) return false; final boolean weTame = mobA.getOwnerId() == null; final boolean theyTame = mobB.getOwnerId() == null; @@ -94,10 +92,10 @@ public boolean continueExecuting() final float weHealth = mobA.getEntity().getHealth() / mobA.getEntity().getMaxHealth(); final float theyHealth = mobB.getEntity().getHealth() / mobB.getEntity().getMaxHealth(); // Wild mobs shouldn't fight to the death unless hunting. - if (weHealth < 0.25 || theyHealth < 0.25) + if (weHealth < 0.5 || theyHealth < 0.5) { - this.setCombatState(mobA, CombatStates.MATEFIGHT, false); - this.setCombatState(mobB, CombatStates.MATEFIGHT, false); + mobA.setCombatState(CombatStates.MATEFIGHT, false); + mobB.setCombatState(CombatStates.MATEFIGHT, false); return false; } // Give up if we took too long to fight. @@ -105,7 +103,7 @@ public boolean continueExecuting() } } - if (mobA.getLogicState(LogicStates.FAINTED)) return false; + if (mobA.getCombatState(CombatStates.FAINTED)) return false; if (!this.entityTarget.isAlive() || this.entityTarget.getHealth() <= 0) return false; if (!this.entity.isAlive() || this.entity.getHealth() <= 0) return false; @@ -117,19 +115,26 @@ public boolean continueExecuting() public void reset() { this.battleTime = 0; - if (this.running) - { - this.running = false; - this.addEntityPath(this.entity, null, this.movementSpeed); - } + this.clearUseMove(); AIFindTarget.deagro(this.entity); } + private void setUseMove() + { + this.pokemob.setCombatState(CombatStates.EXECUTINGMOVE, true); + BrainUtils.setMoveUseTarget(this.entity, this.targetLoc); + } + + private void clearUseMove() + { + this.pokemob.setCombatState(CombatStates.EXECUTINGMOVE, false); + BrainUtils.clearMoveUseTarget(this.entity); + } + @Override public void run() { this.battleTime++; - Path path; // Check if the pokemob has an active move being used, if so return if (this.pokemob.getActiveMove() != null) return; @@ -140,11 +145,8 @@ public void run() { if (!((this.attack.getAttackCategory() & IMoveConstants.CATEGORY_SELF) != 0) && !this.pokemob - .getGeneralState(GeneralStates.CONTROLLED)) - { - path = this.entity.getNavigator().getPathToEntityLiving(this.entityTarget, 0); - this.addEntityPath(this.entity, path, this.movementSpeed); - } + .getGeneralState(GeneralStates.CONTROLLED)) this.setWalkTo(this.entityTarget.getPositionVec(), + this.movementSpeed, 0); this.targetLoc.set(this.entityTarget); this.chaseTime = 0; this.running = true; @@ -181,17 +183,15 @@ public void run() } // Look at the target - this.entity.getLookController().setLookPositionWithEntity(this.entityTarget, 30.0F, 30.0F); + BrainUtil.lookAt(this.entity, this.entityTarget); // No executing move state with no target location. - if (this.pokemob.getCombatState(CombatStates.EXECUTINGMOVE) && this.targetLoc.isEmpty()) this.setCombatState( - this.pokemob, CombatStates.EXECUTINGMOVE, false); + if (this.pokemob.getCombatState(CombatStates.EXECUTINGMOVE) && this.targetLoc.isEmpty()) this.clearUseMove(); // If it has been too long since last seen the target, give up. if (this.chaseTime > 200) { - this.setCombatState(this.pokemob, CombatStates.ANGRY, false); - this.addEntityPath(this.entity, null, this.movementSpeed); + this.pokemob.setCombatState(CombatStates.ANGRY, false); this.chaseTime = 0; if (PokecubeMod.debug) PokecubeCore.LOGGER.log(Level.INFO, "Too Long Chase, Forgetting Target: " + this.entity + " " + this.entityTarget); @@ -210,28 +210,24 @@ public void run() return; } + Move_Base move = null; + move = MovesUtils.getMoveFromName(this.pokemob.getMove(this.pokemob.getMoveIndex())); + if (move == null) move = MovesUtils.getMoveFromName(IMoveConstants.DEFAULT_MOVE); double var1 = (double) (this.entity.getWidth() * 2.0F) * (this.entity.getWidth() * 2.0F); boolean distanced = false; - boolean self = false; - Move_Base move = null; + final boolean self = (move.getAttackCategory() & IMoveConstants.CATEGORY_SELF) > 0; final double dist = this.entity.getDistanceSq(this.entityTarget.posX, this.entityTarget.posY, this.entityTarget.posZ); - move = MovesUtils.getMoveFromName(this.pokemob.getMove(this.pokemob.getMoveIndex())); - - if (move == null) move = MovesUtils.getMoveFromName(IMoveConstants.DEFAULT_MOVE); + distanced = (move.getAttackCategory() & IMoveConstants.CATEGORY_DISTANCE) > 0; // Check to see if the move is ranged, contact or self. - if ((move.getAttackCategory() & IMoveConstants.CATEGORY_DISTANCE) > 0) - { - var1 = PokecubeCore.getConfig().rangedAttackDistance * PokecubeCore.getConfig().rangedAttackDistance; - distanced = true; - } + if (distanced) var1 = PokecubeCore.getConfig().rangedAttackDistance * PokecubeCore + .getConfig().rangedAttackDistance; else if (PokecubeCore.getConfig().contactAttackDistance > 0) { var1 = PokecubeCore.getConfig().contactAttackDistance * PokecubeCore.getConfig().contactAttackDistance; distanced = true; } - if ((move.getAttackCategory() & IMoveConstants.CATEGORY_SELF) > 0) self = true; this.delayTime = this.pokemob.getAttackCooldown(); final boolean canUseMove = MovesUtils.canUseMove(this.pokemob); @@ -272,69 +268,62 @@ else if (PokecubeCore.getConfig().contactAttackDistance > 0) this.entityTarget.getHeight() / 2, 0); } + final boolean isTargetDodging = this.pokemobTarget != null && this.pokemobTarget.getCombatState( + CombatStates.DODGING); + + // If the target is not trying to dodge, and the move allows it, + // then + // set target location to where the target is now. This is so that + // it can use the older postion set above, lowering the accuracy of + // move use, allowing easier dodging. + if (!isTargetDodging) this.targetLoc.set(this.entityTarget).addTo(0, this.entityTarget.getHeight() / 2, 0); + boolean delay = false; // Check if the attack should, applying a new delay if this is the // case.. - if (inRange || self) + if (inRange && canSee || self) { - if (canSee || self) + if (this.delayTime <= 0 && this.entity.addedToChunk) { - if (this.delayTime <= 0 && this.entity.addedToChunk) - { - this.delayTime = this.pokemob.getAttackCooldown(); - delay = canUseMove; - } - shouldPath = false; - this.setCombatState(this.pokemob, CombatStates.EXECUTINGMOVE, true); + this.delayTime = this.pokemob.getAttackCooldown(); + delay = canUseMove; } + shouldPath = false; + if (!self) this.setUseMove(); + else this.clearUseMove(); + } + + if (!(distanced || self)) + { + this.setUseMove(); + this.pokemob.setCombatState(CombatStates.LEAPING, true); } - else this.setCombatState(this.pokemob, CombatStates.EXECUTINGMOVE, false); // If all the conditions match, queue up an attack. if (!this.targetLoc.isEmpty() && delay && inRange) { - // If the target is not trying to dodge, and the move allows it, - // then - // set target location to where the target is now. This is so that - // it can use the older postion set above, lowering the accuracy of - // move use, allowing easier dodging. - if (this.pokemobTarget != null && !this.pokemobTarget.getCombatState(CombatStates.DODGING) - || !(this.pokemobTarget != null) || this.attack.move.isNotIntercepable()) this.targetLoc.set( - this.entityTarget).addTo(0, this.entityTarget.getHeight() / 2, 0); // Tell the target no need to try to dodge anymore, move is fired. - if (this.pokemobTarget != null) this.setCombatState(this.pokemobTarget, CombatStates.DODGING, false); + if (this.pokemobTarget != null) this.pokemobTarget.setCombatState(CombatStates.DODGING, false); // Swing arm for effect. if (this.entity.getHeldItemMainhand() != null) this.entity.swingArm(Hand.MAIN_HAND); // Apply the move. final float f = (float) this.targetLoc.distToEntity(this.entity); if (this.entity.addedToChunk) { - if (this.entityTarget.isAlive()) this.addMoveInfo(this.pokemob, this.entityTarget, this.targetLoc - .copy(), f); + if (this.entityTarget.isAlive()) this.pokemob.executeMove(this.entityTarget, this.targetLoc.copy(), f); // Reset executing move and no item use status now that we have // used a move. - this.setCombatState(this.pokemob, CombatStates.EXECUTINGMOVE, false); - this.setCombatState(this.pokemob, CombatStates.NOITEMUSE, false); + this.clearUseMove(); + this.pokemob.setCombatState(CombatStates.NOITEMUSE, false); this.targetLoc.clear(); shouldPath = false; this.delayTime = this.pokemob.getAttackCooldown(); } } - // If the conditions that failed were due to distance, try to start - // leaping to close distance. - else if (shouldPath && !(distanced || self) && !this.pokemob.getCombatState(CombatStates.LEAPING)) - { - this.setCombatState(this.pokemob, CombatStates.EXECUTINGMOVE, true); - this.setCombatState(this.pokemob, CombatStates.LEAPING, true); - if (PokecubeMod.debug) PokecubeCore.LOGGER.log(Level.INFO, "Set To Leap: " + this.entity); - } // If there is a target location, and it should path to it, queue a path // for the mob. - if (!this.targetLoc.isEmpty() && shouldPath) - { - path = this.entity.getNavigator().func_225466_a(this.targetLoc.x, this.targetLoc.y, this.targetLoc.z, 0); - if (path != null) this.addEntityPath(this.entity, path, this.movementSpeed); - } + if (!this.targetLoc.isEmpty() && shouldPath) this.setWalkTo(this.entityTarget.getPositionVec(), + this.movementSpeed, 0); } @Override @@ -345,12 +334,7 @@ public boolean shouldRun() final LivingEntity target = BrainUtils.getAttackTarget(this.entity); // No target, we can't do anything, so return false - if (target == null) - { - if (this.entity.getNavigator().noPath() && this.pokemob.getCombatState(CombatStates.EXECUTINGMOVE)) this - .setCombatState(this.pokemob, CombatStates.EXECUTINGMOVE, false); - return false; - } + if (target == null) return false; // If either us, or target is dead, or about to be so (0 health) return // false if (!target.isAlive() || target.getHealth() <= 0 || this.pokemob.getHealth() <= 0 || !this.entity.isAlive()) diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AICombatMovement.java b/src/main/java/pokecube/core/ai/tasks/combat/AICombatMovement.java index 355d1cdd12..c03db5447c 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/AICombatMovement.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/AICombatMovement.java @@ -2,7 +2,6 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.pathfinding.Path; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; import pokecube.core.interfaces.IPokemob; @@ -76,11 +75,7 @@ public void run() if (diff.magSq() > combatDistanceSq) { this.pokemob.setCombatState(CombatStates.LEAPING, false); - final Path path = this.entity.getNavigator().getPathToPos(this.centre.getPos(), 0); - // Path back to center of ring. - if (path != null) this.addEntityPath(this.entity, path, this.movementSpeed); - // Could not path to center, so null it to re-calulate next run. - else this.centre = null; + this.setWalkTo(this.centre, this.movementSpeed, 0); } else { @@ -89,8 +84,7 @@ public void run() if (this.entity.ticksExisted % revTime > revTime / 2) perp.reverse(); perp.addTo(here); if (Math.abs(perp.y - this.centre.y) > combatDistance / 2) perp.y = this.centre.y; - final Path path = this.entity.getNavigator().getPathToPos(perp.getPos(), 0); - this.addEntityPath(this.entity, path, this.movementSpeed); + this.setWalkTo(perp, this.movementSpeed, 0); } } diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AIDodge.java b/src/main/java/pokecube/core/ai/tasks/combat/AIDodge.java index 13a8267db5..4a3875d0b3 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/AIDodge.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/AIDodge.java @@ -2,32 +2,32 @@ import java.util.Random; -import org.apache.logging.log4j.Level; - -import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.IPosWrapper; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; -import pokecube.core.interfaces.IMoveConstants; +import pokecube.core.ai.tasks.TaskBase; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.IPokemob.Stats; -import pokecube.core.interfaces.Move_Base; import pokecube.core.interfaces.PokecubeMod; -import pokecube.core.interfaces.capabilities.CapabilityPokemob; import pokecube.core.interfaces.pokemob.ai.CombatStates; -import pokecube.core.moves.MovesUtils; import pokecube.core.utils.AITools; import thut.api.entity.ai.IAICombat; import thut.api.maths.Vector3; public class AIDodge extends FightTask implements IAICombat { - Entity target; + + // Location of the targetted attack + IPosWrapper pos = null; + double movementSpeed; double dodgeSpeedFactor = 0.25f; - int dodgeCooldown = 10; + + int dodgeCooldown = -1; public AIDodge(final IPokemob mob) { @@ -49,7 +49,8 @@ private SoundEvent getDodgeSound() @Override public void reset() { - this.target = null; + this.dodgeCooldown = -1; + this.pokemob.setCombatState(CombatStates.DODGING, false); } /** @@ -62,20 +63,18 @@ public void reset() @Override public void run() { - if (PokecubeMod.debug) PokecubeCore.LOGGER.log(Level.INFO, "Dodge: " + this.entity); /* - * Set dodging state to notify attack AI that target is dodging. + * We just dodged, so return false here for now */ - if (!this.pokemob.getCombatState(CombatStates.DODGING)) - { - this.pokemob.setCombatState(CombatStates.DODGING, true); - this.dodgeCooldown = PokecubeCore.getConfig().attackCooldown; - } + if (this.pokemob.getCombatState(CombatStates.DODGING)) return; + // set the dodge flag so other mobs know about this for missing + this.pokemob.setCombatState(CombatStates.DODGING, true); + if (PokecubeMod.debug) PokecubeCore.LOGGER.debug("Dodge: " + this.entity); /* * Compute a random perpendicular direction. */ final Vector3 loc = Vector3.getNewVector().set(this.entity); - final Vector3 target = Vector3.getNewVector().set(BrainUtils.getAttackTarget(this.entity)); + final Vector3 target = Vector3.getNewVector().set(this.pos.getPos()); final Vector3 temp = Vector3.getNewVector(); Vector3 perp = target.subtractFrom(loc).rotateAboutLine(Vector3.secondAxis, Math.PI / 2, temp); if (Math.random() > 0.5) perp = perp.scalarMultBy(-1); @@ -101,9 +100,9 @@ public void run() * Apply the dodge */ perp.addVelocities(this.entity); - // Only play sound once. - if (this.dodgeCooldown == -1) this.toRun.add(new PlaySound(this.entity.dimension, Vector3.getNewVector().set( - this.entity), this.getDodgeSound(), SoundCategory.HOSTILE, 1, 1)); + + new PlaySound(this.entity.dimension, Vector3.getNewVector().set(this.entity), this.getDodgeSound(), + SoundCategory.HOSTILE, 1, 1).run(this.world); } /** @@ -116,38 +115,35 @@ public void run() @Override public boolean shouldRun() { - if (!this.canMove()) return false; + if (!TaskBase.canMove(this.pokemob)) return false; + + // We are still preparing to dodge + if (this.dodgeCooldown-- >= 0) return true; - // We are already set to dodge, cooldown ensures dodge state lasts long - // enough to make some ranged attacks miss - if (this.pokemob.getCombatState(CombatStates.DODGING)) if (this.dodgeCooldown-- < 0) return true; - // Off cooldown, reset dodge state. - else this.pokemob.setCombatState(CombatStates.DODGING, false); + final LivingEntity target = BrainUtils.getAttackTarget(this.entity); // Only dodge if there is an attack target. - if ((this.target = BrainUtils.getAttackTarget(this.entity)) == null) return false; + if (target == null) return false; + // Only flying or floating can dodge while in the air if (!AITools.canNavigate.test(this.pokemob)) return false; - final IPokemob target = CapabilityPokemob.getPokemobFor(this.target); - if (target != null) + this.pos = BrainUtils.getMoveUseTarget(target); + if (this.pos != null) { - boolean shouldDodgeMove = target.getCombatState(CombatStates.EXECUTINGMOVE); - if (shouldDodgeMove) - { - /* - * Check if the enemy is using a self move, if so, no point in - * trying to dodge this. - */ - final Move_Base move = MovesUtils.getMoveFromName(target.getMove(target.getMoveIndex())); - if (move == null || (move.getAttackCategory() & IMoveConstants.CATEGORY_SELF) > 0) - shouldDodgeMove = false; - } - return shouldDodgeMove; + final double ds2 = this.entity.getDistanceSq(this.pos.getPos()); + // No need to dodge if the target isn't near us + if (ds2 > 16) return false; } + // Nothing to dodge if target isn't attacking! + else return false; + /* * Scale amount jumped by evasion stat. */ final double evasionMod = this.pokemob.getFloatStat(Stats.EVASION, true) / 30d; - return Math.random() > 1 - evasionMod; + final boolean dodge = Math.random() > 1 - evasionMod; + if (dodge) this.dodgeCooldown = 10; + + return dodge; } } diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AIFindTarget.java b/src/main/java/pokecube/core/ai/tasks/combat/AIFindTarget.java index 8654d6be02..523478df39 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/AIFindTarget.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/AIFindTarget.java @@ -87,7 +87,11 @@ public static void deagro(final LivingEntity mob) AIFindTarget.deagro(oldTarget); } mob.getBrain().removeMemory(MemoryModules.ATTACKTARGET); - if (aggressor != null) aggressor.setCombatState(CombatStates.ANGRY, false); + if (aggressor != null) + { + aggressor.setCombatState(CombatStates.ANGRY, false); + aggressor.setCombatState(CombatStates.MATEFIGHT, false); + } } @SubscribeEvent @@ -204,17 +208,6 @@ public static void onDamaged(final LivingDamageEvent event) if (!(oldTarget == null && attacker != attacked && attacker instanceof LivingEntity && oldTarget != attacker)) attacker = null; - final IPokemob agres = CapabilityPokemob.getPokemobFor(attacker); - if (agres != null) - { - if (agres.getPokedexEntry().isFood(pokemobCap.getPokedexEntry()) && agres.getCombatState( - CombatStates.HUNTING)) - { - // track running away. - } - if (agres.getLover() == attacked && attacker != null) agres.setLover(attacker); - - } LivingEntity newTarget = oldTarget; // Either keep old target, or agress the attacker. if (oldTarget != null && BrainUtils.getAttackTarget(attacked) != oldTarget) newTarget = oldTarget; @@ -233,15 +226,16 @@ public static void onDamaged(final LivingDamageEvent event) * targetting things on the same team. */ final Predicate validGuardTarget = input -> - { - if (input == AIFindTarget.this.entity) return false; - if (TeamManager.sameTeam(AIFindTarget.this.entity, input)) - return false; - if (!AITools.validTargets.test(input)) return false; - return input instanceof LivingEntity; - }; - private int agroTimer = -1; - private LivingEntity entityTarget = null; + { + if (input == AIFindTarget.this.entity) return false; + if (TeamManager.sameTeam(AIFindTarget.this.entity, input)) return false; + if (!AITools.validTargets.test(input)) return false; + return input instanceof LivingEntity; + }; + + private int agroTimer = -1; + + private LivingEntity entityTarget = null; public AIFindTarget(final IPokemob mob) { @@ -599,8 +593,8 @@ public boolean shouldRun() } // If the target is a pokemob, on same team, we shouldn't target - // it either - if (TeamManager.sameTeam(target, this.entity)) + // it either, unless it is fighting over a mate + if (TeamManager.sameTeam(target, this.entity) && !this.pokemob.getCombatState(CombatStates.MATEFIGHT)) { this.setAttackTarget(this.entity, null); if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug("Cannot target team mates."); diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AILeap.java b/src/main/java/pokecube/core/ai/tasks/combat/AILeap.java index d73968a936..b8a9a1b62a 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/AILeap.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/AILeap.java @@ -1,35 +1,55 @@ package pokecube.core.ai.tasks.combat; +import java.util.Map; import java.util.Random; -import org.apache.logging.log4j.Level; +import com.google.common.collect.Maps; -import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.IPosWrapper; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.brain.MemoryModules; +import pokecube.core.ai.tasks.TaskBase; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.PokecubeMod; import pokecube.core.interfaces.pokemob.ai.CombatStates; import thut.api.entity.ai.IAICombat; import thut.api.maths.Vector3; -public class AILeap extends FightTask implements IAICombat +/** + * This one extends TaskBase, rather than FightTask, as it can apply when just a + * move target, ie attacking blocks, so it doesn't need to actually have a + * living target to apply. + */ +public class AILeap extends TaskBase implements IAICombat { - Entity target; - int leapCooldown = 10; - double leapSpeed = 1; - double movementSpeed; - Vector3 leapTarget = null; - Vector3 leapOrigin = null; + private static final Map, MemoryModuleStatus> MEMS = Maps.newHashMap(); + + static + { + AILeap.MEMS.put(MemoryModules.MOVE_TARGET, MemoryModuleStatus.VALUE_PRESENT); + } + + int leapTick = -1; + + double leapSpeed = 1; + double movementSpeed; + + IPosWrapper pos = null; + + Vector3 leapTarget = Vector3.getNewVector(); + Vector3 leapOrigin = Vector3.getNewVector(); public AILeap(final IPokemob mob) { - super(mob); + super(mob, AILeap.MEMS); this.movementSpeed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue() * 1.8; - this.setMutex(0); } /** @@ -45,37 +65,27 @@ private SoundEvent getLeapSound() @Override public void reset() { - this.target = null; - this.leapTarget = null; - this.leapOrigin = null; } @Override public void run() { + final LivingEntity target = BrainUtils.getAttackTarget(this.entity); // Target loc could just be a position - this.leapTarget = this.target != null ? Vector3.getNewVector().set(this.target) : this.pokemob.getTargetPos(); + this.leapTarget.set(this.pos.getPos()); final Vector3 location = Vector3.getNewVector().set(this.entity); - final Vector3 dir = this.leapTarget.subtract(location); + final Vector3 diff = this.leapTarget.subtract(location); /* Don't leap up if too far. */ - if (dir.y > 5) return; + if (diff.y > 5) return; - final double dist = dir.x * dir.x + dir.z * dir.z; - float diff = this.entity.getWidth() + (this.target == null ? 0 : this.target.getWidth()); - diff = diff * diff; + final double dist = diff.magSq(); // Wait till it is a bit closer than this... if (dist >= 16.0D) return; - if (dist <= diff) - { - this.pokemob.setCombatState(CombatStates.LEAPING, false); - this.leapCooldown = PokecubeCore.getConfig().attackCooldown / 2; - return; - } - dir.norm(); + final Vector3 dir = diff.normalize(); dir.scalarMultBy(this.leapSpeed * PokecubeCore.getConfig().leapSpeedFactor); if (dir.isNaN()) { @@ -83,13 +93,11 @@ public void run() dir.clear(); } - if (PokecubeMod.debug) PokecubeCore.LOGGER.log(Level.INFO, "Leap: " + this.entity + " " + dir.mag()); - // Compute differences in velocities, and then account for that during // the leap. final Vector3 v_a = Vector3.getNewVector().setToVelocity(this.entity); final Vector3 v_t = Vector3.getNewVector(); - if (this.target != null) v_t.setToVelocity(this.target); + if (target != null) v_t.setToVelocity(target); // Compute velocity differential. final Vector3 dv = v_a.subtractFrom(v_t); // Adjust for existing velocity differential. @@ -98,19 +106,28 @@ public void run() * Apply the leap */ dir.addVelocities(this.entity); - // Only play sound once. - if (this.leapCooldown == -1) this.toRun.add(new PlaySound(this.entity.dimension, Vector3.getNewVector().set( - this.entity), this.getLeapSound(), SoundCategory.HOSTILE, 1, 1)); + + if (PokecubeMod.debug) PokecubeCore.LOGGER.debug("Leap: " + this.entity + " " + diff + " " + dir); + + // Set the timer so we don't leap again rapidly + this.leapTick = this.entity.ticksExisted + PokecubeCore.getConfig().attackCooldown / 2; + + new PlaySound(this.entity.dimension, Vector3.getNewVector().set(this.entity), this.getLeapSound(), + SoundCategory.HOSTILE, 1, 1).run(this.world); + this.pokemob.setCombatState(CombatStates.LEAPING, false); } @Override public boolean shouldRun() { - if (!this.canMove()) return false; - - return this.leapCooldown-- < 0 && this.pokemob.getCombatState(CombatStates.LEAPING) - && ((this.target = BrainUtils.getAttackTarget(this.entity)) != null || this.pokemob - .getTargetPos() != null); + // Can't move, no leap + if (!TaskBase.canMove(this.pokemob)) return false; + // Not actually set to leap + if (!this.pokemob.getCombatState(CombatStates.LEAPING)) return false; + // On cooldown, no leap + if (this.leapTick > this.entity.ticksExisted) return false; + // Leap if we have a target pos + return (this.pos = BrainUtils.getMoveUseTarget(this.entity)) != null; } } diff --git a/src/main/java/pokecube/core/ai/tasks/combat/FightTask.java b/src/main/java/pokecube/core/ai/tasks/combat/FightTask.java index cdd2996e96..ccfa76c826 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/FightTask.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/FightTask.java @@ -27,4 +27,9 @@ public FightTask(final IPokemob pokemob) super(pokemob, FightTask.MEMS); } + public FightTask(final IPokemob pokemob, final Map, MemoryModuleStatus> mems) + { + super(pokemob, TaskBase.merge(FightTask.MEMS, mems)); + } + } diff --git a/src/main/java/pokecube/core/ai/tasks/idle/AIGuardEgg.java b/src/main/java/pokecube/core/ai/tasks/idle/AIGuardEgg.java index 2b59ff01c1..f12772e1f4 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/AIGuardEgg.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/AIGuardEgg.java @@ -5,8 +5,8 @@ import java.util.function.Predicate; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.brain.memory.MemoryModuleType; -import net.minecraft.pathfinding.Path; import pokecube.core.PokecubeCore; import pokecube.core.ai.tasks.combat.AIFindTarget; import pokecube.core.interfaces.IPokemob; @@ -24,9 +24,10 @@ public class AIGuardEgg extends IdleTask public static int PATHCOOLDOWN = 50; public static int SEARCHCOOLDOWN = 50; - EntityPokemobEgg egg = null; - int eggSearchCooldown = 0; - int eggPathCooldown = 0; + EntityPokemobEgg egg = null; + + int eggSearchCooldown = 0; + int eggPathCooldown = 0; public AIGuardEgg(final IPokemob mob) { @@ -50,8 +51,8 @@ public void run() if (this.eggPathCooldown-- > 0) return; this.eggPathCooldown = AIGuardEgg.PATHCOOLDOWN; // Path to the egg. - final Path path = this.entity.getNavigator().getPathToEntityLiving(this.egg, 0); - this.addEntityPath(this.entity, path, this.pokemob.getMovementSpeed()); + final double speed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); + this.setWalkTo(this.egg.getPositionVec(), speed, 0); } @Override diff --git a/src/main/java/pokecube/core/ai/tasks/idle/AIHungry.java b/src/main/java/pokecube/core/ai/tasks/idle/AIHungry.java index 42f9b09efd..1fb2d6d030 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/AIHungry.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/AIHungry.java @@ -3,37 +3,48 @@ import java.util.Collections; import java.util.List; import java.util.Random; -import java.util.function.Predicate; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.material.Material; +import com.google.common.base.Predicate; +import com.google.common.collect.Lists; + +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.projectile.FishingBobberEntity; -import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; -import net.minecraft.pathfinding.Path; import net.minecraft.util.DamageSource; -import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.RayTraceContext.BlockMode; +import net.minecraft.util.math.RayTraceContext.FluidMode; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.RayTraceResult.Type; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; +import pokecube.core.ai.tasks.IRunnable; +import pokecube.core.ai.tasks.idle.hunger.EatFromChest; +import pokecube.core.ai.tasks.idle.hunger.EatPlant; +import pokecube.core.ai.tasks.idle.hunger.EatRedstone; +import pokecube.core.ai.tasks.idle.hunger.EatRock; +import pokecube.core.ai.tasks.idle.hunger.EatWater; +import pokecube.core.ai.tasks.idle.hunger.IBlockEatTask; import pokecube.core.blocks.berries.BerryGenManager; -import pokecube.core.handlers.events.MoveEventsHandler; -import pokecube.core.interfaces.IBerryFruitBlock; import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.capabilities.CapabilityPokemob; import pokecube.core.interfaces.pokemob.ai.CombatStates; import pokecube.core.interfaces.pokemob.ai.GeneralStates; import pokecube.core.interfaces.pokemob.ai.LogicStates; import pokecube.core.utils.ChunkCoordinate; import pokecube.core.utils.TimePeriod; -import pokecube.core.world.terrain.PokecubeTerrainChecker; import thut.api.item.ItemList; import thut.api.maths.Vector3; import thut.lib.ItemStackTools; @@ -68,7 +79,6 @@ public boolean run(final World world) } return true; } - } public static float calculateHunger(final IPokemob pokemob) @@ -87,6 +97,17 @@ public static boolean hitThreshold(final float hungerValue, final float threshol return hungerValue <= threshold; } + public static final List EATTASKS = Lists.newArrayList(); + + static + { + AIHungry.EATTASKS.add(new EatWater()); + AIHungry.EATTASKS.add(new EatRedstone()); + AIHungry.EATTASKS.add(new EatRock()); + AIHungry.EATTASKS.add(new EatPlant()); + AIHungry.EATTASKS.add(new EatFromChest()); + } + public static int TICKRATE = 20; public static float EATTHRESHOLD = 0.75f; @@ -98,17 +119,22 @@ public static boolean hitThreshold(final float hungerValue, final float threshol // final World world; final ItemEntity berry; - final double distance; - int lastMessageTick1 = -1; - int lastMessageTick2 = -1; - Vector3 foodLoc = null; - boolean block = false; - boolean sleepy = false; - float hungerValue = 1; - double moveSpeed; - Vector3 v = Vector3.getNewVector(); - Vector3 v1 = Vector3.getNewVector(); - Random rand; + + final double distance; + + int lastMessageTick1 = -1; + int lastMessageTick2 = -1; + + boolean sleepy = false; + + float hungerValue = 1; + double moveSpeed; + + List blocks = null; + + Vector3 v = Vector3.getNewVector(); + Vector3 v1 = Vector3.getNewVector(); + Random rand; public AIHungry(final IPokemob pokemob, final ItemEntity berry_, final double distance) { @@ -138,8 +164,7 @@ protected boolean checkBait() final FishingBobberEntity hook = hooks.get(0); if (this.v.isVisible(this.world, this.v1.set(hook))) { - final Path path = this.entity.getNavigator().getPathToEntityLiving(hook, 0); - this.addEntityPath(this.entity, path, this.moveSpeed); + this.setWalkTo(hook.getPositionVec(), this.moveSpeed, 0); if (this.entity.getDistanceSq(hook) < 2) { hook.caughtEntity = this.entity; @@ -152,23 +177,6 @@ protected boolean checkBait() return false; } - /** - * Checks for redstone blocks nearby. - * - * @return found redstone block. - */ - protected boolean checkElectricEat() - { - final int num = this.v.blockCount(this.world, Blocks.REDSTONE_BLOCK, 8); - if (num >= 1) - { - this.pokemob.setHungerTime(this.pokemob.getHungerTime() - PokecubeCore.getConfig().pokemobLifeSpan / 4); - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - return true; - } - return false; - } - /** * Checks for a variety of nearby food supplies, returns true if it finds * food. @@ -179,8 +187,26 @@ protected boolean checkHunt() { if (!this.hitThreshold(AIHungry.HUNTTHRESHOLD)) return false; if (this.pokemob.isPhototroph()) if (this.checkPhotoeat()) return true; - if (this.pokemob.isLithotroph()) if (this.checkRockEat()) return true; - if (this.pokemob.isElectrotroph()) if (this.checkElectricEat()) return true; + for (final IBlockEatTask task : AIHungry.EATTASKS) + if (task.tryEat(this.pokemob, this.blocks).test()) return true; + // If none of these, then lets actually try to hunt. + if (this.pokemob.getPokedexEntry().hasPrey() && this.entity.getBrain().hasMemory(MemoryModuleType.VISIBLE_MOBS)) + { + final List targets = this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS).get(); + for (final LivingEntity mob : targets) + { + final IPokemob other = CapabilityPokemob.getPokemobFor(mob); + if (other != null && this.pokemob.getPokedexEntry().isFood(other.getPokedexEntry())) + { + final boolean isValid = other.getLevel() - this.pokemob.getLevel() < 5; + if (isValid) + { + BrainUtils.setHuntTarget(this.entity, mob); + return true; + } + } + } + } return false; } @@ -205,7 +231,7 @@ protected boolean checkInventory() final ItemStack stack = this.pokemob.getInventory().getStackInSlot(i); if (ItemList.is(AIHungry.FOODTAG, stack)) { - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); + this.pokemob.setCombatState(CombatStates.HUNTING, false); this.pokemob.eat(this.berry); stack.shrink(1); if (stack.isEmpty()) this.pokemob.getInventory().setInventorySlotContents(i, ItemStack.EMPTY); @@ -225,51 +251,7 @@ protected boolean checkPhotoeat() if (this.entity.getEntityWorld().dimension.isDaytime() && this.v.canSeeSky(this.world)) { this.pokemob.setHungerTime(this.pokemob.getHungerTime() - PokecubeCore.getConfig().pokemobLifeSpan / 4); - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - return true; - } - return false; - } - - /** - * Checks for rocks nearby to eat - * - * @return found and ate rocks. - */ - protected boolean checkRockEat() - { - final BlockState state = this.v.offset(Direction.DOWN).getBlockState(this.world); - final Block b = state.getBlock(); - // Look for nearby rocks. - if (!PokecubeTerrainChecker.isRock(state)) - { - final Predicate checker = (b2) -> PokecubeTerrainChecker.isRock(b2); - final Vector3 temp = this.v.findClosestVisibleObject(this.world, true, (int) this.distance, checker); - if (temp != null) - { - this.block = true; - this.foodLoc = temp.copy(); - } - if (this.foodLoc != null) return true; - } - else - { - // Check configs, and if so, actually eat the rocks - if (PokecubeCore.getConfig().pokemobsEatRocks) - { - this.v.set(this.entity).offsetBy(Direction.DOWN); - if (MoveEventsHandler.canEffectBlock(this.pokemob, this.v)) if (b == Blocks.COBBLESTONE) this.v - .setBlock(this.world, Blocks.GRAVEL.getDefaultState()); - else if (b == Blocks.GRAVEL && PokecubeCore.getConfig().pokemobsEatGravel) this.v.setBlock(this.world, - Blocks.AIR.getDefaultState()); - else if (state.getMaterial() == Material.ROCK) this.v.setBlock(this.world, Blocks.COBBLESTONE - .getDefaultState()); - } - // Apply the eating of the item. - this.berry.setItem(new ItemStack(b)); - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - this.pokemob.eat(this.berry); - this.foodLoc = null; + this.pokemob.setCombatState(CombatStates.HUNTING, false); return true; } return false; @@ -297,12 +279,7 @@ protected boolean checkSleep() .getGeneralState(GeneralStates.STAYING); if (this.sleepy && this.hitThreshold(AIHungry.EATTHRESHOLD) && !ownedSleepCheck) { - if (!this.isGoodSleepingSpot(c)) - { - Path path = this.entity.getNavigator().getPathToPos(this.pokemob.getHome(), 0); - if (path != null && path.getCurrentPathLength() > 32) path = null; - this.addEntityPath(this.entity, path, this.moveSpeed); - } + if (!this.isGoodSleepingSpot(c)) this.setWalkTo(this.pokemob.getHome(), this.moveSpeed, 0); else if (this.entity.getNavigator().noPath()) { this.pokemob.setLogicState(LogicStates.SLEEPING, true); @@ -317,299 +294,6 @@ else if (!this.pokemob.getLogicState(LogicStates.TIRED)) this.pokemob.setLogicSt return false; } - /** - * Eats a berry - * - * @param b - * the berry - * @param distance - * to the berry - */ - protected void eatBerry(final BlockState b, final double distance) - { - final ItemStack fruit = ((IBerryFruitBlock) b.getBlock()).getBerryStack(this.world, this.foodLoc.getPos()); - - if (fruit.isEmpty()) - { - this.foodLoc = null; - this.pokemob.noEat(null); - return; - } - - if (distance < 3) - { - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - this.berry.setItem(fruit); - this.pokemob.eat(this.berry); - this.toRun.add(new InventoryChange(this.entity, 2, fruit, true)); - this.foodLoc.setBlock(this.world, Blocks.AIR.getDefaultState()); - this.foodLoc = null; - } - else if (this.entity.ticksExisted % 20 == this.rand.nextInt(20)) - { - boolean shouldChangePath = true; - if (!this.entity.getNavigator().noPath()) - { - final Vector3 p = this.v.set(this.entity.getNavigator().getPath().getFinalPathPoint()); - final Vector3 v = this.v1.set(this.foodLoc); - if (p.distToSq(v) <= 16) shouldChangePath = false; - } - Path path = null; - if (shouldChangePath && (path = this.entity.getNavigator().func_225466_a(this.foodLoc.x, this.foodLoc.y, - this.foodLoc.z, 0)) == null) - { - this.addEntityPath(this.entity, path, this.moveSpeed); - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - this.berry.setItem(fruit); - this.pokemob.noEat(this.berry); - this.foodLoc.clear(); - } - else this.addEntityPath(this.entity, path, this.moveSpeed); - } - } - - /** - * Eats a plant. - * - * @param b - * the plant - * @param location - * where the plant is - * @param dist - * distance to the plant - */ - protected void eatPlant(final BlockState b, final Vector3 location, final double dist) - { - double diff = 1.5; - diff = Math.max(diff, this.entity.getWidth()); - if (dist < diff) - { - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - this.berry.setItem(new ItemStack(b.getBlock())); - this.pokemob.eat(this.berry); - if (PokecubeCore.getConfig().pokemobsEatPlants) - { - if (b.getMaterial() != Material.PLANTS) - { - final List list = Block.getDrops(b, this.world, this.foodLoc.getPos(), null); - for (final ItemStack stack : list) - this.toRun.add(new InventoryChange(this.entity, 2, stack, true)); - } - if (b.getMaterial() == Material.ORGANIC) this.world.setBlockState(location.getPos(), Blocks.DIRT - .getDefaultState()); - else this.world.destroyBlock(location.getPos(), false); - } - this.foodLoc = null; - this.addEntityPath(this.entity, null, this.moveSpeed); - } - else - { - boolean shouldChangePath = true; - this.block = false; - this.v.set(this.entity).add(0, this.entity.getHeight(), 0); - if (!this.entity.getNavigator().noPath()) - { - Vector3 pathEnd, destination; - pathEnd = this.v.set(this.entity.getNavigator().getPath().getFinalPathPoint()); - destination = this.v1.set(this.foodLoc); - if (pathEnd.distToSq(destination) < 1) shouldChangePath = false; - } - Path path = null; - if (shouldChangePath) - { - path = this.entity.getNavigator().func_225466_a(this.foodLoc.x, this.foodLoc.y, this.foodLoc.z, 0); - if (path == null) - { - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - this.berry.setItem(new ItemStack(b.getBlock())); - this.pokemob.noEat(this.berry); - this.foodLoc = null; - this.addEntityPath(this.entity, null, this.moveSpeed); - } - else this.addEntityPath(this.entity, path, this.moveSpeed); - } - } - } - - /** - * Eats a rock. - * - * @param b - * the rock - * @param location - * where the rock is - * @param dist - * distance to the rock - */ - protected void eatRocks(final BlockState b, final Vector3 location, final double dist) - { - double diff = 2; - diff = Math.max(diff, this.entity.getWidth()); - if (dist < diff) - { - if (PokecubeCore.getConfig().pokemobsEatRocks) if (b.getBlock() == Blocks.COBBLESTONE) location.setBlock( - this.world, Blocks.GRAVEL.getDefaultState()); - else if (b.getBlock() == Blocks.GRAVEL && PokecubeCore.getConfig().pokemobsEatGravel) location.setBlock( - this.world, Blocks.AIR.getDefaultState()); - else if (b.getMaterial() == Material.ROCK) location.setBlock(this.world, Blocks.COBBLESTONE - .getDefaultState()); - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - this.berry.setItem(new ItemStack(b.getBlock())); - this.pokemob.eat(this.berry); - this.foodLoc = null; - this.addEntityPath(this.entity, null, this.moveSpeed); - } - else if (this.entity.ticksExisted % 20 == this.rand.nextInt(20)) - { - boolean shouldChangePath = true; - this.block = false; - this.v.set(this.entity).add(0, this.entity.getHeight(), 0); - - final Predicate checker = (b2) -> PokecubeTerrainChecker.isRock(b2); - final Vector3 temp = this.v.findClosestVisibleObject(this.world, true, (int) this.distance, checker); - if (temp != null) - { - this.block = true; - this.foodLoc = temp.copy(); - } - - Vector3 p, m; - if (!this.entity.getNavigator().noPath()) - { - p = this.v.set(this.entity.getNavigator().getPath().getFinalPathPoint()); - m = this.v1.set(this.foodLoc); - if (p.distToSq(m) >= 16) shouldChangePath = false; - } - boolean pathed = false; - Path path = null; - if (shouldChangePath) - { - path = this.entity.getNavigator().func_225466_a(this.foodLoc.x, this.foodLoc.y, this.foodLoc.z, 0); - pathed = path != null; - this.addEntityPath(this.entity, path, this.moveSpeed); - } - if (shouldChangePath && !pathed) - { - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - this.berry.setItem(new ItemStack(b.getBlock())); - this.pokemob.noEat(this.berry); - this.foodLoc = null; - if (this.pokemob.hasHomeArea()) - { - path = this.entity.getNavigator().func_225466_a(this.pokemob.getHome().getX(), this.pokemob - .getHome().getY(), this.pokemob.getHome().getZ(), 0); - this.addEntityPath(this.entity, path, this.moveSpeed); - } - else this.addEntityPath(this.entity, null, this.moveSpeed); - } - } - } - - protected void findFood() - { - this.v.set(this.entity).addTo(0, this.entity.getEyeHeight(), 0); - - final boolean tameCheck = this.pokemob.getGeneralState(GeneralStates.TAMED) && !this.pokemob.getGeneralState( - GeneralStates.STAYING); - - /* - * Tame pokemon can eat berries out of trapped chests, so check for one - * of those here. - */ - if (tameCheck) - { - IInventory container = null; - this.v.set(this.entity).add(0, this.entity.getHeight(), 0); - - final Vector3 temp = this.v.findClosestVisibleObject(this.world, true, 10, Blocks.TRAPPED_CHEST); - - if (temp != null && temp.getBlock(this.world) == Blocks.TRAPPED_CHEST) - { - container = (IInventory) temp.getTileEntity(this.world); - - for (int i1 = 0; i1 < container.getSizeInventory(); i1++) - { - final ItemStack stack = container.getStackInSlot(i1); - if (ItemList.is(AIHungry.FOODTAG, stack)) - { - stack.shrink(1); - if (stack.isEmpty()) container.setInventorySlotContents(i1, ItemStack.EMPTY); - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - final Path path = this.entity.getNavigator().func_225466_a(temp.x, temp.y, temp.z, 0); - this.addEntityPath(this.entity, path, this.moveSpeed); - this.pokemob.eat(this.berry); - return; - } - } - } - } - - // No food already obtained, reset mating rules, hungry things don't - // mate - if (this.hitThreshold(AIHungry.MATERESET)) this.pokemob.resetLoveStatus(); - - if (tameCheck && this.pokemob.getLogicState(LogicStates.SITTING)) - { - this.pokemob.setHungerCooldown(100); - // Still let them go hunting if they really want to. - return; - } - this.block = false; - this.v.set(this.entity, true); - - if (this.foodLoc == null) - { - if (!this.block && this.pokemob.isHerbivore()) - { - final Predicate checker = (b2) -> this.isHerb(b2); - final Vector3 temp = this.v.findClosestVisibleObject(this.world, true, (int) this.distance, checker); - if (temp != null) - { - this.block = true; - this.foodLoc = temp.copy(); - } - } - if (!this.block && this.pokemob.isLithotroph()) - { - final Predicate checker = (b2) -> PokecubeTerrainChecker.isRock(b2); - final Vector3 temp = this.v.findClosestVisibleObject(this.world, true, (int) this.distance, checker); - if (temp != null) - { - this.block = true; - this.foodLoc = temp.copy(); - } - } - if (!this.block && this.pokemob.filterFeeder()) - { - final Vector3 temp = this.v.findClosestVisibleObject(this.world, true, (int) this.distance, - Blocks.WATER); - if (this.entity.isInWater()) - { - this.pokemob.eat(this.berry); - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - return; - } - if (temp != null) - { - this.block = true; - this.foodLoc = temp.copy(); - } - } - if (!this.block && this.pokemob.eatsBerries()) if (this.pokemob.getGeneralState(GeneralStates.TAMED)) - { - final Vector3 temp = this.v.findClosestVisibleObject(this.world, true, (int) this.distance, - IBerryFruitBlock.class); - if (temp != null) - { - this.block = true; - this.foodLoc = temp.copy(); - } - } - } - - if (this.foodLoc == null) this.pokemob.setHungerCooldown(10); - } - // 0 is sunrise, 6000 noon, 12000 dusk, 18000 midnight, 23999 public boolean isGoodSleepingSpot(final ChunkCoordinate c) { @@ -629,32 +313,25 @@ public void reset() { } - private boolean isHerb(final BlockState state) - { - return PokecubeTerrainChecker.isFruit(state) || PokecubeTerrainChecker.isEdiblePlant(state); - } - @Override public void run() { - if (this.foodLoc == null) this.findFood(); - else - { - this.rand = new Random(this.pokemob.getRNGValue()); - // Go find and eat the block - final double d = this.foodLoc.addTo(0.5, 0.5, 0.5).distToEntity(this.entity); - this.foodLoc.addTo(-0.5, -0.5, -0.5); - final BlockState b = this.foodLoc.getBlockState(this.world); - if (b == null) - { - this.foodLoc = null; - return; - } - if (b.getBlock() instanceof IBerryFruitBlock) this.eatBerry(b, d); - else if (this.isHerb(b)) this.eatPlant(b, this.foodLoc, d); - else if (PokecubeTerrainChecker.isRock(b) && this.pokemob.isLithotroph()) this.eatRocks(b, this.foodLoc, d); - else this.foodLoc = null; - } + this.v.set(this.entity); + + // Check if we should go after bait. The Math.random() > 0.99 is to + // allow non-hungry fish to also try to get bait. + if (Math.random() > 0.99) this.checkBait(); + + // Do not run this if not really hungry + if (!this.hitThreshold(AIHungry.EATTHRESHOLD)) return; + + // Check if we are hunting or should be + // Reset hunting status if we are not actually hungry + if (this.hitThreshold(AIHungry.HUNTTHRESHOLD)) this.checkHunt(); + + final boolean hunting = this.pokemob.getCombatState(CombatStates.HUNTING); + if (this.pokemob.getLogicState(LogicStates.SLEEPING) && !hunting) if (hunting) this.pokemob.setCombatState( + CombatStates.HUNTING, false); } @Override @@ -664,9 +341,6 @@ public boolean shouldRun() // This can be set in configs to disable. if (hungerTicks < 0) return false; - // Only run this every few ticks. - if (this.entity.ticksExisted % hungerTicks != 0) return false; - // Ensure we are not set to hunt if we shouldn't be if (!this.hitThreshold(AIHungry.EATTHRESHOLD) && this.pokemob.getCombatState(CombatStates.HUNTING)) this.pokemob .setCombatState(CombatStates.HUNTING, false); @@ -689,31 +363,34 @@ public boolean shouldRun() // Do not run this if on cooldown if (this.pokemob.getHungerCooldown() > 0) return false; + // We are already hunting something! + if (BrainUtils.hasHuntTarget(this.entity)) return false; - this.v.set(this.entity); - - // Check if we should go after bait. The Math.random() > 0.99 is to - // allow non-hungry fish to also try to get bait. - if (Math.random() > 0.99) this.checkBait(); - - // Do not run this if not really hungry - if (!this.hitThreshold(AIHungry.EATTHRESHOLD)) return false; - - // Check if we are hunting or should be - // Reset hunting status if we are not actually hungry - if (this.hitThreshold(AIHungry.HUNTTHRESHOLD)) if (!this.pokemob.getCombatState(CombatStates.HUNTING)) - this.pokemob.setCombatState(CombatStates.HUNTING, true); + final List blocks = BrainUtils.getNearBlocks(this.entity); - final boolean hunting = this.pokemob.getCombatState(CombatStates.HUNTING); - if (this.pokemob.getLogicState(LogicStates.SLEEPING) && !hunting) + if (blocks != null) { - if (hunting) this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - return false; + final ServerWorld world = (ServerWorld) this.entity.getEntityWorld(); + final Vec3d start = this.entity.getEyePosition(1); + final Predicate visible = input -> + { + final Vec3d end = new Vec3d(input.getPos()); + final RayTraceContext context = new RayTraceContext(start, end, BlockMode.COLLIDER, FluidMode.NONE, + this.entity); + final RayTraceResult result = world.rayTraceBlocks(context); + if (result.getType() == Type.MISS) return true; + final BlockRayTraceResult hit = (BlockRayTraceResult) result; + return hit.getPos().equals(input.getPos()); + }; + if (this.blocks == null) this.blocks = Lists.newArrayList(blocks); + else + { + this.blocks.clear(); + this.blocks.addAll(blocks); + } + this.blocks.removeIf(b -> !visible.apply(b)); } - // Ensure food location is not too far away. - if (this.foodLoc != null && this.foodLoc.distToEntity(this.entity) > 32) this.foodLoc = null; - // We have a location, so can run. - if (this.foodLoc != null) return true; + // We are hunting for food, so can run. return true; } @@ -726,15 +403,10 @@ private void calculateHunger() @Override public void tick() { - // Configs can set this to -1 to disable ticking. - if (AIHungry.TICKRATE < 0) return; this.v.set(this.entity); final int hungerTicks = AIHungry.TICKRATE; - // Everything after here only applies about once per second. - if (this.entity.ticksExisted % hungerTicks != 0) return; - // Check if we should go to sleep instead. this.checkSleep(); @@ -742,12 +414,16 @@ public void tick() final int cur = this.entity.ticksExisted / hungerTicks; final int tick = rand.nextInt(10); + if (!this.hitThreshold(AIHungry.EATTHRESHOLD)) return; /* * Check the various hunger types if it is hunting. * And if so, refresh the hunger time counter. */ if (this.pokemob.getCombatState(CombatStates.HUNTING)) if (this.checkHunt()) this.calculateHunger(); + // Everything after here only applies about once per second. + if (this.entity.ticksExisted % hungerTicks != 0) return; + // Check own inventory for berries to eat, and then if the mob is // allowed to, collect berries if none to eat. if (this.hitThreshold(AIHungry.EATTHRESHOLD) && !this.checkInventory()) @@ -766,7 +442,7 @@ public void tick() { // Only run this if we are getting close to hurt damage, mostly // to allow trying other food sources first. - if (this.hitThreshold(AIHungry.BERRYGEN)) this.toRun.add(new GenBerries(this.pokemob)); + if (this.hitThreshold(AIHungry.BERRYGEN)) new GenBerries(this.pokemob).run(this.world); } // Otherwise take damage. else if (this.hitThreshold(AIHungry.DAMAGE)) diff --git a/src/main/java/pokecube/core/ai/tasks/idle/AIIdle.java b/src/main/java/pokecube/core/ai/tasks/idle/AIIdle.java index ca1f484cb8..ddc2dff686 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/AIIdle.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/AIIdle.java @@ -2,22 +2,19 @@ import java.util.Map; import java.util.Random; -import java.util.UUID; import com.google.common.collect.Maps; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.entity.ai.attributes.AttributeModifier; -import net.minecraft.entity.ai.attributes.AttributeModifier.Operation; import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; import net.minecraft.entity.ai.brain.memory.MemoryModuleType; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.pathfinding.Path; import net.minecraft.tags.FluidTags; import net.minecraft.world.IBlockReader; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.MemoryModules; +import pokecube.core.ai.tasks.TaskBase; import pokecube.core.database.PokedexEntry; import pokecube.core.interfaces.IMoveConstants.AIRoutine; import pokecube.core.interfaces.IPokemob; @@ -63,12 +60,14 @@ public static Vector3 getRandomPointNear(final IBlockReader world, final IPokemo private static final Map, MemoryModuleStatus> mems = Maps.newHashMap(); static { + // Dont run if have a walk target AIIdle.mems.put(MemoryModules.WALK_TARGET, MemoryModuleStatus.VALUE_ABSENT); + // Don't run if have a target location for moves + AIIdle.mems.put(MemoryModules.MOVE_TARGET, MemoryModuleStatus.VALUE_ABSENT); + // Don't run if we have a path AIIdle.mems.put(MemoryModules.PATH, MemoryModuleStatus.VALUE_ABSENT); } - private AttributeModifier idlePathing = null; - final PokedexEntry entry; private double x; @@ -77,21 +76,14 @@ public static Vector3 getRandomPointNear(final IBlockReader world, final IPokemo private final double speed; - private int ticksSinceLastPathed = 0; - - private double maxLength = 16; - Vector3 v = Vector3.getNewVector(); Vector3 v1 = Vector3.getNewVector(); public AIIdle(final IPokemob pokemob) { super(pokemob, AIIdle.mems); - this.setMutex(2); this.entry = pokemob.getPokedexEntry(); this.speed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); - this.idlePathing = new AttributeModifier(UUID.fromString("4454b0d8-75ef-4689-8fce-daab61a7e1b1"), - "pokecube:idle_path", 0.5, Operation.MULTIPLY_BASE); } /** Floating things try to stay their preferedHeight from the ground. */ @@ -115,14 +107,9 @@ private void doFlyingIdle() GeneralStates.STAYING); final boolean up = Math.random() < 0.9; if (grounded && up && !tamed) this.pokemob.setRoutineState(AIRoutine.AIRBORNE, true); - else if (!tamed) - { - this.pokemob.setRoutineState(AIRoutine.AIRBORNE, false); - this.v.set(this.x, this.y, this.z); - this.v.set(Vector3.getNextSurfacePoint(this.world, this.v, Vector3.secondAxisNeg, this.v.y)); - if (this.v != null) this.y = this.v.y; - } - final PlayerEntity player = this.getNearestPlayer(this.entity, PokecubeCore.getConfig().aiDisableDistance); + else if (!tamed) this.doGroundIdle(); + final PlayerEntity player = this.world.getClosestPlayer(this.entity, PokecubeCore + .getConfig().aiDisableDistance); if (player != null) { final double diff = Math.abs(player.posY - this.y); @@ -163,7 +150,6 @@ private boolean getLocation() final boolean tameFactor = this.pokemob.getGeneralState(GeneralStates.TAMED) && !this.pokemob.getGeneralState( GeneralStates.STAYING); int distance = tameFactor ? PokecubeCore.getConfig().idleMaxPathTame : PokecubeCore.getConfig().idleMaxPathWild; - this.maxLength = distance + this.pokemob.getHomeDistance(); boolean goHome = false; if (!tameFactor) { @@ -202,20 +188,18 @@ private boolean getLocation() this.y = Math.round(v.y); this.z = v.z; } - this.pokemob.setGeneralState(GeneralStates.IDLE, true); return true; } @Override public void reset() { - this.pokemob.setGeneralState(GeneralStates.IDLE, false); } @Override public void run() { - if (!this.pokemob.getGeneralState(GeneralStates.IDLE)) if (!this.getLocation()) return; + if (!this.getLocation()) return; if (this.pokemob.getPokedexEntry().flys()) this.doFlyingIdle(); else if (this.pokemob.getPokedexEntry().floats()) this.doFloatingIdle(); else if (this.entry.swims() && this.entity.isInWater()) this.doWaterIdle(); @@ -223,16 +207,8 @@ public void run() else this.doGroundIdle(); this.v1.set(this.entity); this.v.set(this.x, this.y, this.z); - - this.pokemob.setGeneralState(GeneralStates.IDLE, false); if (this.v1.distToSq(this.v) <= 1) return; - - this.entity.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).removeModifier(this.idlePathing); - this.entity.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).applyModifier(this.idlePathing); - Path path = this.entity.getNavigator().func_225466_a(this.x, this.y, this.z, 0); - this.entity.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).removeModifier(this.idlePathing); - if (path != null && path.getCurrentPathLength() > this.maxLength) path = null; - this.addEntityPath(this.entity, path, this.speed); + this.setWalkTo(this.v, this.speed, 0); } @Override @@ -242,7 +218,7 @@ public boolean shouldRun() if (AIIdle.IDLETIMER <= 0) return false; // Not currently able to move. - if (!this.canMove()) return false; + if (!TaskBase.canMove(this.pokemob)) return false; // Check a random number as well if (this.entity.getRNG().nextInt(AIIdle.IDLETIMER) != 0) return false; @@ -256,24 +232,13 @@ public boolean shouldRun() // Angry at something if (this.pokemob.getCombatState(CombatStates.ANGRY)) return false; - // Trying to use a move. - if (this.pokemob.getCombatState(CombatStates.EXECUTINGMOVE)) return false; - // Pathing somewhere. if (this.pokemob.getLogicState(LogicStates.PATHING)) return false; // Owner is controlling us. if (this.pokemob.getGeneralState(GeneralStates.CONTROLLED)) return false; - // Sitting - if (this.pokemob.getLogicState(LogicStates.SITTING)) return false; - - Path current = this.entity.getNavigator().getPath(); - if (current != null && this.entity.getNavigator().noPath()) current = null; - // Have path, no need to idle - if (current != null) this.ticksSinceLastPathed = 0; - - return this.ticksSinceLastPathed++ > AIIdle.IDLETIMER; + return !this.entity.getBrain().hasMemory(MemoryModules.WALK_TARGET); } } \ No newline at end of file diff --git a/src/main/java/pokecube/core/ai/tasks/idle/AIMate.java b/src/main/java/pokecube/core/ai/tasks/idle/AIMate.java index 107aff7353..4305def6b6 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/AIMate.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/AIMate.java @@ -1,26 +1,25 @@ package pokecube.core.ai.tasks.idle; -import java.util.Arrays; import java.util.List; +import java.util.Map; -import net.minecraft.entity.Entity; -import net.minecraft.entity.passive.AnimalEntity; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.world.World; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import net.minecraft.entity.AgeableEntity; +import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.entity.ai.brain.memory.WalkTarget; +import net.minecraft.util.math.EntityPosWrapper; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.brain.MemoryModules; import pokecube.core.ai.tasks.combat.AIFindTarget; import pokecube.core.interfaces.IMoveConstants.AIRoutine; -import pokecube.core.interfaces.IMoveNames; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.capabilities.CapabilityPokemob; -import pokecube.core.interfaces.pokemob.IHasMobAIStates; import pokecube.core.interfaces.pokemob.ai.CombatStates; import pokecube.core.interfaces.pokemob.ai.GeneralStates; -import pokecube.core.interfaces.pokemob.ai.LogicStates; -import pokecube.core.utils.PokeType; -import thut.api.entity.IBreedingMob; -import thut.api.maths.Vector3; /** * This IAIRunnable is responsible for most of the breeding AI for the @@ -29,157 +28,61 @@ */ public class AIMate extends IdleTask { - public static int PATHCOOLDOWN = 5; - - int cooldown = 0; - int spawnBabyDelay = 0; - int pathDelay = 0; - - public AIMate(final IPokemob mob) + private static final Map, MemoryModuleStatus> mems = Maps.newHashMap(); + static { - super(mob); + // only run this if we have mate targets. + AIMate.mems.put(MemoryModules.POSSIBLE_MATES, MemoryModuleStatus.VALUE_PRESENT); } - public boolean findLover() - { - if (!this.pokemob.isRoutineEnabled(AIRoutine.MATE)) return false; - if (this.pokemob.getLover() != null) return true; - boolean transforms = false; - for (final String s : this.pokemob.getMoves()) - if (s != null && s.equalsIgnoreCase(IMoveNames.MOVE_TRANSFORM)) transforms = true; - if (!this.pokemob.getPokedexEntry().breeds && !transforms) return false; - if (this.pokemob.isType(PokeType.getType("ghost")) && !this.pokemob.getGeneralState(GeneralStates.TAMED)) - return false; - if (this.pokemob.getSexe() == IPokemob.MALE && !transforms || this.pokemob.getMalesForBreeding().size() > 0) - return false; - - final float searchingLoveDist = 5F; - AxisAlignedBB bb = this.makeBox(searchingLoveDist, searchingLoveDist, searchingLoveDist, this.entity - .getBoundingBox()); - final List targetMates = this.entity.getEntityWorld().getEntitiesInAABBexcluding(this.entity, bb, - input -> - { - final World world = input.getEntityWorld(); - input = PokecubeCore.getEntityProvider().getEntity(world, input.getEntityId(), true); - return input instanceof AnimalEntity && AIMate.this.pokemob.canMate((AnimalEntity) input); - }); - bb = this.makeBox(PokecubeCore.getConfig().maxSpawnRadius, searchingLoveDist, PokecubeCore - .getConfig().maxSpawnRadius, this.entity.getBoundingBox()); - final List otherMobs = this.entity.getEntityWorld().getEntitiesInAABBexcluding(this.entity, bb, - input -> input instanceof AnimalEntity && CapabilityPokemob.getPokemobFor(input) != null); - final float multiplier = (float) (this.pokemob.isPlayerOwned() ? PokecubeCore.getConfig().mateDensityPlayer - : PokecubeCore.getConfig().mateDensityWild); - if (otherMobs.size() >= PokecubeCore.getConfig().mobSpawnNumber * multiplier) - { - this.pokemob.resetLoveStatus(); - return false; - } - final boolean gendered = this.pokemob.getSexe() == IPokemob.MALE || this.pokemob.getSexe() == IPokemob.FEMALE; - for (final Entity targetMate : targetMates) - { - Entity mob = targetMate; - if (!(mob instanceof AnimalEntity)) mob = PokecubeCore.getEntityProvider().getEntity(mob.getEntityWorld(), - mob.getEntityId(), true); - final IPokemob otherPokemob = CapabilityPokemob.getPokemobFor(mob); - final AnimalEntity animal = (AnimalEntity) mob; - if (gendered && !transforms && otherPokemob.getSexe() == this.pokemob.getSexe()) continue; - if (!otherPokemob.isRoutineEnabled(AIRoutine.MATE)) continue; - if (otherPokemob == this.pokemob || otherPokemob.getGeneralState(GeneralStates.TAMED) != this.pokemob - .getGeneralState(GeneralStates.TAMED) || !otherPokemob.getPokedexEntry().breeds) continue; - boolean otherTransforms = false; - for (final String s : otherPokemob.getMoves()) - if (s != null && s.equalsIgnoreCase(IMoveNames.MOVE_TRANSFORM)) otherTransforms = true; - - if (transforms && otherTransforms || !(otherPokemob.getEntity() instanceof AnimalEntity)) continue; - - final boolean validMate = this.pokemob.canMate((AnimalEntity) otherPokemob.getEntity()); - if (!validMate || this.entity.getDistanceSq(otherPokemob.getEntity()) > searchingLoveDist - * searchingLoveDist) continue; - if (!Vector3.isVisibleEntityFromEntity(this.entity, otherPokemob.getEntity()) || otherPokemob - .getCombatState(CombatStates.ANGRY)) continue; - - if (otherPokemob != this && animal.getHealth() > animal.getMaxHealth() / 1.5f) if (!this.pokemob - .getMalesForBreeding().contains(otherPokemob)) - { - otherPokemob.setLover(this.entity); - if (transforms) this.pokemob.setLover(animal); - this.pokemob.getMalesForBreeding().add(otherPokemob); - otherPokemob.setLoveTimer(200); - } - } - return !this.pokemob.getMalesForBreeding().isEmpty(); - } - - public void initiateMateFight() - { - if (this.pokemob.getSexe() == IPokemob.MALE && this.pokemob.getLover() != null) - { - Entity emob = this.pokemob.getLover(); - if (emob != null) emob = PokecubeCore.getEntityProvider().getEntity(emob.getEntityWorld(), emob - .getEntityId(), true); - final IPokemob loverMob = CapabilityPokemob.getPokemobFor(emob); - this.entity.getLookController().setLookPositionWithEntity(emob, 10.0F, this.entity.getVerticalFaceSpeed()); - if (loverMob.getMalesForBreeding().size() > 1) - { - final IPokemob[] males = loverMob.getMalesForBreeding().toArray(new IPokemob[0]); - Arrays.sort(males, (o1, o2) -> - { - if (o2.getLevel() == o1.getLevel()) return o1.getDisplayName().getFormattedText().compareTo(o2 - .getDisplayName().getFormattedText()); - return o2.getLevel() - o1.getLevel(); - }); - final int level = males[0].getLevel(); - int n = 0; - for (final IPokemob mob : males) - if (mob.getLevel() < level || mob.getHealth() < mob.getMaxHealth() / 1.5f) - { - loverMob.getMalesForBreeding().remove(mob); - mob.resetLoveStatus(); - n++; - } - if (n == 0 && loverMob.getMalesForBreeding().size() > 1) - { + int spawnBabyDelay = 0; - final IPokemob mob0 = (IPokemob) loverMob.getMalesForBreeding().get(0); - final IPokemob mob1 = (IPokemob) loverMob.getMalesForBreeding().get(1); - mob0.resetLoveStatus(); - mob1.resetLoveStatus(); - mob0.setCombatState(CombatStates.MATEFIGHT, true); - mob1.setCombatState(CombatStates.MATEFIGHT, true); - AIFindTarget.initiateCombat(mob0.getEntity(), mob1.getEntity()); - } - } + List mates = Lists.newArrayList(); - if (loverMob.getMalesForBreeding().size() > 1) return; - else if (loverMob.getMalesForBreeding().size() == 0) - { - loverMob.resetLoveStatus(); - this.pokemob.resetLoveStatus(); - } - } - else if (this.pokemob.getMalesForBreeding().size() == 1) - { - final IBreedingMob loverMob = this.pokemob.getMalesForBreeding().get(0); - this.pokemob.setLover(loverMob.getLover()); - loverMob.setLover(this.entity); - } - } + AgeableEntity mate; - private AxisAlignedBB makeBox(final double dx, final double dy, final double dz, final AxisAlignedBB centre) + public AIMate(final IPokemob mob) { - return centre.grow(dx, dy, dz); + super(mob, AIMate.mems); } @Override public void reset() { - if (this.cooldown > 0) return; - this.cooldown = 20; + this.spawnBabyDelay = 0; + this.mate = null; + this.pokemob.setGeneralState(GeneralStates.MATING, false); + BrainUtils.setMateTarget((AgeableEntity) this.entity, null); } @Override public void run() { + // already have a mate, lets return early from this + if (this.mate != null) return; + // No options, return. + if (this.mates == null || this.mates.isEmpty()) return; + + // Only one mate, we can choose it + if (this.mates.size() == 1) + { + this.mate = this.mates.get(0); + return; + } + + // Battle between the first two on the list. + final AgeableEntity mobA = this.mates.get(0); + final AgeableEntity mobB = this.mates.get(1); + + final IPokemob pokeA = CapabilityPokemob.getPokemobFor(mobA); + final IPokemob pokeB = CapabilityPokemob.getPokemobFor(mobB); + + if (pokeA != null) pokeA.setCombatState(CombatStates.MATEFIGHT, true); + if (pokeB != null) pokeB.setCombatState(CombatStates.MATEFIGHT, true); + + // This fight should end when one gets below half health, which would + // then be invalid for the next selection round of mating targets. + AIFindTarget.initiateCombat(mobA, mobB); } @Override @@ -188,89 +91,39 @@ public boolean shouldRun() if (!this.pokemob.getPokedexEntry().breeds) return false; if (this.pokemob.getPokedexEntry().isLegendary() && !PokecubeCore.getConfig().legendsBreed) return false; if (!this.pokemob.isRoutineEnabled(AIRoutine.MATE)) return false; - if (--this.cooldown > 0) return false; - if (this.pokemob.getLover() != null) if (this.pokemob.tryToBreed() && this.pokemob.getLover().isAlive()) - return true; - if (this.pokemob.getGeneralState(GeneralStates.MATING)) return true; - if (this.pokemob.getLover() != null) return true; - if (this.pokemob.getSexe() == IPokemob.MALE || !this.pokemob.tryToBreed()) return false; + if (this.pokemob.getSexe() == IPokemob.MALE || !this.pokemob.canBreed()) return false; if (this.pokemob.getCombatState(CombatStates.ANGRY) || BrainUtils.hasAttackTarget(this.entity)) return false; - return true; + this.mate = BrainUtils.getMateTarget((AgeableEntity) this.entity); + if (this.mate != null) return true; + this.mates = BrainUtils.getMates((AgeableEntity) this.entity); + if (this.mates != null) + { + int mateNum = PokecubeCore.getConfig().mobSpawnNumber; + mateNum *= this.pokemob.isPlayerOwned() ? PokecubeCore.getConfig().mateDensityPlayer + : PokecubeCore.getConfig().mateDensityWild; + this.mates.removeIf(e -> !e.isAlive()); + if (this.mates.size() > mateNum) return false; + } + return this.mates != null; } @Override public void tick() { - Entity mob = this.pokemob.getLover(); - if (mob != null) mob = PokecubeCore.getEntityProvider().getEntity(mob.getEntityWorld(), mob.getEntityId(), - true); - final IPokemob loverMob = CapabilityPokemob.getPokemobFor(mob); - if (this.pokemob.getGeneralState(GeneralStates.MATING) && (mob == null || !mob.isAlive() - || loverMob != this.pokemob)) this.pokemob.setGeneralState(GeneralStates.MATING, false); - if (this.cooldown-- > 0) return; + // No chosen mate, return early + if (this.mate == null) return; - if (this.pokemob.getLoveTimer() > 0 && mob == null) this.findLover(); - if (this.pokemob.getLover() == null && this.pokemob.getMalesForBreeding().isEmpty()) - { - this.cooldown = PokecubeCore.getConfig().mateAIRate; - return; - } - boolean transforms = false; - for (final String s : this.pokemob.getMoves()) - if (s != null && s.equalsIgnoreCase(IMoveNames.MOVE_TRANSFORM)) transforms = true; - mob = this.pokemob.getLover(); - if (mob != null) mob = PokecubeCore.getEntityProvider().getEntity(mob.getEntityWorld(), mob.getEntityId(), - true); - if (transforms && mob != null) this.pokemob.setTransformedTo(mob); - if ((mob != null || !this.pokemob.getMalesForBreeding().isEmpty()) && (transforms || this.pokemob - .getSexe() != IPokemob.MALE)) - { - if (this.pokemob.getMalesForBreeding().size() == 1 && mob == null && this.pokemob.getMalesForBreeding().get( - 0) instanceof IPokemob) this.pokemob.setLover(((IPokemob) this.pokemob.getMalesForBreeding().get(0)) - .getEntity()); - if (this.pokemob.getMalesForBreeding().size() <= 1) this.tryFindMate(); - else this.initiateMateFight(); - } - if (!this.pokemob.tryToBreed()) this.cooldown = PokecubeCore.getConfig().mateAIRate; - } - - public void tryFindMate() - { - Entity emob = this.pokemob.getLover(); - if (emob != null) emob = PokecubeCore.getEntityProvider().getEntity(emob.getEntityWorld(), emob.getEntityId(), - true); - if (emob == null) return; - if (!this.pokemob.isRoutineEnabled(AIRoutine.MATE)) - { - this.pokemob.resetLoveStatus(); - return; - } - if (this.pokemob.getLogicState(LogicStates.SITTING)) this.pokemob.setLogicState(LogicStates.SITTING, false); + // Make them walk to each other + this.setWalkTo(this.mate, this.pokemob.getMovementSpeed(), 0); + this.mate.getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(new EntityPosWrapper(this.entity), + (float) this.pokemob.getMovementSpeed(), 0)); - double dist = this.entity.getWidth() * this.entity.getWidth() + emob.getWidth() * emob.getWidth(); - dist = Math.max(dist, 1); - if (this.pathDelay-- < 0) - { - this.pathDelay = AIMate.PATHCOOLDOWN; - this.entity.getNavigator().tryMoveToEntityLiving(emob, this.pokemob.getMovementSpeed()); - } - this.spawnBabyDelay++; this.pokemob.setGeneralState(GeneralStates.MATING, true); - final IPokemob loverMob = CapabilityPokemob.getPokemobFor(emob); - if (loverMob != null) - { - loverMob.setGeneralState(GeneralStates.MATING, true); - loverMob.setLover(this.entity); - if (this.spawnBabyDelay >= 50) - { - if (emob instanceof IHasMobAIStates) ((IHasMobAIStates) emob).setGeneralState(GeneralStates.MATING, - false); - this.pokemob.mateWith(loverMob); - this.pokemob.setGeneralState(GeneralStates.MATING, false); - this.spawnBabyDelay = 0; - this.pokemob.resetLoveStatus(); - loverMob.resetLoveStatus(); - } - } + if (this.spawnBabyDelay++ < 50) return; + final IPokemob other = CapabilityPokemob.getPokemobFor(this.mate); + if (other != null) this.pokemob.mateWith(other); + this.reset(); + other.resetLoveStatus(); + this.pokemob.resetLoveStatus(); } } diff --git a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatBlockBase.java b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatBlockBase.java new file mode 100644 index 0000000000..a05007be9a --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatBlockBase.java @@ -0,0 +1,27 @@ +package pokecube.core.ai.tasks.idle.hunger; + +import net.minecraft.entity.MobEntity; +import net.minecraft.entity.ai.brain.memory.WalkTarget; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import pokecube.core.ai.brain.MemoryModules; +import thut.api.maths.Vector3; + +public abstract class EatBlockBase implements IBlockEatTask +{ + protected void setWalkTo(final MobEntity entity, final Vector3 pos, final double speed, final int dist) + { + this.setWalkTo(entity, pos.toVec3d(), speed, dist); + } + + protected void setWalkTo(final MobEntity entity, final Vec3d pos, final double speed, final int dist) + { + entity.getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(pos, (float) speed, dist)); + } + + protected void setWalkTo(final MobEntity entity, final BlockPos pos, final double speed, final int dist) + { + entity.getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(pos, (float) speed, dist)); + } + +} diff --git a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatFromChest.java b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatFromChest.java new file mode 100644 index 0000000000..a77c116ba8 --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatFromChest.java @@ -0,0 +1,63 @@ +package pokecube.core.ai.tasks.idle.hunger; + +import java.util.function.Predicate; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.MobEntity; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.world.server.ServerWorld; +import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; +import pokecube.core.ai.tasks.idle.AIHungry; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.pokemob.ai.CombatStates; +import thut.api.item.ItemList; + +public class EatFromChest extends EatBlockBase +{ + private static boolean isTrappedChest(final BlockState state) + { + return state.getBlock() == Blocks.TRAPPED_CHEST; + } + + private static final Predicate checker = (b2) -> EatFromChest.isTrappedChest(b2); + + @Override + public EatResult eat(final IPokemob pokemob, final NearBlock block) + { + if (!pokemob.isHerbivore()) return EatResult.NOEAT; + + final MobEntity entity = pokemob.getEntity(); + + double diff = 1.5; + diff = Math.max(diff, entity.getWidth()); + final double dist = block.getPos().manhattanDistance(entity.getPosition()); + this.setWalkTo(entity, block.getPos(), pokemob.getMovementSpeed(), 0); + if (dist > diff) return EatResult.PATHING; + final ServerWorld world = (ServerWorld) entity.getEntityWorld(); + final BlockState current = world.getBlockState(block.getPos()); + if (!EatFromChest.checker.test(current)) return EatResult.NOEAT; + final IInventory container = (IInventory) world.getTileEntity(block.getPos()); + for (int i1 = 0; i1 < container.getSizeInventory(); i1++) + { + final ItemStack stack = container.getStackInSlot(i1); + if (ItemList.is(AIHungry.FOODTAG, stack)) + { + pokemob.setCombatState(CombatStates.HUNTING, false); + pokemob.eat(stack); + stack.shrink(1); + if (stack.isEmpty()) container.setInventorySlotContents(i1, ItemStack.EMPTY); + return EatResult.EATEN; + } + } + return EatResult.NOEAT; + } + + @Override + public boolean isValid(final NearBlock block) + { + return EatFromChest.checker.test(block.getState()); + } + +} diff --git a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatPlant.java b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatPlant.java new file mode 100644 index 0000000000..629f48261a --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatPlant.java @@ -0,0 +1,67 @@ +package pokecube.core.ai.tasks.idle.hunger; + +import java.util.List; +import java.util.function.Predicate; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.entity.MobEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.world.server.ServerWorld; +import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; +import pokecube.core.ai.tasks.TaskBase.InventoryChange; +import pokecube.core.ai.tasks.utility.AIGatherStuff.ReplantTask; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.world.terrain.PokecubeTerrainChecker; + +public class EatPlant extends EatBlockBase +{ + private static boolean isHerb(final BlockState state) + { + return PokecubeTerrainChecker.isFruit(state) || PokecubeTerrainChecker.isEdiblePlant(state); + } + + private static final Predicate checker = (b2) -> EatPlant.isHerb(b2); + + @Override + public EatResult eat(final IPokemob pokemob, final NearBlock block) + { + if (!pokemob.isHerbivore()) return EatResult.NOEAT; + + final MobEntity entity = pokemob.getEntity(); + + double diff = 1.5; + diff = Math.max(diff, entity.getWidth()); + final double dist = block.getPos().manhattanDistance(entity.getPosition()); + this.setWalkTo(entity, block.getPos(), pokemob.getMovementSpeed(), 0); + if (dist > diff) return EatResult.PATHING; + + final ServerWorld world = (ServerWorld) entity.getEntityWorld(); + final BlockState current = world.getBlockState(block.getPos()); + if (!EatPlant.checker.test(current)) return EatResult.NOEAT; + + final List list = Block.getDrops(current, world, block.getPos(), null); + if (list.isEmpty()) return EatResult.NOEAT; + final ItemStack first = list.get(0); + pokemob.eat(first); + first.grow(-1); + if (first.isEmpty()) list.remove(0); + boolean replanted = false; + // See if anything dropped was a seed for the thing we + // picked. + for (final ItemStack stack : list) + { + // If so, Replant it. + if (!replanted) replanted = new ReplantTask(stack, current, block.getPos(), true).run(world); + new InventoryChange(entity, 2, stack, true).run(world); + } + return EatResult.EATEN; + } + + @Override + public boolean isValid(final NearBlock block) + { + return EatPlant.checker.test(block.getState()); + } + +} diff --git a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatRedstone.java b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatRedstone.java new file mode 100644 index 0000000000..29008ba7f7 --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatRedstone.java @@ -0,0 +1,47 @@ +package pokecube.core.ai.tasks.idle.hunger; + +import java.util.function.Predicate; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.MobEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.server.ServerWorld; +import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; +import pokecube.core.interfaces.IPokemob; +import thut.api.item.ItemList; + +public class EatRedstone extends EatBlockBase +{ + public static final ResourceLocation FOODTAG = new ResourceLocation(PokecubeCore.MODID, "pokemob_redstone_food"); + + private static final Predicate checker = (b2) -> ItemList.is(EatRedstone.FOODTAG, b2); + + @Override + public EatResult eat(final IPokemob pokemob, final NearBlock block) + { + if (!pokemob.isElectrotroph()) return EatResult.NOEAT; + + final MobEntity entity = pokemob.getEntity(); + double diff = 1.5; + diff = Math.max(diff, entity.getWidth()); + final double dist = block.getPos().manhattanDistance(entity.getPosition()); + this.setWalkTo(entity, block.getPos(), pokemob.getMovementSpeed(), 0); + if (dist > diff) return EatResult.PATHING; + + final ServerWorld world = (ServerWorld) entity.getEntityWorld(); + final BlockState current = world.getBlockState(block.getPos()); + if (!EatRedstone.checker.test(current)) return EatResult.NOEAT; + + pokemob.setHungerTime(pokemob.getHungerTime() - PokecubeCore.getConfig().pokemobLifeSpan / 4); + + return EatResult.EATEN; + } + + @Override + public boolean isValid(final NearBlock block) + { + return EatRedstone.checker.test(block.getState()); + } + +} \ No newline at end of file diff --git a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatResult.java b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatResult.java new file mode 100644 index 0000000000..d5772361cf --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatResult.java @@ -0,0 +1,11 @@ +package pokecube.core.ai.tasks.idle.hunger; + +public enum EatResult +{ + EATEN, PATHING, NOEAT; + + public boolean test() + { + return this != NOEAT; + } +} diff --git a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatRock.java b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatRock.java new file mode 100644 index 0000000000..0761612247 --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatRock.java @@ -0,0 +1,68 @@ +package pokecube.core.ai.tasks.idle.hunger; + +import java.util.List; +import java.util.function.Predicate; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.MobEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.server.ServerWorld; +import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; +import pokecube.core.ai.tasks.TaskBase.InventoryChange; +import pokecube.core.ai.tasks.utility.AIGatherStuff.ReplantTask; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.world.terrain.PokecubeTerrainChecker; +import thut.api.item.ItemList; + +public class EatRock extends EatBlockBase +{ + private static final ResourceLocation ORE = new ResourceLocation("forge", "ores"); + + private static final Predicate checker = (b2) -> PokecubeTerrainChecker.isRock(b2); + + @Override + public EatResult eat(final IPokemob pokemob, final NearBlock block) + { + if (!pokemob.isLithotroph()) return EatResult.NOEAT; + + final MobEntity entity = pokemob.getEntity(); + double diff = 1.5; + diff = Math.max(diff, entity.getWidth()); + final double dist = block.getPos().manhattanDistance(entity.getPosition()); + this.setWalkTo(entity, block.getPos(), pokemob.getMovementSpeed(), 0); + if (dist > diff) return EatResult.PATHING; + + final ServerWorld world = (ServerWorld) entity.getEntityWorld(); + final BlockState current = world.getBlockState(block.getPos()); + if (!EatRock.checker.test(current)) return EatResult.NOEAT; + + final List list = Block.getDrops(current, world, block.getPos(), null); + if (list.isEmpty()) return EatResult.NOEAT; + final ItemStack first = list.get(0); + final boolean isOre = ItemList.is(EatRock.ORE, first); + pokemob.eat(first); + first.grow(-1); + if (first.isEmpty()) list.remove(0); + if (isOre) list.add(0, new ItemStack(Blocks.COBBLESTONE)); + boolean replanted = false; + // See if anything dropped was a seed for the thing we + // picked. + for (final ItemStack stack : list) + { + // If so, Replant it. + if (!replanted) replanted = new ReplantTask(stack, current, block.getPos(), true).run(world); + new InventoryChange(entity, 2, stack, true).run(world); + } + return EatResult.EATEN; + } + + @Override + public boolean isValid(final NearBlock block) + { + return EatRock.checker.test(block.getState()); + } + +} \ No newline at end of file diff --git a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatWater.java b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatWater.java new file mode 100644 index 0000000000..f57aff2495 --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatWater.java @@ -0,0 +1,48 @@ +package pokecube.core.ai.tasks.idle.hunger; + +import java.util.function.Predicate; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.MobEntity; +import net.minecraft.fluid.WaterFluid; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.server.ServerWorld; +import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; +import pokecube.core.interfaces.IPokemob; +import thut.api.item.ItemList; + +public class EatWater extends EatBlockBase +{ + public static final ResourceLocation FOODTAG = new ResourceLocation(PokecubeCore.MODID, "pokemob_redstone_food"); + + private static final Predicate checker = (b2) -> ItemList.is(EatWater.FOODTAG, b2); + + @Override + public EatResult eat(final IPokemob pokemob, final NearBlock block) + { + if (!pokemob.filterFeeder()) return EatResult.NOEAT; + + final MobEntity entity = pokemob.getEntity(); + double diff = 1.5; + diff = Math.max(diff, entity.getWidth()); + final double dist = block.getPos().manhattanDistance(entity.getPosition()); + this.setWalkTo(entity, block.getPos(), pokemob.getMovementSpeed(), 0); + if (dist > diff) return EatResult.PATHING; + + final ServerWorld world = (ServerWorld) entity.getEntityWorld(); + final BlockState current = world.getBlockState(block.getPos()); + if (!EatWater.checker.test(current)) return EatResult.NOEAT; + + pokemob.setHungerTime(pokemob.getHungerTime() - PokecubeCore.getConfig().pokemobLifeSpan / 4); + + return EatResult.EATEN; + } + + @Override + public boolean isValid(final NearBlock block) + { + return block.getState().getFluidState().getFluid() instanceof WaterFluid; + } + +} \ No newline at end of file diff --git a/src/main/java/pokecube/core/ai/tasks/idle/hunger/IBlockEatTask.java b/src/main/java/pokecube/core/ai/tasks/idle/hunger/IBlockEatTask.java new file mode 100644 index 0000000000..484dcce9f9 --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/IBlockEatTask.java @@ -0,0 +1,25 @@ +package pokecube.core.ai.tasks.idle.hunger; + +import java.util.List; + +import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; +import pokecube.core.interfaces.IPokemob; + +public interface IBlockEatTask +{ + default EatResult tryEat(final IPokemob pokemob, final List blocks) + { + if (blocks != null) for (final NearBlock b : blocks) + if (this.isValid(b)) + { + final EatResult result = this.eat(pokemob, b); + if (result == EatResult.NOEAT) continue; + else return result; + } + return EatResult.NOEAT; + } + + EatResult eat(IPokemob pokemob, NearBlock block); + + boolean isValid(NearBlock block); +} diff --git a/src/main/java/pokecube/core/ai/tasks/utility/AIGatherStuff.java b/src/main/java/pokecube/core/ai/tasks/utility/AIGatherStuff.java index 9ba445f371..dc0d84e147 100644 --- a/src/main/java/pokecube/core/ai/tasks/utility/AIGatherStuff.java +++ b/src/main/java/pokecube/core/ai/tasks/utility/AIGatherStuff.java @@ -1,8 +1,6 @@ package pokecube.core.ai.tasks.utility; -import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Random; import com.google.common.base.Predicate; @@ -11,16 +9,12 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.CropsBlock; -import net.minecraft.entity.Entity; -import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; -import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.IInventory; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; -import net.minecraft.pathfinding.Path; import net.minecraft.state.IProperty; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; @@ -28,15 +22,22 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.RayTraceContext.BlockMode; +import net.minecraft.util.math.RayTraceContext.FluidMode; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.IPlantable; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; +import pokecube.core.ai.tasks.IRunnable; import pokecube.core.interfaces.IMoveConstants.AIRoutine; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.PokecubeMod; -import pokecube.core.interfaces.pokemob.ai.CombatStates; import pokecube.core.interfaces.pokemob.ai.GeneralStates; import pokecube.core.interfaces.pokemob.ai.LogicStates; import thut.api.item.ItemList; @@ -55,17 +56,25 @@ public class AIGatherStuff extends UtilTask * * @author Patrick */ - private static class ReplantTask implements IRunnable + public static class ReplantTask implements IRunnable { final ItemStack seeds; final BlockPos pos; final BlockState oldState; + final boolean selfPlacement; + public ReplantTask(final ItemStack seeds, final BlockState old, final BlockPos pos) + { + this(seeds, old, pos, false); + } + + public ReplantTask(final ItemStack seeds, final BlockState old, final BlockPos pos, final boolean selfPlacment) { this.seeds = seeds; this.pos = new BlockPos(pos); this.oldState = old; + this.selfPlacement = selfPlacment; } @Override @@ -80,7 +89,7 @@ public boolean run(final World world) final ItemUseContext context = new ItemUseContext(player, Hand.MAIN_HAND, new BlockRayTraceResult(new Vec3d( 0.5, 1, 0.5), Direction.UP, down, false)); check: - if (this.seeds.getItem() instanceof BlockItem) + if (this.seeds.getItem() instanceof BlockItem && !this.selfPlacement) { final Block block = Block.getBlockFromItem(this.seeds.getItem()); if (block != this.oldState.getBlock()) break check; @@ -138,12 +147,13 @@ public boolean run(final World world) || !input.isAddedToWorld(); final double distance; - boolean block = false; - List stuff = Lists.newArrayList(); - Vector3 stuffLoc = Vector3.getNewVector(); + List blocks = null; + List items = null; + + ItemEntity targetItem = null; + NearBlock targetBlock = null; - Vector3 backup = this.stuffLoc; boolean hasRoom = true; int collectCooldown = 0; @@ -152,34 +162,23 @@ public boolean run(final World world) final AIStoreStuff storage; Vector3 seeking = Vector3.getNewVector(); - Vector3 v = Vector3.getNewVector(); - Vector3 v1 = Vector3.getNewVector(); + + Vector3 v = Vector3.getNewVector(); + Vector3 v1 = Vector3.getNewVector(); public AIGatherStuff(final IPokemob mob, final double distance, final AIStoreStuff storage) { super(mob); this.distance = distance; this.storage = storage; - this.setMutex(1); - this.clearLoc(); } - @Override - public Map, MemoryModuleStatus> getNeededMemories() + private boolean hasStuff() { - return super.getNeededMemories(); - } - - private void setLoc(final Object o) - { - this.stuffLoc = this.backup; - this.stuffLoc.set(o); - } - - private void clearLoc() - { - this.stuffLoc = null; - this.block = false; + if (this.targetItem != null && AIGatherStuff.deaditemmatcher.apply(this.targetItem)) this.targetItem = null; + if (this.targetBlock != null && !AIGatherStuff.harvestMatcher.apply(this.entity.getEntityWorld().getBlockState( + this.targetBlock.getPos()))) this.targetBlock = null; + return this.targetItem != null || this.targetBlock != null; } private void findStuff() @@ -188,110 +187,75 @@ private void findStuff() if (this.pokemob.getHome() == null || this.pokemob.getGeneralState(GeneralStates.TAMED) && this.pokemob .getLogicState(LogicStates.SITTING)) return; // This means we have stuff - if (this.stuffLoc != null) return; - this.block = false; - this.v.set(this.pokemob.getHome()).add(0, this.entity.getHeight(), 0); - - final int distance = this.pokemob.getGeneralState(GeneralStates.TAMED) ? PokecubeCore - .getConfig().tameGatherDistance : PokecubeCore.getConfig().wildGatherDistance; - - final List list = this.getEntitiesWithinDistance(this.entity, distance, ItemEntity.class); + if (this.hasStuff()) return; - // Only allow y difference of 5 for collection of items. - list.removeIf(e -> Math.abs(e.posY - this.entity.posY) > 5); - - this.stuff.clear(); - double closest = 1000; - - // Check for items to possibly gather. - for (final Entity o : list) + if (this.items != null) { - final ItemEntity e = (ItemEntity) o; - final double dist = e.getPosition().distanceSq(this.pokemob.getHome()); - this.v.set(e); - if (dist < closest && Vector3.isVisibleEntityFromEntity(this.entity, e)) - { - this.stuff.add(e); - closest = dist; - } + // Check for items to possibly gather. + for (final ItemEntity e : this.items) + if (!AIGatherStuff.deaditemmatcher.apply(e)) + { + this.targetItem = e; + return; + } + if (this.targetItem != null) return; } - // Found an item, return. - if (!this.stuff.isEmpty()) + if (this.blocks != null && this.blocks.size() > 0) { - Collections.sort(this.stuff, (o1, o2) -> - { - final int dist1 = (int) o1.getDistanceSq(AIGatherStuff.this.entity); - final int dist2 = (int) o2.getDistanceSq(AIGatherStuff.this.entity); - return dist1 - dist2; - }); - this.setLoc(this.stuff.get(0)); + this.targetBlock = this.blocks.get(0); return; - } - this.v.set(this.entity).addTo(0, this.entity.getEyeHeight(), 0); - // check for berries to collect. - if (!this.block) - { - final Vector3 temp = this.v.findClosestVisibleObject(this.world, true, distance, - AIGatherStuff.harvestMatcher); - if (temp != null) - { - this.block = true; - this.setLoc(temp); - } - } - if (this.pokemob.isElectrotroph()) - { - } // Nothing found, enter cooldown. - if (this.stuffLoc == null) this.collectCooldown = AIGatherStuff.COOLDOWN_SEARCH; + this.collectCooldown = AIGatherStuff.COOLDOWN_SEARCH; } private void gatherStuff() { - if (this.pathCooldown-- <= 0) + if (!this.hasStuff()) return; + + final Vector3 stuffLoc = Vector3.getNewVector(); + if (this.targetItem != null) stuffLoc.set(this.targetItem); + else stuffLoc.set(this.targetBlock.getPos()); + + // Set path to the stuff found. + final double speed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); + this.setWalkTo(stuffLoc, speed, 0); + + // The stuff below is for collecting blocks, so we return after setting + // path if it is an item we are after + if (this.targetItem != null) { - this.pathCooldown = AIGatherStuff.COOLDOWN_PATH; - // Set path to the stuff found. - final double speed = 1; - if (!this.stuff.isEmpty() && this.stuffLoc == null) + double diff = 1; + diff = Math.max(diff, this.entity.getWidth()); + if (this.targetItem.getDistance(this.entity) < diff) { - this.setLoc(this.stuff.get(0)); - final Path path = this.entity.getNavigator().func_225466_a(this.stuffLoc.x, this.stuffLoc.y, - this.stuffLoc.z, 0); - this.addEntityPath(this.entity, path, speed); - } - else if (this.stuffLoc != null) - { - final Path path = this.entity.getNavigator().func_225466_a(this.stuffLoc.x, this.stuffLoc.y, - this.stuffLoc.z, 0); - this.addEntityPath(this.entity, path, speed); + ItemStackTools.addItemStackToInventory(this.targetItem.getItem(), this.pokemob.getInventory(), 2); + this.targetItem.remove(); } + this.reset(); + return; } - if (this.stuffLoc == null || !this.block) return; - - double diff = 3; + double diff = 2; diff = Math.max(diff, this.entity.getWidth()); - final double dist = this.stuffLoc.distToEntity(this.entity); - this.v.set(this.entity).subtractFrom(this.stuffLoc); + final double dist = stuffLoc.distToEntity(this.entity); + this.v.set(this.entity).subtractFrom(stuffLoc); final double dot = this.v.normalize().dot(Vector3.secondAxis); // This means that the item is directly above the pokemob, assume it // can pick up to 3 blocks upwards. if (dot < -0.9 && this.entity.onGround) diff = Math.max(3, diff); if (dist < diff) { - this.setCombatState(this.pokemob, CombatStates.HUNTING, false); - final BlockState state = this.stuffLoc.getBlockState(this.entity.getEntityWorld()); - this.stuffLoc.setAir(this.world); - final List list = Block.getDrops(state, this.world, this.stuffLoc.getPos(), null); + final BlockState state = stuffLoc.getBlockState(this.entity.getEntityWorld()); + stuffLoc.setAir(this.world); + final List list = Block.getDrops(state, this.world, stuffLoc.getPos(), null); boolean replanted = false; // See if anything dropped was a seed for the thing we // picked. for (final ItemStack stack : list) { // If so, Replant it. - if (!replanted) replanted = new ReplantTask(stack, state, this.stuffLoc.getPos()).run(this.world); - this.toRun.add(new InventoryChange(this.entity, 2, stack, true)); + if (!replanted) replanted = new ReplantTask(stack, state, stuffLoc.getPos()).run(this.world); + new InventoryChange(this.entity, 2, stack, true).run(this.world); } if (!replanted) for (int i = 2; i < this.pokemob.getInventory().getSizeInventory(); i++) { @@ -299,30 +263,29 @@ else if (this.stuffLoc != null) if (!stack.isEmpty() && stack.getItem() instanceof IPlantable) { final IPlantable plantable = (IPlantable) stack.getItem(); - final BlockState plantState = plantable.getPlant(this.world, this.stuffLoc.getPos().up()); + final BlockState plantState = plantable.getPlant(this.world, stuffLoc.getPos().up()); if (plantState.getBlock() == state.getBlock() && !replanted) { - replanted = new ReplantTask(stack, state, this.stuffLoc.getPos()).run(this.world); + replanted = new ReplantTask(stack, state, stuffLoc.getPos()).run(this.world); break; } } } - this.clearLoc(); + this.reset(); } } @Override public void reset() { - this.clearLoc(); - this.stuff.clear(); + this.targetItem = null; + this.targetBlock = null; } @Override public void run() { this.findStuff(); - this.gatherStuff(); } @Override @@ -334,11 +297,15 @@ public boolean shouldRun() // Dont run if the storage is currently trying to path somewhere if (this.storage.pathing) return false; + // We are going after something. + if (this.hasStuff()) return true; + final boolean wildCheck = !PokecubeCore.getConfig().wildGather && !this.pokemob.getGeneralState( GeneralStates.TAMED); // Check if this should be doing something else instead, if so return // false. if (this.tameCheck() || BrainUtils.hasAttackTarget(this.entity) || wildCheck) return false; + final int rate = this.pokemob.getGeneralState(GeneralStates.TAMED) ? PokecubeCore.getConfig().tameGatherDelay : PokecubeCore.getConfig().wildGatherDelay; final Random rand = new Random(this.pokemob.getRNGValue()); @@ -346,20 +313,32 @@ public boolean shouldRun() // not correct tick for this pokemob. if (this.pokemob.getHome() == null || this.entity.ticksExisted % rate != rand.nextInt(rate)) return false; - // Apply cooldown. - if (this.collectCooldown < -2000) this.collectCooldown = AIGatherStuff.COOLDOWN_SEARCH; - // If too far, clear location. - if (this.stuffLoc != null && this.stuffLoc.distToEntity(this.entity) > 32) this.clearLoc(); + final List blocks = BrainUtils.getNearBlocks(this.entity); + final List items = BrainUtils.getNearItems(this.entity); - // check if pokemob has room in inventory for stuff, if so, return true. - final IInventory inventory = this.pokemob.getInventory(); - for (int i = 3; i < inventory.getSizeInventory(); i++) + if (blocks != null) { - this.hasRoom = inventory.getStackInSlot(i).isEmpty(); - if (this.hasRoom) return true; + final ServerWorld world = (ServerWorld) this.entity.getEntityWorld(); + final Vec3d start = this.entity.getEyePosition(1); + final Predicate visible = input -> + { + final Vec3d end = new Vec3d(input.getPos()); + final RayTraceContext context = new RayTraceContext(start, end, BlockMode.COLLIDER, FluidMode.NONE, + AIGatherStuff.this.entity); + final RayTraceResult result = world.rayTraceBlocks(context); + if (result.getType() == Type.MISS) return true; + final BlockRayTraceResult hit = (BlockRayTraceResult) result; + return hit.getPos().equals(input.getPos()); + }; + this.blocks = Lists.newArrayList(blocks); + this.blocks.removeIf(b -> !AIGatherStuff.harvestMatcher.apply(b.getState()) || !visible.apply(b)); } - // Otherwise return false. - return false; + // Only replace this if the new list is not null. + if (items != null) this.items = items; + + if (this.blocks == null && this.items == null) return false; + // check if pokemob has room in inventory for stuff, if so, return true. + return this.storage.emptySlots > 0; } /** @@ -376,41 +355,6 @@ private boolean tameCheck() @Override public void tick() { - if (!this.stuff.isEmpty()) - { - final int num = this.stuff.size(); - this.stuff.removeIf(AIGatherStuff.deaditemmatcher); - Collections.sort(this.stuff, (o1, o2) -> - { - final int dist1 = (int) o1.getDistanceSq(AIGatherStuff.this.entity); - final int dist2 = (int) o2.getDistanceSq(AIGatherStuff.this.entity); - return dist1 - dist2; - }); - - if (this.stuff.isEmpty()) - { - this.reset(); - return; - } - - if (this.stuff.size() != num) - { - this.setLoc(this.stuff.get(0)); - return; - } - - final ItemEntity itemStuff = this.stuff.get(0); - - double close = this.entity.getWidth() * this.entity.getWidth(); - close = Math.max(close, 1); - if (itemStuff.getDistance(this.entity) < close) - { - ItemStackTools.addItemStackToInventory(itemStuff.getItem(), this.pokemob.getInventory(), 2); - itemStuff.remove(); - this.stuff.remove(0); - if (this.stuff.isEmpty()) this.reset(); - else this.setLoc(this.stuff.get(0)); - } - } + this.gatherStuff(); } } diff --git a/src/main/java/pokecube/core/ai/tasks/utility/AIStoreStuff.java b/src/main/java/pokecube/core/ai/tasks/utility/AIStoreStuff.java index 1cf8358052..a0540950c4 100644 --- a/src/main/java/pokecube/core/ai/tasks/utility/AIStoreStuff.java +++ b/src/main/java/pokecube/core/ai/tasks/utility/AIStoreStuff.java @@ -11,8 +11,6 @@ import net.minecraft.inventory.Inventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.pathfinding.Path; -import net.minecraft.pathfinding.PathPoint; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; @@ -25,11 +23,9 @@ import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.InvWrapper; -import pokecube.core.PokecubeCore; import pokecube.core.ai.tasks.idle.AIHungry; import pokecube.core.interfaces.IMoveConstants.AIRoutine; import pokecube.core.interfaces.IPokemob; -import pokecube.core.interfaces.PokecubeMod; import pokecube.core.interfaces.pokemob.ai.GeneralStates; import pokecube.core.items.berries.ItemBerry; import thut.api.item.ItemList; @@ -64,16 +60,21 @@ public class AIStoreStuff extends UtilTask implements INBTSerializable 9) { this.pathing = true; - final Path current = this.pokemob.getEntity().getNavigator().getPath(); - if (current != null) - { - final PathPoint end = current.getFinalPathPoint(); - final BlockPos dest = new BlockPos(end.x, end.y, end.z); - if (dest.withinDistance(this.berryLoc, 2)) return true; - } final double speed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); - this.pokemob.getEntity().getNavigator().tryMoveToXYZ(this.berryLoc.getX() + 0.5, this.berryLoc.getY() + 0.5, - this.berryLoc.getZ() + 0.5, speed); + this.setWalkTo(this.berryLoc, speed, 0); // We should be pathing to berries, so return true to stop other // storage tasks. - if (PokecubeMod.debug) PokecubeCore.LOGGER.info(this.pokemob.getDisplayName().getUnformattedComponentText() - + " Pathing to Berries at " + this.berryLoc); + // PokecubeCore.LOGGER.debug(this.pokemob.getDisplayName().getUnformattedComponentText() + // + " Pathing to Berries at " + this.berryLoc); return true; } for (int i = 0; i < Math.min(berries.getSlots(), AIStoreStuff.MAXSIZE); i++) @@ -205,8 +198,9 @@ private boolean doBerryCheck(final IItemHandlerModifiable pokemobInv) pokemobInv.setStackInSlot(this.firstEmpty, pokemobInv.getStackInSlot(2)); pokemobInv.setStackInSlot(2, stack); // Collected our berry, Can pass to storage now. - if (PokecubeMod.debug) PokecubeCore.LOGGER.info(this.pokemob.getDisplayName() - .getUnformattedComponentText() + " Took " + stack); + // PokecubeCore.LOGGER.debug(this.pokemob.getDisplayName().getUnformattedComponentText() + // + " Took " + // + stack); return false; } } @@ -237,19 +231,11 @@ private boolean doEmptyCheck(final IItemHandlerModifiable pokemobInv) if (this.pokemob.getEntity().getPosition().distanceSq(this.emptyInventory) > 9) { this.pathing = true; - final Path current = this.pokemob.getEntity().getNavigator().getPath(); - if (current != null) - { - final PathPoint end = current.getFinalPathPoint(); - final BlockPos dest = new BlockPos(end.x, end.y, end.z); - if (dest.withinDistance(this.emptyInventory, 2)) return true; - } final double speed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); - this.pokemob.getEntity().getNavigator().tryMoveToXYZ(this.emptyInventory.getX() + 0.5, this.emptyInventory - .getY() + 0.5, this.emptyInventory.getZ() + 0.5, speed); + this.setWalkTo(this.emptyInventory, speed, 0); // We should be pathing, so return true. - if (PokecubeMod.debug) PokecubeCore.LOGGER.info(this.pokemob.getDisplayName().getUnformattedComponentText() - + " Pathing to Pick Up at " + this.emptyInventory); + // PokecubeCore.LOGGER.debug(this.pokemob.getDisplayName().getUnformattedComponentText() + // + " Pathing to Pick Up at " + this.emptyInventory); return true; } boolean collected = false; @@ -265,8 +251,9 @@ private boolean doEmptyCheck(final IItemHandlerModifiable pokemobInv) inventory.setStackInSlot(i, ItemStack.EMPTY); pokemobInv.setStackInSlot(slot, stack); // Collected our item successfully - if (PokecubeMod.debug) PokecubeCore.LOGGER.info(this.pokemob.getDisplayName() - .getUnformattedComponentText() + " Took " + stack); + // PokecubeCore.LOGGER.debug(this.pokemob.getDisplayName().getUnformattedComponentText() + // + " Took " + // + stack); collected = true; start = i + 1; continue inv; @@ -286,19 +273,11 @@ private boolean doStorageCheck(final IItemHandlerModifiable pokemobInv) if (this.pokemob.getEntity().getPosition().distanceSq(this.storageLoc) > 9) { this.pathing = true; - final Path current = this.pokemob.getEntity().getNavigator().getPath(); - if (current != null) - { - final PathPoint end = current.getFinalPathPoint(); - final BlockPos dest = new BlockPos(end.x, end.y, end.z); - if (dest.withinDistance(this.storageLoc, 2)) return true; - } - final double speed = 1; - this.pokemob.getEntity().getNavigator().tryMoveToXYZ(this.storageLoc.getX() + 0.5, this.storageLoc.getY() - + 0.5, this.storageLoc.getZ() + 0.5, speed); + final double speed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); + this.setWalkTo(this.storageLoc, speed, 0); // We should be pathing to storage here, so return true. - PokecubeCore.LOGGER.debug(this.pokemob.getDisplayName().getUnformattedComponentText() - + " Pathing to Storage at " + this.storageLoc); + // PokecubeCore.LOGGER.debug(this.pokemob.getDisplayName().getUnformattedComponentText() + // + " Pathing to Storage at " + this.storageLoc); return true; } IItemHandlerModifiable storage = this.getInventory(this.world, this.storageLoc, this.storageFace); @@ -311,11 +290,12 @@ private boolean doStorageCheck(final IItemHandlerModifiable pokemobInv) for (int i = 3; i < pokemobInv.getSlots(); i++) { ItemStack stack = pokemobInv.getStackInSlot(i); - final ItemStack prev = stack.copy(); + // final ItemStack prev = stack.copy(); if (ItemStackTools.addItemStackToInventory(stack, storage, 0)) { - PokecubeCore.LOGGER.debug(this.pokemob.getDisplayName().getUnformattedComponentText() + " Storing " - + prev); + // PokecubeCore.LOGGER.debug(this.pokemob.getDisplayName().getUnformattedComponentText() + // + " Storing " + // + prev); if (stack.isEmpty()) stack = ItemStack.EMPTY; pokemobInv.setStackInSlot(i, stack); } diff --git a/src/main/java/pokecube/core/ai/tasks/utility/AIUseMove.java b/src/main/java/pokecube/core/ai/tasks/utility/AIUseMove.java index 0337b752c6..ac6665a70c 100644 --- a/src/main/java/pokecube/core/ai/tasks/utility/AIUseMove.java +++ b/src/main/java/pokecube/core/ai/tasks/utility/AIUseMove.java @@ -1,7 +1,13 @@ package pokecube.core.ai.tasks.utility; -import net.minecraft.pathfinding.Path; +import java.util.Map; + +import com.google.common.collect.Maps; + +import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.IPosWrapper; import net.minecraft.util.math.RayTraceContext; import net.minecraft.util.math.RayTraceContext.BlockMode; import net.minecraft.util.math.RayTraceContext.FluidMode; @@ -10,6 +16,8 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.brain.MemoryModules; import pokecube.core.interfaces.IMoveConstants; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.Move_Base; @@ -19,157 +27,141 @@ public class AIUseMove extends UtilTask { + private static final Map, MemoryModuleStatus> MEMS = Maps.newHashMap(); + + static + { + AIUseMove.MEMS.put(MemoryModules.MOVE_TARGET, MemoryModuleStatus.VALUE_PRESENT); + } + private boolean running = false; private boolean checkRange = false; - double speed; + + IPosWrapper pos = null; + + Vector3 destination = Vector3.getNewVector(); + + double speed; public AIUseMove(final IPokemob pokemob) { - super(pokemob); + super(pokemob, AIUseMove.MEMS); } @Override public void reset() { + this.running = false; } @Override public void run() { - final Vector3 destination = this.pokemob.getTargetPos(); + this.destination.set(this.pos.getPos()); final Move_Base move = MovesUtils.getMoveFromName(this.pokemob.getMove(this.pokemob.getMoveIndex())); + if (move == null) + { + BrainUtils.clearMoveUseTarget(this.entity); + return; + } + if (!this.running) { this.speed = this.pokemob.getMovementSpeed(); - this.pokemob.setCombatState(CombatStates.NEWEXECUTEMOVE, false); - if (move == null) return; - // No destination given, just apply the move directly. - if (destination == null) + + final boolean self = (move.getAttackCategory() & IMoveConstants.CATEGORY_SELF) != 0; + // Apply self moves directly. + if (self) { - this.addMoveInfo(this.pokemob, null, null, 0); - this.pokemob.setCombatState(CombatStates.EXECUTINGMOVE, false); + this.pokemob.executeMove(null, this.destination, 0); return; } - else + final boolean ranged = (move.getAttackCategory() & IMoveConstants.CATEGORY_DISTANCE) != 0; + if (ranged && !this.checkRange) { - final boolean self = (move.getAttackCategory() & IMoveConstants.CATEGORY_SELF) != 0; - // Apply self moves directly. - if (self) + final double dist = this.destination.distToEntity(this.entity); + // If in range, divert to main thread to see if visible. + if (dist < PokecubeCore.getConfig().rangedAttackDistance) { - this.addMoveInfo(this.pokemob, this.entity, null, 0); + this.checkRange = true; return; } - final boolean ranged = (move.getAttackCategory() & IMoveConstants.CATEGORY_DISTANCE) != 0; - if (ranged && !this.checkRange) - { - final double dist = destination.distToEntity(this.entity); - // If in range, divert to main thread to see if visible. - if (dist < PokecubeCore.getConfig().rangedAttackDistance) - { - this.checkRange = true; - return; - } - } - // Try to path to where the move is needed. - this.pokemob.setCombatState(CombatStates.EXECUTINGMOVE, true); - final Path path = this.entity.getNavigator().func_225466_a(destination.x, destination.y, destination.z, - 0); - this.addEntityPath(this.entity, path, this.speed); } + this.setWalkTo(this.destination, this.speed, 0); this.running = true; } // Look at your destination - this.entity.getLookController().setLookPosition(destination.x, destination.y, destination.z, 10, this.entity - .getVerticalFaceSpeed()); + BrainUtils.lookAt(this.entity, this.destination); final Vector3 loc = Vector3.getNewVector().set(this.entity, false); - final double dist = loc.distToSq(destination); - double var1 = 16; - if (move == null) - { - this.running = false; - this.pokemob.setCombatState(CombatStates.EXECUTINGMOVE, false); - return; - } - if (!this.checkRange && (move.getAttackCategory() & IMoveConstants.CATEGORY_DISTANCE) > 0) + final double dist = loc.distToSq(this.destination); + double var1 = 4; + + final boolean rangedMove = (move.getAttackCategory() & IMoveConstants.CATEGORY_DISTANCE) > 0; + + if (!this.checkRange && rangedMove) { var1 = PokecubeCore.getConfig().rangedAttackDistance * PokecubeCore.getConfig().rangedAttackDistance; // Divert ranged moves to main thread for visiblity checks. this.checkRange = true; } - if (!this.checkRange && dist < var1) - { - // If in range, apply the move and reset tasks - this.addMoveInfo(this.pokemob, null, destination, 0); - this.addEntityPath(this.entity, null, this.speed); - this.pokemob.setCombatState(CombatStates.EXECUTINGMOVE, false); - // Leap at the target location + if (!rangedMove) // Leap at the target location this.pokemob.setCombatState(CombatStates.LEAPING, true); - this.running = false; - } + + if (!this.checkRange && dist < var1) // If in range, apply the move + this.pokemob.executeMove(null, this.destination, 0); } @Override public boolean shouldRun() { - return this.running || this.pokemob.getCombatState(CombatStates.NEWEXECUTEMOVE) && !this.pokemob.getCombatState( - CombatStates.ANGRY) && this.pokemob.getAttackCooldown() <= 0; + return (this.pos = BrainUtils.getMoveUseTarget(this.entity)) != null; } @Override public void tick() { - // If the move was ranged, check that it is visible, if so, execute // move, otherwise path to location. if (this.checkRange) { - final Vector3 destination = this.pokemob.getTargetPos(); - if (destination != null) + RayTraceContext context = new RayTraceContext(this.entity.getPositionVector(), new Vec3d(this.destination.x, + this.destination.y, this.destination.z), BlockMode.COLLIDER, FluidMode.NONE, this.entity); + RayTraceResult trace = this.world.rayTraceBlocks(context); + BlockRayTraceResult result = null; + + // Adjust destination accordingly based on side hit, since it is + // normally center of block. + if (trace.getType() == Type.BLOCK) { - RayTraceContext context = new RayTraceContext(this.entity.getPositionVector(), new Vec3d(destination.x, - destination.y, destination.z), BlockMode.COLLIDER, FluidMode.NONE, this.entity); - RayTraceResult trace = this.world.rayTraceBlocks(context); - BlockRayTraceResult result = null; - - // Adjust destination accordingly based on side hit, since it is - // normally center of block. - if (trace.getType() == Type.BLOCK) - { - result = (BlockRayTraceResult) trace; - final Vec3i dir = result.getFace().getDirectionVec(); - // Make a new location that is shifted to closer to edge of - // the block for the visiblity checks. - final Vector3 loc = destination.copy(); - if (loc.x % 1 == 0.5) loc.x += dir.getX() * 0.49; - if (loc.y % 1 == 0.5) loc.y += dir.getY() * 0.49; - if (loc.z % 1 == 0.5) loc.z += dir.getZ() * 0.49; - result = null; - context = new RayTraceContext(this.entity.getPositionVector(), new Vec3d(loc.x, loc.y, loc.z), - BlockMode.COLLIDER, FluidMode.NONE, this.entity); - // Raytrace against shifted location. - trace = this.world.rayTraceBlocks(context); - if (trace.getType() == Type.BLOCK) result = (BlockRayTraceResult) trace; - } + result = (BlockRayTraceResult) trace; + final Vec3i dir = result.getFace().getDirectionVec(); + // Make a new location that is shifted to closer to edge of + // the block for the visiblity checks. + final Vector3 loc = this.destination.copy(); + if (loc.x % 1 == 0.5) loc.x += dir.getX() * 0.49; + if (loc.y % 1 == 0.5) loc.y += dir.getY() * 0.49; + if (loc.z % 1 == 0.5) loc.z += dir.getZ() * 0.49; + result = null; + context = new RayTraceContext(this.entity.getPositionVector(), new Vec3d(loc.x, loc.y, loc.z), + BlockMode.COLLIDER, FluidMode.NONE, this.entity); + // Raytrace against shifted location. + trace = this.world.rayTraceBlocks(context); + if (trace.getType() == Type.BLOCK) result = (BlockRayTraceResult) trace; + } - // Apply move directly from here. - if (result == null || result.getPos().equals(destination.getPos())) - { - this.addMoveInfo(this.pokemob, null, destination, 0); - this.addEntityPath(this.entity, null, this.speed); - this.pokemob.setCombatState(CombatStates.EXECUTINGMOVE, false); - this.running = false; - } - else - { - // Set destination and wait for move to be checked again. - this.running = true; - this.pokemob.setCombatState(CombatStates.EXECUTINGMOVE, true); - final Path path = this.entity.getNavigator().func_225466_a(destination.x, destination.y, - destination.z, 0); - this.addEntityPath(this.entity, path, this.speed); - } + // Apply move directly from here. + if (result == null || result.getPos().equals(this.destination.getPos())) + { + this.pokemob.executeMove(null, this.destination, 0); + this.running = false; + } + else + { + // Set destination and wait for move to be checked again. + this.running = true; + this.setWalkTo(this.destination, this.speed, 0); } this.checkRange = false; } diff --git a/src/main/java/pokecube/core/client/render/mobs/RenderPokemob.java b/src/main/java/pokecube/core/client/render/mobs/RenderPokemob.java index 5143973682..fe54ff2d73 100644 --- a/src/main/java/pokecube/core/client/render/mobs/RenderPokemob.java +++ b/src/main/java/pokecube/core/client/render/mobs/RenderPokemob.java @@ -571,8 +571,13 @@ public void doRender(final GenericPokemob entity, final double x, final double y final float entityYaw, final float partialTicks) { final IPokemob pokemob = entity.pokemobCap; + transform: if (pokemob.getTransformedTo() != null) { + final Entity to = pokemob.getTransformedTo(); + final IPokemob other = CapabilityPokemob.getPokemobFor(to); + // No transform loops! + if (other != null && other.getTransformedTo() != null) break transform; this.renderManager.getRenderer(pokemob.getTransformedTo()).doRender(pokemob.getTransformedTo(), x, y, z, entityYaw, partialTicks); return; diff --git a/src/main/java/pokecube/core/entity/pokemobs/EntityPokemob.java b/src/main/java/pokecube/core/entity/pokemobs/EntityPokemob.java index fcf1c4bfe2..ad2bf19ce2 100644 --- a/src/main/java/pokecube/core/entity/pokemobs/EntityPokemob.java +++ b/src/main/java/pokecube/core/entity/pokemobs/EntityPokemob.java @@ -46,6 +46,7 @@ import pokecube.core.handlers.playerdata.PlayerPokemobCache; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.capabilities.CapabilityPokemob; +import pokecube.core.interfaces.pokemob.ai.CombatStates; import pokecube.core.interfaces.pokemob.ai.LogicStates; import pokecube.core.items.pokemobeggs.EntityPokemobEgg; import pokecube.core.items.pokemobeggs.ItemPokemobEgg; @@ -185,7 +186,7 @@ protected void onDeathUpdate() public void onDeath(final DamageSource cause) { super.onDeath(cause); - this.pokemobCap.setLogicState(LogicStates.FAINTED, true); + this.pokemobCap.setCombatState(CombatStates.FAINTED, true); } @Override diff --git a/src/main/java/pokecube/core/handlers/events/EventsHandler.java b/src/main/java/pokecube/core/handlers/events/EventsHandler.java index 1f67db5509..3713516970 100644 --- a/src/main/java/pokecube/core/handlers/events/EventsHandler.java +++ b/src/main/java/pokecube/core/handlers/events/EventsHandler.java @@ -63,7 +63,7 @@ import pokecube.core.PokecubeCore; import pokecube.core.PokecubeItems; import pokecube.core.ai.routes.IGuardAICapability; -import pokecube.core.ai.tasks.AIBase.IRunnable; +import pokecube.core.ai.tasks.IRunnable; import pokecube.core.blocks.pc.PCTile; import pokecube.core.blocks.tms.TMTile; import pokecube.core.blocks.trade.TraderTile; diff --git a/src/main/java/pokecube/core/handlers/events/PokemobEventsHandler.java b/src/main/java/pokecube/core/handlers/events/PokemobEventsHandler.java index bf888bb89d..9a9283a230 100644 --- a/src/main/java/pokecube/core/handlers/events/PokemobEventsHandler.java +++ b/src/main/java/pokecube/core/handlers/events/PokemobEventsHandler.java @@ -494,7 +494,7 @@ public static void processInteract(final PlayerInteractEvent evt, final Entity t if (held.isEmpty()) player.inventory.setInventorySlotContents(player.inventory.currentItem, ItemStack.EMPTY); } - pokemob.setLoveTimer(0); + pokemob.setReadyToMate(player); BrainUtils.setAttackTarget(entity, null); entity.getEntityWorld().setEntityState(entity, (byte) 18); evt.setCanceled(true); diff --git a/src/main/java/pokecube/core/interfaces/IPokemob.java b/src/main/java/pokecube/core/interfaces/IPokemob.java index c928ac1729..55f1cff853 100644 --- a/src/main/java/pokecube/core/interfaces/IPokemob.java +++ b/src/main/java/pokecube/core/interfaces/IPokemob.java @@ -36,7 +36,6 @@ import pokecube.core.interfaces.pokemob.IHasOwner; import pokecube.core.interfaces.pokemob.IHasStats; import pokecube.core.interfaces.pokemob.ai.CombatStates; -import pokecube.core.interfaces.pokemob.ai.LogicStates; import pokecube.core.utils.PokeType; import thut.api.ModelHolder; import thut.api.entity.IBreedingMob; @@ -499,7 +498,7 @@ default ItemStack wildHeldItem(final MobEntity mob) default void revive() { - this.setLogicState(LogicStates.FAINTED, false); + this.setCombatState(CombatStates.FAINTED, false); this.setCombatState(CombatStates.ANGRY, false); this.setHungerTime(0); this.onSetTarget(null, true); diff --git a/src/main/java/pokecube/core/interfaces/capabilities/DefaultPokemob.java b/src/main/java/pokecube/core/interfaces/capabilities/DefaultPokemob.java index af2655020f..403de7f81f 100644 --- a/src/main/java/pokecube/core/interfaces/capabilities/DefaultPokemob.java +++ b/src/main/java/pokecube/core/interfaces/capabilities/DefaultPokemob.java @@ -121,6 +121,7 @@ public void deserializeNBT(final CompoundNBT nbt) public LazyOptional getCapability(final Capability capability, final Direction facing) { if (capability == ThutCaps.COLOURABLE) return this.holder.cast(); + if (capability == ThutCaps.BREEDS) return this.holder.cast(); return CapabilityPokemob.POKEMOB_CAP.orEmpty(capability, this.holder); } @@ -339,7 +340,7 @@ else if (target != null && this.getOwnerId() != null && this.getOwnerId().equals BrainUtils.setAttackTarget(this.getEntity(), null); return; } - else if (TeamManager.sameTeam(entity, this.getEntity())) + else if (TeamManager.sameTeam(entity, this.getEntity()) && !this.getCombatState(CombatStates.MATEFIGHT)) { BrainUtils.setAttackTarget(this.getEntity(), null); return; diff --git a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobAI.java b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobAI.java index d91e3c07ea..a943166a2e 100644 --- a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobAI.java +++ b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobAI.java @@ -63,12 +63,6 @@ public int getPokemonUID() return this.uid; } - @Override - public Vector3 getTargetPos() - { - return this.target; - } - @Override public List getTickLogic() { @@ -190,12 +184,6 @@ public void setRoutineState(final AIRoutine routine, final boolean enabled) this.routineStates[routine.ordinal()] = enabled; } - @Override - public void setTargetPos(final Vector3 pos) - { - this.target = pos; - } - @Override public void setTotalCombatState(final int state) { diff --git a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobBase.java b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobBase.java index b9dc4447e8..0426a25a74 100644 --- a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobBase.java +++ b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobBase.java @@ -7,6 +7,7 @@ import com.google.common.collect.Lists; +import net.minecraft.entity.AgeableEntity; import net.minecraft.entity.Entity; import net.minecraft.entity.MobEntity; import net.minecraft.entity.SharedMonsterAttributes; @@ -148,8 +149,6 @@ public void register(final IPokemob pokemob) protected StatModifiers modifiers = new StatModifiers(); /** Egg we are trying to protect. */ protected Entity egg = null; - /** Mob to breed with */ - protected Entity lover; /** * Timer for determining whether wants to breed, will only do so if this is * greater than 0 @@ -192,14 +191,12 @@ public void register(final IPokemob pokemob) /** Stack which will be used for evolution */ protected ItemStack stack = ItemStack.EMPTY; - /** Location to try to attack. */ - protected Vector3 target; /** Manages mounted control */ public LogicMountedControl controller; /** Used for various cases where things at mobs location need checking */ protected Vector3 here = Vector3.getNewVector(); /** The Entity this IPokemob is attached to. */ - protected MobEntity entity; + protected AgeableEntity entity; /** RNG used, should be entity.getRNG() */ protected Random rand = new Random(); /** Our original owner. */ @@ -232,7 +229,7 @@ public DataSync dataSync() } @Override - public MobEntity getEntity() + public AgeableEntity getEntity() { return this.entity; } @@ -257,7 +254,7 @@ public void setDataSync(final DataSync sync) public void setEntity(final MobEntity entityIn) { this.rand = entityIn.getRNG(); - this.entity = entityIn; + this.entity = (AgeableEntity) entityIn; } protected void setMaxHealth(final float maxHealth) diff --git a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobHungry.java b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobHungry.java index c9df77bf30..66ff2c92f9 100644 --- a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobHungry.java +++ b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobHungry.java @@ -26,9 +26,10 @@ public abstract class PokemobHungry extends PokemobMoves public void eat(final Object e) { int hungerValue = PokecubeCore.getConfig().pokemobLifeSpan / 4; - if (e instanceof ItemEntity) + ItemStack item = e instanceof ItemStack ? (ItemStack) e : ItemStack.EMPTY; + if (e instanceof ItemEntity) item = ((ItemEntity) e).getItem(); + if (!item.isEmpty()) { - final ItemStack item = ((ItemEntity) e).getItem(); final IPokemobUseable usable = IPokemobUseable.getUsableFor(item); if (usable != null) { diff --git a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobMoves.java b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobMoves.java index 0b2509890e..3bca045a21 100644 --- a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobMoves.java +++ b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobMoves.java @@ -40,6 +40,8 @@ public abstract class PokemobMoves extends PokemobSexed public void executeMove(final Entity target, Vector3 targetLocation, final float f) { String attack = this.getMove(this.getMoveIndex()); + BrainUtils.clearMoveUseTarget(this.getEntity()); + // If no move selected, just return here. if (attack == IMoveConstants.MOVE_NONE || attack == null) return; diff --git a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobSexed.java b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobSexed.java index 956d49f053..68cdf7a42c 100644 --- a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobSexed.java +++ b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobSexed.java @@ -1,9 +1,9 @@ package pokecube.core.interfaces.capabilities.impl; -import java.util.Vector; +import java.util.UUID; +import net.minecraft.entity.AgeableEntity; import net.minecraft.entity.Entity; -import net.minecraft.entity.passive.AnimalEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.server.MinecraftServer; @@ -29,14 +29,24 @@ public abstract class PokemobSexed extends PokemobStats { + private final UUID loveCause = null; @Override - public boolean canMate(final AnimalEntity AnimalEntity) + public boolean canMate(final AgeableEntity otherAnimal) { + if (otherAnimal == null || !otherAnimal.isAlive()) return false; + if (otherAnimal == this.getEntity()) return false; + // Not allowed to mate! if (!this.isRoutineEnabled(AIRoutine.MATE)) return false; - final IPokemob otherMob = CapabilityPokemob.getPokemobFor(AnimalEntity); + // Too injured, no mate! + if (otherAnimal.getHealth() < otherAnimal.getMaxHealth() / 2) return false; + + final IPokemob otherMob = CapabilityPokemob.getPokemobFor(otherAnimal); if (otherMob != null) { + // Not allowed to mate! + if (!otherMob.isRoutineEnabled(AIRoutine.MATE)) return false; + PokedexEntry thisEntry = this.getPokedexEntry(); PokedexEntry thatEntry = otherMob.getPokedexEntry(); @@ -63,7 +73,6 @@ else if (transforms || otherTransforms) // Anything else will mate // with a transformer. return true; } - return false; } @@ -88,29 +97,6 @@ public Object getChild(final IBreedingMob male) return this.getPokedexEntry().getChild(((IPokemob) male).getPokedexEntry()); } - @Override - /** - * Which entity is this pokemob trying to breed with - * - * @return - */ - public Entity getLover() - { - return this.lover; - } - - @Override - public int getLoveTimer() - { - return this.loveTimer; - } - - @Override - public Vector getMalesForBreeding() - { - return this.males; - } - public void lay(final IPokemob male) { this.here.set(this.getEntity()); @@ -164,13 +150,11 @@ protected void mate(final IBreedingMob male) final int hungerValue = PokecubeCore.getConfig().pokemobLifeSpan / 2; mate.setHungerTime(mate.getHungerTime() + hungerValue); this.setHungerTime(this.getHungerTime() + hungerValue); - mate.setLover(null); mate.resetLoveStatus(); AIFindTarget.deagro(this.getEntity()); AIFindTarget.deagro(mate.getEntity()); this.lay(mate); this.resetLoveStatus(); - this.lover = null; } @Override @@ -184,32 +168,43 @@ public void mateWith(final IBreedingMob male) @Override public void resetLoveStatus() { - this.setLoveTimer(this.rand.nextInt(600) - this.getBreedingDelay(null)); - this.setLover(null); + this.loveTimer = -this.rand.nextInt(600 + this.getBreedingDelay(null)); this.setGeneralState(GeneralStates.MATING, false); - if (this.males != null) this.males.clear(); } @Override - /** - * Sets the entity to try to breed with - * - * @param lover - */ - public void setLover(final Entity newLover) + public void tickBreedDelay(final int amount) + { + this.loveTimer += amount; + if (this.loveTimer > 6000) this.resetLoveStatus(); + } + + @Override + public void setReadyToMate(final PlayerEntity cause) { - this.lover = newLover; + this.loveTimer = 0; + } + + @Override + public ServerPlayerEntity getCause() + { + if (this.loveCause == null) return null; + else + { + final PlayerEntity playerentity = this.getEntity().getEntityWorld().getPlayerByUuid(this.loveCause); + return playerentity instanceof ServerPlayerEntity ? (ServerPlayerEntity) playerentity : null; + } } @Override - public void setLoveTimer(final int value) + public boolean canBreed() { - this.loveTimer = value; + return this.loveTimer >= 0; } @Override - public boolean tryToBreed() + public boolean isBreeding() { - return this.loveTimer >= 0 || this.lover != null; + return this.getGeneralState(GeneralStates.MATING); } } diff --git a/src/main/java/pokecube/core/interfaces/pokemob/IHasMoves.java b/src/main/java/pokecube/core/interfaces/pokemob/IHasMoves.java index 5d24a10c0d..3f924e8794 100644 --- a/src/main/java/pokecube/core/interfaces/pokemob/IHasMoves.java +++ b/src/main/java/pokecube/core/interfaces/pokemob/IHasMoves.java @@ -212,13 +212,6 @@ default String[] getGZMoves() /** @return entityId of our target. */ int getTargetID(); - /** - * This is the target location for move use. - * - * @return - */ - Vector3 getTargetPos(); - /** @return Mob we are transformed into, null for no mob. */ Entity getTransformedTo(); @@ -439,13 +432,6 @@ default boolean setStatus(final byte status) */ void setTargetID(int id); - /** - * Sets the target location for a move use. - * - * @param pos - */ - void setTargetPos(Vector3 pos); - /** * The pokemob will render and have moves according to whatever is set * here. If null is set, then it will use its own moves. diff --git a/src/main/java/pokecube/core/interfaces/pokemob/ai/CombatStates.java b/src/main/java/pokecube/core/interfaces/pokemob/ai/CombatStates.java index 71be11cc31..59c1662971 100644 --- a/src/main/java/pokecube/core/interfaces/pokemob/ai/CombatStates.java +++ b/src/main/java/pokecube/core/interfaces/pokemob/ai/CombatStates.java @@ -22,10 +22,14 @@ public enum CombatStates DODGING(1 << 5, false), /** Pokemon is fighting over mate)), should stop when hp hits 50%. */ MATEFIGHT(1 << 6, false), - /** Indicates that the pokemon is going to execute a move. */ + /** + * Indicates that the pokemon is going to execute a move. This value is used + * to signal that a move is in progress, for things such as dodging and + * rendering + */ EXECUTINGMOVE(1 << 7, false), - /** Indeicates that there is a new move to use. */ - NEWEXECUTEMOVE(1 << 8, false), + /** This pokemob has fainted and cannot battle */ + FAINTED(1 << 8), /** Pokemon cannot have item used on it */ NOITEMUSE(1 << 9), /** Pokemon is forbidden from swapping move */ diff --git a/src/main/java/pokecube/core/interfaces/pokemob/ai/GeneralStates.java b/src/main/java/pokecube/core/interfaces/pokemob/ai/GeneralStates.java index 655c1ac68a..82b26449d1 100644 --- a/src/main/java/pokecube/core/interfaces/pokemob/ai/GeneralStates.java +++ b/src/main/java/pokecube/core/interfaces/pokemob/ai/GeneralStates.java @@ -26,13 +26,13 @@ public enum GeneralStates final int mask; final boolean persist; - private GeneralStates(int mask) + private GeneralStates(final int mask) { this.mask = mask; this.persist = true; } - private GeneralStates(int mask, boolean persist) + private GeneralStates(final int mask, final boolean persist) { this.mask = mask; this.persist = persist; diff --git a/src/main/java/pokecube/core/interfaces/pokemob/ai/LogicStates.java b/src/main/java/pokecube/core/interfaces/pokemob/ai/LogicStates.java index 2590175831..3641259ed0 100644 --- a/src/main/java/pokecube/core/interfaces/pokemob/ai/LogicStates.java +++ b/src/main/java/pokecube/core/interfaces/pokemob/ai/LogicStates.java @@ -19,9 +19,7 @@ public enum LogicStates /** A sleeping pokemon will try to sit at its home location */ SLEEPING(1 << 7, false), /** This pokemob wants to sleep, but not here */ - TIRED(1 << 8), - /** This pokemob has fainted and cannot battle */ - FAINTED(1 << 9); + TIRED(1 << 8); final int mask; final boolean persist; diff --git a/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/AttackLocationHandler.java b/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/AttackLocationHandler.java index 30b4d6d37e..9296876581 100644 --- a/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/AttackLocationHandler.java +++ b/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/AttackLocationHandler.java @@ -4,11 +4,11 @@ import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TranslationTextComponent; import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.ai.tasks.idle.AIHungry; import pokecube.core.events.pokemob.combat.CommandAttackEvent; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.Move_Base; -import pokecube.core.interfaces.pokemob.ai.CombatStates; import pokecube.core.moves.MovesUtils; import pokecube.core.network.pokemobs.PacketCommand.DefaultHandler; import thut.api.maths.Vector3; @@ -52,8 +52,7 @@ public void handleCommand(final IPokemob pokemob) } // Otherwise set the location for execution of move. - pokemob.setCombatState(CombatStates.NEWEXECUTEMOVE, true); - pokemob.setTargetPos(this.location); + BrainUtils.setMoveUseTarget(pokemob.getEntity(), this.location); } } diff --git a/src/main/java/pokecube/core/items/pokecubes/helper/SendOutManager.java b/src/main/java/pokecube/core/items/pokecubes/helper/SendOutManager.java index cd3b73907a..087d59a90a 100644 --- a/src/main/java/pokecube/core/items/pokecubes/helper/SendOutManager.java +++ b/src/main/java/pokecube/core/items/pokecubes/helper/SendOutManager.java @@ -17,7 +17,7 @@ import net.minecraftforge.server.permission.PermissionAPI; import net.minecraftforge.server.permission.context.PlayerContext; import pokecube.core.PokecubeCore; -import pokecube.core.ai.tasks.AIBase.IRunnable; +import pokecube.core.ai.tasks.IRunnable; import pokecube.core.database.PokedexEntry; import pokecube.core.events.pokemob.SpawnEvent.SendOut; import pokecube.core.handlers.Config; diff --git a/src/main/java/pokecube/core/moves/MovesUtils.java b/src/main/java/pokecube/core/moves/MovesUtils.java index 3cab3aca4f..91fdc81cfa 100644 --- a/src/main/java/pokecube/core/moves/MovesUtils.java +++ b/src/main/java/pokecube/core/moves/MovesUtils.java @@ -73,7 +73,6 @@ public static void sendPairedMessages(final Entity target, final IPokemob attack { String key = baseKey + ".user"; final IPokemob attacked = CapabilityPokemob.getPokemobFor(target); - final ITextComponent targName = attacker != null ? attacker.getDisplayName() : target.getDisplayName(); if (attacker != null) attacker.displayMessageToOwner(new TranslationTextComponent(key, targName)); key = baseKey + ".target"; diff --git a/src/main/java/pokecube/core/moves/templates/Move_Basic.java b/src/main/java/pokecube/core/moves/templates/Move_Basic.java index 02fc8254e0..efae8305dd 100644 --- a/src/main/java/pokecube/core/moves/templates/Move_Basic.java +++ b/src/main/java/pokecube/core/moves/templates/Move_Basic.java @@ -22,6 +22,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.ai.tasks.combat.AIFindTarget; import pokecube.core.database.abilities.Ability; import pokecube.core.database.moves.MoveEntry; @@ -202,7 +203,11 @@ public void attack(final IPokemob attacker, final Vector3 location) this.attack(attacker, attacked); } } - else MovesUtils.displayEfficiencyMessages(attacker, null, -1, 0); + else if (BrainUtils.hasAttackTarget(attacker.getEntity())) + { + final LivingEntity target = BrainUtils.getAttackTarget(attacker.getEntity()); + MovesUtils.displayEfficiencyMessages(attacker, target, -1, 0); + } this.doWorldAction(attacker, location); } diff --git a/src/main/java/pokecube/mobs/moves/attacks/special/Transform.java b/src/main/java/pokecube/mobs/moves/attacks/special/Transform.java index 4df6f588ac..1077475fe2 100644 --- a/src/main/java/pokecube/mobs/moves/attacks/special/Transform.java +++ b/src/main/java/pokecube/mobs/moves/attacks/special/Transform.java @@ -14,7 +14,6 @@ import pokecube.core.interfaces.pokemob.moves.MovePacket; import pokecube.core.moves.MovesUtils; import pokecube.core.moves.templates.Move_Basic; -import thut.api.entity.IBreedingMob; /** @author Manchou */ public class Transform extends Move_Basic @@ -79,8 +78,7 @@ public void attack(final IPokemob attacker, final Entity attacked) final IPokemob attackedMob = CapabilityPokemob.getPokemobFor(attacked); if (attacked instanceof LivingEntity) { - if (!(attacked instanceof IBreedingMob) || attacked != ((IBreedingMob) attacker).getLover()) AIFindTarget - .initiateCombat(attacker.getEntity(), (LivingEntity) attacked); + AIFindTarget.initiateCombat(attacker.getEntity(), (LivingEntity) attacked); attacker.setTransformedTo(attacked); } else if (attackedMob != null) diff --git a/src/main/java/thut/api/OwnableCaps.java b/src/main/java/thut/api/OwnableCaps.java index 678bad8b1e..b36dea6502 100644 --- a/src/main/java/thut/api/OwnableCaps.java +++ b/src/main/java/thut/api/OwnableCaps.java @@ -284,7 +284,6 @@ public static void attachMobs(final AttachCapabilitiesEvent event) (TameableEntity) event.getObject())); else if (event.getObject() instanceof AbstractHorseEntity) event.addCapability(OwnableCaps.LOCWRAP, new HorseWrapper((AbstractHorseEntity) event.getObject())); - } else if (OwnableCaps.MOBS.contains(event.getObject().getClass())) event.addCapability(OwnableCaps.LOCBASE, new Impl()); diff --git a/src/main/java/thut/api/ThutCaps.java b/src/main/java/thut/api/ThutCaps.java index 8dacf9a7bd..53f46e5d8f 100644 --- a/src/main/java/thut/api/ThutCaps.java +++ b/src/main/java/thut/api/ThutCaps.java @@ -4,6 +4,7 @@ import net.minecraftforge.common.capabilities.CapabilityInject; import thut.api.LinkableCaps.ILinkStorage; import thut.api.LinkableCaps.ILinkable; +import thut.api.entity.IBreedingMob; import thut.api.entity.IMobColourable; import thut.api.terrain.CapabilityTerrain.ITerrainProvider; @@ -24,4 +25,7 @@ public class ThutCaps @CapabilityInject(IMobColourable.class) public static final Capability COLOURABLE = null; + @CapabilityInject(IBreedingMob.class) + public static final Capability BREEDS = null; + } diff --git a/src/main/java/thut/api/entity/BreedableCaps.java b/src/main/java/thut/api/entity/BreedableCaps.java new file mode 100644 index 0000000000..8766cfaf53 --- /dev/null +++ b/src/main/java/thut/api/entity/BreedableCaps.java @@ -0,0 +1,143 @@ +package thut.api.entity; + +import javax.annotation.Nullable; + +import net.minecraft.entity.AgeableEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.passive.AnimalEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.nbt.INBT; +import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.CapabilityManager; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.capabilities.ICapabilitySerializable; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import thut.api.ThutCaps; + +public class BreedableCaps +{ + public static class Impl implements IBreedingMob, ICapabilityProvider + { + private final LazyOptional holder = LazyOptional.of(() -> this); + + @Override + public LazyOptional getCapability(final Capability cap, final Direction side) + { + return ThutCaps.BREEDS.orEmpty(cap, this.holder); + } + + @Override + public AgeableEntity getEntity() + { + return null; + } + } + + public static class AgeableWrapper extends Impl + { + final AgeableEntity wrapped; + + public AgeableWrapper(final AgeableEntity wrapped) + { + this.wrapped = wrapped; + } + + @Override + public Object getChild(final IBreedingMob male) + { + return this.wrapped.createChild(male.getEntity()); + } + + @Override + public boolean canMate(final AgeableEntity other) + { + if (this.wrapped instanceof AnimalEntity && other instanceof AnimalEntity) + return ((AnimalEntity) this.wrapped).canMateWith((AnimalEntity) other); + return other.getClass() == this.wrapped.getClass(); + } + + @Override + public boolean canBreed() + { + if (this.wrapped instanceof AnimalEntity) return ((AnimalEntity) this.wrapped).canBreed(); + return super.canBreed(); + } + + @Override + public boolean isBreeding() + { + if (this.wrapped instanceof AnimalEntity) return ((AnimalEntity) this.wrapped).isInLove(); + return super.isBreeding(); + } + + @Override + public void setReadyToMate(@Nullable final PlayerEntity cause) + { + if (this.wrapped instanceof AnimalEntity) ((AnimalEntity) this.wrapped).setInLove(cause); + } + + @Override + public void resetLoveStatus() + { + if (this.wrapped instanceof AnimalEntity) ((AnimalEntity) this.wrapped).resetInLove(); + } + + @Override + public ServerPlayerEntity getCause() + { + if (this.wrapped instanceof AnimalEntity) return ((AnimalEntity) this.wrapped).getLoveCause(); + return super.getCause(); + } + } + + public static class Storage implements Capability.IStorage + { + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void readNBT(final Capability capability, final IBreedingMob instance, + final Direction side, final INBT nbt) + { + if (instance instanceof ICapabilitySerializable) ((ICapabilitySerializable) instance).deserializeNBT(nbt); + } + + @Override + public INBT writeNBT(final Capability capability, final IBreedingMob instance, + final Direction side) + { + if (instance instanceof ICapabilitySerializable) return ((ICapabilitySerializable) instance) + .serializeNBT(); + return null; + } + } + + public static final ResourceLocation WRAP = new ResourceLocation("thutcore:breedable_wrap"); + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void attachMobs(final AttachCapabilitiesEvent event) + { + // Check if someone else adds this first (like say an IPokemob + for (final ICapabilityProvider p : event.getCapabilities().values()) + if (p.getCapability(ThutCaps.BREEDS).isPresent()) return; + if (event.getObject() instanceof AgeableEntity) event.addCapability(BreedableCaps.WRAP, new AgeableWrapper( + (AgeableEntity) event.getObject())); + } + + public static IBreedingMob getBreedable(final ICapabilityProvider in) + { + if (in == null) return null; + return in.getCapability(ThutCaps.BREEDS).orElse(null); + } + + public static void setup() + { + CapabilityManager.INSTANCE.register(IBreedingMob.class, new Storage(), Impl::new); + MinecraftForge.EVENT_BUS.register(BreedableCaps.class); + } +} diff --git a/src/main/java/thut/api/entity/IBreedingMob.java b/src/main/java/thut/api/entity/IBreedingMob.java index aa962cfd03..940e579ed4 100644 --- a/src/main/java/thut/api/entity/IBreedingMob.java +++ b/src/main/java/thut/api/entity/IBreedingMob.java @@ -1,9 +1,10 @@ package thut.api.entity; -import java.util.Vector; +import javax.annotation.Nullable; -import net.minecraft.entity.Entity; -import net.minecraft.entity.passive.AnimalEntity; +import net.minecraft.entity.AgeableEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; /** * This interface is used for mobs which can breed with other mobs. @@ -12,7 +13,12 @@ */ public interface IBreedingMob { - boolean canMate(AnimalEntity AnimalEntity); + AgeableEntity getEntity(); + + default boolean canMate(final AgeableEntity AnimalEntity) + { + return false; + } /** * Will be called by the mother before she lays to know what baby to put in @@ -22,47 +28,56 @@ public interface IBreedingMob * the male * @return the pokedex number of the child */ - Object getChild(IBreedingMob male); - - /** - * Which entity is this pokemob trying to breed with - * - * @return - */ - Entity getLover(); - - /** @return the timer indcating delay between looking for a mate. */ - int getLoveTimer(); - - Vector getMalesForBreeding(); + default Object getChild(final IBreedingMob male) + { + return null; + } /** @return the byte sexe */ - byte getSexe(); + default byte getSexe() + { + return -1; + } - void mateWith(IBreedingMob male); + default void mateWith(final IBreedingMob male) + { + } /** resets the status of being in love */ - void resetLoveStatus(); + default void resetLoveStatus() + { + } - /** - * Sets the entity to try to breed with - * - * @param lover - */ - void setLover(Entity lover); + default void setReadyToMate(@Nullable final PlayerEntity cause) + { + } - /** - * Sets the timer for the delay between looking for a mate. - * - * @param value - */ - void setLoveTimer(int value); + @Nullable + default ServerPlayerEntity getCause() + { + return null; + } /** * @param sexe * the byte sexe */ - void setSexe(byte sexe); + default void setSexe(final byte sexe) + { + } + + default void tickBreedDelay(final int tickAmount) + { + + } + + default boolean canBreed() + { + return false; + } - boolean tryToBreed(); + default boolean isBreeding() + { + return false; + } } diff --git a/src/main/java/thut/api/entity/ai/VectorPosWrapper.java b/src/main/java/thut/api/entity/ai/VectorPosWrapper.java new file mode 100644 index 0000000000..29daa1b2a9 --- /dev/null +++ b/src/main/java/thut/api/entity/ai/VectorPosWrapper.java @@ -0,0 +1,40 @@ +package thut.api.entity.ai; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.IPosWrapper; +import net.minecraft.util.math.Vec3d; +import thut.api.maths.Vector3; + +public class VectorPosWrapper implements IPosWrapper +{ + final BlockPos bpos; + final Vec3d vpos; + final Vector3 pos; + + public VectorPosWrapper(final Vector3 pos) + { + this.bpos = pos.getPos().toImmutable(); + this.vpos = pos.toVec3d(); + this.pos = pos.copy(); + } + + @Override + public BlockPos getBlockPos() + { + return this.bpos; + } + + @Override + public Vec3d getPos() + { + return this.vpos; + } + + @Override + public boolean isVisibleTo(final LivingEntity p_220610_1_) + { + return true; + } + +} diff --git a/src/main/java/thut/api/maths/Vector3.java b/src/main/java/thut/api/maths/Vector3.java index 850383019b..cd6b67fb6d 100644 --- a/src/main/java/thut/api/maths/Vector3.java +++ b/src/main/java/thut/api/maths/Vector3.java @@ -97,6 +97,12 @@ public void set(final int x0, final int y0, final int z0) this.y = y0; this.z = z0; } + + @Override + public BlockPos toImmutable() + { + return new BlockPos(this); + } } public static final Vector3 secondAxis = Vector3.getNewVector().set(0, 1, 0); diff --git a/src/main/java/thut/core/common/ThutCore.java b/src/main/java/thut/core/common/ThutCore.java index 929dbf9787..69c01e260c 100644 --- a/src/main/java/thut/core/common/ThutCore.java +++ b/src/main/java/thut/core/common/ThutCore.java @@ -45,6 +45,7 @@ import net.minecraftforge.fml.loading.FMLPaths; import thut.api.LinkableCaps; import thut.api.OwnableCaps; +import thut.api.entity.BreedableCaps; import thut.api.entity.IMobColourable; import thut.api.entity.IMobTexturable; import thut.api.entity.IMultiplePassengerEntity; @@ -280,6 +281,7 @@ private void setup(final FMLCommonSetupEvent event) OwnableCaps.setup(); LinkableCaps.setup(); ShearableCaps.setup(); + BreedableCaps.setup(); // Register terrain capabilies CapabilityManager.INSTANCE.register(CapabilityTerrain.ITerrainProvider.class, new CapabilityTerrain.Storage(), diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 3842ef301f..2da2c86724 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -19,6 +19,8 @@ public net.minecraft.entity.ai.brain.Brain func_218217_d(Lnet/minecraft/entity/a public net.minecraft.entity.ai.brain.Brain field_218230_a # memories public net.minecraft.entity.ai.brain.Brain field_218231_b # sensors +public net.minecraft.pathfinding.PathNavigator func_225464_a(Ljava/util/Set;IZI)Lnet/minecraft/pathfinding/Path; # func_225464_a + # Player related public net.minecraft.network.play.ServerPlayNetHandler field_147365_f # floatingTickCount public net.minecraft.network.play.ServerPlayNetHandler field_184346_E # vehicleFloatingTickCount diff --git a/src/main/resources/data/pokecube/tags/blocks/pokemob_redstone_food.json b/src/main/resources/data/pokecube/tags/blocks/pokemob_redstone_food.json new file mode 100644 index 0000000000..f20a3ced25 --- /dev/null +++ b/src/main/resources/data/pokecube/tags/blocks/pokemob_redstone_food.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:redstone_block" + ] +} \ No newline at end of file