@Override
  public void shoot(double d0, double d1, double d2, float f, float f1) {
    float f2 = MathHelper.sqrt(d0 * d0 + d1 * d1 + d2 * d2);

    d0 /= f2;
    d1 /= f2;
    d2 /= f2;
    d0 += random.nextGaussian() * 0.007499999832361937D * f1;
    d1 += random.nextGaussian() * 0.007499999832361937D * f1;
    d2 += random.nextGaussian() * 0.007499999832361937D * f1;
    d0 *= f;
    d1 *= f;
    d2 *= f;
    motX = d0;
    motY = d1;
    motZ = d2;
    float f3 = MathHelper.sqrt(d0 * d0 + d2 * d2);

    lastYaw = yaw = (float) (Math.atan2(d0, d2) * 180.0D / 3.1415927410125732D);
    lastPitch = pitch = (float) (Math.atan2(d1, f3) * 180.0D / 3.1415927410125732D);
  }
  @Override
  public void s_() {
    K();
    BlockPosition blockposition = new BlockPosition(locX, locY, locZ);
    IBlockData iblockdata = world.getType(blockposition);
    Block block = iblockdata.getBlock();

    if (!ignoredMaterials.contains(Material.getMaterial(Block.getId(block)))) {
      AxisAlignedBB axisalignedbb = block.a(world, blockposition, iblockdata);

      if ((axisalignedbb != null) && (axisalignedbb.a(new Vec3D(locX, locY, locZ)))) {
        float damageMultiplier = MathHelper.sqrt(motX * motX + motY * motY + motZ * motZ);
        CustomProjectileHitEvent event =
            new ItemProjectileHitEvent(
                this,
                damageMultiplier,
                world.getWorld().getBlockAt((int) locX, (int) locY, (int) locZ),
                BlockFace.UP,
                getItem());
        Bukkit.getPluginManager().callEvent(event);
        if (!event.isCancelled()) {
          die();
        }
      }
    }
    age += 1;
    Vec3D vec3d = new Vec3D(locX, locY, locZ);
    Vec3D vec3d1 = new Vec3D(locX + motX, locY + motY, locZ + motZ);
    MovingObjectPosition movingobjectposition = world.rayTrace(vec3d, vec3d1, false, true, false);

    vec3d = new Vec3D(locX, locY, locZ);
    vec3d1 = new Vec3D(locX + motX, locY + motY, locZ + motZ);
    if (movingobjectposition != null) {
      vec3d1 =
          new Vec3D(
              movingobjectposition.pos.a, movingobjectposition.pos.b, movingobjectposition.pos.c);
    }

    Entity entity = null;
    List list =
        world.getEntities(this, getBoundingBox().a(motX, motY, motZ).grow(1.0D, 1.0D, 1.0D));
    double d0 = 0.0D;

    for (Object aList : list) {
      Entity entity1 = (Entity) aList;

      if ((entity1.ad()) && ((entity1 != shooter) || (age >= 5))) {
        float f1 = 0.3F;
        AxisAlignedBB axisalignedbb1 = entity1.getBoundingBox().grow(f1, f1, f1);
        MovingObjectPosition movingobjectposition1 = axisalignedbb1.a(vec3d, vec3d1);

        if (movingobjectposition1 != null) {
          double d1 = vec3d.distanceSquared(movingobjectposition1.pos);

          if ((d1 < d0) || (d0 == 0.0D)) {
            entity = entity1;
            d0 = d1;
          }
        }
      }
    }
    if (entity != null) {
      movingobjectposition = new MovingObjectPosition(entity);
    }
    if ((movingobjectposition != null)
        && (movingobjectposition.entity != null)
        && ((movingobjectposition.entity instanceof EntityHuman))) {
      EntityHuman entityhuman = (EntityHuman) movingobjectposition.entity;
      if ((entityhuman.abilities.isInvulnerable)
          || (((shooter instanceof EntityHuman)) && (!((EntityHuman) shooter).a(entityhuman)))) {
        movingobjectposition = null;
      }
    }
    if (movingobjectposition != null) {
      if (movingobjectposition.entity != null
          && movingobjectposition.entity instanceof EntityLiving) {
        float damageMultiplier = MathHelper.sqrt(motX * motX + motY * motY + motZ * motZ);
        CustomProjectileHitEvent event =
            new ItemProjectileHitEvent(
                this,
                damageMultiplier,
                (LivingEntity) movingobjectposition.entity.getBukkitEntity(),
                getItem());
        Bukkit.getPluginManager().callEvent(event);
        if (!event.isCancelled()) {
          if (getKnockback() > 0) {
            float f4 = MathHelper.sqrt(motX * motX + motZ * motZ);
            if (f4 > 0.0F) {
              movingobjectposition.entity.g(
                  motX * getKnockback() * 0.6000000238418579D / f4,
                  0.1D,
                  motZ * getKnockback() * 0.6000000238418579D / f4);
            }
          }
          die();
        }
      } else if (movingobjectposition.a() != null) {
        if (!ignoredMaterials.contains(Material.getMaterial(Block.getId(block)))) {
          motX = ((float) (movingobjectposition.pos.a - locX));
          motY = ((float) (movingobjectposition.pos.b - locY));
          motZ = ((float) (movingobjectposition.pos.c - locZ));
          float f3 = MathHelper.sqrt(motX * motX + motY * motY + motZ * motZ);
          locX -= motX / f3 * 0.0500000007450581D;
          locY -= motY / f3 * 0.0500000007450581D;
          locZ -= motZ / f3 * 0.0500000007450581D;
          float damageMultiplier = MathHelper.sqrt(motX * motX + motY * motY + motZ * motZ);
          CustomProjectileHitEvent event =
              new ItemProjectileHitEvent(
                  this,
                  damageMultiplier,
                  world
                      .getWorld()
                      .getBlockAt(
                          (int) movingobjectposition.pos.a,
                          (int) movingobjectposition.pos.b,
                          (int) movingobjectposition.pos.c),
                  CraftBlock.notchToBlockFace(movingobjectposition.direction),
                  getItem());
          Bukkit.getPluginManager().callEvent(event);
          if (!event.isCancelled()) {
            die();
          }
        }
      }
    }

    locX += motX;
    locY += motY;
    locZ += motZ;
    float f3 = 0.99F;
    float f1 = 0.05F;
    motX *= f3;
    motY *= f3;
    motZ *= f3;
    motY -= f1;
    setPosition(locX, locY, locZ);
    checkBlockCollisions();
    if (isAlive()) {
      if (this.age >= 1000) {
        die();
      }
      for (Runnable r : runnables) {
        r.run();
      }
      for (TypedRunnable<ItemProjectile> r : typedRunnables) {
        r.run(this);
      }
    }
  }