package gr8pefish.ironbackpacks.crafting; import gr8pefish.ironbackpacks.api.items.backpacks.interfaces.IUpgradableBackpack; import gr8pefish.ironbackpacks.api.recipes.IRemoveUpgradeRecipe; import gr8pefish.ironbackpacks.api.register.ItemIUpgradeRegistry; import gr8pefish.ironbackpacks.container.backpack.InventoryBackpack; import gr8pefish.ironbackpacks.items.backpacks.ItemBackpack; import gr8pefish.ironbackpacks.items.upgrades.UpgradeMethods; import gr8pefish.ironbackpacks.registry.ItemRegistry; import gr8pefish.ironbackpacks.util.IronBackpacksConstants; import gr8pefish.ironbackpacks.util.helpers.IronBackpacksHelper; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.world.World; import net.minecraftforge.oredict.OreDictionary; import net.minecraftforge.oredict.ShapelessOreRecipe; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Deals with the cases when a backpack is shapelessly crafted alone to remove an upgrade. */ public class BackpackRemoveUpgradeRecipe extends ShapelessOreRecipe implements IRemoveUpgradeRecipe { private ItemStack recipeOutput; //The outputted items after recipes private ItemStack upgradeRemovedStack; public BackpackRemoveUpgradeRecipe(ItemStack recipeOutput, Object... items) { super(recipeOutput, items); this.recipeOutput = recipeOutput; } /** * Crafts the backpack by itself to remove an upgrade; * First it checks if the backpack has any upgrades. * If it does it progresses, otherwise it returns null; * <p/> * Then it checks for where the backpack is located in the recipes grid. * It then removes the upgrade in said slot. So if it is in the 2nd slot then it removes the 2nd upgrade on the backpack. * * @param inventoryCrafting - the inventory recipes to check * @return - the resulting itemstack */ @Override public ItemStack getCraftingResult(InventoryCrafting inventoryCrafting) { int slotOfBackpack = getFirstUpgradableBackpackSlotNumber(inventoryCrafting); if (slotOfBackpack == -1) //if no backpack return null; //return no output //get the backpack ItemStack backpack = inventoryCrafting.getStackInSlot(slotOfBackpack); ItemStack result = backpack.copy(); //get the upgrades ArrayList<ItemStack> upgrades = IronBackpacksHelper.getUpgradesAppliedFromNBT(result); if (upgrades.isEmpty()) //no upgrades return null; //no output itemStack, i.e. no recipes result //get the old tag compound NBTTagCompound nbtTagCompound = result.getTagCompound(); if (nbtTagCompound == null) { nbtTagCompound = new NBTTagCompound(); nbtTagCompound.setTag(IronBackpacksConstants.NBTKeys.ITEMS, new NBTTagList()); result.setTagCompound(nbtTagCompound); } //make sure that we can check for an upgrade to remove boolean nullChecksPassed = false; ItemStack upgradeInQuestion = null; if ((slotOfBackpack <= (upgrades.size() - 1)) && (slotOfBackpack >= 0) && (upgrades.get(slotOfBackpack) != null)) { upgradeInQuestion = upgrades.get(slotOfBackpack); //can't remove it if is a nesting upgrade and there are nested backpacks inside //ToDo: Give descriptive error message to player if (!canRemoveNestingUpgrade(backpack, upgradeInQuestion)) { upgradeInQuestion = null; } else { nullChecksPassed = true; } } //init variables for the return stack boolean upgradeRemoved = false; NBTTagList tagList = new NBTTagList(); for (ItemStack upgrade : upgrades) { //for each slot in possible upgrades if (nullChecksPassed && (UpgradeMethods.areUpgradesFunctionallyEquivalent(upgrade, upgradeInQuestion))) { //same upgrade, remove it upgradeRemoved = true; //not adding the old recipe is the same outcome as removing the recipe, so no code needed here if (ItemIUpgradeRegistry.isInstanceOfIConfigurableUpgrade(upgradeInQuestion)) //if in alt gui need to remove the stored items there nbtTagCompound.setTag(IronBackpacksConstants.NBTKeys.REMOVED_ALT_GUI, upgradeInQuestion.writeToNBT(new NBTTagCompound())); //add items stack to nbt key } else { //save old contents to new tag tagList.appendTag(upgrade.writeToNBT(new NBTTagCompound())); } } //set the new tag compound and return the new stack if it has changed nbtTagCompound.setTag(IronBackpacksConstants.NBTKeys.UPGRADES, tagList); if (upgradeRemoved) { upgradeRemovedStack = upgradeInQuestion; return result; } else { upgradeRemovedStack = null; return null; } } @Override //copied directly from ShapelessOreRecipe public boolean matches(InventoryCrafting var1, World world) { ArrayList<Object> required = new ArrayList<Object>(input); for (int x = 0; x < var1.getSizeInventory(); x++) { ItemStack slot = var1.getStackInSlot(x); if (slot != null) { boolean inRecipe = false; Iterator<Object> req = required.iterator(); while (req.hasNext()) { boolean match = false; Object next = req.next(); if (next instanceof ItemStack) { match = OreDictionary.itemMatches((ItemStack)next, slot, false); } else if (next instanceof List) { Iterator<ItemStack> itr = ((List<ItemStack>)next).iterator(); while (itr.hasNext() && !match) { match = OreDictionary.itemMatches(itr.next(), slot, false); } } if (match) { inRecipe = true; required.remove(next); break; } } if (!inRecipe) { return false; } } } return required.isEmpty(); } @Override public ItemStack getRecipeOutput() { return recipeOutput; } @Override public ItemStack[] getRemainingItems(InventoryCrafting inv){ //needs matches overridden due to (Forge?) bug if (upgradeRemovedStack != null){ ItemStack[] ret = new ItemStack[inv.getSizeInventory()]; ret[0] = upgradeRemovedStack.copy(); for (int i = 1; i < ret.length; i++) { ret[i] = null; //remove everything else (i.e can't leave backpack) } return ret; }else{ return super.getRemainingItems(inv); } } //=============================================================================Helper Methods==================================================================== /** * Helper method for getting the first backpack in the recipes grid (which will be the one used) * @param inventoryCrafting - the inventory to search * @return - the integer of the slot number that the backpack is in (-1 if no slot found) */ private int getFirstUpgradableBackpackSlotNumber(InventoryCrafting inventoryCrafting) { for (int i = 0; i < 9; ++i) { ItemStack itemstack = inventoryCrafting.getStackInSlot(i); if (itemstack != null && (itemstack.getItem() instanceof IUpgradableBackpack)) return i; } return -1; } /** * Find an empty slot in the recipes grid to put the removed upgrade in. * @param inventoryCrafting - the inventory to search * @return - the integer of the slot number of the empty slot (-1 if no slot found) */ public static int findEmptySlot(IInventory inventoryCrafting) { for (int i = 0; i < 9; i++) { ItemStack itemstack = inventoryCrafting.getStackInSlot(i); if (itemstack == null) return i; } return -1; } /** * Checks if the upgrade is a nesting or advanced nesting, and then checks if the backpack has any nested inside of it, because if it does the upgrade should be impossible to remove. * @param backpack - the backpack to remove the upgrade from * @param upgrade - the upgrade in question * @return true if it can be removed, false otherwise */ private boolean canRemoveNestingUpgrade(ItemStack backpack, ItemStack upgrade) { if (ItemIUpgradeRegistry.isInstanceOfIConflictingUpgrade(upgrade)) { if (ItemIUpgradeRegistry.getItemIConflictingUpgrade(upgrade.getItemDamage()).equals(ItemRegistry.nestingUpgrade) || ItemIUpgradeRegistry.getItemIConflictingUpgrade(upgrade.getItemDamage()).equals(ItemRegistry.nestingAdvancedUpgrade)) { //check if has backpack of any tier inside InventoryBackpack inventoryBackpack = new InventoryBackpack(backpack, true); for (int i = 0; i < inventoryBackpack.getSizeInventory(); i++){ if (inventoryBackpack.getStackInSlot(i) != null && inventoryBackpack.getStackInSlot(i).getItem() instanceof ItemBackpack) { return false; } } } } return true; } }