diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 95c0b41307..7b260569b3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,6 +1,9 @@ --- name: Bug report about: Create a report to help us improve +title: '' +labels: Unconfirmed +assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 066b2d920a..11fc491ef1 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,6 +1,9 @@ --- name: Feature request about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' --- diff --git a/src/main/java/pokecube/adventures/Config.java b/src/main/java/pokecube/adventures/Config.java index cd96ef689c..f79bb2b9d6 100644 --- a/src/main/java/pokecube/adventures/Config.java +++ b/src/main/java/pokecube/adventures/Config.java @@ -29,15 +29,19 @@ public class Config extends ConfigData private static final String BAG = "bag"; @Configure(category = Config.TRAINER) - public boolean npcsAreTrainers = true; + public boolean npcsAreTrainers = true; + + @Configure(category = Config.TRAINER) + public int trainerCooldown = 5000; @Configure(category = Config.TRAINER) - public int trainerCooldown = 5000; + public int trainerSightRange = 8; @Configure(category = Config.TRAINER) - public int trainerSightRange = 8; + public int trainerBattleDelay = 50; @Configure(category = Config.TRAINER) - public int trainerBattleDelay = 50; + public int trainerSendOutDelay = 50; @Configure(category = Config.TRAINER) - public int trainerSendOutDelay = 50; + public int trainerAgroRate = 20; + @Configure(category = Config.TRAINER) public boolean trainerslevel = true; @Configure(category = Config.TRAINER) @@ -128,6 +132,8 @@ public class Config extends ConfigData public String afaCostFunctionShiny = "(d^3)/10"; @Configure(category = Config.MACHINE) public int afaMaxEnergy = 3200; + @Configure(category = Config.MACHINE) + public int afaTickRate = 5; @Configure(category = Config.BAG, type = Type.SERVER) public boolean bagsHoldEverything = false; @@ -154,6 +160,8 @@ public void onUpdated() DaycareTile.initParser(this.dayCarePowerPerExp, this.dayCareExpFunction); AfaTile.initParser(this.afaCostFunction, this.afaCostFunctionShiny); this.dayCareTickRate = Math.max(1, this.dayCareTickRate); + this.afaTickRate = Math.max(1, this.afaTickRate); + this.trainerAgroRate = Math.max(1, this.trainerAgroRate); if (this.autoAddFossilDNA) for (final Entry fossil : ItemGenerator.fossils.entrySet()) { diff --git a/src/main/java/pokecube/adventures/PokecubeAdv.java b/src/main/java/pokecube/adventures/PokecubeAdv.java index 1d4450c711..7e4032171c 100644 --- a/src/main/java/pokecube/adventures/PokecubeAdv.java +++ b/src/main/java/pokecube/adventures/PokecubeAdv.java @@ -8,12 +8,15 @@ import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.EntityType; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.entity.merchant.villager.VillagerProfession; import net.minecraft.inventory.container.ContainerType; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; +import net.minecraft.village.PointOfInterestType; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.TextureStitchEvent; @@ -25,8 +28,12 @@ import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import pokecube.adventures.advancements.Triggers; +import pokecube.adventures.ai.brain.MemoryTypes; +import pokecube.adventures.ai.poi.PointsOfInterest; +import pokecube.adventures.ai.poi.Professions; import pokecube.adventures.blocks.BlockEventHandler; import pokecube.adventures.blocks.afa.AfaBlock; +import pokecube.adventures.blocks.afa.AfaContainer; import pokecube.adventures.blocks.afa.AfaTile; import pokecube.adventures.blocks.commander.CommanderBlock; import pokecube.adventures.blocks.commander.CommanderTile; @@ -99,6 +106,7 @@ public static void registerContainers(final RegistryEvent.Register> event.getRegistry().register(LeaderNpc.TYPE.setRegistryName(PokecubeAdv.MODID, "leader")); } + @SubscribeEvent + public static void registerMemories(final RegistryEvent.Register> event) + { + MemoryTypes.register(event); + } + @SubscribeEvent public static void registerItems(final RegistryEvent.Register event) { @@ -157,6 +171,18 @@ public static void registerRecipes(final RegistryEvent.Register event) + { + PointsOfInterest.register(event); + } + + @SubscribeEvent + public static void registerProfessions(final RegistryEvent.Register event) + { + Professions.register(event); + } + @SubscribeEvent public static void registerTiles(final RegistryEvent.Register> event) { @@ -210,32 +236,36 @@ public static void textureStitch(final TextureStitchEvent.Pre event) public static final Map BADGES = Maps.newHashMap(); public static final Map BADGEINV = Maps.newHashMap(); - static void init() + static + { + PokecubeAdv.AFA = new AfaBlock(Block.Properties.create(Material.IRON).variableOpacity()); + PokecubeAdv.COMMANDER = new CommanderBlock(Block.Properties.create(Material.IRON).variableOpacity()); + PokecubeAdv.DAYCARE = new DaycareBlock(Block.Properties.create(Material.IRON).variableOpacity()); + PokecubeAdv.CLONER = new ClonerBlock(Block.Properties.create(Material.IRON).variableOpacity()); + PokecubeAdv.EXTRACTOR = new ExtractorBlock(Block.Properties.create(Material.IRON).variableOpacity()); + PokecubeAdv.SPLICER = new SplicerBlock(Block.Properties.create(Material.IRON).variableOpacity()); + PokecubeAdv.SIPHON = new SiphonBlock(Block.Properties.create(Material.IRON).variableOpacity()); + PokecubeAdv.WARPPAD = new WarppadBlock(Block.Properties.create(Material.IRON)); + PokecubeAdv.EXPSHARE = new Item(new Item.Properties().group(PokecubeItems.POKECUBEITEMS)); + PokecubeAdv.LINKER = new Linker(new Item.Properties().group(PokecubeItems.POKECUBEITEMS)); + PokecubeAdv.BAG = new BagItem(new Item.Properties().group(PokecubeItems.POKECUBEITEMS)); + PokecubeAdv.TRAINEREDITOR = new TrainerEditor(new Item.Properties().group(PokecubeItems.POKECUBEITEMS)); + } + + private static void init() { - PokecubeAdv.AFA = new AfaBlock(Block.Properties.create(Material.IRON).variableOpacity()).setRegistryName( - PokecubeAdv.MODID, "afa"); - PokecubeAdv.COMMANDER = new CommanderBlock(Block.Properties.create(Material.IRON).variableOpacity()) - .setRegistryName(PokecubeAdv.MODID, "commander"); - PokecubeAdv.DAYCARE = new DaycareBlock(Block.Properties.create(Material.IRON).variableOpacity()) - .setRegistryName(PokecubeAdv.MODID, "daycare"); - PokecubeAdv.CLONER = new ClonerBlock(Block.Properties.create(Material.IRON).variableOpacity()).setRegistryName( - PokecubeAdv.MODID, "cloner"); - PokecubeAdv.EXTRACTOR = new ExtractorBlock(Block.Properties.create(Material.IRON).variableOpacity()) - .setRegistryName(PokecubeAdv.MODID, "extractor"); - PokecubeAdv.SPLICER = new SplicerBlock(Block.Properties.create(Material.IRON).variableOpacity()) - .setRegistryName(PokecubeAdv.MODID, "splicer"); - PokecubeAdv.SIPHON = new SiphonBlock(Block.Properties.create(Material.IRON).variableOpacity()).setRegistryName( - PokecubeAdv.MODID, "siphon"); - PokecubeAdv.WARPPAD = new WarppadBlock(Block.Properties.create(Material.IRON).variableOpacity()) - .setRegistryName(PokecubeAdv.MODID, "warppad"); - PokecubeAdv.EXPSHARE = new Item(new Item.Properties().group(PokecubeItems.POKECUBEITEMS)).setRegistryName( - PokecubeAdv.MODID, "exp_share"); - PokecubeAdv.LINKER = new Linker(new Item.Properties().group(PokecubeItems.POKECUBEITEMS)).setRegistryName( - PokecubeAdv.MODID, "linker"); - PokecubeAdv.BAG = new BagItem(new Item.Properties().group(PokecubeItems.POKECUBEITEMS)).setRegistryName( - PokecubeAdv.MODID, "bag"); - PokecubeAdv.TRAINEREDITOR = new TrainerEditor(new Item.Properties().group(PokecubeItems.POKECUBEITEMS)) - .setRegistryName(PokecubeAdv.MODID, "trainer_editor"); + PokecubeAdv.AFA.setRegistryName(PokecubeAdv.MODID, "afa"); + PokecubeAdv.COMMANDER.setRegistryName(PokecubeAdv.MODID, "commander"); + PokecubeAdv.DAYCARE.setRegistryName(PokecubeAdv.MODID, "daycare"); + PokecubeAdv.CLONER.setRegistryName(PokecubeAdv.MODID, "cloner"); + PokecubeAdv.EXTRACTOR.setRegistryName(PokecubeAdv.MODID, "extractor"); + PokecubeAdv.SPLICER.setRegistryName(PokecubeAdv.MODID, "splicer"); + PokecubeAdv.SIPHON.setRegistryName(PokecubeAdv.MODID, "siphon"); + PokecubeAdv.WARPPAD.setRegistryName(PokecubeAdv.MODID, "warppad"); + PokecubeAdv.EXPSHARE.setRegistryName(PokecubeAdv.MODID, "exp_share"); + PokecubeAdv.LINKER.setRegistryName(PokecubeAdv.MODID, "linker"); + PokecubeAdv.BAG.setRegistryName(PokecubeAdv.MODID, "bag"); + PokecubeAdv.TRAINEREDITOR.setRegistryName(PokecubeAdv.MODID, "trainer_editor"); // Initialize advancement triggers Triggers.init(); @@ -249,7 +279,7 @@ static void init() public final static CommonProxy proxy = DistExecutor.runForDist(() -> () -> new ClientProxy(), () -> () -> new CommonProxy()); - private static final String NETVERSION = "1.0.0"; + private static final String NETVERSION = "1.0.1"; // Handler for network stuff. public static final PacketHandler packets = new PacketHandler(new ResourceLocation(PokecubeAdv.MODID, "comms"), PokecubeAdv.NETVERSION); @@ -258,7 +288,6 @@ static void init() public PokecubeAdv() { - // Initialize items and blocks PokecubeAdv.init(); FMLJavaModLoadingContext.get().getModEventBus().addListener(PokecubeAdv.proxy::setup); diff --git a/src/main/java/pokecube/adventures/ai/brain/MemoryTypes.java b/src/main/java/pokecube/adventures/ai/brain/MemoryTypes.java new file mode 100644 index 0000000000..7dc0780733 --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/brain/MemoryTypes.java @@ -0,0 +1,18 @@ +package pokecube.adventures.ai.brain; + +import java.util.Optional; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraftforge.event.RegistryEvent.Register; +import pokecube.adventures.PokecubeAdv; + +public class MemoryTypes +{ + public static final MemoryModuleType BATTLETARGET = new MemoryModuleType<>(Optional.empty()); + + public static void register(final Register> event) + { + event.getRegistry().register(MemoryTypes.BATTLETARGET.setRegistryName(PokecubeAdv.MODID, "battle_target")); + } +} diff --git a/src/main/java/pokecube/adventures/ai/poi/PointsOfInterest.java b/src/main/java/pokecube/adventures/ai/poi/PointsOfInterest.java new file mode 100644 index 0000000000..2e03f21879 --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/poi/PointsOfInterest.java @@ -0,0 +1,40 @@ +package pokecube.adventures.ai.poi; + +import java.util.Set; + +import com.google.common.collect.Sets; + +import net.minecraft.block.BlockState; +import net.minecraft.village.PointOfInterestType; +import net.minecraftforge.event.RegistryEvent.Register; +import pokecube.adventures.PokecubeAdv; +import pokecube.core.PokecubeItems; + +public class PointsOfInterest +{ + public static Set LABMACHINES = Sets.newHashSet(); + + public static PointOfInterestType GENELAB; + public static PointOfInterestType HEALER; + + public static void register(final Register event) + { + PointsOfInterest.LABMACHINES.addAll(PokecubeAdv.EXTRACTOR.getStateContainer().getValidStates()); + PointsOfInterest.LABMACHINES.addAll(PokecubeAdv.SPLICER.getStateContainer().getValidStates()); + PointsOfInterest.LABMACHINES.addAll(PokecubeAdv.CLONER.getStateContainer().getValidStates()); + + PointsOfInterest.GENELAB = new PointOfInterestType("pokecube_adventures:gene_lab", PointsOfInterest.LABMACHINES, + 1, null, 2); + PointsOfInterest.HEALER = new PointOfInterestType("pokecube_adventures:healer", Sets.newHashSet( + PokecubeItems.HEALER.getStateContainer().getValidStates()), 1, null, 2); + System.out.println(Sets.newHashSet(PokecubeItems.HEALER.getStateContainer().getValidStates())); + System.out.println(PointsOfInterest.LABMACHINES); + + event.getRegistry().register(PointsOfInterest.GENELAB.setRegistryName("pokecube_adventures:gene_lab")); + event.getRegistry().register(PointsOfInterest.HEALER.setRegistryName("pokecube_adventures:healer")); + + PointOfInterestType.func_221052_a(PointsOfInterest.GENELAB); + PointOfInterestType.func_221052_a(PointsOfInterest.HEALER); + } + +} diff --git a/src/main/java/pokecube/adventures/ai/poi/Professions.java b/src/main/java/pokecube/adventures/ai/poi/Professions.java new file mode 100644 index 0000000000..90b79198f8 --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/poi/Professions.java @@ -0,0 +1,26 @@ +package pokecube.adventures.ai.poi; + +import com.google.common.collect.ImmutableSet; + +import net.minecraft.entity.merchant.villager.VillagerProfession; +import net.minecraftforge.event.RegistryEvent.Register; +import pokecube.core.entity.npc.NpcType; + +public class Professions +{ + public static VillagerProfession HEALER; + public static VillagerProfession PROFESSOR; + + public static void register(final Register event) + { + Professions.HEALER = new VillagerProfession("pokecube_adventures:healer", PointsOfInterest.HEALER, ImmutableSet + .of(), ImmutableSet.of()); + Professions.PROFESSOR = new VillagerProfession("pokecube_adventures:professor", PointsOfInterest.GENELAB, + ImmutableSet.of(), ImmutableSet.of()); + event.getRegistry().register(Professions.HEALER.setRegistryName("pokecube_adventures:healer")); + event.getRegistry().register(Professions.PROFESSOR.setRegistryName("pokecube_adventures:professor")); + + NpcType.HEALER.setProfession(Professions.HEALER); + NpcType.PROFESSOR.setProfession(Professions.PROFESSOR); + } +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/AIBattle.java b/src/main/java/pokecube/adventures/ai/tasks/AIBattle.java deleted file mode 100644 index 59de40f610..0000000000 --- a/src/main/java/pokecube/adventures/ai/tasks/AIBattle.java +++ /dev/null @@ -1,360 +0,0 @@ -package pokecube.adventures.ai.tasks; - -import java.util.List; - -import net.minecraft.command.arguments.EntityAnchorArgument.Type; -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.MobEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.pathfinding.PathNavigator; -import net.minecraft.util.math.BlockPos; -import pokecube.adventures.Config; -import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs; -import pokecube.adventures.capabilities.CapabilityNPCAIStates.IHasNPCAIStates; -import pokecube.adventures.capabilities.TrainerCaps; -import pokecube.adventures.capabilities.utils.MessageState; -import pokecube.core.PokecubeCore; -import pokecube.core.ai.brain.BrainUtils; -import pokecube.core.ai.tasks.combat.AIFindTarget; -import pokecube.core.database.Database; -import pokecube.core.database.PokedexEntry; -import pokecube.core.handlers.events.PCEventsHandler; -import pokecube.core.interfaces.IPokemob; -import pokecube.core.interfaces.Move_Base; -import pokecube.core.interfaces.capabilities.CapabilityPokemob; -import pokecube.core.interfaces.pokemob.ai.CombatStates; -import pokecube.core.items.pokecubes.EntityPokecubeBase; -import pokecube.core.items.pokecubes.PokecubeManager; -import pokecube.core.moves.MovesUtils; -import pokecube.core.utils.PokeType; -import thut.api.maths.Vector3; - -public class AIBattle extends AITrainerBase -{ - private boolean canPath = true; - private BlockPos battleLoc = null; - private int deagrotimer = 0; - - public AIBattle(final LivingEntity trainer) - { - this(trainer, true); - } - - public AIBattle(final LivingEntity trainer, final boolean canPath) - { - super(trainer); - this.canPath = canPath; - } - - private boolean checkPokemobTarget() - { - final Entity mobTarget = BrainUtils.getAttackTarget(this.trainer.getOutMob().getEntity()); - final IPokemob target = CapabilityPokemob.getPokemobFor(mobTarget); - if (!this.trainer.getOutMob().getCombatState(CombatStates.ANGRY)) this.trainer.getOutMob().setCombatState( - CombatStates.ANGRY, true); - // check if pokemob's target is same as trainers. - if (mobTarget != this.trainer.getTarget() && target == null) AIFindTarget.initiateCombat(this.trainer - .getOutMob().getEntity(), this.trainer.getTarget()); - // Return if trainer's pokemob's target is also a pokemob. - return CapabilityPokemob.getPokemobFor(BrainUtils.getAttackTarget(this.trainer.getOutMob() - .getEntity())) != null; - } - - private void considerSwapMove() - { - // TODO choose between damaging/stats/status moves - this.setMostDamagingMove(); - } - - private boolean considerSwapPokemob() - { - // TODO check if the target pokemob is bad matchup, consider swapping to - // better choice. - - // check if can mega evolve - final IPokemob out = this.trainer.getOutMob(); - if (this.trainer.canMegaEvolve() && out != null && out.getPokedexEntry().hasMegaForm) - { - final List formes = Database.getFormes(out.getPokedexEntry()); - if (!formes.isEmpty()) - { - final int start = this.entity.getRNG().nextInt(formes.size()); - for (int i = 0; i < formes.size(); i++) - { - final PokedexEntry mega = formes.get((i + start) % formes.size()); - if (mega.isMega) - { - out.megaEvolve(mega); - break; - } - } - } - - } - return false; - } - - void doAggression() - { - // Check if we are being targetted by the enemies pokemob, if so, we - // will make it be passive for now. - if (this.entity instanceof MobEntity) - { - final Entity target = BrainUtils.getAttackTarget(this.entity); - if (target instanceof LivingEntity) AIFindTarget.initiateCombat((MobEntity) this.entity, - (LivingEntity) target); - } - - // Check if maybe mob was sent out, but just not seen - final List mobs = PCEventsHandler.getOutMobs(this.entity, false); - if (!mobs.isEmpty()) - { - boolean found = false; - for (final Entity mob : mobs) - // Ones not added to chunk are in pokecubes, so wait for them to - // exit. - if (mob.addedToChunk) - { - final IPokemob pokemob = CapabilityPokemob.getPokemobFor(mob); - if (pokemob != null && !found) - { - this.trainer.setOutMob(pokemob); - found = true; - } - // Prevent players from grabbing the pokecube of the - // trainer. - else if (mob instanceof EntityPokecubeBase) - { - final EntityPokecubeBase cube = (EntityPokecubeBase) mob; - if (cube.canBePickedUp) - { - // This prevents pickup - cube.canBePickedUp = false; - // This makes it send out in 1s regardless of - // hitting anything. - cube.autoRelease = 20; - } - } - } - return; - } - - final int cooldown = this.trainer.getTarget() instanceof PlayerEntity ? this.trainer.getAttackCooldown() : 0; - - // If no mob was found, then it means trainer was not throwing cubes, as - // those are counted along with active pokemobs. - this.aiTracker.setAIState(IHasNPCAIStates.THROWING, false); - // If the trainer is on attack cooldown, then check if to send message - // about next pokemob, or to return early. - if (cooldown > 0) - { - // If no next pokemob, reset trainer and return early. - if (this.trainer.getNextPokemob().isEmpty()) - { - this.aiTracker.setAIState(IHasNPCAIStates.INBATTLE, false); - this.trainer.onLose(this.trainer.getTarget()); - this.trainer.resetPokemob(); - return; - } - // If cooldown is at specific number, send the message for sending - // out next pokemob. - if (cooldown == Config.instance.trainerSendOutDelay / 2) - { - final ItemStack nextStack = this.trainer.getNextPokemob(); - if (!nextStack.isEmpty()) - { - IPokemob next = PokecubeManager.itemToPokemob(nextStack, this.world); - if (next != null) - { - // check if our mob should evolve, if so, do so - while (next.canEvolve(next.getHeldItem())) - { - next = next.evolve(false, false); - nextStack.setTag(PokecubeManager.pokemobToItem(next).getTag()); - } - this.messages.sendMessage(MessageState.ABOUTSEND, this.trainer.getTarget(), this.entity - .getDisplayName(), next.getDisplayName(), this.trainer.getTarget().getDisplayName()); - this.messages.doAction(MessageState.ABOUTSEND, this.trainer.getTarget(), this.entity); - } - } - } - return; - } - // Send next cube at the target. - this.trainer.throwCubeAt(this.trainer.getTarget()); - } - - /** - * @param move - * - the attack to check - * @param user - * - the user of the sttack - * @param target - * - the target of the attack - * @return - the damage that will be dealt by the attack (before reduction - * due to armour) - */ - private int getPower(final String move, final IPokemob user, final Entity target) - { - final Move_Base attack = MovesUtils.getMoveFromName(move); - if (attack == null) return 0; - int pwr = attack.getPWR(user, target); - final IPokemob mob = CapabilityPokemob.getPokemobFor(target); - if (mob != null) pwr *= PokeType.getAttackEfficiency(attack.getType(user), mob.getType1(), mob.getType2()); - return pwr; - } - - /** Resets the task */ - @Override - public void reset() - { - this.trainer.resetPokemob(); - this.trainer.setTarget(null); - this.battleLoc = null; - } - - /** - * Searches for pokemobs most damaging move against the target, and sets it - * as current attack - */ - private void setMostDamagingMove() - { - final IPokemob outMob = this.trainer.getOutMob(); - int index = outMob.getMoveIndex(); - int max = 0; - final Entity target = BrainUtils.getAttackTarget(outMob.getEntity()); - final String[] moves = outMob.getMoves(); - for (int i = 0; i < 4; i++) - { - final String s = moves[i]; - if (s != null) - { - final int temp = this.getPower(s, outMob, target); - if (temp > max) - { - index = i; - max = temp; - } - } - } - outMob.setMoveIndex(index); - } - - @Override - public boolean shouldRun() - { - final LivingEntity target = this.trainer.getTarget(); - if (target == null) return false; - final IHasPokemobs other = TrainerCaps.getHasPokemobs(target); - final boolean hitUs = target.getLastAttackedEntity() == this.entity; - if (!hitUs && other != null && other.getNextPokemob().isEmpty()) - { - if (other.getOutID() != null) - { - final IPokemob outMob = other.getOutMob(); - if (outMob != null && !outMob.getEntity().isAlive()) - { - other.setOutID(null); - other.setOutMob(null); - } - } - if (other.getOutID() == null) - { - final List mobs = PCEventsHandler.getOutMobs(target, false); - if (!mobs.isEmpty()) - { - boolean found = false; - for (final Entity mob : mobs) - if (mob.addedToChunk && mob.getDistanceSq(target) < 32 * 32) - { - final IPokemob pokemob = CapabilityPokemob.getPokemobFor(mob); - if (pokemob != null && !found) - { - other.setOutMob(pokemob); - found = true; - break; - } - } - this.deagrotimer = 20; - } - if (this.deagrotimer-- < 0) - { - this.trainer.onWin(target); - if (other.getTarget() == this.entity) other.onLose(this.entity); - return false; - } - } - } - return true; - } - - @Override - public void tick() - { - // Check if trainer has any pokemobs, if not, cancel agression, no - // reward. - if (this.trainer.getPokemob(0).isEmpty()) - { - this.trainer.deAgro(this.trainer, TrainerCaps.getHasPokemobs(this.trainer.getTarget())); - this.trainer.setTarget(null); - return; - } - - // Stop trainer from pathing if it shouldn't do so during battle - if (!this.canPath && this.entity instanceof MobEntity) - { - if (this.battleLoc == null) this.battleLoc = this.entity.getPosition(); - final PathNavigator navi = ((MobEntity) this.entity).getNavigator(); - if (!navi.noPath() && navi.getPath().getFinalPathPoint().func_224758_c(this.battleLoc) > 1) navi - .clearPath(); - if (this.entity.getPosition().distanceSq(this.battleLoc) > 4) navi.setPath(navi.getPathToPos(this.battleLoc, - 0), 0.75); - } - - this.entity.lookAt(Type.EYES, this.trainer.getTarget().getEyePosition(0)); - - // If target is no longer visbile, forget about it and reset. - if (!Vector3.isVisibleEntityFromEntity(this.entity, this.trainer.getTarget())) - { - if (this.noSeeTicks++ > Config.instance.trainerDeAgressTicks) - { - this.trainer.setTarget(null); - this.trainer.resetPokemob(); - } - return; - } - this.noSeeTicks = 0; - // Check if in range, if too far, target has run away, so forget about - // it. - final double distance = this.entity.getDistanceSq(this.trainer.getTarget()); - if (distance > PokecubeCore.getConfig().chaseDistance * PokecubeCore.getConfig().chaseDistance) - { - this.trainer.setTarget(null); - this.trainer.resetPokemob(); - } - else if (this.trainer.getOutMob() != null && this.trainer.getOutMob().getEntity().isAlive() && this.trainer - .getOutMob().getEntity().addedToChunk) - { - // If trainer has a living, real mob out, tell it to do stuff. - // Check if pokemob has a valid Pokemob as a target. - if (this.checkPokemobTarget()) - { - // If not swapping the pokemob (not implemented), then Ensure - // using best move for target. - if (!this.considerSwapPokemob()) this.considerSwapMove(); - } - // Otherwise, set to most damaging more for non pokemobs. - else this.setMostDamagingMove(); - } - else - { - // Set out mob to null if it is dead so the trainer forgets about - // it. - this.trainer.setOutMob(null); - // Do agression code for sending out next pokemob. - this.doAggression(); - } - } -} diff --git a/src/main/java/pokecube/adventures/ai/tasks/AIMate.java b/src/main/java/pokecube/adventures/ai/tasks/AIMate.java deleted file mode 100644 index 303a8578af..0000000000 --- a/src/main/java/pokecube/adventures/ai/tasks/AIMate.java +++ /dev/null @@ -1,92 +0,0 @@ -package pokecube.adventures.ai.tasks; - -import net.minecraft.entity.AgeableEntity; -import net.minecraft.entity.EntityPredicate; -import net.minecraft.entity.LivingEntity; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.living.BabyEntitySpawnEvent; -import pokecube.adventures.Config; -import pokecube.adventures.capabilities.CapabilityNPCAIStates.IHasNPCAIStates; -import pokecube.adventures.utils.TrainerTracker; -import pokecube.core.PokecubeCore; -import pokecube.core.interfaces.PokecubeMod; -import thut.api.maths.Vector3; - -public class AIMate extends AITrainerBase -{ - AgeableEntity foundMate = null; - final Class targetClass; - final AgeableEntity thisEntity; - AgeableEntity child = null; - int mateTimer = -1; - final EntityPredicate predicate; - - public AIMate(final LivingEntity trainer, final Class targetClass) - { - super(trainer); - this.targetClass = targetClass; - if (trainer instanceof AgeableEntity) this.thisEntity = (AgeableEntity) trainer; - else this.thisEntity = null; - this.predicate = new EntityPredicate().setDistance(8); - } - - @Override - public boolean shouldRun() - { - if (!Config.instance.trainersMate) return false; - return this.thisEntity != null && this.thisEntity.getGrowingAge() == 0 && this.trainer.getGender() == 2 - && this.aiTracker.getAIState(IHasNPCAIStates.MATES) && TrainerTracker.countTrainers(this.world, Vector3 - .getNewVector().set(this.thisEntity), - Config.instance.trainerBox) < Config.instance.trainerDensity * 2; - } - - @Override - public void tick() - { - super.tick(); - if (this.shouldRun()) - { - if (PokecubeMod.debug) PokecubeCore.LOGGER.debug(this.thisEntity + " is Looking for mate"); - this.foundMate = this.world.getClosestEntityWithinAABB(this.targetClass, this.predicate, this.thisEntity, - this.thisEntity.posX, this.thisEntity.posY + this.thisEntity.getEyeHeight(), this.thisEntity.posZ, - this.thisEntity.getBoundingBox().grow(8.0D, 3.0D, 8.0D)); - if (this.foundMate == null) - { - this.thisEntity.setGrowingAge(600); - return; - } - if (this.world.getEntitiesWithinAABB(this.targetClass, this.thisEntity.getBoundingBox().grow(16.0D, 10.0D, - 16.0D)).size() > 3) - { - this.thisEntity.setGrowingAge(6000); - return; - } - this.child = this.thisEntity.createChild(this.foundMate); - this.thisEntity.setGrowingAge(6000); - this.foundMate.setGrowingAge(6000); - final BabyEntitySpawnEvent event = new net.minecraftforge.event.entity.living.BabyEntitySpawnEvent( - this.thisEntity, this.foundMate, this.child); - if (MinecraftForge.EVENT_BUS.post(event) || event.getChild() == null) return; - this.child = event.getChild(); - this.child.setGrowingAge(-24000); - this.mateTimer = 50; - } - if (this.child != null && this.foundMate != null) if (this.mateTimer-- <= 0) - { - this.thisEntity.getNavigator().tryMoveToEntityLiving(this.foundMate, this.thisEntity.getAIMoveSpeed()); - this.foundMate.getNavigator().tryMoveToEntityLiving(this.thisEntity, this.foundMate.getAIMoveSpeed()); - } - else - { - final Vector3 loc = Vector3.getNewVector().set(this.thisEntity.getLookVec()); - loc.y = 0; - loc.norm(); - this.child.setLocationAndAngles(this.thisEntity.posX + loc.x, this.thisEntity.posY, this.thisEntity.posZ - + loc.z, 0.0F, 0.0F); - this.world.addEntity(this.child); - this.world.setEntityState(this.child, (byte) 12); - this.child = null; - this.foundMate = null; - } - } -} diff --git a/src/main/java/pokecube/adventures/ai/tasks/AIRetaliate.java b/src/main/java/pokecube/adventures/ai/tasks/AIRetaliate.java deleted file mode 100644 index 6a945f5b28..0000000000 --- a/src/main/java/pokecube/adventures/ai/tasks/AIRetaliate.java +++ /dev/null @@ -1,60 +0,0 @@ -package pokecube.adventures.ai.tasks; - -import net.minecraft.entity.LivingEntity; -import pokecube.adventures.capabilities.CapabilityHasPokemobs.ITargetWatcher; - -public class AIRetaliate extends AITrainerBase implements ITargetWatcher -{ - - public AIRetaliate(final LivingEntity entityIn) - { - super(entityIn); - this.trainer.addTargetWatcher(this); - } - - @Override - public boolean shouldRun() - { - if (this.trainer.getTarget() != null) return false; - // Dead trainers can't fight. - if (!this.entity.isAlive()) return false; - // Trainers on cooldown shouldn't fight, neither should friendly ones - if (this.trainer.getCooldown() > this.entity.getEntityWorld().getGameTime() || !this.trainer.isAgressive()) - return false; - final LivingEntity target = this.entity.getAttackingEntity(); - return this.isValidTarget(target); - } - - @Override - public void tick() - { - this.updateTask(); - } - - public void updateTask() - { - // If target is valid, return. - if (this.trainer.getTarget() != null) return; - final LivingEntity target = this.entity.getAttackingEntity(); - - if (target != null) - { - // Set trainers target - this.trainer.setTarget(target); - // Ensure no cooldown - this.trainer.setAttackCooldown(-1); - } - } - - @Override - public boolean isValidTarget(final LivingEntity target) - { - if (target == null) return false; - if (!(target.isAlive() && this.entity.canEntityBeSeen(target))) return false; - if (target != null && target.getLastAttackedEntity() == this.entity && target - .getLastAttackedEntityTime() < target.ticksExisted + 20) return true; - final int timer = this.entity.getRevengeTimer(); - final int age = this.entity.ticksExisted - 50; - return this.entity.getAttackingEntity() == target && timer > age; - } -} diff --git a/src/main/java/pokecube/adventures/ai/tasks/AITrainerAgro.java b/src/main/java/pokecube/adventures/ai/tasks/AITrainerAgro.java deleted file mode 100644 index 6f11866614..0000000000 --- a/src/main/java/pokecube/adventures/ai/tasks/AITrainerAgro.java +++ /dev/null @@ -1,277 +0,0 @@ -package pokecube.adventures.ai.tasks; - -import java.util.List; -import java.util.function.Predicate; - -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.MobEntity; -import net.minecraft.util.EntityPredicates; -import pokecube.adventures.PokecubeAdv; -import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs; -import pokecube.adventures.capabilities.CapabilityHasPokemobs.ITargetWatcher; -import pokecube.adventures.capabilities.CapabilityNPCAIStates.IHasNPCAIStates; -import pokecube.adventures.capabilities.TrainerCaps; -import pokecube.adventures.utils.TrainerTracker; -import pokecube.core.PokecubeCore; -import pokecube.core.ai.tasks.combat.AIFindTarget; -import pokecube.core.handlers.events.PCEventsHandler; -import pokecube.core.interfaces.IPokemob; -import pokecube.core.interfaces.capabilities.CapabilityPokemob; -import pokecube.core.utils.AITools; -import thut.api.IOwnable; -import thut.api.OwnableCaps; -import thut.api.maths.Vector3; -import thut.api.terrain.TerrainManager; - -public class AITrainerAgro extends AITrainerBase implements ITargetWatcher -{ - public static boolean canBattle(final LivingEntity input, final LivingEntity mobIn) - { - if (input != null && input.getLastAttackedEntity() == mobIn) return true; - if (mobIn.getRevengeTarget() != null && mobIn.getRevengeTarget() == input) return true; - final IHasPokemobs other = TrainerCaps.getHasPokemobs(input); - if (other == null) return true; - if (other.getTarget() != null && other.getTarget() != mobIn) return false; - if (other.getNextPokemob().isEmpty() && other.getOutID() == null) - { - boolean found = false; - if (other.getOutID() == null) - { - final List mobs = PCEventsHandler.getOutMobs(input, false); - if (!mobs.isEmpty()) for (final Entity mob : mobs) - if (mob.getDistanceSq(input) < 32 * 32) - { - final IPokemob pokemob = CapabilityPokemob.getPokemobFor(mob); - if (pokemob != null && !found) - { - other.setOutMob(pokemob); - found = true; - break; - } - } - } - return found; - } - return true; - } - - @SafeVarargs - public static Predicate match(final LivingEntity entityIn, final boolean allowTamed, - final Class... targetClass) - { - return new Predicate() - { - IHasPokemobs trainer = TrainerCaps.getHasPokemobs(entityIn); - - @Override - public boolean test(final LivingEntity input) - { - if (!AITools.validTargets.test(input)) return false; - - // If the input has attacked us recently, then return true - // regardless of following checks. - if (input.getLastAttackedEntity() == entityIn && input.ticksExisted - input - .getLastAttackedEntityTime() < 50) return true; - - final boolean validClass = this.validClass(input); - final boolean validAgro = input.attackable(); - final boolean canBattle = AITrainerAgro.canBattle(input, entityIn); - - // Only target valid classes. - if (!validClass || !validAgro || !canBattle) return false; - final IOwnable ownable = OwnableCaps.getOwnable(input); - // Don't target pets - if (ownable != null && ownable.getOwner() == entityIn) return false; - // Maybe not target other's pets as well - if (!this.tameCheck(input)) return false; - // Don't target invulnerable players (spectator/creative) - if (!EntityPredicates.CAN_AI_TARGET.test(input)) return false; - // Return true if player can battle the input. - return this.trainer.canBattle(input); - } - - private boolean tameCheck(final LivingEntity input) - { - if (allowTamed) return true; - final IOwnable mob = OwnableCaps.getOwnable(input); - if (mob == null) return true; - return mob.getOwnerId() == null; - } - - private boolean validClass(final LivingEntity input) - { - for (final Class s : targetClass) - if (s.isInstance(input)) return true; - return false; - } - }; - } - - @SafeVarargs - public static Predicate match(final LivingEntity entityIn, - final Class... targetClass) - { - return AITrainerAgro.match(entityIn, false, targetClass); - } - - // Predicated to return true for invalid targets - final Predicate validTargets; - - private float agroChance = 1f; - private int timer = 0; - private final int maxTimer; - - final Vector3 here = Vector3.getNewVector(); - - // This is whether the ai should run for the current task holder - private Predicate shouldRun = e -> true; - - public AITrainerAgro(final LivingEntity entityIn, final float agressionProbability, final int battleTime, - final Predicate validTargets) - { - super(entityIn); - this.trainer.addTargetWatcher(this); - this.maxTimer = battleTime; - this.agroChance = agressionProbability; - this.validTargets = validTargets; - } - - @SafeVarargs - public AITrainerAgro(final LivingEntity entityIn, final Class... targetClass) - { - this(entityIn, 1, -1, targetClass); - } - - @SafeVarargs - public AITrainerAgro(final LivingEntity entityIn, final float agressionProbability, - final Class... targetClass) - { - this(entityIn, agressionProbability, -1, targetClass); - } - - @SafeVarargs - public AITrainerAgro(final LivingEntity entityIn, final float agressionProbability, final int battleTime, - final Class... targetClass) - { - this(entityIn, agressionProbability, battleTime, AITrainerAgro.match(entityIn, targetClass)); - } - - public AITrainerAgro setRunCondition(final Predicate shouldRun) - { - this.shouldRun = shouldRun; - return this; - } - - @Override - public boolean shouldRun() - { - if (!this.shouldRun.test(this.entity)) return false; - if (this.trainer.getTarget() != null) - { - final LivingEntity target = this.trainer.getTarget(); - // Check if timer has run out. - if (this.maxTimer > 0 && this.timer++ >= this.maxTimer) - { - this.timer = 0; - final IHasPokemobs other = TrainerCaps.getHasPokemobs(target); - // this is an ended battle, so we cancel both side. - if (other != null) other.setTarget(null); - - // Lets reset revenge/battle targets as well. - if (target.getRevengeTarget() == this.entity) target.setRevengeTarget(null); - if (this.entity.getRevengeTarget() == target) this.entity.setRevengeTarget(null); - // Reset attack targets as well. - if (target instanceof MobEntity) AIFindTarget.deagro(target); - AIFindTarget.deagro(this.entity); - - this.trainer.setTarget(null); - this.trainer.resetPokemob(); - return false; - } - // Check if target is invalid. - if (!target.isAlive()) - { - this.trainer.setTarget(null); - this.trainer.resetPokemob(); - return false; - } - // check if too far away - if (this.entity.getDistance(target) > PokecubeCore.getConfig().chaseDistance) - { - this.trainer.setTarget(null); - this.trainer.resetPokemob(); - return false; - } - return false; - } - // Dead trainers can't fight. - if (!this.entity.isAlive() || this.entity.ticksExisted % 20 != 0) return false; - // Permfriendly trainers shouldn't fight. - if (this.aiTracker != null && this.aiTracker.getAIState(IHasNPCAIStates.PERMFRIENDLY)) return false; - // Trainers on cooldown shouldn't fight, neither should friendly ones - if (this.trainer.getCooldown() > this.entity.getEntityWorld().getGameTime() || !this.trainer.isAgressive()) - return false; - return true; - } - - @Override - public void tick() - { - if (this.aiTracker != null && this.aiTracker.getAIState(IHasNPCAIStates.FIXEDDIRECTION) && this.trainer - .getTarget() == null) - { - this.entity.setRotationYawHead(this.aiTracker.getDirection()); - this.entity.prevRotationYawHead = this.aiTracker.getDirection(); - this.entity.rotationYawHead = this.aiTracker.getDirection(); - this.entity.rotationYaw = this.aiTracker.getDirection(); - this.entity.prevRotationYaw = this.aiTracker.getDirection(); - } - this.updateTask(); - } - - public void updateTask() - { - // If target is valid, return. - if (this.trainer.getTarget() != null) return; - - // Check random chance of actually aquiring a target. - if (Math.random() > this.agroChance) return; - - // Look for targets - this.here.set(this.entity, true); - LivingEntity target = null; - final int sight = this.trainer.getAgressDistance(); - - if (!TerrainManager.isAreaLoaded(this.world, this.here, sight + 3)) return; - - final Predicate matcher = e -> e instanceof LivingEntity && this.isValidTarget((LivingEntity) e); - final Entity match = this.here.firstEntityExcluding(sight, this.entity.getLook(0), this.world, this.entity, - matcher); - if (match instanceof LivingEntity) target = (LivingEntity) match; - - // If no target, return false. - if (target == null) - { - // If trainer was in battle (any of these 3) reset trainer before - // returning. - if (this.trainer.getOutMob() != null || this.aiTracker.getAIState(IHasNPCAIStates.THROWING) - || this.aiTracker.getAIState(IHasNPCAIStates.INBATTLE)) this.trainer.resetPokemob(); - return; - } - final IHasPokemobs other = TrainerCaps.getHasPokemobs(target); - // Set trainers target - this.trainer.setTarget(target); - if (other != null) other.setTarget(this.entity); - } - - @Override - public boolean isValidTarget(final LivingEntity target) - { - this.here.set(this.entity, true); - final int dist = PokecubeAdv.config.trainer_crowding_radius; - final int num = PokecubeAdv.config.trainer_crowding_number; - if (TrainerTracker.countTrainers(this.world, this.here, dist) > num) return false; - return this.validTargets.test(target); - } -} diff --git a/src/main/java/pokecube/adventures/ai/tasks/AITrainerBase.java b/src/main/java/pokecube/adventures/ai/tasks/AITrainerBase.java deleted file mode 100644 index 5c227038f4..0000000000 --- a/src/main/java/pokecube/adventures/ai/tasks/AITrainerBase.java +++ /dev/null @@ -1,89 +0,0 @@ -package pokecube.adventures.ai.tasks; - -import java.util.List; - -import com.google.common.collect.Lists; - -import net.minecraft.entity.LivingEntity; -import net.minecraft.world.server.ServerWorld; -import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs; -import pokecube.adventures.capabilities.CapabilityNPCAIStates.IHasNPCAIStates; -import pokecube.adventures.capabilities.CapabilityNPCMessages.IHasMessages; -import pokecube.adventures.capabilities.TrainerCaps; -import pokecube.core.ai.tasks.IRunnable; -import thut.api.entity.ai.IAIRunnable; - -public class AITrainerBase implements IAIRunnable -{ - ServerWorld world; - // The trainer Entity - final LivingEntity entity; - final IHasPokemobs trainer; - final IHasNPCAIStates aiTracker; - final IHasMessages messages; - final boolean valid; - int noSeeTicks = 0; - protected List toRun = Lists.newArrayList(); - - int priority = 0; - int mutex = 0; - - public AITrainerBase(final LivingEntity trainer) - { - this.entity = trainer; - this.world = (ServerWorld) trainer.getEntityWorld(); - this.aiTracker = TrainerCaps.getNPCAIStates(trainer); - this.trainer = TrainerCaps.getHasPokemobs(trainer); - this.messages = TrainerCaps.getMessages(trainer); - this.valid = trainer != null && this.aiTracker != null && this.messages != null; - } - - @Override - public void finish() - { - this.toRun.forEach(w -> w.run(this.world)); - this.toRun.clear(); - } - - @Override - public int getMutex() - { - return this.mutex; - } - - @Override - public int getPriority() - { - return this.priority; - } - - @Override - public void reset() - { - } - - @Override - public void run() - { - } - - @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 boolean shouldRun() - { - return true; - } -} diff --git a/src/main/java/pokecube/adventures/ai/tasks/BaseTask.java b/src/main/java/pokecube/adventures/ai/tasks/BaseTask.java new file mode 100644 index 0000000000..f9507629ab --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/BaseTask.java @@ -0,0 +1,49 @@ +package pokecube.adventures.ai.tasks; + +import java.util.Map; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.entity.ai.brain.task.Task; +import net.minecraft.world.server.ServerWorld; +import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs; +import pokecube.adventures.capabilities.CapabilityNPCAIStates.IHasNPCAIStates; +import pokecube.adventures.capabilities.CapabilityNPCMessages.IHasMessages; +import pokecube.adventures.capabilities.TrainerCaps; + +public abstract class BaseTask extends Task +{ + protected ServerWorld world; + // The trainer Entity + protected final LivingEntity entity; + protected final IHasPokemobs trainer; + protected final IHasNPCAIStates aiTracker; + protected final IHasMessages messages; + protected final boolean valid; + + public BaseTask(final LivingEntity trainer, + final Map, MemoryModuleStatus> requiredMemoryStateIn) + { + super(requiredMemoryStateIn); + this.entity = trainer; + this.world = (ServerWorld) trainer.getEntityWorld(); + this.aiTracker = TrainerCaps.getNPCAIStates(trainer); + this.trainer = TrainerCaps.getHasPokemobs(trainer); + this.messages = TrainerCaps.getMessages(trainer); + this.valid = trainer != null && this.aiTracker != null && this.messages != null; + } + + protected boolean canTimeOut() + { + return false; + } + + @Override + protected boolean isTimedOut(final long gameTime) + { + if (!this.canTimeOut()) return false; + return super.isTimedOut(gameTime); + } + +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/Tasks.java b/src/main/java/pokecube/adventures/ai/tasks/Tasks.java new file mode 100644 index 0000000000..cf831f9699 --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/Tasks.java @@ -0,0 +1,86 @@ +package pokecube.adventures.ai.tasks; + +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.mojang.datafixers.util.Pair; + +import net.minecraft.entity.LivingEntity; +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.schedule.Activity; +import net.minecraft.entity.ai.brain.sensor.DummySensor; +import net.minecraft.entity.ai.brain.sensor.SensorType; +import net.minecraft.entity.ai.brain.task.Task; +import pokecube.adventures.PokecubeAdv; +import pokecube.adventures.ai.brain.MemoryTypes; +import pokecube.adventures.ai.tasks.battle.ChooseAttacks; +import pokecube.adventures.ai.tasks.battle.ManageOutMob; +import pokecube.adventures.ai.tasks.battle.ManagePokemobTarget; +import pokecube.adventures.ai.tasks.battle.agro.BaseAgroTask; +import pokecube.adventures.ai.tasks.battle.agro.DeAgro; +import pokecube.adventures.ai.tasks.battle.agro.Retaliate; +import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.brain.MemoryModules; +import pokecube.core.ai.brain.Sensors; +import pokecube.core.ai.npc.Activities; + +public class Tasks +{ + public static final SensorType DUMMY = new SensorType<>(DummySensor::new); + + public static void init() + { + Tasks.DUMMY.setRegistryName(PokecubeAdv.MODID, "dummy_sensor"); + } + + public static final List> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, + SensorType.NEAREST_PLAYERS, SensorType.INTERACTABLE_DOORS, SensorType.HURT_BY, Sensors.VISIBLE_BLOCKS, + Sensors.VISIBLE_ITEMS, Sensors.INTERESTING_MOBS); + + public static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModules.ATTACKTARGET, + MemoryTypes.BATTLETARGET); + + @SuppressWarnings("unchecked") + public static void addBattleTasks(final LivingEntity mob, + final List>> tasks) + { + final Brain brain = mob.getBrain(); + + final List> senses = Lists.newArrayList(Tasks.DUMMY); + for (final SensorType type : Tasks.SENSOR_TYPES) + if (!brain.sensors.containsKey(type)) senses.add(type); + + BrainUtils.addToBrain(brain, Tasks.MEMORY_TYPES, senses); + + final List>> battle_list = Lists.newArrayList(); + final List>> other_list = Lists.newArrayList(); + for (final Pair> task_pair : tasks) + if (task_pair.getSecond() instanceof BaseAgroTask) other_list.add(task_pair); + else battle_list.add(task_pair); + + Task task = new DeAgro(mob); + battle_list.add(Pair.of(1, (Task) task)); + + task = new Retaliate(mob); + other_list.add(Pair.of(1, (Task) task)); + + task = new ChooseAttacks(mob); + battle_list.add(Pair.of(1, (Task) task)); + task = new ManageOutMob(mob); + battle_list.add(Pair.of(1, (Task) task)); + task = new ManagePokemobTarget(mob); + battle_list.add(Pair.of(1, (Task) task)); + + brain.registerActivity(Activities.BATTLE, ImmutableList.copyOf(battle_list), ImmutableSet.of(Pair.of( + MemoryModuleType.VISIBLE_MOBS, MemoryModuleStatus.VALUE_PRESENT))); + + BrainUtils.addToActivity(brain, Activity.CORE, other_list); + BrainUtils.addToActivity(brain, Activity.IDLE, other_list); + BrainUtils.addToActivity(brain, Activities.STATIONARY, other_list); + + } +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/battle/BaseBattleTask.java b/src/main/java/pokecube/adventures/ai/tasks/battle/BaseBattleTask.java new file mode 100644 index 0000000000..2b9d6fafb2 --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/battle/BaseBattleTask.java @@ -0,0 +1,46 @@ +package pokecube.adventures.ai.tasks.battle; + +import java.util.Map; + +import com.google.common.collect.Maps; + +import net.minecraft.entity.LivingEntity; +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.world.server.ServerWorld; +import pokecube.adventures.ai.brain.MemoryTypes; +import pokecube.adventures.ai.tasks.BaseTask; +import pokecube.core.ai.tasks.TaskBase; + +public abstract class BaseBattleTask extends BaseTask +{ + private static final Map, MemoryModuleStatus> MEMS = Maps.newHashMap(); + + static + { + BaseBattleTask.MEMS.put(MemoryTypes.BATTLETARGET, MemoryModuleStatus.VALUE_PRESENT); + } + + protected LivingEntity target; + + public BaseBattleTask(final LivingEntity trainer) + { + super(trainer, BaseBattleTask.MEMS); + } + + public BaseBattleTask(final LivingEntity trainer, final Map, MemoryModuleStatus> mems) + { + super(trainer, TaskBase.merge(BaseBattleTask.MEMS, mems)); + } + + @Override + protected boolean shouldExecute(final ServerWorld worldIn, final LivingEntity owner) + { + final Brain brain = owner.getBrain(); + if (!brain.hasMemory(MemoryTypes.BATTLETARGET)) return false; + this.target = brain.getMemory(MemoryTypes.BATTLETARGET).get(); + return true; + } + +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/AICapture.java b/src/main/java/pokecube/adventures/ai/tasks/battle/CaptureMob.java similarity index 53% rename from src/main/java/pokecube/adventures/ai/tasks/AICapture.java rename to src/main/java/pokecube/adventures/ai/tasks/battle/CaptureMob.java index 8f9cd7182c..7031587f9f 100644 --- a/src/main/java/pokecube/adventures/ai/tasks/AICapture.java +++ b/src/main/java/pokecube/adventures/ai/tasks/battle/CaptureMob.java @@ -1,43 +1,42 @@ -package pokecube.adventures.ai.tasks; +package pokecube.adventures.ai.tasks.battle; import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; +import net.minecraft.world.server.ServerWorld; import pokecube.core.PokecubeItems; import pokecube.core.interfaces.IPokecube; import pokecube.core.interfaces.IPokecube.PokecubeBehavior; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.capabilities.CapabilityPokemob; -public class AICapture extends AITrainerBase +public class CaptureMob extends BaseBattleTask { public static int COOLDOWN = 100; - int cooldown = 0; + long lastTry = 0; - public AICapture(final LivingEntity trainer) + public CaptureMob(final LivingEntity trainer, final float chance) { super(trainer); } @Override - public boolean shouldRun() + protected void startExecuting(final ServerWorld worldIn, final LivingEntity entityIn, final long gameTimeIn) { - return this.trainer.getTarget() != null && this.trainer.countPokemon() < this.trainer.getMaxPokemobCount() / 2; - } - - @Override - public void run() - { - this.cooldown--; final IPokemob targ = CapabilityPokemob.getPokemobFor(this.trainer.getTarget()); - if (targ != null && targ.getOwnerId() == null && targ.getHealth() < targ.getMaxHealth() / 4 - && this.cooldown < 0) + if (targ != null && targ.getOwnerId() == null && gameTimeIn - this.lastTry > CaptureMob.COOLDOWN) { - this.cooldown = AICapture.COOLDOWN; + this.lastTry = gameTimeIn; final ItemStack itemStack = new ItemStack(PokecubeItems.getFilledCube(PokecubeBehavior.DEFAULTCUBE), 1); ((IPokecube) itemStack.getItem()).throwPokecubeAt(this.world, this.entity, itemStack, null, this.trainer .getTarget()); } } + @Override + protected boolean shouldExecute(final ServerWorld worldIn, final LivingEntity owner) + { + if (!super.shouldExecute(worldIn, owner)) return false; + return this.trainer.countPokemon() < this.trainer.getMaxPokemobCount() / 2; + } } diff --git a/src/main/java/pokecube/adventures/ai/tasks/battle/ChooseAttacks.java b/src/main/java/pokecube/adventures/ai/tasks/battle/ChooseAttacks.java new file mode 100644 index 0000000000..7dd301a20c --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/battle/ChooseAttacks.java @@ -0,0 +1,98 @@ +package pokecube.adventures.ai.tasks.battle; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.world.server.ServerWorld; +import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.Move_Base; +import pokecube.core.interfaces.capabilities.CapabilityPokemob; +import pokecube.core.moves.MovesUtils; +import pokecube.core.utils.PokeType; + +public class ChooseAttacks extends BaseBattleTask +{ + public ChooseAttacks(final LivingEntity trainer) + { + super(trainer); + } + + /** + * @param move + * - the attack to check + * @param user + * - the user of the sttack + * @param target + * - the target of the attack + * @return - the damage that will be dealt by the attack (before reduction + * due to armour) + */ + private int getPower(final String move, final IPokemob user, final Entity target) + { + final Move_Base attack = MovesUtils.getMoveFromName(move); + if (attack == null) return 0; + int pwr = attack.getPWR(user, target); + final IPokemob mob = CapabilityPokemob.getPokemobFor(target); + if (mob != null) pwr *= PokeType.getAttackEfficiency(attack.getType(user), mob.getType1(), mob.getType2()); + return pwr; + } + + /** + * Searches for pokemobs most damaging move against the target, and sets it + * as current attack + */ + private void setMostDamagingMove() + { + final IPokemob outMob = this.trainer.getOutMob(); + int index = outMob.getMoveIndex(); + int max = 0; + final Entity target = BrainUtils.getAttackTarget(outMob.getEntity()); + final String[] moves = outMob.getMoves(); + for (int i = 0; i < 4; i++) + { + final String s = moves[i]; + if (s != null) + { + final int temp = this.getPower(s, outMob, target); + if (temp > max) + { + index = i; + max = temp; + } + } + } + outMob.setMoveIndex(index); + } + + private void considerSwapMove() + { + // TODO choose between damaging/stats/status moves + this.setMostDamagingMove(); + } + + @Override + protected void updateTask(final ServerWorld worldIn, final LivingEntity owner, final long gameTime) + { + // If trainer has a living, real mob out, tell it to do stuff. + // Check if pokemob has a valid Pokemob as a target. + if (CapabilityPokemob.getPokemobFor(this.target) != null) + // using best move for target. + this.considerSwapMove(); + // Otherwise just pick whatever does most damage + else this.setMostDamagingMove(); + } + + @Override + protected boolean shouldContinueExecuting(final ServerWorld worldIn, final LivingEntity entityIn, + final long gameTimeIn) + { + return this.trainer.getOutMob() != null; + } + + @Override + protected boolean shouldExecute(final ServerWorld worldIn, final LivingEntity owner) + { + if (!super.shouldExecute(worldIn, owner)) return false; + return this.trainer.getOutMob() != null; + } +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/battle/ManageOutMob.java b/src/main/java/pokecube/adventures/ai/tasks/battle/ManageOutMob.java new file mode 100644 index 0000000000..e8de7e08d8 --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/battle/ManageOutMob.java @@ -0,0 +1,139 @@ +package pokecube.adventures.ai.tasks.battle; + +import java.util.List; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.brain.BrainUtil; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.world.server.ServerWorld; +import pokecube.adventures.Config; +import pokecube.adventures.capabilities.CapabilityNPCAIStates.IHasNPCAIStates; +import pokecube.adventures.capabilities.utils.MessageState; +import pokecube.core.database.Database; +import pokecube.core.database.PokedexEntry; +import pokecube.core.handlers.events.PCEventsHandler; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.capabilities.CapabilityPokemob; +import pokecube.core.items.pokecubes.PokecubeManager; + +public class ManageOutMob extends BaseBattleTask +{ + public ManageOutMob(final LivingEntity trainer) + { + super(trainer); + } + + void doAggression() + { + // Check if maybe mob was sent out, but just not seen + final List mobs = PCEventsHandler.getOutMobs(this.entity, false); + if (!mobs.isEmpty()) + { + boolean found = false; + for (final Entity mob : mobs) + // Ones not added to chunk are in pokecubes, so wait for them to + // exit. + if (mob.isAddedToWorld()) + { + final IPokemob pokemob = CapabilityPokemob.getPokemobFor(mob); + if (pokemob != null && !found) + { + this.trainer.setOutMob(pokemob); + found = true; + } + } + return; + } + if (this.aiTracker.getAIState(IHasNPCAIStates.THROWING)) return; + + final int cooldown = this.trainer.getTarget() instanceof PlayerEntity ? this.trainer.getAttackCooldown() : 0; + + // If no mob was found, then it means trainer was not throwing cubes, as + // those are counted along with active pokemobs. + this.aiTracker.setAIState(IHasNPCAIStates.THROWING, false); + // If the trainer is on attack cooldown, then check if to send message + // about next pokemob, or to return early. + if (cooldown > 0) + { + // If no next pokemob, reset trainer and return early. + if (this.trainer.getNextPokemob().isEmpty()) + { + this.aiTracker.setAIState(IHasNPCAIStates.INBATTLE, false); + this.trainer.onLose(this.trainer.getTarget()); + return; + } + // If cooldown is at specific number, send the message for sending + // out next pokemob. + if (cooldown == Config.instance.trainerSendOutDelay / 2) + { + final ItemStack nextStack = this.trainer.getNextPokemob(); + if (!nextStack.isEmpty()) + { + IPokemob next = PokecubeManager.itemToPokemob(nextStack, this.world); + if (next != null) + { + // check if our mob should evolve, if so, do so + while (next.canEvolve(next.getHeldItem())) + { + next = next.evolve(false, false); + nextStack.setTag(PokecubeManager.pokemobToItem(next).getTag()); + } + this.messages.sendMessage(MessageState.ABOUTSEND, this.trainer.getTarget(), this.entity + .getDisplayName(), next.getDisplayName(), this.trainer.getTarget().getDisplayName()); + this.messages.doAction(MessageState.ABOUTSEND, this.trainer.getTarget(), this.entity); + } + } + } + return; + } + // Send next cube at the target. + this.trainer.throwCubeAt(this.trainer.getTarget()); + } + + private boolean considerSwapPokemob() + { + // TODO check if the target pokemob is bad matchup, consider swapping to + // better choice. + + // check if can mega evolve + final IPokemob out = this.trainer.getOutMob(); + if (this.trainer.canMegaEvolve() && out != null && out.getPokedexEntry().hasMegaForm) + { + final List formes = Database.getFormes(out.getPokedexEntry()); + if (!formes.isEmpty()) + { + final int start = this.entity.getRNG().nextInt(formes.size()); + for (int i = 0; i < formes.size(); i++) + { + final PokedexEntry mega = formes.get((i + start) % formes.size()); + if (mega.isMega) + { + out.megaEvolve(mega); + break; + } + } + } + } + return false; + } + + @Override + protected void updateTask(final ServerWorld worldIn, final LivingEntity owner, final long gameTime) + { + final boolean hasMob = this.trainer.getOutMob() != null; + + BrainUtil.lookAt(this.entity, this.target); + + if (hasMob) this.considerSwapPokemob(); + else this.doAggression(); + } + + @Override + protected boolean shouldContinueExecuting(final ServerWorld worldIn, final LivingEntity entityIn, + final long gameTimeIn) + { + return super.shouldExecute(worldIn, entityIn); + } +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/battle/ManagePokemobTarget.java b/src/main/java/pokecube/adventures/ai/tasks/battle/ManagePokemobTarget.java new file mode 100644 index 0000000000..9f27970f47 --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/battle/ManagePokemobTarget.java @@ -0,0 +1,61 @@ +package pokecube.adventures.ai.tasks.battle; + +import java.util.List; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.world.server.ServerWorld; +import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs; +import pokecube.adventures.capabilities.TrainerCaps; +import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.capabilities.CapabilityPokemob; +import pokecube.core.utils.PokemobTracker; + +public class ManagePokemobTarget extends BaseBattleTask +{ + + public ManagePokemobTarget(final LivingEntity trainer) + { + super(trainer); + } + + @Override + protected void updateTask(final ServerWorld worldIn, final LivingEntity owner, final long gameTime) + { + final IHasPokemobs other = TrainerCaps.getHasPokemobs(this.target); + if (other != null) other.onSetTarget(this.entity, true); + + final IPokemob mob = this.trainer.getOutMob(); + if (mob == null || this.target == null) return; + final LivingEntity mobTarget = BrainUtils.getAttackTarget(mob.getEntity()); + LivingEntity newTarget = this.target; + final IPokemob target = CapabilityPokemob.getPokemobFor(mobTarget); + // Try to send our mob after the target's nearest mob instead. + if (target == null) + { + newTarget = this.target; + final List alternates = PokemobTracker.getMobs(this.target, e -> e.getDistanceSq(this.entity) < 64 + && CapabilityPokemob.getPokemobFor(e) != null); + if (!alternates.isEmpty()) newTarget = (LivingEntity) alternates.get(0); + } + + // check if pokemob's target is same as trainers. + if (mobTarget != newTarget && newTarget != null) BrainUtils.initiateCombat(mob.getEntity(), newTarget); + + } + + @Override + protected boolean shouldContinueExecuting(final ServerWorld worldIn, final LivingEntity entityIn, + final long gameTimeIn) + { + return super.shouldExecute(worldIn, entityIn); + } + + @Override + protected boolean shouldExecute(final ServerWorld worldIn, final LivingEntity owner) + { + if (!super.shouldExecute(worldIn, owner)) return false; + return this.trainer.getOutMob() != null; + } +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/battle/agro/AgroTargets.java b/src/main/java/pokecube/adventures/ai/tasks/battle/agro/AgroTargets.java new file mode 100644 index 0000000000..b961e292a8 --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/battle/agro/AgroTargets.java @@ -0,0 +1,43 @@ +package pokecube.adventures.ai.tasks.battle.agro; + +import java.util.function.Predicate; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.EntityPredicates; +import pokecube.adventures.PokecubeAdv; +import pokecube.adventures.utils.TrainerTracker; +import thut.api.maths.Vector3; + +public class AgroTargets extends BaseAgroTask +{ + // Predicated to return true for invalid targets + final Predicate validTargets; + + // This is whether the ai should run for the current task holder + private Predicate shouldRun = e -> true; + + public AgroTargets(final LivingEntity trainer, final float agressionProbability, final int battleTime, + final Predicate validTargets) + { + super(trainer, agressionProbability, battleTime); + this.validTargets = validTargets; + } + + public AgroTargets setRunCondition(final Predicate shouldRun) + { + this.shouldRun = shouldRun; + return this; + } + + @Override + public boolean isValidTarget(final LivingEntity target) + { + if (!this.shouldRun.test(this.entity)) return false; + if (!EntityPredicates.CAN_AI_TARGET.test(target)) return false; + if (!this.trainer.canBattle(target, false).test()) return false; + final int dist = PokecubeAdv.config.trainer_crowding_radius; + final int num = PokecubeAdv.config.trainer_crowding_number; + if (TrainerTracker.countTrainers(this.world, Vector3.getNewVector().set(this.entity), dist) > num) return false; + return this.validTargets.test(target); + } +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/battle/agro/BaseAgroTask.java b/src/main/java/pokecube/adventures/ai/tasks/battle/agro/BaseAgroTask.java new file mode 100644 index 0000000000..77169d511b --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/battle/agro/BaseAgroTask.java @@ -0,0 +1,124 @@ +package pokecube.adventures.ai.tasks.battle.agro; + +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +import com.google.common.collect.Maps; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.brain.Brain; +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.util.math.Vec3d; +import net.minecraft.world.server.ServerWorld; +import pokecube.adventures.PokecubeAdv; +import pokecube.adventures.ai.brain.MemoryTypes; +import pokecube.adventures.ai.tasks.BaseTask; +import pokecube.adventures.capabilities.CapabilityHasPokemobs.ITargetWatcher; +import thut.api.IOwnable; +import thut.api.OwnableCaps; + +public abstract class BaseAgroTask extends BaseTask implements ITargetWatcher +{ + private static final Map, MemoryModuleStatus> MEMS = Maps.newHashMap(); + + static + { + BaseAgroTask.MEMS.put(MemoryTypes.BATTLETARGET, MemoryModuleStatus.VALUE_ABSENT); + } + + private int timer = 0; + + private final int maxTimer; + + private final float chance; + + LivingEntity target = null; + + public BaseAgroTask(final LivingEntity trainer, final float agressionProbability, final int battleTime) + { + super(trainer, BaseAgroTask.MEMS); + this.trainer.addTargetWatcher(this); + this.maxTimer = battleTime; + this.chance = agressionProbability; + } + + @Override + protected boolean shouldContinueExecuting(final ServerWorld worldIn, final LivingEntity entityIn, + final long gameTimeIn) + { + final Brain brain = this.entity.getBrain(); + if (!brain.hasMemory(MemoryTypes.BATTLETARGET)) return false; + final LivingEntity targ = brain.getMemory(MemoryTypes.BATTLETARGET).get(); + if (targ != this.target) + { + this.timer = 0; + this.target = targ; + } + return this.maxTimer <= 0 || this.timer++ < this.maxTimer; + } + + @Override + protected void updateTask(final ServerWorld worldIn, final LivingEntity owner, final long gameTime) + { + this.timer++; + } + + @Override + protected void startExecuting(final ServerWorld worldIn, final LivingEntity entityIn, final long gameTimeIn) + { + if (this.trainer.getCooldown() > gameTimeIn) return; + if (worldIn.getRandom().nextDouble() > this.chance) return; + final List mobs = this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS).get(); + + // Count tame mobs as their owners, rather than seperately mobs + final Predicate tameChecker = mob -> + { + final IOwnable owned = OwnableCaps.getOwnable(mob); + LivingEntity owner; + if (owned != null && (owner = owned.getOwner(worldIn)) != null) return this.isValidTarget(owner); + return true; + }; + final double s = this.trainer.getAgressDistance(); + final Vec3d start = entityIn.getEyePosition(1); + final Vec3d end = start.add(entityIn.getLook(1).mul(s, s, s)); + + for (LivingEntity mob : mobs) + if (this.isValidTarget(mob) && tameChecker.test(mob)) + { + final boolean lookingAt = mob.getBoundingBox().rayTrace(start, end).isPresent(); + if (!lookingAt) + { + BrainUtil.lookAt(this.entity, mob); + return; + } + final IOwnable owned = OwnableCaps.getOwnable(mob); + LivingEntity owner; + // Agro the owner of the mob, instead of the mob itself in this + // case. + if (owned != null && (owner = owned.getOwner(worldIn)) != null) mob = owner; + this.timer = 0; + this.target = mob; + this.trainer.onSetTarget(mob); + return; + } + } + + @Override + protected boolean shouldExecute(final ServerWorld worldIn, final LivingEntity owner) + { + final Brain brain = owner.getBrain(); + if (brain.hasMemory(MemoryTypes.BATTLETARGET)) return false; + if (owner.ticksExisted % PokecubeAdv.config.trainerAgroRate != 0) return false; + return this.entity.getBrain().hasMemory(MemoryModuleType.VISIBLE_MOBS); + } + + @Override + protected void resetTask(final ServerWorld worldIn, final LivingEntity entityIn, final long gameTimeIn) + { + this.timer = 0; + this.target = null; + } +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/battle/agro/DeAgro.java b/src/main/java/pokecube/adventures/ai/tasks/battle/agro/DeAgro.java new file mode 100644 index 0000000000..46c8a08d3b --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/battle/agro/DeAgro.java @@ -0,0 +1,124 @@ +package pokecube.adventures.ai.tasks.battle.agro; + +import java.util.List; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.brain.Brain; +import net.minecraft.entity.ai.brain.BrainUtil; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import net.minecraft.world.server.ServerWorld; +import pokecube.adventures.Config; +import pokecube.adventures.ai.tasks.battle.BaseBattleTask; +import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs; +import pokecube.adventures.capabilities.TrainerCaps; +import pokecube.core.PokecubeCore; +import pokecube.core.handlers.events.PCEventsHandler; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.capabilities.CapabilityPokemob; + +public class DeAgro extends BaseBattleTask +{ + int deagroTimer = 0; + int noSeeTicks = 0; + + public DeAgro(final LivingEntity trainer) + { + super(trainer); + } + + @Override + protected void updateTask(final ServerWorld worldIn, final LivingEntity owner, final long gameTime) + { + boolean deagro = !this.target.isAlive() || this.target.getHealth() <= 0; + + boolean won = false; + + // Check if trainer has any pokemobs, if not, cancel agression, no + // reward. + if (this.trainer.getPokemob(0).isEmpty()) deagro = true; + + if (!deagro) + { + final double distance = this.entity.getDistanceSq(this.target); + if (distance > PokecubeCore.getConfig().chaseDistance * PokecubeCore.getConfig().chaseDistance) + deagro = true; + } + + if (!deagro && !BrainUtil.canSee(this.entity.getBrain(), this.target)) + { + final boolean timeout = this.noSeeTicks++ > Config.instance.trainerDeAgressTicks; + if (timeout) deagro = true; + else this.noSeeTicks = 0; + } + + final IHasPokemobs other = TrainerCaps.getHasPokemobs(this.target); + + final Brain brain = this.entity.getBrain(); + final LivingEntity lastHitBy = brain.hasMemory(MemoryModuleType.HURT_BY_ENTITY) ? brain.getMemory( + MemoryModuleType.HURT_BY_ENTITY).get() : null; + boolean hitUs = lastHitBy == this.target; + + hitUs = hitUs && this.entity.ticksExisted - this.entity.getLastAttackedEntityTime() > 20; + + if (!deagro && !hitUs && other != null && other.getNextPokemob().isEmpty()) + { + won = true; + if (other.getOutID() != null) + { + final IPokemob outMob = other.getOutMob(); + if (outMob != null && !outMob.getEntity().isAlive()) + { + other.setOutID(null); + other.setOutMob(null); + } + } + if (other.getOutID() == null) + { + final List mobs = PCEventsHandler.getOutMobs(this.target, false); + if (!mobs.isEmpty()) + { + boolean found = false; + for (final Entity mob : mobs) + if (mob.addedToChunk && mob.getDistanceSq(this.target) < 32 * 32) + { + final IPokemob pokemob = CapabilityPokemob.getPokemobFor(mob); + if (pokemob != null && !found) + { + other.setOutMob(pokemob); + found = true; + break; + } + } + if (found) this.deagroTimer = 20; + } + if (this.deagroTimer-- < 0) deagro = true; + } + } + + if (deagro) + { + if (won) + { + this.trainer.onWin(this.target); + if (other.getTarget() == this.entity) other.onLose(this.entity); + } + this.trainer.deAgro(this.trainer, TrainerCaps.getHasPokemobs(this.target)); + } + } + + @Override + protected boolean shouldContinueExecuting(final ServerWorld worldIn, final LivingEntity entityIn, + final long gameTimeIn) + { + return this.shouldExecute(worldIn, entityIn); + } + + @Override + protected void startExecuting(final ServerWorld worldIn, final LivingEntity entityIn, final long gameTimeIn) + { + this.deagroTimer = 20; + this.noSeeTicks = 0; + } + +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/battle/agro/Retaliate.java b/src/main/java/pokecube/adventures/ai/tasks/battle/agro/Retaliate.java new file mode 100644 index 0000000000..189cc83acd --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/battle/agro/Retaliate.java @@ -0,0 +1,49 @@ +package pokecube.adventures.ai.tasks.battle.agro; + +import java.util.Map; + +import com.google.common.collect.Maps; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.brain.Brain; +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.util.EntityPredicates; +import pokecube.core.ai.brain.MemoryModules; + +public class Retaliate extends BaseAgroTask +{ + private static final Map, MemoryModuleStatus> MEMS = Maps.newHashMap(); + + static + { + Retaliate.MEMS.put(MemoryModules.ATTACKTARGET, MemoryModuleStatus.VALUE_ABSENT); + } + + public Retaliate(final LivingEntity trainer) + { + super(trainer, 1, -1); + this.trainer.addTargetWatcher(this); + } + + @Override + public boolean ignoreHasBattled(final LivingEntity target) + { + final Brain brain = this.entity.getBrain(); + if (!brain.hasMemory(MemoryModuleType.HURT_BY_ENTITY)) return false; + return brain.getMemory(MemoryModuleType.HURT_BY_ENTITY).get() == target; + } + + @Override + public boolean isValidTarget(final LivingEntity target) + { + if (target == null) return false; + final Brain brain = this.entity.getBrain(); + if (!brain.hasMemory(MemoryModuleType.HURT_BY_ENTITY)) return false; + if (!(target.isAlive() && BrainUtil.canSee(brain, target))) return false; + if (!EntityPredicates.CAN_AI_TARGET.test(target)) return false; + return brain.getMemory(MemoryModuleType.HURT_BY_ENTITY).get() == target; + } + +} diff --git a/src/main/java/pokecube/adventures/ai/tasks/idle/Mate.java b/src/main/java/pokecube/adventures/ai/tasks/idle/Mate.java new file mode 100644 index 0000000000..3adc09c28c --- /dev/null +++ b/src/main/java/pokecube/adventures/ai/tasks/idle/Mate.java @@ -0,0 +1,19 @@ +package pokecube.adventures.ai.tasks.idle; + +import java.util.Map; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import pokecube.adventures.ai.tasks.BaseTask; + +public class Mate extends BaseTask +{ + + public Mate(final LivingEntity trainer, final Map, MemoryModuleStatus> requiredMemoryStateIn) + { + super(trainer, requiredMemoryStateIn); + // TODO Auto-generated constructor stub + } + +} diff --git a/src/main/java/pokecube/adventures/blocks/afa/AfaContainer.java b/src/main/java/pokecube/adventures/blocks/afa/AfaContainer.java index 3a5fae7a00..e4a4f1360c 100644 --- a/src/main/java/pokecube/adventures/blocks/afa/AfaContainer.java +++ b/src/main/java/pokecube/adventures/blocks/afa/AfaContainer.java @@ -1,14 +1,19 @@ package pokecube.adventures.blocks.afa; +import java.util.List; + +import com.google.common.collect.Lists; + import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.IInventoryChangedListener; import net.minecraft.inventory.container.ContainerType; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.IWorldPosCallable; -import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; +import pokecube.core.PokecubeCore; import pokecube.core.inventory.TexturedSlot; import thut.api.ThutCaps; import thut.api.block.IOwnableTE; @@ -18,17 +23,37 @@ public class AfaContainer extends BaseContainer { public static final ContainerType TYPE = new ContainerType<>(AfaContainer::new); - private static class InvWrapper implements IInventory + public static class InvWrapper implements IInventory { final IItemHandlerModifiable wrapped; final IOwnableTE ownable; + private List listeners; + public InvWrapper(final IItemHandlerModifiable wrapped, final IOwnableTE ownable) { this.wrapped = wrapped; this.ownable = ownable; } + /** + * Add a listener that will be notified when any item in this inventory + * is modified. + */ + public void addListener(final IInventoryChangedListener listener) + { + if (this.listeners == null) this.listeners = Lists.newArrayList(); + this.listeners.add(listener); + } + + /** + * removes the specified IInvBasic from receiving further change notices + */ + public void removeListener(final IInventoryChangedListener listener) + { + this.listeners.remove(listener); + } + @Override public void clear() { @@ -57,24 +82,29 @@ public ItemStack getStackInSlot(final int index) @Override public ItemStack decrStackSize(final int index, final int count) { + this.markDirty(); return this.wrapped.extractItem(index, count, false); } @Override public ItemStack removeStackFromSlot(final int index) { + this.markDirty(); return this.wrapped.extractItem(index, this.wrapped.getStackInSlot(index).getCount(), false); } @Override public void setInventorySlotContents(final int index, final ItemStack stack) { + this.markDirty(); this.wrapped.setStackInSlot(index, stack); } @Override public void markDirty() { + if (this.listeners != null) for (final IInventoryChangedListener iinventorychangedlistener : this.listeners) + iinventorychangedlistener.onInventoryChanged(this); } @Override @@ -85,8 +115,9 @@ public boolean isUsableByPlayer(final PlayerEntity player) } - IInventory inv; - IOwnableTE ownable; + IInventory inv; + IOwnableTE ownable; + public AfaTile tile; public AfaContainer(final int id, final PlayerInventory invIn) { @@ -102,28 +133,28 @@ public AfaContainer(final int id, final PlayerInventory invIn, final IWorldPosCa // Server side if (tile instanceof AfaTile) { - this.ownable = (IOwnableTE) tile.getCapability(ThutCaps.OWNABLE_CAP); - final IItemHandlerModifiable handler = (IItemHandlerModifiable) tile.getCapability( - CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); - this.inv = new InvWrapper(handler, this.ownable); + this.ownable = (IOwnableTE) tile.getCapability(ThutCaps.OWNABLE_CAP).orElse(null); + this.tile = (AfaTile) tile; + this.inv = ((AfaTile) tile).inventory; } }); // Client side if (this.ownable == null) { - final AfaTile tile = new AfaTile(); - this.ownable = (IOwnableTE) tile.getCapability(ThutCaps.OWNABLE_CAP); - final IItemHandlerModifiable handler = (IItemHandlerModifiable) tile.getCapability( - CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); - this.inv = new InvWrapper(handler, this.ownable); + this.tile = new AfaTile(); + this.ownable = (IOwnableTE) this.tile.getCapability(ThutCaps.OWNABLE_CAP).orElse(null); + this.inv = this.tile.inventory; + this.tile.setWorld(PokecubeCore.proxy.getWorld()); } - final int di = 17; - final int dj = 32; + final int di = 12; + final int dj = 36; final int i = 0; final int j = 0; this.addSlot(new TexturedSlot(this.inv, 0, dj - 21 + j * 18, di + i * 18, "pokecube:items/slot_cube")); this.bindPlayerInventory(invIn, -19); + + this.trackIntArray(this.tile.syncValues); } @Override diff --git a/src/main/java/pokecube/adventures/blocks/afa/AfaTile.java b/src/main/java/pokecube/adventures/blocks/afa/AfaTile.java index 0e5dbffbbc..6e0e8010cd 100644 --- a/src/main/java/pokecube/adventures/blocks/afa/AfaTile.java +++ b/src/main/java/pokecube/adventures/blocks/afa/AfaTile.java @@ -4,29 +4,42 @@ import org.nfunk.jep.JEP; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.IInventoryChangedListener; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Hand; +import net.minecraft.util.IIntArray; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvents; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.energy.IEnergyStorage; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import pokecube.adventures.PokecubeAdv; +import pokecube.adventures.network.PacketAFA; import pokecube.core.PokecubeCore; import pokecube.core.blocks.InteractableTile; import pokecube.core.database.abilities.Ability; import pokecube.core.events.pokemob.SpawnEvent; import pokecube.core.interfaces.IPokemob; import pokecube.core.items.pokecubes.PokecubeManager; +import thut.api.ThutCaps; +import thut.api.block.IOwnableTE; import thut.api.item.ItemList; import thut.api.maths.Vector3; +import thut.core.common.network.TileUpdate; -public class AfaTile extends InteractableTile implements ITickableTileEntity, IEnergyStorage +public class AfaTile extends InteractableTile implements ITickableTileEntity, IEnergyStorage, IInventoryChangedListener { public static TileEntityType TYPE; public static final ResourceLocation SHINYTAG = new ResourceLocation(PokecubeAdv.MODID, @@ -60,32 +73,86 @@ public static void initParser(final String function, final String functionS) AfaTile.parserS.parseExpression(functionS); } + public final IIntArray syncValues = new IIntArray() + { + + @Override + public int get(final int index) + { + switch (index) + { + case 0: + return AfaTile.this.orig; + case 1: + return AfaTile.this.distance; + case 2: + return AfaTile.this.cost; + } + return 0; + } + + @Override + public void set(final int index, final int value) + { + switch (index) + { + case 0: + AfaTile.this.orig = value; + break; + case 1: + AfaTile.this.distance = value; + break; + case 2: + AfaTile.this.cost = value; + break; + } + } + + @Override + public int size() + { + // TODO Auto-generated method stub + return 3; + } + + }; + private final IItemHandlerModifiable itemstore; - public IPokemob pokemob = null; - boolean shiny = false; - public int[] shift = { 0, 0, 0 }; - public int scale = 1000; - public String animation = "idle"; - public Ability ability = null; - public int distance = 4; - public int transparency = 128; - public boolean rotates = true; - public float angle = 0; - public boolean noEnergy = false; - public boolean frozen = true; - public float animationTime = 0; - - public int energy = 0; - boolean noEnergyNeed = false; + public final IInventory inventory; + + public IPokemob pokemob = null; + boolean shiny = false; + public int[] shift = { 0, 0, 0 }; + public int scale = 1000; + public String animation = "idle"; + public Ability ability = null; + public int distance = 4; + public int transparency = 128; + public boolean rotates = true; + public float angle = 0; + public boolean noEnergy = false; + public boolean frozen = true; + public float animationTime = 0; + + public int orig = 0; + public int energy = 0; + public int cost = 0; + + int tick = 0; + + boolean noEnergyNeed = false; public AfaTile() { super(AfaTile.TYPE); this.itemstore = (IItemHandlerModifiable) this.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) .orElse(null); + this.inventory = new AfaContainer.InvWrapper(this.itemstore, (IOwnableTE) this.getCapability( + ThutCaps.OWNABLE_CAP).orElse(null)); + ((AfaContainer.InvWrapper) this.inventory).addListener(this); } - public void refreshAbility() + public void refreshAbility(final boolean update) { if (this.pokemob != null) { @@ -109,52 +176,59 @@ public void refreshAbility() this.pokemob.getEntity().setPosition(this.getPos().getX() + 0.5, this.getPos().getY() + 0.5, this.getPos() .getZ() + 0.5); this.ability.init(this.pokemob, this.distance); + if (this.getWorld() instanceof ServerWorld && update) TileUpdate.sendUpdate(this); } } + @Override + public void onLoad() + { + super.onLoad(); + this.refreshAbility(false); + } + @Override public void tick() { - final ItemStack stack = this.itemstore.getStackInSlot(0); - if (!stack.isEmpty() && this.pokemob == null) this.refreshAbility(); - else if (stack.isEmpty()) this.refreshAbility(); + if (!(this.getWorld() instanceof ServerWorld)) return; + if (this.tick++ % PokecubeAdv.config.afaTickRate != 0) return; - boolean shouldUseEnergy = this.pokemob != null && this.ability != null; int levelFactor = 0; + if (this.pokemob != null) levelFactor = this.pokemob.getLevel(); + double value = 0; + if (this.shiny) + { + AfaTile.parserS.setVarValue("d", this.distance); + value = AfaTile.parserS.getValue(); + } + else if (this.pokemob != null) + { + AfaTile.parser.setVarValue("l", levelFactor); + AfaTile.parser.setVarValue("d", this.distance); + value = AfaTile.parser.getValue(); + } + this.cost = (int) Math.ceil(value); + + boolean shouldUseEnergy = this.pokemob != null && this.ability != null && !this.noEnergy; if (this.pokemob != null && this.ability != null) this.shiny = false; - if (shouldUseEnergy) if (!this.noEnergy && !this.world.isRemote) + if (shouldUseEnergy && this.energy < this.cost) { - double value; - if (this.shiny) - { - AfaTile.parserS.setVarValue("d", this.distance); - value = AfaTile.parserS.getValue(); - } - else - { - AfaTile.parser.setVarValue("l", levelFactor); - AfaTile.parser.setVarValue("d", this.distance); - value = AfaTile.parser.getValue(); - } - final int needed = (int) Math.ceil(value); - if (this.energy < needed) - { - this.energy = 0; - return; - } - else this.energy -= needed; + this.energy = 0; + return; } + else this.energy -= this.cost; + + final boolean hasEnergy = !shouldUseEnergy || this.energy >= 0; - if (this.pokemob != null && this.ability != null) + if (this.pokemob != null && this.ability != null && hasEnergy) { this.shiny = false; // Tick increase incase ability tracks this for update. // Renderer can also then render it animated. this.pokemob.getEntity().ticksExisted++; - levelFactor = this.pokemob.getLevel(); // Do not call ability update on client. - if (!this.world.isRemote) this.ability.onUpdate(this.pokemob); + this.ability.onUpdate(this.pokemob); } shouldUseEnergy = shouldUseEnergy || this.shiny; } @@ -191,6 +265,7 @@ public void read(final CompoundNBT nbt) this.animationTime = nbt.getFloat("animTime"); this.animation = nbt.getString("animation"); this.shiny = ItemList.is(AfaTile.SHINYTAG, this.itemstore.getStackInSlot(0)); + this.orig = this.energy; } @Override @@ -216,10 +291,11 @@ public CompoundNBT write(final CompoundNBT nbt) public int receiveEnergy(final int maxReceive, final boolean simulate) { int var = maxReceive; - if (maxReceive + this.energy < this.getMaxEnergyStored()) var = this.getMaxEnergyStored() - this.energy; + if (maxReceive + this.energy > this.getMaxEnergyStored()) var = this.getMaxEnergyStored() - this.energy; if (!simulate) this.energy += var; this.energy = Math.max(0, this.energy); this.energy = Math.min(this.getMaxEnergyStored(), this.energy); + this.orig = this.energy; return var; } @@ -266,6 +342,14 @@ public void spawnEvent(final SpawnEvent.Post evt) } } + @Override + public boolean onInteract(final BlockPos pos, final PlayerEntity player, final Hand hand, + final BlockRayTraceResult hit) + { + if (player instanceof ServerPlayerEntity) PacketAFA.openGui((ServerPlayerEntity) player, this); + return true; + } + @Override public int getEnergyStored() { @@ -275,7 +359,7 @@ public int getEnergyStored() @Override public int getMaxEnergyStored() { - return PokecubeAdv.config.warpPadMaxEnergy; + return PokecubeAdv.config.afaMaxEnergy; } @Override @@ -289,4 +373,10 @@ public boolean canReceive() { return true; } + + @Override + public void onInventoryChanged(final IInventory invBasic) + { + this.refreshAbility(true); + } } diff --git a/src/main/java/pokecube/adventures/blocks/commander/CommanderBlock.java b/src/main/java/pokecube/adventures/blocks/commander/CommanderBlock.java index ad0f63d379..d766c65868 100644 --- a/src/main/java/pokecube/adventures/blocks/commander/CommanderBlock.java +++ b/src/main/java/pokecube/adventures/blocks/commander/CommanderBlock.java @@ -45,7 +45,7 @@ public void neighborChanged(final BlockState state, final World world, final Blo } catch (final Exception e) { - PokecubeMod.LOGGER.warn("Invalid Commander Block use at " + pos, e); + PokecubeMod.LOGGER.warn("Invalid Commander Block use at " + pos + " " + e.getMessage()); } commander.power = power; } diff --git a/src/main/java/pokecube/adventures/blocks/commander/CommanderTile.java b/src/main/java/pokecube/adventures/blocks/commander/CommanderTile.java index 5ad9f4f1e6..09148e62e1 100644 --- a/src/main/java/pokecube/adventures/blocks/commander/CommanderTile.java +++ b/src/main/java/pokecube/adventures/blocks/commander/CommanderTile.java @@ -120,7 +120,7 @@ private Object[] getArgs() throws Exception private Object[] getArgs(final Constructor constructor) { - final String[] args = this.args.split(","); + final String[] args = this.args.split(" "); final Class[] argTypes = constructor.getParameterTypes(); int index = 0; final Object[] ret = new Object[argTypes.length]; @@ -130,9 +130,8 @@ private Object[] getArgs(final Constructor constructor) if (type == Vector3.class) { final Vector3 arg = Vector3.getNewVector(); - arg.set(Double.parseDouble(args[index]) + this.getPos().getX(), - Double.parseDouble(args[index + 1]) + this.getPos().getY(), - Double.parseDouble(args[index + 2]) + this.getPos().getZ()); + arg.set(Double.parseDouble(args[index]), Double.parseDouble(args[index + 1]), Double.parseDouble( + args[index + 2])); index += 3; ret[i] = arg; } diff --git a/src/main/java/pokecube/adventures/blocks/genetics/cloner/ClonerTile.java b/src/main/java/pokecube/adventures/blocks/genetics/cloner/ClonerTile.java index 845a7b4571..656c59b1bf 100644 --- a/src/main/java/pokecube/adventures/blocks/genetics/cloner/ClonerTile.java +++ b/src/main/java/pokecube/adventures/blocks/genetics/cloner/ClonerTile.java @@ -17,7 +17,7 @@ import pokecube.adventures.blocks.genetics.helper.ClonerHelper; import pokecube.adventures.blocks.genetics.helper.GeneticsTileParentable; import pokecube.adventures.blocks.genetics.helper.recipe.PoweredRecipe; -import pokecube.adventures.blocks.genetics.helper.recipe.RecipeFossilRevive; +import pokecube.adventures.blocks.genetics.helper.recipe.RecipeClone; import thut.api.item.ItemList; public class ClonerTile extends GeneticsTileParentable @@ -72,7 +72,7 @@ public boolean isItemValidForSlot(final int index, final ItemStack stack) @Override public boolean isValid(final Class recipe) { - return recipe == RecipeFossilRevive.class; + return recipe == RecipeClone.class; } @Override diff --git a/src/main/java/pokecube/adventures/blocks/genetics/helper/BaseGeneticsTile.java b/src/main/java/pokecube/adventures/blocks/genetics/helper/BaseGeneticsTile.java index 5d44e26955..6cd705ddf3 100644 --- a/src/main/java/pokecube/adventures/blocks/genetics/helper/BaseGeneticsTile.java +++ b/src/main/java/pokecube/adventures/blocks/genetics/helper/BaseGeneticsTile.java @@ -162,9 +162,9 @@ public boolean canExtractItem(final int index, final ItemStack stack, final Dire * Returns true if automation can insert the given item in the given slot * from the given side. */ - public boolean canInsertItem(final int index, final ItemStack itemStackIn, final Direction direction) + public boolean canInsertItem(final int index, final ItemStack stack, final Direction direction) { - return this.isItemValidForSlot(index, itemStackIn); + return this.isItemValidForSlot(index, stack); } public void checkRecipes() diff --git a/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/PoweredProcess.java b/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/PoweredProcess.java index b7d0daa116..a5884716f3 100644 --- a/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/PoweredProcess.java +++ b/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/PoweredProcess.java @@ -16,13 +16,13 @@ public class PoweredProcess "pokecube_adventures:extracting")); public static final RecipeSplice SPLICE = new RecipeSplice(new ResourceLocation( "pokecube_adventures:splicing")); - public static final RecipeFossilRevive REVIVE = new RecipeFossilRevive(new ResourceLocation( + public static final RecipeClone REVIVE = new RecipeClone(new ResourceLocation( "pokecube_adventures:reviving")); public static PoweredRecipe findRecipe(final IPoweredProgress tile, final World world) { if (!tile.getStackInSlot(tile.getOutputSlot()).isEmpty()) return null; - if (tile.isValid(RecipeFossilRevive.class) && PoweredProcess.REVIVE.matches(tile.getCraftMatrix(), world)) + if (tile.isValid(RecipeClone.class) && PoweredProcess.REVIVE.matches(tile.getCraftMatrix(), world)) return PoweredProcess.REVIVE; if (tile.isValid(RecipeExtract.class) && !PoweredProcess.EXTRACT.getCraftingResult(tile.getCraftMatrix()) .isEmpty()) return PoweredProcess.EXTRACT; @@ -36,7 +36,7 @@ public static void init(final Register> event) RecipeSelector.SERIALIZER.toString(); RecipeExtract.SERIALIZER.toString(); RecipeSplice.SERIALIZER.toString(); - RecipeFossilRevive.SERIALIZER.toString(); + RecipeClone.SERIALIZER.toString(); // This one needs registration as is actually a real crafting recipe. event.getRegistry().register(RecipeSelector.SERIALIZER.setRegistryName(new ResourceLocation( diff --git a/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeFossilRevive.java b/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeClone.java similarity index 80% rename from src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeFossilRevive.java rename to src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeClone.java index fc3aaa38fb..54fb76892d 100644 --- a/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeFossilRevive.java +++ b/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeClone.java @@ -36,7 +36,7 @@ import pokecube.core.utils.Tools; import thut.api.entity.genetics.IMobGenetics; -public class RecipeFossilRevive extends PoweredRecipe +public class RecipeClone extends PoweredRecipe { public static class AnyMatcher implements ReviveMatcher @@ -48,7 +48,7 @@ public boolean complete(final IPoweredProgress tile) { final World world = ((TileEntity) tile).getWorld(); final BlockPos pos = ((TileEntity) tile).getPos(); - final PokedexEntry entry = RecipeFossilRevive.getEntry(this, tile); + final PokedexEntry entry = RecipeClone.getEntry(this, tile); if (entry == Database.missingno) return false; final boolean tame = !entry.isLegendary(); MobEntity entity = PokecubeCore.createPokemob(entry, world); @@ -60,22 +60,24 @@ public boolean complete(final IPoweredProgress tile) entity.setHealth(entity.getMaxHealth()); // to avoid the death on spawn final int exp = Tools.levelToXp(entry.getEvolutionMode(), AnyMatcher.level); - // that will make your pokemob around level 3-5. - // You can give him more XP if you want - entity = (pokemob = pokemob.setForSpawn(exp)).getEntity(); + + final IMobGenetics genes = ClonerHelper.getGenes(dnaSource); + if (genes != null) GeneticsManager.initFromGenes(genes, pokemob); + pokemob.getEntity().getPersistentData().putInt("spawnExp", exp); + pokemob = pokemob.spawnInit(); + if (tile.getUser() != null && tame) pokemob.setOwner(tile.getUser().getUniqueID()); - final Direction dir = world.getBlockState(pos).get(HorizontalBlock.HORIZONTAL_FACING); - entity.setLocationAndAngles(pos.getX() + 0.5 + dir.getXOffset(), pos.getY() + 1, pos.getZ() + 0.5 + dir - .getZOffset(), world.rand.nextFloat() * 360F, 0.0F); - entity.getPersistentData().putBoolean("cloned", true); final CloneEvent.Spawn event = new CloneEvent.Spawn((ClonerTile) tile, pokemob); if (PokecubeCore.POKEMOB_BUS.post(event)) return false; + pokemob = event.getPokemob(); entity = pokemob.getEntity(); + final Direction dir = world.getBlockState(pos).get(HorizontalBlock.HORIZONTAL_FACING); + entity.setLocationAndAngles(pos.getX() + 0.5 + dir.getXOffset(), pos.getY() + 1, pos.getZ() + 0.5 + dir + .getZOffset(), world.rand.nextFloat() * 360F, 0.0F); + entity.getPersistentData().putBoolean("cloned", true); world.addEntity(entity); - final IMobGenetics genes = ClonerHelper.getGenes(dnaSource); - if (genes != null) GeneticsManager.initFromGenes(genes, pokemob); entity.playAmbientSound(); } return true; @@ -120,7 +122,7 @@ default int priority() default int getEnergyCost() { - return RecipeFossilRevive.ENERGYCOST; + return RecipeClone.ENERGYCOST; } default boolean shouldKeep(final ItemStack stack) @@ -129,14 +131,14 @@ default boolean shouldKeep(final ItemStack stack) } } - public static int ENERGYCOST = 10000; - public static final IRecipeSerializer SERIALIZER = IRecipeSerializer.register( - "pokecube_adventures:reviving", new SpecialRecipeSerializer<>(RecipeFossilRevive::new)); + public static int ENERGYCOST = 10000; + public static final IRecipeSerializer SERIALIZER = IRecipeSerializer.register( + "pokecube_adventures:reviving", new SpecialRecipeSerializer<>(RecipeClone::new)); - public static Function ENERGYNEED = (s) -> RecipeFossilRevive.ENERGYCOST; - private static List recipeList = Lists.newArrayList(); + public static Function ENERGYNEED = (s) -> RecipeClone.ENERGYCOST; + private static List recipeList = Lists.newArrayList(); - private static HashMap entryMap = Maps.newHashMap(); + private static HashMap entryMap = Maps.newHashMap(); public static ReviveMatcher ANYMATCHER = new AnyMatcher(); public static final List MATCHERS = Lists.newArrayList(); @@ -152,17 +154,17 @@ public static PokedexEntry getEntry(final ReviveMatcher matcher, final IPoweredP return entry; } - public static RecipeFossilRevive getRecipe(final PokedexEntry entry) + public static RecipeClone getRecipe(final PokedexEntry entry) { - return RecipeFossilRevive.entryMap.get(entry); + return RecipeClone.entryMap.get(entry); } - public static List getRecipeList() + public static List getRecipeList() { - return Lists.newArrayList(RecipeFossilRevive.recipeList); + return Lists.newArrayList(RecipeClone.recipeList); } - public RecipeFossilRevive(final ResourceLocation loc) + public RecipeClone(final ResourceLocation loc) { super(loc); } @@ -177,9 +179,9 @@ public boolean canFit(final int width, final int height) public boolean complete(final IPoweredProgress tile) { boolean completed = false; - for (final ReviveMatcher matcher : RecipeFossilRevive.MATCHERS) + for (final ReviveMatcher matcher : RecipeClone.MATCHERS) if (completed = matcher.complete(tile)) break; - if (!completed) completed = RecipeFossilRevive.ANYMATCHER.complete(tile); + if (!completed) completed = RecipeClone.ANYMATCHER.complete(tile); if (completed) { final List remaining = Lists.newArrayList(this.getRemainingItems(tile.getCraftMatrix())); @@ -203,7 +205,7 @@ public boolean complete(final IPoweredProgress tile) @Override public Function getCostFunction() { - return RecipeFossilRevive.ENERGYNEED; + return RecipeClone.ENERGYNEED; } @Override @@ -215,32 +217,32 @@ public ItemStack getCraftingResult(final CraftingInventory inv) @Override public int getEnergyCost(final IPoweredProgress tile) { - for (final ReviveMatcher matcher : RecipeFossilRevive.MATCHERS) - if (RecipeFossilRevive.getEntry(matcher, tile) != Database.missingno) return matcher.getEnergyCost(); - return RecipeFossilRevive.ANYMATCHER.getEnergyCost(); + for (final ReviveMatcher matcher : RecipeClone.MATCHERS) + if (RecipeClone.getEntry(matcher, tile) != Database.missingno) return matcher.getEnergyCost(); + return RecipeClone.ANYMATCHER.getEnergyCost(); } public PokedexEntry getPokedexEntry(final IPoweredProgress tile) { PokedexEntry entry = Database.missingno; - for (final ReviveMatcher matcher : RecipeFossilRevive.MATCHERS) - if ((entry = RecipeFossilRevive.getEntry(matcher, tile)) != Database.missingno) return entry; - return RecipeFossilRevive.getEntry(RecipeFossilRevive.ANYMATCHER, tile); + for (final ReviveMatcher matcher : RecipeClone.MATCHERS) + if ((entry = RecipeClone.getEntry(matcher, tile)) != Database.missingno) return entry; + return RecipeClone.getEntry(RecipeClone.ANYMATCHER, tile); } @Override public IRecipeSerializer getSerializer() { - return RecipeFossilRevive.SERIALIZER; + return RecipeClone.SERIALIZER; } /** Used to check if a recipe matches current crafting inventory */ @Override public boolean matches(final CraftingInventory inv, final World worldIn) { - for (final ReviveMatcher matcher : RecipeFossilRevive.MATCHERS) + for (final ReviveMatcher matcher : RecipeClone.MATCHERS) if (matcher.getEntry(inv, worldIn) != Database.missingno) return true; - return RecipeFossilRevive.ANYMATCHER.getEntry(inv, worldIn) != Database.missingno; + return RecipeClone.ANYMATCHER.getEntry(inv, worldIn) != Database.missingno; } @Override @@ -251,8 +253,8 @@ public NonNullList getRemainingItems(final CraftingInventory inv) final PoweredCraftingInventory inv_p = (PoweredCraftingInventory) inv; if (!(inv_p.inventory instanceof ClonerTile)) return nonnulllist; final ClonerTile tile = (ClonerTile) inv_p.inventory; - ReviveMatcher matcher = RecipeFossilRevive.ANYMATCHER; - for (final ReviveMatcher matcher2 : RecipeFossilRevive.MATCHERS) + ReviveMatcher matcher = RecipeClone.ANYMATCHER; + for (final ReviveMatcher matcher2 : RecipeClone.MATCHERS) if (matcher2.getEntry(inv, tile.getWorld()) != Database.missingno) { matcher = matcher2; diff --git a/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeExtract.java b/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeExtract.java index b978316995..951b1a9b7e 100644 --- a/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeExtract.java +++ b/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeExtract.java @@ -8,6 +8,7 @@ import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.SpecialRecipeSerializer; import net.minecraft.nbt.CompoundNBT; @@ -141,8 +142,19 @@ public NonNullList getRemainingItems(final CraftingInventory inv) for (int i = 0; i < nonnulllist.size(); ++i) { final ItemStack item = inv.getStackInSlot(i); - if (i == 0 && keepDNA) nonnulllist.set(i, item); if (i == 1 && keepSelector) nonnulllist.set(i, item); + if (i == 2) + { + final boolean potion = item.getItem() == Items.POTION; + final boolean multiple = item.getCount() > 1; + if (keepDNA) nonnulllist.set(i, item); + else if (potion) nonnulllist.set(i, new ItemStack(Items.GLASS_BOTTLE)); + else if (!multiple) + { + item.setTag(null); + nonnulllist.set(i, item.copy()); + } + } if (item.hasContainerItem()) nonnulllist.set(i, item.getContainerItem()); } tile.override_selector = ItemStack.EMPTY; diff --git a/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeHandlers.java b/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeHandlers.java index 421bb3fd51..b0839dd4a1 100644 --- a/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeHandlers.java +++ b/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeHandlers.java @@ -23,8 +23,8 @@ import pokecube.adventures.blocks.genetics.cloner.ClonerTile; import pokecube.adventures.blocks.genetics.helper.ClonerHelper; import pokecube.adventures.blocks.genetics.helper.ClonerHelper.DNAPack; -import pokecube.adventures.blocks.genetics.helper.recipe.RecipeFossilRevive.AnyMatcher; -import pokecube.adventures.blocks.genetics.helper.recipe.RecipeFossilRevive.ReviveMatcher; +import pokecube.adventures.blocks.genetics.helper.recipe.RecipeClone.AnyMatcher; +import pokecube.adventures.blocks.genetics.helper.recipe.RecipeClone.ReviveMatcher; import pokecube.adventures.blocks.genetics.helper.recipe.RecipeSelector.SelectorValue; import pokecube.adventures.events.CloneEvent; import pokecube.core.PokecubeCore; @@ -68,7 +68,7 @@ public static class RecipeMatcher implements ReviveMatcher boolean tame = false; int level = AnyMatcher.level; int priority = 100; - int energy = RecipeFossilRevive.ENERGYCOST; + int energy = RecipeClone.ENERGYCOST; public RecipeMatcher(final PokedexEntry entry) { @@ -80,7 +80,7 @@ public boolean complete(final IPoweredProgress tile) { final World world = ((TileEntity) tile).getWorld(); final BlockPos pos = ((TileEntity) tile).getPos(); - final PokedexEntry entry = RecipeFossilRevive.getEntry(this, tile); + final PokedexEntry entry = RecipeClone.getEntry(this, tile); if (entry == Database.missingno) return false; final boolean tame = !entry.isLegendary() && this.tame; MobEntity entity = PokecubeCore.createPokemob(entry, world); @@ -218,8 +218,8 @@ public void manageRecipe(final XMLRecipe recipe) throws NullPointerException for (final String s : remain) matcher.remains.add(Integer.parseInt(s)); } - RecipeFossilRevive.MATCHERS.add(matcher); - RecipeFossilRevive.MATCHERS.sort((o1, o2) -> o1.priority() - o2.priority()); + RecipeClone.MATCHERS.add(matcher); + RecipeClone.MATCHERS.sort((o1, o2) -> o1.priority() - o2.priority()); } } diff --git a/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeSplice.java b/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeSplice.java index 02431b9ebc..483e1f4f07 100644 --- a/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeSplice.java +++ b/src/main/java/pokecube/adventures/blocks/genetics/helper/recipe/RecipeSplice.java @@ -112,8 +112,8 @@ public NonNullList getRemainingItems(final CraftingInventory inv) { final ItemStack item = inv.getStackInSlot(i); if (i == 0 && keepDNA) nonnulllist.set(i, item); + else if (i == 0 && item.getItem() == Items.POTION) nonnulllist.set(i, new ItemStack(Items.GLASS_BOTTLE)); if (i == 1 && keepSelector) nonnulllist.set(i, item); - if (i == 0 && item.getItem() == Items.POTION) nonnulllist.set(i, new ItemStack(Items.GLASS_BOTTLE)); if (item.hasContainerItem()) nonnulllist.set(i, item.getContainerItem()); } tile.override_selector = ItemStack.EMPTY; diff --git a/src/main/java/pokecube/adventures/capabilities/CapabilityHasPokemobs.java b/src/main/java/pokecube/adventures/capabilities/CapabilityHasPokemobs.java index b644291d73..056df1e7d4 100644 --- a/src/main/java/pokecube/adventures/capabilities/CapabilityHasPokemobs.java +++ b/src/main/java/pokecube/adventures/capabilities/CapabilityHasPokemobs.java @@ -10,6 +10,9 @@ import net.minecraft.entity.Entity; 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.schedule.Activity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; @@ -17,7 +20,6 @@ import net.minecraft.nbt.INBT; import net.minecraft.nbt.ListNBT; import net.minecraft.util.Direction; -import net.minecraft.util.EntityPredicates; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ICapabilitySerializable; @@ -25,6 +27,7 @@ import net.minecraftforge.common.util.LazyOptional; import pokecube.adventures.Config; import pokecube.adventures.advancements.Triggers; +import pokecube.adventures.ai.brain.MemoryTypes; import pokecube.adventures.capabilities.CapabilityHasRewards.IHasRewards; import pokecube.adventures.capabilities.CapabilityNPCAIStates.IHasNPCAIStates; import pokecube.adventures.capabilities.CapabilityNPCMessages.IHasMessages; @@ -34,10 +37,13 @@ import pokecube.adventures.entity.trainer.TrainerBase; import pokecube.adventures.network.PacketTrainer; import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.npc.Activities; import pokecube.core.handlers.events.EventsHandler; import pokecube.core.interfaces.IPokecube; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.capabilities.CapabilityPokemob; +import pokecube.core.items.pokecubes.EntityPokecubeBase; import pokecube.core.items.pokecubes.PokecubeManager; import thut.api.maths.Vector3; import thut.api.world.mobs.data.DataSync; @@ -173,23 +179,23 @@ public ListNBT save() private int nextSlot; // Cooldown between sending out pokemobs private int attackCooldown = 0; + // Cooldown between agression - private long cooldown = 0; - private int sight = -1; - private TypeTrainer type; - protected LivingEntity target; - private UUID outID; - private boolean canMegaEvolve = false; - private IPokemob outMob; - private LevelMode levelmode = LevelMode.CONFIG; - private final Set watchers = Sets.newHashSet(); + private long cooldown = 0; + private int sight = -1; + private TypeTrainer type; + private UUID outID; + private boolean canMegaEvolve = false; + private IPokemob outMob; + private LevelMode levelmode = LevelMode.CONFIG; + + private final Set watchers = Sets.newHashSet(); public final DataParamHolder holder = new DataParamHolder(); private DataSync datasync; public DefaultPokemobs() { - this.addTargetWatcher((e) -> EntityPredicates.CAN_AI_TARGET.test(e)); } @Override @@ -200,20 +206,25 @@ public void addTargetWatcher(final ITargetWatcher watcher) } @Override - public boolean canBattle(final LivingEntity target, final boolean checkWatcher) + public AllowedBattle canBattle(final LivingEntity target, final boolean checkWatcher) { + boolean ignoreBattled = false; + if (checkWatcher && target != null) for (final ITargetWatcher w : this.watchers) + ignoreBattled = ignoreBattled || w.ignoreHasBattled(target); + + // No battling if we have defeated or been defeated + if (!ignoreBattled) if (this.defeatedBy(target) || this.defeated(target)) return AllowedBattle.NOTNOW; + final IHasPokemobs trainer = TrainerCaps.getHasPokemobs(target); // No battling a target already battling something - if (trainer != null && trainer.getTarget() != null && trainer.getTarget() != target) return false; - // No battling if we have defeated or been defeated - if (this.defeatedBy(target) || this.defeated(target)) return false; + if (trainer != null && trainer.getTarget() != null) return AllowedBattle.NOTNOW; // Not checking watchers, return true - if (!checkWatcher) return true; + if (!checkWatcher) return AllowedBattle.YES; // Valid if any watchers say so for (final ITargetWatcher w : this.watchers) - if (w.isValidTarget(target)) return true; + if (w.isValidTarget(target)) return AllowedBattle.YES; // Otherwise false. - return false; + return AllowedBattle.NO; } @Override @@ -356,7 +367,9 @@ public ItemStack getPokemob(final int slot) @Override public LivingEntity getTarget() { - return this.target; + final Brain brain = this.user.getBrain(); + if (!brain.hasMemory(MemoryTypes.BATTLETARGET)) return null; + return brain.getMemory(MemoryTypes.BATTLETARGET).get(); } @Override @@ -426,7 +439,7 @@ public void lowerCooldowns() else if (this.getOutMob() == null && !this.aiStates.getAIState(IHasNPCAIStates.THROWING)) this .setAttackCooldown(this.getAttackCooldown() - 1); if (this.aiStates.getAIState(IHasNPCAIStates.INBATTLE)) return; - if (!done && this.getTarget() != null) this.setTarget(null); + if (!done && this.getTarget() != null) this.onSetTarget(null); } @Override @@ -448,11 +461,7 @@ public void onWin(final Entity lost) { // Only store for players if (lost instanceof PlayerEntity) this.defeated.validate(lost); - if (lost == this.getTarget()) - { - this.setTarget(null); - this.resetPokemob(); - } + if (lost == this.getTarget()) this.onSetTarget(null); } @Override @@ -469,14 +478,12 @@ public void onLose(final Entity won) if (defeatingTrainer != null) { defeatingTrainer.onWin(this.user); - defeatingTrainer.setTarget(null); - defeatingTrainer.resetPokemob(); + defeatingTrainer.onSetTarget(null); } // Get this cleanup stuff done first. - this.setCooldown(this.user.getEntityWorld().getGameTime() + 10); - this.setTarget(null); - this.resetPokemob(); + this.setCooldown(this.user.getEntityWorld().getGameTime() + 100); + this.onSetTarget(null); // Then parse if rewards and actions should be dealt with. final boolean reward = !(this.defeatedBy(won) || !this.user.isAlive() || this.user.getHealth() <= 0); @@ -528,11 +535,8 @@ public void resetPokemob() this.setNextSlot(0); this.aiStates.setAIState(IHasNPCAIStates.THROWING, false); this.aiStates.setAIState(IHasNPCAIStates.INBATTLE, false); - if (this.getOutID() != null) - { - EventsHandler.recallAllPokemobs(this.user); - this.setOutMob(null); - } + EventsHandler.recallAllPokemobs(this.user); + this.setOutMob(null); } @Override @@ -627,25 +631,51 @@ public void setPokemob(final int slot, final ItemStack cube) } @Override - public void setTarget(final LivingEntity target) + public void onSetTarget(final LivingEntity target, final boolean ignoreCanBattle) { + final LivingEntity old = this.getTarget(); + // No calling this if we already have that target. + if (old == target) return; + // No calling this if we are the target. + if (target == this.getTrainer()) return; + + if (!ignoreCanBattle && target != null && !this.canBattle(target, true).test()) return; + final Set watchers = this.getTargetWatchers(); // No next pokemob, so we shouldn't have a target in this case. + + // Set this here, before trying to validate other's target below. + this.getTrainer().getBrain().removeMemory(MemoryTypes.BATTLETARGET); + if (target != null) this.getTrainer().getBrain().setMemory(MemoryTypes.BATTLETARGET, target); + + final IHasPokemobs oldOther = TrainerCaps.getHasPokemobs(old); + if (oldOther != null) oldOther.onSetTarget(null); + if (target != null && this.getPokemob(0).isEmpty()) { - this.target = null; // Notify the watchers that a target was actually set. for (final ITargetWatcher watcher : watchers) watcher.onSet(null); this.aiStates.setAIState(IHasNPCAIStates.THROWING, false); this.aiStates.setAIState(IHasNPCAIStates.INBATTLE, false); + BrainUtils.deagro(this.getTrainer()); + this.getTrainer().getBrain().removeMemory(MemoryTypes.BATTLETARGET); + this.getTrainer().getBrain().switchTo(Activity.IDLE); return; } - if (target != null && target != this.target && this.attackCooldown <= 0) + + final IHasPokemobs other = TrainerCaps.getHasPokemobs(target); + if (other != null) other.onSetTarget(this.getTrainer(), true); + + if (target != null && this.getAttackCooldown() <= 0) { - this.attackCooldown = Config.instance.trainerBattleDelay; + int cooldown = Config.instance.trainerBattleDelay; + final LivingEntity hitBy = this.user.getBrain().hasMemory(MemoryModuleType.HURT_BY_ENTITY) ? this.user + .getBrain().getMemory(MemoryModuleType.HURT_BY_ENTITY).get() : null; + final int hurtTimer = this.user.ticksExisted - this.user.getLastAttackedEntityTime(); // No cooldown if someone was punching is! - if (target == this.user.getAttackingEntity()) this.attackCooldown = 0; + if (hitBy == target && hurtTimer < 500) cooldown = 0; + this.setAttackCooldown(cooldown); this.messages.sendMessage(MessageState.AGRESS, target, this.user.getDisplayName(), target .getDisplayName()); this.messages.doAction(MessageState.AGRESS, target, this.user); @@ -653,19 +683,26 @@ public void setTarget(final LivingEntity target) } if (target == null) { - if (this.target != null && this.aiStates.getAIState(IHasNPCAIStates.INBATTLE)) + if (old != null && this.aiStates.getAIState(IHasNPCAIStates.INBATTLE)) { - this.messages.sendMessage(MessageState.DEAGRESS, this.target, this.user.getDisplayName(), - this.target.getDisplayName()); + this.messages.sendMessage(MessageState.DEAGRESS, old, this.user.getDisplayName(), old + .getDisplayName()); this.messages.doAction(MessageState.DEAGRESS, target, this.user); } this.aiStates.setAIState(IHasNPCAIStates.THROWING, false); this.aiStates.setAIState(IHasNPCAIStates.INBATTLE, false); } - this.target = target; // Notify the watchers that a target was actually set. for (final ITargetWatcher watcher : watchers) watcher.onSet(target); + + if (target == null) + { + BrainUtils.deagro(this.getTrainer()); + this.resetPokemob(); + this.getTrainer().getBrain().switchTo(Activity.IDLE); + } + else this.getTrainer().getBrain().switchTo(Activities.BATTLE); } @Override @@ -690,13 +727,19 @@ public void throwCubeAt(final Entity target) final Vector3 t = Vector3.getNewVector().set(target); t.set(t.subtractFrom(here).scalarMultBy(0.5).addTo(here)); PokecubeManager.heal(i, target.getEntityWorld()); - cube.throwPokecubeAt(this.user.getEntityWorld(), this.user, i, t, null); - this.aiStates.setAIState(IHasNPCAIStates.THROWING, true); - this.attackCooldown = Config.instance.trainerSendOutDelay; - this.messages.sendMessage(MessageState.SENDOUT, target, this.user.getDisplayName(), i.getDisplayName(), - target.getDisplayName()); - if (target instanceof LivingEntity) this.messages.doAction(MessageState.SENDOUT, (LivingEntity) target, - this.user); + final EntityPokecubeBase thrown = cube.throwPokecubeAt(this.user.getEntityWorld(), this.user, i, t, + null); + if (thrown != null) + { + thrown.autoRelease = 20; + thrown.canBePickedUp = false; + this.aiStates.setAIState(IHasNPCAIStates.THROWING, true); + this.attackCooldown = Config.instance.trainerSendOutDelay; + this.messages.sendMessage(MessageState.SENDOUT, target, this.user.getDisplayName(), i + .getDisplayName(), target.getDisplayName()); + if (target instanceof LivingEntity) this.messages.doAction(MessageState.SENDOUT, + (LivingEntity) target, this.user); + } this.nextSlot++; if (this.nextSlot >= this.getMaxPokemobCount() || this.getNextPokemob() == null) this.nextSlot = -1; return; @@ -719,7 +762,9 @@ public LivingEntity getTrainer() @Override public LivingEntity getTargetRaw() { - return this.target; + final Brain brain = this.user.getBrain(); + if (!brain.hasMemory(MemoryTypes.BATTLETARGET)) return null; + return brain.getMemory(MemoryTypes.BATTLETARGET).get(); } @Override @@ -745,6 +790,16 @@ public static enum LevelMode CONFIG, YES, NO; } + public static enum AllowedBattle + { + YES, NOTNOW, NO; + + public boolean test() + { + return this == YES; + } + } + LivingEntity getTrainer(); /** Adds the pokemob back into the inventory, healing it as needed. */ @@ -815,13 +870,13 @@ default void addTargetWatcher(final ITargetWatcher watcher) } /** If we are agressive, is this a valid target? */ - default boolean canBattle(final LivingEntity target) + default AllowedBattle canBattle(final LivingEntity target) { return this.canBattle(target, false); } /** If we are agressive, is this a valid target? */ - boolean canBattle(final LivingEntity target, final boolean checkWatchers); + AllowedBattle canBattle(final LivingEntity target, final boolean checkWatchers); default boolean canLevel() { @@ -965,7 +1020,12 @@ default void removeTargetWatcher(final ITargetWatcher watcher) void setPokemob(int slot, ItemStack cube); - void setTarget(LivingEntity target); + default void onSetTarget(final LivingEntity target) + { + this.onSetTarget(target, false); + } + + void onSetTarget(LivingEntity target, boolean ignoreCanBattle); void setType(TypeTrainer type); @@ -984,11 +1044,13 @@ default void deAgro(final IHasPokemobs us, final IHasPokemobs them) { us.getTrainer().setRevengeTarget(null); us.getTrainer().setLastAttackedEntity(null); + us.onSetTarget(null); } if (them != null) { them.getTrainer().setRevengeTarget(null); them.getTrainer().setLastAttackedEntity(null); + them.onSetTarget(null); } } } @@ -1005,6 +1067,11 @@ default void onRemoved(final IHasPokemobs pokemobs) boolean isValidTarget(LivingEntity target); + default boolean ignoreHasBattled(final LivingEntity target) + { + return false; + } + default void onSet(final LivingEntity target) { diff --git a/src/main/java/pokecube/adventures/capabilities/CapabilityNPCMessages.java b/src/main/java/pokecube/adventures/capabilities/CapabilityNPCMessages.java index d77dddc7ff..75bdd2978c 100644 --- a/src/main/java/pokecube/adventures/capabilities/CapabilityNPCMessages.java +++ b/src/main/java/pokecube/adventures/capabilities/CapabilityNPCMessages.java @@ -37,7 +37,8 @@ public DefaultMessager() this.messages.put(MessageState.DEFEAT, "pokecube.trainer.defeat"); this.messages.put(MessageState.DEAGRESS, "pokecube.trainer.forget"); this.messages.put(MessageState.GIVEITEM, "pokecube.trainer.drop"); - this.messages.put(MessageState.INTERACT_YESBATTLE, "pokecube.trainer.agress"); + this.messages.put(MessageState.INTERACT_YESBATTLE, "pokecube.trainer.agress_allowed"); + this.messages.put(MessageState.INTERACT_NOBATTLE, "pokecube.trainer.agress_request_denied"); this.actions.put(MessageState.INTERACT_YESBATTLE, new BattleAction()); } diff --git a/src/main/java/pokecube/adventures/capabilities/player/PlayerPokemobs.java b/src/main/java/pokecube/adventures/capabilities/player/PlayerPokemobs.java index 001dc023da..1b5b22c9ef 100644 --- a/src/main/java/pokecube/adventures/capabilities/player/PlayerPokemobs.java +++ b/src/main/java/pokecube/adventures/capabilities/player/PlayerPokemobs.java @@ -9,6 +9,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.world.dimension.DimensionType; import net.minecraftforge.event.AttachCapabilitiesEvent; import pokecube.adventures.capabilities.CapabilityHasPokemobs.DefaultPokemobs; import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs; @@ -16,7 +17,6 @@ import pokecube.adventures.capabilities.CapabilityHasRewards.DefaultRewards; import pokecube.adventures.capabilities.CapabilityNPCAIStates.DefaultAIStates; import pokecube.adventures.capabilities.CapabilityNPCMessages.DefaultMessager; -import pokecube.adventures.capabilities.TrainerCaps; import pokecube.adventures.capabilities.utils.TypeTrainer; import pokecube.adventures.events.TrainerEventHandler; import pokecube.core.items.pokecubes.PokecubeManager; @@ -46,6 +46,9 @@ public static void register(final AttachCapabilitiesEvent event) } PlayerEntity player; + LivingEntity target = null; + + long setTargetTime = 0; public PlayerPokemobs(final PlayerEntity player) { @@ -67,9 +70,10 @@ public boolean addPokemob(final ItemStack mob) } @Override - public boolean canBattle(final LivingEntity target) + public AllowedBattle canBattle(final LivingEntity target) { - return true; + if (this.target != null && target != this.target) return AllowedBattle.NOTNOW; + return AllowedBattle.YES; } @Override @@ -119,14 +123,11 @@ public void deserializeNBT(final CompoundNBT nbt) } @Override - public void setTarget(LivingEntity target) + public void onSetTarget(final LivingEntity target) { - if (target == this.player) return; - final IHasPokemobs oldBattle = TrainerCaps.getHasPokemobs(this.target); - if (target != null && oldBattle != null && oldBattle.getTargetRaw() == this.player && oldBattle.canBattle( - this.player)) return; - final IHasPokemobs targetmobs = TrainerCaps.getHasPokemobs(target); - if (targetmobs == null) target = null; + if (target != null && target.getServer() != null) this.setTargetTime = target.getServer().getWorld( + DimensionType.OVERWORLD).getGameTime(); + if (target == this.target) return; final Set watchers = this.getTargetWatchers(); this.target = target; // Notify the watchers that a target was actually set. @@ -134,12 +135,17 @@ public void setTarget(LivingEntity target) watcher.onSet(target); } + @Override + public void onSetTarget(final LivingEntity target, final boolean ignoreCanBattle) + { + this.onSetTarget(target); + } + @Override public LivingEntity getTarget() { - final IHasPokemobs oldBattle = TrainerCaps.getHasPokemobs(this.target); - if (this.target != null && !this.target.isAlive()) this.target = null; - if (oldBattle != null && oldBattle != this && oldBattle.getTargetRaw() != this.player) this.target = null; + if (this.target != null && this.target.getServer() != null) if (this.target.getServer().getWorld( + DimensionType.OVERWORLD).getGameTime() - this.setTargetTime > 50) this.target = null; return this.target; } @@ -147,6 +153,6 @@ public LivingEntity getTarget() public void resetPokemob() { // We do nothing here either. - this.setTarget(null); + this.onSetTarget(null); } } diff --git a/src/main/java/pokecube/adventures/capabilities/utils/BattleAction.java b/src/main/java/pokecube/adventures/capabilities/utils/BattleAction.java index 5440b657f5..9143244eb9 100644 --- a/src/main/java/pokecube/adventures/capabilities/utils/BattleAction.java +++ b/src/main/java/pokecube/adventures/capabilities/utils/BattleAction.java @@ -21,7 +21,7 @@ public void doAction(final PlayerEntity target, final Entity holder) if (trainer != null && target instanceof ServerPlayerEntity) { trainer.resetPokemob(); - trainer.setTarget(target); + trainer.onSetTarget(target); } } diff --git a/src/main/java/pokecube/adventures/capabilities/utils/TypeTrainer.java b/src/main/java/pokecube/adventures/capabilities/utils/TypeTrainer.java index d3e7c61dca..b6b2ced55d 100644 --- a/src/main/java/pokecube/adventures/capabilities/utils/TypeTrainer.java +++ b/src/main/java/pokecube/adventures/capabilities/utils/TypeTrainer.java @@ -11,6 +11,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.mojang.datafixers.util.Pair; import net.minecraft.client.Minecraft; import net.minecraft.entity.INPC; @@ -18,6 +19,7 @@ import net.minecraft.entity.MobEntity; import net.minecraft.entity.ai.brain.schedule.Activity; import net.minecraft.entity.ai.brain.schedule.Schedule; +import net.minecraft.entity.ai.brain.task.Task; import net.minecraft.entity.merchant.villager.VillagerEntity; import net.minecraft.entity.monster.ZombieEntity; import net.minecraft.entity.player.PlayerEntity; @@ -33,11 +35,9 @@ import net.minecraftforge.api.distmarker.OnlyIn; import pokecube.adventures.Config; import pokecube.adventures.PokecubeAdv; -import pokecube.adventures.ai.tasks.AIBattle; -import pokecube.adventures.ai.tasks.AICapture; -import pokecube.adventures.ai.tasks.AITrainerAgro; -import pokecube.adventures.ai.tasks.AIMate; -import pokecube.adventures.ai.tasks.AIRetaliate; +import pokecube.adventures.ai.tasks.Tasks; +import pokecube.adventures.ai.tasks.battle.CaptureMob; +import pokecube.adventures.ai.tasks.battle.agro.AgroTargets; import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs; import pokecube.adventures.capabilities.TrainerCaps; import pokecube.adventures.entity.trainer.TrainerBase; @@ -52,7 +52,6 @@ import pokecube.core.database.SpawnBiomeMatcher; import pokecube.core.entity.npc.NpcMob; import pokecube.core.entity.npc.NpcType; -import pokecube.core.entity.pokemobs.EntityPokemob; import pokecube.core.events.pokemob.SpawnEvent.Variance; import pokecube.core.handlers.events.SpawnHandler; import pokecube.core.interfaces.IPokecube.PokecubeBehavior; @@ -61,9 +60,8 @@ import pokecube.core.items.pokecubes.PokecubeManager; import pokecube.core.utils.PokeType; import pokecube.core.utils.Tools; -import thut.api.entity.ai.GoalsWrapper; -import thut.api.entity.ai.IAIRunnable; +@SuppressWarnings("unchecked") public class TypeTrainer extends NpcType { @@ -81,7 +79,7 @@ public static interface ITypeMapper public static interface AIAdder { - void process(MobEntity mob); + List>> process(MobEntity mob); } private static final List mappers = Lists.newArrayList(); @@ -99,8 +97,10 @@ public static void registerAIAdder(final AIAdder adder) public static void addAI(final MobEntity mob) { + final List>> tasks = Lists.newArrayList(); for (final AIAdder adder : TypeTrainer.aiAdders) - adder.process(mob); + tasks.addAll(adder.process(mob)); + Tasks.addBattleTasks(mob, tasks); } public static TypeTrainer get(final LivingEntity mob, final boolean forSpawn) @@ -143,15 +143,6 @@ else if (mob instanceof VillagerEntity && Config.instance.npcsAreTrainers) TypeTrainer.registerAIAdder((npc) -> { - final List ais = Lists.newArrayList(); - // All can battle, but only trainers will path during battle. - ais.add(new AIBattle(npc, !(npc instanceof TrainerBase)).setPriority(0)); - - // All attack zombies. - ais.add(new AITrainerAgro(npc, ZombieEntity.class).setPriority(20)); - - // All retaliate - ais.add(new AIRetaliate(npc)); final Predicate noRunWhileRest = e -> { @@ -175,29 +166,46 @@ else if (mob instanceof VillagerEntity && Config.instance.npcsAreTrainers) } return true; }; + final Predicate onlyIfHasMobs = e -> + { + final IHasPokemobs other = TrainerCaps.getHasPokemobs(e); + if (other == null) return true; + final boolean hasMob = !other.getNextPokemob().isEmpty(); + if (hasMob) return true; + return other.getOutID() != null; + }; + + final List>> list = Lists.newArrayList(); + Task task = new AgroTargets(npc, 1, 0, z -> z instanceof ZombieEntity); + list.add(Pair.of(1, (Task) task)); + // Only trainers specifically target players. if (npc instanceof TrainerBase) { - ais.add(new AITrainerAgro(npc, PlayerEntity.class).setRunCondition(noRunWhileRest).setPriority(10)); - ais.add(new AIMate(npc, ((TrainerBase) npc).getClass())); + final Predicate validPlayer = onlyIfHasMobs.and(e -> e instanceof PlayerEntity); + task = new AgroTargets(npc, 1, 0, validPlayer).setRunCondition(noRunWhileRest); + list.add(Pair.of(1, (Task) task)); } // 5% chance of battling a random nearby pokemob if they see it. if (Config.instance.trainersBattlePokemobs) { - ais.add(new AITrainerAgro(npc, 0.05f, EntityPokemob.class).setRunCondition(noRunWhileRest).setPriority( - 20)); - ais.add(new AICapture(npc).setPriority(10)); + task = new AgroTargets(npc, 0.05f, 1200, z -> CapabilityPokemob.getPokemobFor(z) != null) + .setRunCondition(noRunWhileRest); + list.add(Pair.of(1, (Task) task)); + task = new CaptureMob(npc, 1); + list.add(Pair.of(1, (Task) task)); } // 1% chance of battling another of same class if seen // Also this will stop the battle after 1200 ticks. if (Config.instance.trainersBattleEachOther) { final Predicate shouldRun = noRunWhileMeet.and(noRunWhileRest); - ais.add(new AITrainerAgro(npc, 0.001f, 1200, npc.getClass()).setRunCondition(shouldRun).setPriority(20)); + task = new AgroTargets(npc, 0.05f, 1200, z -> z.getClass() == npc.getClass()).setRunCondition( + shouldRun); + list.add(Pair.of(1, (Task) task)); } - - npc.goalSelector.addGoal(0, new GoalsWrapper(npc, ais.toArray(new IAIRunnable[0]))); + return list; }); } diff --git a/src/main/java/pokecube/adventures/client/gui/blocks/AFA.java b/src/main/java/pokecube/adventures/client/gui/blocks/AFA.java new file mode 100644 index 0000000000..69593bb583 --- /dev/null +++ b/src/main/java/pokecube/adventures/client/gui/blocks/AFA.java @@ -0,0 +1,93 @@ +package pokecube.adventures.client.gui.blocks; + +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import pokecube.adventures.PokecubeAdv; +import pokecube.adventures.blocks.afa.AfaContainer; +import pokecube.adventures.network.PacketAFA; + +public class AFA extends ContainerScreen +{ + + public AFA(final AfaContainer screenContainer, final PlayerInventory inv, final ITextComponent titleIn) + { + super(screenContainer, inv, titleIn); + } + + @Override + protected void drawGuiContainerBackgroundLayer(final float partialTicks, final int mouseX, final int mouseY) + { + GL11.glPushMatrix(); + GL11.glColor4f(1f, 1f, 1f, 1f); + this.minecraft.getTextureManager().bindTexture(new ResourceLocation(PokecubeAdv.MODID, "textures/gui/afa.png")); + final int x = (this.width - this.xSize) / 2; + final int y = (this.height - this.ySize) / 2; + this.blit(x, y, 0, 0, this.xSize, this.ySize); + + GL11.glPopMatrix(); + } + + @Override + protected void drawGuiContainerForegroundLayer(final int mouseX, final int mouseY) + { + String text = this.getTitle().getFormattedText(); + this.font.drawString(text, 172 - this.font.getStringWidth(text), 6, 4210752); + this.font.drawString(this.playerInventory.getName().getFormattedText(), 8, this.ySize - 96 + 2, 4210752); + + text = this.container.tile.ability != null ? I18n.format("block.afa.ability.info", I18n.format( + this.container.tile.ability.getName())) : I18n.format("block.afa.ability.none"); + + this.font.drawString(text, 172 - this.font.getStringWidth(text), 22, 4210752); + + text = I18n.format("block.afa.range.info", this.container.tile.distance); + + this.font.drawString(text, 172 - this.font.getStringWidth(text), 42, 4210752); + + text = I18n.format("block.afa.power.info", this.container.tile.cost, this.container.tile.orig); + + this.font.drawString(text, 172 - this.font.getStringWidth(text), 62, 4210752); + } + + @Override + /** Draws the screen and all the components in it. */ + public void render(final int mouseX, final int mouseY, final float partialTicks) + { + this.renderBackground(); + super.render(mouseX, mouseY, partialTicks); + this.renderHoveredToolTip(mouseX, mouseY); + } + + @Override + protected void init() + { + super.init(); + + final int xOffset = -119; + final int yOffset = -88; + final String next = I18n.format("block.pc.next"); + this.addButton(new Button(this.width / 2 - xOffset - 44, this.height / 2 - yOffset - 121, 10, 10, next, b -> + { + final PacketAFA message = new PacketAFA(); + message.data.putBoolean("U", true); + message.data.putBoolean("S", Screen.hasShiftDown()); + PokecubeAdv.packets.sendToServer(message); + })); + final String prev = I18n.format("block.pc.previous"); + this.addButton(new Button(this.width / 2 - xOffset - 54, this.height / 2 - yOffset - 121, 10, 10, prev, b -> + { + final PacketAFA message = new PacketAFA(); + message.data.putBoolean("U", false); + message.data.putBoolean("S", Screen.hasShiftDown()); + PokecubeAdv.packets.sendToServer(message); + })); + + } + +} diff --git a/src/main/java/pokecube/adventures/client/gui/blocks/Commander.java b/src/main/java/pokecube/adventures/client/gui/blocks/Commander.java index 8088be00f1..74cdbfdce8 100644 --- a/src/main/java/pokecube/adventures/client/gui/blocks/Commander.java +++ b/src/main/java/pokecube/adventures/client/gui/blocks/Commander.java @@ -40,6 +40,13 @@ public boolean keyPressed(final int key, final int unk1, final int unk2) return super.keyPressed(key, unk1, unk2); } + @Override + public void render(final int a, final int b, final float c) + { + this.renderBackground(); + super.render(a, b, c); + } + @Override protected void init() { diff --git a/src/main/java/pokecube/adventures/client/gui/items/editor/pages/Spawn.java b/src/main/java/pokecube/adventures/client/gui/items/editor/pages/Spawn.java index 2299717f88..880eede298 100644 --- a/src/main/java/pokecube/adventures/client/gui/items/editor/pages/Spawn.java +++ b/src/main/java/pokecube/adventures/client/gui/items/editor/pages/Spawn.java @@ -19,6 +19,7 @@ public class Spawn extends Page int index = 0; boolean leader = false; + boolean stand = false; public Spawn(final EditorGui parent) { @@ -81,13 +82,20 @@ public void onPageOpened() else b.setMessage("trainer"); this.leader = b.getMessage().equals("leader"); })); - this.addButton(new Button(xOffset + 25, yOffset + 40, 40, 20, "spawn", b -> + this.addButton(new Button(xOffset - 5, yOffset + 40, 40, 20, "stands", b -> + { + if (b.getMessage().equals("wanders")) b.setMessage("stands"); + else b.setMessage("wanders"); + this.stand = b.getMessage().equals("stands"); + })); + this.addButton(new Button(xOffset + 35, yOffset + 40, 40, 20, "spawn", b -> { final PacketTrainer message = new PacketTrainer(PacketTrainer.SPAWN); message.getTag().putString("T", this.type.getText()); final int value = this.level.getText().isEmpty() ? 1 : Integer.parseInt(this.level.getText()); message.getTag().putInt("L", value); message.getTag().putBoolean("C", this.leader); + message.getTag().putBoolean("S", this.stand); PacketTrainer.ASSEMBLER.sendToServer(message); })); } diff --git a/src/main/java/pokecube/adventures/entity/trainer/TrainerBase.java b/src/main/java/pokecube/adventures/entity/trainer/TrainerBase.java index ad04c44fc3..69b2fb51a6 100644 --- a/src/main/java/pokecube/adventures/entity/trainer/TrainerBase.java +++ b/src/main/java/pokecube/adventures/entity/trainer/TrainerBase.java @@ -5,7 +5,6 @@ import java.util.OptionalInt; import java.util.Random; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.container.MerchantContainer; @@ -34,7 +33,6 @@ import pokecube.core.handlers.events.EventsHandler; import pokecube.core.handlers.events.SpawnHandler; import pokecube.core.interfaces.IPokemob; -import pokecube.core.interfaces.capabilities.CapabilityPokemob; import pokecube.core.utils.Tools; import thut.api.item.ItemList; import thut.api.maths.Vector3; @@ -101,7 +99,7 @@ else if (ItemList.is(TrainerBase.BRIBE, stack) && this.pokemobsCap.friendlyCoold { stack.split(1); player.setHeldItem(hand, stack); - this.pokemobsCap.setTarget(null); + this.pokemobsCap.onSetTarget(null); for (final IPokemob pokemob : this.currentPokemobs) pokemob.onRecall(false); this.pokemobsCap.friendlyCooldown = 2400; @@ -125,7 +123,7 @@ else if (this.canTrade(player)) else this.setCustomer(null); return true; } - else if (this.pokemobsCap.getCooldown() <= 0 && stack.getItem() == Items.STICK) this.pokemobsCap.setTarget( + else if (this.pokemobsCap.getCooldown() <= 0 && stack.getItem() == Items.STICK) this.pokemobsCap.onSetTarget( player); return false; @@ -169,18 +167,11 @@ public void livingTick() { super.livingTick(); if (!this.isServerWorld()) return; - if (this.pokemobsCap.getOutID() != null && this.pokemobsCap.getOutMob() == null) - { - final Entity mob = this.getServer().getWorld(this.dimension).getEntityByUuid(this.pokemobsCap.getOutID()); - final IPokemob pokemob = CapabilityPokemob.getPokemobFor(mob); - this.pokemobsCap.setOutMob(pokemob); - if (this.pokemobsCap.getOutMob() == null) this.pokemobsCap.setOutID(null); - } ItemStack cube = this.pokemobsCap.getNextPokemob(); ItemStack reward = this.rewardsCap.getRewards().isEmpty() ? ItemStack.EMPTY : this.rewardsCap.getRewards().get(0).stack; - if (this.pokemobsCap.getCooldown() > 0) + if (this.pokemobsCap.getCooldown() > this.world.getGameTime()) { cube = ItemStack.EMPTY; reward = ItemStack.EMPTY; @@ -321,6 +312,7 @@ public void setMale(final boolean male) @Override public NpcType getNpcType() { + if (this.pokemobsCap == null) return super.getNpcType(); return this.pokemobsCap.getType(); } } diff --git a/src/main/java/pokecube/adventures/events/TrainerEventHandler.java b/src/main/java/pokecube/adventures/events/TrainerEventHandler.java index c302f95e45..6c67fcca97 100644 --- a/src/main/java/pokecube/adventures/events/TrainerEventHandler.java +++ b/src/main/java/pokecube/adventures/events/TrainerEventHandler.java @@ -10,6 +10,8 @@ import net.minecraft.entity.LivingEntity; import net.minecraft.entity.MobEntity; import net.minecraft.entity.SpawnReason; +import net.minecraft.entity.ai.brain.Brain; +import net.minecraft.entity.ai.brain.schedule.Activity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; @@ -31,8 +33,11 @@ import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import pokecube.adventures.Config; import pokecube.adventures.PokecubeAdv; +import pokecube.adventures.ai.brain.MemoryTypes; +import pokecube.adventures.ai.tasks.Tasks; import pokecube.adventures.capabilities.CapabilityHasPokemobs.DefaultPokemobs; import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs; +import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs.AllowedBattle; import pokecube.adventures.capabilities.CapabilityHasRewards.DefaultRewards; import pokecube.adventures.capabilities.CapabilityHasRewards.Reward; import pokecube.adventures.capabilities.CapabilityHasTrades.DefaultTrades; @@ -52,6 +57,7 @@ import pokecube.adventures.network.PacketTrainer; import pokecube.adventures.utils.DBLoader; import pokecube.core.PokecubeCore; +import pokecube.core.ai.npc.Activities; import pokecube.core.ai.routes.IGuardAICapability; import pokecube.core.database.Database; import pokecube.core.database.PokedexEntryLoader; @@ -292,7 +298,7 @@ public static void livingHurtEvent(final LivingHurtEvent evt) .getDisplayName(), evt.getSource().getTrueSource().getDisplayName()); messages.doAction(MessageState.HURT, (LivingEntity) evt.getSource().getTrueSource(), evt.getEntity()); } - if (pokemobHolder != null && pokemobHolder.getTarget() == null) pokemobHolder.setTarget((LivingEntity) evt + if (pokemobHolder != null && pokemobHolder.getTarget() == null) pokemobHolder.onSetTarget((LivingEntity) evt .getSource().getTrueSource()); } } @@ -307,9 +313,6 @@ public static void livingHurtEvent(final LivingHurtEvent evt) public static void livingSetTargetEvent(final LivingSetAttackTargetEvent evt) { if (evt.getTarget() == null || !(evt.getEntity() instanceof LivingEntity)) return; - final IHasPokemobs pokemobHolder = TrainerCaps.getHasPokemobs(evt.getTarget()); - if (pokemobHolder != null && pokemobHolder.getTarget() == null) pokemobHolder.setTarget((LivingEntity) evt - .getEntity()); } @SubscribeEvent @@ -334,7 +337,22 @@ public static void onNpcSpawn(final NpcSpawn event) public static void onNpcTick(final LivingUpdateEvent event) { final IHasPokemobs pokemobHolder = TrainerCaps.getHasPokemobs(event.getEntityLiving()); - if (pokemobHolder != null) pokemobHolder.onTick(); + if (pokemobHolder != null) + { + final LivingEntity npc = event.getEntityLiving(); + final Brain brain = npc.getBrain(); + if (!brain.hasMemory(MemoryTypes.BATTLETARGET) && brain.hasActivity(Activities.BATTLE)) brain.switchTo( + Activity.IDLE); + // Add our task if the dummy not present, this can happen if the + // brain has reset before + if (npc instanceof MobEntity && !brain.sensors.containsKey(Tasks.DUMMY) && npc + .getEntityWorld() instanceof ServerWorld) + { + TypeTrainer.addAI((MobEntity) npc); + PokecubeCore.LOGGER.debug("Added Tasks: " + npc); + } + pokemobHolder.onTick(); + } } private static void initTrainer(final LivingEntity npc, final SpawnReason reason) @@ -351,10 +369,6 @@ private static void initTrainer(final LivingEntity npc, final SpawnReason reason .getEntityWorld().getGameTime()) return; npc.getPersistentData().putLong("pokeadv_join", npc.getEntityWorld().getGameTime()); - // Wrap it as a fake vanilla AI - if (npc instanceof MobEntity) TypeTrainer.addAI((MobEntity) npc); - PokecubeCore.LOGGER.debug("Added Tasks: " + npc); - final TypeTrainer newType = TypeTrainer.get(npc, true); if (mobs.countPokemon() != 0) return; if (newType == null) return; @@ -394,8 +408,22 @@ public static void processInteract(final PlayerInteractEvent evt, final Entity t if (messages != null) { MessageState state = MessageState.INTERACT; - if (pokemobs != null) state = pokemobs.canBattle(evt.getPlayer(), true) ? MessageState.INTERACT_YESBATTLE - : MessageState.INTERACT_NOBATTLE; + final AllowedBattle test = pokemobs.canBattle(evt.getPlayer(), true); + switch (test) + { + case NO: + state = MessageState.INTERACT; + break; + case NOTNOW: + state = MessageState.INTERACT_NOBATTLE; + break; + case YES: + state = MessageState.INTERACT_YESBATTLE; + break; + default: + break; + + } messages.sendMessage(state, evt.getPlayer(), target.getDisplayName(), evt.getPlayer().getDisplayName()); messages.doAction(state, evt.getPlayer(), target); } diff --git a/src/main/java/pokecube/adventures/network/PacketAFA.java b/src/main/java/pokecube/adventures/network/PacketAFA.java new file mode 100644 index 0000000000..f5b47973ac --- /dev/null +++ b/src/main/java/pokecube/adventures/network/PacketAFA.java @@ -0,0 +1,54 @@ +package pokecube.adventures.network; + +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.SimpleNamedContainerProvider; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.IWorldPosCallable; +import net.minecraft.util.text.TranslationTextComponent; +import pokecube.adventures.blocks.afa.AfaContainer; +import pokecube.adventures.blocks.afa.AfaTile; +import thut.core.common.network.Packet; + +public class PacketAFA extends Packet +{ + public static void openGui(final ServerPlayerEntity player, final AfaTile tile) + { + final TranslationTextComponent name = new TranslationTextComponent("block.pokecube_adventures.afa"); + final SimpleNamedContainerProvider provider = new SimpleNamedContainerProvider((i, p, e) -> new AfaContainer(i, + p, IWorldPosCallable.of(tile.getWorld(), tile.getPos())), name); + player.openContainer(provider); + } + + public CompoundNBT data = new CompoundNBT(); + + public PacketAFA() + { + } + + public PacketAFA(final PacketBuffer buf) + { + this.data = buf.readCompoundTag(); + } + + @Override + public void write(final PacketBuffer buffer) + { + buffer.writeCompoundTag(this.data); + } + + @Override + public void handleServer(final ServerPlayerEntity player) + { + final Container cont = player.openContainer; + if (cont instanceof AfaContainer) + { + final AfaTile tile = ((AfaContainer) cont).tile; + final int scale = this.data.getBoolean("S") ? 10 : 1; + tile.distance += this.data.getBoolean("U") ? 1 * scale : -1 * scale; + tile.distance = Math.max(0, tile.distance); + tile.refreshAbility(true); + } + } +} diff --git a/src/main/java/pokecube/adventures/network/PacketTrainer.java b/src/main/java/pokecube/adventures/network/PacketTrainer.java index e34eb8eb21..1094891a6e 100644 --- a/src/main/java/pokecube/adventures/network/PacketTrainer.java +++ b/src/main/java/pokecube/adventures/network/PacketTrainer.java @@ -171,10 +171,13 @@ protected void onCompleteServer(final ServerPlayerEntity player) final JsonObject thing = new JsonObject(); thing.addProperty("level", level); thing.addProperty("trainerType", type); - final GuardInfo info = new GuardInfo(); - info.time = "day"; - info.roam = 2; - thing.add("guard", PokedexEntryLoader.gson.toJsonTree(info)); + if (this.data.getBoolean("S")) + { + final GuardInfo info = new GuardInfo(); + info.time = "day"; + info.roam = 2; + thing.add("guard", PokedexEntryLoader.gson.toJsonTree(info)); + } final String var = PokedexEntryLoader.gson.toJson(thing); args = args + var; final StructureEvent.ReadTag event = new ReadTag(args, vec.getPos(), player.getEntityWorld(), player diff --git a/src/main/java/pokecube/adventures/proxy/ClientProxy.java b/src/main/java/pokecube/adventures/proxy/ClientProxy.java index f8913a1dbd..84e9a00e65 100644 --- a/src/main/java/pokecube/adventures/proxy/ClientProxy.java +++ b/src/main/java/pokecube/adventures/proxy/ClientProxy.java @@ -28,6 +28,7 @@ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import pokecube.adventures.Config; import pokecube.adventures.PokecubeAdv; +import pokecube.adventures.blocks.afa.AfaContainer; import pokecube.adventures.blocks.genetics.cloner.ClonerContainer; import pokecube.adventures.blocks.genetics.extractor.ExtractorContainer; import pokecube.adventures.blocks.genetics.helper.ClonerHelper; @@ -36,6 +37,7 @@ import pokecube.adventures.blocks.genetics.helper.recipe.RecipeSelector.SelectorValue; import pokecube.adventures.blocks.genetics.splicer.SplicerContainer; import pokecube.adventures.capabilities.utils.TypeTrainer; +import pokecube.adventures.client.gui.blocks.AFA; import pokecube.adventures.client.gui.blocks.Cloner; import pokecube.adventures.client.gui.blocks.Extractor; import pokecube.adventures.client.gui.blocks.Splicer; @@ -172,6 +174,7 @@ public void setupClient(final FMLClientSetupEvent event) ScreenManager.registerFactory(ClonerContainer.TYPE, Cloner::new); ScreenManager.registerFactory(SplicerContainer.TYPE, Splicer::new); ScreenManager.registerFactory(ExtractorContainer.TYPE, Extractor::new); + ScreenManager.registerFactory(AfaContainer.TYPE, AFA::new); ScreenManager.registerFactory(BagContainer.TYPE, Bag::new); RenderTypeLookup.setRenderLayer(PokecubeAdv.CLONER, RenderType.getTranslucent()); diff --git a/src/main/java/pokecube/adventures/proxy/CommonProxy.java b/src/main/java/pokecube/adventures/proxy/CommonProxy.java index 516a026004..d33168d903 100644 --- a/src/main/java/pokecube/adventures/proxy/CommonProxy.java +++ b/src/main/java/pokecube/adventures/proxy/CommonProxy.java @@ -11,6 +11,9 @@ import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import pokecube.adventures.PokecubeAdv; +import pokecube.adventures.ai.tasks.Tasks; +import pokecube.adventures.blocks.afa.AfaTile; +import pokecube.adventures.blocks.warppad.WarppadTile; import pokecube.adventures.capabilities.CapabilityHasPokemobs; import pokecube.adventures.capabilities.CapabilityHasPokemobs.DefaultPokemobs; import pokecube.adventures.capabilities.CapabilityHasPokemobs.IHasPokemobs; @@ -28,10 +31,12 @@ import pokecube.adventures.capabilities.CapabilityNPCMessages.IHasMessages; import pokecube.adventures.capabilities.utils.TypeTrainer; import pokecube.adventures.events.CompatEvent; +import pokecube.adventures.network.PacketAFA; import pokecube.adventures.network.PacketBag; import pokecube.adventures.network.PacketCommander; import pokecube.adventures.network.PacketTrainer; import pokecube.compat.Compat; +import thut.api.OwnableCaps; import thut.core.common.Proxy; import thut.wearables.EnumWearable; import thut.wearables.IActiveWearable; @@ -87,8 +92,13 @@ public void setup(final FMLCommonSetupEvent event) PokecubeAdv.packets.registerMessage(PacketBag.class, PacketBag::new); PokecubeAdv.packets.registerMessage(PacketTrainer.class, PacketTrainer::new); PokecubeAdv.packets.registerMessage(PacketCommander.class, PacketCommander::new); + PokecubeAdv.packets.registerMessage(PacketAFA.class, PacketAFA::new); + + OwnableCaps.TILES.add(AfaTile.class); + OwnableCaps.TILES.add(WarppadTile.class); PacketTrainer.register(); + Tasks.init(); } @Override diff --git a/src/main/java/pokecube/compat/jei/categories/cloner/Category.java b/src/main/java/pokecube/compat/jei/categories/cloner/Category.java index bac67cda1d..a0d3247d46 100644 --- a/src/main/java/pokecube/compat/jei/categories/cloner/Category.java +++ b/src/main/java/pokecube/compat/jei/categories/cloner/Category.java @@ -5,9 +5,9 @@ import mezz.jei.api.ingredients.IIngredients; import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.util.ResourceLocation; -import pokecube.adventures.blocks.genetics.helper.recipe.RecipeFossilRevive; +import pokecube.adventures.blocks.genetics.helper.recipe.RecipeClone; -public class Category implements IRecipeCategory +public class Category implements IRecipeCategory { public Category() @@ -30,7 +30,7 @@ public IDrawable getIcon() } @Override - public Class getRecipeClass() + public Class getRecipeClass() { // TODO Auto-generated method stub return null; @@ -51,13 +51,13 @@ public ResourceLocation getUid() } @Override - public void setIngredients(final RecipeFossilRevive arg0, final IIngredients arg1) + public void setIngredients(final RecipeClone arg0, final IIngredients arg1) { // TODO Auto-generated method stub } @Override - public void setRecipe(final IRecipeLayout arg0, final RecipeFossilRevive arg1, final IIngredients arg2) + public void setRecipe(final IRecipeLayout arg0, final RecipeClone arg1, final IIngredients arg2) { // TODO Auto-generated method stub diff --git a/src/main/java/pokecube/compat/jei/categories/evolution/Category.java b/src/main/java/pokecube/compat/jei/categories/evolution/Category.java index 127fee1dd2..60d66c3a48 100644 --- a/src/main/java/pokecube/compat/jei/categories/evolution/Category.java +++ b/src/main/java/pokecube/compat/jei/categories/evolution/Category.java @@ -5,9 +5,9 @@ import mezz.jei.api.ingredients.IIngredients; import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.util.ResourceLocation; -import pokecube.adventures.blocks.genetics.helper.recipe.RecipeFossilRevive; +import pokecube.adventures.blocks.genetics.helper.recipe.RecipeClone; -public class Category implements IRecipeCategory +public class Category implements IRecipeCategory { public Category() @@ -30,7 +30,7 @@ public IDrawable getIcon() } @Override - public Class getRecipeClass() + public Class getRecipeClass() { // TODO Auto-generated method stub return null; @@ -51,13 +51,13 @@ public ResourceLocation getUid() } @Override - public void setIngredients(final RecipeFossilRevive arg0, final IIngredients arg1) + public void setIngredients(final RecipeClone arg0, final IIngredients arg1) { // TODO Auto-generated method stub } @Override - public void setRecipe(final IRecipeLayout arg0, final RecipeFossilRevive arg1, final IIngredients arg2) + public void setRecipe(final IRecipeLayout arg0, final RecipeClone arg1, final IIngredients arg2) { // TODO Auto-generated method stub diff --git a/src/main/java/pokecube/compat/jei/categories/interaction/Category.java b/src/main/java/pokecube/compat/jei/categories/interaction/Category.java index db85b2199c..25e62bd939 100644 --- a/src/main/java/pokecube/compat/jei/categories/interaction/Category.java +++ b/src/main/java/pokecube/compat/jei/categories/interaction/Category.java @@ -5,9 +5,9 @@ import mezz.jei.api.ingredients.IIngredients; import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.util.ResourceLocation; -import pokecube.adventures.blocks.genetics.helper.recipe.RecipeFossilRevive; +import pokecube.adventures.blocks.genetics.helper.recipe.RecipeClone; -public class Category implements IRecipeCategory +public class Category implements IRecipeCategory { public Category() @@ -30,7 +30,7 @@ public IDrawable getIcon() } @Override - public Class getRecipeClass() + public Class getRecipeClass() { // TODO Auto-generated method stub return null; @@ -51,13 +51,13 @@ public ResourceLocation getUid() } @Override - public void setIngredients(final RecipeFossilRevive arg0, final IIngredients arg1) + public void setIngredients(final RecipeClone arg0, final IIngredients arg1) { // TODO Auto-generated method stub } @Override - public void setRecipe(final IRecipeLayout arg0, final RecipeFossilRevive arg1, final IIngredients arg2) + public void setRecipe(final IRecipeLayout arg0, final RecipeClone arg1, final IIngredients arg2) { // TODO Auto-generated method stub diff --git a/src/main/java/pokecube/compat/jei/categories/move/Category.java b/src/main/java/pokecube/compat/jei/categories/move/Category.java index 9d65a0d768..6453dfbae5 100644 --- a/src/main/java/pokecube/compat/jei/categories/move/Category.java +++ b/src/main/java/pokecube/compat/jei/categories/move/Category.java @@ -5,9 +5,9 @@ import mezz.jei.api.ingredients.IIngredients; import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.util.ResourceLocation; -import pokecube.adventures.blocks.genetics.helper.recipe.RecipeFossilRevive; +import pokecube.adventures.blocks.genetics.helper.recipe.RecipeClone; -public class Category implements IRecipeCategory +public class Category implements IRecipeCategory { public Category() @@ -30,7 +30,7 @@ public IDrawable getIcon() } @Override - public Class getRecipeClass() + public Class getRecipeClass() { // TODO Auto-generated method stub return null; @@ -51,13 +51,13 @@ public ResourceLocation getUid() } @Override - public void setIngredients(final RecipeFossilRevive arg0, final IIngredients arg1) + public void setIngredients(final RecipeClone arg0, final IIngredients arg1) { // TODO Auto-generated method stub } @Override - public void setRecipe(final IRecipeLayout arg0, final RecipeFossilRevive arg1, final IIngredients arg2) + public void setRecipe(final IRecipeLayout arg0, final RecipeClone arg1, final IIngredients arg2) { // TODO Auto-generated method stub diff --git a/src/main/java/pokecube/core/PokecubeItems.java b/src/main/java/pokecube/core/PokecubeItems.java index be5a4b55e9..1e0fc1492e 100644 --- a/src/main/java/pokecube/core/PokecubeItems.java +++ b/src/main/java/pokecube/core/PokecubeItems.java @@ -156,7 +156,7 @@ public ItemStack createIcon() private static Set errored = Sets.newHashSet(); - public static void init() + static { // Items PokecubeItems.BERRYJUICE = new Item(new Properties().food(new Food.Builder().hunger(4).saturation(0.3F).build()) @@ -170,25 +170,38 @@ public static void init() // Blocks PokecubeItems.HEALER = new HealerBlock(Block.Properties.create(Material.IRON).hardnessAndResistance(2000) - .lightValue(15)).setRegistryName(PokecubeCore.MODID, "pokecenter"); - PokecubeItems.NESTBLOCK = new NestBlock(Block.Properties.create(Material.ORGANIC)).setRegistryName( - PokecubeCore.MODID, "nest"); - PokecubeItems.REPELBLOCK = new RepelBlock(Block.Properties.create(Material.ORGANIC)).setRegistryName( - PokecubeCore.MODID, "repel"); + .lightValue(15)); + PokecubeItems.NESTBLOCK = new NestBlock(Block.Properties.create(Material.ORGANIC)); + PokecubeItems.REPELBLOCK = new RepelBlock(Block.Properties.create(Material.ORGANIC)); PokecubeItems.DYNABLOCK = new MaxBlock(Block.Properties.create(Material.ROCK).lightValue(15) - .hardnessAndResistance(2000)).setRegistryName(PokecubeCore.MODID, "dynamax"); + .hardnessAndResistance(2000)); PokecubeItems.PCTOP = new PCBlock(Block.Properties.create(Material.IRON).hardnessAndResistance(2000).lightValue( - 15), true).setRegistryName(PokecubeCore.MODID, "pc_top"); + 15), true); PokecubeItems.PCBASE = new PCBlock(Block.Properties.create(Material.IRON).hardnessAndResistance(2000) - .lightValue(15), false).setRegistryName(PokecubeCore.MODID, "pc_base"); + .lightValue(15), false); PokecubeItems.TRADER = new TraderBlock(Block.Properties.create(Material.IRON).hardnessAndResistance(2000) - .lightValue(15)).setRegistryName(PokecubeCore.MODID, "trade_machine"); + .lightValue(15)); PokecubeItems.TMMACHINE = new TMBlock(Block.Properties.create(Material.IRON).hardnessAndResistance(2000) - .lightValue(15)).setRegistryName(PokecubeCore.MODID, "tm_machine"); - PokecubeItems.SECRETBASE = new BaseBlock(Block.Properties.create(Material.ROCK).hardnessAndResistance(2000)) - .setRegistryName(PokecubeCore.MODID, "secret_base"); + .lightValue(15)); + PokecubeItems.SECRETBASE = new BaseBlock(Block.Properties.create(Material.ROCK).hardnessAndResistance(2000)); PokecubeItems.FOSSILSTONE = new Block(Block.Properties.create(Material.ROCK).hardnessAndResistance(1.5f, 10) - .harvestTool(ToolType.PICKAXE)).setRegistryName(PokecubeCore.MODID, "fossilstone"); + .harvestTool(ToolType.PICKAXE)); + } + + public static void init() + { + + // Blocks + PokecubeItems.HEALER.setRegistryName(PokecubeCore.MODID, "pokecenter"); + PokecubeItems.NESTBLOCK.setRegistryName(PokecubeCore.MODID, "nest"); + PokecubeItems.REPELBLOCK.setRegistryName(PokecubeCore.MODID, "repel"); + PokecubeItems.DYNABLOCK.setRegistryName(PokecubeCore.MODID, "dynamax"); + PokecubeItems.PCTOP.setRegistryName(PokecubeCore.MODID, "pc_top"); + PokecubeItems.PCBASE.setRegistryName(PokecubeCore.MODID, "pc_base"); + PokecubeItems.TRADER.setRegistryName(PokecubeCore.MODID, "trade_machine"); + PokecubeItems.TMMACHINE.setRegistryName(PokecubeCore.MODID, "tm_machine"); + PokecubeItems.SECRETBASE.setRegistryName(PokecubeCore.MODID, "secret_base"); + PokecubeItems.FOSSILSTONE.setRegistryName(PokecubeCore.MODID, "fossilstone"); } /** diff --git a/src/main/java/pokecube/core/ai/brain/BrainUtils.java b/src/main/java/pokecube/core/ai/brain/BrainUtils.java index 590ebdc5a9..5cbc18b5f0 100644 --- a/src/main/java/pokecube/core/ai/brain/BrainUtils.java +++ b/src/main/java/pokecube/core/ai/brain/BrainUtils.java @@ -1,19 +1,29 @@ package pokecube.core.ai.brain; +import java.util.Collection; import java.util.List; import java.util.Optional; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.mojang.datafixers.util.Pair; + import net.minecraft.entity.AgeableEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.MobEntity; 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.schedule.Activity; import net.minecraft.entity.ai.brain.sensor.Sensor; import net.minecraft.entity.ai.brain.sensor.SensorType; +import net.minecraft.entity.ai.brain.task.Task; import net.minecraft.entity.item.ItemEntity; import net.minecraft.util.math.IPosWrapper; import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.capabilities.CapabilityPokemob; +import pokecube.core.interfaces.pokemob.ai.CombatStates; import thut.api.entity.ai.VectorPosWrapper; import thut.api.maths.Vector3; @@ -171,4 +181,64 @@ public static void addToBrain(final Brain brain, final List brain, final Activity act, + final Collection>> tasks) + { + tasks.forEach((pair) -> + { + final Integer prior = pair.getFirst(); + final Task task = pair.getSecond(); + brain.field_218232_c.computeIfAbsent(prior, (val) -> + { + return Maps.newHashMap(); + }).computeIfAbsent(act, (tmp) -> + { + return Sets.newLinkedHashSet(); + }).add(task); + }); + } + + public static void initiateCombat(final MobEntity mob, final LivingEntity target) + { + // No target self + if (mob == target) return; + // No target null + if (target == null) return; + // No target dead + if (!target.isAlive() || target.getHealth() <= 0) return; + // No target already had target + if (target == BrainUtils.getAttackTarget(mob)) return; + + final IPokemob aggressor = CapabilityPokemob.getPokemobFor(mob); + final IPokemob targetMob = CapabilityPokemob.getPokemobFor(target); + if (targetMob != null) targetMob.setCombatState(CombatStates.ANGRY, true); + if (aggressor != null) aggressor.setCombatState(CombatStates.ANGRY, true); + + BrainUtils.setAttackTarget(mob, target); + BrainUtils.setAttackTarget(target, mob); + } + + public static void deagro(final LivingEntity mob) + { + if (mob == null) return; + final IPokemob aggressor = CapabilityPokemob.getPokemobFor(mob); + + if (aggressor != null) + { + aggressor.getTargetFinder().clear(); + aggressor.setCombatState(CombatStates.ANGRY, false); + aggressor.setCombatState(CombatStates.MATEFIGHT, false); + } + final LivingEntity oldTarget = BrainUtils.getAttackTarget(mob); + if (mob instanceof MobEntity) + { + BrainUtils.setAttackTarget(mob, null); + BrainUtils.deagro(oldTarget); + } + mob.getBrain().removeMemory(MemoryModules.ATTACKTARGET); + mob.getBrain().removeMemory(MemoryModules.MATE_TARGET); + mob.getBrain().removeMemory(MemoryModuleType.HURT_BY_ENTITY); + mob.getBrain().removeMemory(MemoryModuleType.HURT_BY); + } } diff --git a/src/main/java/pokecube/core/ai/brain/MemoryModules.java b/src/main/java/pokecube/core/ai/brain/MemoryModules.java index 7af433dfd8..5984112601 100644 --- a/src/main/java/pokecube/core/ai/brain/MemoryModules.java +++ b/src/main/java/pokecube/core/ai/brain/MemoryModules.java @@ -36,6 +36,8 @@ public class MemoryModules public static final MemoryModuleType> POSSIBLE_MATES = new MemoryModuleType<>(Optional.empty()); public static final MemoryModuleType MATE_TARGET = new MemoryModuleType<>(Optional.empty()); + public static final MemoryModuleType> HERD_MEMBERS = new MemoryModuleType<>(Optional.empty()); + public static void register(final Register> event) { event.getRegistry().register(MemoryModules.ATTACKTARGET.setRegistryName(PokecubeCore.MODID, "attack_target")); diff --git a/src/main/java/pokecube/core/ai/brain/Sensors.java b/src/main/java/pokecube/core/ai/brain/Sensors.java index b95d004cec..7f0cc0a14b 100644 --- a/src/main/java/pokecube/core/ai/brain/Sensors.java +++ b/src/main/java/pokecube/core/ai/brain/Sensors.java @@ -3,21 +3,21 @@ import net.minecraft.entity.ai.brain.sensor.SensorType; import net.minecraftforge.event.RegistryEvent.Register; import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.sensors.InterestingMobs; 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 final SensorType VISIBLE_BLOCKS = new SensorType<>(NearBlocks::new); + public static final SensorType VISIBLE_ITEMS = new SensorType<>(NearItems::new); + public static final SensorType INTERESTING_MOBS = new SensorType<>(InterestingMobs::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")); + event.getRegistry().register(Sensors.INTERESTING_MOBS.setRegistryName(PokecubeCore.MODID, "interesting_mobs")); } } diff --git a/src/main/java/pokecube/core/ai/brain/sensors/PossibleMates.java b/src/main/java/pokecube/core/ai/brain/sensors/InterestingMobs.java similarity index 92% rename from src/main/java/pokecube/core/ai/brain/sensors/PossibleMates.java rename to src/main/java/pokecube/core/ai/brain/sensors/InterestingMobs.java index 7591b277e8..9de96951d6 100644 --- a/src/main/java/pokecube/core/ai/brain/sensors/PossibleMates.java +++ b/src/main/java/pokecube/core/ai/brain/sensors/InterestingMobs.java @@ -15,7 +15,7 @@ import thut.api.entity.BreedableCaps; import thut.api.entity.IBreedingMob; -public class PossibleMates extends Sensor +public class InterestingMobs extends Sensor { long lastUpdate = 0; @@ -47,7 +47,7 @@ protected void update(final ServerWorld worldIn, final AgeableEntity entityIn) @Override public Set> getUsedMemories() { - return ImmutableSet.of(MemoryModules.POSSIBLE_MATES); + return ImmutableSet.of(MemoryModules.POSSIBLE_MATES, MemoryModules.HERD_MEMBERS); } } diff --git a/src/main/java/pokecube/core/ai/brain/sensors/NearBlocks.java b/src/main/java/pokecube/core/ai/brain/sensors/NearBlocks.java index a09e2320ba..902742a57c 100644 --- a/src/main/java/pokecube/core/ai/brain/sensors/NearBlocks.java +++ b/src/main/java/pokecube/core/ai/brain/sensors/NearBlocks.java @@ -21,6 +21,7 @@ import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; import net.minecraft.world.server.ServerWorld; +import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; import pokecube.core.ai.brain.MemoryModules; import thut.api.maths.Cruncher; @@ -68,7 +69,7 @@ public BlockState getState() } } - long lastUpdate = 0; + int tick = 0; @Override protected void update(final ServerWorld worldIn, final LivingEntity entityIn) @@ -76,6 +77,9 @@ protected void update(final ServerWorld worldIn, final LivingEntity entityIn) if (BrainUtils.hasAttackTarget(entityIn)) return; if (BrainUtils.hasMoveUseTarget(entityIn)) return; + this.tick++; + if (this.tick % PokecubeCore.getConfig().nearBlockUpdateRate != 0) return; + final Vector3 r = Vector3.getNewVector(), rAbs = Vector3.getNewVector(); final Vector3 origin = Vector3.getNewVector(); origin.set(entityIn); @@ -83,6 +87,7 @@ protected void update(final ServerWorld worldIn, final LivingEntity entityIn) final int size = 8; final Vec3d start = entityIn.getEyePosition(1); + final Predicate visible = input -> { final Vec3d end = new Vec3d(input); diff --git a/src/main/java/pokecube/core/ai/logic/LogicInMaterials.java b/src/main/java/pokecube/core/ai/logic/LogicInMaterials.java index 3b879a6ca9..51df672da9 100644 --- a/src/main/java/pokecube/core/ai/logic/LogicInMaterials.java +++ b/src/main/java/pokecube/core/ai/logic/LogicInMaterials.java @@ -17,13 +17,13 @@ public class LogicInMaterials extends LogicBase { Vector3 v = Vector3.getNewVector(); - public LogicInMaterials(IPokemob entity) + public LogicInMaterials(final IPokemob entity) { super(entity); } @Override - public void tick(World world) + public void tick(final World world) { super.tick(world); if (this.pokemob.getPokedexEntry().hatedMaterial != null) @@ -46,8 +46,8 @@ else if (action.equalsIgnoreCase("hurt") && Math.random() < 0.1) this.entity.att } } else if (material.equalsIgnoreCase("water")) if (this.entity.isInWater() && this.entity.getRNG().nextInt( - 10) == 0) this.entity.attackEntityFrom(new TerrainDamageSource("material", TerrainType.MATERIAL), - 1); + 10) == 0) this.entity.attackEntityFrom(new TerrainDamageSource("material", TerrainType.MATERIAL, + null), 1); } } } diff --git a/src/main/java/pokecube/core/ai/logic/LogicMiscUpdate.java b/src/main/java/pokecube/core/ai/logic/LogicMiscUpdate.java index fab3914e14..e7165896c7 100644 --- a/src/main/java/pokecube/core/ai/logic/LogicMiscUpdate.java +++ b/src/main/java/pokecube/core/ai/logic/LogicMiscUpdate.java @@ -2,7 +2,9 @@ import java.util.Calendar; import java.util.Random; +import java.util.UUID; +import net.minecraft.entity.AgeableEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; import net.minecraft.particles.ParticleTypes; @@ -28,6 +30,7 @@ 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.PokemobTracker; import thut.api.item.ItemList; import thut.api.maths.Vector3; @@ -45,17 +48,22 @@ public class LogicMiscUpdate extends LogicBase public static final boolean holiday = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) == 25 && Calendar .getInstance().get(Calendar.MONTH) == 11; - private int lastHadTargetTime = 0; - private final int[] flavourAmounts = new int[5]; + private int lastHadTargetTime = 0; + + private final int[] flavourAmounts = new int[5]; + private PokedexEntry entry; - private String particle = null; - private boolean reset = false; - private boolean initHome = false; - private boolean checkedEvol = false; - private int pathTimer = 0; - private long dynatime = -1; - private boolean de_dyna = false; - Vector3 v = Vector3.getNewVector(); + private String particle = null; + private boolean reset = false; + private boolean initHome = false; + private boolean checkedEvol = false; + private int pathTimer = 0; + private long dynatime = -1; + private boolean de_dyna = false; + + Vector3 v = Vector3.getNewVector(); + + UUID prevOwner = null; public LogicMiscUpdate(final IPokemob entity) { @@ -94,6 +102,9 @@ private void checkAIStates() this.de_dyna = false; } + if (this.pokemob.getGeneralState(GeneralStates.MATING) && !BrainUtils.hasMateTarget( + (AgeableEntity) this.entity)) this.pokemob.setGeneralState(GeneralStates.MATING, false); + // Check if we are sheared every second or so if (this.entity.ticksExisted % 20 == 0) this.pokemob.isSheared(); @@ -119,6 +130,7 @@ else if (!angry && this.reset) this.pokemob.getModifiers().outOfCombatReset(); this.pokemob.getMoveStats().reset(); } + this.pokemob.setCombatState(CombatStates.NOITEMUSE, false); } else /** Angry pokemobs shouldn't decide to walk around. */ this.pokemob.setRoutineState(AIRoutine.AIRBORNE, true); @@ -263,10 +275,18 @@ public void tick(final World world) // Everything below here is client side only! - if (id >= 0 && targ == null) BrainUtils.setAttackTarget(this.entity, (LivingEntity) PokecubeCore - .getEntityProvider().getEntity(world, id, false)); - if (id < 0 && targ != null) BrainUtils.setAttackTarget(this.entity, null); - if (targ != null && !targ.isAlive()) BrainUtils.setAttackTarget(this.entity, null); + if (id >= 0 && targ == null) this.entity.setAttackTarget((LivingEntity) PokecubeCore.getEntityProvider() + .getEntity(world, id, false)); + if (id < 0 && targ != null) this.entity.setAttackTarget(null); + if (targ != null && !targ.isAlive()) this.entity.setAttackTarget(null); + + // Sync the addition of this, as onAddedToWorld is called before this + // value is synchronized + if (this.prevOwner == null && this.pokemob.getOwnerId() != null) + { + this.prevOwner = this.pokemob.getOwnerId(); + PokemobTracker.addPokemob(this.pokemob); + } // Particle stuff below here, WARNING, RESETTING RNG HERE rand = new Random(); diff --git a/src/main/java/pokecube/core/ai/npc/Schedules.java b/src/main/java/pokecube/core/ai/npc/Schedules.java index 6d49c7e1b0..6e7e055d3d 100644 --- a/src/main/java/pokecube/core/ai/npc/Schedules.java +++ b/src/main/java/pokecube/core/ai/npc/Schedules.java @@ -25,7 +25,6 @@ private static Schedule makeAdult() //@formatter:off .add(10, Activity.IDLE) .add(10, Activities.STATIONARY) - .add(10, Activities.BATTLE) .add(2000,Activity.WORK) .add(9000, Activity.MEET) .add(11000, Activity.IDLE) @@ -37,8 +36,8 @@ private static Schedule makeAdult() private static Schedule makeChild() { final ScheduleBuilder builder = new ScheduleBuilder(new Schedule()); - builder.add(10, Activity.IDLE).add(10, Activities.STATIONARY).add(10, Activities.BATTLE).add(3000, - Activity.PLAY).add(6000, Activity.IDLE).add(10000, Activity.PLAY).add(12000, Activity.REST); + builder.add(10, Activity.IDLE).add(10, Activities.STATIONARY).add(3000, Activity.PLAY).add(6000, Activity.IDLE) + .add(10000, Activity.PLAY).add(12000, Activity.REST); return builder.build(); } } diff --git a/src/main/java/pokecube/core/ai/routes/GuardTask.java b/src/main/java/pokecube/core/ai/routes/GuardTask.java index 3fe6e7d702..532dd0308a 100644 --- a/src/main/java/pokecube/core/ai/routes/GuardTask.java +++ b/src/main/java/pokecube/core/ai/routes/GuardTask.java @@ -28,7 +28,9 @@ protected boolean shouldContinueExecuting(final ServerWorld worldIn, final Livin @Override protected boolean shouldExecute(final ServerWorld worldIn, final LivingEntity owner) { - return this.goal.shouldExecute(); + final boolean valid = this.goal.shouldExecute(); + if (!valid && owner.getBrain().hasActivity(Activities.STATIONARY)) owner.getBrain().switchTo(Activity.IDLE); + return valid; } @Override diff --git a/src/main/java/pokecube/core/ai/tasks/AIFollowOwner.java b/src/main/java/pokecube/core/ai/tasks/AIFollowOwner.java index c6b0513d1b..49f7796e41 100644 --- a/src/main/java/pokecube/core/ai/tasks/AIFollowOwner.java +++ b/src/main/java/pokecube/core/ai/tasks/AIFollowOwner.java @@ -93,9 +93,8 @@ else if (!this.petPathfinder.noPath() && this.petPathfinder.getPath().getCurrent BrainUtils.lookAt(this.entity, x, y, z); } - 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); + final double dl = this.v.set(this.entity).distTo(this.ownerPos); + this.ownerPos.set(this.theOwner); double ownerSpeed = this.theOwner.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); @@ -109,11 +108,12 @@ else if (!this.petPathfinder.noPath() && this.petPathfinder.getPath().getCurrent if (ownerSpeed == 0) ownerSpeed = this.pokemob.getMovementSpeed(); double dist_speed = ownerSpeed; - if (dl > 3) dist_speed *= 1 + (dl - 3) / 10; + if (dl > 3) dist_speed *= 1 + (dl - 3) / 20; + 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); + this.speed = Math.min(1.25, this.speed); this.setWalkTo(this.ownerPos, this.speed, 0); } diff --git a/src/main/java/pokecube/core/ai/tasks/TaskBase.java b/src/main/java/pokecube/core/ai/tasks/TaskBase.java index c5a76dd3cd..82542713d9 100644 --- a/src/main/java/pokecube/core/ai/tasks/TaskBase.java +++ b/src/main/java/pokecube/core/ai/tasks/TaskBase.java @@ -155,18 +155,23 @@ protected void setWalkTo(final Vector3 pos, final double speed, final int dist) protected void setWalkTo(final Vec3d pos, final double speed, final int dist) { - this.entity.getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(pos, (float) speed, dist)); + this.setWalkTo(new WalkTarget(pos, (float) speed, dist)); } protected void setWalkTo(final BlockPos pos, final double speed, final int dist) { - this.entity.getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(pos, (float) speed, dist)); + this.setWalkTo(new WalkTarget(pos, (float) speed, dist)); } protected void setWalkTo(final Entity mobIn, final double speed, final int dist) { - this.entity.getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(new EntityPosWrapper(mobIn), - (float) speed, dist)); + this.setWalkTo(new WalkTarget(new EntityPosWrapper(mobIn), (float) speed, dist)); + } + + protected void setWalkTo(final WalkTarget target) + { + this.pokemob.setLogicState(LogicStates.SITTING, false); + this.entity.getBrain().setMemory(MemoryModules.WALK_TARGET, target); } @Override diff --git a/src/main/java/pokecube/core/ai/tasks/Tasks.java b/src/main/java/pokecube/core/ai/tasks/Tasks.java index 8f492c8ff4..97f4590727 100644 --- a/src/main/java/pokecube/core/ai/tasks/Tasks.java +++ b/src/main/java/pokecube/core/ai/tasks/Tasks.java @@ -19,7 +19,7 @@ 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.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; import pokecube.core.ai.brain.MemoryModules; import pokecube.core.ai.brain.Sensors; @@ -28,19 +28,22 @@ 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; -import pokecube.core.ai.tasks.combat.AIFindTarget; -import pokecube.core.ai.tasks.combat.AILeap; -import pokecube.core.ai.tasks.combat.AISelectMove; -import pokecube.core.ai.tasks.idle.AIGuardEgg; -import pokecube.core.ai.tasks.idle.AIHungry; -import pokecube.core.ai.tasks.idle.AIIdle; -import pokecube.core.ai.tasks.idle.AIMate; -import pokecube.core.ai.tasks.utility.AIGatherStuff; -import pokecube.core.ai.tasks.utility.AIStoreStuff; -import pokecube.core.ai.tasks.utility.AIUseMove; +import pokecube.core.ai.tasks.combat.attacks.SelectMoveTask; +import pokecube.core.ai.tasks.combat.attacks.UseAttacksTask; +import pokecube.core.ai.tasks.combat.management.CallForHelpTask; +import pokecube.core.ai.tasks.combat.management.FindTargetsTask; +import pokecube.core.ai.tasks.combat.management.ForgetTargetTask; +import pokecube.core.ai.tasks.combat.movement.CicleTask; +import pokecube.core.ai.tasks.combat.movement.DodgeTask; +import pokecube.core.ai.tasks.combat.movement.LeapTask; +import pokecube.core.ai.tasks.idle.ForgetHuntedByTask; +import pokecube.core.ai.tasks.idle.GuardEggTask; +import pokecube.core.ai.tasks.idle.HungerTask; +import pokecube.core.ai.tasks.idle.IdleWalkTask; +import pokecube.core.ai.tasks.idle.MateTask; +import pokecube.core.ai.tasks.utility.GatherTask; +import pokecube.core.ai.tasks.utility.StoreTask; +import pokecube.core.ai.tasks.utility.UseMoveTask; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.pokemob.ai.GeneralStates; import pokecube.core.utils.CapHolders; @@ -57,17 +60,16 @@ public class Tasks public static final List> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.INTERACTABLE_DOORS, SensorType.HURT_BY, Sensors.VISIBLE_BLOCKS, - Sensors.VISIBLE_ITEMS, Sensors.VALID_MATES); + Sensors.VISIBLE_ITEMS, Sensors.INTERESTING_MOBS); public static void initBrain(final Brain brain) { BrainUtils.addToBrain(brain, Tasks.MEMORY_TYPES, Tasks.SENSOR_TYPES); } - //@formatter:off @SuppressWarnings("unchecked") - public static ImmutableList>> idle( - final IPokemob pokemob, final float speed) + public static ImmutableList>> idle(final IPokemob pokemob, + final float speed) { // Tasks for idle final List aiList = Lists.newArrayList(); @@ -76,22 +78,22 @@ public static void initBrain(final Brain brain) final IGuardAICapability guardCap = entity.getCapability(CapHolders.GUARDAI_CAP).orElse(null); // Idle tasks // Guard your egg - aiList.add(new AIGuardEgg(pokemob).setPriority(250)); + aiList.add(new GuardEggTask(pokemob)); // Mate with things - aiList.add(new AIMate(pokemob).setPriority(300)); + aiList.add(new MateTask(pokemob)); // Eat things - aiList.add(new AIHungry(pokemob, new ItemEntity(entity.getEntityWorld(), 0, 0, 0), 16).setPriority(300)); + aiList.add(new HungerTask(pokemob)); // Wander around - aiList.add(new AIIdle(pokemob).setPriority(500)); + aiList.add(new IdleWalkTask(pokemob)); // Owner related tasks if (!pokemob.getPokedexEntry().isStationary) // Follow owner around - aiList.add(new AIFollowOwner(pokemob, 3 + entity.getWidth() + pokemob.getPokedexEntry().length, 8 + entity.getWidth() - + pokemob.getPokedexEntry().length).setPriority(400)); + aiList.add(new AIFollowOwner(pokemob, 3 + entity.getWidth() + pokemob.getPokedexEntry().length, 8 + entity + .getWidth() + pokemob.getPokedexEntry().length)); final List>> list = Lists.newArrayList(); - final GuardAI guardai = new GuardAI(pokemob.getEntity(),guardCap); + final GuardAI guardai = new GuardAI(pokemob.getEntity(), guardCap); guardai.shouldRun = new ShouldRun() { @Override @@ -105,14 +107,14 @@ 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 task = new LookTask(45, 90); + list.add(Pair.of(1, (Task) task)); task = new WalkToTask(200); - list.add(Pair.of(1, (Task)task)); + 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)); + 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()); @@ -129,34 +131,39 @@ public boolean shouldRun() } @SuppressWarnings("unchecked") - public static ImmutableList>> combat( - final IPokemob pokemob, final float speed) + public static ImmutableList>> combat(final IPokemob pokemob, + final float speed) { // Tasks for combat final List aiList = Lists.newArrayList(); // combat tasks - aiList.add(new AISelectMove(pokemob).setPriority(190)); + aiList.add(new SelectMoveTask(pokemob)); + // Attack stuff + aiList.add(new UseAttacksTask(pokemob)); // Attack stuff - aiList.add(new AIAttack(pokemob).setPriority(200)); + aiList.add(new ForgetTargetTask(pokemob)); // Dodge attacks - aiList.add(new AIDodge(pokemob).setPriority(225)); + aiList.add(new DodgeTask(pokemob)); // Leap at things - aiList.add(new AILeap(pokemob).setPriority(225)); + aiList.add(new LeapTask(pokemob)); // Move around in combat - aiList.add(new AICombatMovement(pokemob).setPriority(250)); + aiList.add(new CicleTask(pokemob)); + // Call for help task + aiList.add(new CallForHelpTask(pokemob, (float) PokecubeCore.getConfig().hordeRateFactor)); + // Look for targets to kill - final AIFindTarget targetFind = new AIFindTarget(pokemob); - aiList.add(targetFind.setPriority(400)); + final FindTargetsTask targetFind = new FindTargetsTask(pokemob); + aiList.add(targetFind); pokemob.setTargetFinder(targetFind); final List>> list = Lists.newArrayList(); - Task task = new LookTask(45, 90); - list.add(Pair.of(1, (Task)task)); + 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)); + 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) @@ -170,25 +177,27 @@ public boolean shouldRun() } @SuppressWarnings("unchecked") - public static ImmutableList>> utility( - final IPokemob pokemob, final float speed) + public static ImmutableList>> utility(final IPokemob pokemob, + final float speed) { // Tasks for utilitiy final List aiList = Lists.newArrayList(); // combat tasks - final AIStoreStuff ai = new AIStoreStuff(pokemob); + final StoreTask ai = new StoreTask(pokemob); // Store things in chests - aiList.add(ai.setPriority(350)); + aiList.add(ai); // Gather things from ground - aiList.add(new AIGatherStuff(pokemob, 32, ai).setPriority(400)); + aiList.add(new GatherTask(pokemob, 32, ai)); // Execute moves when told to - aiList.add(new AIUseMove(pokemob).setPriority(250)); + aiList.add(new UseMoveTask(pokemob)); + // forget we were being hunted + aiList.add(new ForgetHuntedByTask(pokemob, 100)); final List>> list = Lists.newArrayList(); final IGuardAICapability guardCap = pokemob.getEntity().getCapability(CapHolders.GUARDAI_CAP).orElse(null); - final GuardAI guardai = new GuardAI(pokemob.getEntity(),guardCap); + final GuardAI guardai = new GuardAI(pokemob.getEntity(), guardCap); guardai.shouldRun = new ShouldRun() { @Override @@ -202,13 +211,13 @@ public boolean shouldRun() list.add(pair); Task task = new LookTask(45, 90); - list.add(Pair.of(1, (Task)task)); + list.add(Pair.of(1, (Task) task)); task = new WalkToTask(200); - list.add(Pair.of(1, (Task)task)); + 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)); + 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) @@ -221,6 +230,7 @@ public boolean shouldRun() return ImmutableList.copyOf(list); } + //@formatter:off private static Pair> lookAtMany() { return Pair.of(5, new FirstShuffledTask<>( diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AIFindTarget.java b/src/main/java/pokecube/core/ai/tasks/combat/AIFindTarget.java deleted file mode 100644 index 03677d5a13..0000000000 --- a/src/main/java/pokecube/core/ai/tasks/combat/AIFindTarget.java +++ /dev/null @@ -1,654 +0,0 @@ -package pokecube.core.ai.tasks.combat; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.function.Predicate; - -import org.apache.logging.log4j.Level; - -import com.google.common.collect.ImmutableMap; - -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; -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.player.PlayerEntity; -import net.minecraft.util.DamageSource; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.living.LivingAttackEvent; -import net.minecraftforge.event.entity.living.LivingDamageEvent; -import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; -import net.minecraftforge.eventbus.api.Event.Result; -import net.minecraftforge.eventbus.api.SubscribeEvent; -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.handlers.TeamManager; -import pokecube.core.handlers.events.PCEventsHandler; -import pokecube.core.interfaces.IMoveConstants.AIRoutine; -import pokecube.core.interfaces.IPokemob; -import pokecube.core.interfaces.IPokemob.ITargetFinder; -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.AITools; -import thut.api.IOwnable; -import thut.api.OwnableCaps; -import thut.api.entity.ai.IAICombat; -import thut.api.maths.Vector3; -import thut.api.terrain.TerrainManager; - -/** This IAIRunnable is to find targets for the pokemob to try to kill. */ -public class AIFindTarget extends TaskBase implements IAICombat, ITargetFinder -{ - - public static boolean handleDamagedTargets = true; - static - { - MinecraftForge.EVENT_BUS.register(AIFindTarget.class); - } - - public static int DEAGROTIMER = 50; - - public static void initiateCombat(final MobEntity mob, final LivingEntity target) - { - // No target self - if (mob == target) return; - // No target null - if (target == null) return; - // No target dead - if (!target.isAlive() || target.getHealth() <= 0) return; - // No target already had target - if (target == BrainUtils.getAttackTarget(mob)) return; - - final IPokemob aggressor = CapabilityPokemob.getPokemobFor(mob); - final IPokemob targetMob = CapabilityPokemob.getPokemobFor(target); - if (targetMob != null) targetMob.setCombatState(CombatStates.ANGRY, true); - if (aggressor != null) aggressor.setCombatState(CombatStates.ANGRY, true); - - BrainUtils.setAttackTarget(mob, target); - BrainUtils.setAttackTarget(target, mob); - } - - public static void deagro(final LivingEntity mob) - { - if (mob == null) return; - final IPokemob aggressor = CapabilityPokemob.getPokemobFor(mob); - - if (mob instanceof MobEntity) - { - final LivingEntity oldTarget = BrainUtils.getAttackTarget(mob); - BrainUtils.setAttackTarget(mob, null); - AIFindTarget.deagro(oldTarget); - } - mob.getBrain().removeMemory(MemoryModules.ATTACKTARGET); - if (aggressor != null) - { - aggressor.getTargetFinder().clear(); - aggressor.setCombatState(CombatStates.ANGRY, false); - aggressor.setCombatState(CombatStates.MATEFIGHT, false); - } - } - - @SubscribeEvent - public static void livingSetTargetEvent(final LivingSetAttackTargetEvent evt) - { - if (!AIFindTarget.handleDamagedTargets || evt.getEntity().getEntityWorld().isRemote) return; - // Only handle attack target set, not revenge target set. - if (evt.getTarget() == ((LivingEntity) evt.getEntity()).getRevengeTarget()) return; - // Prevent mob from targetting self. - if (evt.getTarget() == evt.getEntity()) - { - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.log(Level.WARN, evt.getTarget() - + " is targetting self again.", new IllegalArgumentException()); - return; - } - - // Attempt to divert the target over to one of our mobs. - final List outmobs = PCEventsHandler.getOutMobs(evt.getTarget(), true); - outmobs.removeIf(o -> o == evt.getEntityLiving() || !o.isAlive()); - if (!outmobs.isEmpty() && evt.getEntityLiving() instanceof MobEntity) - { - Collections.sort(outmobs, (o1, o2) -> - { - final double dist1 = o1.getDistanceSq(evt.getEntityLiving()); - final double dist2 = o2.getDistanceSq(evt.getEntityLiving()); - return (int) (dist1 - dist2); - }); - final Entity nearest = outmobs.get(0); - if (nearest.getDistanceSq(evt.getEntityLiving()) < 256 && nearest instanceof LivingEntity) - { - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug("Diverting agro to owner!"); - AIFindTarget.initiateCombat((MobEntity) evt.getEntityLiving(), (LivingEntity) nearest); - return; - } - } - - final IPokemob pokemob = CapabilityPokemob.getPokemobFor(evt.getEntity()); - if (pokemob != null) - { - if (evt.getTarget() != null && pokemob.getTargetID() == evt.getTarget().getEntityId()) - { - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug("Already targetted!"); - return; - } - if (evt.getTarget() == null && pokemob.getTargetID() == -1) return; - - // Prevent pokemob from targetting its owner. - if (evt.getTarget() != null && evt.getTarget().getUniqueID().equals(pokemob.getOwnerId())) - { - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.log(Level.WARN, evt.getTarget() - + " is targetting owner.", new IllegalArgumentException()); - return; - } - final boolean force = evt.getTarget() != null && evt.getTarget().getLastAttackedEntity() == evt.getEntity(); - pokemob.onSetTarget(evt.getTarget(), force); - } - } - - /** Prevents the owner from attacking their own pokemob. */ - @SubscribeEvent - public static void onAttacked(final LivingAttackEvent event) - { - if (!AIFindTarget.handleDamagedTargets || event.getEntity().getEntityWorld().isRemote) return; - - final DamageSource source = event.getSource(); - final LivingEntity attacked = (LivingEntity) event.getEntity(); - final IPokemob pokemobCap = CapabilityPokemob.getPokemobFor(attacked); - if (pokemobCap == null) return; - - final Entity attacker = source.getTrueSource(); - - // Camcel the event if it is from owner. - if (pokemobCap.getGeneralState(GeneralStates.TAMED) && attacker instanceof PlayerEntity && attacker - .getUniqueID().equals(pokemobCap.getOwnerId())) - { - event.setCanceled(true); - event.setResult(Result.DENY); - return; - } - } - - /** - * Prevents the owner from attacking their own pokemob, and takes care of - * properly setting attack targets for whatever was hurt. - */ - @SubscribeEvent - public static void onDamaged(final LivingDamageEvent event) - { - if (!AIFindTarget.handleDamagedTargets || event.getEntity().getEntityWorld().isRemote) return; - - final DamageSource source = event.getSource(); - final LivingEntity attacked = (LivingEntity) event.getEntity(); - final IPokemob pokemobCap = CapabilityPokemob.getPokemobFor(attacked); - if (pokemobCap == null) return; - - Entity attacker = source.getTrueSource(); - - // Cancel the event if it is from owner. - if (pokemobCap.getGeneralState(GeneralStates.TAMED) && attacker instanceof PlayerEntity - && (PlayerEntity) attacker == pokemobCap.getOwner()) - { - event.setCanceled(true); - event.setResult(Result.DENY); - return; - } - pokemobCap.setLogicState(LogicStates.SITTING, false); - - if (attacked instanceof MobEntity) - { - LivingEntity oldTarget = BrainUtils.getAttackTarget(attacked); - // Don't include dead old targets. - if (oldTarget != null && !oldTarget.isAlive()) oldTarget = null; - - if (!(oldTarget == null && attacker != attacked && attacker instanceof LivingEntity - && oldTarget != attacker)) attacker = null; - - LivingEntity newTarget = oldTarget; - // Either keep old target, or agress the attacker. - if (oldTarget != null && BrainUtils.getAttackTarget(attacked) != oldTarget) newTarget = oldTarget; - else if (attacker instanceof LivingEntity) newTarget = (LivingEntity) attacker; - final MobEntity living = (MobEntity) attacked; - AIFindTarget.initiateCombat(living, newTarget); - } - - } - - Vector3 v = Vector3.getNewVector(); - Vector3 v1 = Vector3.getNewVector(); - - /** - * Checks the validTargts as well as team settings, will not allow - * 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; - - public AIFindTarget(final IPokemob mob) - { - super(mob, ImmutableMap.of(MemoryModuleType.VISIBLE_MOBS, MemoryModuleStatus.VALUE_PRESENT)); - } - - @Override - public void clear() - { - this.agroTimer = AIFindTarget.DEAGROTIMER; - this.entityTarget = null; - } - - /** - * Check if there are any mobs nearby that will help us.
- *
- * This is called from {@link AIFindTarget#shouldRun()} - * - * @return someone needed help. - */ - protected boolean checkForHelp(final LivingEntity from) - { - // No need to get help against null - if (from == null) return false; - - // Not social. doesn't do this. - if (!this.pokemob.getPokedexEntry().isSocial) return false; - - // Random factor for this ai to apply - if (Math.random() > 0.01 * PokecubeCore.getConfig().hordeRateFactor) return false; - - final List ret = new ArrayList<>(); - final List pokemobs = this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS).get(); - - // Select either owner or home position as the centre of the check, - // this results in it guarding either its home or its owner. Home is - // used if it is on stay, or it has no owner. - final Vector3 centre = Vector3.getNewVector(); - if (this.pokemob.getGeneralState(GeneralStates.STAYING) || this.pokemob.getOwner() == null) centre.set( - this.pokemob.getHome()); - else centre.set(this.pokemob.getOwner()); - - if (!TerrainManager.isAreaLoaded(this.world, centre, 18)) return false; - - // pokemobs = - // this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS); - - // We check for whether it is the same species and, has the same owner - // (including null) or is on the team. - final Predicate relationCheck = input -> - { - final IPokemob other = CapabilityPokemob.getPokemobFor(input); - // No pokemob, no helps. - if (other == null) return false; - // Not related, no helps. - if (!other.getPokedexEntry().areRelated(AIFindTarget.this.pokemob.getPokedexEntry())) return false; - // Same owner (owned or null), helps. - if (other.getOwnerId() == null && AIFindTarget.this.pokemob.getOwnerId() == null || other - .getOwnerId() != null && other.getOwnerId().equals(AIFindTarget.this.pokemob.getOwnerId())) - return true; - // Same team, helps. - if (TeamManager.sameTeam(input, AIFindTarget.this.entity)) return true; - return false; - }; - - // Only allow valid guard targets. - for (final Object o : pokemobs) - if (relationCheck.test((MobEntity) o)) ret.add((MobEntity) o); - - for (final LivingEntity mob : ret) - { - if (!(mob instanceof MobEntity)) continue; - // Only agress mobs that can see you are really under attack. - if (!mob.canEntityBeSeen(this.entity)) continue; - // Only agress if not currently in combat. - if (BrainUtils.hasAttackTarget(mob)) continue; - // Make all valid ones agress the target. - this.setAttackTarget((MobEntity) mob, from); - } - - return false; - } - - /** - * Check for and agress any guard targets.
- *
- * This is called from {@link AIFindTarget#run()} - * - * @return a guard target was found - */ - protected boolean checkGuard() - { - // Disabled via the boolean config. - if (!PokecubeCore.getConfig().guardModeEnabled) return false; - - final int rate = PokecubeCore.getConfig().guardTickRate; - // Disable via rate out of bounds, or not correct time in the rate. - if (rate <= 0 || this.entity.ticksExisted % rate != 0) return false; - - // Select either owner or home position as the centre of the check, - // this results in it guarding either its home or its owner. Home is - // used if it is on stay, or it has no owner. - final Vector3 centre = Vector3.getNewVector(); - if (this.pokemob.getGeneralState(GeneralStates.STAYING) || this.pokemob.getOwner() == null) centre.set( - this.pokemob.getHome()); - else centre.set(this.pokemob.getOwner()); - - if (!TerrainManager.isAreaLoaded(this.world, centre, PokecubeCore.getConfig().guardSearchDistance + 2)) - return false; - - final List ret = new ArrayList<>(); - final List pokemobs = this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS).get(); - // Only allow valid guard targets. - for (final Object o : pokemobs) - if (this.validGuardTarget.test((Entity) o)) ret.add((LivingEntity) o); - ret.removeIf(e -> e.getDistance(this.entity) > PokecubeCore.getConfig().guardSearchDistance); - if (ret.isEmpty()) return false; - - LivingEntity newtarget = null; - double closest = Integer.MAX_VALUE; - final Vector3 here = this.v1.set(this.entity, true); - - // Select closest visible guard target. - for (final LivingEntity e : ret) - { - final double dist = e.getDistanceSq(this.entity); - this.v.set(e, true); - if (dist < closest && here.isVisible(this.world, this.v)) - { - closest = dist; - newtarget = e; - } - } - - // Agro the target. - if (newtarget != null && Vector3.isVisibleEntityFromEntity(this.entity, newtarget)) - { - this.setAttackTarget(this.entity, newtarget); - return true; - } - return false; - } - - protected void setAttackTarget(final MobEntity attacker, final LivingEntity target) - { - if (target == null) - { - AIFindTarget.deagro(attacker); - this.clear(); - } - else - { - AIFindTarget.initiateCombat(attacker, target); - this.entityTarget = target; - } - } - - /** - * Check if there is a target to hunt, if so, sets it as target.
- *
- * This is called from {@link AIFindTarget#run()} - * - * @return if a hunt target was found. - */ - protected boolean checkHunt() - { - final int rate = PokecubeCore.getConfig().hungerTickRate; - // Disable via rate out of bounds, or not correct time in the rate. - if (rate <= 0 || this.entity.ticksExisted % rate != 0) return false; - - if (!TerrainManager.isAreaLoaded(this.world, this.entity.getPosition(), PokecubeCore - .getConfig().guardSearchDistance + 2)) return false; - - final List list = new ArrayList<>(); - final List pokemobs = this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS).get(); - list.addAll(pokemobs); - list.removeIf(e -> e.getDistance(this.entity) > PokecubeCore.getConfig().guardSearchDistance); - if (list.isEmpty()) return false; - - if (!list.isEmpty()) for (final LivingEntity entity : list) - { - final IPokemob mob = CapabilityPokemob.getPokemobFor(entity); - if (mob != null && this.pokemob.getPokedexEntry().isFood(mob.getPokedexEntry()) && this.pokemob - .getLevel() > mob.getLevel() && Vector3.isVisibleEntityFromEntity(entity, entity)) - { - this.setAttackTarget(this.entity, entity); - return true; - } - } - return false; - } - - /** - * Check if owner is under attack, if so, agress the attacker.
- *
- * This is called from {@link AIFindTarget#run()} - * - * @return if target was found. - */ - protected boolean checkOwner() - { - final Entity owner = this.pokemob.getOwner(); - - // Only apply if has owner. - if (owner == null) return false; - // Only apply if owner is close. - if (this.entity.getDistanceSq(owner) > 64) return false; - - final int rate = PokecubeCore.getConfig().guardTickRate; - // Disable via rate out of bounds, or not correct time in the rate. - if (rate <= 0 || this.entity.ticksExisted % rate != 0) return false; - - if (!TerrainManager.isAreaLoaded(this.world, this.entity.getPosition(), PokecubeCore - .getConfig().guardSearchDistance + 2)) return false; - - final List list = new ArrayList<>(); - final List pokemobs = this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS).get(); - list.addAll(pokemobs); - list.removeIf(e -> e.getDistance(this.entity) > PokecubeCore.getConfig().guardSearchDistance); - if (list.isEmpty()) return false; - - final Entity old = BrainUtils.getAttackTarget(this.entity); - final IOwnable oldOwnable = OwnableCaps.getOwnable(old); - final Entity oldOwner = oldOwnable != null ? oldOwnable.getOwner(this.world) : null; - - if (!list.isEmpty()) for (final LivingEntity entity : list) - { - if (oldOwner != null && entity == oldOwner) return false; - final LivingEntity targ = BrainUtils.getAttackTarget(entity); - if (entity instanceof MobEntity && targ != null && targ.equals(owner) && Vector3.isVisibleEntityFromEntity( - entity, entity)) - { - this.setAttackTarget(this.entity, entity); - return true; - } - } - return false; - } - - @Override - public void reset() - { - } - - @Override - public void run() - { - final LivingEntity targ = BrainUtils.getAttackTarget(this.entity); - // No need to find a target if we have one. - if (targ != null) - { - // If target is dead, lets forget about it. - if (!targ.isAlive() || targ.getHealth() <= 0) this.clear(); - return; - } - - // If hunting, look for valid prey, and if found, agress it. - if (!this.pokemob.getLogicState(LogicStates.SITTING) && this.pokemob.isCarnivore() && this.pokemob - .getCombatState(CombatStates.HUNTING)) if (this.checkHunt()) return; - // If guarding, look for mobs not on the same team as you, and if you - // find them, try to agress them. - if (this.pokemob.getCombatState(CombatStates.GUARDING)) if (this.checkGuard()) return; - } - - @Override - public boolean shouldRun() - { - if (!this.pokemob.isRoutineEnabled(AIRoutine.AGRESSIVE)) return false; - - if (!this.entity.getBrain().hasMemory(MemoryModuleType.VISIBLE_MOBS)) return false; - - // Ensure the correct owner is tracked. - this.pokemob.getOwner(this.world); - - LivingEntity target = BrainUtils.getAttackTarget(this.entity); - - // Don't look for targets if you are sitting. - final boolean ret = target == null && !this.pokemob.getLogicState(LogicStates.SITTING); - final boolean tame = this.pokemob.getGeneralState(GeneralStates.TAMED); - - // Target is too far away, lets forget it. - if (target != null && this.entity.getDistance(target) > PokecubeCore.getConfig().chaseDistance) - { - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug("Forgetting Target due to distance. {} -> {}", - this.entity, target); - this.setAttackTarget(this.entity, null); - return false; - } - - // If we have a target, we don't need to look for another. - if (target != null) - { - final IOwnable targetOwnable = OwnableCaps.getOwnable(this.entityTarget); - - // Prevents swapping to owner as target if we are owned and we just - // defeated someone, only applies to tame mobs, wild mobs will still - // try to kill the owner if they run away. - if (this.entityTarget != null && this.entityTarget != target && targetOwnable != null && targetOwnable - .getOwner(this.world) == target && this.pokemob.getGeneralState(GeneralStates.TAMED) - && this.entityTarget.getHealth() <= 0) - { - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug("Battle is over."); - this.setAttackTarget(this.entity, null); - return false; - } - - this.entityTarget = target; - // If our target is dead, we can forget it, so long as it isn't - // owned - if (!target.isAlive() || target.getHealth() <= 0) - { - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug("Target is dead!"); - this.setAttackTarget(this.entity, null); - return false; - } - - // If our target is us, we should forget it. - if (target == this.entity) - { - this.setAttackTarget(this.entity, null); - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug("Cannot target self."); - return false; - } - - // If we are not angry, we should forget target. - if (!this.pokemob.getCombatState(CombatStates.ANGRY)) - { - this.setAttackTarget(this.entity, null); - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug("Not Angry. losing target now."); - return false; - } - - // If our target is owner, we should forget it. - if (target.getUniqueID().equals(this.pokemob.getOwnerId())) - { - this.setAttackTarget(this.entity, null); - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug("Cannot target owner."); - return false; - } - - // If your owner is too far away, shouldn't have a target, should be - // going back to the owner. - if (tame) - { - final Entity owner = this.pokemob.getOwner(); - final boolean stayOrGuard = this.pokemob.getCombatState(CombatStates.GUARDING) || this.pokemob - .getGeneralState(GeneralStates.STAYING); - if (owner != null && !stayOrGuard && owner.getDistance(this.entity) > PokecubeCore - .getConfig().chaseDistance) - { - this.setAttackTarget(this.entity, null); - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug( - "Cannot target mob that far while guarding."); - return false; - } - - // If the target is a pokemob, on same team, we shouldn't target - // 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."); - return false; - } - - } - return false; - } - - // Check if the pokemob is set to follow, and if so, look for mobs - // nearby trying to attack the owner of the pokemob, if any such are - // found, try to aggress them immediately. - if (!this.pokemob.getGeneralState(GeneralStates.STAYING) && this.pokemob.getGeneralState(GeneralStates.TAMED)) - if (this.checkOwner()) return false; - - /* - * Check for others to try to help you. - */ - if (this.checkForHelp(target)) return false; - - if (target == null && this.entityTarget != null) - { - target = this.entityTarget; - if (this.agroTimer == -1) this.agroTimer = AIFindTarget.DEAGROTIMER; - else - { - this.agroTimer--; - if (this.agroTimer == -1 || !this.pokemob.getCombatState(CombatStates.ANGRY)) this.clear(); - else if (this.entity.getDistance(target) < PokecubeCore.getConfig().chaseDistance) - { - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug( - "Somehow lost target? Well, found it back again! {} -> {}", this.entity, this.entityTarget); - this.setAttackTarget(this.entity, this.entityTarget); - } - } - } - - final boolean playerNear = this.entity.getBrain().hasMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER); - // If wild, randomly decided to agro a nearby player instead. - if (ret && playerNear && AITools.shouldAgroNearestPlayer.test(this.pokemob)) - { - PlayerEntity player = this.entity.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER).get(); - if (player != null && player.getDistance(this.entity) > PokecubeCore.getConfig().mobAggroRadius) - player = null; - if (player != null && AITools.validTargets.test(player)) - { - this.setAttackTarget(this.entity, player); - if (PokecubeCore.getConfig().debug) PokecubeCore.LOGGER.debug( - "Found player to be angry with, agressing."); - return false; - } - } - return ret; - } - -} \ No newline at end of file diff --git a/src/main/java/pokecube/core/ai/tasks/combat/FightTask.java b/src/main/java/pokecube/core/ai/tasks/combat/CombatTask.java similarity index 57% rename from src/main/java/pokecube/core/ai/tasks/combat/FightTask.java rename to src/main/java/pokecube/core/ai/tasks/combat/CombatTask.java index ccfa76c826..5b88978dab 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/FightTask.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/CombatTask.java @@ -12,24 +12,24 @@ import pokecube.core.interfaces.IPokemob; import thut.api.entity.ai.IAICombat; -public abstract class FightTask extends TaskBase implements IAICombat +public abstract class CombatTask extends TaskBase implements IAICombat { private static final Map, MemoryModuleStatus> MEMS = Maps.newHashMap(); static { - FightTask.MEMS.put(MemoryModules.ATTACKTARGET, MemoryModuleStatus.VALUE_PRESENT); + CombatTask.MEMS.put(MemoryModules.ATTACKTARGET, MemoryModuleStatus.VALUE_PRESENT); } - public FightTask(final IPokemob pokemob) + public CombatTask(final IPokemob pokemob) { - super(pokemob, FightTask.MEMS); + super(pokemob, CombatTask.MEMS); } - public FightTask(final IPokemob pokemob, final Map, MemoryModuleStatus> mems) + public CombatTask(final IPokemob pokemob, final Map, MemoryModuleStatus> mems) { - super(pokemob, TaskBase.merge(FightTask.MEMS, mems)); + super(pokemob, TaskBase.merge(CombatTask.MEMS, mems)); } } diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AISelectMove.java b/src/main/java/pokecube/core/ai/tasks/combat/attacks/SelectMoveTask.java similarity index 93% rename from src/main/java/pokecube/core/ai/tasks/combat/AISelectMove.java rename to src/main/java/pokecube/core/ai/tasks/combat/attacks/SelectMoveTask.java index 3388d181a5..7bd72c0c1e 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/AISelectMove.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/attacks/SelectMoveTask.java @@ -1,4 +1,4 @@ -package pokecube.core.ai.tasks.combat; +package pokecube.core.ai.tasks.combat.attacks; import java.util.Random; @@ -7,6 +7,7 @@ import net.minecraft.entity.Entity; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.tasks.combat.CombatTask; import pokecube.core.interfaces.IMoveConstants; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.Move_Base; @@ -17,12 +18,12 @@ import pokecube.core.utils.Tools; import thut.api.entity.ai.IAICombat; -public class AISelectMove extends FightTask implements IAICombat +public class SelectMoveTask extends CombatTask implements IAICombat { Entity target; private int moveIndexCounter = 0; - public AISelectMove(final IPokemob mob) + public SelectMoveTask(final IPokemob mob) { super(mob); this.setMutex(0); @@ -40,7 +41,8 @@ public void reset() public void run() { // Pokemobs hunting or guarding will always select whatever is strongest - if (this.pokemob.getCombatState(CombatStates.GUARDING) || this.pokemob.getCombatState(CombatStates.HUNTING)) + if (this.pokemob.getCombatState(CombatStates.GUARDING) || this.pokemob.getCombatState(CombatStates.HUNTING) + || this.pokemob.getCombatState(CombatStates.MATEFIGHT)) { this.selectHighestDamage(); return; diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AIAttack.java b/src/main/java/pokecube/core/ai/tasks/combat/attacks/UseAttacksTask.java similarity index 69% rename from src/main/java/pokecube/core/ai/tasks/combat/AIAttack.java rename to src/main/java/pokecube/core/ai/tasks/combat/attacks/UseAttacksTask.java index 681e8cbe08..55bff52ee4 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/AIAttack.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/attacks/UseAttacksTask.java @@ -1,4 +1,4 @@ -package pokecube.core.ai.tasks.combat; +package pokecube.core.ai.tasks.combat.attacks; import org.apache.logging.log4j.Level; @@ -13,10 +13,10 @@ import net.minecraftforge.common.util.FakePlayer; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.tasks.combat.CombatTask; import pokecube.core.interfaces.IMoveConstants; import pokecube.core.interfaces.IPokemob; 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.interfaces.pokemob.ai.GeneralStates; @@ -36,21 +36,22 @@ * decided to battle, as well as dealing with combat between rivals over a mate. * It is the one to queue the attack for the pokemob to perform. */ -public class AIAttack extends FightTask implements IAICombat +public class UseAttacksTask extends CombatTask implements IAICombat { - public static int maxWildBattleDur = 600; /** The target being attacked. */ LivingEntity entityTarget; + /** IPokemob version of entityTarget. */ - IPokemob pokemobTarget; + IPokemob pokemobTarget; /** Where the target is/was for attack. */ - Vector3 targetLoc = Vector3.getNewVector(); + Vector3 targetLoc = Vector3.getNewVector(); + Matrix3 targetBox = new Matrix3(); + Matrix3 attackerBox = new Matrix3(); + /** Move we are using */ Move_Base attack; - Matrix3 targetBox = new Matrix3(); - Matrix3 attackerBox = new Matrix3(); /** Temp vectors for checking things. */ Vector3 v = Vector3.getNewVector(); @@ -59,15 +60,12 @@ public class AIAttack extends FightTask implements IAICombat /** Speed for pathing. */ double movementSpeed; - /** Used to determine when to give up attacking. */ - protected int chaseTime; /** Used for when to execute attacks. */ protected int delayTime = -1; - boolean running = false; - int battleTime = 0; + boolean waitingToStart = false; - public AIAttack(final IPokemob mob) + public UseAttacksTask(final IPokemob mob) { super(mob); this.movementSpeed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue() * 1.8; @@ -76,49 +74,14 @@ public AIAttack(final IPokemob mob) public boolean continueExecuting() { - final IPokemob mobA = this.pokemob; - final IPokemob mobB = this.pokemobTarget; - - if (mobB != null) - { - if (mobB.getCombatState(CombatStates.FAINTED)) return false; - - final boolean weTame = mobA.getOwnerId() != null || mobA.getCombatState(CombatStates.MATEFIGHT); - final boolean theyTame = mobB.getOwnerId() != null || mobB.getCombatState(CombatStates.MATEFIGHT); - final boolean weHunt = mobA.getCombatState(CombatStates.HUNTING); - final boolean theyHunt = mobB.getCombatState(CombatStates.HUNTING); - - if (weTame == theyTame && !weTame && weHunt == theyHunt && !theyHunt) - { - 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.5 || theyHealth < 0.5) - { - mobA.setCombatState(CombatStates.MATEFIGHT, false); - mobB.setCombatState(CombatStates.MATEFIGHT, false); - AIFindTarget.deagro(this.entity); - return false; - } - // Give up if we took too long to fight. - if (this.battleTime > AIAttack.maxWildBattleDur) 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; - return this.pokemob.getCombatState(CombatStates.ANGRY); } @Override public void reset() { - this.battleTime = 0; this.clearUseMove(); - AIFindTarget.deagro(this.entity); + this.waitingToStart = false; } private void setUseMove() @@ -136,21 +99,19 @@ private void clearUseMove() @Override public void run() { - this.battleTime++; // Check if the pokemob has an active move being used, if so return if (this.pokemob.getActiveMove() != null) return; this.attack = MovesUtils.getMoveFromName(this.pokemob.getMove(this.pokemob.getMoveIndex())); if (this.attack == null) this.attack = MovesUtils.getMoveFromName(IMoveConstants.DEFAULT_MOVE); - if (!this.running) + if (!this.waitingToStart) { if (!((this.attack.getAttackCategory() & IMoveConstants.CATEGORY_SELF) != 0) && !this.pokemob .getGeneralState(GeneralStates.CONTROLLED)) this.setWalkTo(this.entityTarget.getPositionVec(), this.movementSpeed, 0); this.targetLoc.set(this.entityTarget); - this.chaseTime = 0; - this.running = true; + this.waitingToStart = true; /** * Don't want to notify if the pokemob just broke out of a * pokecube. @@ -189,28 +150,6 @@ public void run() // No executing move state with no target location. 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.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); - // Send deagress message and put mob on cooldown. - final ITextComponent message = new TranslationTextComponent("pokemob.deagress.timeout", this.pokemob - .getDisplayName().getFormattedText()); - try - { - this.entityTarget.sendMessage(message); - } - catch (final Exception e) - { - PokecubeCore.LOGGER.log(Level.WARN, "Error with message for " + this.entityTarget, e); - } - this.pokemob.setAttackCooldown(PokecubeCore.getConfig().pokemobagressticks); - return; - } - Move_Base move = null; move = MovesUtils.getMoveFromName(this.pokemob.getMove(this.pokemob.getMoveIndex())); if (move == null) move = MovesUtils.getMoveFromName(IMoveConstants.DEFAULT_MOVE); @@ -248,26 +187,11 @@ else if (PokecubeCore.getConfig().contactAttackDistance > 0) final boolean canSee = BrainUtil.canSee(this.entity.getBrain(), this.entityTarget); - // If can't see, increment the timer for giving up later. - if (!canSee) - { - this.chaseTime++; - if (!this.pokemob.getCombatState(CombatStates.EXECUTINGMOVE)) this.targetLoc.set(this.entityTarget).addTo(0, - this.entityTarget.getHeight() / 2, 0); - // Try to path to target if you can't see it, regardless of what - // move you have selected. - shouldPath = true; - } - else - { - // Otherwise set timer to 0, and if newly executing the move, set - // the target location as a "aim". This aiming is done so that when - // the move is fired, it is fired at the location, not the target, - // giving option to dodge. - this.chaseTime = 0; - if (!this.pokemob.getCombatState(CombatStates.EXECUTINGMOVE)) this.targetLoc.set(this.entityTarget).addTo(0, - this.entityTarget.getHeight() / 2, 0); - } + // If we have not set a move executing, we update target location. If we + // have a move executing, we leave the old location to give the target + // time to dodge needed. + if (!this.pokemob.getCombatState(CombatStates.EXECUTINGMOVE)) this.targetLoc.set(this.entityTarget).addTo(0, + this.entityTarget.getHeight() / 2, 0); final boolean isTargetDodging = this.pokemobTarget != null && this.pokemobTarget.getCombatState( CombatStates.DODGING); @@ -344,12 +268,6 @@ public boolean shouldRun() if (target != this.entityTarget) this.pokemobTarget = CapabilityPokemob.getPokemobFor(target); this.entityTarget = target; - if (!this.continueExecuting()) - { - AIFindTarget.deagro(this.entity); - return false; - } - return true; } diff --git a/src/main/java/pokecube/core/ai/tasks/combat/management/CallForHelpTask.java b/src/main/java/pokecube/core/ai/tasks/combat/management/CallForHelpTask.java new file mode 100644 index 0000000000..7b30fecb1a --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/combat/management/CallForHelpTask.java @@ -0,0 +1,106 @@ +package pokecube.core.ai.tasks.combat.management; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.MobEntity; +import net.minecraft.entity.ai.brain.memory.MemoryModuleType; +import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.tasks.combat.CombatTask; +import pokecube.core.handlers.TeamManager; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.capabilities.CapabilityPokemob; + +public class CallForHelpTask extends CombatTask +{ + boolean checked = false; + + final float chance; + + LivingEntity target = null; + + public CallForHelpTask(final IPokemob pokemob, final float chance) + { + super(pokemob); + this.chance = chance; + } + + @Override + public void reset() + { + this.checked = false; + this.target = null; + } + + /** + * Check if there are any mobs nearby that will help us.
+ *
+ * This is called from {@link FindTargetsTask#shouldRun()} + * + * @return someone needed help. + */ + protected boolean checkForHelp(final LivingEntity from) + { + // No need to get help against null + if (from == null) return false; + + // Not social. doesn't do this. + if (!this.pokemob.getPokedexEntry().isSocial) return false; + + final List ret = new ArrayList<>(); + final List pokemobs = this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS).get(); + + // We check for whether it is the same species and, has the same owner + // (including null) or is on the team. + final Predicate relationCheck = input -> + { + final IPokemob other = CapabilityPokemob.getPokemobFor(input); + // No pokemob, no helps. + if (other == null) return false; + // Not related, no helps. + if (!other.getPokedexEntry().areRelated(this.pokemob.getPokedexEntry())) return false; + // both wild, helps. + if (other.getOwnerId() == null && this.pokemob.getOwnerId() == null) return true; + // Same team, helps. + if (TeamManager.sameTeam(input, this.entity)) return true; + return false; + }; + + pokemobs.forEach(o -> + { + // Only allow valid guard targets. + if (relationCheck.test(o)) ret.add(o); + }); + + for (final LivingEntity mob : ret) + { + if (!(mob instanceof MobEntity)) continue; + // Only agress mobs that can see you are really under attack. + if (!mob.canEntityBeSeen(this.entity)) continue; + // Only agress if not currently in combat. + if (BrainUtils.hasAttackTarget(mob)) continue; + // Make all valid ones agress the target. + BrainUtils.initiateCombat((MobEntity) mob, from); + } + return false; + } + + @Override + public void run() + { + if (this.checked) return; + this.checked = true; + if (Math.random() < this.chance) return; + this.checkForHelp(this.target); + } + + @Override + public boolean shouldRun() + { + this.target = BrainUtils.getAttackTarget(this.entity); + return this.target != null; + } + +} diff --git a/src/main/java/pokecube/core/ai/tasks/combat/management/FindTargetsTask.java b/src/main/java/pokecube/core/ai/tasks/combat/management/FindTargetsTask.java new file mode 100644 index 0000000000..702eeec58f --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/combat/management/FindTargetsTask.java @@ -0,0 +1,248 @@ +package pokecube.core.ai.tasks.combat.management; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + +import com.google.common.collect.ImmutableMap; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.MobEntity; +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.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.tasks.TaskBase; +import pokecube.core.handlers.TeamManager; +import pokecube.core.interfaces.IMoveConstants.AIRoutine; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.IPokemob.ITargetFinder; +import pokecube.core.interfaces.capabilities.CapabilityPokemob; +import pokecube.core.interfaces.pokemob.ai.CombatStates; +import pokecube.core.interfaces.pokemob.ai.GeneralStates; +import pokecube.core.utils.AITools; +import pokecube.core.utils.PokemobTracker; +import thut.api.IOwnable; +import thut.api.OwnableCaps; +import thut.api.entity.ai.IAICombat; +import thut.api.maths.Vector3; + +/** This IAIRunnable is to find targets for the pokemob to try to kill. */ +public class FindTargetsTask extends TaskBase implements IAICombat, ITargetFinder +{ + + public static boolean handleDamagedTargets = true; + static + { + MinecraftForge.EVENT_BUS.register(FindTargetsTask.class); + } + + @SubscribeEvent + public static void livingSetTarget(final LivingSetAttackTargetEvent event) + { + // Don't manage this. + if (event.getTarget() == null) return; + List mobs = PokemobTracker.getMobs(event.getTarget(), e -> CapabilityPokemob.getPokemobFor(e) != null + && e.getDistanceSq(event.getTarget()) < 64); + final boolean targetHasMobs = !mobs.isEmpty(); + if (targetHasMobs) + { + mobs.sort((o1, o2) -> (int) (o1.getDistanceSq(event.getEntityLiving()) - o2.getDistanceSq(event + .getEntityLiving()))); + final Entity mob = mobs.get(0); + mobs = PokemobTracker.getMobs(mob, e -> true); + // No loop diverting + if (!mobs.isEmpty()) return; + // Divert the target over. + BrainUtils.setAttackTarget(event.getEntityLiving(), (LivingEntity) mob); + } + } + + public static int DEAGROTIMER = 50; + + Vector3 v = Vector3.getNewVector(); + Vector3 v1 = Vector3.getNewVector(); + + /** + * Checks the validTargts as well as team settings, will not allow + * targetting things on the same team. + */ + final Predicate validGuardTarget = input -> + { + if (input == FindTargetsTask.this.entity) return false; + if (TeamManager.sameTeam(FindTargetsTask.this.entity, input)) return false; + if (!AITools.validTargets.test(input)) return false; + return input instanceof LivingEntity; + }; + + public FindTargetsTask(final IPokemob mob) + { + super(mob, ImmutableMap.of(MemoryModuleType.VISIBLE_MOBS, MemoryModuleStatus.VALUE_PRESENT)); + } + + @Override + public void clear() + { + } + + /** + * Check for and agress any guard targets.
+ *
+ * This is called from {@link FindTargetsTask#run()} + * + * @return a guard target was found + */ + protected boolean checkGuard() + { + // Disabled via the boolean config. + if (!PokecubeCore.getConfig().guardModeEnabled) return false; + + final int rate = PokecubeCore.getConfig().guardTickRate; + // Disable via rate out of bounds, or not correct time in the rate. + if (rate <= 0 || this.entity.ticksExisted % rate != 0) return false; + + // Select either owner or home position as the centre of the check, + // this results in it guarding either its home or its owner. Home is + // used if it is on stay, or it has no owner. + final Vector3 centre = Vector3.getNewVector(); + if (this.pokemob.getGeneralState(GeneralStates.STAYING) || this.pokemob.getOwner() == null) centre.set( + this.pokemob.getHome()); + else centre.set(this.pokemob.getOwner()); + + final List ret = new ArrayList<>(); + final List pokemobs = this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS).get(); + // Only allow valid guard targets. + for (final LivingEntity o : pokemobs) + if (this.validGuardTarget.test(o)) ret.add(o); + ret.removeIf(e -> e.getDistance(this.entity) > PokecubeCore.getConfig().guardSearchDistance); + if (ret.isEmpty()) return false; + + // This is already sorted by distance! + final LivingEntity newtarget = ret.get(0); + // Agro the target. + if (newtarget != null) + { + this.setAttackTarget(this.entity, newtarget); + return true; + } + return false; + } + + protected void setAttackTarget(final MobEntity attacker, final LivingEntity target) + { + if (target == null || !AITools.validTargets.test(target)) + { + BrainUtils.deagro(attacker); + this.clear(); + } + else BrainUtils.initiateCombat(attacker, target); + } + + /** + * Check if owner is under attack, if so, agress the attacker.
+ *
+ * This is called from {@link FindTargetsTask#run()} + * + * @return if target was found. + */ + protected boolean checkOwner() + { + final Entity owner = this.pokemob.getOwner(); + + // Only apply if has owner. + if (owner == null) return false; + + if (this.pokemob.getGeneralState(GeneralStates.STAYING)) return false; + + final int rate = PokecubeCore.getConfig().guardTickRate; + // Disable via rate out of bounds, or not correct time in the rate. + if (rate <= 0 || this.entity.ticksExisted % rate != 0) return false; + + final List list = new ArrayList<>(); + final List pokemobs = this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS).get(); + list.addAll(pokemobs); + list.removeIf(e -> e.getDistance(this.entity) > PokecubeCore.getConfig().guardSearchDistance + && AITools.validTargets.test(e)); + if (list.isEmpty()) return false; + + final Entity old = BrainUtils.getAttackTarget(this.entity); + final IOwnable oldOwnable = OwnableCaps.getOwnable(old); + final Entity oldOwner = oldOwnable != null ? oldOwnable.getOwner(this.world) : null; + + if (!list.isEmpty()) for (final LivingEntity entity : list) + { + if (oldOwner != null && entity == oldOwner) return false; + final LivingEntity targ = BrainUtils.getAttackTarget(entity); + if (entity instanceof MobEntity && targ != null && targ.equals(owner)) + { + this.setAttackTarget(this.entity, entity); + return true; + } + } + return false; + } + + @Override + public void reset() + { + } + + @Override + public void run() + { + final Optional hurtBy = this.entity.getBrain().getMemory(MemoryModuleType.HURT_BY_ENTITY); + if (hurtBy != null && hurtBy.isPresent()) + { + final LivingEntity target = hurtBy.get(); + if (BrainUtil.canSee(this.entity.getBrain(), target)) + { + this.setAttackTarget(this.entity, target); + return; + } + } + + // If guarding, look for mobs not on the same team as you, and if you + // find them, try to agress them. + if (this.pokemob.getCombatState(CombatStates.GUARDING)) if (this.checkGuard()) return; + + // Ensure the correct owner is tracked. + this.pokemob.getOwner(this.world); + + // Check if the pokemob is set to follow, and if so, look for mobs + // nearby trying to attack the owner of the pokemob, if any such are + // found, try to aggress them immediately. + if (!this.pokemob.getGeneralState(GeneralStates.STAYING)) if (this.checkOwner()) return; + + final boolean playerNear = this.entity.getBrain().hasMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER); + // If wild, randomly decided to agro a nearby player instead. + if (playerNear && AITools.shouldAgroNearestPlayer.test(this.pokemob)) + { + PlayerEntity player = this.entity.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER).get(); + if (player != null && player.getDistance(this.entity) > PokecubeCore.getConfig().mobAggroRadius) + player = null; + if (player != null && AITools.validTargets.test(player)) + { + this.setAttackTarget(this.entity, player); + PokecubeCore.LOGGER.debug("Found player to be angry with, agressing."); + return; + } + } + } + + @Override + public boolean shouldRun() + { + if (!this.pokemob.isRoutineEnabled(AIRoutine.AGRESSIVE)) return false; + if (!this.entity.getBrain().hasMemory(MemoryModuleType.VISIBLE_MOBS)) return false; + if (BrainUtils.hasAttackTarget(this.entity)) return false; + return true; + } + +} \ No newline at end of file diff --git a/src/main/java/pokecube/core/ai/tasks/combat/management/ForgetTargetTask.java b/src/main/java/pokecube/core/ai/tasks/combat/management/ForgetTargetTask.java new file mode 100644 index 0000000000..f04ace7e2b --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/combat/management/ForgetTargetTask.java @@ -0,0 +1,296 @@ +package pokecube.core.ai.tasks.combat.management; + +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.apache.logging.log4j.Level; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import net.minecraft.entity.AgeableEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +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.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import pokecube.core.PokecubeCore; +import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.brain.MemoryModules; +import pokecube.core.ai.tasks.combat.CombatTask; +import pokecube.core.handlers.TeamManager; +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; + +public class ForgetTargetTask extends CombatTask +{ + private static class ForgetEntry + { + long forgotTime; + + LivingEntity mob; + + public ForgetEntry(final long time, final LivingEntity mob) + { + this.forgotTime = time; + this.mob = mob; + } + + boolean isValid(final long gameTime) + { + if (gameTime - this.forgotTime > 100) return false; + return true; + } + + @Override + public int hashCode() + { + return this.mob.getUniqueID().hashCode(); + } + + @Override + public boolean equals(final Object obj) + { + return this.mob.getUniqueID().equals(obj); + } + } + + public static int maxWildBattleDur = 600; + /** The target being attacked. */ + LivingEntity entityTarget; + + /** IPokemob version of entityTarget. */ + IPokemob pokemobTarget; + + int battleTime = 0; + + int ticksSinceSeen = 0; + + Map forgotten = Maps.newHashMap(); + + public ForgetTargetTask(final IPokemob pokemob) + { + super(pokemob); + } + + @Override + public void reset() + { + this.entityTarget = null; + this.pokemobTarget = null; + this.battleTime = 0; + this.ticksSinceSeen = 0; + BrainUtils.deagro(this.entity); + } + + @Override + public void run() + { + this.battleTime++; + + // Check if we should be cancelling due to wild mobs + + final IPokemob mobA = this.pokemob; + final IPokemob mobB = this.pokemobTarget; + + LivingEntity mate = BrainUtils.getMateTarget((AgeableEntity) this.entity); + + if (mate != null && !mate.isAlive()) + { + BrainUtils.setMateTarget((AgeableEntity) this.entity, null); + mate = null; + } + + if (!this.forgotten.isEmpty()) + { + final Set ids = Sets.newHashSet(this.forgotten.keySet()); + for (final UUID id : ids) + if (!this.forgotten.get(id).isValid(this.world.getGameTime())) this.forgotten.remove(id); + } + + boolean deAgro = mate == this.entityTarget; + + final ForgetEntry entry = new ForgetEntry(this.world.getGameTime(), this.entityTarget); + if (this.forgotten.containsKey(entry.mob.getUniqueID())) deAgro = true; + + agroCheck: + if (mobB != null && !deAgro) + { + if (mobB.getCombatState(CombatStates.FAINTED)) + { + deAgro = true; + break agroCheck; + } + + final boolean weTame = mobA.getOwnerId() != null && !mobA.getCombatState(CombatStates.MATEFIGHT); + final boolean theyTame = mobB.getOwnerId() != null && !mobB.getCombatState(CombatStates.MATEFIGHT); + final boolean weHunt = mobA.getCombatState(CombatStates.HUNTING); + final boolean theyHunt = mobB.getCombatState(CombatStates.HUNTING); + + final boolean bothWild = !weTame && !theyTame; + final boolean oneHunting = weHunt || theyHunt; + + // Give up if we took too long to fight. + if (bothWild && this.battleTime > ForgetTargetTask.maxWildBattleDur) + { + deAgro = true; + break agroCheck; + } + + if (bothWild && !oneHunting) + { + 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.5 || theyHealth < 0.5) + { + mobA.setCombatState(CombatStates.MATEFIGHT, false); + mobB.setCombatState(CombatStates.MATEFIGHT, false); + + if (weHealth < 0.5) if (mobA.getEntity().getBrain().hasMemory(MemoryModules.HUNTED_BY, + MemoryModuleStatus.REGISTERED)) mobA.getEntity().getBrain().setMemory( + MemoryModules.HUNTED_BY, mobB.getEntity()); + if (theyHealth < 0.5) if (mobB.getEntity().getBrain().hasMemory(MemoryModules.HUNTED_BY, + MemoryModuleStatus.REGISTERED)) mobB.getEntity().getBrain().setMemory( + MemoryModules.HUNTED_BY, mobA.getEntity()); + + PokecubeCore.LOGGER.debug("No want to fight, too weak!"); + deAgro = true; + } + } + } + if (mobA.getCombatState(CombatStates.FAINTED)) deAgro = true; + + agroCheck: + if (!deAgro) + { + if (!this.entityTarget.isAlive() || this.entityTarget.getHealth() <= 0) + { + PokecubeCore.LOGGER.debug("They are Dead!"); + deAgro = true; + break agroCheck; + } + if (!this.entity.isAlive() || this.entity.getHealth() <= 0) + { + PokecubeCore.LOGGER.debug("We are Dead!"); + deAgro = true; + break agroCheck; + } + + // If our target is us, we should forget it. + if (this.entityTarget == this.entity) + { + PokecubeCore.LOGGER.debug("Cannot target self."); + deAgro = true; + break agroCheck; + } + + // If we are not angry, we should forget target. + if (!this.pokemob.getCombatState(CombatStates.ANGRY)) + { + PokecubeCore.LOGGER.debug("Not Angry. losing target now."); + deAgro = true; + break agroCheck; + } + + // If our target is owner, we should forget it. + if (this.entityTarget.getUniqueID().equals(this.pokemob.getOwnerId())) + { + PokecubeCore.LOGGER.debug("Cannot target owner."); + deAgro = true; + break agroCheck; + } + + final boolean tame = this.pokemob.getGeneralState(GeneralStates.TAMED); + // If your owner is too far away, shouldn't have a target, should be + // going back to the owner. + if (tame) + { + final Entity owner = this.pokemob.getOwner(); + final boolean stayOrGuard = this.pokemob.getCombatState(CombatStates.GUARDING) || this.pokemob + .getGeneralState(GeneralStates.STAYING); + if (owner != null && !stayOrGuard && owner.getDistance(this.entity) > PokecubeCore + .getConfig().chaseDistance) + { + PokecubeCore.LOGGER.debug("Cannot target mob that far while guarding."); + deAgro = true; + break agroCheck; + } + + // If the target is a pokemob, on same team, we shouldn't target + // it either, unless it is fighting over a mate + if (TeamManager.sameTeam(this.entityTarget, this.entity) && !this.pokemob.getCombatState( + CombatStates.MATEFIGHT)) + { + PokecubeCore.LOGGER.debug("Cannot target team mates."); + deAgro = true; + break agroCheck; + } + + } + + if (BrainUtil.canSee(this.entity.getBrain(), this.entityTarget)) this.ticksSinceSeen = 0; + + // If it has been too long since last seen the target, give up. + if (this.ticksSinceSeen++ > 100) + { + // Send deagress message and put mob on cooldown. + final ITextComponent message = new TranslationTextComponent("pokemob.deagress.timeout", this.pokemob + .getDisplayName().getFormattedText()); + try + { + this.entityTarget.sendMessage(message); + } + catch (final Exception e) + { + PokecubeCore.LOGGER.log(Level.WARN, "Error with message for " + this.entityTarget, e); + } + deAgro = true; + break agroCheck; + } + + // Target is too far away, lets forget it. + if (this.entity.getDistance(this.entityTarget) > PokecubeCore.getConfig().chaseDistance) + { + // Send deagress message and put mob on cooldown. + final ITextComponent message = new TranslationTextComponent("pokemob.deagress.timeout", this.pokemob + .getDisplayName().getFormattedText()); + try + { + this.entityTarget.sendMessage(message); + } + catch (final Exception e) + { + PokecubeCore.LOGGER.log(Level.WARN, "Error with message for " + this.entityTarget, e); + } + deAgro = true; + break agroCheck; + } + } + // All we do is deagro if needed. + if (deAgro) + { + this.pokemob.setAttackCooldown(PokecubeCore.getConfig().pokemobagressticks); + BrainUtils.deagro(this.entity); + } + } + + @Override + public boolean shouldRun() + { + this.entityTarget = BrainUtils.getAttackTarget(this.entity); + this.pokemobTarget = CapabilityPokemob.getPokemobFor(this.entityTarget); + + if (this.entityTarget == null && this.entity.getBrain().hasMemory(MemoryModuleType.HURT_BY_ENTITY)) + this.entityTarget = this.entity.getBrain().getMemory(MemoryModuleType.HURT_BY_ENTITY).get(); + + // Only run if we have a combat target + return this.entityTarget != null; + } + +} diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AICombatMovement.java b/src/main/java/pokecube/core/ai/tasks/combat/movement/CicleTask.java similarity index 94% rename from src/main/java/pokecube/core/ai/tasks/combat/AICombatMovement.java rename to src/main/java/pokecube/core/ai/tasks/combat/movement/CicleTask.java index c03db5447c..a23d7bac7d 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/AICombatMovement.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/movement/CicleTask.java @@ -1,9 +1,10 @@ -package pokecube.core.ai.tasks.combat; +package pokecube.core.ai.tasks.combat.movement; import net.minecraft.entity.Entity; import net.minecraft.entity.SharedMonsterAttributes; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.tasks.combat.CombatTask; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.pokemob.ai.CombatStates; import thut.api.entity.ai.IAICombat; @@ -14,13 +15,13 @@ * on cooldown between attacks. It also manages the leaping at targets, and the * dodging of attacks. */ -public class AICombatMovement extends FightTask implements IAICombat +public class CicleTask extends CombatTask implements IAICombat { Entity target; Vector3 centre; double movementSpeed; - public AICombatMovement(final IPokemob mob) + public CicleTask(final IPokemob mob) { super(mob); this.movementSpeed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue() * 1.8; diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AIDodge.java b/src/main/java/pokecube/core/ai/tasks/combat/movement/DodgeTask.java similarity index 96% rename from src/main/java/pokecube/core/ai/tasks/combat/AIDodge.java rename to src/main/java/pokecube/core/ai/tasks/combat/movement/DodgeTask.java index 4a3875d0b3..cc923fc342 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/AIDodge.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/movement/DodgeTask.java @@ -1,4 +1,4 @@ -package pokecube.core.ai.tasks.combat; +package pokecube.core.ai.tasks.combat.movement; import java.util.Random; @@ -10,6 +10,7 @@ import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; import pokecube.core.ai.tasks.TaskBase; +import pokecube.core.ai.tasks.combat.CombatTask; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.IPokemob.Stats; import pokecube.core.interfaces.PokecubeMod; @@ -18,7 +19,7 @@ import thut.api.entity.ai.IAICombat; import thut.api.maths.Vector3; -public class AIDodge extends FightTask implements IAICombat +public class DodgeTask extends CombatTask implements IAICombat { // Location of the targetted attack @@ -29,7 +30,7 @@ public class AIDodge extends FightTask implements IAICombat int dodgeCooldown = -1; - public AIDodge(final IPokemob mob) + public DodgeTask(final IPokemob mob) { super(mob); this.movementSpeed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue() * 1.8; diff --git a/src/main/java/pokecube/core/ai/tasks/combat/AILeap.java b/src/main/java/pokecube/core/ai/tasks/combat/movement/LeapTask.java similarity index 93% rename from src/main/java/pokecube/core/ai/tasks/combat/AILeap.java rename to src/main/java/pokecube/core/ai/tasks/combat/movement/LeapTask.java index b8a9a1b62a..3a5ca1e3de 100644 --- a/src/main/java/pokecube/core/ai/tasks/combat/AILeap.java +++ b/src/main/java/pokecube/core/ai/tasks/combat/movement/LeapTask.java @@ -1,4 +1,4 @@ -package pokecube.core.ai.tasks.combat; +package pokecube.core.ai.tasks.combat.movement; import java.util.Map; import java.util.Random; @@ -27,13 +27,13 @@ * 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 +public class LeapTask extends TaskBase implements IAICombat { private static final Map, MemoryModuleStatus> MEMS = Maps.newHashMap(); static { - AILeap.MEMS.put(MemoryModules.MOVE_TARGET, MemoryModuleStatus.VALUE_PRESENT); + LeapTask.MEMS.put(MemoryModules.MOVE_TARGET, MemoryModuleStatus.VALUE_PRESENT); } int leapTick = -1; @@ -46,9 +46,9 @@ public class AILeap extends TaskBase implements IAICombat Vector3 leapTarget = Vector3.getNewVector(); Vector3 leapOrigin = Vector3.getNewVector(); - public AILeap(final IPokemob mob) + public LeapTask(final IPokemob mob) { - super(mob, AILeap.MEMS); + super(mob, LeapTask.MEMS); this.movementSpeed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue() * 1.8; } diff --git a/src/main/java/pokecube/core/ai/tasks/idle/IdleTask.java b/src/main/java/pokecube/core/ai/tasks/idle/BaseIdleTask.java similarity index 56% rename from src/main/java/pokecube/core/ai/tasks/idle/IdleTask.java rename to src/main/java/pokecube/core/ai/tasks/idle/BaseIdleTask.java index 7a2bf508bc..7c4a44cad6 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/IdleTask.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/BaseIdleTask.java @@ -11,23 +11,23 @@ import pokecube.core.ai.tasks.TaskBase; import pokecube.core.interfaces.IPokemob; -public abstract class IdleTask extends TaskBase +public abstract class BaseIdleTask extends TaskBase { private static final Map, MemoryModuleStatus> MEMS = Maps.newHashMap(); static { - IdleTask.MEMS.put(MemoryModules.ATTACKTARGET, MemoryModuleStatus.VALUE_ABSENT); + BaseIdleTask.MEMS.put(MemoryModules.ATTACKTARGET, MemoryModuleStatus.VALUE_ABSENT); } - public IdleTask(final IPokemob pokemob) + public BaseIdleTask(final IPokemob pokemob) { - super(pokemob, IdleTask.MEMS); + super(pokemob, BaseIdleTask.MEMS); } - public IdleTask(final IPokemob pokemob, final Map, MemoryModuleStatus> mems) + public BaseIdleTask(final IPokemob pokemob, final Map, MemoryModuleStatus> mems) { - super(pokemob, TaskBase.merge(IdleTask.MEMS, mems)); + super(pokemob, TaskBase.merge(BaseIdleTask.MEMS, mems)); } } diff --git a/src/main/java/pokecube/core/ai/tasks/idle/ForgetHuntedByTask.java b/src/main/java/pokecube/core/ai/tasks/idle/ForgetHuntedByTask.java new file mode 100644 index 0000000000..b12b6d12ab --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/idle/ForgetHuntedByTask.java @@ -0,0 +1,39 @@ +package pokecube.core.ai.tasks.idle; + +import net.minecraft.entity.LivingEntity; +import pokecube.core.ai.brain.MemoryModules; +import pokecube.core.ai.tasks.TaskBase; +import pokecube.core.interfaces.IPokemob; + +public class ForgetHuntedByTask extends TaskBase +{ + int fleeingTicks = 0; + + final int duration; + + public ForgetHuntedByTask(final IPokemob pokemob, final int duration) + { + super(pokemob); + this.duration = duration; + } + + @Override + public void reset() + { + this.fleeingTicks = 0; + this.entity.getBrain().removeMemory(MemoryModules.HUNTED_BY); + } + + @Override + public void run() + { + this.fleeingTicks++; + } + + @Override + public boolean shouldRun() + { + return this.entity.getBrain().hasMemory(MemoryModules.HUNTED_BY) && this.fleeingTicks < this.duration; + } + +} diff --git a/src/main/java/pokecube/core/ai/tasks/idle/AIGuardEgg.java b/src/main/java/pokecube/core/ai/tasks/idle/GuardEggTask.java similarity index 89% rename from src/main/java/pokecube/core/ai/tasks/idle/AIGuardEgg.java rename to src/main/java/pokecube/core/ai/tasks/idle/GuardEggTask.java index f12772e1f4..1fe3bfbc19 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/AIGuardEgg.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/GuardEggTask.java @@ -8,7 +8,7 @@ import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.brain.memory.MemoryModuleType; import pokecube.core.PokecubeCore; -import pokecube.core.ai.tasks.combat.AIFindTarget; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.interfaces.IPokemob; import pokecube.core.items.pokemobeggs.EntityPokemobEgg; import thut.api.terrain.TerrainManager; @@ -19,7 +19,7 @@ * the mother's breeding cooldown from dropping while an egg is being * guarded. */ -public class AIGuardEgg extends IdleTask +public class GuardEggTask extends BaseIdleTask { public static int PATHCOOLDOWN = 50; public static int SEARCHCOOLDOWN = 50; @@ -29,7 +29,7 @@ public class AIGuardEgg extends IdleTask int eggSearchCooldown = 0; int eggPathCooldown = 0; - public AIGuardEgg(final IPokemob mob) + public GuardEggTask(final IPokemob mob) { super(mob); } @@ -49,7 +49,7 @@ public void run() if (this.entity.getDistanceSq(this.egg) < 4) return; // On cooldown if (this.eggPathCooldown-- > 0) return; - this.eggPathCooldown = AIGuardEgg.PATHCOOLDOWN; + this.eggPathCooldown = GuardEggTask.PATHCOOLDOWN; // Path to the egg. final double speed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); this.setWalkTo(this.egg.getPositionVec(), speed, 0); @@ -73,14 +73,14 @@ public boolean shouldRun() if (this.eggSearchCooldown-- > 0) return false; // Only the female (or neutral) will guard the eggs. if (this.pokemob.getSexe() == IPokemob.MALE) return false; - this.eggSearchCooldown = AIGuardEgg.SEARCHCOOLDOWN; + this.eggSearchCooldown = GuardEggTask.SEARCHCOOLDOWN; if (!TerrainManager.isAreaLoaded(this.world, this.entity.getPosition(), PokecubeCore .getConfig().guardSearchDistance + 2)) return false; final List list = new ArrayList<>(); final List pokemobs = this.entity.getBrain().getMemory(MemoryModuleType.VISIBLE_MOBS).get(); list.addAll(pokemobs); - final Predicate isEgg = input -> input instanceof EntityPokemobEgg && AIGuardEgg.this.entity + final Predicate isEgg = input -> input instanceof EntityPokemobEgg && GuardEggTask.this.entity .getUniqueID().equals(((EntityPokemobEgg) input).getMotherId()) && input.isAlive(); list.removeIf(e -> !isEgg.test(e)); list.removeIf(e -> e.getDistance(this.entity) > PokecubeCore.getConfig().guardSearchDistance); @@ -89,7 +89,7 @@ public boolean shouldRun() this.egg = (EntityPokemobEgg) list.get(0); this.egg.mother = this.pokemob; - AIFindTarget.deagro(this.pokemob.getEntity()); + BrainUtils.deagro(this.pokemob.getEntity()); // Only run if we have a live egg to watch. if (this.egg != null) return this.egg.isAlive() ? true : false; diff --git a/src/main/java/pokecube/core/ai/tasks/idle/HerdTask.java b/src/main/java/pokecube/core/ai/tasks/idle/HerdTask.java new file mode 100644 index 0000000000..46b6229c91 --- /dev/null +++ b/src/main/java/pokecube/core/ai/tasks/idle/HerdTask.java @@ -0,0 +1,44 @@ +package pokecube.core.ai.tasks.idle; + +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 pokecube.core.ai.brain.MemoryModules; +import pokecube.core.interfaces.IPokemob; + +public class HerdTask extends BaseIdleTask +{ + private static final Map, MemoryModuleStatus> MEMS = Maps.newHashMap(); + + static + { + HerdTask.MEMS.put(MemoryModules.HERD_MEMBERS, MemoryModuleStatus.VALUE_PRESENT); + } + + public HerdTask(final IPokemob pokemob) + { + super(pokemob, HerdTask.MEMS); + } + + @Override + public void reset() + { + + } + + @Override + public void run() + { + + } + + @Override + public boolean shouldRun() + { + return false; + } + +} diff --git a/src/main/java/pokecube/core/ai/tasks/idle/AIHungry.java b/src/main/java/pokecube/core/ai/tasks/idle/HungerTask.java similarity index 88% rename from src/main/java/pokecube/core/ai/tasks/idle/AIHungry.java rename to src/main/java/pokecube/core/ai/tasks/idle/HungerTask.java index 0651e56fc0..571c6329e5 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/AIHungry.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/HungerTask.java @@ -45,7 +45,7 @@ * what adds berries to their inventories based on which biome they are * currently in. */ -public class AIHungry extends IdleTask +public class HungerTask extends BaseIdleTask { public static final ResourceLocation FOODTAG = new ResourceLocation(PokecubeCore.MODID, "pokemob_food"); @@ -92,11 +92,11 @@ public static boolean hitThreshold(final float hungerValue, final float threshol 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()); + HungerTask.EATTASKS.add(new EatWater()); + HungerTask.EATTASKS.add(new EatRedstone()); + HungerTask.EATTASKS.add(new EatRock()); + HungerTask.EATTASKS.add(new EatPlant()); + HungerTask.EATTASKS.add(new EatFromChest()); } public static int TICKRATE = 20; @@ -108,11 +108,6 @@ public static boolean hitThreshold(final float hungerValue, final float threshol public static float DAMAGE = 0.3f; public static float DEATH = 0.0f; - // final World world; - final ItemEntity berry; - - final double distance; - int lastMessageTick1 = -1; int lastMessageTick2 = -1; @@ -127,11 +122,9 @@ public static boolean hitThreshold(final float hungerValue, final float threshol Vector3 v1 = Vector3.getNewVector(); Random rand; - public AIHungry(final IPokemob pokemob, final ItemEntity berry_, final double distance) + public HungerTask(final IPokemob pokemob) { super(pokemob); - this.berry = berry_; - this.distance = distance; this.moveSpeed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue() * 1.75; } @@ -175,9 +168,10 @@ protected boolean checkBait() */ protected boolean checkHunt() { - if (!this.hitThreshold(AIHungry.HUNTTHRESHOLD)) return false; + if (!this.hitThreshold(HungerTask.HUNTTHRESHOLD)) return false; if (this.pokemob.isPhototroph()) if (this.checkPhotoeat()) return true; - for (final IBlockEatTask task : AIHungry.EATTASKS) + if (this.entity.ticksExisted % PokecubeCore.getConfig().huntUpdateRate != 0) return false; + for (final IBlockEatTask task : HungerTask.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)) @@ -203,7 +197,7 @@ protected boolean checkHunt() private boolean hitThreshold(final float threshold) { - return AIHungry.hitThreshold(this.hungerValue, threshold); + return HungerTask.hitThreshold(this.hungerValue, threshold); } /** @@ -215,14 +209,14 @@ private boolean hitThreshold(final float threshold) protected boolean checkInventory() { // Too hungry to check inventory. - if (this.hitThreshold(AIHungry.DEATH)) return false; + if (this.hitThreshold(HungerTask.DEATH)) return false; for (int i = 2; i < 7; i++) { final ItemStack stack = this.pokemob.getInventory().getStackInSlot(i); - if (ItemList.is(AIHungry.FOODTAG, stack)) + if (ItemList.is(HungerTask.FOODTAG, stack)) { - this.pokemob.eat(this.berry); + this.pokemob.eat(stack); stack.shrink(1); if (stack.isEmpty()) this.pokemob.getInventory().setInventorySlotContents(i, ItemStack.EMPTY); return true; @@ -267,7 +261,7 @@ protected boolean checkSleep() final ChunkCoordinate c = new ChunkCoordinate(this.v, this.entity.dimension.getId()); final boolean ownedSleepCheck = this.pokemob.getGeneralState(GeneralStates.TAMED) && !this.pokemob .getGeneralState(GeneralStates.STAYING); - if (this.sleepy && this.hitThreshold(AIHungry.EATTHRESHOLD) && !ownedSleepCheck) + if (this.sleepy && this.hitThreshold(HungerTask.EATTHRESHOLD) && !ownedSleepCheck) { if (!this.isGoodSleepingSpot(c)) this.setWalkTo(this.pokemob.getHome(), this.moveSpeed, 0); else if (this.entity.getNavigator().noPath()) @@ -313,11 +307,11 @@ public void run() if (Math.random() > 0.99) this.checkBait(); // Do not run this if not really hungry - if (!this.hitThreshold(AIHungry.EATTHRESHOLD)) return; + if (!this.hitThreshold(HungerTask.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(); + if (this.hitThreshold(HungerTask.HUNTTHRESHOLD)) this.checkHunt(); final boolean hunting = this.pokemob.getCombatState(CombatStates.HUNTING); if (this.pokemob.getLogicState(LogicStates.SLEEPING) && !hunting) if (hunting) this.pokemob.setCombatState( @@ -327,13 +321,13 @@ public void run() @Override public boolean shouldRun() { - final int hungerTicks = AIHungry.TICKRATE; + final int hungerTicks = HungerTask.TICKRATE; // This can be set in configs to disable. if (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); + if (!this.hitThreshold(HungerTask.EATTHRESHOLD) && this.pokemob.getCombatState(CombatStates.HUNTING)) + this.pokemob.setCombatState(CombatStates.HUNTING, false); // Do not run if the mob is in battle. if (this.pokemob.getCombatState(CombatStates.ANGRY)) return false; @@ -371,7 +365,7 @@ public boolean shouldRun() private void calculateHunger() { - this.hungerValue = AIHungry.calculateHunger(this.pokemob); + this.hungerValue = HungerTask.calculateHunger(this.pokemob); } @Override @@ -379,7 +373,7 @@ public void tick() { this.v.set(this.entity); - final int hungerTicks = AIHungry.TICKRATE; + final int hungerTicks = HungerTask.TICKRATE; // Check if we should go to sleep instead. this.checkSleep(); @@ -388,7 +382,7 @@ public void tick() final int cur = this.entity.ticksExisted / hungerTicks; final int tick = rand.nextInt(10); - if (!this.hitThreshold(AIHungry.EATTHRESHOLD)) return; + if (!this.hitThreshold(HungerTask.EATTHRESHOLD)) return; /* * Check the various hunger types if it is hunting. * And if so, refresh the hunger time counter. @@ -400,7 +394,7 @@ public void tick() // 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()) + if (this.hitThreshold(HungerTask.EATTHRESHOLD) && !this.checkInventory()) { // Pokemobs set to stay can collect berries, or wild ones, boolean tameCheck = this.pokemob.getGeneralState(GeneralStates.STAYING) || this.pokemob @@ -412,18 +406,16 @@ public void tick() if (diff < PokecubeCore.getConfig().pokemobLifeSpan) tameCheck = false; } // If they are allowed to, find the berries. - if (tameCheck) - { - // Only run this if we are getting close to hurt damage, mostly - // to allow trying other food sources first. - if (this.hitThreshold(AIHungry.BERRYGEN)) new GenBerries(this.pokemob).run(this.world); - } + // Only run this if we are getting close to hurt damage, mostly + // to allow trying other food sources first. + if (tameCheck && this.hitThreshold(HungerTask.BERRYGEN)) new GenBerries(this.pokemob).run(this.world); + // Otherwise take damage. - else if (this.hitThreshold(AIHungry.DAMAGE)) + if (this.hitThreshold(HungerTask.DAMAGE)) { - final float ratio = (AIHungry.DAMAGE - this.hungerValue) / AIHungry.DAMAGE; + final float ratio = (HungerTask.DAMAGE - this.hungerValue) / HungerTask.DAMAGE; final boolean dead = this.pokemob.getMaxHealth() * ratio > this.pokemob.getHealth() || this - .hitThreshold(AIHungry.DEATH); + .hitThreshold(HungerTask.DEATH); // Ensure it dies if it should. final float damage = dead ? this.pokemob.getMaxHealth() * 20 : this.pokemob.getMaxHealth() * ratio; if (damage >= 1 && ratio >= 0.0625 && this.entity.getHealth() > 0) diff --git a/src/main/java/pokecube/core/ai/tasks/idle/AIIdle.java b/src/main/java/pokecube/core/ai/tasks/idle/IdleWalkTask.java similarity index 92% rename from src/main/java/pokecube/core/ai/tasks/idle/AIIdle.java rename to src/main/java/pokecube/core/ai/tasks/idle/IdleWalkTask.java index ddc2dff686..d3147ff536 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/AIIdle.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/IdleWalkTask.java @@ -28,7 +28,7 @@ * This IAIRunnable makes the mobs randomly wander around if they have nothing * better to do. */ -public class AIIdle extends IdleTask +public class IdleWalkTask extends BaseIdleTask { public static int IDLETIMER = 1; @@ -61,11 +61,11 @@ public static Vector3 getRandomPointNear(final IBlockReader world, final IPokemo static { // Dont run if have a walk target - AIIdle.mems.put(MemoryModules.WALK_TARGET, MemoryModuleStatus.VALUE_ABSENT); + IdleWalkTask.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); + IdleWalkTask.mems.put(MemoryModules.MOVE_TARGET, MemoryModuleStatus.VALUE_ABSENT); // Don't run if we have a path - AIIdle.mems.put(MemoryModules.PATH, MemoryModuleStatus.VALUE_ABSENT); + IdleWalkTask.mems.put(MemoryModules.PATH, MemoryModuleStatus.VALUE_ABSENT); } final PokedexEntry entry; @@ -79,9 +79,9 @@ public static Vector3 getRandomPointNear(final IBlockReader world, final IPokemo Vector3 v = Vector3.getNewVector(); Vector3 v1 = Vector3.getNewVector(); - public AIIdle(final IPokemob pokemob) + public IdleWalkTask(final IPokemob pokemob) { - super(pokemob, AIIdle.mems); + super(pokemob, IdleWalkTask.mems); this.entry = pokemob.getPokedexEntry(); this.speed = this.entity.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); } @@ -178,7 +178,7 @@ private boolean getLocation() } else { - final Vector3 v = AIIdle.getRandomPointNear(this.world, this.pokemob, this.v, distance); + final Vector3 v = IdleWalkTask.getRandomPointNear(this.world, this.pokemob, this.v, distance); if (v == null) return false; double diff = Math.max(this.pokemob.getPokedexEntry().length * this.pokemob.getSize(), this.pokemob .getPokedexEntry().width * this.pokemob.getSize()); @@ -215,13 +215,13 @@ public void run() public boolean shouldRun() { // Configs can set this to -1 to disable idle movement entirely. - if (AIIdle.IDLETIMER <= 0) return false; + if (IdleWalkTask.IDLETIMER <= 0) return false; // Not currently able to move. if (!TaskBase.canMove(this.pokemob)) return false; // Check a random number as well - if (this.entity.getRNG().nextInt(AIIdle.IDLETIMER) != 0) return false; + if (this.entity.getRNG().nextInt(IdleWalkTask.IDLETIMER) != 0) return false; // Wander disabled, so don't run. if (!this.pokemob.isRoutineEnabled(AIRoutine.WANDER)) return false; diff --git a/src/main/java/pokecube/core/ai/tasks/idle/AIMate.java b/src/main/java/pokecube/core/ai/tasks/idle/MateTask.java similarity index 61% rename from src/main/java/pokecube/core/ai/tasks/idle/AIMate.java rename to src/main/java/pokecube/core/ai/tasks/idle/MateTask.java index 4305def6b6..cec57ce669 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/AIMate.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/MateTask.java @@ -7,6 +7,7 @@ import com.google.common.collect.Maps; import net.minecraft.entity.AgeableEntity; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus; import net.minecraft.entity.ai.brain.memory.MemoryModuleType; import net.minecraft.entity.ai.brain.memory.WalkTarget; @@ -14,7 +15,6 @@ 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.IPokemob; import pokecube.core.interfaces.capabilities.CapabilityPokemob; @@ -26,13 +26,13 @@ * pokemobs. It finds the mates, initiates the fighting over a mate (if * applicable), then tells the mobs to breed if they should. */ -public class AIMate extends IdleTask +public class MateTask extends BaseIdleTask { private static final Map, MemoryModuleStatus> mems = Maps.newHashMap(); static { // only run this if we have mate targets. - AIMate.mems.put(MemoryModules.POSSIBLE_MATES, MemoryModuleStatus.VALUE_PRESENT); + MateTask.mems.put(MemoryModules.POSSIBLE_MATES, MemoryModuleStatus.VALUE_PRESENT); } int spawnBabyDelay = 0; @@ -41,9 +41,14 @@ public class AIMate extends IdleTask AgeableEntity mate; - public AIMate(final IPokemob mob) + AgeableEntity mobA = null; + AgeableEntity mobB = null; + + WalkTarget startSpot = null; + + public MateTask(final IPokemob mob) { - super(mob, AIMate.mems); + super(mob, MateTask.mems); } @Override @@ -51,7 +56,9 @@ public void reset() { this.spawnBabyDelay = 0; this.mate = null; - this.pokemob.setGeneralState(GeneralStates.MATING, false); + this.mobA = null; + this.mobB = null; + this.startSpot = null; BrainUtils.setMateTarget((AgeableEntity) this.entity, null); } @@ -69,20 +76,30 @@ public void run() this.mate = this.mates.get(0); return; } + if (this.startSpot != null) this.setWalkTo(this.startSpot); + + if (this.mobA != null && this.mobB != null && this.mates.contains(this.mobA) && this.mates.contains(this.mobB)) + return; + + // Flag them all as valid mates + for (final AgeableEntity mob : this.mates) + BrainUtils.setMateTarget(mob, (AgeableEntity) this.entity); // Battle between the first two on the list. - final AgeableEntity mobA = this.mates.get(0); - final AgeableEntity mobB = this.mates.get(1); + this.mobA = this.mates.get(0); + this.mobB = this.mates.get(1); - final IPokemob pokeA = CapabilityPokemob.getPokemobFor(mobA); - final IPokemob pokeB = CapabilityPokemob.getPokemobFor(mobB); + final IPokemob pokeA = CapabilityPokemob.getPokemobFor(this.mobA); + final IPokemob pokeB = CapabilityPokemob.getPokemobFor(this.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); + BrainUtils.initiateCombat(this.mobA, this.mobB); + + this.startSpot = new WalkTarget(this.entity.getPositionVec(), (float) this.pokemob.getMovementSpeed(), 0); } @Override @@ -94,6 +111,11 @@ public boolean shouldRun() if (this.pokemob.getSexe() == IPokemob.MALE || !this.pokemob.canBreed()) return false; if (this.pokemob.getCombatState(CombatStates.ANGRY) || BrainUtils.hasAttackTarget(this.entity)) return false; this.mate = BrainUtils.getMateTarget((AgeableEntity) this.entity); + if (this.mate != null && !this.mate.isAlive()) + { + BrainUtils.setMateTarget((AgeableEntity) this.entity, null); + this.mate = null; + } if (this.mate != null) return true; this.mates = BrainUtils.getMates((AgeableEntity) this.entity); if (this.mates != null) @@ -114,16 +136,32 @@ public void tick() if (this.mate == null) return; // 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)); + this.approachEachOther(this.entity, this.mate, (float) this.pokemob.getMovementSpeed()); + + BrainUtils.setMateTarget((AgeableEntity) this.entity, this.mate); + BrainUtils.setMateTarget(this.mate, (AgeableEntity) this.entity); this.pokemob.setGeneralState(GeneralStates.MATING, true); - if (this.spawnBabyDelay++ < 50) return; final IPokemob other = CapabilityPokemob.getPokemobFor(this.mate); + if (other != null) other.setGeneralState(GeneralStates.MATING, true); + if (this.spawnBabyDelay++ < 100) return; if (other != null) this.pokemob.mateWith(other); this.reset(); other.resetLoveStatus(); this.pokemob.resetLoveStatus(); } + + void approachEachOther(final LivingEntity firstEntity, final LivingEntity secondEntity, final float speed) + { + this.approach(firstEntity, secondEntity, speed); + this.approach(secondEntity, firstEntity, speed); + } + + void approach(final LivingEntity living, final LivingEntity target, final float speed) + { + final EntityPosWrapper entityposwrapper = new EntityPosWrapper(target); + final WalkTarget walktarget = new WalkTarget(entityposwrapper, speed, 0); + living.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, entityposwrapper); + living.getBrain().setMemory(MemoryModuleType.WALK_TARGET, walktarget); + } } 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 index 50d2cf2854..d8aa64f30e 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatFromChest.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatFromChest.java @@ -9,7 +9,7 @@ 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.ai.tasks.idle.HungerTask; import pokecube.core.interfaces.IPokemob; import thut.api.item.ItemList; @@ -41,7 +41,7 @@ public EatResult eat(final IPokemob pokemob, final NearBlock block) for (int i1 = 0; i1 < container.getSizeInventory(); i1++) { final ItemStack stack = container.getStackInSlot(i1); - if (ItemList.is(AIHungry.FOODTAG, stack)) + if (ItemList.is(HungerTask.FOODTAG, stack)) { pokemob.eat(stack); stack.shrink(1); 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 index 629f48261a..6120b8acf9 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatPlant.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatPlant.java @@ -10,7 +10,7 @@ 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.ai.tasks.utility.GatherTask.ReplantTask; import pokecube.core.interfaces.IPokemob; import pokecube.core.world.terrain.PokecubeTerrainChecker; 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 index 29008ba7f7..6fe1a5c254 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatRedstone.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatRedstone.java @@ -23,7 +23,7 @@ public EatResult eat(final IPokemob pokemob, final NearBlock block) if (!pokemob.isElectrotroph()) return EatResult.NOEAT; final MobEntity entity = pokemob.getEntity(); - double diff = 1.5; + double diff = 3; diff = Math.max(diff, entity.getWidth()); final double dist = block.getPos().manhattanDistance(entity.getPosition()); this.setWalkTo(entity, block.getPos(), pokemob.getMovementSpeed(), 0); 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 index 0761612247..7f998ef980 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatRock.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatRock.java @@ -12,7 +12,7 @@ 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.ai.tasks.utility.GatherTask.ReplantTask; import pokecube.core.interfaces.IPokemob; import pokecube.core.world.terrain.PokecubeTerrainChecker; import thut.api.item.ItemList; 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 index f57aff2495..15916b687e 100644 --- a/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatWater.java +++ b/src/main/java/pokecube/core/ai/tasks/idle/hunger/EatWater.java @@ -10,13 +10,12 @@ 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); + private static final Predicate checker = (b2) -> b2.getFluidState().getFluid() instanceof WaterFluid; @Override public EatResult eat(final IPokemob pokemob, final NearBlock block) @@ -32,6 +31,7 @@ public EatResult eat(final IPokemob pokemob, final NearBlock block) 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); @@ -42,7 +42,7 @@ public EatResult eat(final IPokemob pokemob, final NearBlock block) @Override public boolean isValid(final NearBlock block) { - return block.getState().getFluidState().getFluid() instanceof WaterFluid; + return EatWater.checker.test(block.getState()); } } \ No newline at end of file diff --git a/src/main/java/pokecube/core/ai/tasks/utility/AIGatherStuff.java b/src/main/java/pokecube/core/ai/tasks/utility/GatherTask.java similarity index 94% rename from src/main/java/pokecube/core/ai/tasks/utility/AIGatherStuff.java rename to src/main/java/pokecube/core/ai/tasks/utility/GatherTask.java index 1095115258..f0c4bdcea8 100644 --- a/src/main/java/pokecube/core/ai/tasks/utility/AIGatherStuff.java +++ b/src/main/java/pokecube/core/ai/tasks/utility/GatherTask.java @@ -43,7 +43,7 @@ * berries. It requires an AIStoreStuff to have located a suitable storage * before it will run. */ -public class AIGatherStuff extends UtilTask +public class GatherTask extends UtilTask { /** * This manages the pokemobs replanting anything that they gather. @@ -130,11 +130,11 @@ public boolean run(final World world) // Matcher used to determine if a block is a fruit or crop to be picked. private static final Predicate harvestMatcher = input -> { - final boolean blacklisted = ItemList.is(AIGatherStuff.BLACKLIST, input); + final boolean blacklisted = ItemList.is(GatherTask.BLACKLIST, input); if (blacklisted) return false; final boolean fullCrop = input.getBlock() instanceof CropsBlock && input.get( CropsBlock.AGE) >= ((CropsBlock) input.getBlock()).getMaxAge(); - return fullCrop || ItemList.is(AIGatherStuff.HARVEST, input); + return fullCrop || ItemList.is(GatherTask.HARVEST, input); }; private static final Predicate deaditemmatcher = input -> !input.isAlive() || !input.addedToChunk @@ -153,14 +153,14 @@ public boolean run(final World world) int collectCooldown = 0; int pathCooldown = 0; - final AIStoreStuff storage; + final StoreTask storage; Vector3 seeking = Vector3.getNewVector(); Vector3 v = Vector3.getNewVector(); Vector3 v1 = Vector3.getNewVector(); - public AIGatherStuff(final IPokemob mob, final double distance, final AIStoreStuff storage) + public GatherTask(final IPokemob mob, final double distance, final StoreTask storage) { super(mob); this.distance = distance; @@ -169,8 +169,8 @@ public AIGatherStuff(final IPokemob mob, final double distance, final AIStoreStu private boolean hasStuff() { - if (this.targetItem != null && AIGatherStuff.deaditemmatcher.apply(this.targetItem)) this.targetItem = null; - if (this.targetBlock != null && !AIGatherStuff.harvestMatcher.apply(this.entity.getEntityWorld().getBlockState( + if (this.targetItem != null && GatherTask.deaditemmatcher.apply(this.targetItem)) this.targetItem = null; + if (this.targetBlock != null && !GatherTask.harvestMatcher.apply(this.entity.getEntityWorld().getBlockState( this.targetBlock.getPos()))) this.targetBlock = null; return this.targetItem != null || this.targetBlock != null; } @@ -187,7 +187,7 @@ private void findStuff() { // Check for items to possibly gather. for (final ItemEntity e : this.items) - if (!AIGatherStuff.deaditemmatcher.apply(e)) + if (!GatherTask.deaditemmatcher.apply(e)) { this.targetItem = e; return; @@ -200,7 +200,7 @@ private void findStuff() return; } // Nothing found, enter cooldown. - this.collectCooldown = AIGatherStuff.COOLDOWN_SEARCH; + this.collectCooldown = GatherTask.COOLDOWN_SEARCH; } private void gatherStuff() @@ -313,7 +313,7 @@ public boolean shouldRun() if (blocks != null) { this.blocks = Lists.newArrayList(blocks); - this.blocks.removeIf(b -> !AIGatherStuff.harvestMatcher.apply(b.getState())); + this.blocks.removeIf(b -> !GatherTask.harvestMatcher.apply(b.getState())); } // Only replace this if the new list is not null. if (items != null) this.items = items; diff --git a/src/main/java/pokecube/core/ai/tasks/utility/AIStoreStuff.java b/src/main/java/pokecube/core/ai/tasks/utility/StoreTask.java similarity index 95% rename from src/main/java/pokecube/core/ai/tasks/utility/AIStoreStuff.java rename to src/main/java/pokecube/core/ai/tasks/utility/StoreTask.java index a0540950c4..e8b1b2e497 100644 --- a/src/main/java/pokecube/core/ai/tasks/utility/AIStoreStuff.java +++ b/src/main/java/pokecube/core/ai/tasks/utility/StoreTask.java @@ -23,7 +23,7 @@ import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.InvWrapper; -import pokecube.core.ai.tasks.idle.AIHungry; +import pokecube.core.ai.tasks.idle.HungerTask; import pokecube.core.interfaces.IMoveConstants.AIRoutine; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.pokemob.ai.GeneralStates; @@ -37,7 +37,7 @@ * allows using pokemobs for automatic harvesting and storage of berries and * dropped items. */ -public class AIStoreStuff extends UtilTask implements INBTSerializable, IInventoryChangedListener +public class StoreTask extends UtilTask implements INBTSerializable, IInventoryChangedListener { public static int COOLDOWN = 10; public static int MAXSIZE = 100; @@ -66,7 +66,7 @@ public class AIStoreStuff extends UtilTask implements INBTSerializable 9) { this.pathing = true; @@ -189,7 +189,7 @@ private boolean doBerryCheck(final IItemHandlerModifiable pokemobInv) // + " Pathing to Berries at " + this.berryLoc); return true; } - for (int i = 0; i < Math.min(berries.getSlots(), AIStoreStuff.MAXSIZE); i++) + for (int i = 0; i < Math.min(berries.getSlots(), StoreTask.MAXSIZE); i++) { final ItemStack stack = berries.getStackInSlot(i); if (stack.getItem() instanceof ItemBerry) @@ -243,7 +243,7 @@ private boolean doEmptyCheck(final IItemHandlerModifiable pokemobInv) inv: for (int slot = this.firstEmpty; slot < pokemobInv.getSlots(); slot++) if (pokemobInv.getStackInSlot(slot).isEmpty()) for (int i = start; i < Math.min(inventory.getSlots(), - AIStoreStuff.MAXSIZE); i++) + StoreTask.MAXSIZE); i++) { final ItemStack stack = inventory.getStackInSlot(i); if (!stack.isEmpty()) @@ -376,14 +376,14 @@ private IItemHandlerModifiable getInventory(final IBlockReader world, final Bloc final TileEntity tile = world.getTileEntity(pos); if (tile == null) return null; IItemHandler handler; - if ((handler = tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side).orElseGet( + if ((handler = tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side).orElse( null)) instanceof IItemHandlerModifiable) return (IItemHandlerModifiable) handler; return null; } private boolean hasItem(final ResourceLocation tag, final IItemHandlerModifiable inventory) { - for (int i = 0; i < Math.min(inventory.getSlots(), AIStoreStuff.MAXSIZE); i++) + for (int i = 0; i < Math.min(inventory.getSlots(), StoreTask.MAXSIZE); i++) { final ItemStack stack = inventory.getStackInSlot(i); if (stack.isEmpty()) continue; @@ -468,14 +468,14 @@ public void tick() boolean stuff = false; if (this.searchInventoryCooldown-- < 0) { - this.searchInventoryCooldown = AIStoreStuff.COOLDOWN; + this.searchInventoryCooldown = StoreTask.COOLDOWN; this.findBerryStorage(true); stuff = this.findItemStorage(true); - if (!stuff) this.searchInventoryCooldown = 50 * AIStoreStuff.COOLDOWN; + if (!stuff) this.searchInventoryCooldown = 50 * StoreTask.COOLDOWN; } final IItemHandlerModifiable itemhandler = new InvWrapper(this.pokemob.getInventory()); if (this.doBerryCheck(itemhandler) || this.doStorageCheck(itemhandler) || this.doEmptyCheck(itemhandler)) this.doStorageCooldown = 5; - else this.doStorageCooldown = 10 * AIStoreStuff.COOLDOWN; + else this.doStorageCooldown = 10 * StoreTask.COOLDOWN; } } diff --git a/src/main/java/pokecube/core/ai/tasks/utility/AIUseMove.java b/src/main/java/pokecube/core/ai/tasks/utility/UseMoveTask.java similarity index 96% rename from src/main/java/pokecube/core/ai/tasks/utility/AIUseMove.java rename to src/main/java/pokecube/core/ai/tasks/utility/UseMoveTask.java index ac6665a70c..b12bfc15b9 100644 --- a/src/main/java/pokecube/core/ai/tasks/utility/AIUseMove.java +++ b/src/main/java/pokecube/core/ai/tasks/utility/UseMoveTask.java @@ -25,13 +25,13 @@ import pokecube.core.moves.MovesUtils; import thut.api.maths.Vector3; -public class AIUseMove extends UtilTask +public class UseMoveTask extends UtilTask { private static final Map, MemoryModuleStatus> MEMS = Maps.newHashMap(); static { - AIUseMove.MEMS.put(MemoryModules.MOVE_TARGET, MemoryModuleStatus.VALUE_PRESENT); + UseMoveTask.MEMS.put(MemoryModules.MOVE_TARGET, MemoryModuleStatus.VALUE_PRESENT); } private boolean running = false; @@ -43,9 +43,9 @@ public class AIUseMove extends UtilTask double speed; - public AIUseMove(final IPokemob pokemob) + public UseMoveTask(final IPokemob pokemob) { - super(pokemob, AIUseMove.MEMS); + super(pokemob, UseMoveTask.MEMS); } @Override diff --git a/src/main/java/pokecube/core/client/EventsHandlerClient.java b/src/main/java/pokecube/core/client/EventsHandlerClient.java index 1b4cc66e1d..e9749f6ab9 100644 --- a/src/main/java/pokecube/core/client/EventsHandlerClient.java +++ b/src/main/java/pokecube/core/client/EventsHandlerClient.java @@ -1,6 +1,7 @@ package pokecube.core.client; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -21,6 +22,8 @@ import net.minecraft.client.renderer.entity.PlayerRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.MobEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; @@ -65,11 +68,13 @@ import pokecube.core.interfaces.pokemob.ai.CombatStates; import pokecube.core.interfaces.pokemob.ai.GeneralStates; import pokecube.core.interfaces.pokemob.commandhandlers.StanceHandler; +import pokecube.core.items.pokecubes.EntityPokecubeBase; import pokecube.core.items.pokecubes.PokecubeManager; import pokecube.core.network.pokemobs.PacketChangeForme; import pokecube.core.network.pokemobs.PacketCommand; import pokecube.core.network.pokemobs.PacketMountedControl; import pokecube.core.proxy.ClientProxy; +import pokecube.core.utils.PokemobTracker; import pokecube.core.utils.TagNames; import pokecube.core.utils.Tools; import thut.api.entity.genetics.GeneRegistry; @@ -82,6 +87,24 @@ public class EventsHandlerClient static long lastSetTime = 0; + /** + * Gets all pokemobs owned by owner within the given distance. + * + * @param owner + * @param distance + * @return + */ + public static List getPokemobs(final LivingEntity owner, final double distance) + { + final List ret = new ArrayList<>(); + for (final Entity e : PokemobTracker.getMobs(owner, e -> !(e instanceof EntityPokecubeBase))) + { + final IPokemob mob = CapabilityPokemob.getPokemobFor(e); + if (mob != null) ret.add(mob); + } + return ret; + } + @SubscribeEvent public static void clientTick(final TickEvent.PlayerTickEvent event) { diff --git a/src/main/java/pokecube/core/client/gui/GuiDisplayPokecubeInfo.java b/src/main/java/pokecube/core/client/gui/GuiDisplayPokecubeInfo.java index 3013afccf0..b451cd8d6b 100644 --- a/src/main/java/pokecube/core/client/gui/GuiDisplayPokecubeInfo.java +++ b/src/main/java/pokecube/core/client/gui/GuiDisplayPokecubeInfo.java @@ -35,10 +35,10 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.client.EventsHandlerClient; import pokecube.core.client.GuiEvent; import pokecube.core.client.Resources; import pokecube.core.client.gui.pokemob.GuiPokemobBase; -import pokecube.core.handlers.events.EventsHandler; import pokecube.core.interfaces.IMoveConstants; import pokecube.core.interfaces.IMoveConstants.AIRoutine; import pokecube.core.interfaces.IMoveNames; @@ -542,7 +542,7 @@ public IPokemob[] getPokemobsToDisplay() if (player == null || player.getEntityWorld() == null) return new IPokemob[0]; - final List pokemobs = EventsHandler.getPokemobs(player, 96); + final List pokemobs = EventsHandlerClient.getPokemobs(player, 96); final List ret = new ArrayList<>(); for (final IPokemob pokemob : pokemobs) { diff --git a/src/main/java/pokecube/core/client/gui/pokemob/GuiPokemobStorage.java b/src/main/java/pokecube/core/client/gui/pokemob/GuiPokemobStorage.java index b0f8848b12..a8b2951b0b 100644 --- a/src/main/java/pokecube/core/client/gui/pokemob/GuiPokemobStorage.java +++ b/src/main/java/pokecube/core/client/gui/pokemob/GuiPokemobStorage.java @@ -16,7 +16,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TranslationTextComponent; -import pokecube.core.ai.tasks.utility.AIStoreStuff; +import pokecube.core.ai.tasks.utility.StoreTask; import pokecube.core.entity.pokemobs.ContainerPokemob; import pokecube.core.interfaces.IPokemob; import pokecube.core.network.pokemobs.PacketPokemobGui; @@ -34,7 +34,7 @@ public class GuiPokemobStorage extends GuiPokemobBase TextFieldWidget storage; TextFieldWidget storageFace; TextFieldWidget empty; - AIStoreStuff ai; + StoreTask ai; TextFieldWidget emptyFace; List textBoxes = Lists.newArrayList(); @@ -45,7 +45,7 @@ public GuiPokemobStorage(final ContainerPokemob container, final PlayerInventory this.playerInventory = playerInv; this.pokeInventory = this.pokemob.getInventory(); this.entity = this.pokemob.getEntity(); - this.ai = new AIStoreStuff(this.pokemob); + this.ai = new StoreTask(this.pokemob); final CompoundNBT tag = container.data.readCompoundTag(); this.ai.deserializeNBT(tag); container.setMode(PacketPokemobGui.STORAGE); 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 a02887d585..f2a1fcac39 100644 --- a/src/main/java/pokecube/core/client/render/mobs/RenderPokemob.java +++ b/src/main/java/pokecube/core/client/render/mobs/RenderPokemob.java @@ -547,6 +547,7 @@ public static void register() final Holder holder = new Holder(entry); RenderPokemob.holderMap.put(type, holder); RenderPokemob.holders.put(entry, holder); + if (PokecubeCore.getConfig().preloadModels) holder.init(); } } diff --git a/src/main/java/pokecube/core/database/Database.java b/src/main/java/pokecube/core/database/Database.java index f2844ccd27..f7d26af6ac 100644 --- a/src/main/java/pokecube/core/database/Database.java +++ b/src/main/java/pokecube/core/database/Database.java @@ -16,9 +16,6 @@ import java.util.Map; import java.util.Set; -import thut.core.xml.bind.annotation.XmlAttribute; -import thut.core.xml.bind.annotation.XmlElement; -import thut.core.xml.bind.annotation.XmlRootElement; import javax.xml.namespace.QName; import com.google.common.collect.Lists; @@ -67,6 +64,9 @@ import pokecube.core.moves.implementations.MovesAdder; import pokecube.core.utils.PokeType; import thut.core.common.ThutCore; +import thut.core.xml.bind.annotation.XmlAttribute; +import thut.core.xml.bind.annotation.XmlElement; +import thut.core.xml.bind.annotation.XmlRootElement; public class Database { @@ -666,16 +666,22 @@ public static void initSounds(final IForgeRegistry registry) { final ResourceLocation sound = new ResourceLocation(entry.soundEffectSource); final SoundEvent event = new SoundEvent(sound); - event.setRegistryName(sound); - if (!registry.containsKey(sound) && !sound.getNamespace().equals("minecraft")) registry.register(event); + if (!registry.containsKey(sound) && !sound.getNamespace().equals("minecraft")) + { + event.setRegistryName(sound); + registry.register(event); + } } // Register sound on target if (entry.soundEffectTarget != null) { final ResourceLocation sound = new ResourceLocation(entry.soundEffectTarget); final SoundEvent event = new SoundEvent(sound); - event.setRegistryName(sound); - if (!registry.containsKey(sound) && !sound.getNamespace().equals("minecraft")) registry.register(event); + if (!registry.containsKey(sound) && !sound.getNamespace().equals("minecraft")) + { + event.setRegistryName(sound); + registry.register(event); + } } // Register sounds for the animations if (entry.animations != null) for (final AnimationJson anim : entry.animations) @@ -683,9 +689,11 @@ public static void initSounds(final IForgeRegistry registry) { final ResourceLocation sound = new ResourceLocation(anim.sound); final SoundEvent event = new SoundEvent(sound); - event.setRegistryName(sound); - if (!registry.containsKey(sound) && !sound.getNamespace().equals("minecraft")) registry.register( - event); + if (!registry.containsKey(sound) && !sound.getNamespace().equals("minecraft")) + { + event.setRegistryName(sound); + registry.register(event); + } } } @@ -694,8 +702,11 @@ public static void initSounds(final IForgeRegistry registry) { final ResourceLocation sound = new ResourceLocation(var); final SoundEvent event = new SoundEvent(sound); - event.setRegistryName(sound); - if (!registry.containsKey(sound) && !sound.getNamespace().equals("minecraft")) registry.register(event); + if (!registry.containsKey(sound) && !sound.getNamespace().equals("minecraft")) + { + event.setRegistryName(sound); + registry.register(event); + } } } diff --git a/src/main/java/pokecube/core/database/PokedexEntry.java b/src/main/java/pokecube/core/database/PokedexEntry.java index e0387981d3..4fe689615d 100644 --- a/src/main/java/pokecube/core/database/PokedexEntry.java +++ b/src/main/java/pokecube/core/database/PokedexEntry.java @@ -45,7 +45,7 @@ import net.minecraftforge.fml.ModLoadingContext; import pokecube.core.PokecubeCore; import pokecube.core.PokecubeItems; -import pokecube.core.ai.tasks.combat.AIFindTarget; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.database.PokedexEntryLoader.Action; import pokecube.core.database.PokedexEntryLoader.DefaultFormeHolder; import pokecube.core.database.PokedexEntryLoader.Drop; @@ -526,7 +526,7 @@ public boolean applyInteraction(final PlayerEntity player, final IPokemob pokemo if (consumeInput) held.shrink(1); if (held.isEmpty()) player.inventory.setInventorySlotContents(player.inventory.currentItem, result); else if (!player.inventory.addItemStackToInventory(result)) player.dropItem(result, false); - if (player != pokemob.getOwner()) AIFindTarget.initiateCombat(entity, player); + if (player != pokemob.getOwner()) BrainUtils.initiateCombat(entity, player); return true; } @@ -1781,7 +1781,7 @@ protected void initRelations() * returns whether the interaction logic has a response listed for the * given key. * - * @param pokemob + * @param cube * @param doInteract * - if false, will not actually do anything. * @return diff --git a/src/main/java/pokecube/core/database/recipes/XMLRecipeHandler.java b/src/main/java/pokecube/core/database/recipes/XMLRecipeHandler.java index 6e7c5c6015..cafbb4d5eb 100644 --- a/src/main/java/pokecube/core/database/recipes/XMLRecipeHandler.java +++ b/src/main/java/pokecube/core/database/recipes/XMLRecipeHandler.java @@ -4,10 +4,6 @@ import java.util.Map; import java.util.Set; -import thut.core.xml.bind.annotation.XmlAnyAttribute; -import thut.core.xml.bind.annotation.XmlAttribute; -import thut.core.xml.bind.annotation.XmlElement; -import thut.core.xml.bind.annotation.XmlRootElement; import javax.xml.namespace.QName; import com.google.common.collect.Lists; @@ -17,6 +13,10 @@ import net.minecraft.util.ResourceLocation; import pokecube.core.PokecubeCore; import pokecube.core.database.PokedexEntryLoader.Drop; +import thut.core.xml.bind.annotation.XmlAnyAttribute; +import thut.core.xml.bind.annotation.XmlAttribute; +import thut.core.xml.bind.annotation.XmlElement; +import thut.core.xml.bind.annotation.XmlRootElement; public class XMLRecipeHandler { diff --git a/src/main/java/pokecube/core/database/rewards/XMLRewardsHandler.java b/src/main/java/pokecube/core/database/rewards/XMLRewardsHandler.java index 387c9d1463..9ec58b0565 100644 --- a/src/main/java/pokecube/core/database/rewards/XMLRewardsHandler.java +++ b/src/main/java/pokecube/core/database/rewards/XMLRewardsHandler.java @@ -7,10 +7,6 @@ import java.util.Map; import java.util.Set; -import thut.core.xml.bind.annotation.XmlAnyAttribute; -import thut.core.xml.bind.annotation.XmlAttribute; -import thut.core.xml.bind.annotation.XmlElement; -import thut.core.xml.bind.annotation.XmlRootElement; import javax.xml.namespace.QName; import org.jline.utils.InputStreamReader; @@ -39,6 +35,10 @@ import pokecube.core.handlers.PokedexInspector.IInspectReward; import pokecube.core.handlers.playerdata.PokecubePlayerCustomData; import pokecube.core.utils.Tools; +import thut.core.xml.bind.annotation.XmlAnyAttribute; +import thut.core.xml.bind.annotation.XmlAttribute; +import thut.core.xml.bind.annotation.XmlElement; +import thut.core.xml.bind.annotation.XmlRootElement; public class XMLRewardsHandler { diff --git a/src/main/java/pokecube/core/entity/npc/NpcMob.java b/src/main/java/pokecube/core/entity/npc/NpcMob.java index 6d46255c14..86f18a8c88 100644 --- a/src/main/java/pokecube/core/entity/npc/NpcMob.java +++ b/src/main/java/pokecube/core/entity/npc/NpcMob.java @@ -103,8 +103,9 @@ protected void initBrain(final Brain brain) if (guard != null) { final GuardAI guardai = new GuardAI(this, guard); - final VillagerProfession profession = this.getVillagerData().getProfession(); + if (this.getNpcType() != null && this.getNpcType().getProfession() != profession) this.setVillagerData(this + .getVillagerData().withLevel(3).withProfession(this.getNpcType().getProfession())); final float f = (float) this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue(); if (this.isChild()) { @@ -158,7 +159,7 @@ public boolean attackEntityFrom(final DamageSource source, final float i) public void setVillagerData(final VillagerData data) { final MerchantOffers trades = this.offers; - super.setVillagerData(data.withProfession(VillagerProfession.NITWIT)); + super.setVillagerData(data); this.offers = trades; } @@ -172,7 +173,8 @@ public IPacket createSpawnPacket() public ILivingEntityData onInitialSpawn(final IWorld worldIn, final DifficultyInstance difficultyIn, final SpawnReason reason, final ILivingEntityData spawnDataIn, final CompoundNBT dataTag) { - this.setVillagerData(this.getVillagerData().withProfession(VillagerProfession.NONE)); + final VillagerProfession proff = this.getNpcType().getProfession(); + this.setVillagerData(this.getVillagerData().withProfession(proff).withLevel(3)); this.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).applyModifier(new AttributeModifier( "Random spawn bonus", this.rand.nextGaussian() * 0.05D, AttributeModifier.Operation.MULTIPLY_BASE)); if (this.rand.nextFloat() < 0.05F) this.setLeftHanded(true); diff --git a/src/main/java/pokecube/core/entity/npc/NpcType.java b/src/main/java/pokecube/core/entity/npc/NpcType.java index 95e11d92cc..f0b5f252c0 100644 --- a/src/main/java/pokecube/core/entity/npc/NpcType.java +++ b/src/main/java/pokecube/core/entity/npc/NpcType.java @@ -5,6 +5,7 @@ import com.google.common.collect.Maps; +import net.minecraft.entity.merchant.villager.VillagerProfession; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.container.SimpleNamedContainerProvider; @@ -98,7 +99,9 @@ public static NpcType byType(String string) private ResourceLocation maleTex; private ResourceLocation femaleTex; - private IInteract interaction = (p, h, mob) -> false; + private VillagerProfession profession = VillagerProfession.NITWIT; + + private IInteract interaction = (p, h, mob) -> false; public NpcType(String string) { @@ -158,4 +161,14 @@ public IInteract getInteraction() { return this.interaction; } + + public VillagerProfession getProfession() + { + return this.profession; + } + + public void setProfession(final VillagerProfession profession) + { + this.profession = profession; + } } diff --git a/src/main/java/pokecube/core/entity/pokemobs/EntityPokemob.java b/src/main/java/pokecube/core/entity/pokemobs/EntityPokemob.java index b26dcc462c..da636b1fbb 100644 --- a/src/main/java/pokecube/core/entity/pokemobs/EntityPokemob.java +++ b/src/main/java/pokecube/core/entity/pokemobs/EntityPokemob.java @@ -286,9 +286,12 @@ public void setPortal(final BlockPos pos) @Override public void onAddedToWorld() { - PokemobTracker.addPokemob(this.pokemobCap); - if (this.pokemobCap.isPlayerOwned() && this.pokemobCap.getOwnerId() != null) PlayerPokemobCache.UpdateCache( - this.pokemobCap); + if (!this.isAddedToWorld()) + { + PokemobTracker.addPokemob(this.pokemobCap); + if (this.pokemobCap.isPlayerOwned() && this.pokemobCap.getOwnerId() != null) PlayerPokemobCache.UpdateCache( + this.pokemobCap); + } super.onAddedToWorld(); } diff --git a/src/main/java/pokecube/core/entity/pokemobs/helper/PokemobBase.java b/src/main/java/pokecube/core/entity/pokemobs/helper/PokemobBase.java index 70b5ab652a..43e7bd0e47 100644 --- a/src/main/java/pokecube/core/entity/pokemobs/helper/PokemobBase.java +++ b/src/main/java/pokecube/core/entity/pokemobs/helper/PokemobBase.java @@ -20,7 +20,6 @@ public abstract class PokemobBase extends ShoulderRidingEntity implements IEntit IMobColourable { public final DefaultPokemob pokemobCap; - protected EntitySize size; public PokemobBase(final EntityType type, final World worldIn) { diff --git a/src/main/java/pokecube/core/entity/pokemobs/helper/PokemobRidable.java b/src/main/java/pokecube/core/entity/pokemobs/helper/PokemobRidable.java index 78d0668001..43dd7c9618 100644 --- a/src/main/java/pokecube/core/entity/pokemobs/helper/PokemobRidable.java +++ b/src/main/java/pokecube/core/entity/pokemobs/helper/PokemobRidable.java @@ -119,7 +119,6 @@ public void updateSeat(final int index, final UUID id) { toSet = new Seat(toSet.seat, id); this.dataManager.set(PokemobRidable.SEAT[index], toSet); - } } @@ -140,7 +139,7 @@ protected void initSeats() final float dx = this.pokemobCap.getPokedexEntry().width * this.pokemobCap.getSize(), dz = this.pokemobCap .getPokedexEntry().length * this.pokemobCap.getSize(); seat.x *= dx; - seat.y *= this.getHeight(); + seat.y *= this.pokemobCap.getPokedexEntry().height * this.pokemobCap.getSize(); seat.z *= dz; this.getSeat(index).seat = seat; } diff --git a/src/main/java/pokecube/core/events/EggEvent.java b/src/main/java/pokecube/core/events/EggEvent.java index 9c59d53835..76349c7e24 100644 --- a/src/main/java/pokecube/core/events/EggEvent.java +++ b/src/main/java/pokecube/core/events/EggEvent.java @@ -1,15 +1,38 @@ package pokecube.core.events; import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraftforge.eventbus.api.Cancelable; import net.minecraftforge.eventbus.api.Event; import pokecube.core.items.pokemobeggs.EntityPokemobEgg; public class EggEvent extends Event { + @Cancelable + /** + * This is called when two pokemobs try to decide if they can breed, if + * cancelled, they are not compatible. + */ + public static class CanBreed extends LivingEvent + { + private final LivingEntity other; + + public CanBreed(final LivingEntity first, final LivingEntity other) + { + super(first); + this.other = other; + } + + public LivingEntity getOther() + { + return this.other; + } + } + public static class Hatch extends EggEvent { - public Hatch(Entity egg) + public Hatch(final Entity egg) { super((EntityPokemobEgg) egg); } @@ -22,7 +45,7 @@ public Hatch(Entity egg) */ public static class Lay extends EggEvent { - public Lay(Entity egg) + public Lay(final Entity egg) { super((EntityPokemobEgg) egg); } @@ -34,7 +57,7 @@ public Lay(Entity egg) */ public static class Place extends EggEvent { - public Place(Entity egg) + public Place(final Entity egg) { super((EntityPokemobEgg) egg); } @@ -47,7 +70,7 @@ public Place(Entity egg) */ public static class PreHatch extends EggEvent { - public PreHatch(Entity egg) + public PreHatch(final Entity egg) { super((EntityPokemobEgg) egg); } @@ -57,7 +80,7 @@ public PreHatch(Entity egg) public final EntityPokemobEgg egg; - private EggEvent(EntityPokemobEgg egg) + private EggEvent(final EntityPokemobEgg egg) { this.placer = egg.getEggOwner(); this.egg = egg; diff --git a/src/main/java/pokecube/core/handlers/Config.java b/src/main/java/pokecube/core/handlers/Config.java index 99011b3794..a602fa54b4 100644 --- a/src/main/java/pokecube/core/handlers/Config.java +++ b/src/main/java/pokecube/core/handlers/Config.java @@ -13,8 +13,8 @@ import pokecube.core.PokecubeCore; import pokecube.core.PokecubeItems; import pokecube.core.ai.logic.LogicMountedControl; -import pokecube.core.ai.tasks.idle.AIHungry; -import pokecube.core.ai.tasks.idle.AIIdle; +import pokecube.core.ai.tasks.idle.HungerTask; +import pokecube.core.ai.tasks.idle.IdleWalkTask; import pokecube.core.database.Database.EnumDatabase; import pokecube.core.database.recipes.XMLRecipeHandler; import pokecube.core.database.rewards.XMLRewardsHandler; @@ -26,6 +26,7 @@ import pokecube.core.items.pokecubes.Pokecube; import pokecube.core.items.pokecubes.PokecubeManager; import pokecube.core.items.pokemobeggs.ItemPokemobEgg; +import pokecube.core.utils.AITools; import pokecube.core.utils.PokecubeSerializer; import pokecube.core.world.terrain.PokecubeTerrainChecker; import thut.core.common.config.Config.ConfigData; @@ -177,127 +178,134 @@ private static SoundEvent getRegisteredSoundEvent(final String id) @Configure(category = Config.moves) public boolean defaultIceActions = true; - @Configure(category = Config.moves, type = Type.CLIENT) - public double moveVolumeCry = 0.0625f; - @Configure(category = Config.moves, type = Type.CLIENT) - public double moveVolumeEffect = 1; - // AI Related settings @Configure(category = Config.mobAI) - public int mateMultiplier = 1; - @Configure(category = Config.mobAI) - public double mateDensityWild = 2; - @Configure(category = Config.mobAI) - public int mateAIRate = 40; + public int mateMultiplier = 1; @Configure(category = Config.mobAI) - public double mateDensityPlayer = 4; + public int mateAIRate = 40; @Configure(category = Config.mobAI) - public int breedingDelay = 4000; + public int breedingDelay = 4000; @Configure(category = Config.mobAI) - public int eggHatchTime = 10000; - @Configure(category = Config.mobAI) - /** do wild pokemobs which leave cullDistance despawn immediately */ - public boolean cull = false; + public int eggHatchTime = 10000; /** distance for culling */ @Configure(category = Config.mobAI) - public int cullDistance = 96; - @Configure(category = Config.mobAI) - public boolean despawn = true; + public int cullDistance = 96; /** distance for culling */ @Configure(category = Config.mobAI) - public int despawnTimer = 2000; - @Configure(category = Config.mobAI) - /** Will lithovores eat gravel */ - public boolean pokemobsEatGravel = false; - @Configure(category = Config.mobAI) - /** Will lithovores eat rocks */ - public boolean pokemobsEatRocks = true; - @Configure(category = Config.mobAI) - /** Will herbivores eat plants */ - public boolean pokemobsEatPlants = true; - @Configure(category = Config.mobAI) - /** Is there a warning before a wild pok�mob attacks the player. */ - public boolean pokemobagresswarning = true; + public int despawnTimer = 2000; @Configure(category = Config.mobAI) /** Distance to player needed to agress the player */ - public int mobAggroRadius = 3; + public int mobAggroRadius = 3; @Configure(category = Config.mobAI) /** * Approximately how many ticks between wild pokemobs running agro * checks. */ - public int mobAgroRate = 200; + public int mobAgroRate = 200; @Configure(category = Config.mobAI) /** * Approximate number of ticks before pok�mob starts taking hunger * damage */ - public int pokemobLifeSpan = 8000; + public int pokemobLifeSpan = 8000; @Configure(category = Config.mobAI) - /** Warning time before a wild pok�mob attacks a player */ - public int pokemobagressticks = 100; + /** Warning time before a wild pokemob attacks a player */ + public int pokemobagressticks = 100; + @Configure(category = Config.mobAI) - public boolean pokemobsDamageOwner = false; + public double mateDensityWild = 2; @Configure(category = Config.mobAI) - public boolean pokemobsDamagePlayers = true; + public double expFromDeathDropScale = 1; @Configure(category = Config.mobAI) - public boolean pokemobsDamageBlocks = false; + public double mateDensityPlayer = 4; + @Configure(category = Config.mobAI) - public boolean pokemobsDropItems = true; + /** do wild pokemobs which leave cullDistance despawn immediately */ + public boolean cull = false; + @Configure(category = Config.mobAI) + public boolean despawn = true; + @Configure(category = Config.mobAI) + /** Will lithovores eat gravel */ + public boolean pokemobsEatGravel = false; @Configure(category = Config.mobAI) - public double expFromDeathDropScale = 1; + /** Will lithovores eat rocks */ + public boolean pokemobsEatRocks = true; + @Configure(category = Config.mobAI) + /** Will herbivores eat plants */ + public boolean pokemobsEatPlants = true; + @Configure(category = Config.mobAI) + /** Is there a warning before a wild pok�mob attacks the player. */ + public boolean pokemobagresswarning = true; + @Configure(category = Config.mobAI) + public boolean pokemobsDamageOwner = false; + @Configure(category = Config.mobAI) + public boolean pokemobsDamagePlayers = true; + @Configure(category = Config.mobAI) + public boolean pokemobsDamageBlocks = false; + @Configure(category = Config.mobAI) + public boolean pokemobsDropItems = true; @Configure(category = Config.mobAI) /** Do explosions occur and cause damage */ - public boolean explosions = true; + public boolean explosions = true; + @Configure(category = Config.mobAI) - public int chaseDistance = 32; + public int chaseDistance = 32; @Configure(category = Config.mobAI) - public int combatDistance = 4; + public int combatDistance = 4; @Configure(category = Config.mobAI) - public int aiDisableDistance = 32; + public int aiDisableDistance = 32; @Configure(category = Config.mobAI) - public int tameGatherDelay = 20; + public int tameGatherDelay = 20; @Configure(category = Config.mobAI) - public int wildGatherDelay = 200; + public int wildGatherDelay = 200; @Configure(category = Config.mobAI) - public int tameGatherDistance = 16; + public int tameGatherDistance = 16; @Configure(category = Config.mobAI) - public int wildGatherDistance = 8; + public int wildGatherDistance = 8; + @Configure(category = Config.mobAI) - public boolean tameGather = true; + public boolean tameGather = true; @Configure(category = Config.mobAI) - public boolean wildGather = false; + public boolean wildGather = false; @Configure(category = Config.mobAI) - public boolean flyEnabled = true; + public boolean flyEnabled = true; @Configure(category = Config.mobAI) - public boolean surfEnabled = true; + public boolean surfEnabled = true; @Configure(category = Config.mobAI) - public boolean diveEnabled = true; + public boolean diveEnabled = true; + @Configure(category = Config.mobAI) - public List dodgeSounds = Lists.newArrayList("entity.witch.throw"); + public List dodgeSounds = Lists.newArrayList("entity.witch.throw"); @Configure(category = Config.mobAI) - public List leapSounds = Lists.newArrayList("entity.witch.throw"); + public List leapSounds = Lists.newArrayList("entity.witch.throw"); @Configure(category = Config.mobAI) - public List guardBlacklistClass = Lists.newArrayList("net.minecraft.entity.IMerchant", - "net.minecraft.entity.INpc", "pokecube.core.items.pokemobeggs.EntityPokemobEgg", - "net.minecraft.entity.IProjectile"); + public List aggroBlacklistTags = Lists.newArrayList(); @Configure(category = Config.mobAI) - public List guardBlacklistId = Lists.newArrayList(); + public List aggroBlacklistIds = Lists.newArrayList("minecraft:villager", "minecraft:armor_stand", + "pokecube_adventures:trainer", "pokecube_adventures:leader"); + @Configure(category = Config.mobAI) - public double interactHungerScale = 1; + public double interactHungerScale = 1; @Configure(category = Config.mobAI) - public double interactDelayScale = 1; + public double interactDelayScale = 1; @Configure(category = Config.mobAI) - public boolean pokemobsOnShoulder = true; + public boolean pokemobsOnShoulder = true; + @Configure(category = Config.mobAI) - public int fishHookBaitRange = 16; + public int fishHookBaitRange = 16; @Configure(category = Config.mobAI) - public boolean guardModeEnabled = true; + public boolean guardModeEnabled = true; + @Configure(category = Config.mobAI) - public int guardSearchDistance = 16; + public int guardSearchDistance = 16; @Configure(category = Config.mobAI) - public int guardTickRate = 20; + public int guardTickRate = 20; + + @Configure(category = Config.mobAI) + public int nearBlockUpdateRate = 5; + @Configure(category = Config.mobAI) + public int huntUpdateRate = 5; // Used by pathfinder's movehelper for scaling speed in air and water. @Configure(category = Config.mobAI) @@ -319,7 +327,7 @@ private static SoundEvent getRegisteredSoundEvent(final String id) @Configure(category = Config.mobAI) public int hungerTickRate = 20; @Configure(category = Config.mobAI) - public double hordeRateFactor = 1; + public double hordeRateFactor = 0.1; @Configure(category = Config.mobAI) public double leapSpeedFactor = 1; @Configure(category = Config.mobAI) @@ -444,54 +452,63 @@ private static SoundEvent getRegisteredSoundEvent(final String id) // Gui/client settings @Configure(category = Config.client, type = Type.CLIENT) - public String guiRef = "top_left"; + public String guiRef = "top_left"; @Configure(category = Config.client, type = Type.CLIENT) - public String messageRef = "right_middle"; + public String messageRef = "right_middle"; @Configure(category = Config.client, type = Type.CLIENT) - public String targetRef = "top_right"; + public String targetRef = "top_right"; @Configure(category = Config.client, type = Type.CLIENT) - public String teleRef = "top_right"; + public String teleRef = "top_right"; + @Configure(category = Config.client, type = Type.CLIENT) - public List guiPos = Lists.newArrayList(new Integer[] { 0, 0 }); + public List guiPos = Lists.newArrayList(new Integer[] { 0, 0 }); @Configure(category = Config.client, type = Type.CLIENT) - public double guiSize = 1; + public List telePos = Lists.newArrayList(new Integer[] { 89, 17 }); @Configure(category = Config.client, type = Type.CLIENT) - public List telePos = Lists.newArrayList(new Integer[] { 89, 17 }); + public List targetPos = Lists.newArrayList(new Integer[] { 147, -42 }); @Configure(category = Config.client, type = Type.CLIENT) - public double teleSize = 1; + public List messagePos = Lists.newArrayList(new Integer[] { -150, -100 }); @Configure(category = Config.client, type = Type.CLIENT) - public List targetPos = Lists.newArrayList(new Integer[] { 147, -42 }); + public List messagePadding = Lists.newArrayList(new Integer[] { 0, 0 }); + @Configure(category = Config.client, type = Type.CLIENT) - public double targetSize = 1; + public double guiSize = 1; @Configure(category = Config.client, type = Type.CLIENT) - public List messagePos = Lists.newArrayList(new Integer[] { -150, -100 }); + public double teleSize = 1; @Configure(category = Config.client, type = Type.CLIENT) - public int messageWidth = 150;; + public double targetSize = 1; @Configure(category = Config.client, type = Type.CLIENT) - public List messagePadding = Lists.newArrayList(new Integer[] { 0, 0 }); + public double messageSize = 1; @Configure(category = Config.client, type = Type.CLIENT) - public double messageSize = 1; + public double captureVolume = 0.2; + @Configure(category = Config.moves, type = Type.CLIENT) + public double moveVolumeCry = 0.0625f; + @Configure(category = Config.moves, type = Type.CLIENT) + public double moveVolumeEffect = 1; + @Configure(category = Config.client, type = Type.CLIENT) - public boolean guiDown = true; + public boolean guiDown = true; @Configure(category = Config.client, type = Type.CLIENT) - public boolean guiAutoScale = false; + public boolean guiAutoScale = false; @Configure(category = Config.client, type = Type.CLIENT) - public boolean autoSelectMoves = false; + public boolean autoSelectMoves = false; @Configure(category = Config.client, type = Type.CLIENT) - public boolean autoRecallPokemobs = false; + public boolean autoRecallPokemobs = false; @Configure(category = Config.client, type = Type.CLIENT) - public int autoRecallDistance = 32; + public boolean riddenMobsTurnWithLook = true; @Configure(category = Config.client, type = Type.CLIENT) - public boolean riddenMobsTurnWithLook = true; + public boolean extraberries = false; @Configure(category = Config.client, type = Type.CLIENT) - public boolean extraberries = false; + public boolean battleLogInChat = false; @Configure(category = Config.client, type = Type.CLIENT) - public boolean battleLogInChat = false; + public boolean pokeCenterMusic = true; @Configure(category = Config.client, type = Type.CLIENT) - public boolean pokeCenterMusic = true; + public boolean preloadModels = false; @Configure(category = Config.client, type = Type.CLIENT) - public double captureVolume = 0.2; + public int messageWidth = 150;; + @Configure(category = Config.client, type = Type.CLIENT) + public int autoRecallDistance = 32; @Configure(category = Config.advanced) public List mystLocs = Lists.newArrayList(); @@ -666,9 +683,11 @@ public void onUpdated() if (this.spawnRate <= 0) this.spawnRate = 1; if (this.idleTickRate == 0) this.idleTickRate = 1; if (this.hungerTickRate == 0) this.hungerTickRate = 1; + if (this.nearBlockUpdateRate <= 0) this.nearBlockUpdateRate = 1; + if (this.huntUpdateRate <= 0) this.huntUpdateRate = 1; - AIIdle.IDLETIMER = this.idleTickRate; - AIHungry.TICKRATE = this.hungerTickRate; + IdleWalkTask.IDLETIMER = this.idleTickRate; + HungerTask.TICKRATE = this.hungerTickRate; // TODO Init secret bases. // DimensionSecretBase.init(baseSizeFunction); @@ -678,6 +697,8 @@ public void onUpdated() SpawnHandler.MAXNUM = this.mobSpawnNumber; if (this.breedingDelay < 600) this.breedingDelay = 1000; + AITools.initIDs(); + SpawnHandler.doSpawns = this.pokemonSpawn; SpawnHandler.lvlCap = this.shouldCap; SpawnHandler.capLevel = this.levelCap; diff --git a/src/main/java/pokecube/core/handlers/events/EventsHandler.java b/src/main/java/pokecube/core/handlers/events/EventsHandler.java index 3713516970..815cbf3ba8 100644 --- a/src/main/java/pokecube/core/handlers/events/EventsHandler.java +++ b/src/main/java/pokecube/core/handlers/events/EventsHandler.java @@ -29,7 +29,6 @@ import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; @@ -97,6 +96,7 @@ import pokecube.core.network.packets.PacketPokedex; import pokecube.core.utils.PokeType; import pokecube.core.utils.PokecubeSerializer; +import pokecube.core.utils.PokemobTracker; import pokecube.core.world.gen.jigsaw.JigsawPieces; import thut.api.boom.ExplosionCustom; import thut.api.entity.ShearableCaps; @@ -421,30 +421,6 @@ public static void explosionEvents(final ExplosionEvent.Detonate evt) } } - /** - * Gets all pokemobs owned by owner within the given distance. - * - * @param owner - * @param distance - * @return - */ - public static List getPokemobs(final LivingEntity owner, final double distance) - { - final List ret = new ArrayList<>(); - - final AxisAlignedBB box = new AxisAlignedBB(owner.posX, owner.posY, owner.posZ, owner.posX, owner.posY, - owner.posZ).grow(distance, distance, distance); - - final List pokemobs = owner.getEntityWorld().getEntitiesWithinAABB(LivingEntity.class, box); - for (final LivingEntity o : pokemobs) - { - final IPokemob mob = CapabilityPokemob.getPokemobFor(o); - if (mob != null) if (mob.getOwner() == owner) ret.add(mob); - } - - return ret; - } - @SubscribeEvent public static void denySpawns(final LivingSpawnEvent.CheckSpawn event) { @@ -520,17 +496,16 @@ public static void PokecubeWatchEvent(final StartTracking event) public static void recallAllPokemobs(final LivingEntity user) { if (!user.isServerWorld()) return; - final ServerWorld world = (ServerWorld) user.getEntityWorld(); - final List pokemobs = new ArrayList<>(world.getEntities(null, e -> EventsHandler.validRecall(user, e, - null, true))); + final List pokemobs = PokemobTracker.getMobs(user, e -> EventsHandler.validRecall(user, e, null, + false)); PCEventsHandler.recallAll(pokemobs, true); } public static void recallAllPokemobsExcluding(final ServerPlayerEntity player, final IPokemob excluded, final boolean includeStaying) { - final List pokemobs = new ArrayList<>(player.getServerWorld().getEntities(null, e -> EventsHandler - .validRecall(player, e, excluded, includeStaying))); + final List pokemobs = PokemobTracker.getMobs(player, e -> EventsHandler.validRecall(player, e, excluded, + includeStaying)); PCEventsHandler.recallAll(pokemobs, true); } diff --git a/src/main/java/pokecube/core/handlers/events/PCEventsHandler.java b/src/main/java/pokecube/core/handlers/events/PCEventsHandler.java index f6bef9500d..3d3abe2661 100644 --- a/src/main/java/pokecube/core/handlers/events/PCEventsHandler.java +++ b/src/main/java/pokecube/core/handlers/events/PCEventsHandler.java @@ -38,6 +38,7 @@ import pokecube.core.items.pokecubes.PokecubeManager; import pokecube.core.items.pokecubes.helper.SendOutManager; import pokecube.core.network.packets.PacketPC; +import pokecube.core.utils.PokemobTracker; import thut.core.common.ThutCore; public class PCEventsHandler @@ -54,8 +55,7 @@ public class PCEventsHandler public static List getOutMobs(final LivingEntity player, final boolean includeStay) { if (player == null) return Collections.emptyList(); - return ((ServerWorld) player.getEntityWorld()).getEntities(null, c -> EventsHandler.validRecall(player, c, null, - false, includeStay)); + return PokemobTracker.getMobs(player, c -> EventsHandler.validRecall(player, c, null, false, includeStay)); } /** @@ -173,6 +173,7 @@ public static void recallAll(final List mobs, final boolean cubesToPC) for (final Entity o : mobs) { final IPokemob pokemob = CapabilityPokemob.getPokemobFor(o); + if (!o.isAddedToWorld()) continue; if (pokemob != null) pokemob.onRecall(); else if (o instanceof EntityPokecube) { diff --git a/src/main/java/pokecube/core/handlers/events/PokemobEventsHandler.java b/src/main/java/pokecube/core/handlers/events/PokemobEventsHandler.java index 41c04192b1..3c5151cb7e 100644 --- a/src/main/java/pokecube/core/handlers/events/PokemobEventsHandler.java +++ b/src/main/java/pokecube/core/handlers/events/PokemobEventsHandler.java @@ -49,7 +49,6 @@ import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; import pokecube.core.ai.logic.Logic; -import pokecube.core.ai.tasks.combat.AIFindTarget; import pokecube.core.database.Pokedex; import pokecube.core.database.PokedexEntry; import pokecube.core.database.PokedexEntry.EvolutionData; @@ -179,13 +178,13 @@ else if (giveExp) final Entity targetOwner = attackedMob.getOwner(); attacker.displayMessageToOwner(new TranslationTextComponent("pokemob.action.faint.enemy", attackedMob .getDisplayName())); - if (targetOwner instanceof PlayerEntity && attacker.getOwner() != targetOwner) AIFindTarget.initiateCombat( + if (targetOwner instanceof PlayerEntity && attacker.getOwner() != targetOwner) BrainUtils.initiateCombat( pokemob, (LivingEntity) targetOwner); - else AIFindTarget.deagro(pokemob); + else BrainUtils.deagro(pokemob); if (attacker.getPokedexEntry().isFood(attackedMob.getPokedexEntry()) && attacker.getCombatState( CombatStates.HUNTING)) { - attacker.eat(BrainUtils.getHuntTarget(pokemob)); + attacker.eat(attackedMob.getEntity()); attacker.setCombatState(CombatStates.HUNTING, false); pokemob.getNavigator().clearPath(); } diff --git a/src/main/java/pokecube/core/handlers/events/SpawnHandler.java b/src/main/java/pokecube/core/handlers/events/SpawnHandler.java index e3cae2a218..3a8b877fd9 100644 --- a/src/main/java/pokecube/core/handlers/events/SpawnHandler.java +++ b/src/main/java/pokecube/core/handlers/events/SpawnHandler.java @@ -28,10 +28,14 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; import net.minecraft.world.Difficulty; import net.minecraft.world.IWorld; import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunk; import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.gen.Heightmap; import net.minecraft.world.gen.Heightmap.Type; import net.minecraft.world.server.ServerWorld; import net.minecraft.world.spawner.AbstractSpawner; @@ -142,13 +146,11 @@ public boolean equals(final Object obj) || input == BiomeType.NONE.getType(); }; - private static Vector3 vec1 = Vector3.getNewVector(); - private static Vector3 temp = Vector3.getNewVector(); - public static double MAX_DENSITY = 1; - public static int MAXNUM = 10; - public static boolean lvlCap = false; - public static boolean expFunction = false; - public static int capLevel = 50; + public static double MAX_DENSITY = 1; + public static int MAXNUM = 10; + public static boolean lvlCap = false; + public static boolean expFunction = false; + public static int capLevel = 50; public static boolean addForbiddenSpawningCoord(final BlockPos pos, final int dimensionId, final int distance) { @@ -239,7 +241,6 @@ public World getWorld() IPokemob pokemob = CapabilityPokemob.getPokemobFor(MobEntity); if (pokemob != null) { - final long time = System.nanoTime(); int maxXP = 10; int level = 1; @@ -266,9 +267,9 @@ else if (overrideLevel == -1) level = SpawnHandler.getSpawnLevel(world, Vector3. final double dt = (System.nanoTime() - time) / 10e3D; if (PokecubeMod.debug && dt > 100) { - SpawnHandler.temp.set(SpawnHandler.temp.set(posX, posY, posZ).getPos()); + final Vector3 v = Vector3.getNewVector().set(posX, posY, posZ); final String toLog = "location: %1$s took: %2$s\u00B5s to spawn Init for %3$s"; - PokecubeCore.LOGGER.info(String.format(toLog, SpawnHandler.temp, dt, pokemob.getDisplayName() + PokecubeCore.LOGGER.info(String.format(toLog, v.getPos(), dt, pokemob.getDisplayName() .getFormattedText())); } return pokemob.getEntity(); @@ -303,33 +304,50 @@ public static ForbidReason getNoSpawnReason(final IWorld world, final int x, fin return entry == null ? ForbidReason.NONE : entry.reason; } - public static Vector3 getRandomPointNear(final Entity player, final int range) + private static BlockPos getRandomHeight(final World worldIn, final Chunk chunk, final int yCenter, final int dy) { - if (player == null) return null; - final World world = player.getEntityWorld(); - final Vector3 v = SpawnHandler.vec1.set(player); - - final Random rand = new Random(); - // SElect random gaussians from here. - double x = rand.nextGaussian() * range; - double z = rand.nextGaussian() * range; - - // Cap x and z to distance. - if (Math.abs(x) > range) x = Math.signum(x) * range; - if (Math.abs(z) > range) z = Math.signum(z) * range; + final ChunkPos chunkpos = chunk.getPos(); + final int x = chunkpos.getXStart() + worldIn.rand.nextInt(16); + final int z = chunkpos.getZStart() + worldIn.rand.nextInt(16); + int y = yCenter - dy + worldIn.rand.nextInt(2 * dy + 1); + final int top = chunk.getTopBlockY(Heightmap.Type.WORLD_SURFACE, x, z) + 1; + if (y > top) y = top; + return new BlockPos(x, y, z); + } - // Don't select distances too far up/down from current. - final double y = Math.min(Math.max(-5, rand.nextGaussian() * 10), 10); - v.addTo(x, y, z); - v.set(v.getPos()).addTo(0.5, 0.5, 0.5); + public static Vector3 getRandomPointNear(final ServerWorld world, final Vector3 pos, final int range) + { + // Lets try a few times + int n = 10; + while (n-- > 0) + { + int dx = world.getRandom().nextInt(range); + int dz = world.getRandom().nextInt(range); + dx *= world.getRandom().nextBoolean() ? 1 : -1; + dz *= world.getRandom().nextBoolean() ? 1 : -1; + final int dy = 10; + final Vector3 vec = pos.add(dx, 0, dz); + final IChunk chunk = world.getChunk(vec.getPos()); + if (!(chunk instanceof Chunk)) continue; + final BlockPos blockpos = SpawnHandler.getRandomHeight(world, (Chunk) chunk, vec.intY(), dy); + final int j = blockpos.getX(); + final int k = blockpos.getY(); + final int l = blockpos.getZ(); + vec.set(j + 0.5, k, l + 0.5); + if (vec.distanceTo(pos) > range) continue; + final BlockState blockstate = world.getBlockState(blockpos); + if (blockstate.isNormalCube(world, blockpos)) continue; + return vec; + } + return null; - // Don't select unloaded areas. - if (!TerrainManager.isAreaLoaded(world, v, 8)) return null; + } - // Find surface - final Vector3 temp1 = SpawnHandler.getSpawnSurface(world, v, 10); - if (!(temp1.isClearOfBlocks(world) || temp1.offset(Direction.UP).isClearOfBlocks(world))) return null; - return temp1; + public static Vector3 getRandomPointNear(final Entity player, final int range) + { + if (player == null || !(player.getEntityWorld() instanceof ServerWorld)) return null; + return SpawnHandler.getRandomPointNear((ServerWorld) player.getEntityWorld(), Vector3.getNewVector().set( + player), range); } public static PokedexEntry getSpawnForLoc(final World world, final Vector3 pos) @@ -383,7 +401,7 @@ public static Vector3 getSpawnSurface(final World world, final Vector3 loc, fina { int tries = 0; BlockState state; - while (tries++ <= range) + if (loc.y > 0) while (tries++ <= range) { state = loc.getBlockState(world); if (state.getMaterial() == Material.WATER) return loc.copy(); @@ -496,7 +514,7 @@ public static void makeMeteor(final World world, final Vector3 location, final f private static int parse(final IWorld world, final Vector3 location) { - final Vector3 spawn = SpawnHandler.temp.set(world.getWorld().getSpawnPoint()); + final Vector3 spawn = Vector3.getNewVector().set(world.getWorld().getSpawnPoint()); final DimensionType type = world.getDimension().getType(); final JEP toUse = SpawnHandler.getParser(type); final Function function = SpawnHandler.getFunction(type); @@ -600,13 +618,6 @@ public static boolean removeForbiddenSpawningCoord(final int x, final int y, fin } public JEP parser = new JEP(); - Vector3 v = Vector3.getNewVector(); - - Vector3 v1 = Vector3.getNewVector(); - - Vector3 v2 = Vector3.getNewVector(); - - Vector3 v3 = Vector3.getNewVector(); public SpawnHandler() { @@ -626,14 +637,16 @@ public void doMeteor(final ServerWorld world) final Entity player = players.get(rand.nextInt(players.size())); final int dx = rand.nextInt(200) - 100; final int dz = rand.nextInt(200) - 100; - final Vector3 v = this.v.set(player).add(dx, 0, dz); + final Vector3 v = Vector3.getNewVector(); + final Vector3 v1 = Vector3.getNewVector(); + v.set(player).add(dx, 0, dz); final Vector4 loc = new Vector4(player); loc.x += dx; loc.z += dz; loc.y = world.getHeight(Type.WORLD_SURFACE, (int) loc.x, (int) loc.z); if (PokecubeSerializer.getInstance().canMeteorLand(loc, world)) { - final Vector3 direction = this.v1.set(rand.nextGaussian() / 2, -1, rand.nextGaussian() / 2); + final Vector3 direction = v1.set(rand.nextGaussian() / 2, -1, rand.nextGaussian() / 2); v.set(loc.x, loc.y, loc.z); final Vector3 location = Vector3.getNextSurfacePoint(world, v, direction, 255); if (location != null) @@ -647,12 +660,7 @@ public void doMeteor(final ServerWorld world) } } - public int doSpawnForLocation(final World world, final Vector3 v) - { - return this.doSpawnForLocation(world, v, true); - } - - public int doSpawnForLocation(final World world, final Vector3 v, final boolean checkPlayers) + public int doSpawnForLocation(final ServerWorld world, final Vector3 v) { int ret = 0; int num = 0; @@ -669,18 +677,18 @@ public int doSpawnForLocation(final World world, final Vector3 v, final boolean double dt = (System.nanoTime() - time) / 10e3D; if (PokecubeMod.debug && dt > 500) { - SpawnHandler.temp.set(v.getPos()); + final Vector3 debug = Vector3.getNewVector().set(v.getPos()); final String toLog = "location: %1$s took: %2$s\u00B5s to find a valid spawn and location"; - PokecubeCore.LOGGER.info(String.format(toLog, SpawnHandler.temp, dt)); + PokecubeCore.LOGGER.info(String.format(toLog, debug.getPos(), dt)); } time = System.nanoTime(); - ret += num = this.doSpawnForType(world, v, dbe, this.parser, t, checkPlayers); + ret += num = this.doSpawnForType(world, v, dbe, this.parser, t); dt = (System.nanoTime() - time) / 10e3D; if (PokecubeMod.debug && dt > 500) { - SpawnHandler.temp.set(v.getPos()); + final Vector3 debug = Vector3.getNewVector().set(v.getPos()); final String toLog = "location: %1$s took: %2$s\u00B5s to find a valid spawn for %3$s %4$s"; - PokecubeCore.LOGGER.info(String.format(toLog, SpawnHandler.temp, dt, num, dbe)); + PokecubeCore.LOGGER.info(String.format(toLog, debug.getPos(), dt, num, dbe)); } return ret; } @@ -690,54 +698,74 @@ public int doSpawnForLocation(final World world, final Vector3 v, final boolean * * @param player * @param world + * @param maxSpawnRadius * @return number of mobs spawned. */ - public void doSpawnForPlayer(final PlayerEntity player, final World world) + public void doSpawnForPlayer(final PlayerEntity player, final ServerWorld world, final int minRadius, + final int maxRadius) + { + final Vector3 v = Vector3.getNewVector(); + v.set(player); + this.doSpawnForPoint(v, world, minRadius, maxRadius); + return; + } + + /** + * Attempts to spawn mobs near the player. + * + * @param player + * @param world + * @param maxSpawnRadius + * @return number of mobs spawned. + */ + public void doSpawnForPoint(final Vector3 v, final ServerWorld world, final int minRadius, final int maxRadius) { long time = System.nanoTime(); - final int radius = PokecubeCore.getConfig().maxSpawnRadius; - this.v.set(player); - if (!TerrainManager.isAreaLoaded(world, this.v, radius)) return; - if (!Tools.isAnyPlayerInRange(radius, 10, world, this.v)) return; + if (!TerrainManager.isAreaLoaded(world, v, maxRadius)) return; final int height = world.getActualHeight(); - final AxisAlignedBB box = this.v.getAABB().grow(radius, Math.max(height, radius), radius); + // This lookup box uses configs rather than the passed in radius. + final int boxR = PokecubeCore.getConfig().maxSpawnRadius; + final AxisAlignedBB box = v.getAABB().grow(boxR, Math.max(height, boxR), boxR); int num = PokemobTracker.countPokemobs(world, box); if (num > SpawnHandler.MAX_DENSITY * SpawnHandler.MAXNUM) return; - final Vector3 v = SpawnHandler.getRandomPointNear(player, PokecubeCore.getConfig().maxSpawnRadius); - double dt = (System.nanoTime() - time) / 1000d; - if (PokecubeMod.debug && dt > 100) PokecubeCore.LOGGER.info("Location Find took " + dt); - if (v == null) return; + final Vector3 v1 = SpawnHandler.getRandomPointNear(world, v, maxRadius); + double dt = (System.nanoTime() - time) / 1e3D; + if (PokecubeMod.debug && dt > 100) PokecubeCore.LOGGER.debug("Location Find took " + dt); + if (v1 == null) return; + if (v.distanceTo(v1) < minRadius) return; time = System.nanoTime(); - num = this.doSpawnForLocation(world, v); - dt = (System.nanoTime() - time) / 10e3D; - if (PokecubeMod.debug && dt > 100) PokecubeCore.LOGGER.info(dt + "\u00B5" + "s for player " + player - .getDisplayName().getUnformattedComponentText() + " at " + v + ", spawned " + num); + num = this.doSpawnForLocation(world, v1); + dt = (System.nanoTime() - time) / 1e3D; + if (PokecubeMod.debug && dt > 100) PokecubeCore.LOGGER.debug(dt + "\u00B5" + "s for " + v + ", spawned " + + num); return; } - private int doSpawnForType(final World world, final Vector3 loc, final PokedexEntry dbe, final JEP parser, - final TerrainSegment t, final boolean checkPlayers) + private int doSpawnForType(final ServerWorld world, final Vector3 loc, final PokedexEntry dbe, final JEP parser, + final TerrainSegment t) { final SpawnData entry = dbe.getSpawnData(); + final Vector3 v = Vector3.getNewVector(); + final Vector3 v2 = Vector3.getNewVector(); + final Vector3 v3 = Vector3.getNewVector(); int totalSpawnCount = 0; - final Vector3 offset = this.v1.clear(); - final Vector3 point = this.v2.clear(); + final Vector3 point = v2.clear(); SpawnHandler.refreshTerrain(loc, world, false); final SpawnBiomeMatcher matcher = entry.getMatcher(world, loc); if (matcher == null) return 0; - final byte distGroupZone = 6; + final byte distGroupZone = 4; final Random rand = new Random(); final int n = Math.max(entry.getMax(matcher) - entry.getMin(matcher), 1); final int spawnNumber = entry.getMin(matcher) + rand.nextInt(n); for (int i = 0; i < spawnNumber; i++) { - offset.set(rand.nextInt(distGroupZone) - rand.nextInt(distGroupZone), rand.nextInt(1) - rand.nextInt(1), - rand.nextInt(distGroupZone) - rand.nextInt(distGroupZone)); - this.v.set(loc); - point.set(this.v.addTo(offset)); - if (!SpawnHandler.isPointValidForSpawn(world, point, dbe)) continue; + final Vector3 dr = SpawnHandler.getRandomPointNear(world, loc, distGroupZone); + if (dr != null) point.set(dr); + else continue; + + if (!SpawnHandler.checkNoSpawnerInArea(world, point.intX(), point.intY(), point.intZ())) continue; final float x = (float) point.x; final float y = (float) point.y; @@ -747,11 +775,6 @@ private int doSpawnForType(final World world, final Vector3 loc, final PokedexEn final float var29 = y - world.getSpawnPoint().getY(); final float var30 = z - world.getSpawnPoint().getZ(); final float distFromSpawnPoint = var28 * var28 + var29 * var29 + var30 * var30; - - if (!SpawnHandler.checkNoSpawnerInArea(world, point.intX(), point.intY(), point.intZ())) continue; - final float dist = PokecubeCore.getConfig().minSpawnRadius; - final boolean player = checkPlayers && Tools.isAnyPlayerInRange(dist, dist, world, point); - if (player) continue; if (distFromSpawnPoint >= 256.0F) { MobEntity entity = null; @@ -767,22 +790,22 @@ private int doSpawnForType(final World world, final Vector3 loc, final PokedexEn entity.setLocationAndAngles(x, y, z, world.rand.nextFloat() * 360.0F, 0.0F); if (entity.canSpawn(world, SpawnReason.NATURAL)) { - if ((entity = SpawnHandler.creatureSpecificInit(entity, world, x, y, z, this.v3.set(entity), + if ((entity = SpawnHandler.creatureSpecificInit(entity, world, x, y, z, v3.set(entity), entry.getLevel(matcher), entry.getVariance(matcher))) != null) { final IPokemob pokemob = CapabilityPokemob.getPokemobFor(entity); if (!event.getSpawnArgs().isEmpty()) { final String[] args = event.getSpawnArgs().split(" "); - Pokemake.setToArgs(args, pokemob, 0, this.v, false); + Pokemake.setToArgs(args, pokemob, 0, v, false); } else if (matcher.spawnRule.values.containsKey(SpawnBiomeMatcher.SPAWNCOMMAND)) { final String[] args = matcher.spawnRule.values.get(SpawnBiomeMatcher.SPAWNCOMMAND) .split(" "); - Pokemake.setToArgs(args, pokemob, 0, this.v, false); + Pokemake.setToArgs(args, pokemob, 0, v, false); } - final SpawnEvent.Post evt = new SpawnEvent.Post(dbe, this.v3, world, pokemob); + final SpawnEvent.Post evt = new SpawnEvent.Post(dbe, v3, world, pokemob); PokecubeCore.POKEMOB_BUS.post(evt); world.addEntity(entity); totalSpawnCount++; @@ -814,7 +837,8 @@ public void spawn(final ServerWorld world) for (final ServerPlayerEntity player : players) { if (player.dimension != world.getDimension().getType()) continue; - this.doSpawnForPlayer(player, world); + this.doSpawnForPlayer(player, world, PokecubeCore.getConfig().minSpawnRadius, PokecubeCore + .getConfig().maxSpawnRadius); } } diff --git a/src/main/java/pokecube/core/handlers/playerdata/PlayerPokemobCache.java b/src/main/java/pokecube/core/handlers/playerdata/PlayerPokemobCache.java index 1db33bc4eb..441711d426 100644 --- a/src/main/java/pokecube/core/handlers/playerdata/PlayerPokemobCache.java +++ b/src/main/java/pokecube/core/handlers/playerdata/PlayerPokemobCache.java @@ -23,6 +23,7 @@ public class PlayerPokemobCache extends PlayerData public static void UpdateCache(final IPokemob mob) { if (!mob.isPlayerOwned() || mob.getOwnerId() == null) return; + if (!mob.getEntity().isServerWorld()) return; final ItemStack stack = PokecubeManager.pokemobToItem(mob); final MinecraftServer server = LogicalSidedProvider.INSTANCE.get(LogicalSide.SERVER); // Schedule this to run at some point, as it takes a while. diff --git a/src/main/java/pokecube/core/interfaces/IPokecube.java b/src/main/java/pokecube/core/interfaces/IPokecube.java index c405edf735..fdcbc21fd7 100644 --- a/src/main/java/pokecube/core/interfaces/IPokecube.java +++ b/src/main/java/pokecube/core/interfaces/IPokecube.java @@ -15,6 +15,7 @@ import pokecube.core.events.pokemob.CaptureEvent.Post; import pokecube.core.events.pokemob.CaptureEvent.Pre; import pokecube.core.interfaces.capabilities.CapabilityPokemob; +import pokecube.core.items.pokecubes.EntityPokecubeBase; import thut.api.maths.Vector3; public interface IPokecube @@ -27,12 +28,12 @@ public abstract static class DefaultPokecubeBehavior extends PokecubeBehavior { @Override - public void onPostCapture(Post evt) + public void onPostCapture(final Post evt) { } @Override - public void onPreCapture(Pre evt) + public void onPreCapture(final Pre evt) { } } @@ -41,13 +42,13 @@ public static class NormalPokecubeBehavoir extends DefaultPokecubeBehavior { final double rate; - public NormalPokecubeBehavoir(double rate) + public NormalPokecubeBehavoir(final double rate) { this.rate = rate; } @Override - public double getCaptureModifier(IPokemob mob) + public double getCaptureModifier(final IPokemob mob) { return this.rate; } @@ -66,7 +67,7 @@ public static abstract class PokecubeBehavior extends ForgeRegistryEntry 0.5) if (this.here == null) this.here = Vector3.getNewVector(); this.here.set(this.getEntity()).addTo(0, this.getEntity().getEyeHeight(), 0); MovesUtils.useMove(move, this.getEntity(), target, this.here, targetLocation); + // clear this if we use a move. + this.setCombatState(CombatStates.NOITEMUSE, false); this.here.set(this.getEntity()); } diff --git a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobOwned.java b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobOwned.java index 772bad103c..b2c176d89d 100644 --- a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobOwned.java +++ b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobOwned.java @@ -25,7 +25,6 @@ import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; import pokecube.core.ai.logic.LogicMountedControl; -import pokecube.core.ai.tasks.combat.AIFindTarget; import pokecube.core.client.gui.GuiInfoMessages; import pokecube.core.database.PokedexEntryLoader.SpawnRule; import pokecube.core.database.abilities.AbilityManager; @@ -346,7 +345,7 @@ else if (this.getOwnerId() != null) final IPokemob targetMob = CapabilityPokemob.getPokemobFor(targ); if (targetMob != null) { - AIFindTarget.initiateCombat(targetMob.getEntity(), this.getOwner()); + BrainUtils.initiateCombat(targetMob.getEntity(), this.getOwner()); if (PokecubeMod.debug) PokecubeCore.LOGGER.info("Swapping agro to cowardly owner!"); } else targ.setRevengeTarget(this.getOwner()); 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 68cdf7a42c..4b3c471053 100644 --- a/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobSexed.java +++ b/src/main/java/pokecube/core/interfaces/capabilities/impl/PokemobSexed.java @@ -12,7 +12,8 @@ import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.LogicalSidedProvider; import pokecube.core.PokecubeCore; -import pokecube.core.ai.tasks.combat.AIFindTarget; +import pokecube.core.ai.brain.BrainUtils; +import pokecube.core.ai.tasks.idle.HungerTask; import pokecube.core.database.PokedexEntry; import pokecube.core.events.EggEvent; import pokecube.core.handlers.playerdata.advancements.triggers.Triggers; @@ -37,15 +38,20 @@ 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; + if (!this.canBreed()) return false; // 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; + // Don't let tame and wild breed, prevents exploits with dittos + if (otherMob.getOwnerId() != null && this.getOwnerId() == null) return false; + if (this.getOwnerId() != null && otherMob.getOwnerId() == null) return false; + + if (!otherMob.canBreed()) return false; + + if (PokecubeCore.POKEMOB_BUS.post(new EggEvent.CanBreed(this.getEntity(), otherAnimal))) return false; PokedexEntry thisEntry = this.getPokedexEntry(); PokedexEntry thatEntry = otherMob.getPokedexEntry(); @@ -56,7 +62,7 @@ public boolean canMate(final AgeableEntity otherAnimal) // Check if pokedex entries state they can breed, and then if so, // ensure sexe is different. final boolean neutral = this.getSexe() == IPokemob.NOSEXE || otherMob.getSexe() == IPokemob.NOSEXE; - if (thisEntry.areRelated(thatEntry) || thatEntry.areRelated(thisEntry) && (neutral || otherMob + if ((thisEntry.areRelated(thatEntry) || thatEntry.areRelated(thisEntry)) && (neutral || otherMob .getSexe() != this.getSexe())) return true; // Otherwise check for transform. @@ -151,8 +157,8 @@ protected void mate(final IBreedingMob male) mate.setHungerTime(mate.getHungerTime() + hungerValue); this.setHungerTime(this.getHungerTime() + hungerValue); mate.resetLoveStatus(); - AIFindTarget.deagro(this.getEntity()); - AIFindTarget.deagro(mate.getEntity()); + BrainUtils.deagro(this.getEntity()); + BrainUtils.deagro(mate.getEntity()); this.lay(mate); this.resetLoveStatus(); } @@ -199,6 +205,12 @@ public ServerPlayerEntity getCause() @Override public boolean canBreed() { + if (!this.isRoutineEnabled(AIRoutine.MATE)) return false; + PokedexEntry thisEntry = this.getPokedexEntry(); + if (thisEntry.isMega) thisEntry = this.getMegaBase(); + if (!thisEntry.breeds) return false; + final float hunger = HungerTask.calculateHunger(this); + if (HungerTask.hitThreshold(hunger, HungerTask.MATERESET)) return false; return this.loveTimer >= 0; } diff --git a/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/AttackEntityHandler.java b/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/AttackEntityHandler.java index ea7de01a48..5263bb9e8c 100644 --- a/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/AttackEntityHandler.java +++ b/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/AttackEntityHandler.java @@ -8,7 +8,7 @@ import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import pokecube.core.PokecubeCore; -import pokecube.core.ai.tasks.combat.AIFindTarget; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.events.pokemob.combat.CommandAttackEvent; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.Move_Base; @@ -62,7 +62,7 @@ public void handleCommand(final IPokemob pokemob) .getDisplayName(), target.getDisplayName(), new TranslationTextComponent(MovesUtils .getUnlocalizedMove(move.getName()))); if (this.fromOwner()) pokemob.displayMessageToOwner(mess); - AIFindTarget.initiateCombat(pokemob.getEntity(), (LivingEntity) target); + BrainUtils.initiateCombat(pokemob.getEntity(), (LivingEntity) target); } } } 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 9296876581..6b18e4cdef 100644 --- a/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/AttackLocationHandler.java +++ b/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/AttackLocationHandler.java @@ -5,7 +5,7 @@ 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.ai.tasks.idle.HungerTask; import pokecube.core.events.pokemob.combat.CommandAttackEvent; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.Move_Base; @@ -41,10 +41,10 @@ public void handleCommand(final IPokemob pokemob) new TranslationTextComponent(MovesUtils.getUnlocalizedMove(move.getName()))); if (this.fromOwner()) pokemob.displayMessageToOwner(mess); - final float value = AIHungry.calculateHunger(pokemob); + final float value = HungerTask.calculateHunger(pokemob); // If too hungry, send message about that. - if (AIHungry.hitThreshold(value, AIHungry.HUNTTHRESHOLD)) + if (HungerTask.hitThreshold(value, HungerTask.HUNTTHRESHOLD)) { mess = new TranslationTextComponent("pokemob.action.hungry", pokemob.getDisplayName()); if (this.fromOwner()) pokemob.displayMessageToOwner(mess); diff --git a/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/MoveToHandler.java b/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/MoveToHandler.java index ffd01ba94f..61ff71e589 100644 --- a/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/MoveToHandler.java +++ b/src/main/java/pokecube/core/interfaces/pokemob/commandhandlers/MoveToHandler.java @@ -1,7 +1,8 @@ package pokecube.core.interfaces.pokemob.commandhandlers; import io.netty.buffer.ByteBuf; -import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.brain.memory.WalkTarget; +import pokecube.core.ai.brain.MemoryModules; import pokecube.core.interfaces.IPokemob; import pokecube.core.network.pokemobs.PacketCommand.DefaultHandler; import thut.api.maths.Vector3; @@ -24,11 +25,9 @@ public MoveToHandler(final Vector3 location, final Float speed) @Override public void handleCommand(final IPokemob pokemob) throws Exception { - this.speed = (float) Math.min(this.speed, - pokemob.getEntity().getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getValue()); - pokemob.getEntity().getNavigator().setPath( - pokemob.getEntity().getNavigator().getPathToPos(this.location.x, this.location.y, this.location.z, 0), - this.speed); + this.speed = (float) Math.min(this.speed, pokemob.getMovementSpeed()); + pokemob.getEntity().getBrain().setMemory(MemoryModules.WALK_TARGET, new WalkTarget(this.location.toVec3d(), + this.speed, 0)); } @Override diff --git a/src/main/java/pokecube/core/items/ItemPokedex.java b/src/main/java/pokecube/core/items/ItemPokedex.java index 473c115033..899a026859 100644 --- a/src/main/java/pokecube/core/items/ItemPokedex.java +++ b/src/main/java/pokecube/core/items/ItemPokedex.java @@ -103,7 +103,7 @@ public ActionResultType onItemUse(final ItemUseContext context) SpawnHandler.refreshTerrain(Vector3.getNewVector().set(playerIn), playerIn.getEntityWorld(), true); if (PokecubeMod.debug) { - final Set infos = StructureManager.getFor(pos); + final Set infos = StructureManager.getFor(worldIn.getDimension().getType(), pos); for (final StructureInfo i : infos) playerIn.sendMessage(new StringTextComponent(i.name)); } diff --git a/src/main/java/pokecube/core/items/pokecubes/DispenserBehaviorPokecube.java b/src/main/java/pokecube/core/items/pokecubes/DispenserBehaviorPokecube.java index 8ed3520dfd..04110b8670 100644 --- a/src/main/java/pokecube/core/items/pokecubes/DispenserBehaviorPokecube.java +++ b/src/main/java/pokecube/core/items/pokecubes/DispenserBehaviorPokecube.java @@ -61,7 +61,7 @@ else if (stack.getItem() instanceof IPokecube) { final IPokecube cube = (IPokecube) stack.getItem(); final Vector3 direction = Vector3.getNewVector().set(dir); - if (cube.throwPokecube(source.getWorld(), player, stack, direction, 0.25f)) stack.split(1); + if (cube.throwPokecube(source.getWorld(), player, stack, direction, 0.25f) != null) stack.split(1); } return stack; } diff --git a/src/main/java/pokecube/core/items/pokecubes/EntityPokecube.java b/src/main/java/pokecube/core/items/pokecubes/EntityPokecube.java index 85056bdc7b..950f774a44 100644 --- a/src/main/java/pokecube/core/items/pokecubes/EntityPokecube.java +++ b/src/main/java/pokecube/core/items/pokecubes/EntityPokecube.java @@ -96,8 +96,9 @@ void writeToNBT(final CompoundNBT nbt) .immuneToFire().size(0.25f, 0.25f).build("pokecube"); } - public long reset = 0; - public long resetTime = 0; + public long reset = 0; + public long resetTime = 0; + public ArrayList players = Lists.newArrayList(); public ArrayList loot = Lists.newArrayList(); public ArrayList lootStacks = Lists.newArrayList(); diff --git a/src/main/java/pokecube/core/items/pokecubes/EntityPokecubeBase.java b/src/main/java/pokecube/core/items/pokecubes/EntityPokecubeBase.java index ff3720e31a..9d3c1c2304 100644 --- a/src/main/java/pokecube/core/items/pokecubes/EntityPokecubeBase.java +++ b/src/main/java/pokecube/core/items/pokecubes/EntityPokecubeBase.java @@ -42,12 +42,13 @@ import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; import pokecube.core.PokecubeCore; -import pokecube.core.ai.tasks.combat.AIFindTarget; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.capabilities.CapabilityPokemob; import pokecube.core.interfaces.pokemob.ai.CombatStates; import pokecube.core.items.pokecubes.helper.CaptureManager; import pokecube.core.items.pokecubes.helper.SendOutManager; +import pokecube.core.utils.PokemobTracker; import pokecube.core.utils.TagNames; import thut.api.maths.Vector3; import thut.core.common.network.EntityUpdate; @@ -124,6 +125,8 @@ public static void setNoCaptureBasedOnConfigs(final IPokemob pokemob) NonNullList stuff = NonNullList.create(); + public IPokemob containedMob; + public EntityPokecubeBase(final EntityType type, final World worldIn) { super(type, worldIn); @@ -202,7 +205,7 @@ protected void onImpact(final RayTraceResult result) if (PokecubeManager.isFilled(this.getItem())) { final LivingEntity sent = SendOutManager.sendOut(this, true); - if (sent instanceof MobEntity && hit.getEntity() instanceof LivingEntity) AIFindTarget.initiateCombat( + if (sent instanceof MobEntity && hit.getEntity() instanceof LivingEntity) BrainUtils.initiateCombat( (MobEntity) sent, (LivingEntity) hit.getEntity()); } @@ -215,6 +218,20 @@ protected void onImpact(final RayTraceResult result) } } + @Override + public void onAddedToWorld() + { + if (!this.isAddedToWorld()) PokemobTracker.addPokecube(this); + super.onAddedToWorld(); + } + + @Override + public void onRemovedFromWorld() + { + PokemobTracker.removePokecube(this); + super.onRemovedFromWorld(); + } + @Override public boolean canBeCollidedWith() { @@ -448,13 +465,13 @@ protected void registerData() /** Sets the ItemStack for this entity */ public void setItem(final ItemStack stack) { + if (this.isAddedToWorld()) PokemobTracker.removePokecube(this); this.getDataManager().set(EntityPokecubeBase.ITEM, stack); - } - - // For compatiblity - public void setItemEntityStack(final ItemStack stack) - { - this.setItem(stack); + if (this.isAddedToWorld()) + { + this.containedMob = PokecubeManager.itemToPokemob(stack, PokecubeCore.proxy.getWorld()); + PokemobTracker.addPokecube(this); + } } @Override @@ -552,12 +569,6 @@ public ItemStack getItem() return itemstack.isEmpty() ? new ItemStack(Blocks.STONE) : itemstack; } - // For compatiblity. - public ItemStack getItemEntity() - { - return this.getItem(); - } - @Override public ItemStack getItemStackFromSlot(final EquipmentSlotType slotIn) { diff --git a/src/main/java/pokecube/core/items/pokecubes/Pokecube.java b/src/main/java/pokecube/core/items/pokecubes/Pokecube.java index 5109667ba0..fa0b5f5b37 100644 --- a/src/main/java/pokecube/core/items/pokecubes/Pokecube.java +++ b/src/main/java/pokecube/core/items/pokecubes/Pokecube.java @@ -312,12 +312,12 @@ public void onPlayerStoppedUsing(final ItemStack stack, final World worldIn, fin boolean used = false; final boolean filledOrSneak = filled || player.isCrouching() || dt > 5; if (target != null && EntityPokecubeBase.SEEKING) used = this.throwPokecubeAt(worldIn, player, stack, - targetLocation, target); + targetLocation, target) != null; else if (filledOrSneak || !EntityPokecubeBase.SEEKING) { float power = (this.getUseDuration(stack) - timeLeft) / (float) 100; power = Math.min(1, power); - used = this.throwPokecube(worldIn, player, stack, direction, power); + used = this.throwPokecube(worldIn, player, stack, direction, power) != null; } else { @@ -360,12 +360,12 @@ public boolean showDurabilityBar(final ItemStack stack) } @Override - public boolean throwPokecube(final World world, final LivingEntity thrower, final ItemStack cube, + public EntityPokecubeBase throwPokecube(final World world, final LivingEntity thrower, final ItemStack cube, final Vector3 direction, final float power) { EntityPokecube entity = null; final ResourceLocation id = PokecubeItems.getCubeId(cube); - if (id == null || !IPokecube.BEHAVIORS.containsKey(id)) return false; + if (id == null || !IPokecube.BEHAVIORS.containsKey(id)) return null; final ItemStack stack = cube.copy(); final boolean hasMob = PokecubeManager.isFilled(stack); final Config config = PokecubeCore.getConfig(); @@ -377,9 +377,9 @@ public boolean throwPokecube(final World world, final LivingEntity thrower, fina final IPermissionHandler handler = PermissionAPI.getPermissionHandler(); final PlayerContext context = new PlayerContext(player); if (config.permsSendOut && !handler.hasPermission(player.getGameProfile(), Permissions.SENDOUTPOKEMOB, - context)) return false; + context)) return null; if (config.permsSendOutSpecific && !handler.hasPermission(player.getGameProfile(), - Permissions.SENDOUTSPECIFIC.get(entry), context)) return false; + Permissions.SENDOUTSPECIFIC.get(entry), context)) return null; } stack.setCount(1); entity = new EntityPokecube(EntityPokecube.TYPE, world); @@ -404,16 +404,16 @@ public boolean throwPokecube(final World world, final LivingEntity thrower, fina world.addEntity(entity); if (hasMob && thrower instanceof PlayerEntity) PlayerPokemobCache.UpdateCache(stack, false, false); } - return true; + return entity; } @Override - public boolean throwPokecubeAt(final World world, final LivingEntity thrower, final ItemStack cube, + public EntityPokecubeBase throwPokecubeAt(final World world, final LivingEntity thrower, final ItemStack cube, Vector3 targetLocation, Entity target) { EntityPokecube entity = null; final ResourceLocation id = PokecubeItems.getCubeId(cube); - if (id == null || !IPokecube.BEHAVIORS.containsKey(id)) return false; + if (id == null || !IPokecube.BEHAVIORS.containsKey(id)) return null; final ItemStack stack = cube.copy(); stack.setCount(1); entity = new EntityPokecube(EntityPokecube.TYPE, world); @@ -454,7 +454,7 @@ public boolean throwPokecubeAt(final World world, final LivingEntity thrower, fi stack, false, false); } } - else if (!rightclick) return false; - return true; + else if (!rightclick) return null; + return entity; } } diff --git a/src/main/java/pokecube/core/items/pokecubes/helper/CaptureManager.java b/src/main/java/pokecube/core/items/pokecubes/helper/CaptureManager.java index e769076e54..8e952b5ddf 100644 --- a/src/main/java/pokecube/core/items/pokecubes/helper/CaptureManager.java +++ b/src/main/java/pokecube/core/items/pokecubes/helper/CaptureManager.java @@ -16,7 +16,7 @@ import net.minecraftforge.eventbus.api.Event.Result; import pokecube.core.PokecubeCore; import pokecube.core.PokecubeItems; -import pokecube.core.ai.tasks.combat.AIFindTarget; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.database.abilities.AbilityManager; import pokecube.core.events.pokemob.CaptureEvent; import pokecube.core.events.pokemob.CaptureEvent.Pre; @@ -161,7 +161,7 @@ public static void captureFailed(final EntityPokecubeBase cube) ((PlayerEntity) cube.shootingEntity).sendMessage(mess); } } - if (mob instanceof MobEntity && cube.shootingEntity != null) AIFindTarget.initiateCombat((MobEntity) mob, + if (mob instanceof MobEntity && cube.shootingEntity != null) BrainUtils.initiateCombat((MobEntity) mob, cube.shootingEntity); } diff --git a/src/main/java/pokecube/core/items/pokemobeggs/EntityPokemobEgg.java b/src/main/java/pokecube/core/items/pokemobeggs/EntityPokemobEgg.java index 1c063de04b..ab595d8e65 100644 --- a/src/main/java/pokecube/core/items/pokemobeggs/EntityPokemobEgg.java +++ b/src/main/java/pokecube/core/items/pokemobeggs/EntityPokemobEgg.java @@ -21,7 +21,6 @@ import net.minecraftforge.common.MinecraftForge; import pokecube.core.PokecubeCore; import pokecube.core.ai.brain.BrainUtils; -import pokecube.core.ai.tasks.combat.AIFindTarget; import pokecube.core.database.PokedexEntry; import pokecube.core.events.EggEvent; import pokecube.core.interfaces.IPokemob; @@ -73,7 +72,7 @@ public boolean attackEntityFrom(final DamageSource source, final float damage) final ItemStack itemstack = this.getHeldItemMainhand(); final int i = itemstack.getCount(); final PlayerEntity player = (PlayerEntity) e; - if (this.mother != null && this.mother.getOwner() != player) AIFindTarget.initiateCombat(this.mother + if (this.mother != null && this.mother.getOwner() != player) BrainUtils.initiateCombat(this.mother .getEntity(), player); if (i <= 0 || player.inventory.addItemStackToInventory(itemstack)) { diff --git a/src/main/java/pokecube/core/moves/MovesUtils.java b/src/main/java/pokecube/core/moves/MovesUtils.java index 178dea4a56..a105409f6a 100644 --- a/src/main/java/pokecube/core/moves/MovesUtils.java +++ b/src/main/java/pokecube/core/moves/MovesUtils.java @@ -18,6 +18,7 @@ import net.minecraft.util.SoundEvents; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import pokecube.core.PokecubeCore; @@ -74,7 +75,8 @@ 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(); + final ITextComponent targName = target != null ? target.getDisplayName() + : attacker != null ? attacker.getDisplayName() : new StringTextComponent("ERR PLS REPORT"); if (attacker != null) attacker.displayMessageToOwner(new TranslationTextComponent(key, targName)); key = baseKey + ".target"; if (target != attacker.getEntity() && target != null) @@ -349,8 +351,8 @@ public static float getAttackStrength(final IPokemob attacker, final IPokemob at } // If this is a fight over a mate, the strength is reduced. - if (attacker.getCombatState(CombatStates.MATEFIGHT) && attacked.getCombatState(CombatStates.MATEFIGHT)) - statusMultiplier *= 0.25; + if (attacker.getCombatState(CombatStates.MATEFIGHT) || attacked.getCombatState(CombatStates.MATEFIGHT)) + statusMultiplier *= 0.125; ATT = (int) (statusMultiplier * ATT); diff --git a/src/main/java/pokecube/core/moves/PokemobTerrainEffects.java b/src/main/java/pokecube/core/moves/PokemobTerrainEffects.java index 3c778c18f9..b40bef8fd2 100644 --- a/src/main/java/pokecube/core/moves/PokemobTerrainEffects.java +++ b/src/main/java/pokecube/core/moves/PokemobTerrainEffects.java @@ -54,10 +54,15 @@ public class PokemobTerrainEffects implements ITerrainEffect public static final int CLEAR_ENTRYEFFECTS = 16; - public static final TerrainDamageSource HAILDAMAGE = new TerrainDamageSource("terrain.hail", - TerrainType.TERRAIN); - public static final TerrainDamageSource SANDSTORMDAMAGE = new TerrainDamageSource("terrain.sandstorm", - TerrainType.TERRAIN); + public static final TerrainDamageSource createHailSource(final IPokemob mobIn) + { + return new TerrainDamageSource("terrain.hail", TerrainType.TERRAIN, mobIn); + } + + public static final TerrainDamageSource createSandstormSource(final IPokemob mobIn) + { + return new TerrainDamageSource("terrain.sandstorm", TerrainType.TERRAIN, mobIn); + } public final long[] effects = new long[16]; @@ -67,6 +72,8 @@ public class PokemobTerrainEffects implements ITerrainEffect Set pokemon = new HashSet<>(); + IPokemob[] users = new IPokemob[16]; + public PokemobTerrainEffects() { } @@ -90,14 +97,16 @@ public void doEffect(final LivingEntity entity) { final float thisMaxHP = entity.getMaxHealth(); final int damage = Math.max(1, (int) (0.0625 * thisMaxHP)); - entity.attackEntityFrom(PokemobTerrainEffects.HAILDAMAGE, damage); + entity.attackEntityFrom(PokemobTerrainEffects.createHailSource( + this.users[PokemobTerrainEffects.EFFECT_WEATHER_HAIL]), damage); } if (this.effects[PokemobTerrainEffects.EFFECT_WEATHER_SAND] > 0 && !(mob.isType(PokeType.getType("rock")) || mob.isType(PokeType.getType("steel")) || mob.isType(PokeType.getType("ground")))) { final float thisMaxHP = entity.getMaxHealth(); final int damage = Math.max(1, (int) (0.0625 * thisMaxHP)); - entity.attackEntityFrom(PokemobTerrainEffects.SANDSTORMDAMAGE, damage); + entity.attackEntityFrom(PokemobTerrainEffects.createSandstormSource( + this.users[PokemobTerrainEffects.EFFECT_WEATHER_SAND]), damage); } if (this.effects[PokemobTerrainEffects.EFFECT_TERRAIN_ELECTRIC] > 0 && mob.isOnGround()) if (mob .getStatus() == IMoveConstants.STATUS_SLP) mob.healStatus(); @@ -117,13 +126,15 @@ else if (PokecubeCore.getConfig().pokemobsDamagePlayers) { final float thisMaxHP = entity.getMaxHealth(); final int damage = Math.max(1, (int) (0.0625 * thisMaxHP)); - entity.attackEntityFrom(PokemobTerrainEffects.HAILDAMAGE, damage); + entity.attackEntityFrom(PokemobTerrainEffects.createHailSource( + this.users[PokemobTerrainEffects.EFFECT_WEATHER_HAIL]), damage); } if (this.effects[PokemobTerrainEffects.EFFECT_WEATHER_SAND] > 0) { final float thisMaxHP = entity.getMaxHealth(); final int damage = Math.max(1, (int) (0.0625 * thisMaxHP)); - entity.attackEntityFrom(PokemobTerrainEffects.SANDSTORMDAMAGE, damage); + entity.attackEntityFrom(PokemobTerrainEffects.createSandstormSource( + this.users[PokemobTerrainEffects.EFFECT_WEATHER_SAND]), damage); } if (this.effects[PokemobTerrainEffects.EFFECT_TERRAIN_GRASS] > 0 && entity.onGround) { @@ -183,6 +194,7 @@ private void dropDurations(final Entity e) if (diff < 0) { this.effects[i] = 0; + this.users[i] = null; send = true; } } @@ -324,6 +336,7 @@ public void renderTerrainEffects(final RenderWorldLastEvent event, final Vector3 */ public void setEffect(final int effect, final long duration) { + this.users[effect] = user; if (effect == PokemobTerrainEffects.EFFECT_WEATHER_HAIL) { this.effects[PokemobTerrainEffects.EFFECT_WEATHER_RAIN] = 0; diff --git a/src/main/java/pokecube/core/moves/damage/TerrainDamageSource.java b/src/main/java/pokecube/core/moves/damage/TerrainDamageSource.java index c2a93a66d0..90e3afe62d 100644 --- a/src/main/java/pokecube/core/moves/damage/TerrainDamageSource.java +++ b/src/main/java/pokecube/core/moves/damage/TerrainDamageSource.java @@ -1,9 +1,11 @@ package pokecube.core.moves.damage; +import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TranslationTextComponent; +import pokecube.core.interfaces.IPokemob; public class TerrainDamageSource extends DamageSource implements IPokedamage { @@ -14,10 +16,13 @@ public static enum TerrainType public final TerrainType type; - public TerrainDamageSource(final String damageTypeIn, final TerrainType type) + public final IPokemob user; + + public TerrainDamageSource(final String damageTypeIn, final TerrainType type, final IPokemob user) { super(damageTypeIn); this.type = type; + this.user = user; } @Override @@ -27,4 +32,23 @@ public ITextComponent getDeathMessage(final LivingEntity LivingEntityIn) final String s = "death.attack." + this.damageType; return new TranslationTextComponent(s, LivingEntityIn.getDisplayName()); } + + @Override + public Entity getImmediateSource() + { + if (this.user != null) return this.user.getEntity(); + return super.getImmediateSource(); + } + + @Override + public Entity getTrueSource() + { + if (this.user != null) + { + Entity source = this.user.getEntity(); + if (this.user.getOwner() != null) source = this.user.getOwner(); + return source; + } + return super.getTrueSource(); + } } 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 efae8305dd..b55bfbc53a 100644 --- a/src/main/java/pokecube/core/moves/templates/Move_Basic.java +++ b/src/main/java/pokecube/core/moves/templates/Move_Basic.java @@ -23,7 +23,6 @@ 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; import pokecube.core.events.pokemob.combat.MoveUse; @@ -370,7 +369,7 @@ public void onAttack(MovePacket packet) } if (attacked != attackerMob && targetPokemob != null) { - AIFindTarget.initiateCombat((MobEntity) attacked, attackerMob); + BrainUtils.initiateCombat((MobEntity) attacked, attackerMob); targetPokemob.setCombatState(CombatStates.ANGRY, true); } if (efficiency > 0 && packet.applyOngoing) diff --git a/src/main/java/pokecube/core/moves/templates/Move_Terrain.java b/src/main/java/pokecube/core/moves/templates/Move_Terrain.java index fc5d5e1f60..546d8dc494 100644 --- a/src/main/java/pokecube/core/moves/templates/Move_Terrain.java +++ b/src/main/java/pokecube/core/moves/templates/Move_Terrain.java @@ -22,7 +22,7 @@ public class Move_Terrain extends Move_Basic * @param name * @param effect */ - public Move_Terrain(String name) + public Move_Terrain(final String name) { super(name); this.effect = this.move.baseEntry.extraInfo; @@ -38,7 +38,7 @@ public Move_Terrain(String name) * @param finalAttackStrength * the number of HPs the attack takes from target */ - public void doWorldAction(IPokemob attacker, Vector3 location) + public void doWorldAction(final IPokemob attacker, final Vector3 location) { if (attacker.getMoveStats().SPECIALCOUNTER > 0) return; attacker.getMoveStats().SPECIALCOUNTER = 20; @@ -51,14 +51,14 @@ public void doWorldAction(IPokemob attacker, Vector3 location) // TODO check if effect already exists, and send message if so. // Otherwise send the it starts to effect message - teffect.setEffect(this.effect, this.duration + world.getGameTime()); + teffect.setEffect(this.effect, this.duration + world.getGameTime(), attacker); if (attacker.getEntity().isServerWorld()) PacketSyncTerrain.sendTerrainEffects(attacker.getEntity(), segment.chunkX, segment.chunkY, segment.chunkZ, teffect); } - public void setDuration(int duration) + public void setDuration(final int duration) { this.duration = duration; } diff --git a/src/main/java/pokecube/core/network/pokemobs/PacketPokemobGui.java b/src/main/java/pokecube/core/network/pokemobs/PacketPokemobGui.java index c278fc5896..3d3e74ade8 100644 --- a/src/main/java/pokecube/core/network/pokemobs/PacketPokemobGui.java +++ b/src/main/java/pokecube/core/network/pokemobs/PacketPokemobGui.java @@ -9,7 +9,7 @@ import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.network.NetworkHooks; import pokecube.core.PokecubeCore; -import pokecube.core.ai.tasks.utility.AIStoreStuff; +import pokecube.core.ai.tasks.utility.StoreTask; import pokecube.core.entity.pokemobs.ContainerPokemob; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.capabilities.CapabilityPokemob; @@ -88,10 +88,10 @@ public void handleServer(final ServerPlayerEntity player) }); return; case STORAGE: - AIStoreStuff ai = null; + StoreTask ai = null; for (final IAIRunnable run : pokemob.getTasks()) - if (run instanceof AIStoreStuff) ai = (AIStoreStuff) run; - final AIStoreStuff toSend = ai; + if (run instanceof StoreTask) ai = (StoreTask) run; + final StoreTask toSend = ai; buffer.writeCompoundTag(toSend.serializeNBT()); provider = new SimpleNamedContainerProvider((i, p, e) -> new ContainerPokemob(i, p, buffer), entity .getDisplayName()); diff --git a/src/main/java/pokecube/core/utils/AITools.java b/src/main/java/pokecube/core/utils/AITools.java index b7b06e2b1d..bf48868135 100644 --- a/src/main/java/pokecube/core/utils/AITools.java +++ b/src/main/java/pokecube/core/utils/AITools.java @@ -7,6 +7,7 @@ import com.google.common.collect.Sets; import net.minecraft.entity.Entity; +import net.minecraft.entity.MobEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.ResourceLocation; @@ -15,7 +16,6 @@ import pokecube.core.PokecubeCore; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.pokemob.ai.GeneralStates; -import pokecube.core.items.pokecubes.EntityPokecubeBase; import pokecube.core.items.pokemobeggs.EntityPokemobEgg; import pokecube.core.moves.damage.IPokedamage; @@ -43,22 +43,25 @@ private static class ValidCheck implements Predicate @Override public boolean test(final Entity input) { + if (input == null) return true; final ResourceLocation eid = input.getType().getRegistryName(); if (AITools.invalidIDs.contains(eid)) return false; - // Then check if disabled via class - for (final Class clas : AITools.invalidClasses) - if (clas.isInstance(input)) return false; - // Then check if is a spectating player. + for (final String tag : AITools.invalidTags) + if (input.getTags().contains(tag)) return false; + + // Then check if is a valid player. if (input instanceof ServerPlayerEntity) { final ServerPlayerEntity player = (ServerPlayerEntity) input; - if (player.isSpectator() || player.getServerWorld().getDifficulty().getId() <= Difficulty.EASY.getId()) - return false; + // Do not target creative or spectator + if (player.isCreative() || player.isSpectator()) return false; + // Do not target any player on easy or peaceful + if (player.getServerWorld().getDifficulty().getId() <= Difficulty.EASY.getId()) return false; + return true; } // Confirm is not an egg or a pokecube as well if (input instanceof EntityPokemobEgg) return false; - if (input instanceof EntityPokecubeBase) return false; - return true; + return input instanceof MobEntity; } } @@ -87,11 +90,12 @@ public boolean test(final DamageSource t) public static boolean handleDamagedTargets = true; - public static int DEAGROTIMER = 50; - public static Set> invalidClasses = Sets.newHashSet(); + public static int DEAGROTIMER = 50; public static Set invalidIDs = Sets.newHashSet(); + public static Set invalidTags = Sets.newHashSet(); + /** * Checks the blacklists set via configs, to see whether the target is a * valid choice. @@ -118,18 +122,8 @@ public boolean test(final DamageSource t) public static void initIDs() { - for (final String s : PokecubeCore.getConfig().guardBlacklistClass) - try - { - final Class c = Class.forName(s, false, PokecubeCore.getConfig().getClass().getClassLoader()); - AITools.invalidClasses.add(c); - } - catch (final ClassNotFoundException e) - { - e.printStackTrace(); - } final Set keys = ForgeRegistries.ENTITIES.getKeys(); - for (String s : PokecubeCore.getConfig().guardBlacklistId) + for (String s : PokecubeCore.getConfig().aggroBlacklistIds) if (s.endsWith("*")) { s = s.substring(0, s.length() - 1); @@ -137,6 +131,9 @@ public static void initIDs() if (res.toString().startsWith(s)) AITools.invalidIDs.add(res); } else AITools.invalidIDs.add(new ResourceLocation(s)); + + for (final String s : PokecubeCore.getConfig().aggroBlacklistTags) + AITools.invalidTags.add(s); } } diff --git a/src/main/java/pokecube/core/utils/PokemobTracker.java b/src/main/java/pokecube/core/utils/PokemobTracker.java index a9e4885816..2a211bcdc5 100644 --- a/src/main/java/pokecube/core/utils/PokemobTracker.java +++ b/src/main/java/pokecube/core/utils/PokemobTracker.java @@ -1,28 +1,37 @@ package pokecube.core.utils; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; +import com.google.common.collect.Lists; + +import net.minecraft.entity.Entity; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IWorld; import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.event.world.WorldEvent.Load; import net.minecraftforge.eventbus.api.SubscribeEvent; import pokecube.core.database.PokedexEntry; import pokecube.core.interfaces.IPokemob; +import pokecube.core.items.pokecubes.EntityPokecubeBase; import thut.api.maths.Vector3; public class PokemobTracker { - private static class Entry implements Comparable + private static class MobEntry implements Comparable { final IPokemob pokemob; - public Entry(final IPokemob pokemob) + public MobEntry(final IPokemob pokemob) { this.pokemob = pokemob; } @@ -35,7 +44,7 @@ public BlockPos getPos() @Override public boolean equals(final Object obj) { - if (obj instanceof Entry) return ((Entry) obj).pokemob.getEntity().getUniqueID().equals(this.pokemob + if (obj instanceof MobEntry) return ((MobEntry) obj).pokemob.getEntity().getUniqueID().equals(this.pokemob .getEntity().getUniqueID()); return false; } @@ -47,41 +56,151 @@ public int hashCode() } @Override - public int compareTo(final Entry o) + public int compareTo(final MobEntry o) + { + return this.getPos().compareTo(o.getPos()); + } + } + + private static class CubeEntry implements Comparable + { + final EntityPokecubeBase cube; + + public CubeEntry(final EntityPokecubeBase cube) + { + this.cube = cube; + } + + public BlockPos getPos() + { + return this.cube.getEntity().getPosition(); + } + + @Override + public boolean equals(final Object obj) + { + if (obj instanceof MobEntry) return ((MobEntry) obj).pokemob.getEntity().getUniqueID().equals(this.cube + .getEntity().getUniqueID()); + return false; + } + + @Override + public int hashCode() + { + return this.cube.getEntity().getUniqueID().hashCode(); + } + + @Override + public int compareTo(final CubeEntry o) { return this.getPos().compareTo(o.getPos()); } } - private static Map> mobMap = new HashMap<>(); + // Client and server instances as they operate seperate worlds + private static final PokemobTracker CLIENT = new PokemobTracker(); + private static final PokemobTracker SERVER = new PokemobTracker(); - public static void addPokemob(final IPokemob pokemob) + private static PokemobTracker getFor(final Entity mob) { - // First remove the mob from all maps, incase it is in one. - PokemobTracker.removePokemob(pokemob); + return mob.getEntityWorld() instanceof ServerWorld ? PokemobTracker.SERVER : PokemobTracker.CLIENT; + } + + private static PokemobTracker getFor(final IWorld mob) + { + return mob.getWorld() instanceof ServerWorld ? PokemobTracker.SERVER : PokemobTracker.CLIENT; + } + + private final Map> liveMobs = new ConcurrentHashMap<>(); + private final Map> ownerMap = new ConcurrentHashMap<>(); + private final Map> ownedCubes = new ConcurrentHashMap<>(); + private MobEntry _addPokemob(final IPokemob pokemob) + { + // First remove the mob from all maps, incase it is in one. + final MobEntry e = PokemobTracker.removePokemob(pokemob); final DimensionType dim = pokemob.getEntity().dimension; // Find the appropriate map - final List mobList = PokemobTracker.mobMap.getOrDefault(dim, new ArrayList<>()); + final List mobList = this.liveMobs.getOrDefault(dim, new ArrayList<>()); // Register the dimension if not already there - if (!PokemobTracker.mobMap.containsKey(dim)) PokemobTracker.mobMap.put(dim, mobList); + if (!this.liveMobs.containsKey(dim)) this.liveMobs.put(dim, mobList); // Add the pokemob to the list - mobList.add(new Entry(pokemob)); + mobList.add(e); + + final UUID owner = pokemob.getOwnerId(); + if (owner == null) return e; + + final Set owned = this.ownerMap.getOrDefault(owner, new HashSet<>()); + // Register the dimension if not already there + if (!this.ownerMap.containsKey(owner)) this.ownerMap.put(owner, owned); + // Add the pokemob to the list + owned.add(e); + return e; } - public static void removePokemob(final IPokemob pokemob) + private MobEntry _removePokemob(final IPokemob pokemob) { - final Entry e = new Entry(pokemob); + final MobEntry e = new MobEntry(pokemob); + // Remove the mob from all maps, incase it is in one. + this.liveMobs.forEach((d, m) -> m.remove(e)); // Remove the mob from all maps, incase it is in one. - PokemobTracker.mobMap.forEach((d, m) -> m.remove(e)); + this.ownerMap.forEach((d, m) -> m.remove(e)); + // Thread.dumpStack(); + return e; + } + + private CubeEntry _addPokecube(final EntityPokecubeBase cube) + { + final UUID owner = cube.containedMob != null ? cube.containedMob.getOwnerId() : null; + if (owner == null) return null; + final CubeEntry e = PokemobTracker.removePokecube(cube); + final Set owned = this.ownedCubes.getOrDefault(owner, new HashSet<>()); + // Register the dimension if not already there + if (!this.ownedCubes.containsKey(owner)) this.ownedCubes.put(owner, owned); + // Add the pokemob to the list + owned.add(e); + return e; + } + + private CubeEntry _removePokecube(final EntityPokecubeBase cube) + { + final CubeEntry e = new CubeEntry(cube); + // Remove the mob from all maps, incase it is in one. + this.ownedCubes.forEach((d, m) -> m.remove(e)); + return e; + } + + public static MobEntry addPokemob(final IPokemob pokemob) + { + final PokemobTracker tracker = PokemobTracker.getFor(pokemob.getEntity()); + return tracker._addPokemob(pokemob); + } + + public static MobEntry removePokemob(final IPokemob pokemob) + { + final PokemobTracker tracker = PokemobTracker.getFor(pokemob.getEntity()); + return tracker._removePokemob(pokemob); + } + + public static CubeEntry addPokecube(final EntityPokecubeBase cube) + { + final PokemobTracker tracker = PokemobTracker.getFor(cube); + return tracker._addPokecube(cube); + } + + public static CubeEntry removePokecube(final EntityPokecubeBase cube) + { + final PokemobTracker tracker = PokemobTracker.getFor(cube); + return tracker._removePokecube(cube); } public static int countPokemobs(final IWorld world, final AxisAlignedBB box, final Predicate matches) { + final PokemobTracker tracker = PokemobTracker.getFor(world); final DimensionType dim = world.getDimension().getType(); - final Entry[] mobList = PokemobTracker.mobMap.getOrDefault(dim, new ArrayList<>()).toArray(new Entry[0]); + final MobEntry[] mobList = tracker.liveMobs.getOrDefault(dim, new ArrayList<>()).toArray(new MobEntry[0]); int num = 0; - for (final Entry e : mobList) + for (final MobEntry e : mobList) if (box.contains(e.getPos().getX(), e.getPos().getY(), e.getPos().getZ()) && matches.test(e.pokemob)) num++; return num; } @@ -111,11 +230,29 @@ public static int countPokemobs(final IWorld world, final Vector3 location, fina return PokemobTracker.countPokemobs(world, box); } + public static List getMobs(final Entity owner, final Predicate matcher) + { + final PokemobTracker tracker = PokemobTracker.getFor(owner); + final List pokemobs = Lists.newArrayList(); + final UUID id = owner.getUniqueID(); + final Set mobs = tracker.ownerMap.getOrDefault(id, Collections.emptySet()); + final Set cubes = tracker.ownedCubes.getOrDefault(id, Collections.emptySet()); + mobs.forEach(e -> + { + if (matcher.test(e.pokemob.getEntity())) pokemobs.add(e.pokemob.getEntity()); + }); + cubes.forEach(e -> + { + if (matcher.test(e.cube)) pokemobs.add(e.cube); + }); + return pokemobs; + } + @SubscribeEvent public static void worldLoadEvent(final Load evt) { - if (evt.getWorld().isRemote()) return; + final PokemobTracker tracker = PokemobTracker.getFor(evt.getWorld()); // Reset the tracked map for this world - PokemobTracker.mobMap.put(evt.getWorld().getDimension().getType(), new ArrayList<>()); + tracker.liveMobs.put(evt.getWorld().getDimension().getType(), new ArrayList<>()); } } diff --git a/src/main/java/pokecube/core/world/terrain/PokecubeTerrainChecker.java b/src/main/java/pokecube/core/world/terrain/PokecubeTerrainChecker.java index 874f68fdcf..d6e919c594 100644 --- a/src/main/java/pokecube/core/world/terrain/PokecubeTerrainChecker.java +++ b/src/main/java/pokecube/core/world/terrain/PokecubeTerrainChecker.java @@ -127,7 +127,7 @@ public int getSubBiome(final IWorld world, final Vector3 v, final TerrainSegment { if (caveAdjusted) { - final Set set = StructureManager.getFor(v.getPos()); + final Set set = StructureManager.getFor(world.getDimension().getType(), v.getPos()); for (final StructureInfo info : set) { final String name = info.name; diff --git a/src/main/java/pokecube/legends/conditions/LegendaryConditions.java b/src/main/java/pokecube/legends/conditions/LegendaryConditions.java index d597b41355..2de7d809ad 100644 --- a/src/main/java/pokecube/legends/conditions/LegendaryConditions.java +++ b/src/main/java/pokecube/legends/conditions/LegendaryConditions.java @@ -6,6 +6,7 @@ import net.minecraft.block.Blocks; import net.minecraftforge.common.MinecraftForge; +import pokecube.core.PokecubeCore; import pokecube.core.database.Pokedex; import pokecube.core.database.PokedexEntry; import pokecube.core.database.stats.ISpecialCaptureCondition; @@ -63,6 +64,7 @@ public void init() // Register the thng that prevents genetic modification of protected // mobs MinecraftForge.EVENT_BUS.register(new GeneProtector()); + PokecubeCore.POKEMOB_BUS.register(new GeneProtector()); MinecraftForge.EVENT_BUS.register(LegendarySpawn.class); List> foundClasses; diff --git a/src/main/java/pokecube/legends/handlers/GeneProtector.java b/src/main/java/pokecube/legends/handlers/GeneProtector.java index e665a8feba..c23111b8c1 100644 --- a/src/main/java/pokecube/legends/handlers/GeneProtector.java +++ b/src/main/java/pokecube/legends/handlers/GeneProtector.java @@ -8,14 +8,15 @@ import pokecube.core.entity.pokemobs.genetics.GeneticsManager; import pokecube.core.entity.pokemobs.genetics.genes.SpeciesGene; import pokecube.core.entity.pokemobs.genetics.genes.SpeciesGene.SpeciesInfo; +import pokecube.core.events.EggEvent.CanBreed; +import pokecube.core.interfaces.IPokemob; +import pokecube.core.interfaces.capabilities.CapabilityPokemob; import thut.api.entity.genetics.Alleles; public class GeneProtector { - public boolean invalidGene(final SpeciesGene gene) + public boolean invalidEntry(final PokedexEntry entry) { - final SpeciesInfo info = gene.getValue(); - final PokedexEntry entry = info.entry; // No cloning legends. if (entry.isLegendary()) return true; // No cloning things with requirements @@ -26,6 +27,13 @@ public boolean invalidGene(final SpeciesGene gene) return false; } + public boolean invalidGene(final SpeciesGene gene) + { + final SpeciesInfo info = gene.getValue(); + final PokedexEntry entry = info.entry; + return this.invalidEntry(entry); + } + @SubscribeEvent public void GeneEditEvent(final GeneEditEvent evt) { @@ -36,4 +44,13 @@ public void GeneEditEvent(final GeneEditEvent evt) if (this.invalidGene(gene)) evt.resultGenes.getAlleles().remove(GeneticsManager.SPECIESGENE); } } + + @SubscribeEvent + public void CanBreedEvent(final CanBreed evt) + { + final IPokemob mobA = CapabilityPokemob.getPokemobFor(evt.getEntity()); + final IPokemob mobB = CapabilityPokemob.getPokemobFor(evt.getOther()); + if (mobA != null && this.invalidEntry(mobA.getPokedexEntry())) evt.setCanceled(true); + if (mobB != null && this.invalidEntry(mobB.getPokedexEntry())) evt.setCanceled(true); + } } \ No newline at end of file diff --git a/src/main/java/pokecube/mobs/abilities/a/ArenaTrap.java b/src/main/java/pokecube/mobs/abilities/a/ArenaTrap.java index b1d63c9e2d..224c7d746c 100644 --- a/src/main/java/pokecube/mobs/abilities/a/ArenaTrap.java +++ b/src/main/java/pokecube/mobs/abilities/a/ArenaTrap.java @@ -1,22 +1,37 @@ package pokecube.mobs.abilities.a; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.world.server.ServerWorld; import pokecube.core.PokecubeCore; import pokecube.core.database.abilities.Ability; import pokecube.core.interfaces.IPokemob; +import thut.api.maths.Vector3; public class ArenaTrap extends Ability { // the part that usually prevents switching is still "TODO" + int range = 4; + + @Override + public Ability init(final Object... args) + { + if (args == null) return this; + for (final Object arg : args) + if (arg instanceof Integer) + { + this.range = (int) arg; + return this; + } + return this; + } + @Override - public void onUpdate(IPokemob mob) + public void onUpdate(final IPokemob mob) { + if (!(mob.getEntity().getEntityWorld() instanceof ServerWorld)) return; if (mob.getEntity().ticksExisted % 20 == 0) { - if (!(mob.getOwner() instanceof ServerPlayerEntity)) return; - PokecubeCore.spawner.doSpawnForPlayer((PlayerEntity) mob.getOwner(), mob.getOwner() - .getEntityWorld()); + final ServerWorld world = (ServerWorld) mob.getEntity().getEntityWorld(); + PokecubeCore.spawner.doSpawnForPoint(Vector3.getNewVector().set(mob.getEntity()), world, 0, this.range); } } } diff --git a/src/main/java/pokecube/mobs/abilities/eventwatchers/Damp.java b/src/main/java/pokecube/mobs/abilities/eventwatchers/Damp.java index 7dce8cf877..6831c4ae8e 100644 --- a/src/main/java/pokecube/mobs/abilities/eventwatchers/Damp.java +++ b/src/main/java/pokecube/mobs/abilities/eventwatchers/Damp.java @@ -1,6 +1,5 @@ package pokecube.mobs.abilities.eventwatchers; -import net.minecraft.entity.LivingEntity; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.world.ExplosionEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -14,10 +13,11 @@ public class Damp extends Ability { IPokemob mob; - int range = 16; + + int range = 16; @SubscribeEvent - public void denyBoom(ExplosionEvent.Start boom) + public void denyBoom(final ExplosionEvent.Start boom) { if (!this.mob.getEntity().isAlive()) this.destroy(); else @@ -35,7 +35,7 @@ public void destroy() } @Override - public Ability init(Object... args) + public Ability init(final Object... args) { if (ThutCore.proxy.isClientSide()) return this; for (int i = 0; i < 2; i++) @@ -52,12 +52,7 @@ public Ability init(Object... args) } @Override - public void onAgress(IPokemob mob, LivingEntity target) - { - } - - @Override - public void onMoveUse(IPokemob mob, MovePacket move) + public void onMoveUse(final IPokemob mob, final MovePacket move) { if (move.getMove() instanceof Move_Explode) { @@ -67,7 +62,7 @@ public void onMoveUse(IPokemob mob, MovePacket move) } @Override - public void onUpdate(IPokemob mob) + public void onUpdate(final IPokemob mob) { this.mob = mob; } diff --git a/src/main/java/pokecube/mobs/abilities/h/HoneyGather.java b/src/main/java/pokecube/mobs/abilities/h/HoneyGather.java index 015af6a153..29a8c0d77b 100644 --- a/src/main/java/pokecube/mobs/abilities/h/HoneyGather.java +++ b/src/main/java/pokecube/mobs/abilities/h/HoneyGather.java @@ -23,10 +23,11 @@ public class HoneyGather extends Ability @Override public Ability init(final Object... args) { - for (int i = 0; i < 2; i++) - if (args != null && args.length > i) if (args[i] instanceof Integer) + if (args == null) return this; + for (final Object arg : args) + if (arg instanceof Integer) { - this.range = (int) args[i]; + this.range = (int) arg; return this; } return this; diff --git a/src/main/java/pokecube/mobs/abilities/i/Illuminate.java b/src/main/java/pokecube/mobs/abilities/i/Illuminate.java index eae1121ebe..8cb8e0653e 100644 --- a/src/main/java/pokecube/mobs/abilities/i/Illuminate.java +++ b/src/main/java/pokecube/mobs/abilities/i/Illuminate.java @@ -1,21 +1,36 @@ package pokecube.mobs.abilities.i; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.world.server.ServerWorld; import pokecube.core.PokecubeCore; import pokecube.core.database.abilities.Ability; import pokecube.core.interfaces.IPokemob; +import thut.api.maths.Vector3; public class Illuminate extends Ability { + int range = 4; + + @Override + public Ability init(final Object... args) + { + if (args == null) return this; + for (final Object arg : args) + if (arg instanceof Integer) + { + this.range = (int) arg; + return this; + } + return this; + } + @Override - public void onUpdate(IPokemob mob) + public void onUpdate(final IPokemob mob) { + if (!(mob.getEntity().getEntityWorld() instanceof ServerWorld)) return; if (mob.getEntity().ticksExisted % 20 == 0) { - if (!(mob.getOwner() instanceof ServerPlayerEntity)) return; - PokecubeCore.spawner.doSpawnForPlayer((PlayerEntity) mob.getOwner(), mob.getOwner() - .getEntityWorld()); + final ServerWorld world = (ServerWorld) mob.getEntity().getEntityWorld(); + PokecubeCore.spawner.doSpawnForPoint(Vector3.getNewVector().set(mob.getEntity()), world, 0, this.range); } } } diff --git a/src/main/java/pokecube/mobs/abilities/s/Swarm.java b/src/main/java/pokecube/mobs/abilities/s/Swarm.java index 87cf05b57f..db7c1dc61c 100644 --- a/src/main/java/pokecube/mobs/abilities/s/Swarm.java +++ b/src/main/java/pokecube/mobs/abilities/s/Swarm.java @@ -1,32 +1,47 @@ package pokecube.mobs.abilities.s; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.world.server.ServerWorld; import pokecube.core.PokecubeCore; import pokecube.core.database.abilities.Ability; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.pokemob.moves.MovePacket; import pokecube.core.utils.PokeType; +import thut.api.maths.Vector3; public class Swarm extends Ability { + int range = 4; + @Override - public void onMoveUse(IPokemob mob, MovePacket move) + public Ability init(final Object... args) { - - if (!move.pre) return; - if (mob == move.attacker && move.attackType == PokeType.getType("bug") && mob.getEntity().getHealth() < mob - .getEntity().getMaxHealth() / 3) move.PWR *= 1.5; + if (args == null) return this; + for (final Object arg : args) + if (arg instanceof Integer) + { + this.range = (int) arg; + return this; + } + return this; } @Override - public void onUpdate(IPokemob mob) + public void onUpdate(final IPokemob mob) { + if (!(mob.getEntity().getEntityWorld() instanceof ServerWorld)) return; if (mob.getEntity().ticksExisted % 20 == 0) { - if (!(mob.getOwner() instanceof ServerPlayerEntity)) return; - PokecubeCore.spawner.doSpawnForPlayer((PlayerEntity) mob.getOwner(), mob.getOwner() - .getEntityWorld()); + final ServerWorld world = (ServerWorld) mob.getEntity().getEntityWorld(); + PokecubeCore.spawner.doSpawnForPoint(Vector3.getNewVector().set(mob.getEntity()), world, 0, this.range); } } + + @Override + public void onMoveUse(final IPokemob mob, final MovePacket move) + { + + if (!move.pre) return; + if (mob == move.attacker && move.attackType == PokeType.getType("bug") && mob.getEntity().getHealth() < mob + .getEntity().getMaxHealth() / 3) move.PWR *= 1.5; + } } diff --git a/src/main/java/pokecube/mobs/moves/attacks/special/Teleport.java b/src/main/java/pokecube/mobs/moves/attacks/special/Teleport.java index 107074af34..4e08bc5c2a 100644 --- a/src/main/java/pokecube/mobs/moves/attacks/special/Teleport.java +++ b/src/main/java/pokecube/mobs/moves/attacks/special/Teleport.java @@ -1,6 +1,6 @@ package pokecube.mobs.moves.attacks.special; -import pokecube.core.ai.tasks.combat.AIFindTarget; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.pokemob.moves.MovePacket; import pokecube.core.moves.templates.Move_Basic; @@ -16,7 +16,7 @@ public Teleport() public void postAttack(final MovePacket packet) { final IPokemob attacker = packet.attacker; - AIFindTarget.deagro(attacker.getEntity()); + BrainUtils.deagro(attacker.getEntity()); super.postAttack(packet); } } 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 925d7e415c..c6790579de 100644 --- a/src/main/java/pokecube/mobs/moves/attacks/special/Transform.java +++ b/src/main/java/pokecube/mobs/moves/attacks/special/Transform.java @@ -5,7 +5,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; -import pokecube.core.ai.tasks.combat.AIFindTarget; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.interfaces.IMoveAnimation; import pokecube.core.interfaces.IMoveConstants; import pokecube.core.interfaces.IMoveNames; @@ -64,7 +64,7 @@ public void attack(final IPokemob attacker, final Entity attacked) final IPokemob attackedMob = CapabilityPokemob.getPokemobFor(attacked); if (attacked instanceof LivingEntity) { - AIFindTarget.initiateCombat(attacker.getEntity(), (LivingEntity) attacked); + BrainUtils.initiateCombat(attacker.getEntity(), (LivingEntity) attacked); attacker.setTransformedTo(attacked); } else if (attackedMob != null) diff --git a/src/main/java/pokecube/mobs/moves/attacks/special/Whirlwind.java b/src/main/java/pokecube/mobs/moves/attacks/special/Whirlwind.java index abcf2834e9..71cac65c04 100644 --- a/src/main/java/pokecube/mobs/moves/attacks/special/Whirlwind.java +++ b/src/main/java/pokecube/mobs/moves/attacks/special/Whirlwind.java @@ -1,6 +1,6 @@ package pokecube.mobs.moves.attacks.special; -import pokecube.core.ai.tasks.combat.AIFindTarget; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.interfaces.IPokemob; import pokecube.core.interfaces.capabilities.CapabilityPokemob; import pokecube.core.interfaces.pokemob.ai.CombatStates; @@ -39,6 +39,6 @@ public void postAttack(final MovePacket packet) attacked.setCombatState(CombatStates.ANGRY, false); } // ends the battle - AIFindTarget.deagro(packet.attacker.getEntity()); + BrainUtils.deagro(packet.attacker.getEntity()); } } diff --git a/src/main/java/pokecube/mobs/moves/world/ActionTeleport.java b/src/main/java/pokecube/mobs/moves/world/ActionTeleport.java index 8fcc2e520b..4bab7e658e 100644 --- a/src/main/java/pokecube/mobs/moves/world/ActionTeleport.java +++ b/src/main/java/pokecube/mobs/moves/world/ActionTeleport.java @@ -6,7 +6,7 @@ import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvents; import pokecube.core.PokecubeCore; -import pokecube.core.ai.tasks.combat.AIFindTarget; +import pokecube.core.ai.brain.BrainUtils; import pokecube.core.handlers.events.EventsHandler; import pokecube.core.handlers.events.SpawnHandler; import pokecube.core.interfaces.IMoveAction; @@ -95,7 +95,7 @@ public boolean applyEffect(final IPokemob user, final Vector3 location) } else if (angry) { - AIFindTarget.deagro(user.getEntity()); + BrainUtils.deagro(user.getEntity()); if (user.getGeneralState(GeneralStates.TAMED)) user.onRecall(); else ActionTeleport.teleportRandomly(user.getEntity()); } diff --git a/src/main/java/thut/api/OwnableCaps.java b/src/main/java/thut/api/OwnableCaps.java index d241c27b17..a6bb375161 100644 --- a/src/main/java/thut/api/OwnableCaps.java +++ b/src/main/java/thut/api/OwnableCaps.java @@ -276,22 +276,25 @@ public static IOwnable getOwnable(final ICapabilityProvider in) @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.OWNABLE_CAP).isPresent()) return; // We check if it is already here, incase someone else wants to wrap a // tameable differently. - if (!event.getCapabilities().containsKey(OwnableCaps.LOCWRAP)) - { - if (event.getObject() instanceof TameableEntity) event.addCapability(OwnableCaps.LOCWRAP, new TameWrapper( - (TameableEntity) event.getObject())); - else if (event.getObject() instanceof AbstractHorseEntity) event.addCapability(OwnableCaps.LOCWRAP, - new HorseWrapper((AbstractHorseEntity) event.getObject())); - } + if (event.getObject() instanceof TameableEntity) event.addCapability(OwnableCaps.LOCWRAP, new TameWrapper( + (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()); } - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.LOWEST) public static void attachTEs(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.OWNABLE_CAP).isPresent()) return; if (OwnableCaps.TILES.contains(event.getObject().getClass())) event.addCapability(OwnableCaps.LOCBASE, new ImplTE()); } diff --git a/src/main/java/thut/api/terrain/ITerrainProvider.java b/src/main/java/thut/api/terrain/ITerrainProvider.java index 1eb724b049..a06ae79a69 100644 --- a/src/main/java/thut/api/terrain/ITerrainProvider.java +++ b/src/main/java/thut/api/terrain/ITerrainProvider.java @@ -1,10 +1,7 @@ package thut.api.terrain; -import java.util.Collections; import java.util.Map; -import com.google.common.collect.Maps; - import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; @@ -18,12 +15,46 @@ public interface ITerrainProvider { Object lock = new Object(); + static class TerrainCache + { + TerrainSegment[] segs = new TerrainSegment[16]; + int num = 16; + + public TerrainCache(final ChunkPos temp, final IChunk chunk) + { + for (int i = 0; i < 16; i++) + { + this.segs[i] = new TerrainSegment(temp.x, i, temp.z); + this.segs[i].chunk = chunk; + this.segs[i].real = false; + } + } + + public TerrainSegment remove(final int y) + { + final TerrainSegment seg = this.segs[y]; + if (seg == null) return null; + this.num--; + return seg; + } + + public boolean isValid() + { + return this.num > 0; + } + + public TerrainSegment get(final int y) + { + return this.segs[y]; + } + } + /** * This is a cache of pending terrain segments, it is used as sometimes * segments need to have things set for them which the chunk is still being * generated, ie not completely loaded. */ - public static Map> pendingCache = new Object2ObjectOpenHashMap<>(); + public static Map pendingCache = new Object2ObjectOpenHashMap<>(); /** * This is a cache of loaded chunks, it is used to prevent thread lock @@ -71,7 +102,12 @@ public static IChunk getChunk(final DimensionType dim, final ChunkPos cpos) public static TerrainSegment removeCached(final DimensionType dim, final BlockPos pos) { - return ITerrainProvider.pendingCache.getOrDefault(dim, Collections.emptyMap()).remove(pos); + final GlobalChunkPos wpos = new GlobalChunkPos(dim, new ChunkPos(pos.getX(), pos.getZ())); + final TerrainCache segs = ITerrainProvider.pendingCache.get(wpos); + if (segs == null) return null; + final TerrainSegment var = segs.remove(pos.getY()); + if (!segs.isValid()) ITerrainProvider.pendingCache.remove(wpos); + return var; } /** @@ -85,31 +121,26 @@ default TerrainSegment getTerrain(final IWorld world, final BlockPos p) { // Convert the pos to a chunk pos final ChunkPos temp = new ChunkPos(p); + int y = p.getY() >> 4; + if (y < 0) y = 0; + if (y > 15) y = 15; // Include the value for y - final BlockPos pos = new BlockPos(temp.x, p.getY() / 16, temp.z); + final BlockPos pos = new BlockPos(temp.x, y, temp.z); final DimensionType dim = world.getDimension().getType(); final IChunk chunk = ITerrainProvider.getChunk(dim, temp); final boolean real = chunk != null && chunk instanceof ICapabilityProvider; // This means it occurs during worldgen? if (!real) { - final Map dimMap = ITerrainProvider.pendingCache.getOrDefault(dim, Maps - .newConcurrentMap()); - /** - * Here we need to make a new terrain segment, and cache it, then - * later if the world is actually available, we can get the terrain - * segment. from that. - */ - if (dimMap.containsKey(pos)) return dimMap.get(pos); - // No real world, so lets deal with the cache. - final TerrainSegment segment = new TerrainSegment(pos); - segment.chunk = chunk; - segment.real = false; - dimMap.put(pos, segment); - if (!ITerrainProvider.pendingCache.containsKey(dim)) ITerrainProvider.pendingCache.put(dim, dimMap); - return segment; + final GlobalChunkPos wpos = new GlobalChunkPos(dim, temp); + TerrainCache segs = ITerrainProvider.pendingCache.get(wpos); + if (segs == null) + { + segs = new TerrainCache(temp, chunk); + ITerrainProvider.pendingCache.put(wpos, segs); + } + return segs.get(y); } - final CapabilityTerrain.ITerrainProvider provider = ((ICapabilityProvider) chunk).getCapability( ThutCaps.TERRAIN_CAP).orElse(null); provider.setChunk(chunk); diff --git a/src/main/java/thut/api/terrain/StructureManager.java b/src/main/java/thut/api/terrain/StructureManager.java index e97d97a4f0..fc14b75618 100644 --- a/src/main/java/thut/api/terrain/StructureManager.java +++ b/src/main/java/thut/api/terrain/StructureManager.java @@ -1,15 +1,17 @@ package thut.api.terrain; import java.util.Collections; +import java.util.Map; import java.util.Map.Entry; import java.util.Set; import com.google.common.collect.Sets; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.gen.feature.structure.StructurePiece; import net.minecraft.world.gen.feature.structure.StructureStart; import net.minecraftforge.event.world.ChunkEvent; @@ -83,23 +85,25 @@ private static boolean sameBounds(final MutableBoundingBox boxA, final MutableBo } } - private static Long2ObjectOpenHashMap> map_by_chunk = new Long2ObjectOpenHashMap<>(); + /** + * This is a cache of loaded chunks, it is used to prevent thread lock + * contention when trying to look up a chunk, as it seems that + * world.chunkExists returning true does not mean that you can just go and + * ask for the chunk... + */ + public static Map> map_by_pos = new Object2ObjectOpenHashMap<>(); - private static Set getOrMake(final long pos) + private static Set getOrMake(final GlobalChunkPos pos) { - final Set set = StructureManager.map_by_chunk.getOrDefault(pos, Sets.newHashSet()); - if (!StructureManager.map_by_chunk.containsKey(pos)) StructureManager.map_by_chunk.put(pos, set); + final Set set = StructureManager.map_by_pos.getOrDefault(pos, Sets.newHashSet()); + if (!StructureManager.map_by_pos.containsKey(pos)) StructureManager.map_by_pos.put(pos, set); return set; } - public static Set getFor(final long pos) + public static Set getFor(final DimensionType dim, final BlockPos loc) { - return StructureManager.map_by_chunk.getOrDefault(pos, Collections.emptySet()); - } - - public static Set getFor(final BlockPos loc) - { - final Set forPos = StructureManager.getFor(new ChunkPos(loc).asLong()); + final GlobalChunkPos pos = new GlobalChunkPos(dim, new ChunkPos(loc)); + final Set forPos = StructureManager.map_by_pos.getOrDefault(pos, Collections.emptySet()); if (forPos.isEmpty()) return forPos; final Set matches = Sets.newHashSet(); for (final StructureInfo i : forPos) @@ -110,6 +114,9 @@ public static Set getFor(final BlockPos loc) @SubscribeEvent public static void onChunkLoad(final ChunkEvent.Load evt) { + // The world is null when it is loaded off thread during worldgen! + if (evt.getWorld() == null || evt.getWorld().isRemote()) return; + final DimensionType dim = evt.getWorld().getDimension().getType(); for (final Entry entry : evt.getChunk().getStructureStarts().entrySet()) { final StructureInfo info = new StructureInfo(entry); @@ -118,14 +125,26 @@ public static void onChunkLoad(final ChunkEvent.Load evt) for (int z = b.minZ >> 4; z <= b.maxZ >> 4; z++) { final ChunkPos p = new ChunkPos(x, z); - final Set set = StructureManager.getOrMake(p.asLong()); + final GlobalChunkPos pos = new GlobalChunkPos(dim, p); + final Set set = StructureManager.getOrMake(pos); set.add(info); } } } + @SubscribeEvent + public static void onChunkUnload(final ChunkEvent.Unload evt) + { + if (evt.getWorld() == null || evt.getWorld().isRemote()) return; + final DimensionType dim = evt.getChunk().getWorldForge().getDimension().getType(); + final GlobalChunkPos pos = new GlobalChunkPos(dim, evt.getChunk().getPos()); + StructureManager.map_by_pos.remove(pos); + } + public static void clear() { - StructureManager.map_by_chunk.clear(); + StructureManager.map_by_pos.clear(); + ITerrainProvider.loadedChunks.clear(); + ITerrainProvider.pendingCache.clear(); } } diff --git a/src/main/java/thut/api/terrain/TerrainManager.java b/src/main/java/thut/api/terrain/TerrainManager.java index d8a2df387e..8508b4d289 100644 --- a/src/main/java/thut/api/terrain/TerrainManager.java +++ b/src/main/java/thut/api/terrain/TerrainManager.java @@ -81,6 +81,8 @@ public static void onChunkLoad(final ChunkEvent.Load evt) DimensionType dim = null; if (evt.getWorld() != null && evt.getWorld().getDimension() != null) dim = evt.getWorld().getDimension() .getType(); + // This is null when this is loaded off-thread, IE before the chunk is + // finished if (dim != null) ITerrainProvider.addChunk(dim, evt.getChunk()); } diff --git a/src/main/java/thut/core/client/render/animation/AnimationXML.java b/src/main/java/thut/core/client/render/animation/AnimationXML.java index f136549209..2a1b83e342 100644 --- a/src/main/java/thut/core/client/render/animation/AnimationXML.java +++ b/src/main/java/thut/core/client/render/animation/AnimationXML.java @@ -4,10 +4,6 @@ import java.util.List; import java.util.Map; -import thut.core.xml.bind.annotation.XmlAnyAttribute; -import thut.core.xml.bind.annotation.XmlAttribute; -import thut.core.xml.bind.annotation.XmlElement; -import thut.core.xml.bind.annotation.XmlRootElement; import javax.xml.namespace.QName; import com.google.common.collect.Lists; @@ -15,6 +11,10 @@ import thut.core.common.ThutCore; import thut.core.xml.bind.Factory; +import thut.core.xml.bind.annotation.XmlAnyAttribute; +import thut.core.xml.bind.annotation.XmlAttribute; +import thut.core.xml.bind.annotation.XmlElement; +import thut.core.xml.bind.annotation.XmlRootElement; public class AnimationXML { diff --git a/src/main/java/thut/core/client/render/mca/McaXML.java b/src/main/java/thut/core/client/render/mca/McaXML.java index 0848134d86..df441fa296 100644 --- a/src/main/java/thut/core/client/render/mca/McaXML.java +++ b/src/main/java/thut/core/client/render/mca/McaXML.java @@ -4,16 +4,15 @@ import java.util.ArrayList; import java.util.List; -import thut.core.xml.bind.annotation.XmlAttribute; -import thut.core.xml.bind.annotation.XmlElement; -import thut.core.xml.bind.annotation.XmlRootElement; - import com.google.common.collect.Lists; import thut.core.client.render.model.Vertex; import thut.core.client.render.texturing.TextureCoordinate; import thut.core.client.render.x3d.ModelFormatException; import thut.core.xml.bind.Factory; +import thut.core.xml.bind.annotation.XmlAttribute; +import thut.core.xml.bind.annotation.XmlElement; +import thut.core.xml.bind.annotation.XmlRootElement; public class McaXML { diff --git a/src/main/java/thut/core/client/render/x3d/X3dXML.java b/src/main/java/thut/core/client/render/x3d/X3dXML.java index 2eef84f677..8351051fd0 100644 --- a/src/main/java/thut/core/client/render/x3d/X3dXML.java +++ b/src/main/java/thut/core/client/render/x3d/X3dXML.java @@ -5,10 +5,6 @@ import java.util.List; import java.util.Set; -import thut.core.xml.bind.annotation.XmlAttribute; -import thut.core.xml.bind.annotation.XmlElement; -import thut.core.xml.bind.annotation.XmlRootElement; - import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -16,6 +12,9 @@ import thut.core.client.render.model.Vertex; import thut.core.common.ThutCore; import thut.core.xml.bind.Factory; +import thut.core.xml.bind.annotation.XmlAttribute; +import thut.core.xml.bind.annotation.XmlElement; +import thut.core.xml.bind.annotation.XmlRootElement; public class X3dXML { diff --git a/src/main/java/thut/core/common/ThutCore.java b/src/main/java/thut/core/common/ThutCore.java index 69c01e260c..f99faecd3e 100644 --- a/src/main/java/thut/core/common/ThutCore.java +++ b/src/main/java/thut/core/common/ThutCore.java @@ -56,7 +56,6 @@ import thut.api.entity.genetics.IMobGenetics; import thut.api.particle.ThutParticles; import thut.api.terrain.CapabilityTerrain; -import thut.api.terrain.ITerrainProvider; import thut.api.terrain.StructureManager; import thut.api.world.mobs.data.DataSync; import thut.core.common.config.Config; @@ -243,7 +242,6 @@ public void onServerAboutToStart(final FMLServerAboutToStartEvent event) { // do something when the server starts ThutCore.LOGGER.debug("Clearing terrain cache"); - ITerrainProvider.pendingCache.clear(); StructureManager.clear(); } diff --git a/src/main/java/thut/core/common/network/TileUpdate.java b/src/main/java/thut/core/common/network/TileUpdate.java index 53c4d67285..cf21cbf393 100644 --- a/src/main/java/thut/core/common/network/TileUpdate.java +++ b/src/main/java/thut/core/common/network/TileUpdate.java @@ -21,7 +21,7 @@ public static void sendUpdate(final TileEntity tile) { if (tile.getWorld().isRemote) { - ThutCore.LOGGER.error("Packet sent on wrong side!", new IllegalArgumentException()); + ThutCore.LOGGER.error("Packet sent on wrong side!"); return; } final CompoundNBT tag = new CompoundNBT(); diff --git a/src/main/java/thut/core/xml/bind/Factory.java b/src/main/java/thut/core/xml/bind/Factory.java index cac2b19470..718d616819 100644 --- a/src/main/java/thut/core/xml/bind/Factory.java +++ b/src/main/java/thut/core/xml/bind/Factory.java @@ -11,10 +11,6 @@ import java.util.Map; import javax.xml.XMLConstants; -import thut.core.xml.bind.annotation.XmlAnyAttribute; -import thut.core.xml.bind.annotation.XmlAttribute; -import thut.core.xml.bind.annotation.XmlElement; -import thut.core.xml.bind.annotation.XmlRootElement; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -32,6 +28,10 @@ import com.google.common.collect.Maps; import thut.core.common.ThutCore; +import thut.core.xml.bind.annotation.XmlAnyAttribute; +import thut.core.xml.bind.annotation.XmlAttribute; +import thut.core.xml.bind.annotation.XmlElement; +import thut.core.xml.bind.annotation.XmlRootElement; public class Factory { diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 674a83fb03..2d38ec0061 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -10,17 +10,21 @@ public net.minecraft.entity.Entity field_70165_t # posX public net.minecraft.entity.Entity field_70163_u # posY public net.minecraft.entity.Entity field_70161_v # posZ +public net.minecraft.entity.EntityType field_220359_bi # size +public net.minecraft.entity.Entity field_213325_aI # size + public net.minecraft.entity.passive.SheepEntity field_200206_bz # WOOL_BY_COLOR protected net.minecraft.entity.merchant.villager.VillagerEntity func_213744_a(Lnet/minecraft/entity/ai/brain/Brain;)V # initBrain public net.minecraft.world.server.ServerWorld field_217492_a # tickingEntities public net.minecraft.entity.ai.brain.Brain func_218217_d(Lnet/minecraft/entity/ai/brain/schedule/Activity;)Z # hasRequiredMemories -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.entity.ai.brain.Brain * # everything public net.minecraft.pathfinding.PathNavigator func_225464_a(Ljava/util/Set;IZI)Lnet/minecraft/pathfinding/Path; # func_225464_a +public net.minecraft.village.PointOfInterestType func_221052_a(Lnet/minecraft/village/PointOfInterestType;)Lnet/minecraft/village/PointOfInterestType; # registerBlockStates + # 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/assets/pokecube_adventures/lang/en_us.json b/src/main/resources/assets/pokecube_adventures/lang/en_us.json index 769411c659..00f87831db 100644 --- a/src/main/resources/assets/pokecube_adventures/lang/en_us.json +++ b/src/main/resources/assets/pokecube_adventures/lang/en_us.json @@ -2,6 +2,10 @@ "_comment": "Pokecube Adventures translation", "block.rfsiphon.info": "Energy Output: %1$s/%2$s", + "block.afa.ability.none": "No Ability Set", + "block.afa.ability.info": "Ability: %s", + "block.afa.range.info": "Range: %s", + "block.afa.power.info": "Power: %1$s/%2$s", "item.pokecube_adventures.target": "Target", "item.pokecube_adventures.linker": "Location Linker", @@ -210,6 +214,8 @@ "entity.pokecube_adventures.targetParticles": "Target", "pokecube.trainer.agress": "%1$s §cwants to battle!", + "pokecube.trainer.agress_request_allowed": "§aYou request a battle with §r%1$s§a!", + "pokecube.trainer.agress_request_denied": "%1$s §c does not want to battle you right now.", "pokecube.trainer.forget": "%1$s §cno longer wants to battle...", "pokecube.trainer.defeat": "%1$s §ahas been defeated!", "pokecube.trainer.toss": "%1$s §csent out %2$s!", @@ -424,7 +430,5 @@ "_comment": "Misc", "pokecube.config.tmRecipe.tooltip": "Can TMs be crafted", - "pokedex.inspect.geneticsguide": "§aYou recieved a Genetics Guide from the Pokédex.", - - "pokeadv.infobook1.json": "{pages:[\"{\\\"text\\\":\\\"Pokemob Genetics Guide\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n V.1.0\\\"}\",\"[\\\"\\\",{\\\"text\\\":\\\"Index\\\",\\\"bold\\\":true,\\\"underlined\\\":true},{\\\"text\\\":\\\"\\\\n\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"Basic Terms\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_red\\\",\\\"clickEvent\\\":{\\\"action\\\":\\\"change_page\\\",\\\"value\\\":3}},{\\\"text\\\":\\\"\\\\n\\\",\\\"color\\\":\\\"reset\\\",\\\"underlined\\\":true},{\\\"text\\\":\\\"Pokemob DNA\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_aqua\\\",\\\"clickEvent\\\":{\\\"action\\\":\\\"change_page\\\",\\\"value\\\":7}},{\\\"text\\\":\\\"\\\\n\\\",\\\"color\\\":\\\"reset\\\",\\\"underlined\\\":true},{\\\"text\\\":\\\"Extracting DNA\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_green\\\",\\\"clickEvent\\\":{\\\"action\\\":\\\"change_page\\\",\\\"value\\\":14}},{\\\"text\\\":\\\"\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\" \\\",\\\"color\\\":\\\"dark_green\\\"},{\\\"text\\\":\\\"DNA Selectors\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_green\\\",\\\"clickEvent\\\":{\\\"action\\\":\\\"change_page\\\",\\\"value\\\":15}},{\\\"text\\\":\\\"\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\" \\\",\\\"color\\\":\\\"dark_green\\\"},{\\\"text\\\":\\\"Gene Extractor\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_green\\\",\\\"clickEvent\\\":{\\\"action\\\":\\\"change_page\\\",\\\"value\\\":18}},{\\\"text\\\":\\\"\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"Cloning Pokemobs\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_purple\\\",\\\"clickEvent\\\":{\\\"action\\\":\\\"change_page\\\",\\\"value\\\":23}},{\\\"text\\\":\\\"\\\\n\\\",\\\"color\\\":\\\"reset\\\",\\\"underlined\\\":true},{\\\"text\\\":\\\"Splicing DNA\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"blue\\\",\\\"clickEvent\\\":{\\\"action\\\":\\\"change_page\\\",\\\"value\\\":25}}]\",\"[\\\"\\\",{\\\"text\\\":\\\"Basic Terminology\\\\n\\\\nExpressed Gene (EG):\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_red\\\"},{\\\"text\\\":\\\"\\\\nThis is the trait that shows on your mob.\\\\n\\\\n\\\",\\\"color\\\":\\\"dark_red\\\"},{\\\"text\\\":\\\"Parent Genes (PG):\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_red\\\"},{\\\"text\\\":\\\"\\\\nThese are the inherited genes which, when merged, result in the Expressed Gene. Each EG corresponds to 2 PGs\\\",\\\"color\\\":\\\"dark_red\\\"}]\",\"[\\\"\\\",{\\\"text\\\":\\\"Recessive:\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_red\\\"},{\\\"text\\\":\\\"\\\\nRecessive genes require both of the PGs to be the same for them to be expressed.\\\",\\\"color\\\":\\\"dark_red\\\"},{\\\"text\\\":\\\"\\\\n\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"Co-dominant\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_red\\\"},{\\\"text\\\":\\\"\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"Co-dominant genes will select a random PG for the EG.\\\",\\\"color\\\":\\\"dark_red\\\"}]\",\"[\\\"\\\",{\\\"text\\\":\\\"\\\\n\\\"},{\\\"text\\\":\\\"Epigenetic:\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_red\\\"},{\\\"text\\\":\\\"\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"If a gene is epigenetic, then instead of using a PG for inheritance, it will use the EG, and the EG will change based on the pokemob.\\\",\\\"color\\\":\\\"dark_red\\\"}]\",\"[\\\"\\\",{\\\"text\\\":\\\"Pokemob DNA\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_aqua\\\"},{\\\"text\\\":\\\"\\\\n\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"There are presently 9 known genes that Pokemobs can have.\\\\n\\\\nOf these 9, 2 are strictly Epigenetic, and 1 has a low chance of showing Epigenetic tendencies.\\\",\\\"color\\\":\\\"dark_aqua\\\"}]\",\"[\\\"\\\",{\\\"text\\\":\\\"The known Genes are:\\\",\\\"color\\\":\\\"dark_aqua\\\"},{\\\"text\\\":\\\"\\\\n\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"ability\\\",\\\"color\\\":\\\"dark_aqua\\\"},{\\\"text\\\":\\\"\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"colour\\\\nsize\\\\nnature\\\\nshiny\\\\nmoves*\\\\nivs\\\\nevs*\\\\nspecies\\\\n\\\\n*Epigenetic\\\",\\\"color\\\":\\\"dark_aqua\\\"}]\",\"{\\\"text\\\":\\\"Most of these genes appear to be Co-Dominant, with a low rate of mutation. The exceptions are listed below:\\\\n\\\\nNature\\\\nShiny\\\\nSpecies\\\\nMoves\\\",\\\"color\\\":\\\"dark_aqua\\\"}\",\"{\\\"text\\\":\\\"Nature Gene:\\\\n\\\\nThe nature gene appears to exhibit a merging effect rather than dominance, the EG will be a merge of the two PG, with a small chance of being entirely random instead.\\\",\\\"color\\\":\\\"dark_aqua\\\"}\",\"{\\\"text\\\":\\\"Shiny Gene:\\\\n\\\\nThe Shiny Gene appears to be a rare, recessive Gene. \\\\n\\\\nThe Shiny Charm seems to somehow force expression of this gene, without actually allowing it to be passed on.\\\",\\\"color\\\":\\\"dark_aqua\\\"}\",\"{\\\"text\\\":\\\"Species Gene:\\\\n\\\\nFor the Species Gene, it seems dominance is based on whether one of the genes is gendered. Genderless Species Genes are recessive.\\\\n\\\\nThis gene sometimes shows Epigenetic tendencies.\\\",\\\"color\\\":\\\"dark_aqua\\\"}\",\"{\\\"text\\\":\\\"Moves Gene:\\\\n\\\\nThe Moves Gene only seems to be expressed if both PG share a similarity in this gene. In most cases this is not the case.\\\",\\\"color\\\":\\\"dark_aqua\\\"}\",\"[\\\"\\\",{\\\"text\\\":\\\"Extracting DNA\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_green\\\"},{\\\"text\\\":\\\"\\\\n\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"DNA is Extracted via the Gene Extractor.\\\\n\\\\nThis process requires Power, a Bottle of Water (for DNA to go into), a Selector, and a DNA Source.\\\",\\\"color\\\":\\\"dark_green\\\"}]\",\"[\\\"\\\",{\\\"text\\\":\\\"DNA Selectors\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_green\\\"},{\\\"text\\\":\\\"\\\\n\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"DNA Selectors will let the machine know which Gene to target for Extraction or Splicing.\\\\n\\\\nThere are 2 ways to make a selector, via a Computer Interface (Open Computers) or via a written book.\\\",\\\"color\\\":\\\"dark_green\\\"}]\",\"{\\\"text\\\":\\\"A Book selector can be made by creating a written book named \\\\\\\"Selector\\\\\\\", then placing the name of each gene to select on a seperate line of the first page.\\\\n\\\\n\\\\\\\"all\\\\\\\" can also be used to select all genes.\\\",\\\"color\\\":\\\"dark_green\\\"}\",\"{\\\"text\\\":\\\"Book Selectors can then be crafted with various objects to change their chances of breaking themselves or the source of the DNA. The only currently known object for this is a nether star.\\\",\\\"color\\\":\\\"dark_green\\\"}\",\"[\\\"\\\",{\\\"text\\\":\\\"Gene Extractor\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_green\\\"},{\\\"text\\\":\\\"\\\\n\\\\nThe Gene Extractor is used to extract DNA from a source, and into a bottle. Known sources are:\\\\n\\\\nFilled Pokecubes\\\\nPokemob Eggs\\\\nFossils (only have species)\\\",\\\"color\\\":\\\"dark_green\\\"}]\",\"{\\\"text\\\":\\\"The slots in the Extractor are marked according to what should go in them, and it will automatically begin extraction as soon as the slots are filled.\\\\n\\\\nWhen using a computer to specify the Selector, no book is needed.\\\",\\\"color\\\":\\\"dark_green\\\"}\",\"{\\\"text\\\":\\\"The tooltip on the Selector will display the genes being selected, and will have 2 numbers at the bottom.\\\\n\\\\nThese numbers represent how unstable the selector is, larger numbers are bad, these numbers go from 0-1.\\\",\\\"color\\\":\\\"dark_green\\\"}\",\"{\\\"text\\\":\\\"The first number represents the chance of the selector breaking during extraction, and the second represents the chance the DNA source will break during extraction.\\\",\\\"color\\\":\\\"dark_green\\\"}\",\"{\\\"text\\\":\\\"The DNA source will also have a tooltip, which will display the EGs for the source. \\\\n\\\\nTo get information on the PGs, you need to use the computer interface.\\\",\\\"color\\\":\\\"dark_green\\\"}\",\"[\\\"\\\",{\\\"text\\\":\\\"Cloning Pokemobs\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"dark_purple\\\"},{\\\"text\\\":\\\"\\\\n\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"Once you have extracted some Species DNA, you can place the bottle of it in the bottle slot of the cloning device. The Egg slot needs to be provided with an egg as well, this can be any egg, even a chicken.\\\",\\\"color\\\":\\\"dark_purple\\\"}]\",\"{\\\"text\\\":\\\"The cloning process will require energy, and when complete, will result in a Pokemob infront of the device, usually at level 20.\\\\n\\\\nAny source of Species DNA should work, and if any other genes are present, they will be applied to the Pokemob.\\\",\\\"color\\\":\\\"dark_purple\\\"}\",\"[\\\"\\\",{\\\"text\\\":\\\"Splicing DNA\\\",\\\"underlined\\\":true,\\\"color\\\":\\\"blue\\\"},{\\\"text\\\":\\\"\\\\n\\\\n\\\",\\\"color\\\":\\\"reset\\\"},{\\\"text\\\":\\\"The Gene Splicer can be used to splice together DNA from different sources. The Selector used is the same as in the Gene Extractor, but now the destination and source slots can both take DNA.\\\",\\\"color\\\":\\\"blue\\\"}]\"],title:\"Pokemob Genetics\",author:Thutmose,display:{Lore:[\"Your Guide to Pokemob Genetics\"]}}" + "pokedex.inspect.geneticsguide": "§aYou recieved a Genetics Guide from the Pokédex." } diff --git a/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/glalie.x3d b/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/glalie.x3d index ba2b90c46a..1d19bb1a74 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/glalie.x3d +++ b/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/glalie.x3d @@ -1,9 +1,8 @@ - - + - + - - - + - + - - - + + + - - - + - + - - - + + + - - - + - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/glalie.xml b/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/glalie.xml index eea6be45be..d151595e6e 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/glalie.xml +++ b/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/glalie.xml @@ -1,7 +1,50 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/rayquaza_mega.xml b/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/rayquaza_mega.xml index 0b26a94c9e..758744e811 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/rayquaza_mega.xml +++ b/src/main/resources/assets/pokecube_mobs/gen_3/entity/models/rayquaza_mega.xml @@ -6,24 +6,30 @@ + + + + + + diff --git a/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalie.png b/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalie.png index e73b749c41..6c30e16720 100644 Binary files a/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalie.png and b/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalie.png differ diff --git a/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalieeye.png b/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalieeye.png new file mode 100644 index 0000000000..cb90c895aa Binary files /dev/null and b/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalieeye.png differ diff --git a/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalieeyes.png b/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalieeyes.png new file mode 100644 index 0000000000..0aa12f90e9 Binary files /dev/null and b/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalieeyes.png differ diff --git a/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalies.png b/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalies.png index 19831f26a1..3ce4a9d4a9 100644 Binary files a/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalies.png and b/src/main/resources/assets/pokecube_mobs/gen_3/entity/textures/glalies.png differ diff --git a/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/litwick.xml b/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/litwick.xml index 25c979b6d5..67f1a7e538 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/litwick.xml +++ b/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/litwick.xml @@ -6,7 +6,7 @@ - + diff --git a/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/reshiram.x3d b/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/reshiram.x3d index 7fac1890d7..9978efb47a 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/reshiram.x3d +++ b/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/reshiram.x3d @@ -1543,7 +1543,7 @@ > - + @@ -3475,7 +3475,7 @@ > - + @@ -3502,7 +3502,7 @@ > - + @@ -4094,7 +4094,7 @@ > - + @@ -5047,7 +5047,7 @@ > - + @@ -5074,7 +5074,7 @@ > - + diff --git a/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/virizion.x3d b/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/virizion.x3d index 2117450568..ad0e3e2ba8 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/virizion.x3d +++ b/src/main/resources/assets/pokecube_mobs/gen_5/entity/models/virizion.x3d @@ -58,11 +58,11 @@ - - - + + + diff --git a/src/main/resources/assets/pokecube_mobs/gen_5/entity/textures/reshirams.png b/src/main/resources/assets/pokecube_mobs/gen_5/entity/textures/reshirams.png index 0a4bc3861d..611d3a4ee2 100644 Binary files a/src/main/resources/assets/pokecube_mobs/gen_5/entity/textures/reshirams.png and b/src/main/resources/assets/pokecube_mobs/gen_5/entity/textures/reshirams.png differ diff --git a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/amaura.xml b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/amaura.xml index cd9780be1b..ad4b04023a 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/amaura.xml +++ b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/amaura.xml @@ -8,7 +8,7 @@ - + diff --git a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/aurorus.xml b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/aurorus.xml index eba362f67a..c595564e5c 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/aurorus.xml +++ b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/aurorus.xml @@ -8,7 +8,7 @@ - + diff --git a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/litleo.x3d b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/litleo.x3d index 9c08777a28..f1e3932e82 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/litleo.x3d +++ b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/litleo.x3d @@ -192,11 +192,11 @@ - - - + + + diff --git a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/yveltal.x3d b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/yveltal.x3d index 67682f7b4a..bcd7b34a82 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/yveltal.x3d +++ b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/yveltal.x3d @@ -2680,6 +2680,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/zygarde_10.xml b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/zygarde_10.xml index ed05bcbef6..b111aa08ca 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/zygarde_10.xml +++ b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/zygarde_10.xml @@ -3,6 +3,7 @@ + diff --git a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/zygarde_100.xml b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/zygarde_100.xml index 03c5af82ad..8905520d6c 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/zygarde_100.xml +++ b/src/main/resources/assets/pokecube_mobs/gen_6/entity/models/zygarde_100.xml @@ -24,7 +24,7 @@ - + diff --git a/src/main/resources/assets/pokecube_mobs/gen_7/entity/models/morelull.xml b/src/main/resources/assets/pokecube_mobs/gen_7/entity/models/morelull.xml index 180b1b90f3..d760087a9d 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_7/entity/models/morelull.xml +++ b/src/main/resources/assets/pokecube_mobs/gen_7/entity/models/morelull.xml @@ -7,7 +7,7 @@ - + diff --git a/src/main/resources/assets/pokecube_mobs/gen_7/entity/models/solgaleo_dusk.xml b/src/main/resources/assets/pokecube_mobs/gen_7/entity/models/solgaleo_dusk.xml index f532453f3a..9127458e2e 100644 --- a/src/main/resources/assets/pokecube_mobs/gen_7/entity/models/solgaleo_dusk.xml +++ b/src/main/resources/assets/pokecube_mobs/gen_7/entity/models/solgaleo_dusk.xml @@ -5,7 +5,7 @@ - + diff --git a/src/main/resources/data/pokecube_mobs/database/pokemobs/pokemobs_offsets.json b/src/main/resources/data/pokecube_mobs/database/pokemobs/pokemobs_offsets.json index 8a98820d93..4522d6bfbb 100644 --- a/src/main/resources/data/pokecube_mobs/database/pokemobs/pokemobs_offsets.json +++ b/src/main/resources/data/pokecube_mobs/database/pokemobs/pokemobs_offsets.json @@ -5,6 +5,10 @@ "name": "Doduo", "ridden_offsets": "0,0.25,-0.5" }, + { + "name": "Lapras", + "ridden_offsets": "0,0.4,0.0:0.5,0.4,0.0:-0.5,0.4,0" + }, { "name": "Rayquaza", "ridden_offsets": "0,0.75,0.15:0,0.75,0.0:0,0.75,-0.15"