package thaumcraft.api.crafting; import java.util.ArrayList; import java.util.HashMap; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import net.minecraftforge.oredict.OreDictionary; import thaumcraft.api.ThaumcraftApiHelper; import thaumcraft.api.aspects.AspectList; public class ShapedArcaneRecipe implements IArcaneRecipe { //Added in for future ease of change, but hard coded for now. private static final int MAX_CRAFT_GRID_WIDTH = 3; private static final int MAX_CRAFT_GRID_HEIGHT = 3; public ItemStack output = null; public Object[] input = null; public AspectList aspects = null; public String research; public int width = 0; public int height = 0; private boolean mirrored = true; public ShapedArcaneRecipe(String research, Block result, AspectList aspects, Object... recipe){ this(research, new ItemStack(result), aspects, recipe); } public ShapedArcaneRecipe(String research, Item result, AspectList aspects, Object... recipe){ this(research, new ItemStack(result), aspects, recipe); } public ShapedArcaneRecipe(String research, ItemStack result, AspectList aspects, Object... recipe) { output = result.copy(); this.research = research; this.aspects = aspects; String shape = ""; int idx = 0; if (recipe[idx] instanceof Boolean) { mirrored = (Boolean)recipe[idx]; if (recipe[idx+1] instanceof Object[]) { recipe = (Object[])recipe[idx+1]; } else { idx = 1; } } if (recipe[idx] instanceof String[]) { String[] parts = ((String[])recipe[idx++]); for (String s : parts) { width = s.length(); shape += s; } height = parts.length; } else { while (recipe[idx] instanceof String) { String s = (String)recipe[idx++]; shape += s; width = s.length(); height++; } } if (width * height != shape.length()) { String ret = "Invalid shaped ore recipe: "; for (Object tmp : recipe) { ret += tmp + ", "; } ret += output; throw new RuntimeException(ret); } HashMap<Character, Object> itemMap = new HashMap<Character, Object>(); for (; idx < recipe.length; idx += 2) { Character chr = (Character)recipe[idx]; Object in = recipe[idx + 1]; if (in instanceof ItemStack) { itemMap.put(chr, ((ItemStack)in).copy()); } else if (in instanceof Item) { itemMap.put(chr, new ItemStack((Item)in)); } else if (in instanceof Block) { itemMap.put(chr, new ItemStack((Block)in, 1, OreDictionary.WILDCARD_VALUE)); } else if (in instanceof String) { itemMap.put(chr, OreDictionary.getOres((String)in)); } else { String ret = "Invalid shaped ore recipe: "; for (Object tmp : recipe) { ret += tmp + ", "; } ret += output; throw new RuntimeException(ret); } } input = new Object[width * height]; int x = 0; for (char chr : shape.toCharArray()) { input[x++] = itemMap.get(chr); } } @Override public ItemStack getCraftingResult(IInventory var1){ return output.copy(); } @Override public int getRecipeSize(){ return input.length; } @Override public ItemStack getRecipeOutput(){ return output; } @Override public boolean matches(IInventory inv, World world, EntityPlayer player) { if (research.length()>0 && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) { return false; } for (int x = 0; x <= MAX_CRAFT_GRID_WIDTH - width; x++) { for (int y = 0; y <= MAX_CRAFT_GRID_HEIGHT - height; ++y) { if (checkMatch(inv, x, y, false)) { return true; } if (mirrored && checkMatch(inv, x, y, true)) { return true; } } } return false; } private boolean checkMatch(IInventory inv, int startX, int startY, boolean mirror) { for (int x = 0; x < MAX_CRAFT_GRID_WIDTH; x++) { for (int y = 0; y < MAX_CRAFT_GRID_HEIGHT; y++) { int subX = x - startX; int subY = y - startY; Object target = null; if (subX >= 0 && subY >= 0 && subX < width && subY < height) { if (mirror) { target = input[width - subX - 1 + subY * width]; } else { target = input[subX + subY * width]; } } ItemStack slot = ThaumcraftApiHelper.getStackInRowAndColumn(inv, x, y); if (target instanceof ItemStack) { if (!checkItemEquals((ItemStack)target, slot)) { return false; } } else if (target instanceof ArrayList) { boolean matched = false; for (ItemStack item : (ArrayList<ItemStack>)target) { matched = matched || checkItemEquals(item, slot); } if (!matched) { return false; } } else if (target == null && slot != null) { return false; } } } return true; } private boolean checkItemEquals(ItemStack target, ItemStack input) { if (input == null && target != null || input != null && target == null) { return false; } return (target.getItem() == input.getItem() && (!target.hasTagCompound() || ThaumcraftApiHelper.areItemStackTagsEqualForCrafting(input,target)) && (target.getItemDamage() == OreDictionary.WILDCARD_VALUE|| target.getItemDamage() == input.getItemDamage())); } public ShapedArcaneRecipe setMirrored(boolean mirror) { mirrored = mirror; return this; } /** * Returns the input for this recipe, any mod accessing this value should never * manipulate the values in this array as it will effect the recipe itself. * @return The recipes input vales. */ public Object[] getInput() { return this.input; } @Override public AspectList getAspects() { return aspects; } @Override public AspectList getAspects(IInventory inv) { return aspects; } @Override public String getResearch() { return research; } }