From 007c6c5acec6fc24cb213b934e8abe19b948ad07 Mon Sep 17 00:00:00 2001 From: WayofTime Date: Tue, 16 Aug 2016 16:13:29 -0400 Subject: [PATCH] Corrosive Sentient Specters will steal the negative effects from the owner and attempt to apply them to other entities it attacks. --- .../ai/EntityAIGrabEffectsFromOwner.java | 160 ++++++++++++++++++ .../entity/mob/EntitySentientSpecter.java | 139 ++++++++++++++- .../item/soul/ItemSentientSword.java | 25 ++- .../util/handler/event/GenericHandler.java | 31 ++++ .../assets/bloodmagic/lang/en_US.lang | 3 + 5 files changed, 344 insertions(+), 14 deletions(-) create mode 100644 src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIGrabEffectsFromOwner.java diff --git a/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIGrabEffectsFromOwner.java b/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIGrabEffectsFromOwner.java new file mode 100644 index 00000000..04e5fc62 --- /dev/null +++ b/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIGrabEffectsFromOwner.java @@ -0,0 +1,160 @@ +package WayofTime.bloodmagic.entity.ai; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.pathfinding.PathNavigate; +import net.minecraft.pathfinding.PathNavigateGround; +import net.minecraft.pathfinding.PathNodeType; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; + +public class EntityAIGrabEffectsFromOwner extends EntityAIBase +{ + private EntitySentientSpecter thePet; + private EntityLivingBase theOwner; + World theWorld; + private double followSpeed; + private PathNavigate petPathfinder; + private int timeToRecalcPath; + float minDist; + private float oldWaterCost; + + /** + * In order to steal effects from the owner, the mob has to be close to the + * owner. + */ + public EntityAIGrabEffectsFromOwner(EntitySentientSpecter thePetIn, double followSpeedIn, float minDistIn) + { + this.thePet = thePetIn; + this.theWorld = thePetIn.worldObj; + this.followSpeed = followSpeedIn; + this.petPathfinder = thePetIn.getNavigator(); + this.minDist = minDistIn; + this.setMutexBits(3); + + if (!(thePetIn.getNavigator() instanceof PathNavigateGround)) + { + throw new IllegalArgumentException("Unsupported mob type for FollowOwnerGoal"); + } + } + + /** + * Returns whether the EntityAIBase should begin execution. + */ + public boolean shouldExecute() + { + EntityLivingBase entitylivingbase = this.thePet.getOwner(); + + if (entitylivingbase == null) + { + return false; + } else if (entitylivingbase instanceof EntityPlayer && ((EntityPlayer) entitylivingbase).isSpectator()) + { + return false; + } else if (this.thePet.isStationary()) + { + return false; +// } else if (this.thePet.getDistanceSqToEntity(entitylivingbase) < (double) (this.minDist * this.minDist)) +// { +// return false; + } else if (!this.thePet.canStealEffectFromOwner(entitylivingbase)) + { + return false; + } else + { + this.theOwner = entitylivingbase; + return true; + } + } + + /** + * Returns whether an in-progress EntityAIBase should continue executing + */ + public boolean continueExecuting() + { + return this.thePet.canStealEffectFromOwner(theOwner);// || !this.petPathfinder.noPath() && this.thePet.getDistanceSqToEntity(this.theOwner) > (double) (this.minDist * this.minDist) && !this.thePet.isStationary(); + } + + /** + * Execute a one shot task or start executing a continuous task + */ + public void startExecuting() + { + this.timeToRecalcPath = 0; + this.oldWaterCost = this.thePet.getPathPriority(PathNodeType.WATER); + this.thePet.setPathPriority(PathNodeType.WATER, 0.0F); + } + + /** + * Resets the task + */ + public void resetTask() + { + this.theOwner = null; + this.petPathfinder.clearPathEntity(); + this.thePet.setPathPriority(PathNodeType.WATER, this.oldWaterCost); + } + + private boolean isEmptyBlock(BlockPos pos) + { + IBlockState iblockstate = this.theWorld.getBlockState(pos); + Block block = iblockstate.getBlock(); + return block == Blocks.AIR ? true : !iblockstate.isFullCube(); + } + + /** + * Updates the task + */ + public void updateTask() + { + this.thePet.getLookHelper().setLookPositionWithEntity(this.theOwner, 10.0F, (float) this.thePet.getVerticalFaceSpeed()); + + if (this.thePet.getDistanceSqToEntity(theOwner) < this.minDist * this.minDist) + { + if (this.thePet.stealEffectsFromOwner(theOwner)) + { + return; + } + } + + if (!this.thePet.isStationary()) + { + if (--this.timeToRecalcPath <= 0) + { + this.timeToRecalcPath = 10; + + if (!this.petPathfinder.tryMoveToEntityLiving(this.theOwner, this.followSpeed)) + { + if (!this.thePet.getLeashed()) + { + if (this.thePet.getDistanceSqToEntity(this.theOwner) >= 144.0D) + { + int i = MathHelper.floor_double(this.theOwner.posX) - 2; + int j = MathHelper.floor_double(this.theOwner.posZ) - 2; + int k = MathHelper.floor_double(this.theOwner.getEntityBoundingBox().minY); + + for (int l = 0; l <= 4; ++l) + { + for (int i1 = 0; i1 <= 4; ++i1) + { + if ((l < 1 || i1 < 1 || l > 3 || i1 > 3) && this.theWorld.getBlockState(new BlockPos(i + l, k - 1, j + i1)).isFullyOpaque() && this.isEmptyBlock(new BlockPos(i + l, k, j + i1)) && this.isEmptyBlock(new BlockPos(i + l, k + 1, j + i1))) + { + this.thePet.setLocationAndAngles((double) ((float) (i + l) + 0.5F), (double) k, (double) ((float) (j + i1) + 0.5F), this.thePet.rotationYaw, this.thePet.rotationPitch); + this.petPathfinder.clearPathEntity(); + return; + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/WayofTime/bloodmagic/entity/mob/EntitySentientSpecter.java b/src/main/java/WayofTime/bloodmagic/entity/mob/EntitySentientSpecter.java index 3675975b..7586ab5c 100644 --- a/src/main/java/WayofTime/bloodmagic/entity/mob/EntitySentientSpecter.java +++ b/src/main/java/WayofTime/bloodmagic/entity/mob/EntitySentientSpecter.java @@ -1,9 +1,14 @@ package WayofTime.bloodmagic.entity.mob; +import java.util.ArrayList; +import java.util.Iterator; import java.util.UUID; +import lombok.Getter; +import lombok.Setter; import net.minecraft.block.Block; import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityOwnable; import net.minecraft.entity.SharedMonsterAttributes; @@ -19,7 +24,6 @@ import net.minecraft.entity.monster.EntityGhast; import net.minecraft.entity.monster.EntityMob; import net.minecraft.entity.passive.EntityHorse; import net.minecraft.entity.passive.EntityTameable; -import net.minecraft.entity.passive.EntityWolf; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.projectile.EntityTippedArrow; import net.minecraft.init.Enchantments; @@ -38,9 +42,13 @@ import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.EnumDifficulty; +import net.minecraft.world.Explosion; import net.minecraft.world.World; +import WayofTime.bloodmagic.api.Constants; +import WayofTime.bloodmagic.api.soul.EnumDemonWillType; import WayofTime.bloodmagic.entity.ai.EntityAIAttackRangedBow; import WayofTime.bloodmagic.entity.ai.EntityAIFollowOwner; +import WayofTime.bloodmagic.entity.ai.EntityAIGrabEffectsFromOwner; import WayofTime.bloodmagic.entity.ai.EntityAIOwnerHurtByTarget; import WayofTime.bloodmagic.entity.ai.EntityAIOwnerHurtTarget; import WayofTime.bloodmagic.item.soul.ItemSentientBow; @@ -53,6 +61,10 @@ public class EntitySentientSpecter extends EntityMob implements IEntityOwnable protected static final DataParameter TAMED = EntityDataManager.createKey(EntityTameable.class, DataSerializers.BYTE); protected static final DataParameter> OWNER_UNIQUE_ID = EntityDataManager.>createKey(EntityTameable.class, DataSerializers.OPTIONAL_UNIQUE_ID); + @Getter + @Setter + protected EnumDemonWillType type = EnumDemonWillType.DESTRUCTIVE; + private final EntityAIAttackRangedBow aiArrowAttack = new EntityAIAttackRangedBow(this, 1.0D, 20, 15.0F); private final EntityAIAttackMelee aiAttackOnCollide = new EntityAIAttackMelee(this, 1.0D, false); @@ -65,7 +77,8 @@ public class EntitySentientSpecter extends EntityMob implements IEntityOwnable // ((PathNavigateGround) getNavigator()).setCanSwim(false); this.tasks.addTask(0, new EntityAISwimming(this)); this.tasks.addTask(attackPriority, aiAttackOnCollide); - this.tasks.addTask(3, new EntityAIFollowOwner(this, 1.0D, 10.0F, 2.0F)); + this.tasks.addTask(3, new EntityAIGrabEffectsFromOwner(this, 2.0D, 1.0F)); + this.tasks.addTask(4, new EntityAIFollowOwner(this, 1.0D, 10.0F, 2.0F)); this.tasks.addTask(5, new EntityAIWander(this, 1.0D)); this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F)); this.tasks.addTask(7, new EntityAILookIdle(this)); @@ -123,6 +136,107 @@ public class EntitySentientSpecter extends EntityMob implements IEntityOwnable } } + public boolean canStealEffectFromOwner(EntityLivingBase owner, PotionEffect effect) + { + return effect.getPotion().isBadEffect() && this.type == EnumDemonWillType.CORROSIVE; + } + + public boolean canStealEffectFromOwner(EntityLivingBase owner) + { + if (this.type == EnumDemonWillType.CORROSIVE) + { + return false; + } + + for (PotionEffect eff : owner.getActivePotionEffects()) + { + if (canStealEffectFromOwner(owner, eff)) + { + return true; + } + } + + return false; + } + + public boolean stealEffectsFromOwner(EntityLivingBase owner) + { + if (this.type == EnumDemonWillType.CORROSIVE) + { + return false; + } + + boolean hasStolenEffect = false; + Iterator itr = new ArrayList(owner.getActivePotionEffects()).iterator(); + while (itr.hasNext()) + { + PotionEffect eff = itr.next(); + if (canStealEffectFromOwner(owner, eff)) + { + owner.removePotionEffect(eff.getPotion()); + this.addPotionEffect(eff); + hasStolenEffect = true; + } + } + + return hasStolenEffect; + } + + public boolean applyNegativeEffectsToAttacked(EntityLivingBase attackedEntity, float percentTransmitted) + { + boolean hasProvidedEffect = false; + Iterator itr = new ArrayList(this.getActivePotionEffects()).iterator(); + while (itr.hasNext()) + { + PotionEffect eff = itr.next(); + if (attackedEntity.isPotionApplicable(eff)) + { + if (!attackedEntity.isPotionActive(eff.getPotion())) + { + PotionEffect newEffect = new PotionEffect(eff.getPotion(), (int) (eff.getDuration() * percentTransmitted), eff.getAmplifier(), eff.getIsAmbient(), eff.doesShowParticles()); + attackedEntity.addPotionEffect(newEffect); + + PotionEffect newSentientEffect = new PotionEffect(eff.getPotion(), (int) (eff.getDuration() * (1 - percentTransmitted)), eff.getAmplifier(), eff.getIsAmbient(), eff.doesShowParticles()); + this.removePotionEffect(eff.getPotion()); + this.addPotionEffect(newSentientEffect); + hasProvidedEffect = true; + } else + { + PotionEffect activeEffect = attackedEntity.getActivePotionEffect(eff.getPotion()); + if (activeEffect.getAmplifier() < eff.getAmplifier() || activeEffect.getDuration() < eff.getDuration() * percentTransmitted) + { + PotionEffect newEffect = new PotionEffect(eff.getPotion(), (int) (eff.getDuration() * percentTransmitted), eff.getAmplifier(), activeEffect.getIsAmbient(), activeEffect.doesShowParticles()); + attackedEntity.addPotionEffect(newEffect); + + PotionEffect newSentientEffect = new PotionEffect(eff.getPotion(), (int) (eff.getDuration() * (1 - percentTransmitted)), eff.getAmplifier(), eff.getIsAmbient(), eff.doesShowParticles()); + this.removePotionEffect(eff.getPotion()); + this.addPotionEffect(newSentientEffect); + hasProvidedEffect = true; + } + } + } + } + return hasProvidedEffect; + } + + @Override + public boolean attackEntityAsMob(Entity attackedEntity) + { + if (super.attackEntityAsMob(attackedEntity)) + { + if (this.type == EnumDemonWillType.CORROSIVE && attackedEntity instanceof EntityLivingBase) + { +// ((EntityLivingBase) attackedEntity).addPotionEffect(new PotionEffect(MobEffects.WITHER, 200)); + applyNegativeEffectsToAttacked((EntityLivingBase) attackedEntity, 1); + } + + return true; + } else + { + return false; + } + } + @Override public void setItemStackToSlot(EntityEquipmentSlot slotIn, ItemStack stack) { @@ -139,6 +253,11 @@ public class EntitySentientSpecter extends EntityMob implements IEntityOwnable return false; } + public boolean absorbExplosion(Explosion explosion) + { + return true; + } + @Override protected boolean canDespawn() { @@ -158,6 +277,8 @@ public class EntitySentientSpecter extends EntityMob implements IEntityOwnable { tag.setString("OwnerUUID", this.getOwnerId().toString()); } + + tag.setString(Constants.NBT.WILL_TYPE, type.toString()); } @Override @@ -188,6 +309,14 @@ public class EntitySentientSpecter extends EntityMob implements IEntityOwnable } } + if (!tag.hasKey(Constants.NBT.WILL_TYPE)) + { + type = EnumDemonWillType.DEFAULT; + } else + { + type = EnumDemonWillType.valueOf(tag.getString(Constants.NBT.WILL_TYPE)); + } + this.setCombatTask(); } @@ -196,11 +325,11 @@ public class EntitySentientSpecter extends EntityMob implements IEntityOwnable { if (!(attacker instanceof EntityCreeper) && !(attacker instanceof EntityGhast)) { - if (attacker instanceof EntityWolf) + if (attacker instanceof IEntityOwnable) { - EntityWolf entitywolf = (EntityWolf) attacker; + IEntityOwnable entityOwnable = (IEntityOwnable) attacker; - if (entitywolf.isTamed() && entitywolf.getOwner() == owner) + if (entityOwnable.getOwner() == owner) { return false; } diff --git a/src/main/java/WayofTime/bloodmagic/item/soul/ItemSentientSword.java b/src/main/java/WayofTime/bloodmagic/item/soul/ItemSentientSword.java index cfc91067..20131d60 100644 --- a/src/main/java/WayofTime/bloodmagic/item/soul/ItemSentientSword.java +++ b/src/main/java/WayofTime/bloodmagic/item/soul/ItemSentientSword.java @@ -90,8 +90,13 @@ public class ItemSentientSword extends ItemSword implements IDemonWillWeapon, IM { EnumDemonWillType type = PlayerDemonWillHandler.getLargestWillType(player); double soulsRemaining = PlayerDemonWillHandler.getTotalDemonWill(type, player); - this.setCurrentType(stack, soulsRemaining > 0 ? type : EnumDemonWillType.DEFAULT); - int level = getLevel(stack, soulsRemaining); + recalculatePowers(stack, type, soulsRemaining); + } + + public void recalculatePowers(ItemStack stack, EnumDemonWillType type, double will) + { + this.setCurrentType(stack, will > 0 ? type : EnumDemonWillType.DEFAULT); + int level = getLevel(stack, will); double drain = level >= 0 ? soulDrainPerSwing[level] : 0; double extraDamage = getExtraDamage(type, level); @@ -254,14 +259,16 @@ public class ItemSentientSword extends ItemSword implements IDemonWillWeapon, IM world.spawnEntityInWorld(specterEntity); System.out.println("Spawning Specter..."); - ItemStack bowStack = new ItemStack(ModItems.sentientBow); - ((ItemSentientBow) ModItems.sentientBow).recalculatePowers(bowStack, EnumDemonWillType.DEFAULT, 1025); +// ItemStack bowStack = new ItemStack(ModItems.sentientBow); +// ((ItemSentientBow) ModItems.sentientBow).recalculatePowers(bowStack, EnumDemonWillType.DEFAULT, 1025); - specterEntity.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, bowStack); - specterEntity.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(ModItems.sentientArmourHelmet)); - specterEntity.setItemStackToSlot(EntityEquipmentSlot.CHEST, new ItemStack(ModItems.sentientArmourChest)); - specterEntity.setItemStackToSlot(EntityEquipmentSlot.LEGS, new ItemStack(ModItems.sentientArmourLegs)); - specterEntity.setItemStackToSlot(EntityEquipmentSlot.FEET, new ItemStack(ModItems.sentientArmourBoots)); +// specterEntity.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, bowStack); + specterEntity.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, stack.copy()); +// specterEntity.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(ModItems.sentientArmourHelmet)); +// specterEntity.setItemStackToSlot(EntityEquipmentSlot.CHEST, new ItemStack(ModItems.sentientArmourChest)); +// specterEntity.setItemStackToSlot(EntityEquipmentSlot.LEGS, new ItemStack(ModItems.sentientArmourLegs)); +// specterEntity.setItemStackToSlot(EntityEquipmentSlot.FEET, new ItemStack(ModItems.sentientArmourBoots)); + specterEntity.setType(this.getCurrentType(stack)); specterEntity.setOwner(player); specterEntity.setTamed(true); } diff --git a/src/main/java/WayofTime/bloodmagic/util/handler/event/GenericHandler.java b/src/main/java/WayofTime/bloodmagic/util/handler/event/GenericHandler.java index 5ae04283..62124de5 100644 --- a/src/main/java/WayofTime/bloodmagic/util/handler/event/GenericHandler.java +++ b/src/main/java/WayofTime/bloodmagic/util/handler/event/GenericHandler.java @@ -1,5 +1,7 @@ package WayofTime.bloodmagic.util.handler.event; +import java.util.List; + import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.enchantment.EnchantmentHelper; @@ -15,7 +17,11 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.Explosion; +import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.living.LivingDropsEvent; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; @@ -23,6 +29,7 @@ import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerPickupXpEvent; +import net.minecraftforge.event.world.ExplosionEvent; import net.minecraftforge.fml.common.eventhandler.Event.Result; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -45,6 +52,7 @@ import WayofTime.bloodmagic.api.util.helper.NetworkHelper; import WayofTime.bloodmagic.api.util.helper.PlayerHelper; import WayofTime.bloodmagic.block.BlockAltar; import WayofTime.bloodmagic.demonAura.WorldDemonWillHandler; +import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; import WayofTime.bloodmagic.item.ItemAltarMaker; import WayofTime.bloodmagic.item.ItemExperienceBook; import WayofTime.bloodmagic.item.armour.ItemLivingArmour; @@ -79,6 +87,29 @@ public class GenericHandler } } + @SubscribeEvent + public void onExplosion(ExplosionEvent.Start event) + { + World world = event.getWorld(); + Explosion exp = event.getExplosion(); + Vec3d position = exp.getPosition(); + double radius = 3; + + AxisAlignedBB bb = new AxisAlignedBB(position.xCoord - radius, position.yCoord - radius, position.zCoord - radius, position.xCoord + radius, position.yCoord + radius, position.zCoord + radius); + List specterList = world.getEntitiesWithinAABB(EntitySentientSpecter.class, bb); + if (!specterList.isEmpty()) + { + for (EntitySentientSpecter specter : specterList) + { + if (specter.absorbExplosion(exp)) + { + event.setCanceled(true); + return; + } + } + } + } + @SubscribeEvent public void onEntityHurt(LivingHurtEvent event) { diff --git a/src/main/resources/assets/bloodmagic/lang/en_US.lang b/src/main/resources/assets/bloodmagic/lang/en_US.lang index 9e201d3d..a544e076 100644 --- a/src/main/resources/assets/bloodmagic/lang/en_US.lang +++ b/src/main/resources/assets/bloodmagic/lang/en_US.lang @@ -583,6 +583,9 @@ chat.BloodMagic.altar.comp.notair=a solid block chat.BloodMagic.altar.nextTier=The next tier of blood altar is missing %s at %s. +# entity +entity.BloodMagic.SentientSpecter.name=Sentient Specter + # sekrit secret.BloodMagic.bread.bloody=&r&cBloody Bread