@Override
  public ItemStack onFocusRightClick(
      ItemStack itemstack, World world, EntityPlayer player, MovingObjectPosition mop) {
    player.swingItem();
    if (mop != null
        && ThaumcraftApiHelper.consumeVisFromWand(itemstack, player, visCost.copy(), true, false)) {
      int x = mop.blockX;
      int y = mop.blockY;
      int z = mop.blockZ;

      switch (mop.sideHit) {
        case (0):
          {
            y--;
            break;
          }
        case (1):
          {
            y++;
            break;
          }
        case (2):
          {
            z--;
            break;
          }
        case (3):
          {
            z++;
            break;
          }
        case (4):
          {
            x--;
            break;
          }
        case (5):
          {
            x++;
            break;
          }
      }

      if (world.getBlock(x, y, z).isReplaceable(world, x, y, z) || world.isAirBlock(x, y, z)) {
        ItemStack focusStack = ((ItemWandCasting) itemstack.getItem()).getFocusItem(itemstack);

        world.setBlock(x, y, z, TCBlocks.nitorColour);
        TileColouredNitor te = (TileColouredNitor) world.getTileEntity(x, y, z);
        te.setColour(getColour(focusStack));
        world.playSoundEffect(
            mop.blockX + 0.5D, mop.blockY + 0.5D, mop.blockZ + 0.5D, "thaumcraft:zap", 0.25F, 1.0F);
      }
    }

    return itemstack;
  }
  @Override
  public boolean matches(
      ArrayList<ItemStack> input, ItemStack in, World world, EntityPlayer player) {
    if (in == null || !(in.getItem() instanceof ItemEtherealFamiliar))
      return false; // We call it "FamiliarAugment" Recipe for a reason..
    if (getRecipeInput() == null || !(getRecipeInput().getItem() instanceof ItemEtherealFamiliar))
      return false; // A bit late but still working..

    if ((this.research.length() > 0)
        && (!ThaumcraftApiHelper.isResearchComplete(
            player.getCommandSenderName(), this.research))) {
      return false;
    }

    FamiliarAugment.FamiliarAugmentList list = ItemEtherealFamiliar.getAugments(in);

    int level;
    if (list.contains(toAdd)) {
      level = list.getLevel(toAdd);
    } else {
      level = 0;
    }
    if (requiredPreviousLevel > level) return false; // Requires higher level to do this infusion.

    if (!toAdd.checkConditions(list, level + 1)) {
      return false; // Preconditions not met.
    }

    // Normal infusionrecipe stuff...

    ItemStack inCopy;
    ArrayList<ItemStack> ii = new ArrayList<ItemStack>();
    for (ItemStack is : input) {
      ii.add(is.copy());
    }
    for (ItemStack comp : getComponents()) {
      boolean b = false;
      for (int a = 0; a < ii.size(); a++) {
        inCopy = ii.get(a).copy();
        if (comp.getItemDamage() == 32767) {
          inCopy.setItemDamage(32767);
        }
        if (areItemStacksEqual(inCopy, comp, true)) {
          ii.remove(a);
          b = true;
          break;
        }
      }
      if (!b) {
        return false;
      }
    }
    return true;
  }
  /** Checks if the region of a crafting inventory is match for the recipe. */
  private boolean checkMatch(IInventory par1InventoryCrafting, int par2, int par3, boolean par4) {
    for (int var5 = 0; var5 < 3; ++var5) {
      for (int var6 = 0; var6 < 3; ++var6) {
        int var7 = var5 - par2;
        int var8 = var6 - par3;
        ItemStack var9 = null;

        if (var7 >= 0 && var8 >= 0 && var7 < this.recipeWidth && var8 < this.recipeHeight) {
          if (par4) {
            var9 = this.recipeItems[this.recipeWidth - var7 - 1 + var8 * this.recipeWidth];
          } else {
            var9 = this.recipeItems[var7 + var8 * this.recipeWidth];
          }
        }

        ItemStack var10 =
            ThaumcraftApiHelper.getStackInRowAndColumn(par1InventoryCrafting, var5, var6);

        if (var10 != null || var9 != null) {
          if (var10 == null && var9 != null || var10 != null && var9 == null) {
            return false;
          }

          if (var9.itemID != var10.itemID) {
            return false;
          }

          if (var9.getItemDamage() != -1 && var9.getItemDamage() != var10.getItemDamage()) {
            return false;
          }

          if (var9.hasTagCompound()) {
            NBTTagCompound tc = var9.getTagCompound();
            for (Object tag : tc.getTags().toArray()) {
              NBTBase base = (NBTBase) tag;
              Class nc = NBTBase.newTag(base.getId(), base.getName()).getClass();
              if (!(var10.hasTagCompound()
                  && nc.cast(var10.getTagCompound().getTag(base.getName()))
                      .equals(nc.cast(base)))) {
                return false;
              }
            }
          }
        }
      }
    }

    return true;
  }
  /**
   * Used to check if a recipe matches current crafting inventory
   *
   * @param player
   */
  public boolean matches(
      ArrayList<ItemStack> input, ItemStack central, World world, EntityPlayer player) {
    if (research.length() > 0
        && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) {
      return false;
    }

    if (!enchantment.canApply(central) || !central.getItem().isItemTool(central)) {
      return false;
    }

    Map map1 = EnchantmentHelper.getEnchantments(central);
    Iterator iterator = map1.keySet().iterator();
    while (iterator.hasNext()) {
      int j1 = ((Integer) iterator.next()).intValue();
      Enchantment ench = Enchantment.enchantmentsList[j1];
      if (j1 == enchantment.effectId
          && EnchantmentHelper.getEnchantmentLevel(j1, central) >= ench.getMaxLevel()) return false;
      if (enchantment.effectId != ench.effectId
          && (!enchantment.canApplyTogether(ench) || !ench.canApplyTogether(enchantment))) {
        return false;
      }
    }

    ItemStack i2 = null;

    ArrayList<ItemStack> ii = new ArrayList<ItemStack>();
    for (ItemStack is : input) {
      ii.add(is.copy());
    }

    for (ItemStack comp : components) {
      boolean b = false;
      for (int a = 0; a < ii.size(); a++) {
        i2 = ii.get(a).copy();
        if (comp.getItemDamage() == OreDictionary.WILDCARD_VALUE) {
          i2.setItemDamage(OreDictionary.WILDCARD_VALUE);
        }
        if (areItemStacksEqual(i2, comp, true)) {
          ii.remove(a);
          b = true;
          break;
        }
      }
      if (!b) return false;
    }
    //		System.out.println(ii.size());
    return ii.size() == 0 ? true : false;
  }
  /** Used to check if a recipe matches current crafting inventory */
  public boolean matches(IInventory par1InventoryCrafting, EntityPlayer player) {
    if (key.length() > 0 && !ThaumcraftApiHelper.isResearchComplete(player.username, key)) {
      return false;
    }
    for (int var2 = 0; var2 <= 3 - this.recipeWidth; ++var2) {
      for (int var3 = 0; var3 <= 3 - this.recipeHeight; ++var3) {
        if (this.checkMatch(par1InventoryCrafting, var2, var3, true)) {
          return true;
        }

        if (this.checkMatch(par1InventoryCrafting, var2, var3, false)) {
          return true;
        }
      }
    }

    return false;
  }
 private boolean areItemStacksEqual(ItemStack stack0, ItemStack stack1, boolean fuzzy) {
   if (stack0 == null && stack1 != null) return false;
   if (stack0 != null && stack1 == null) return false;
   if (stack0 == null && stack1 == null) return true;
   boolean t1 = false;
   if (fuzzy) {
     t1 = true;
     int od = OreDictionary.getOreID(stack0);
     if (od != -1) {
       ItemStack[] ores = OreDictionary.getOres(od).toArray(new ItemStack[] {});
       if (ThaumcraftApiHelper.containsMatch(false, new ItemStack[] {stack1}, ores)) return true;
     }
   } else t1 = ItemStack.areItemStackTagsEqual(stack0, stack1);
   return stack0.itemID != stack1.itemID
       ? false
       : (stack0.getItemDamage() != stack1.getItemDamage()
           ? false
           : (stack0.stackSize > stack0.getMaxStackSize() ? false : t1));
 }
  /**
   * Used to check if a recipe matches current crafting inventory
   *
   * @param player
   */
  public boolean matches(
      ArrayList<ItemStack> input, ItemStack central, World world, EntityPlayer player) {
    if (recipeInput == null) return false;

    if (research.length() > 0
        && !ThaumcraftApiHelper.isResearchComplete(player.username, research)) {
      return false;
    }

    ItemStack i2 = central.copy();
    if (recipeInput.getItemDamage() == OreDictionary.WILDCARD_VALUE) {
      i2.setItemDamage(OreDictionary.WILDCARD_VALUE);
    }

    if (!areItemStacksEqual(i2, recipeInput, true)) return false;

    ArrayList<ItemStack> ii = new ArrayList<ItemStack>();
    for (ItemStack is : input) {
      ii.add(is.copy());
    }

    for (ItemStack comp : components) {
      boolean b = false;
      for (int a = 0; a < ii.size(); a++) {
        i2 = ii.get(a).copy();
        if (comp.getItemDamage() == OreDictionary.WILDCARD_VALUE) {
          i2.setItemDamage(OreDictionary.WILDCARD_VALUE);
        }
        if (areItemStacksEqual(i2, comp, true)) {
          ii.remove(a);
          b = true;
          break;
        }
      }
      if (!b) return false;
    }
    //		System.out.println(ii.size());
    return ii.size() == 0 ? true : false;
  }