diff --git a/src/main/java/WayofTime/alchemicalWizardry/api/alchemy/AlchemyRecipe.java b/src/main/java/WayofTime/alchemicalWizardry/api/alchemy/AlchemyRecipe.java index 1aeb081fd..832a86c8c 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/api/alchemy/AlchemyRecipe.java +++ b/src/main/java/WayofTime/alchemicalWizardry/api/alchemy/AlchemyRecipe.java @@ -1,11 +1,12 @@ package WayofTime.alchemicalWizardry.api.alchemy; -import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraftforge.oredict.OreDictionary; public class AlchemyRecipe { + public static final int MAX_INPUT_SLOTS = 5; + private final ItemStack output; private final ItemStack[] recipe; private final int bloodOrbLevel; @@ -19,87 +20,75 @@ public AlchemyRecipe(ItemStack output, int amountNeeded, ItemStack[] recipe, int } public boolean doesRecipeMatch(ItemStack[] items, int slottedBloodOrbLevel) { + return getSlotUsage(items, slottedBloodOrbLevel) != null; + } + + /** + * Matches the recipe against the input slots and returns how many items have to be taken from each slot, or null if + * the recipe does not match. Duplicate ingredients may come from a single slot holding a large enough stack, and + * every non-empty slot has to be part of the recipe. + */ + public int[] getSlotUsage(ItemStack[] items, int slottedBloodOrbLevel) { if (slottedBloodOrbLevel < bloodOrbLevel) { - return false; + return null; } - ItemStack[] recipe; - - if (items.length < 5) { - return false; + if (items.length < MAX_INPUT_SLOTS) { + return null; } - if (this.recipe.length != 5) { - ItemStack[] newRecipe = new ItemStack[5]; + int[] usage = new int[MAX_INPUT_SLOTS]; - for (int i = 0; i < 5; i++) { - if (i + 1 > this.recipe.length) { - newRecipe[i] = null; - } else { - newRecipe[i] = this.recipe[i]; + // ponytail: wildcard ingredients are assigned last so they cannot steal a slot an exact ingredient needs. + // A full assignment search would only be needed for ingredients overlapping in more complex ways. + for (int pass = 0; pass < 2; pass++) { + for (ItemStack ingredient : recipe) { + if (ingredient == null) { + continue; } - } - - recipe = newRecipe; - } else { - recipe = this.recipe; - } - - boolean[] checkList = new boolean[5]; - - for (int i = 0; i < 5; i++) { - checkList[i] = false; - } - - for (int i = 0; i < 5; i++) { - ItemStack recipeItemStack = recipe[i]; - - if (recipeItemStack == null) { - continue; - } - boolean test = false; + boolean isWildcard = ingredient.getItemDamage() == OreDictionary.WILDCARD_VALUE; - for (int j = 0; j < 5; j++) { - if (checkList[j]) { + if (isWildcard != (pass == 1)) { continue; } - ItemStack checkedItemStack = items[j]; - - if (checkedItemStack == null) { - continue; + if (!assignIngredient(items, usage, ingredient)) { + return null; } + } + } - boolean quickTest = false; + for (int i = 0; i < MAX_INPUT_SLOTS; i++) { + if (items[i] != null && usage[i] == 0) { + return null; + } + } - if (recipeItemStack.getItem() instanceof ItemBlock) { - if (checkedItemStack.getItem() instanceof ItemBlock) { - quickTest = true; - } - } else if (!(checkedItemStack.getItem() instanceof ItemBlock)) { - quickTest = true; - } + return usage; + } - if (!quickTest) { - continue; - } + private static boolean assignIngredient(ItemStack[] items, int[] usage, ItemStack ingredient) { + for (int i = 0; i < MAX_INPUT_SLOTS; i++) { + ItemStack slotStack = items[i]; - if ((checkedItemStack.getItemDamage() == recipeItemStack.getItemDamage() - || OreDictionary.WILDCARD_VALUE == recipeItemStack.getItemDamage()) - && checkedItemStack.getItem() == recipeItemStack.getItem()) { - test = true; - checkList[j] = true; - break; - } + if (slotStack == null || slotStack.stackSize - usage[i] <= 0) { + continue; } - if (!test) { - return false; + if (matches(slotStack, ingredient)) { + usage[i]++; + return true; } } - return true; + return false; + } + + private static boolean matches(ItemStack slotStack, ItemStack ingredient) { + return slotStack.getItem() == ingredient.getItem() + && (ingredient.getItemDamage() == OreDictionary.WILDCARD_VALUE + || slotStack.getItemDamage() == ingredient.getItemDamage()); } public ItemStack getResult() { diff --git a/src/main/java/WayofTime/alchemicalWizardry/api/alchemy/AlchemyRecipeRegistry.java b/src/main/java/WayofTime/alchemicalWizardry/api/alchemy/AlchemyRecipeRegistry.java index 16bfe2874..9411782fd 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/api/alchemy/AlchemyRecipeRegistry.java +++ b/src/main/java/WayofTime/alchemicalWizardry/api/alchemy/AlchemyRecipeRegistry.java @@ -15,7 +15,7 @@ public static void registerRecipe(ItemStack output, int amountNeeded, ItemStack[ recipes.add(new AlchemyRecipe(output, amountNeeded, recipe, bloodOrbLevel)); } - public static ItemStack getResult(ItemStack[] recipe, ItemStack bloodOrb) { + public static AlchemyRecipe findRecipe(ItemStack[] recipe, ItemStack bloodOrb) { if (bloodOrb == null) { return null; } @@ -28,31 +28,23 @@ public static ItemStack getResult(ItemStack[] recipe, ItemStack bloodOrb) { for (AlchemyRecipe ar : recipes) { if (ar.doesRecipeMatch(recipe, bloodOrbLevel)) { - return (ar.getResult()); + return ar; } } return null; } - public static int getAmountNeeded(ItemStack[] recipe, ItemStack bloodOrb) { - if (bloodOrb == null) { - return 0; - } - - if (!(bloodOrb.getItem() instanceof IBloodOrb)) { - return 0; - } + public static ItemStack getResult(ItemStack[] recipe, ItemStack bloodOrb) { + AlchemyRecipe ar = findRecipe(recipe, bloodOrb); - int bloodOrbLevel = ((IBloodOrb) bloodOrb.getItem()).getOrbLevel(); + return ar == null ? null : ar.getResult(); + } - for (AlchemyRecipe ar : recipes) { - if (ar.doesRecipeMatch(recipe, bloodOrbLevel)) { - return (ar.getAmountNeeded()); - } - } + public static int getAmountNeeded(ItemStack[] recipe, ItemStack bloodOrb) { + AlchemyRecipe ar = findRecipe(recipe, bloodOrb); - return 0; + return ar == null ? 0 : ar.getAmountNeeded(); } public static ItemStack[] getRecipeForItemStack(ItemStack itemStack) { diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TEWritingTable.java b/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TEWritingTable.java index 5d9e76509..81ef0783d 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TEWritingTable.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TEWritingTable.java @@ -13,7 +13,6 @@ import net.minecraft.util.StatCollector; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.oredict.OreDictionary; import WayofTime.alchemicalWizardry.ModItems; import WayofTime.alchemicalWizardry.api.alchemy.AlchemicalPotionCreationHandler; @@ -582,11 +581,7 @@ public void updateEntity() { progress = 0; this.setInventorySlotContents(6, getResultingItemStack()); - ItemStack[] composedRecipe = new ItemStack[5]; - - System.arraycopy(inv, 1, composedRecipe, 0, 5); - - this.decrementSlots(this.getRecipeForItems(composedRecipe, inv[0])); + this.consumeIngredients(); if (worldObj != null) { worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); @@ -623,11 +618,7 @@ && getResultingItemStack().stackSize result.stackSize += getStackInSlot(6).stackSize; this.setInventorySlotContents(6, result); - ItemStack[] composedRecipe = new ItemStack[5]; - - System.arraycopy(inv, 1, composedRecipe, 0, 5); - - this.decrementSlots(this.getRecipeForItems(composedRecipe, inv[0])); + this.consumeIngredients(); if (worldObj != null) { worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); @@ -637,54 +628,40 @@ && getResultingItemStack().stackSize } } - public void decrementSlots(ItemStack[] recipe) { - boolean[] decrementedList = new boolean[] { false, false, false, false, false }; + public void consumeIngredients() { + ItemStack[] composedRecipe = new ItemStack[AlchemyRecipe.MAX_INPUT_SLOTS]; - for (int i = 0; i < (Math.min(recipe.length, 5)); i++) { - ItemStack decStack = recipe[i]; + System.arraycopy(inv, 1, composedRecipe, 0, AlchemyRecipe.MAX_INPUT_SLOTS); - if (decStack == null) { - continue; - } + AlchemyRecipe recipe = AlchemyRecipeRegistry.findRecipe(composedRecipe, inv[0]); - for (int j = 0; j < 5; j++) { - ItemStack testStack = this.getStackInSlot(j + 1); - - if (testStack != null - && (testStack.isItemEqual(decStack) || (testStack.getItem() == decStack.getItem() - && decStack.getItemDamage() == OreDictionary.WILDCARD_VALUE)) - && !(decrementedList[j])) { - if (testStack.getItem() != null && testStack.getItem().hasContainerItem(testStack)) { - this.inv[j + 1] = testStack.getItem().getContainerItem(testStack); - } else { - this.decrStackSize(j + 1, 1); - } - - decrementedList[j] = true; - break; - } - } + if (recipe == null) { + return; } - } - public ItemStack[] getRecipeForItems(ItemStack[] recipe, ItemStack bloodOrb) { - if (bloodOrb == null) { - return null; - } + int[] usage = recipe.getSlotUsage(composedRecipe, ((IBloodOrb) inv[0].getItem()).getOrbLevel()); - if (!(bloodOrb.getItem() instanceof IBloodOrb)) { - return null; + if (usage == null) { + return; } - int bloodOrbLevel = ((IBloodOrb) bloodOrb.getItem()).getOrbLevel(); + for (int i = 0; i < usage.length; i++) { + if (usage[i] <= 0) { + continue; + } + + ItemStack slotStack = this.getStackInSlot(i + 1); - for (AlchemyRecipe ar : AlchemyRecipeRegistry.recipes) { - if (ar.doesRecipeMatch(recipe, bloodOrbLevel)) { - return ar.getRecipe(); + if (slotStack == null) { + continue; } - } - return null; + if (slotStack.getItem().hasContainerItem(slotStack) && slotStack.stackSize == usage[i]) { + this.inv[i + 1] = slotStack.getItem().getContainerItem(slotStack); + } else { + this.decrStackSize(i + 1, usage[i]); + } + } } public int getSpeedIncrease() {