/** Returns true if the shield can block this kind of damage */
 public boolean canBlockDamage(ItemStack shield, DamageSource source) {
   boolean flag = source.isUnblockable() && !(source instanceof DamageSourceArmorBreak);
   if (toolMaterial == ToolMaterial.WOOD) {
     return !flag;
   }
   return !flag
       || source.isMagicDamage()
       || source.isFireDamage()
       || (source.isProjectile() && toolMaterial == ToolMaterial.EMERALD);
 }
  protected float applyPotionDamageCalculations(DamageSource par1DamageSource, float par2) {
    par2 = super.applyPotionDamageCalculations(par1DamageSource, par2);
    if (par1DamageSource.getEntity() == this) {
      par2 = 0.0F;
    }

    if (par1DamageSource.isMagicDamage()) {
      par2 = (float) ((double) par2 * 0.15D);
    }

    return par2;
  }
  @Override
  public ArmorProperties getProperties(
      EntityLivingBase player, ItemStack stack, DamageSource source, double damage, int slot) {
    int h = getArmorMaterial().getDamageReductionAmount(EntityEquipmentSlot.HEAD);
    int c = getArmorMaterial().getDamageReductionAmount(EntityEquipmentSlot.CHEST);
    int p = getArmorMaterial().getDamageReductionAmount(EntityEquipmentSlot.LEGS);
    int b = getArmorMaterial().getDamageReductionAmount(EntityEquipmentSlot.FEET);

    if (!stack.hasTagCompound()) stack.setTagCompound(new NBTTagCompound());

    if (stack.getTagCompound().getBoolean("destroyed"))
      return new ArmorProperties(0, 1 / damage, 1);

    if (stack.getTagCompound().getByte("all") > 0) {
      h += 1;
      c += 2;
      p += 1;
      b += 1;
    } else if (stack.getTagCompound().getByte("blast") > 0 && source.isExplosion()) {
      h += 2;
      c += 3;
      p += 2;
      b += 2;
    } else if (stack.getTagCompound().getByte("fire") > 0 && source.isFireDamage()) {
      h += 2;
      c += 3;
      p += 2;
      b += 2;
    } else if (stack.getTagCompound().getByte("magic") > 0 && source.isMagicDamage()) {
      h += 2;
      c += 3;
      p += 2;
      b += 2;
    } else if (stack.getTagCompound().getByte("projectile") > 0 && source.isProjectile()) {
      h += 2;
      c += 3;
      p += 2;
      b += 2;
    }

    switch (slot) {
      case 3:
        return new ArmorProperties(0, h / 25D, Integer.MAX_VALUE);
      case 2:
        return new ArmorProperties(1, c / 25D, Integer.MAX_VALUE);
      case 1:
        return new ArmorProperties(1, p / 25D, Integer.MAX_VALUE);
      case 0:
        return new ArmorProperties(0, b / 25D, Integer.MAX_VALUE);
      default:
        return null;
    }
  }
 /**
  * Can a damage source harm the entity in question.
  *
  * @param entity - entity being attacked
  * @param source - damage source/type
  * @param damage - amount of damage
  * @return true if the damage can be applied
  */
 public static boolean canHarm(Entity entity, DamageSource source, float damage) {
   if (canDamage(entity)) {
     if (isMachine(entity)) {
       if (source.isFireDamage()) {
         return false;
       }
       if (source.isMagicDamage()) {
         return false;
       }
     }
     return source != null && damage > 0;
   }
   return false;
 }
  @Override
  public void damageArmor(
      EntityLivingBase entity, ItemStack stack, DamageSource source, int damage, int slot) {
    if (!stack.hasTagCompound()) stack.setTagCompound(new NBTTagCompound());

    if (stack.getItemDamage() >= stack.getMaxDamage() - 2) {
      NBTTagCompound tag = stack.getTagCompound();
      tag.setBoolean("destroyed", true);
      stack.setTagCompound(tag);

      return;
    }

    if (stack.getTagCompound().getByte("all") > 0) stack.damageItem(1, entity);
    else if (stack.getTagCompound().getByte("blast") > 0 && source.isExplosion())
      stack.damageItem(1, entity);
    else if (stack.getTagCompound().getByte("fire") > 0 && source.isFireDamage())
      stack.damageItem(1, entity);
    else if (stack.getTagCompound().getByte("magic") > 0 && source.isMagicDamage())
      stack.damageItem(1, entity);
    else if (stack.getTagCompound().getByte("projectile") > 0 && source.isProjectile())
      stack.damageItem(1, entity);
    else if (!source.isUnblockable()) stack.damageItem(2, entity);
  }
 /**
  * Called when the shield blocks an attack when held in the normal fashion (i.e. non-BG2) used by
  * Deku Shield to damage / destroy the stack and by Mirror Shield to reflect projectiles
  *
  * @return Return the amount of damage remaining, if any; 0 cancels the hurt event
  */
 public float onBlock(EntityPlayer player, ItemStack shield, DamageSource source, float damage) {
   ZSSPlayerInfo.get(player).onAttackBlocked(shield, damage);
   WorldUtils.playSoundAtEntity(player, Sounds.HAMMER, 0.4F, 0.5F);
   float damageBlocked = damage;
   if (toolMaterial == ToolMaterial.WOOD) {
     if (source.isProjectile()
         && !source.isExplosion()
         && source.getSourceOfDamage() instanceof IProjectile) {
       if (ZSSMain.isBG2Enabled
           && player.getHeldItem() == shield
           && shield.getItem() instanceof IArrowCatcher) {
         if (((IArrowCatcher) shield.getItem())
             .catchArrow(shield, player, (IProjectile) source.getSourceOfDamage())) {
           ((InventoryPlayerBattle) player.inventory).hasChanged = true;
         }
       }
     } else if (source instanceof IDamageAoE && ((IDamageAoE) source).isAoEDamage()) {
       damageBlocked *= magicReduction;
     }
     int dmg = Math.round(source.isFireDamage() ? damage + 10.0F : damage - 2.0F);
     if (dmg > 0) {
       shield.damageItem(dmg, player);
       if (shield.stackSize <= 0) {
         ForgeEventFactory.onPlayerDestroyItem(player, shield);
         if (ZSSMain.isBG2Enabled && BattlegearUtils.isPlayerInBattlemode(player)) {
           BattlegearUtils.setPlayerOffhandItem(player, null);
         } else {
           player.destroyCurrentEquippedItem();
         }
       }
     }
   } else if (toolMaterial == ToolMaterial.EMERALD) {
     if (source.isProjectile() && !source.isExplosion() && source.getSourceOfDamage() != null) {
       float chance = (source.isMagicDamage() ? (1F / 3F) : 1.0F);
       if (source.getSourceOfDamage() instanceof IReflectable) {
         ((IReflectable) source.getSourceOfDamage())
             .getReflectChance(shield, player, source.getEntity());
       }
       if (player.worldObj.rand.nextFloat() < chance) {
         Entity projectile = null;
         try {
           projectile =
               source
                   .getSourceOfDamage()
                   .getClass()
                   .getConstructor(World.class)
                   .newInstance(player.worldObj);
         } catch (Exception e) {;
         }
         if (projectile != null) {
           NBTTagCompound data = new NBTTagCompound();
           source.getSourceOfDamage().writeToNBT(data);
           projectile.readFromNBT(data);
           projectile.getEntityData().setBoolean("isReflected", true);
           projectile.posX -= projectile.motionX;
           projectile.posY -= projectile.motionY;
           projectile.posZ -= projectile.motionZ;
           double motionX =
               (double)
                   (-MathHelper.sin(player.rotationYaw / 180.0F * (float) Math.PI)
                       * MathHelper.cos(player.rotationPitch / 180.0F * (float) Math.PI));
           double motionZ =
               (double)
                   (MathHelper.cos(player.rotationYaw / 180.0F * (float) Math.PI)
                       * MathHelper.cos(player.rotationPitch / 180.0F * (float) Math.PI));
           double motionY =
               (double) (-MathHelper.sin(player.rotationPitch / 180.0F * (float) Math.PI));
           TargetUtils.setEntityHeading(
               projectile,
               motionX,
               motionY,
               motionZ,
               1.0F,
               2.0F + (20.0F * player.worldObj.rand.nextFloat()),
               false);
           if (projectile instanceof IReflectable) {
             ((IReflectable) projectile)
                 .onReflected(shield, player, source.getEntity(), source.getSourceOfDamage());
           }
           player.worldObj.spawnEntityInWorld(projectile);
         }
       } else if (source.isUnblockable()
           || (source instanceof IDamageAoE
               && ((IDamageAoE) source).isAoEDamage())) { // failed to reflect projectile
         damageBlocked *= magicReduction;
       }
     }
   } else if (source.isUnblockable()
       || (source instanceof IDamageAoE && ((IDamageAoE) source).isAoEDamage())) {
     damageBlocked *=
         magicReduction; // default shield behavior blocks half damage from AoE magic attacks
   }
   return (damage - damageBlocked);
 }