001 package net.minecraftforge.oredict;
002
003 import java.util.ArrayList;
004 import java.util.HashMap;
005 import java.util.Map;
006 import java.util.Map.Entry;
007
008 import net.minecraft.block.Block;
009 import net.minecraft.item.crafting.IRecipe;
010 import net.minecraft.inventory.InventoryCrafting;
011 import net.minecraft.item.Item;
012 import net.minecraft.item.ItemStack;
013 import net.minecraft.item.crafting.ShapedRecipes;
014 import net.minecraft.world.World;
015
016 public class ShapedOreRecipe implements IRecipe
017 {
018 //Added in for future ease of change, but hard coded for now.
019 private static final int MAX_CRAFT_GRID_WIDTH = 3;
020 private static final int MAX_CRAFT_GRID_HEIGHT = 3;
021
022 private ItemStack output = null;
023 private Object[] input = null;
024 private int width = 0;
025 private int height = 0;
026 private boolean mirrored = true;
027
028 public ShapedOreRecipe(Block result, Object... recipe){ this(new ItemStack(result), recipe); }
029 public ShapedOreRecipe(Item result, Object... recipe){ this(new ItemStack(result), recipe); }
030 public ShapedOreRecipe(ItemStack result, Object... recipe)
031 {
032 output = result.copy();
033
034 String shape = "";
035 int idx = 0;
036
037 if (recipe[idx] instanceof Boolean)
038 {
039 mirrored = (Boolean)recipe[idx];
040 if (recipe[idx+1] instanceof Object[])
041 {
042 recipe = (Object[])recipe[idx+1];
043 }
044 else
045 {
046 idx = 1;
047 }
048 }
049
050 if (recipe[idx] instanceof String[])
051 {
052 String[] parts = ((String[])recipe[idx++]);
053
054 for (String s : parts)
055 {
056 width = s.length();
057 shape += s;
058 }
059
060 height = parts.length;
061 }
062 else
063 {
064 while (recipe[idx] instanceof String)
065 {
066 String s = (String)recipe[idx++];
067 shape += s;
068 width = s.length();
069 height++;
070 }
071 }
072
073 if (width * height != shape.length())
074 {
075 String ret = "Invalid shaped ore recipe: ";
076 for (Object tmp : recipe)
077 {
078 ret += tmp + ", ";
079 }
080 ret += output;
081 throw new RuntimeException(ret);
082 }
083
084 HashMap<Character, Object> itemMap = new HashMap<Character, Object>();
085
086 for (; idx < recipe.length; idx += 2)
087 {
088 Character chr = (Character)recipe[idx];
089 Object in = recipe[idx + 1];
090 Object val = null;
091
092 if (in instanceof ItemStack)
093 {
094 itemMap.put(chr, ((ItemStack)in).copy());
095 }
096 else if (in instanceof Item)
097 {
098 itemMap.put(chr, new ItemStack((Item)in));
099 }
100 else if (in instanceof Block)
101 {
102 itemMap.put(chr, new ItemStack((Block)in, 1, -1));
103 }
104 else if (in instanceof String)
105 {
106 itemMap.put(chr, OreDictionary.getOres((String)in));
107 }
108 else
109 {
110 String ret = "Invalid shaped ore recipe: ";
111 for (Object tmp : recipe)
112 {
113 ret += tmp + ", ";
114 }
115 ret += output;
116 throw new RuntimeException(ret);
117 }
118 }
119
120 input = new Object[width * height];
121 int x = 0;
122 for (char chr : shape.toCharArray())
123 {
124 input[x++] = itemMap.get(chr);
125 }
126 }
127
128 ShapedOreRecipe(ShapedRecipes recipe, Map<ItemStack, String> replacements)
129 {
130 output = recipe.getRecipeOutput();
131 width = recipe.recipeWidth;
132 height = recipe.recipeHeight;
133
134 input = new Object[recipe.recipeItems.length];
135
136 for(int i = 0; i < input.length; i++)
137 {
138 ItemStack ingred = recipe.recipeItems[i];
139
140 if(ingred == null) continue;
141
142 input[i] = recipe.recipeItems[i];
143
144 for(Entry<ItemStack, String> replace : replacements.entrySet())
145 {
146 if(OreDictionary.itemMatches(replace.getKey(), ingred, true))
147 {
148 input[i] = OreDictionary.getOres(replace.getValue());
149 break;
150 }
151 }
152 }
153 }
154
155 @Override
156 public ItemStack getCraftingResult(InventoryCrafting var1){ return output.copy(); }
157
158 @Override
159 public int getRecipeSize(){ return input.length; }
160
161 @Override
162 public ItemStack getRecipeOutput(){ return output; }
163
164 @Override
165 public boolean matches(InventoryCrafting inv, World world)
166 {
167 for (int x = 0; x <= MAX_CRAFT_GRID_WIDTH - width; x++)
168 {
169 for (int y = 0; y <= MAX_CRAFT_GRID_HEIGHT - height; ++y)
170 {
171 if (checkMatch(inv, x, y, true))
172 {
173 return true;
174 }
175
176 if (mirrored && checkMatch(inv, x, y, false))
177 {
178 return true;
179 }
180 }
181 }
182
183 return false;
184 }
185
186 private boolean checkMatch(InventoryCrafting inv, int startX, int startY, boolean mirror)
187 {
188 for (int x = 0; x < MAX_CRAFT_GRID_WIDTH; x++)
189 {
190 for (int y = 0; y < MAX_CRAFT_GRID_HEIGHT; y++)
191 {
192 int subX = x - startX;
193 int subY = y - startY;
194 Object target = null;
195
196 if (subX >= 0 && subY >= 0 && subX < width && subY < height)
197 {
198 if (mirror)
199 {
200 target = input[width - subX - 1 + subY * width];
201 }
202 else
203 {
204 target = input[subX + subY * width];
205 }
206 }
207
208 ItemStack slot = inv.getStackInRowAndColumn(x, y);
209
210 if (target instanceof ItemStack)
211 {
212 if (!checkItemEquals((ItemStack)target, slot))
213 {
214 return false;
215 }
216 }
217 else if (target instanceof ArrayList)
218 {
219 boolean matched = false;
220
221 for (ItemStack item : (ArrayList<ItemStack>)target)
222 {
223 matched = matched || checkItemEquals(item, slot);
224 }
225
226 if (!matched)
227 {
228 return false;
229 }
230 }
231 else if (target == null && slot != null)
232 {
233 return false;
234 }
235 }
236 }
237
238 return true;
239 }
240
241 private boolean checkItemEquals(ItemStack target, ItemStack input)
242 {
243 if (input == null && target != null || input != null && target == null)
244 {
245 return false;
246 }
247 return (target.itemID == input.itemID && (target.getItemDamage() == -1 || target.getItemDamage() == input.getItemDamage()));
248 }
249
250 public ShapedOreRecipe setMirrored(boolean mirror)
251 {
252 mirrored = mirror;
253 return this;
254 }
255 }