/*
   * 右クリック使用をやめた時に呼ばれるメソッド。右クリックを継続して押していた時間をもとに、エンティティを発射する処理を行う。
   */
  public void onPlayerStoppedUsing(
      ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer, int par4) {
    boolean ff =
        par3EntityPlayer.capabilities.isCreativeMode
            || EnchantmentHelper.getEnchantmentLevel(Enchantment.infinity.effectId, par1ItemStack)
                > 0;
    boolean flag2 = false;
    if (par1ItemStack.getItem() == this) {
      int c2 = this.discharge(par1ItemStack, 400, false);
      if (ff || c2 == 400) flag2 = true;
    }

    if (flag2) {
      float yaw = par3EntityPlayer.rotationYaw;
      float pitch = par3EntityPlayer.rotationPitch;
      double dx = -(double) (MathHelper.sin(yaw / 180.0F * (float) Math.PI)) * 30.0D;
      double dz = (double) (MathHelper.cos(yaw / 180.0F * (float) Math.PI)) * 30.0D;
      double dy = -(double) (MathHelper.sin(pitch / 180.0F * (float) Math.PI)) * 30.0D;

      double minX = par3EntityPlayer.posX + Math.min(-1, dx);
      double minY = par3EntityPlayer.posY + Math.min(-1, dy);
      double minZ = par3EntityPlayer.posZ + Math.min(-1, dz);
      double maxX = par3EntityPlayer.posX + Math.max(1, dx);
      double maxY = par3EntityPlayer.posY + Math.max(1, dy);
      double maxZ = par3EntityPlayer.posZ + Math.max(1, dz);

      AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
      List list = par2World.getEntitiesWithinAABB(EntityLivingBase.class, aabb);
      EntityLivingBase target = null;

      AMTLogger.debugInfo("yaw & pitch : " + yaw + "," + pitch);
      AMTLogger.debugInfo(
          "aabb : " + minX + "," + minY + "," + minZ + "," + maxX + "," + maxY + "," + maxZ);

      if (list != null && !list.isEmpty()) {
        for (int k = 0; k < list.size(); k++) {
          EntityLivingBase entity = (EntityLivingBase) list.get(k);
          if (entity.canEntityBeSeen(par3EntityPlayer)
              && !(entity instanceof EntityPlayer)
              && !(entity instanceof EntityTameable)
              && !(entity instanceof EntityHorse)
              && !(entity instanceof EntityVillager)) {
            target = entity;
            AMTLogger.debugInfo("target : " + target.toString());
            break;
          }
        }
      }

      // par4は右クリックの押下時間。
      int j = this.getMaxItemUseDuration(par1ItemStack) - par4;

      // 右クリック押下時間をもとに計算。20で割り(単位を秒に変換)、なにやら二次関数的な計算式に入れている。
      // ここではバニラ弓のまま使っているが、独自の計算式でも良いと思います。
      float f = (float) j / 20.0F;
      f = (f * f + f * 2.0F) / 3.0F;
      // タメ時間が一定以下の場合、何も起こさず処理から抜ける。
      if ((double) f < 0.1D) {
        return;
      }
      // fの上限値。
      if (f > 1.0F) {
        f = 1.0F;
      }

      int power = EnchantmentHelper.getEnchantmentLevel(Enchantment.power.effectId, par1ItemStack);
      int punch = EnchantmentHelper.getEnchantmentLevel(Enchantment.power.effectId, par1ItemStack);
      int fire = EnchantmentHelper.getEnchantmentLevel(Enchantment.flame.effectId, par1ItemStack);

      boolean flag = false;

      if (target != null) {
        EntityAnchorMissile bullet =
            new EntityAnchorMissile(
                par2World,
                par3EntityPlayer,
                target,
                1.0F,
                1.0F,
                par3EntityPlayer.rotationYaw,
                0.0F,
                0.0F,
                0.0F);

        if (power > 0) {
          bullet.setDamage(50.0D + power * 5.0D);
        }

        if (punch > 0) {
          bullet.setKnockbackStrength(1 + punch);
        }

        if (fire > 0) {
          bullet.setFire(100);
        }

        ((IBattery) par1ItemStack.getItem()).discharge(par1ItemStack, 400, true);
        par2World.playSoundAtEntity(
            par3EntityPlayer,
            "random.pop",
            1.0F,
            1.0F / (itemRand.nextFloat() * 0.4F + 1.2F) + f * 0.5F);
        if (!par2World.isRemote) {
          flag = par2World.spawnEntityInWorld(bullet);
        }
      }
    }
  }
  /*
   * Tick毎に呼ばれる更新処理。
   * 速度の更新、衝突判定などをここで行う。
   */
  @Override
  public void onUpdate() {
    super.onUpdate();

    livingTimeCount++;

    // その1、爆発処理
    byte exp = this.isExploded();
    if (exp == 1) {
      this.setDead();
    } else if (exp > 1) {
      AMTLogger.debugInfo("current explode int :" + exp);
      this.worldObj.spawnParticle(
          "hugeexplosion",
          this.posX,
          this.posY + 1.0D,
          this.posZ,
          this.motionX,
          this.motionY,
          this.motionZ);
      exp--;
      this.setTimeCount(exp);
    }

    // その2、アクティブか否か
    if (livingTimeCount > 3 && !this.active) {
      this.active = true;
      this.setActive((byte) 1);
      this.playSound("defeatedcrow:knock", 0.5F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F));
    }

    boolean explode = false;

    // 以降、アクティブか否かで動作が変わる。
    if (this.active) {
      double dx = -(double) (MathHelper.sin(this.rotationYaw / 180.0F * (float) Math.PI));
      double dz = -(double) (MathHelper.cos(this.rotationYaw / 180.0F * (float) Math.PI));
      for (int i = 0; i < 4; ++i) {
        this.worldObj.spawnParticle(
            "crit",
            this.posX + dx,
            this.posY,
            this.posZ + dz,
            -this.motionX,
            -this.motionY + 0.2D,
            -this.motionZ);
      }
    }

    // 直前のパラメータと新パラメータを一致させているところ。
    // また、速度に応じてエンティティの向きを調整し、常に進行方向に前面が向くようにしている。
    if (this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F) {
      float f = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ);
      this.prevRotationYaw =
          this.rotationYaw = (float) (Math.atan2(this.motionX, this.motionZ) * 180.0D / Math.PI);
      this.prevRotationPitch =
          this.rotationPitch = (float) (Math.atan2(this.motionY, f) * 180.0D / Math.PI);
    }

    // 激突したブロックを確認している
    Block i = this.worldObj.getBlock(this.xTile, this.yTile, this.zTile);
    boolean air = this.worldObj.isAirBlock(xTile, yTile, zTile);

    // 空気じゃないブロックに当たった&ブロック貫通エンティティでない時
    if (i != null && i.getMaterial() != Material.air) {
      i.setBlockBoundsBasedOnState(this.worldObj, this.xTile, this.yTile, this.zTile);
      AxisAlignedBB axisalignedbb =
          i.getCollisionBoundingBoxFromPool(this.worldObj, this.xTile, this.yTile, this.zTile);

      // 当たり判定に接触しているかどうか
      if (axisalignedbb != null
          && axisalignedbb.isVecInside(Vec3.createVectorHelper(this.posX, this.posY, this.posZ))) {
        this.inGround = true;
      }
    }

    // 空気じゃないブロックに当たった
    if (this.inGround) {
      Block j = this.worldObj.getBlock(this.xTile, this.yTile, this.zTile);
      int k = this.worldObj.getBlockMetadata(this.xTile, this.yTile, this.zTile);

      /*
       * 前のTickに確認した埋まりブロックのIDとメタを照合している。違ったら埋まり状態を解除、一致したら埋まり状態を継続。
       * /* 埋まり状態2tick継続でこのエンティティを消す
       */
      if (j == this.inTile && k == this.inData) {
        ++this.ticksInGround;
        // ブロック貫通の場合、20tick(1秒間)はブロック中にあっても消えないようになる。
        int limit = 2;

        if (this.ticksInGround > limit) {
          explode = true;
        }
      } else // 埋まり状態の解除処理
      {
        this.inGround = false;
        this.motionX *= this.rand.nextFloat() * 0.1F;
        this.motionY *= this.rand.nextFloat() * 0.1F;
        this.motionZ *= this.rand.nextFloat() * 0.1F;
        this.ticksInGround = 0;
        this.ticksInAir = 0;
      }
    } else // 埋まってない時。速度の更新。
    {
      ++this.ticksInAir;
      // ブロックとの衝突判定
      Vec3 vec3 = Vec3.createVectorHelper(this.posX, this.posY, this.posZ);
      Vec3 vec31 =
          Vec3.createVectorHelper(
              this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);
      MovingObjectPosition movingobjectposition =
          this.worldObj.func_147447_a(vec3, vec31, false, true, false);
      vec3 = Vec3.createVectorHelper(this.posX, this.posY, this.posZ);
      vec31 =
          Vec3.createVectorHelper(
              this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);

      // ブロックに当たった
      if (movingobjectposition != null) {
        vec31 =
            Vec3.createVectorHelper(
                movingobjectposition.hitVec.xCoord,
                movingobjectposition.hitVec.yCoord,
                movingobjectposition.hitVec.zCoord);
      }

      // Entityとの衝突判定。
      List list =
          this.worldObj.getEntitiesWithinAABBExcludingEntity(
              this,
              this.boundingBox
                  .addCoord(this.motionX, this.motionY, this.motionZ)
                  .expand(1.0D, 1.0D, 1.0D));
      double d0 = 0.0D;
      int l;
      float f1;

      MovingObjectPosition entityTarget = null;

      // 1ブロック分の範囲内にいるエンティティ全てに対して繰り返す
      for (l = 0; l < list.size(); ++l) {
        Entity entity1 = (Entity) list.get(l);
        Entity entity = null;

        // ターゲットの場合
        if (entity1 instanceof EntityLivingBase || entity1 instanceof EntityDragonPart) {
          f1 = 0.3F;
          AxisAlignedBB axisalignedbb1 = entity1.boundingBox.expand(f1, f1, f1);
          MovingObjectPosition movingobjectposition1 =
              axisalignedbb1.calculateIntercept(vec3, vec31);

          if (movingobjectposition1 != null) {
            double d1 = vec3.distanceTo(movingobjectposition1.hitVec);

            if (d1 < d0 || d0 == 0.0D) {
              // arrowと異なり、あたったEntityすべてをリストに入れる
              entityTarget = new MovingObjectPosition(entity1);
              d0 = d1;
              break;
            }
          }
        }
      }

      /*
       * 当たったエンティティそれそれについての判定部分。
       * ここで特定の種類のエンティティに当たらないようにできる。
       */
      boolean canAttack = false;
      if (entityTarget != null) {
        Entity target = entityTarget.entityHit;

        if (target instanceof EntityPlayer) {
          // プレイヤーに当たった時
          EntityPlayer entityplayer = (EntityPlayer) target;

          if (entityplayer.capabilities.disableDamage
              || this.shootingEntity instanceof EntityPlayer
                  && !((EntityPlayer) this.shootingEntity).canAttackPlayer(entityplayer)) {
            // PvPが許可されていないと当たらない
            canAttack = false;
          } else if (entityplayer == this.shootingEntity) {
            // 対象が撃った本人の場合も当たらない
            canAttack = false;
          } else if (DCsConfig.PvPProhibitionMode && entityplayer instanceof EntityPlayer) {
            canAttack = false;
          }
        } else if (target instanceof EntityTameable || target instanceof EntityHorse) {
          // 事故防止の為、EntityTameable(犬や猫などのペット)、馬にも当たらないようにする
          canAttack = false;
        } else {
          canAttack = true;
        }
      }

      float f2;
      float f3;

      // 当たったあとの処理
      // まずはリストから
      if (canAttack) {
        Entity target = entityTarget.entityHit;

        int i1 = MathHelper.ceiling_double_int(1.0D * this.damage);
        // 0~2程度の乱数値を上乗せ
        i1 += this.rand.nextInt(3);

        DamageSource damagesource = null;

        // 別メソッドでダメージソースを確認
        damagesource = this.thisDamageSource(this.shootingEntity);

        // バニラ矢と同様、このエンティティが燃えているなら対象に着火することも出来る
        if (this.isBurning() && !(target instanceof EntityEnderman)) {
          target.setFire(5);
        } else if (target instanceof IProjectile) {
          // 対象が矢などの飛翔Entityの場合、打ち消すことが出来る
          target.setDead();
        } else {
          // ダメージを与える処理を呼ぶ
          if (target.attackEntityFrom(damagesource, i1)) {
            // ダメージを与えることに成功したら以下の処理を行う
            if (target instanceof EntityLivingBase) {
              EntityLivingBase entitylivingbase = (EntityLivingBase) target;

              // ノックバック
              if (this.knockbackStrength > 0) {
                f3 =
                    MathHelper.sqrt_double(
                        this.motionX * this.motionX + this.motionZ * this.motionZ);

                if (f3 > 0.0F) {
                  // Y方向に大きめに打ち上げる
                  target.addVelocity(
                      this.motionX * this.knockbackStrength * 0.2000000238418579D / f3,
                      0.3D,
                      this.motionZ * this.knockbackStrength * 0.2000000238418579D / f3);
                }
              }

              // 無敵時間はなし
              target.hurtResistantTime = 0;

              // マルチプレイ時に、両者がプレイヤーだった時のパケット送信処理
              if (this.shootingEntity != null
                  && target != this.shootingEntity
                  && target instanceof EntityPlayer
                  && this.shootingEntity instanceof EntityPlayerMP) {
                ((EntityPlayerMP) this.shootingEntity)
                    .playerNetServerHandler.sendPacket(new S2BPacketChangeGameState(6, 0.0F));
              }
            }

            // ここでヒット時の効果音がなる
            this.playSound("random.bowhit", 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F));

            // 当たったあと、弾を消去する。エンティティ貫通がONの弾種はそのまま残す。
            explode = true;
          }
        }
      }

      if (movingobjectposition != null) // blockのみ
      {
        this.xTile = movingobjectposition.blockX;
        this.yTile = movingobjectposition.blockY;
        this.zTile = movingobjectposition.blockZ;
        this.inTile = this.worldObj.getBlock(this.xTile, this.yTile, this.zTile);
        this.inData = this.worldObj.getBlockMetadata(this.xTile, this.yTile, this.zTile);
        this.motionX = ((float) (movingobjectposition.hitVec.xCoord - this.posX));
        this.motionY = ((float) (movingobjectposition.hitVec.yCoord - this.posY));
        this.motionZ = ((float) (movingobjectposition.hitVec.zCoord - this.posZ));
        f2 =
            MathHelper.sqrt_double(
                this.motionX * this.motionX
                    + this.motionY * this.motionY
                    + this.motionZ * this.motionZ);
        this.posX -= this.motionX / f2 * 0.05000000074505806D;
        this.posY -= this.motionY / f2 * 0.05000000074505806D;
        this.posZ -= this.motionZ / f2 * 0.05000000074505806D;
        this.playSound("random.bowhit", 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F));
        this.inGround = true;

        if (this.inTile != null) {
          // Block側に衝突を伝える
          this.inTile.onEntityCollidedWithBlock(
              this.worldObj, this.xTile, this.yTile, this.zTile, this);
        }
      }
    }

    // さいごに爆発処理
    int live = (targetEntity != null && targetEntity.isEntityAlive()) ? 10 : 600;

    if (explode || this.livingTimeCount > live) {
      if (this.isExploded() == 0) {
        AMTLogger.debugInfo("explosion");
        this.setExplosion();
        if (!DCsConfig.disableMissileExplosion && !worldObj.isRemote) {
          float f = 5.0F;
          CustomExplosion explosion =
              new CustomExplosion(
                  worldObj,
                  this,
                  shootingEntity,
                  this.posX,
                  this.posY,
                  this.posZ,
                  f,
                  CustomExplosion.Type.Anchor,
                  true);
          explosion.doExplosion();
        }
      }
    }

    // 追尾
    if (active) {
      if (targetEntity != null && targetEntity.isEntityAlive()) {
        double dx = targetEntity.posX - this.posX;
        double dy = targetEntity.boundingBox.minY + (targetEntity.height / 2.0D) - this.posY;
        double dz = targetEntity.posZ - this.posZ;
        double d3 = MathHelper.sqrt_double(dx * dx + dz * dz);

        if (d3 >= 1.0E-7D) {
          float f4 = (float) d3 * 0.2F;
          double dy2 = dy + f4;

          float ff = MathHelper.sqrt_double(dx * dx + dy2 * dy2 + dz * dz);
          dx /= ff;
          dy /= ff;
          dz /= ff;

          this.motionX = (this.motionX + dx) / 2;
          this.motionY = (this.motionY + dy) / 2;
          this.motionZ = (this.motionZ + dz) / 2;

          this.motionX *= 1.25D;
          this.motionY *= 1.25D;
          this.motionZ *= 1.25D;
        }
      }
    }

    // 直前のパラメータと新パラメータを一致させているところ。
    // また、速度に応じてエンティティの向きを調整し、常に進行方向に前面が向くようにしている。
    if (this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F) {
      float f = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ);
      this.prevRotationYaw =
          this.rotationYaw = (float) (Math.atan2(this.motionX, this.motionZ) * 180.0D / Math.PI);
      this.prevRotationPitch =
          this.rotationPitch = (float) (Math.atan2(this.motionY, f) * 180.0D / Math.PI);
    }

    // 改めてポジションに速度を加算。向きも更新。
    this.posX += this.motionX;
    this.posY += this.motionY;
    this.posZ += this.motionZ;
    float f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ);
    this.rotationYaw = (float) (Math.atan2(this.motionX, this.motionZ) * 180.0D / Math.PI);
    this.rotationPitch = (float) (Math.atan2(this.motionY, f2) * 180.0D / Math.PI);

    while (this.rotationPitch - this.prevRotationPitch < -180.0F) {
      this.prevRotationPitch -= 360.0F;
    }

    while (this.rotationPitch - this.prevRotationPitch >= 180.0F) {
      this.prevRotationPitch += 360.0F;
    }

    while (this.rotationYaw - this.prevRotationYaw < -180.0F) {
      this.prevRotationYaw -= 360.0F;
    }

    while (this.rotationYaw - this.prevRotationYaw >= 180.0F) {
      this.prevRotationYaw += 360.0F;
    }

    this.rotationPitch =
        this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * 0.2F;
    this.rotationYaw = this.prevRotationYaw + (this.rotationYaw - this.prevRotationYaw) * 0.2F;

    // 水中に有る
    if (this.isInWater()) {
      // 泡パーティクルが出る
      for (int j1 = 0; j1 < 4; ++j1) {
        float f3 = 0.25F;
        this.worldObj.spawnParticle(
            "bubble",
            this.posX - this.motionX * f3,
            this.posY - this.motionY * f3,
            this.posZ - this.motionZ * f3,
            this.motionX,
            this.motionY,
            this.motionZ);
      }
    }

    this.setPosition(this.posX, this.posY, this.posZ);
    this.func_145775_I();
  }