/** Returns whether the EntityAIBase should begin execution. */
  @SuppressWarnings("unchecked")
  @Override
  public boolean shouldExecute() {
    EntityLivingBase entitylivingbase = this.attacker.getAttackTarget();

    if (entitylivingbase == null) {
      return false;
    } else if (!entitylivingbase.isEntityAlive()) {
      return false;
    } else if (this.classTarget != null
        && !this.classTarget.isAssignableFrom(entitylivingbase.getClass())) {
      return false;
    } else if (this.worldObj.isDaytime()) {
      return false;
    } else {
      if (--this.field_75445_i <= 0) {
        this.entityPathEntity =
            this.attacker.getNavigator().getPathToEntityLiving(entitylivingbase);
        this.field_75445_i = 4 + this.attacker.getRNG().nextInt(7);
        return this.entityPathEntity != null;
      } else {
        return true;
      }
    }
  }
 @Override
 public boolean shouldExecute() {
   EntityLivingBase entitylivingbase = attacker.getAttackTarget();
   if (entitylivingbase == null) return false;
   else if (!entitylivingbase.isEntityAlive()) return false;
   else if (classTarget != null && !classTarget.isAssignableFrom(entitylivingbase.getClass()))
     return false;
   else if (--findAttemptCount <= 0) {
     entityPathEntity = attacker.getNavigator().getPathToEntityLiving(entitylivingbase);
     findAttemptCount = 4 + attacker.getRNG().nextInt(7);
     return entityPathEntity != null;
   } else return true;
 }
 /** Returns whether an in-progress EntityAIBase should continue executing */
 @Override
 public boolean continueExecuting() {
   EntityLivingBase entitylivingbase = this.attacker.getAttackTarget();
   return entitylivingbase == null
       ? false
       : (!entitylivingbase.isEntityAlive()
           ? false
           : (!this.longMemory
               ? !this.attacker.getNavigator().noPath()
               : this.attacker.isWithinHomeDistance(
                   MathHelper.floor_double(entitylivingbase.posX),
                   MathHelper.floor_double(entitylivingbase.posY),
                   MathHelper.floor_double(entitylivingbase.posZ))));
 }
 /** Returns whether the EntityAIBase should begin execution. */
 public boolean shouldExecute() {
   EntityLivingBase entitylivingbase = this.spirit.getAttackTarget();
   return entitylivingbase != null && entitylivingbase.isEntityAlive();
 }
  /*
   * 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();
  }
  protected void updateAITasks() {
    int i;

    if (this.func_82212_n() > 0) {
      i = this.func_82212_n() - 1;

      if (i <= 0) {
        this.worldObj.newExplosion(
            this,
            this.posX,
            this.posY + (double) this.getEyeHeight(),
            this.posZ,
            7.0F,
            false,
            this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing"));
        this.worldObj.playBroadcastSound(
            1013, (int) this.posX, (int) this.posY, (int) this.posZ, 0);
      }

      this.func_82215_s(i);

      if (this.ticksExisted % 10 == 0) {
        this.heal(10.0F);
      }
    } else {
      super.updateAITasks();
      int i1;

      for (i = 1; i < 3; ++i) {
        if (this.ticksExisted >= this.field_82223_h[i - 1]) {
          this.field_82223_h[i - 1] = this.ticksExisted + 10 + this.rand.nextInt(10);

          if (this.worldObj.difficultySetting == EnumDifficulty.NORMAL
              || this.worldObj.difficultySetting == EnumDifficulty.HARD) {
            int k2 = i - 1;
            int l2 = this.field_82224_i[i - 1];
            this.field_82224_i[k2] = this.field_82224_i[i - 1] + 1;

            if (l2 > 15) {
              float f = 10.0F;
              float f1 = 5.0F;
              double d0 =
                  MathHelper.getRandomDoubleInRange(
                      this.rand, this.posX - (double) f, this.posX + (double) f);
              double d1 =
                  MathHelper.getRandomDoubleInRange(
                      this.rand, this.posY - (double) f1, this.posY + (double) f1);
              double d2 =
                  MathHelper.getRandomDoubleInRange(
                      this.rand, this.posZ - (double) f, this.posZ + (double) f);
              this.func_82209_a(i + 1, d0, d1, d2, true);
              this.field_82224_i[i - 1] = 0;
            }
          }

          i1 = this.getWatchedTargetId(i);

          if (i1 > 0) {
            Entity entity = this.worldObj.getEntityByID(i1);

            if (entity != null
                && entity.isEntityAlive()
                && this.getDistanceSqToEntity(entity) <= 900.0D
                && this.canEntityBeSeen(entity)) {
              this.func_82216_a(i + 1, (EntityLivingBase) entity);
              this.field_82223_h[i - 1] = this.ticksExisted + 40 + this.rand.nextInt(20);
              this.field_82224_i[i - 1] = 0;
            } else {
              this.func_82211_c(i, 0);
            }
          } else {
            List list =
                this.worldObj.selectEntitiesWithinAABB(
                    EntityLivingBase.class,
                    this.boundingBox.expand(20.0D, 8.0D, 20.0D),
                    attackEntitySelector);

            for (int k1 = 0; k1 < 10 && !list.isEmpty(); ++k1) {
              EntityLivingBase entitylivingbase =
                  (EntityLivingBase) list.get(this.rand.nextInt(list.size()));

              if (entitylivingbase != this
                  && entitylivingbase.isEntityAlive()
                  && this.canEntityBeSeen(entitylivingbase)) {
                if (entitylivingbase instanceof EntityPlayer) {
                  if (!((EntityPlayer) entitylivingbase).capabilities.disableDamage) {
                    this.func_82211_c(i, entitylivingbase.getEntityId());
                  }
                } else {
                  this.func_82211_c(i, entitylivingbase.getEntityId());
                }

                break;
              }

              list.remove(entitylivingbase);
            }
          }
        }
      }

      if (this.getAttackTarget() != null) {
        this.func_82211_c(0, this.getAttackTarget().getEntityId());
      } else {
        this.func_82211_c(0, 0);
      }

      if (this.field_82222_j > 0) {
        --this.field_82222_j;

        if (this.field_82222_j == 0
            && this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing")) {
          i = MathHelper.floor_double(this.posY);
          i1 = MathHelper.floor_double(this.posX);
          int j1 = MathHelper.floor_double(this.posZ);
          boolean flag = false;

          for (int l1 = -1; l1 <= 1; ++l1) {
            for (int i2 = -1; i2 <= 1; ++i2) {
              for (int j = 0; j <= 3; ++j) {
                int j2 = i1 + l1;
                int k = i + j;
                int l = j1 + i2;
                Block block = this.worldObj.getBlock(j2, k, l);

                if (!block.isAir(worldObj, j2, k, l)
                    && block.canEntityDestroy(worldObj, j2, k, l, this)) {
                  flag = this.worldObj.func_147480_a(j2, k, l, true) || flag;
                }
              }
            }
          }

          if (flag) {
            this.worldObj.playAuxSFXAtEntity(
                (EntityPlayer) null, 1012, (int) this.posX, (int) this.posY, (int) this.posZ, 0);
          }
        }
      }

      if (this.ticksExisted % 20 == 0) {
        this.heal(1.0F);
      }
    }
  }