@Override
 public boolean onLeftClickEntity(ItemStack stack, EntityPlayer player, Entity target) {
   if (target instanceof EntityLivingBase) {
     WorldUtils.playSoundAtEntity(player, Sounds.HAMMER, 0.4F, 0.5F);
     TargetUtils.knockTargetBack((EntityLivingBase) target, player);
   }
   return true;
 }
  private boolean lootTarget(EntityPlayer player, EntityLivingBase target) {
    if (target.getEntityData().getBoolean("LootableEntityFlag")) {
      return false;
    }
    IEntityLootable lootable =
        (target instanceof IEntityLootable ? (IEntityLootable) target : null);
    float lootChance =
        (lootable != null
            ? lootable.getLootableChance(player, getType())
            : LootableEntityRegistry.getEntityLootChance(target.getClass()));
    lootChance *= Config.getWhipLootMultiplier();
    boolean wasItemStolen = false;
    if (rand.nextFloat() < lootChance) {
      ItemStack loot =
          (lootable != null
              ? lootable.getEntityLoot(player, getType())
              : LootableEntityRegistry.getEntityLoot(target.getClass()));
      // TODO remove the following if Skulltulas are added:
      if (target instanceof EntitySpider && rand.nextInt(25) == 0) {
        loot = new ItemStack(ZSSItems.skulltulaToken);
      }
      if (loot != null) {
        EntityItem item = new EntityItem(worldObj, posX, posY + 1, posZ, loot);
        double dx = player.posX - posX;
        double dy = player.posY - posY;
        double dz = player.posZ - posZ;
        TargetUtils.setEntityHeading(item, dx, dy, dz, 1.0F, 1.0F, true);
        if (!worldObj.isRemote) {
          worldObj.spawnEntityInWorld(item);
        }
        player.triggerAchievement(ZSSAchievements.orcaThief);
        wasItemStolen = true;
      }
    }

    if (lootable == null || lootable.onLootStolen(player, wasItemStolen)) {
      if (!worldObj.isRemote) {
        target.getEntityData().setBoolean("LootableEntityFlag", true);
      }
    }
    return wasItemStolen;
  }
 /**
  * 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);
 }
 protected void swingThrower() {
   EntityLivingBase thrower = getThrower();
   if (thrower != null && !thrower.onGround && isInGround()) {
     if (thrower.worldObj.isRemote) {
       // Determine the swing variables on first swing tick:
       float x = dataWatcher.getWatchableObjectFloat(HIT_POS_X);
       float y = dataWatcher.getWatchableObjectFloat(HIT_POS_Y);
       float z = dataWatcher.getWatchableObjectFloat(HIT_POS_Z);
       if (swingTicks == 0 && swingVec == null && thrower.motionY < 0) {
         swingVec =
             Vec3.createVectorHelper(
                     (x - thrower.posX),
                     y - (thrower.posY + thrower.getEyeHeight()),
                     (z - thrower.posZ))
                 .normalize();
         dy = (thrower.getDistance(x, y, z) / 7.0D); // lower divisor gives bigger change in y
         // calculate horizontal distance to find initial swing tick position
         // as distance approaches zero, swing ticks should approach ticks required / 2
         // as distance approaches maxDistance, swing ticks should approach zero
         // this makes sure player's arc is even around pivot point
         double d = Math.min(thrower.getDistance(x, thrower.posY, z), getMaxDistance());
         swingTicks = MathHelper.floor_double(((getMaxDistance() - d) / getMaxDistance()) * 8);
       }
       if (swingVec != null) {
         double sin = Math.sin(10.0D * swingTicks * Math.PI / 180.0D);
         double f = 0.8D; // arbitrary horizontal motion factor
         thrower.motionX = (sin * swingVec.xCoord * f);
         thrower.motionZ = (sin * swingVec.zCoord * f);
         // y motion needs to oscillate twice as quickly, so it goes up on the other side of the
         // swing
         thrower.motionY = dy * -Math.sin(20.0D * swingTicks * Math.PI / 180.0D);
         // check for horizontal collisions that should stop swinging motion
         MovingObjectPosition mop =
             TargetUtils.checkForImpact(worldObj, thrower, this, -(thrower.width / 4.0F), false);
         if (mop != null && mop.typeOfHit != MovingObjectType.MISS) {
           thrower.motionX = -thrower.motionX * 0.15D;
           thrower.motionY = -thrower.motionY * 0.15D;
           thrower.motionZ = -thrower.motionZ * 0.15D;
           swingVec = null;
         }
         ++swingTicks; // increment at end
         if (thrower.fallDistance > 0 && thrower.motionY < 0) {
           // 0.466885F seems to be roughly the amount added each tick while swinging; round for a
           // little extra server-side padding
           PacketDispatcher.sendToServer(new FallDistancePacket(thrower, -0.467F));
           thrower.fallDistance -= 0.467F;
         }
       } else if (swingTicks > 0) {
         // still let player hang there after colliding, but move towards center
         if (thrower.getDistanceSq(x, thrower.posY, z) > 1.0D) {
           double dx = x - thrower.posX;
           double dz = z - thrower.posZ;
           thrower.motionX = 0.15D * dx;
           thrower.motionZ = 0.15D * dz;
         }
         if (thrower.posY < (y - (getMaxDistance() / 2.0D))) {
           thrower.motionY = 0;
         }
         ++swingTicks; // increment at end
         PacketDispatcher.sendToServer(new FallDistancePacket(thrower, 0.0F));
         thrower.fallDistance = 0.0F;
       }
     }
   }
 }