diff --git a/src/main/java/WayofTime/bloodmagic/client/render/entity/RenderSentientSpecter.java b/src/main/java/WayofTime/bloodmagic/client/render/entity/RenderSentientSpecter.java index bae76231..ec32cddd 100644 --- a/src/main/java/WayofTime/bloodmagic/client/render/entity/RenderSentientSpecter.java +++ b/src/main/java/WayofTime/bloodmagic/client/render/entity/RenderSentientSpecter.java @@ -23,7 +23,7 @@ public class RenderSentientSpecter extends RenderBiped public RenderSentientSpecter(RenderManager renderManager) { - super(renderManager, new ModelBiped(0.0F), 0.5F); + super(renderManager, new ModelBiped(0.0F), 0.1F); this.addLayer(new LayerBipedArmor(this)); this.addLayer(new LayerHeldItem(this)); this.addLayer(new LayerArrow(this)); diff --git a/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIAttackRangedBow.java b/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIAttackRangedBow.java new file mode 100644 index 00000000..ebc0919d --- /dev/null +++ b/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIAttackRangedBow.java @@ -0,0 +1,167 @@ +package WayofTime.bloodmagic.entity.ai; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.item.ItemBow; +import net.minecraft.util.EnumHand; +import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; + +public class EntityAIAttackRangedBow extends EntityAIBase +{ + private final EntitySentientSpecter entity; + private final double moveSpeedAmp; + private int attackCooldown; + private final float maxAttackDistance; + private int attackTime = -1; + private int seeTime; + private boolean strafingClockwise; + private boolean strafingBackwards; + private int strafingTime = -1; + + public EntityAIAttackRangedBow(EntitySentientSpecter specter, double speedAmplifier, int delay, float maxDistance) + { + this.entity = specter; + this.moveSpeedAmp = speedAmplifier; + this.attackCooldown = delay; + this.maxAttackDistance = maxDistance * maxDistance; + this.setMutexBits(3); + } + + public void setAttackCooldown(int p_189428_1_) + { + this.attackCooldown = p_189428_1_; + } + + /** + * Returns whether the EntityAIBase should begin execution. + */ + public boolean shouldExecute() + { + return this.entity.getAttackTarget() == null ? false : this.isBowInMainhand(); + } + + protected boolean isBowInMainhand() + { + return this.entity.getHeldItemMainhand() != null && this.entity.getHeldItemMainhand().getItem() instanceof ItemBow; + } + + /** + * Returns whether an in-progress EntityAIBase should continue executing + */ + public boolean continueExecuting() + { + return (this.shouldExecute() || !this.entity.getNavigator().noPath()) && this.isBowInMainhand(); + } + + /** + * Execute a one shot task or start executing a continuous task + */ + public void startExecuting() + { + super.startExecuting(); +// this.entity.setSwingingArms(true); + } + + /** + * Resets the task + */ + public void resetTask() + { + super.startExecuting(); +// this.entity.setSwingingArms(false); + this.seeTime = 0; + this.attackTime = -1; + this.entity.resetActiveHand(); + } + + /** + * Updates the task + */ + public void updateTask() + { + EntityLivingBase entitylivingbase = this.entity.getAttackTarget(); + + if (entitylivingbase != null) + { + double d0 = this.entity.getDistanceSq(entitylivingbase.posX, entitylivingbase.getEntityBoundingBox().minY, entitylivingbase.posZ); + boolean flag = this.entity.getEntitySenses().canSee(entitylivingbase); + boolean flag1 = this.seeTime > 0; + + if (flag != flag1) + { + this.seeTime = 0; + } + + if (flag) + { + ++this.seeTime; + } else + { + --this.seeTime; + } + + if (d0 <= (double) this.maxAttackDistance && this.seeTime >= 20) + { + this.entity.getNavigator().clearPathEntity(); + ++this.strafingTime; + } else + { + this.entity.getNavigator().tryMoveToEntityLiving(entitylivingbase, this.moveSpeedAmp); + this.strafingTime = -1; + } + + if (this.strafingTime >= 20) + { + if ((double) this.entity.getRNG().nextFloat() < 0.3D) + { + this.strafingClockwise = !this.strafingClockwise; + } + + if ((double) this.entity.getRNG().nextFloat() < 0.3D) + { + this.strafingBackwards = !this.strafingBackwards; + } + + this.strafingTime = 0; + } + + if (this.strafingTime > -1) + { + if (d0 > (double) (this.maxAttackDistance * 0.75F)) + { + this.strafingBackwards = false; + } else if (d0 < (double) (this.maxAttackDistance * 0.25F)) + { + this.strafingBackwards = true; + } + + this.entity.getMoveHelper().strafe(this.strafingBackwards ? -0.5F : 0.5F, this.strafingClockwise ? 0.5F : -0.5F); + this.entity.faceEntity(entitylivingbase, 30.0F, 30.0F); + } else + { + this.entity.getLookHelper().setLookPositionWithEntity(entitylivingbase, 30.0F, 30.0F); + } + + if (this.entity.isHandActive()) + { + if (!flag && this.seeTime < -60) + { + this.entity.resetActiveHand(); + } else if (flag) + { + int i = this.entity.getItemInUseMaxCount(); + + if (i >= 20) + { + this.entity.resetActiveHand(); + this.entity.attackEntityWithRangedAttack(entitylivingbase, ItemBow.getArrowVelocity(i)); + this.attackTime = this.attackCooldown; + } + } + } else if (--this.attackTime <= 0 && this.seeTime >= -60) + { + this.entity.setActiveHand(EnumHand.MAIN_HAND); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIFollowOwner.java b/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIFollowOwner.java new file mode 100644 index 00000000..db3d437c --- /dev/null +++ b/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIFollowOwner.java @@ -0,0 +1,147 @@ +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 EntityAIFollowOwner extends EntityAIBase +{ + private EntitySentientSpecter thePet; + private EntityLivingBase theOwner; + World theWorld; + private double followSpeed; + private PathNavigate petPathfinder; + private int timeToRecalcPath; + float maxDist; + float minDist; + private float oldWaterCost; + + public EntityAIFollowOwner(EntitySentientSpecter thePetIn, double followSpeedIn, float minDistIn, float maxDistIn) + { + this.thePet = thePetIn; + this.theWorld = thePetIn.worldObj; + this.followSpeed = followSpeedIn; + this.petPathfinder = thePetIn.getNavigator(); + this.minDist = minDistIn; + this.maxDist = maxDistIn; + 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 + { + this.theOwner = entitylivingbase; + return true; + } + } + + /** + * Returns whether an in-progress EntityAIBase should continue executing + */ + public boolean continueExecuting() + { + return !this.petPathfinder.noPath() && this.thePet.getDistanceSqToEntity(this.theOwner) > (double) (this.maxDist * this.maxDist) && !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.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/ai/EntityAIOwnerHurtByTarget.java b/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIOwnerHurtByTarget.java new file mode 100644 index 00000000..004db27d --- /dev/null +++ b/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIOwnerHurtByTarget.java @@ -0,0 +1,59 @@ +package WayofTime.bloodmagic.entity.ai; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAITarget; +import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; + +public class EntityAIOwnerHurtByTarget extends EntityAITarget +{ + EntitySentientSpecter theDefendingTameable; + EntityLivingBase theOwnerAttacker; + private int timestamp; + + public EntityAIOwnerHurtByTarget(EntitySentientSpecter theDefendingTameableIn) + { + super(theDefendingTameableIn, false); + this.theDefendingTameable = theDefendingTameableIn; + this.setMutexBits(1); + } + + /** + * Returns whether the EntityAIBase should begin execution. + */ + public boolean shouldExecute() + { + if (!this.theDefendingTameable.isTamed()) + { + return false; + } else + { + EntityLivingBase owner = this.theDefendingTameable.getOwner(); + + if (owner == null) + { + return false; + } else + { + this.theOwnerAttacker = owner.getAITarget(); + int i = owner.getRevengeTimer(); + return i != this.timestamp && this.isSuitableTarget(this.theOwnerAttacker, false) && this.theDefendingTameable.shouldAttackEntity(this.theOwnerAttacker, owner); + } + } + } + + /** + * Execute a one shot task or start executing a continuous task + */ + public void startExecuting() + { + this.taskOwner.setAttackTarget(this.theOwnerAttacker); + EntityLivingBase owner = this.theDefendingTameable.getOwner(); + + if (owner != null) + { + this.timestamp = owner.getRevengeTimer(); + } + + super.startExecuting(); + } +} \ No newline at end of file diff --git a/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIOwnerHurtTarget.java b/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIOwnerHurtTarget.java new file mode 100644 index 00000000..cf65a828 --- /dev/null +++ b/src/main/java/WayofTime/bloodmagic/entity/ai/EntityAIOwnerHurtTarget.java @@ -0,0 +1,59 @@ +package WayofTime.bloodmagic.entity.ai; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.EntityAITarget; +import WayofTime.bloodmagic.entity.mob.EntitySentientSpecter; + +public class EntityAIOwnerHurtTarget extends EntityAITarget +{ + EntitySentientSpecter theEntitySentientSpecter; + EntityLivingBase theTarget; + private int timestamp; + + public EntityAIOwnerHurtTarget(EntitySentientSpecter theEntitySentientSpecterIn) + { + super(theEntitySentientSpecterIn, false); + this.theEntitySentientSpecter = theEntitySentientSpecterIn; + this.setMutexBits(1); + } + + /** + * Returns whether the EntityAIBase should begin execution. + */ + public boolean shouldExecute() + { + if (!this.theEntitySentientSpecter.isTamed()) + { + return false; + } else + { + EntityLivingBase entitylivingbase = this.theEntitySentientSpecter.getOwner(); + + if (entitylivingbase == null) + { + return false; + } else + { + this.theTarget = entitylivingbase.getLastAttacker(); + int i = entitylivingbase.getLastAttackerTime(); + return i != this.timestamp && this.isSuitableTarget(this.theTarget, false) && this.theEntitySentientSpecter.shouldAttackEntity(this.theTarget, entitylivingbase); + } + } + } + + /** + * Execute a one shot task or start executing a continuous task + */ + public void startExecuting() + { + this.taskOwner.setAttackTarget(this.theTarget); + EntityLivingBase entitylivingbase = this.theEntitySentientSpecter.getOwner(); + + if (entitylivingbase != null) + { + this.timestamp = entitylivingbase.getLastAttackerTime(); + } + + super.startExecuting(); + } +} \ 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 2f2575ee..3746518d 100644 --- a/src/main/java/WayofTime/bloodmagic/entity/mob/EntitySentientSpecter.java +++ b/src/main/java/WayofTime/bloodmagic/entity/mob/EntitySentientSpecter.java @@ -1,6 +1,11 @@ package WayofTime.bloodmagic.entity.mob; +import java.util.UUID; + import net.minecraft.block.Block; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityOwnable; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAIAttackMelee; import net.minecraft.entity.ai.EntityAIHurtByTarget; @@ -9,39 +14,78 @@ import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.ai.EntityAISwimming; import net.minecraft.entity.ai.EntityAIWander; import net.minecraft.entity.ai.EntityAIWatchClosest; -import net.minecraft.entity.item.EntityBoat; +import net.minecraft.entity.monster.EntityCreeper; +import net.minecraft.entity.monster.EntityGhast; import net.minecraft.entity.monster.EntityMob; -import net.minecraft.entity.passive.EntityAnimal; -import net.minecraft.entity.passive.EntityVillager; +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; +import net.minecraft.init.Items; +import net.minecraft.init.MobEffects; import net.minecraft.init.SoundEvents; import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.ItemBow; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.pathfinding.PathNavigateGround; +import net.minecraft.network.datasync.DataParameter; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.potion.PotionEffect; +import net.minecraft.server.management.PreYggdrasilConverter; +import net.minecraft.util.EnumHand; 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.World; +import WayofTime.bloodmagic.entity.ai.EntityAIAttackRangedBow; +import WayofTime.bloodmagic.entity.ai.EntityAIFollowOwner; +import WayofTime.bloodmagic.entity.ai.EntityAIOwnerHurtByTarget; +import WayofTime.bloodmagic.entity.ai.EntityAIOwnerHurtTarget; -public class EntitySentientSpecter extends EntityMob +import com.google.common.base.Optional; + +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); + + private final EntityAIAttackRangedBow aiArrowAttack = new EntityAIAttackRangedBow(this, 1.0D, 20, 15.0F); + private final EntityAIAttackMelee aiAttackOnCollide = new EntityAIAttackMelee(this, 1.0D, false); + + private final int attackPriority = 2; + public EntitySentientSpecter(World worldIn) { super(worldIn); this.setSize(0.6F, 1.95F); // ((PathNavigateGround) getNavigator()).setCanSwim(false); this.tasks.addTask(0, new EntityAISwimming(this)); - this.tasks.addTask(2, new EntityAIAttackMelee(this, 1, false)); -// this.tasks.addTask(2, new AIAttackOnCollide(this, EntityPlayer.class, 1.0D, false)); -// this.tasks.addTask(3, new AIAttackOnCollide(this, EntityVillager.class, 1.0D, true)); + this.tasks.addTask(attackPriority, aiAttackOnCollide); + this.tasks.addTask(3, 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)); -// this.tasks.addTask(8, new AIAttackOnCollide(this, EntityAnimal.class, 1.0D, false)); - this.targetTasks.addTask(0, new EntityAIHurtByTarget(this, true, new Class[0])); - this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, true)); - this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityVillager.class, false)); - this.targetTasks.addTask(8, new EntityAINearestAttackableTarget(this, EntityAnimal.class, false)); + + this.targetTasks.addTask(1, new EntityAIOwnerHurtByTarget(this)); + this.targetTasks.addTask(2, new EntityAIOwnerHurtTarget(this)); + this.targetTasks.addTask(3, new EntityAINearestAttackableTarget(this, EntityPlayer.class, true)); + + this.targetTasks.addTask(3, new EntityAIHurtByTarget(this, true, new Class[0])); + + this.setCombatTask(); +// this.targetTasks.addTask(8, new EntityAINearestAttackableTarget(this, EntityAnimal.class, false)); + } + + @Override + protected void entityInit() + { + super.entityInit(); + this.dataManager.register(TAMED, Byte.valueOf((byte) 0)); + this.dataManager.register(OWNER_UNIQUE_ID, Optional.absent()); } @Override @@ -53,16 +97,184 @@ public class EntitySentientSpecter extends EntityMob getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.27D); } + public void setCombatTask() + { + if (this.worldObj != null && !this.worldObj.isRemote) + { + this.tasks.removeTask(this.aiAttackOnCollide); + this.tasks.removeTask(this.aiArrowAttack); + ItemStack itemstack = this.getHeldItemMainhand(); + + if (itemstack != null && itemstack.getItem() instanceof ItemBow) + { + int i = 20; + + if (this.worldObj.getDifficulty() != EnumDifficulty.HARD) + { + i = 40; + } + + this.aiArrowAttack.setAttackCooldown(i); + this.tasks.addTask(attackPriority, this.aiArrowAttack); + } else + { + this.tasks.addTask(attackPriority, this.aiAttackOnCollide); + } + } + } + + @Override + public void setItemStackToSlot(EntityEquipmentSlot slotIn, ItemStack stack) + { + super.setItemStackToSlot(slotIn, stack); + + if (!this.worldObj.isRemote && slotIn == EntityEquipmentSlot.MAINHAND) + { + this.setCombatTask(); + } + } + + public boolean isStationary() + { + return false; + } + + @Override + protected boolean canDespawn() + { + //TODO: Change so that it despawns if not tamed after testing. + return false; + } + @Override public void writeEntityToNBT(NBTTagCompound tag) { super.writeEntityToNBT(tag); + + if (this.getOwnerId() == null) + { + tag.setString("OwnerUUID", ""); + } else + { + tag.setString("OwnerUUID", this.getOwnerId().toString()); + } } @Override public void readEntityFromNBT(NBTTagCompound tag) { super.readEntityFromNBT(tag); + + String s = ""; + + if (tag.hasKey("OwnerUUID", 8)) + { + s = tag.getString("OwnerUUID"); + } else + { + String s1 = tag.getString("Owner"); + s = PreYggdrasilConverter.convertMobOwnerIfNeeded(this.getServer(), s1); + } + + if (!s.isEmpty()) + { + try + { + this.setOwnerId(UUID.fromString(s)); + this.setTamed(true); + } catch (Throwable var4) + { + this.setTamed(false); + } + } + + this.setCombatTask(); + } + + //TODO: Change to fit the given AI + public boolean shouldAttackEntity(EntityLivingBase attacker, EntityLivingBase owner) + { + if (!(attacker instanceof EntityCreeper) && !(attacker instanceof EntityGhast)) + { + if (attacker instanceof EntityWolf) + { + EntityWolf entitywolf = (EntityWolf) attacker; + + if (entitywolf.isTamed() && entitywolf.getOwner() == owner) + { + return false; + } + } + + return attacker instanceof EntityPlayer && owner instanceof EntityPlayer && !((EntityPlayer) owner).canAttackPlayer((EntityPlayer) attacker) ? false : !(attacker instanceof EntityHorse) || !((EntityHorse) attacker).isTame(); + } else + { + return false; + } + } + + public void attackEntityWithRangedAttack(EntityLivingBase target, float p_82196_2_) + { + EntityTippedArrow entitytippedarrow = new EntityTippedArrow(this.worldObj, this); //TODO: Change to an arrow created by the Sentient Bow + double d0 = target.posX - this.posX; + double d1 = target.getEntityBoundingBox().minY + (double) (target.height / 3.0F) - entitytippedarrow.posY; + double d2 = target.posZ - this.posZ; + double d3 = (double) MathHelper.sqrt_double(d0 * d0 + d2 * d2); + entitytippedarrow.setThrowableHeading(d0, d1 + d3 * 0.2, d2, 1.6F, (float) (14 - this.worldObj.getDifficulty().getDifficultyId() * 4)); + int i = EnchantmentHelper.getMaxEnchantmentLevel(Enchantments.POWER, this); + int j = EnchantmentHelper.getMaxEnchantmentLevel(Enchantments.PUNCH, this); + entitytippedarrow.setDamage((double) (p_82196_2_ * 2.0F) + this.rand.nextGaussian() * 0.25D + (double) ((float) this.worldObj.getDifficulty().getDifficultyId() * 0.11F)); + + if (i > 0) + { + entitytippedarrow.setDamage(entitytippedarrow.getDamage() + (double) i * 0.5D + 0.5D); + } + + if (j > 0) + { + entitytippedarrow.setKnockbackStrength(j); + } + + boolean burning = this.isBurning(); + burning = burning || EnchantmentHelper.getMaxEnchantmentLevel(Enchantments.FLAME, this) > 0; + + if (burning) + { + entitytippedarrow.setFire(100); + } + + ItemStack itemstack = this.getHeldItem(EnumHand.OFF_HAND); + + if (itemstack != null && itemstack.getItem() == Items.TIPPED_ARROW) + { + entitytippedarrow.setPotionEffect(itemstack); + } else if (true) //TODO: Add potion effects to the arrows + { + entitytippedarrow.addEffect(new PotionEffect(MobEffects.SLOWNESS, 600)); + } + + this.playSound(SoundEvents.ENTITY_SKELETON_SHOOT, 1.0F, 1.0F / (this.getRNG().nextFloat() * 0.4F + 0.8F)); + this.worldObj.spawnEntityInWorld(entitytippedarrow); + } + + public boolean isTamed() + { + return (((Byte) this.dataManager.get(TAMED)).byteValue() & 4) != 0; + } + + public void setTamed(boolean tamed) + { + byte b0 = ((Byte) this.dataManager.get(TAMED)).byteValue(); + + if (tamed) + { + this.dataManager.set(TAMED, Byte.valueOf((byte) (b0 | 4))); + } else + { + this.dataManager.set(TAMED, Byte.valueOf((byte) (b0 & -5))); + } + +// this.setupTamedAI(); } @Override @@ -97,4 +309,33 @@ public class EntitySentientSpecter extends EntityMob { return 0.4F; } + + @Override + public UUID getOwnerId() + { + return (UUID) (this.dataManager.get(OWNER_UNIQUE_ID)).orNull(); + } + + public void setOwnerId(UUID uuid) + { + this.dataManager.set(OWNER_UNIQUE_ID, Optional.fromNullable(uuid)); + } + + @Override + public EntityLivingBase getOwner() + { + try + { + UUID uuid = this.getOwnerId(); + return uuid == null ? null : this.worldObj.getPlayerEntityByUUID(uuid); + } catch (IllegalArgumentException var2) + { + return null; + } + } + + public void setOwner(EntityPlayer player) + { + setOwnerId(player.getUniqueID()); + } } \ No newline at end of file diff --git a/src/main/java/WayofTime/bloodmagic/item/soul/ItemSentientSword.java b/src/main/java/WayofTime/bloodmagic/item/soul/ItemSentientSword.java index 33788ad4..0a238787 100644 --- a/src/main/java/WayofTime/bloodmagic/item/soul/ItemSentientSword.java +++ b/src/main/java/WayofTime/bloodmagic/item/soul/ItemSentientSword.java @@ -70,7 +70,7 @@ public class ItemSentientSword extends ItemSword implements IDemonWillWeapon, IM public static double[] movementSpeed = new double[] { 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.4 }; - public static final boolean spawnSpecterOnClick = false; + public static final boolean spawnSpecterOnClick = true; public ItemSentientSword() { @@ -253,7 +253,9 @@ public class ItemSentientSword extends ItemSword implements IDemonWillWeapon, IM specterEntity.setPosition(player.posX, player.posY, player.posZ); world.spawnEntityInWorld(specterEntity); System.out.println("Spawning Specter..."); - specterEntity.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(ModItems.sentientSword)); + specterEntity.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(ModItems.sentientBow)); + specterEntity.setOwner(player); + specterEntity.setTamed(true); } return super.onItemRightClick(stack, world, player, hand);