This commit is contained in:
WayofTime 2014-01-17 14:12:49 -05:00
commit 8601e9faff
498 changed files with 45817 additions and 0 deletions

View file

@ -0,0 +1,21 @@
package thaumcraft.api;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
/**
*
* @author Azanor
*
* Equipped head slot items that extend this class will be able to perform most functions that
* goggles of revealing can apart from view nodes which is handled by IRevealer.
*
*/
public interface IGoggles
{
/*
* If this method returns true things like block essentia contents will be shown.
*/
public boolean showIngamePopups(ItemStack itemstack, EntityLivingBase player);
}

View file

@ -0,0 +1,10 @@
package thaumcraft.api;
/**
* @author Azanor
* Items, armor and tools with this interface can receive the Repair enchantment.
* Repairs 1 point of durability every 10 seconds (2 for repair II)
*/
public interface IRepairable
{
}

View file

@ -0,0 +1,14 @@
package thaumcraft.api;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
/**
* @author Azanor
* Items, armor and tools with this interface can receive the Repair enchantment.
* Repairs 1 point of durability every 10 seconds (2 for repair II)
*/
public interface IRepairableExtended extends IRepairable
{
public boolean doRepair(ItemStack stack, EntityPlayer player, int enchantlevel);
}

View file

@ -0,0 +1,12 @@
package thaumcraft.api;
/**
* @author Azanor
* ItemArmor with this interface will grant a discount to the vis cost of actions the wearer performs with casting wands.
* The amount returned is the percentage by which the cost is discounted. There is a built-int max discount of 50%, but
* individual items really shouldn't have a discount more than 5%
*/
public interface IVisDiscounter
{
int getVisDiscount();
}

View file

@ -0,0 +1,86 @@
package thaumcraft.api;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import cpw.mods.fml.common.FMLLog;
/**
* @author Azanor
*
* This is used to gain access to the items in my mod.
* I only give some examples and it will probably still
* require a bit of work for you to get hold of everything you need.
*
*/
public class ItemApi
{
public static ItemStack getItem(String itemString, int meta)
{
ItemStack item = null;
try
{
String itemClass = "thaumcraft.common.config.ConfigItems";
Object obj = Class.forName(itemClass).getField(itemString).get(null);
if (obj instanceof Item)
{
item = new ItemStack((Item) obj, 1, meta);
}
else if (obj instanceof ItemStack)
{
item = (ItemStack) obj;
}
}
catch (Exception ex)
{
FMLLog.warning("[Thaumcraft] Could not retrieve item identified by: " + itemString);
}
return item;
}
public static ItemStack getBlock(String itemString, int meta)
{
ItemStack item = null;
try
{
String itemClass = "thaumcraft.common.config.ConfigBlocks";
Object obj = Class.forName(itemClass).getField(itemString).get(null);
if (obj instanceof Block)
{
item = new ItemStack((Block) obj, 1, meta);
}
else if (obj instanceof ItemStack)
{
item = (ItemStack) obj;
}
}
catch (Exception ex)
{
FMLLog.warning("[Thaumcraft] Could not retrieve block identified by: " + itemString);
}
return item;
}
/**
*
* Some examples
*
* Casting Wands:
* itemWandCasting
*
* Resources:
* itemEssence, itemWispEssence, itemResource, itemShard, itemNugget,
* itemNuggetChicken, itemNuggetBeef, itemNuggetPork, itemTripleMeatTreat
*
* Research:
* itemResearchNotes, itemInkwell, itemThaumonomicon
*
*/
}

View file

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Azanor
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,10 @@
thaumcraft-api
==============
Thaumcraft Api
This is just to create an easy to access place for the api code.
I will still place the zips on the minecraft forum post for the "official" version of the api - the code here will usually be for dev versions.

View file

@ -0,0 +1,513 @@
package thaumcraft.api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumArmorMaterial;
import net.minecraft.item.EnumToolMaterial;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraftforge.common.EnumHelper;
import net.minecraftforge.oredict.OreDictionary;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
import thaumcraft.api.crafting.CrucibleRecipe;
import thaumcraft.api.crafting.InfusionEnchantmentRecipe;
import thaumcraft.api.crafting.InfusionRecipe;
import thaumcraft.api.crafting.ShapedArcaneRecipe;
import thaumcraft.api.crafting.ShapelessArcaneRecipe;
import thaumcraft.api.research.IScanEventHandler;
import thaumcraft.api.research.ResearchCategories;
import thaumcraft.api.research.ResearchCategoryList;
import thaumcraft.api.research.ResearchItem;
import thaumcraft.api.research.ResearchPage;
/**
* @author Azanor
*
*
* IMPORTANT: If you are adding your own aspects to items it is a good idea to do it AFTER Thaumcraft adds its aspects, otherwise odd things may happen.
*
*/
public class ThaumcraftApi
{
//Materials
public static EnumToolMaterial toolMatThaumium = EnumHelper.addToolMaterial("THAUMIUM", 3, 400, 7F, 2, 22);
public static EnumToolMaterial toolMatElemental = EnumHelper.addToolMaterial("THAUMIUM_ELEMENTAL", 3, 1500, 10F, 3, 18);
public static EnumArmorMaterial armorMatThaumium = EnumHelper.addArmorMaterial("THAUMIUM", 25, new int[] { 2, 6, 5, 2 }, 25);
public static EnumArmorMaterial armorMatSpecial = EnumHelper.addArmorMaterial("SPECIAL", 25, new int[] { 1, 3, 2, 1 }, 25);
//Enchantment references
public static int enchantFrugal;
public static int enchantPotency;
public static int enchantWandFortune;
public static int enchantHaste;
public static int enchantRepair;
//Miscellaneous
/**
* Portable Hole Block-id Blacklist.
* Simply add the block-id's of blocks you don't want the portable hole to go through.
*/
public static ArrayList<Integer> portableHoleBlackList = new ArrayList<Integer>();
//RESEARCH/////////////////////////////////////////
public static ArrayList<IScanEventHandler> scanEventhandlers = new ArrayList<IScanEventHandler>();
public static ArrayList<EntityTags> scanEntities = new ArrayList<EntityTags>();
public static class EntityTags
{
public EntityTags(String entityName, NBTBase[] nbts, AspectList aspects)
{
this.entityName = entityName;
this.nbts = nbts;
this.aspects = aspects;
}
public String entityName;
public NBTBase[] nbts;
public AspectList aspects;
}
/**
* not really working atm, so ignore it for now
* @param scanEventHandler
*/
public static void registerScanEventhandler(IScanEventHandler scanEventHandler)
{
scanEventhandlers.add(scanEventHandler);
}
/**
* This is used to add aspects to entities which you can then scan using a thaumometer.
* Also used to calculate vis drops from mobs.
* @param entityName
* @param aspects
* @param nbt you can specify certain nbt keys and their values
* to differentiate between mobs. <br>For example the normal and wither skeleton:
* <br>ThaumcraftApi.registerEntityTag("Skeleton", (new AspectList()).add(Aspect.DEATH, 5));
* <br>ThaumcraftApi.registerEntityTag("Skeleton", (new AspectList()).add(Aspect.DEATH, 8), new NBTTagByte("SkeletonType",(byte) 1));
*/
public static void registerEntityTag(String entityName, AspectList aspects, NBTBase... nbt)
{
scanEntities.add(new EntityTags(entityName, nbt, aspects));
}
//RECIPES/////////////////////////////////////////
private static ArrayList craftingRecipes = new ArrayList();
private static HashMap<List, ItemStack> smeltingBonus = new HashMap<List, ItemStack>();
private static ArrayList<List> smeltingBonusExlusion = new ArrayList<List>();
/**
* This method is used to determine what bonus items are generated when the infernal furnace smelts items
* @param in The result (not input) of the smelting operation. e.g. new ItemStack(ingotGold)
* @param out The bonus item that can be produced from the smelting operation e.g. new ItemStack(nuggetGold,0,0).
* Stacksize should be 0 unless you want to guarantee that at least 1 item is always produced.
*/
public static void addSmeltingBonus(ItemStack in, ItemStack out)
{
smeltingBonus.put(
Arrays.asList(in.itemID, in.getItemDamage()),
new ItemStack(out.itemID, 0, out.getItemDamage()));
}
/**
* Returns the bonus item produced from a smelting operation in the infernal furnace
* @param in The result of the smelting operation. e.g. new ItemStack(ingotGold)
* @return the The bonus item that can be produced
*/
public static ItemStack getSmeltingBonus(ItemStack in)
{
return smeltingBonus.get(Arrays.asList(in.itemID, in.getItemDamage()));
}
/**
* Excludes specific items from producing bonus items when they are smelted in the infernal furnace, even
* if their smelt result would normally produce a bonus item.
* @param in The item to be smelted that should never produce a bonus item (e.g. the various macerated dusts form IC2)
* Even though they produce gold, iron, etc. ingots, they should NOT produce bonus nuggets as well.
*
* Smelting exclusions can also be done via the FMLInterModComms in your @Mod.Init method using "smeltBonusExclude"
* Example for vanilla iron:
* FMLInterModComms.sendMessage("Thaumcraft", "smeltBonusExclude", new ItemStack(Item.ingotIron));
*/
public static void addSmeltingBonusExclusion(ItemStack in)
{
smeltingBonusExlusion.add(Arrays.asList(in.itemID, in.getItemDamage()));
}
/**
* Sees if an item is allowed to produce bonus items when smelted in the infernal furnace
* @param in The item you wish to check
* @return true or false
*/
public static boolean isSmeltingBonusExluded(ItemStack in)
{
return smeltingBonusExlusion.contains(Arrays.asList(in.itemID, in.getItemDamage()));
}
public static List getCraftingRecipes()
{
return craftingRecipes;
}
/**
* @param research the research key required for this recipe to work. Leave blank if it will work without research
* @param result the recipe output
* @param aspects the vis cost per aspect.
* @param recipe The recipe. Format is exactly the same as vanilla recipes. Input itemstacks are NBT sensitive.
*/
public static ShapedArcaneRecipe addArcaneCraftingRecipe(String research, ItemStack result, AspectList aspects, Object ... recipe)
{
ShapedArcaneRecipe r = new ShapedArcaneRecipe(research, result, aspects, recipe);
craftingRecipes.add(r);
return r;
}
/**
* @param research the research key required for this recipe to work. Leave blank if it will work without research
* @param result the recipe output
* @param aspects the vis cost per aspect
* @param recipe The recipe. Format is exactly the same as vanilla shapeless recipes. Input itemstacks are NBT sensitive.
*/
public static ShapelessArcaneRecipe addShapelessArcaneCraftingRecipe(String research, ItemStack result, AspectList aspects, Object ... recipe)
{
ShapelessArcaneRecipe r = new ShapelessArcaneRecipe(research, result, aspects, recipe);
craftingRecipes.add(r);
return r;
}
/**
* @param research the research key required for this recipe to work. Leave blank if it will work without research
* @param result the recipe output. It can either be an itemstack or an nbt compound tag that will be added to the central item
* @param instability a number that represents the N in 1000 chance for the infusion altar to spawn an
* instability effect each second while the crafting is in progress
* @param aspects the essentia cost per aspect.
* @param aspects input the central item to be infused
* @param recipe An array of items required to craft this. Input itemstacks are NBT sensitive.
* Infusion crafting components are automatically "fuzzy" and the oredict will be checked for possible matches.
*
*/
public static InfusionRecipe addInfusionCraftingRecipe(String research, Object result, int instability, AspectList aspects, ItemStack input, ItemStack[] recipe)
{
if (!(result instanceof ItemStack || result instanceof NBTBase))
{
return null;
}
InfusionRecipe r = new InfusionRecipe(research, result, instability, aspects, input, recipe);
craftingRecipes.add(r);
return r;
}
/**
* @param research the research key required for this recipe to work. Leave blank if it will work without research
* @param enchantment the enchantment that will be applied to the item
* @param instability a number that represents the N in 1000 chance for the infusion altar to spawn an
* instability effect each second while the crafting is in progress
* @param aspects the essentia cost per aspect.
* @param recipe An array of items required to craft this. Input itemstacks are NBT sensitive.
* Infusion crafting components are automatically "fuzzy" and the oredict will be checked for possible matches.
*
*/
public static InfusionEnchantmentRecipe addInfusionEnchantmentRecipe(String research, Enchantment enchantment, int instability, AspectList aspects, ItemStack[] recipe)
{
InfusionEnchantmentRecipe r = new InfusionEnchantmentRecipe(research, enchantment, instability, aspects, recipe);
craftingRecipes.add(r);
return r;
}
/**
* @param stack the recipe result
* @return the recipe
*/
public static InfusionRecipe getInfusionRecipe(ItemStack res)
{
for (Object r: getCraftingRecipes())
{
if (r instanceof InfusionRecipe)
{
if (((InfusionRecipe)r).recipeOutput instanceof ItemStack)
{
if (((ItemStack)((InfusionRecipe)r).recipeOutput).isItemEqual(res))
{
return (InfusionRecipe)r;
}
}
}
}
return null;
}
/**
* @param key the research key required for this recipe to work.
* @param result the output result
* @param cost the vis cost
* @param tags the aspects required to craft this
*/
public static CrucibleRecipe addCrucibleRecipe(String key, ItemStack result, Object catalyst, AspectList tags)
{
CrucibleRecipe rc = new CrucibleRecipe(key, result, catalyst, tags);
getCraftingRecipes().add(rc);
return rc;
}
/**
* @param stack the recipe result
* @return the recipe
*/
public static CrucibleRecipe getCrucibleRecipe(ItemStack stack)
{
for (Object r: getCraftingRecipes())
{
if (r instanceof CrucibleRecipe)
{
if (((CrucibleRecipe)r).recipeOutput.isItemEqual(stack))
{
return (CrucibleRecipe)r;
}
}
}
return null;
}
/**
* Used by the thaumonomicon drilldown feature.
* @param stack the item
* @return the thaumcraft recipe key that produces that item.
*/
private static HashMap<int[], Object[]> keyCache = new HashMap<int[], Object[]>();
public static Object[] getCraftingRecipeKey(EntityPlayer player, ItemStack stack)
{
int[] key = new int[] {stack.itemID, stack.getItemDamage()};
if (keyCache.containsKey(key))
{
if (keyCache.get(key) == null)
{
return null;
}
if (ThaumcraftApiHelper.isResearchComplete(player.username, (String)(keyCache.get(key))[0]))
{
return keyCache.get(key);
}
else
{
return null;
}
}
for (ResearchCategoryList rcl: ResearchCategories.researchCategories.values())
{
for (ResearchItem ri: rcl.research.values())
{
if (ri.getPages() == null)
{
continue;
}
for (int a = 0; a < ri.getPages().length; a++)
{
ResearchPage page = ri.getPages()[a];
if (page.recipeOutput != null && stack != null && page.recipeOutput.isItemEqual(stack))
{
keyCache.put(key, new Object[] {ri.key, a});
if (ThaumcraftApiHelper.isResearchComplete(player.username, ri.key))
return new Object[] {ri.key, a};
else
{
return null;
}
}
}
}
}
keyCache.put(key, null);
return null;
}
//ASPECTS////////////////////////////////////////
public static ConcurrentHashMap<List, AspectList> objectTags = new ConcurrentHashMap<List, AspectList>();
/**
* Checks to see if the passed item/block already has aspects associated with it.
* @param id
* @param meta
* @return
*/
public static boolean exists(int id, int meta)
{
AspectList tmp = ThaumcraftApi.objectTags.get(Arrays.asList(id, meta));
if (tmp == null)
{
tmp = ThaumcraftApi.objectTags.get(Arrays.asList(id, -1));
if (meta == -1 && tmp == null)
{
int index = 0;
do
{
tmp = ThaumcraftApi.objectTags.get(Arrays.asList(id, index));
index++;
}
while (index < 16 && tmp == null);
}
if (tmp == null)
{
return false;
}
}
return true;
}
/**
* Used to assign apsects to the given item/block. Here is an example of the declaration for cobblestone:<p>
* <i>ThaumcraftApi.registerObjectTag(Block.cobblestone.blockID, -1, (new ObjectTags()).add(EnumTag.ROCK, 1).add(EnumTag.DESTRUCTION, 1));</i>
* @param id
* @param meta pass -1 if all damage values of this item/block should have the same aspects
* @param aspects A ObjectTags object of the associated aspects
*/
public static void registerObjectTag(int id, int meta, AspectList aspects)
{
if (aspects == null)
{
aspects = new AspectList();
}
objectTags.put(Arrays.asList(id, meta), aspects);
}
/**
* Used to assign apsects to the given item/block. Here is an example of the declaration for cobblestone:<p>
* <i>ThaumcraftApi.registerObjectTag(Block.cobblestone.blockID, new int[]{0,1}, (new ObjectTags()).add(EnumTag.ROCK, 1).add(EnumTag.DESTRUCTION, 1));</i>
* @param id
* @param meta A range of meta values if you wish to lump several item meta's together as being the "same" item (i.e. stair orientations)
* @param aspects A ObjectTags object of the associated aspects
*/
public static void registerObjectTag(int id, int[] meta, AspectList aspects)
{
if (aspects == null)
{
aspects = new AspectList();
}
objectTags.put(Arrays.asList(id, meta), aspects);
}
/**
* Used to assign apsects to the given ore dictionary item.
* @param oreDict the ore dictionary name
* @param aspects A ObjectTags object of the associated aspects
*/
public static void registerObjectTag(String oreDict, AspectList aspects)
{
if (aspects == null)
{
aspects = new AspectList();
}
ArrayList<ItemStack> ores = OreDictionary.getOres(oreDict);
if (ores != null && ores.size() > 0)
{
for (ItemStack ore: ores)
{
int d = ore.getItemDamage();
if (d == OreDictionary.WILDCARD_VALUE)
{
d = -1;
}
objectTags.put(Arrays.asList(ore.itemID, d), aspects);
}
}
}
/**
* Used to assign aspects to the given item/block.
* Attempts to automatically generate aspect tags by checking registered recipes.
* Here is an example of the declaration for pistons:<p>
* <i>ThaumcraftApi.registerComplexObjectTag(Block.pistonBase.blockID, 0, (new ObjectTags()).add(EnumTag.MECHANISM, 2).add(EnumTag.MOTION, 4));</i>
* @param id
* @param meta pass -1 if all damage values of this item/block should have the same aspects
* @param aspects A ObjectTags object of the associated aspects
*/
public static void registerComplexObjectTag(int id, int meta, AspectList aspects)
{
if (!exists(id, meta))
{
AspectList tmp = ThaumcraftApiHelper.generateTags(id, meta);
if (tmp != null && tmp.size() > 0)
{
for (Aspect tag: tmp.getAspects())
{
aspects.add(tag, tmp.getAmount(tag));
}
}
registerObjectTag(id, meta, aspects);
}
else
{
AspectList tmp = ThaumcraftApiHelper.getObjectAspects(new ItemStack(id, 1, meta));
for (Aspect tag: aspects.getAspects())
{
tmp.merge(tag, tmp.getAmount(tag));
}
registerObjectTag(id, meta, tmp);
}
}
//CROPS //////////////////////////////////////////////////////////////////////////////////////////
/**
* To define mod crops you need to use FMLInterModComms in your @Mod.Init method.
* There are two 'types' of crops you can add. Standard crops and clickable crops.
*
* Standard crops work like normal vanilla crops - they grow until a certain metadata
* value is reached and you harvest them by destroying the block and collecting the blocks.
* You need to create and ItemStack that tells the golem what block id and metadata represents
* the crop when fully grown.
* Example for vanilla wheat:
* FMLInterModComms.sendMessage("Thaumcraft", "harvestStandardCrop", new ItemStack(Block.crops,1,7));
*
* Clickable crops are crops that you right click to gather their bounty instead of destroying them.
* As for standard crops, you need to create and ItemStack that tells the golem what block id
* and metadata represents the crop when fully grown. The golem will trigger the blocks onBlockActivated method.
* Example (this will technically do nothing since clicking wheat does nothing, but you get the idea):
* FMLInterModComms.sendMessage("Thaumcraft", "harvestClickableCrop", new ItemStack(Block.crops,1,7));
*/
//NATIVE CLUSTERS //////////////////////////////////////////////////////////////////////////////////
/**
* You can define certain ores that will have a chance to produce native clusters via FMLInterModComms
* in your @Mod.Init method using the "nativeCluster" string message.
* The format should be:
* "[ore item/block id],[ore item/block metadata],[cluster item/block id],[cluster item/block metadata],[chance modifier float]"
*
* NOTE: The chance modifier is a multiplier applied to the default chance for that cluster to be produced (27.5% for a pickaxe of the core)
*
* Example for vanilla iron ore to produce one of my own native iron clusters (assuming default id's) at double the default chance:
* FMLInterModComms.sendMessage("Thaumcraft", "nativeCluster","15,0,25016,16,2.0");
*/
}

View file

@ -0,0 +1,264 @@
package thaumcraft.api;
import java.lang.reflect.Method;
import java.util.HashMap;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import net.minecraftforge.oredict.OreDictionary;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
import thaumcraft.api.aspects.IEssentiaTransport;
import cpw.mods.fml.common.FMLLog;
public class ThaumcraftApiHelper
{
public static AspectList cullTags(AspectList temp)
{
AspectList temp2 = new AspectList();
for (Aspect tag: temp.getAspects())
{
if (tag != null)
{
temp2.add(tag, temp.getAmount(tag));
}
}
while (temp2 != null && temp2.size() > 10)
{
Aspect lowest = null;
int low = Integer.MAX_VALUE;
for (Aspect tag: temp2.getAspects())
{
if (tag == null)
{
continue;
}
if (temp2.getAmount(tag) < low)
{
low = temp2.getAmount(tag);
lowest = tag;
}
}
temp2.aspects.remove(lowest);
}
return temp2;
}
public static boolean areItemsEqual(ItemStack s1, ItemStack s2)
{
if (s1.isItemStackDamageable() && s2.isItemStackDamageable())
{
return s1.itemID == s2.itemID;
}
else
{
return s1.itemID == s2.itemID && s1.getItemDamage() == s2.getItemDamage();
}
}
static Method isResearchComplete;
static Method getObjectTags;
static Method getBonusTags;
static Method generateTags;
public static boolean isResearchComplete(String username, String researchkey)
{
boolean ot = false;
try
{
if (isResearchComplete == null)
{
Class fake = Class.forName("thaumcraft.common.lib.research.ResearchManager");
isResearchComplete = fake.getMethod("isResearchComplete", String.class, String.class);
}
ot = (Boolean) isResearchComplete.invoke(null, username, researchkey);
}
catch (Exception ex)
{
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.research.ResearchManager method isResearchComplete");
}
return ot;
}
public static ItemStack getStackInRowAndColumn(Object instance, int row, int column)
{
ItemStack ot = null;
try
{
Class fake = Class.forName("thaumcraft.common.tiles.TileMagicWorkbench");
Method getStackInRowAndColumn = fake.getMethod("getStackInRowAndColumn", int.class, int.class);
ot = (ItemStack) getStackInRowAndColumn.invoke(instance, row, column);
}
catch (Exception ex)
{
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.tiles.TileMagicWorkbench method getStackInRowAndColumn");
}
return ot;
}
public static AspectList getObjectAspects(ItemStack is)
{
AspectList ot = null;
try
{
if (getObjectTags == null)
{
Class fake = Class.forName("thaumcraft.common.lib.ThaumcraftCraftingManager");
getObjectTags = fake.getMethod("getObjectTags", ItemStack.class);
}
ot = (AspectList) getObjectTags.invoke(null, is);
}
catch (Exception ex)
{
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.ThaumcraftCraftingManager method getObjectTags");
}
return ot;
}
public static AspectList getBonusObjectTags(ItemStack is, AspectList ot)
{
try
{
if (getBonusTags == null)
{
Class fake = Class.forName("thaumcraft.common.lib.ThaumcraftCraftingManager");
getBonusTags = fake.getMethod("getBonusTags", ItemStack.class, AspectList.class);
}
ot = (AspectList) getBonusTags.invoke(null, is, ot);
}
catch (Exception ex)
{
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.ThaumcraftCraftingManager method getBonusTags");
}
return ot;
}
public static AspectList generateTags(int id, int meta)
{
try
{
if (generateTags == null)
{
Class fake = Class.forName("thaumcraft.common.lib.ThaumcraftCraftingManager");
generateTags = fake.getMethod("generateTags", int.class, int.class);
}
return (AspectList) generateTags.invoke(null, id, meta);
}
catch (Exception ex)
{
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.ThaumcraftCraftingManager method generateTags");
}
return null;
}
public static boolean containsMatch(boolean strict, ItemStack[] inputs, ItemStack... targets)
{
for (ItemStack input : inputs)
{
for (ItemStack target : targets)
{
if (itemMatches(target, input, strict))
{
return true;
}
}
}
return false;
}
public static boolean itemMatches(ItemStack target, ItemStack input, boolean strict)
{
if (input == null && target != null || input != null && target == null)
{
return false;
}
return (target.itemID == input.itemID && ((target.getItemDamage() == OreDictionary.WILDCARD_VALUE && !strict) || target.getItemDamage() == input.getItemDamage()));
}
public static TileEntity getConnectableTile(World world, int x, int y, int z, ForgeDirection face)
{
TileEntity te = world.getBlockTileEntity(x + face.offsetX, y + face.offsetY, z + face.offsetZ);
if (te instanceof IEssentiaTransport && ((IEssentiaTransport)te).isConnectable(face.getOpposite()))
{
return te;
}
else
{
return null;
}
}
public static TileEntity getConnectableTile(IBlockAccess world, int x, int y, int z, ForgeDirection face)
{
TileEntity te = world.getBlockTileEntity(x + face.offsetX, y + face.offsetY, z + face.offsetZ);
if (te instanceof IEssentiaTransport && ((IEssentiaTransport)te).isConnectable(face.getOpposite()))
{
return te;
}
else
{
return null;
}
}
private static HashMap<Integer, AspectList> allAspects = new HashMap<Integer, AspectList>();
private static HashMap<Integer, AspectList> allCompoundAspects = new HashMap<Integer, AspectList>();
public static AspectList getAllAspects(int amount)
{
if (allAspects.get(amount) == null)
{
AspectList al = new AspectList();
for (Aspect aspect: Aspect.aspects.values())
{
al.add(aspect, amount);
}
allAspects.put(amount, al);
}
return allAspects.get(amount);
}
public static AspectList getAllCompoundAspects(int amount)
{
if (allCompoundAspects.get(amount) == null)
{
AspectList al = new AspectList();
for (Aspect aspect: Aspect.getCompoundAspects())
{
al.add(aspect, amount);
}
allCompoundAspects.put(amount, al);
}
return allCompoundAspects.get(amount);
}
}

View file

@ -0,0 +1,247 @@
package thaumcraft.api.aspects;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import org.apache.commons.lang3.text.WordUtils;
public class Aspect
{
String tag;
Aspect[] components;
int color;
private String chatcolor;
ResourceLocation image;
int blend;
/**
* Use this constructor to register your own aspects.
* @param tag the key that will be used to reference this aspect, as well as its latin display name
* @param color color to display the tag in
* @param components the aspects this one is formed from
* @param image ResourceLocation pointing to a 32x32 icon of the aspect
* @param blend GL11 blendmode (1 or 771). Used for rendering nodes. Default is 1
*/
public Aspect(String tag, int color, Aspect[] components, ResourceLocation image, int blend)
{
if (aspects.containsKey(tag))
{
throw new IllegalArgumentException(tag + " already registered!");
}
this.tag = tag;
this.components = components;
this.color = color;
this.image = image;
this.blend = blend;
aspects.put(tag, this);
}
/**
* Shortcut constructor I use for the default aspects - you shouldn't be using this.
*/
public Aspect(String tag, int color, Aspect[] components)
{
this(tag, color, components, new ResourceLocation("thaumcraft", "textures/aspects/" + tag.toLowerCase() + ".png"), 1);
}
/**
* Shortcut constructor I use for the default aspects - you shouldn't be using this.
*/
public Aspect(String tag, int color, Aspect[] components, int blend)
{
this(tag, color, components, new ResourceLocation("thaumcraft", "textures/aspects/" + tag.toLowerCase() + ".png"), blend);
}
/**
* Shortcut constructor I use for the primal aspects -
* you shouldn't use this as making your own primal aspects will break all the things.
*/
public Aspect(String tag, int color, String chatcolor, int blend)
{
this(tag, color, (Aspect[])null, blend);
this.setChatcolor(chatcolor);
}
public int getColor()
{
return color;
}
public String getName()
{
return WordUtils.capitalizeFully(tag);
}
public String getLocalizedDescription()
{
return StatCollector.translateToLocal("tc.aspect." + tag);
}
public String getTag()
{
return tag;
}
public void setTag(String tag)
{
this.tag = tag;
}
public Aspect[] getComponents()
{
return components;
}
public void setComponents(Aspect[] components)
{
this.components = components;
}
public ResourceLocation getImage()
{
return image;
}
public static Aspect getAspect(String tag)
{
return aspects.get(tag);
}
public int getBlend()
{
return blend;
}
public void setBlend(int blend)
{
this.blend = blend;
}
public boolean isPrimal()
{
return getComponents() == null || getComponents().length != 2;
}
///////////////////////////////
public static ArrayList<Aspect> getPrimalAspects()
{
ArrayList<Aspect> primals = new ArrayList<Aspect>();
Collection<Aspect> pa = aspects.values();
for (Aspect aspect: pa)
{
if (aspect.isPrimal())
{
primals.add(aspect);
}
}
return primals;
}
public static ArrayList<Aspect> getCompoundAspects()
{
ArrayList<Aspect> compounds = new ArrayList<Aspect>();
Collection<Aspect> pa = aspects.values();
for (Aspect aspect: pa)
{
if (!aspect.isPrimal())
{
compounds.add(aspect);
}
}
return compounds;
}
public String getChatcolor()
{
return chatcolor;
}
public void setChatcolor(String chatcolor)
{
this.chatcolor = chatcolor;
}
///////////////////////////////
public static LinkedHashMap<String, Aspect> aspects = new LinkedHashMap<String, Aspect>();
//PRIMAL
public static final Aspect AIR = new Aspect("aer", 0xffff7e, "e", 1);
public static final Aspect EARTH = new Aspect("terra", 0x56c000, "2", 1);
public static final Aspect FIRE = new Aspect("ignis", 0xff5a01, "c", 1);
public static final Aspect WATER = new Aspect("aqua", 0x3cd4fc, "3", 1);
public static final Aspect ORDER = new Aspect("ordo", 0xd5d4ec, "7", 1);
public static final Aspect ENTROPY = new Aspect("perditio", 0x404040, "8", 771);
//SECONDARY TODO
public static final Aspect VOID = new Aspect("vacuos", 0x888888, new Aspect[] {AIR, ENTROPY}, 771);
public static final Aspect LIGHT = new Aspect("lux", 0xfff663, new Aspect[] {AIR, FIRE});
public static final Aspect ENERGY = new Aspect("potentia", 0xc0ffff, new Aspect[] {ORDER, FIRE});
public static final Aspect MOTION = new Aspect("motus", 0xcdccf4, new Aspect[] {AIR, ORDER});
public static final Aspect STONE = new Aspect("saxum", 0x808080, new Aspect[] {EARTH, EARTH});
public static final Aspect LIFE = new Aspect("victus", 0xde0005, new Aspect[] {WATER, EARTH});
public static final Aspect WEATHER = new Aspect("tempestas", 0xFFFFFF, new Aspect[] {AIR, WATER});
public static final Aspect ICE = new Aspect("gelum", 0xe1ffff, new Aspect[] {WATER, ORDER});
public static final Aspect CRYSTAL = new Aspect("vitreus", 0x80ffff, new Aspect[] {STONE, WATER});
//TERTIARY TODO
public static final Aspect DEATH = new Aspect("mortuus", 0x887788, new Aspect[] {LIFE, ENTROPY});
public static final Aspect FLIGHT = new Aspect("volatus", 0xe7e7d7, new Aspect[] {AIR, MOTION});
public static final Aspect DARKNESS = new Aspect("tenebrae", 0x222222, new Aspect[] {VOID, LIGHT});
public static final Aspect SOUL = new Aspect("spiritus", 0xebebfb, new Aspect[] {LIFE, DEATH});
public static final Aspect HEAL = new Aspect("sano", 0xff2f34, new Aspect[] {LIFE, LIFE});
public static final Aspect TRAVEL = new Aspect("iter", 0xe0585b, new Aspect[] {MOTION, EARTH});
public static final Aspect POISON = new Aspect("venenum", 0x89f000, new Aspect[] {WATER, DEATH});
public static final Aspect ELDRITCH = new Aspect("alienis", 0x805080, new Aspect[] {VOID, DARKNESS});
public static final Aspect MAGIC = new Aspect("praecantatio", 0x9700c0, new Aspect[] {VOID, ENERGY});
public static final Aspect AURA = new Aspect("auram", 0xffc0ff, new Aspect[] {MAGIC, AIR});
public static final Aspect TAINT = new Aspect("vitium", 0x800080, new Aspect[] {MAGIC, ENTROPY});
public static final Aspect SEED = new Aspect("granum", 0xeea16e, new Aspect[] {LIFE, EARTH});
public static final Aspect SLIME = new Aspect("limus", 0x01f800, new Aspect[] {LIFE, WATER});
public static final Aspect PLANT = new Aspect("herba", 0x01ac00, new Aspect[] {SEED, EARTH});
public static final Aspect TREE = new Aspect("arbor", 0x876531, new Aspect[] {EARTH, PLANT});
public static final Aspect BEAST = new Aspect("bestia", 0x9f6409, new Aspect[] {MOTION, LIFE});
public static final Aspect FLESH = new Aspect("corpus", 0xee478d, new Aspect[] {DEATH, BEAST});
public static final Aspect UNDEAD = new Aspect("exanimis", 0x3a4000, new Aspect[] {MOTION, DEATH});
public static final Aspect MIND = new Aspect("cognitio", 0xffc2b3, new Aspect[] {EARTH, SOUL});
public static final Aspect SENSES = new Aspect("sensus", 0x0fd9ff, new Aspect[] {AIR, SOUL});
public static final Aspect MAN = new Aspect("humanus", 0xffd7c0, new Aspect[] {BEAST, MIND});
public static final Aspect CROP = new Aspect("messis", 0xe1b371, new Aspect[] {SEED, MAN});
public static final Aspect HARVEST = new Aspect("meto", 0xeead82, new Aspect[] {CROP, MAN});
public static final Aspect METAL = new Aspect("metallum", 0xb5b5cd, new Aspect[] {STONE, ORDER});
public static final Aspect MINE = new Aspect("perfodio", 0xdcd2d8, new Aspect[] {MAN, STONE});
public static final Aspect TOOL = new Aspect("instrumentum", 0x4040ee, new Aspect[] {MAN, METAL});
public static final Aspect WEAPON = new Aspect("telum", 0xc05050, new Aspect[] {TOOL, ENTROPY});
public static final Aspect ARMOR = new Aspect("tutamen", 0x00c0c0, new Aspect[] {TOOL, EARTH});
public static final Aspect HUNGER = new Aspect("fames", 0x9a0305, new Aspect[] {LIFE, VOID});
public static final Aspect GREED = new Aspect("lucrum", 0xe6be44, new Aspect[] {MAN, HUNGER});
public static final Aspect CRAFT = new Aspect("fabrico", 0x809d80, new Aspect[] {MAN, TOOL});
public static final Aspect CLOTH = new Aspect("pannus", 0xeaeac2, new Aspect[] {TOOL, BEAST});
public static final Aspect MECHANISM = new Aspect("machina", 0x8080a0, new Aspect[] {MOTION, TOOL});
public static final Aspect TRAP = new Aspect("vinculum", 0x9a8080, new Aspect[] {MOTION, ENTROPY});
public static final Aspect EXCHANGE = new Aspect("permutatio", 0x578357, new Aspect[] {MOTION, WATER});
// public static final Aspect LAVA = new Aspect("lava",0xe85729, new Aspect[] {EARTH, FIRE});
// public static final Aspect STEAM = new Aspect("steam",0xFFFFFF, new Aspect[] {WATER, FIRE});
// public static final Aspect MUD = new Aspect("lutum",0x473423, new Aspect[] {WATER, EARTH});
// public static final Aspect SAND = new Aspect("sand",0xFFFFFF, new Aspect[] {AIR, EARTH});
// public static final Aspect ASTRAL = new Aspect("Astral",0xFFFFFF, new Aspect[] {VOID, DARKNESS});
// public static final Aspect HARM = new Aspect("Harm",0xFFFFFF, new Aspect[] {ENTROPY, LIFE});
// public static final Aspect BIRD = new Aspect("Bird",0xFFFFFF, new Aspect[] {BEAST, AIR});
// public static final Aspect FISH = new Aspect("Fish",0xFFFFFF, new Aspect[] {BEAST, WATER});
}

View file

@ -0,0 +1,311 @@
package thaumcraft.api.aspects;
import java.io.Serializable;
import java.util.LinkedHashMap;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import thaumcraft.api.ThaumcraftApiHelper;
public class AspectList implements Serializable
{
public LinkedHashMap<Aspect, Integer> aspects = new LinkedHashMap<Aspect, Integer>(); //aspects associated with this object
/**
* this creates a new aspect list with preloaded values based off the aspects of the given item.
* @param id the item/block id of an existing item
* @param meta the damage value of an existing item
*/
public AspectList(int id, int meta)
{
try
{
AspectList temp = ThaumcraftApiHelper.getObjectAspects(new ItemStack(id, 1, meta));
if (temp != null)
for (Aspect tag: temp.getAspects())
{
add(tag, temp.getAmount(tag));
}
}
catch (Exception e) {}
}
public AspectList()
{
}
public AspectList copy()
{
AspectList out = new AspectList();
for (Aspect a: this.getAspects())
{
out.add(a, this.getAmount(a));
}
return out;
}
/**
* @return the amount of different aspects in this collection
*/
public int size()
{
return aspects.size();
}
/**
* @return the amount of total vis in this collection
*/
public int visSize()
{
int q = 0;
for (Aspect as: aspects.keySet())
{
q += this.getAmount(as);
}
return q;
}
/**
* @return an array of all the aspects in this collection
*/
public Aspect[] getAspects()
{
Aspect[] q = new Aspect[1];
return aspects.keySet().toArray(q);
}
/**
* @return an array of all the aspects in this collection
*/
public Aspect[] getPrimalAspects()
{
AspectList t = new AspectList();
for (Aspect as: aspects.keySet())
{
if (as.isPrimal())
{
t.add(as, 1);
}
}
Aspect[] q = new Aspect[1];
return t.aspects.keySet().toArray(q);
}
/**
* @return an array of all the aspects in this collection sorted by name
*/
public Aspect[] getAspectsSorted()
{
Aspect[] out = aspects.keySet().toArray(new Aspect[1]);
boolean change = false;
do
{
change = false;
for (int a = 0; a < out.length - 1; a++)
{
Aspect e1 = out[a];
Aspect e2 = out[a + 1];
if (e1 != null && e2 != null && e1.getTag().compareTo(e2.getTag()) > 0)
{
out[a] = e2;
out[a + 1] = e1;
change = true;
break;
}
}
}
while (change == true);
return out;
}
/**
* @return an array of all the aspects in this collection sorted by amount
*/
public Aspect[] getAspectsSortedAmount()
{
Aspect[] out = aspects.keySet().toArray(new Aspect[1]);
boolean change = false;
do
{
change = false;
for (int a = 0; a < out.length - 1; a++)
{
int e1 = getAmount(out[a]);
int e2 = getAmount(out[a + 1]);
if (e1 > 0 && e2 > 0 && e2 > e1)
{
Aspect ea = out[a];
Aspect eb = out[a + 1];
out[a] = eb;
out[a + 1] = ea;
change = true;
break;
}
}
}
while (change == true);
return out;
}
/**
* @param key
* @return the amount associated with the given aspect in this collection
*/
public int getAmount(Aspect key)
{
return aspects.get(key) == null ? 0 : aspects.get(key);
}
/**
* Reduces the amount of an aspect in this collection by the given amount.
* @param key
* @param amount
* @return
*/
public boolean reduce(Aspect key, int amount)
{
if (getAmount(key) >= amount)
{
int am = getAmount(key) - amount;
aspects.put(key, am);
return true;
}
return false;
}
/**
* Reduces the amount of an aspect in this collection by the given amount.
* If reduced to 0 or less the aspect will be removed completely.
* @param key
* @param amount
* @return
*/
public AspectList remove(Aspect key, int amount)
{
int am = getAmount(key) - amount;
if (am <= 0)
{
aspects.remove(key);
}
else
{
this.aspects.put(key, am);
}
return this;
}
/**
* Simply removes the aspect from the list
* @param key
* @param amount
* @return
*/
public AspectList remove(Aspect key)
{
aspects.remove(key);
return this;
}
/**
* Adds this aspect and amount to the collection.
* If the aspect exists then its value will be increased by the given amount.
* @param aspect
* @param amount
* @return
*/
public AspectList add(Aspect aspect, int amount)
{
if (this.aspects.containsKey(aspect))
{
int oldamount = this.aspects.get(aspect);
amount += oldamount;
}
this.aspects.put(aspect, amount);
return this;
}
/**
* Adds this aspect and amount to the collection.
* If the aspect exists then only the highest of the old or new amount will be used.
* @param aspect
* @param amount
* @return
*/
public AspectList merge(Aspect aspect, int amount)
{
if (this.aspects.containsKey(aspect))
{
int oldamount = this.aspects.get(aspect);
if (amount < oldamount)
{
amount = oldamount;
}
}
this.aspects.put(aspect, amount);
return this;
}
/**
* Reads the list of aspects from nbt
* @param nbttagcompound
* @return
*/
public void readFromNBT(NBTTagCompound nbttagcompound)
{
aspects.clear();
NBTTagList tlist = nbttagcompound.getTagList("Aspects");
for (int j = 0; j < tlist.tagCount(); j++)
{
NBTTagCompound rs = (NBTTagCompound) tlist.tagAt(j);
if (rs.hasKey("key"))
{
add(Aspect.getAspect(rs.getString("key")),
rs.getInteger("amount"));
}
}
}
/**
* Writes the list of aspects to nbt
* @param nbttagcompound
* @return
*/
public void writeToNBT(NBTTagCompound nbttagcompound)
{
NBTTagList tlist = new NBTTagList();
nbttagcompound.setTag("Aspects", tlist);
for (Aspect aspect : getAspects())
if (aspect != null)
{
NBTTagCompound f = new NBTTagCompound();
f.setString("key", aspect.getTag());
f.setInteger("amount", getAmount(aspect));
tlist.appendTag(f);
}
}
}

View file

@ -0,0 +1,67 @@
package thaumcraft.api.aspects;
/**
*
* @author azanor
*
* Used by blocks like the crucible and alembic to hold their aspects.
* Tiles extending this interface will have their aspects show up when viewed by goggles of revealing
*
*/
public interface IAspectContainer
{
public AspectList getAspects();
public void setAspects(AspectList aspects);
/**
* This method is used to determine of a specific aspect can be added to this container.
* @param tag
* @return true or false
*/
public boolean doesContainerAccept(Aspect tag);
/**
* This method is used to add a certain amount of an aspect to the tile entity.
* @param tag
* @param amount
* @return the amount of aspect left over that could not be added.
*/
public int addToContainer(Aspect tag, int amount);
/**
* Removes a certain amount of a specific aspect from the tile entity
* @param tag
* @param amount
* @return true if that amount of aspect was available and was removed
*/
public boolean takeFromContainer(Aspect tag, int amount);
/**
* removes a bunch of different aspects and amounts from the tile entity.
* @param ot the ObjectTags object that contains the aspects and their amounts.
* @return true if all the aspects and their amounts were available and successfully removed
*/
public boolean takeFromContainer(AspectList ot);
/**
* Checks if the tile entity contains the listed amount (or more) of the aspect
* @param tag
* @param amount
* @return
*/
public boolean doesContainerContainAmount(Aspect tag, int amount);
/**
* Checks if the tile entity contains all the listed aspects and their amounts
* @param ot the ObjectTags object that contains the aspects and their amounts.
* @return
*/
public boolean doesContainerContain(AspectList ot);
/**
* Returns how much of the aspect this tile entity contains
* @param tag
* @return the amount of that aspect found
*/
public int containerContains(Aspect tag);
}

View file

@ -0,0 +1,12 @@
package thaumcraft.api.aspects;
/**
* @author Azanor
*
* This interface is implemented by tile entites (or possibly anything else) like jars
* so that they can act as an essentia source for blocks like the infusion altar.
*
*/
public interface IAspectSource extends IAspectContainer
{
}

View file

@ -0,0 +1,38 @@
package thaumcraft.api.aspects;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
/**
*
* @author azanor
*
* Used by wispy essences and essentia phials to hold their aspects.
* Useful for similar item containers that store their aspect information in nbt form so TC
* automatically picks up the aspects they contain
*
*/
public interface IEssentiaContainerItem
{
public AspectList getAspects(ItemStack itemstack);
public void setAspects(ItemStack itemstack, AspectList aspects);
}
//Example implementation
/*
@Override
public AspectList getAspects(ItemStack itemstack) {
if (itemstack.hasTagCompound()) {
AspectList aspects = new AspectList();
aspects.readFromNBT(itemstack.getTagCompound());
return aspects.size()>0?aspects:null;
}
return null;
}
@Override
public void setAspects(ItemStack itemstack, AspectList aspects) {
if (!itemstack.hasTagCompound()) itemstack.setTagCompound(new NBTTagCompound());
aspects.writeToNBT(itemstack.getTagCompound());
}
*/

View file

@ -0,0 +1,86 @@
package thaumcraft.api.aspects;
import net.minecraftforge.common.ForgeDirection;
/**
* @author Azanor
* This interface is used by tiles that use or transport vis.
* Only tiles that implement this interface will be able to connect to vis conduits or other thaumic devices
*/
public interface IEssentiaTransport
{
/**
* Is this tile able to connect to other vis users/sources on the specified side?
* @param face
* @return
*/
public boolean isConnectable(ForgeDirection face);
/**
* Is this side used to input essentia?
* @param face
* @return
*/
boolean canInputFrom(ForgeDirection face);
/**
* Is this side used to output essentia?
* @param face
* @return
*/
boolean canOutputTo(ForgeDirection face);
// /**
// * Can this tile act as a source of vis?
// * @return
// */
// public boolean isVisSource();
//
// /**
// * Is this tile a conduit that transports vis?
// * @return
// */
// public boolean isVisConduit();
/**
* Sets the amount of suction this block will apply
* @param suction
*/
public void setSuction(AspectList suction);
/**
* Sets the amount of suction this block will apply
* @param suction
*/
public void setSuction(Aspect aspect, int amount);
/**
* Returns the amount of suction this block is applying.
* @param loc
* the location from where the suction is being checked
* @return
*/
public AspectList getSuction(ForgeDirection face);
/**
* remove the specified amount of vis from this transport tile
* @param suction
* @return how much was actually taken
*/
public int takeVis(Aspect aspect, int amount);
public AspectList getEssentia(ForgeDirection face);
/**
* Essentia will not be drawn from this container unless the suction exceeds this amount.
* @return the amount
*/
public int getMinimumSuction();
/**
* Return true if you want the conduit to extend a little further into the block.
* Used by jars and alembics that have smaller than normal hitboxes
* @return
*/
boolean renderExtendedTube();
}

View file

@ -0,0 +1,73 @@
package thaumcraft.api.crafting;
import java.util.ArrayList;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import thaumcraft.api.ThaumcraftApiHelper;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
public class CrucibleRecipe
{
public ItemStack recipeOutput;
public Object catalyst;
public AspectList aspects;
public String key;
public CrucibleRecipe(String researchKey, ItemStack result, Object cat, AspectList tags)
{
recipeOutput = result;
this.aspects = tags;
this.key = researchKey;
this.catalyst = cat;
if (cat instanceof String)
{
this.catalyst = OreDictionary.getOres((String) cat);
}
}
public boolean matches(AspectList itags, ItemStack cat)
{
if (catalyst instanceof ItemStack &&
!ThaumcraftApiHelper.itemMatches((ItemStack) catalyst, cat, false))
{
return false;
}
else if (catalyst instanceof ArrayList && ((ArrayList<ItemStack>)catalyst).size() > 0)
{
if (!ThaumcraftApiHelper.containsMatch(true, ((ArrayList<ItemStack>)catalyst).toArray(new ItemStack[] {}), cat)) return false;
}
if (itags == null)
{
return false;
}
for (Aspect tag: aspects.getAspects())
{
if (itags.getAmount(tag) < aspects.getAmount(tag))
{
return false;
}
}
return true;
}
public AspectList removeMatching(AspectList itags)
{
AspectList temptags = new AspectList();
temptags.aspects.putAll(itags.aspects);
for (Aspect tag: aspects.getAspects())
{
temptags.remove(tag, aspects.getAmount(tag));
// if (!temptags.remove(tag, aspects.getAmount(tag))) return null;
}
itags = temptags;
return itags;
}
}

View file

@ -0,0 +1,30 @@
package thaumcraft.api.crafting;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import thaumcraft.api.aspects.AspectList;
public interface IArcaneRecipe
{
/**
* Used to check if a recipe matches current crafting inventory
* @param player
*/
boolean matches(IInventory var1, World world, EntityPlayer player);
/**
* Returns an Item that is the result of this recipe
*/
ItemStack getCraftingResult(IInventory var1);
/**
* Returns the size of the recipe area
*/
int getRecipeSize();
ItemStack getRecipeOutput();
AspectList getAspects();
String getResearch();
}

View file

@ -0,0 +1,206 @@
package thaumcraft.api.crafting;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.player.EntityPlayer;
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 InfusionEnchantmentRecipe
{
public AspectList aspects;
public String research;
public ItemStack[] components;
public Enchantment enchantment;
public int recipeXP;
public int instability;
public InfusionEnchantmentRecipe(String research, Enchantment input, int inst,
AspectList aspects2, ItemStack[] recipe)
{
this.research = research;
this.enchantment = input;
this.aspects = aspects2;
this.components = recipe;
this.instability = inst;
this.recipeXP = Math.max(1, input.getMinEnchantability(1) / 3);
}
/**
* 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.username, research))
{
return false;
}
if (!enchantment.canApply(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;
}
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));
}
public Enchantment getEnchantment()
{
return enchantment;
}
public AspectList getAspects()
{
return aspects;
}
public String getResearch()
{
return research;
}
public int calcInstability(ItemStack recipeInput)
{
int i = 0;
Map map1 = EnchantmentHelper.getEnchantments(recipeInput);
Iterator iterator = map1.keySet().iterator();
while (iterator.hasNext())
{
int j1 = ((Integer)iterator.next()).intValue();
i += EnchantmentHelper.getEnchantmentLevel(j1, recipeInput);
}
return (i / 2) + instability;
}
public int calcXP(ItemStack recipeInput)
{
return recipeXP * (1 + EnchantmentHelper.getEnchantmentLevel(enchantment.effectId, recipeInput));
}
public float getEssentiaMod(ItemStack recipeInput)
{
float mod = EnchantmentHelper.getEnchantmentLevel(enchantment.effectId, recipeInput);
Map map1 = EnchantmentHelper.getEnchantments(recipeInput);
Iterator iterator = map1.keySet().iterator();
while (iterator.hasNext())
{
int j1 = ((Integer)iterator.next()).intValue();
if (j1 != enchantment.effectId)
{
mod += EnchantmentHelper.getEnchantmentLevel(j1, recipeInput) * .1f;
}
}
return mod;
}
}

View file

@ -0,0 +1,147 @@
package thaumcraft.api.crafting;
import java.util.ArrayList;
import net.minecraft.entity.player.EntityPlayer;
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 InfusionRecipe
{
public AspectList aspects;
public String research;
public ItemStack[] components;
public ItemStack recipeInput;
public Object recipeOutput;
public int instability;
public InfusionRecipe(String research, Object output, int inst,
AspectList aspects2, ItemStack input, ItemStack[] recipe)
{
this.research = research;
this.recipeOutput = output;
this.recipeInput = input;
this.aspects = aspects2;
this.components = recipe;
this.instability = inst;
}
/**
* 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.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;
}
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));
}
public Object getRecipeOutput()
{
return recipeOutput;
}
public AspectList getAspects()
{
return aspects;
}
public String getResearch()
{
return research;
}
}

View file

@ -0,0 +1,282 @@
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.inventory.InventoryCrafting;
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.username, 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.itemID == input.itemID &&
(!target.hasTagCompound() || ItemStack.areItemStackTagsEqual(target, input)) &&
(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 String getResearch()
{
return research;
}
}

View file

@ -0,0 +1,172 @@
package thaumcraft.api.crafting;
import java.util.ArrayList;
import java.util.Iterator;
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 ShapelessArcaneRecipe implements IArcaneRecipe
{
private ItemStack output = null;
private ArrayList input = new ArrayList();
public AspectList aspects = null;
public String research;
public ShapelessArcaneRecipe(String research, Block result, AspectList aspects, Object... recipe)
{
this(research, new ItemStack(result), aspects, recipe);
}
public ShapelessArcaneRecipe(String research, Item result, AspectList aspects, Object... recipe)
{
this(research, new ItemStack(result), aspects, recipe);
}
public ShapelessArcaneRecipe(String research, ItemStack result, AspectList aspects, Object... recipe)
{
output = result.copy();
this.research = research;
this.aspects = aspects;
for (Object in : recipe)
{
if (in instanceof ItemStack)
{
input.add(((ItemStack)in).copy());
}
else if (in instanceof Item)
{
input.add(new ItemStack((Item)in));
}
else if (in instanceof Block)
{
input.add(new ItemStack((Block)in));
}
else if (in instanceof String)
{
input.add(OreDictionary.getOres((String)in));
}
else
{
String ret = "Invalid shapeless ore recipe: ";
for (Object tmp : recipe)
{
ret += tmp + ", ";
}
ret += output;
throw new RuntimeException(ret);
}
}
}
@Override
public int getRecipeSize()
{
return input.size();
}
@Override
public ItemStack getRecipeOutput()
{
return output;
}
@Override
public ItemStack getCraftingResult(IInventory var1)
{
return output.copy();
}
@Override
public boolean matches(IInventory var1, World world, EntityPlayer player)
{
if (research.length() > 0 && !ThaumcraftApiHelper.isResearchComplete(player.username, research))
{
return false;
}
ArrayList required = new ArrayList(input);
for (int x = 0; x < 9; x++)
{
ItemStack slot = var1.getStackInSlot(x);
if (slot != null)
{
boolean inRecipe = false;
Iterator req = required.iterator();
while (req.hasNext())
{
boolean match = false;
Object next = req.next();
if (next instanceof ItemStack)
{
match = checkItemEquals((ItemStack)next, slot);
}
else if (next instanceof ArrayList)
{
for (ItemStack item : (ArrayList<ItemStack>)next)
{
match = match || checkItemEquals(item, slot);
}
}
if (match)
{
inRecipe = true;
required.remove(next);
break;
}
}
if (!inRecipe)
{
return false;
}
}
}
return required.isEmpty();
}
private boolean checkItemEquals(ItemStack target, ItemStack input)
{
return (target.itemID == input.itemID &&
(!target.hasTagCompound() || ItemStack.areItemStackTagsEqual(target, input)) &&
(target.getItemDamage() == OreDictionary.WILDCARD_VALUE || target.getItemDamage() == input.getItemDamage()));
}
/**
* 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 ArrayList getInput()
{
return this.input;
}
@Override
public AspectList getAspects()
{
return aspects;
}
@Override
public String getResearch()
{
return research;
}
}

View file

@ -0,0 +1,48 @@
package thaumcraft.api.nodes;
import thaumcraft.api.aspects.IAspectContainer;
public interface INode extends IAspectContainer
{
/**
* Unique identifier to distinguish nodes. Normal node id's are based on world id and coordinates
* @return
*/
public String getId();
/**
* Return the type of node
* @return
*/
public NodeType getNodeType();
/**
* Set the type of node
* @return
*/
public void setNodeType(NodeType nodeType);
/**
* Return the node modifier
* @return
*/
public void setNodeModifier(NodeModifier nodeModifier);
/**
* Set the node modifier
* @return
*/
public NodeModifier getNodeModifier();
/**
* Return the maximum capacity of each aspect the node can hold
* @return
*/
public int getNodeVisBase();
/**
* Set the maximum capacity of each aspect the node can hold
* @return
*/
public void setNodeVisBase(short nodeVisBase);
}

View file

@ -0,0 +1,20 @@
package thaumcraft.api.nodes;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
/**
*
* @author Azanor
*
* Equipped head slot items that extend this class will make nodes visible in world.
*
*/
public interface IRevealer
{
/*
* If this method returns true the nodes will be visible.
*/
public boolean showNodes(ItemStack itemstack, EntityLivingBase player);
}

View file

@ -0,0 +1,6 @@
package thaumcraft.api.nodes;
public enum NodeModifier
{
BRIGHT, PALE, FADING
}

View file

@ -0,0 +1,6 @@
package thaumcraft.api.nodes;
public enum NodeType
{
NORMAL, UNSTABLE, DARK, TAINTED, HUNGRY, PURE
}

View file

@ -0,0 +1,10 @@
package thaumcraft.api.research;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public interface IScanEventHandler
{
ScanResult scanPhenomena(ItemStack stack, World world, EntityPlayer player);
}

View file

@ -0,0 +1,101 @@
package thaumcraft.api.research;
import java.util.Collection;
import java.util.LinkedHashMap;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
public class ResearchCategories
{
//Research
public static LinkedHashMap <String, ResearchCategoryList> researchCategories = new LinkedHashMap <String, ResearchCategoryList>();
/**
* @param key
* @return the research item linked to this key
*/
public static ResearchCategoryList getResearchList(String key)
{
return researchCategories.get(key);
}
/**
* @param key
* @return the name of the research category linked to this key.
* Must be stored as localization information in the LanguageRegistry.
*/
public static String getCategoryName(String key)
{
return StatCollector.translateToLocal("tc.research_category." + key);
}
/**
* @param key the research key
* @return the ResearchItem object.
*/
public static ResearchItem getResearch(String key)
{
Collection rc = researchCategories.values();
for (Object cat: rc)
{
Collection rl = ((ResearchCategoryList)cat).research.values();
for (Object ri: rl)
{
if ((((ResearchItem)ri).key).equals(key))
{
return (ResearchItem)ri;
}
}
}
return null;
}
/**
* @param key the key used for this category
* @param icon the icon to be used for the research category tab
* @param background the resource location of the background image to use for this category
* @return the name of the research linked to this key
*/
public static void registerCategory(String key, ResourceLocation icon, ResourceLocation background)
{
if (getResearchList(key) == null)
{
ResearchCategoryList rl = new ResearchCategoryList(icon, background);
researchCategories.put(key, rl);
}
}
public static void addResearch(ResearchItem ri)
{
ResearchCategoryList rl = getResearchList(ri.category);
if (rl != null && !rl.research.containsKey(ri.key))
{
rl.research.put(ri.key, ri);
if (ri.displayColumn < rl.minDisplayColumn)
{
rl.minDisplayColumn = ri.displayColumn;
}
if (ri.displayRow < rl.minDisplayRow)
{
rl.minDisplayRow = ri.displayRow;
}
if (ri.displayColumn > rl.maxDisplayColumn)
{
rl.maxDisplayColumn = ri.displayColumn;
}
if (ri.displayRow > rl.maxDisplayRow)
{
rl.maxDisplayRow = ri.displayRow;
}
}
}
}

View file

@ -0,0 +1,34 @@
package thaumcraft.api.research;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.util.ResourceLocation;
public class ResearchCategoryList
{
/** Is the smallest column used on the GUI. */
public int minDisplayColumn;
/** Is the smallest row used on the GUI. */
public int minDisplayRow;
/** Is the biggest column used on the GUI. */
public int maxDisplayColumn;
/** Is the biggest row used on the GUI. */
public int maxDisplayRow;
/** display variables **/
public ResourceLocation icon;
public ResourceLocation background;
public ResearchCategoryList(ResourceLocation icon, ResourceLocation background)
{
this.icon = icon;
this.background = background;
}
//Research
public Map<String, ResearchItem> research = new HashMap<String, ResearchItem>();
}

View file

@ -0,0 +1,336 @@
package thaumcraft.api.research;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class ResearchItem
{
/**
* A short string used as a key for this research. Must be unique
*/
public final String key;
/**
* A short string used as a reference to the research category to which this must be added.
*/
public final String category;
/**
* The aspect tags and their values required to complete this research
*/
public final AspectList tags;
/**
* This links to any research that needs to be completed before this research can be discovered or learnt.
*/
public String[] parents = null;
/**
* Like parent above, but a line will not be displayed in the thaumonomicon linking them. Just used to prevent clutter.
*/
public String[] parentsHidden = null;
/**
* any research linked to this that will be unlocked automatically when this research is complete
*/
public String[] siblings = null;
/**
* the horizontal position of the research icon
*/
public final int displayColumn;
/**
* the vertical position of the research icon
*/
public final int displayRow;
/**
* the icon to be used for this research
*/
public final ItemStack icon_item;
/**
* the icon to be used for this research
*/
public final ResourceLocation icon_resource;
/**
* How large the research grid is. Valid values are 1 to 5.
*/
private int complexity;
/**
* Special research has a spiky border. Used for important research milestones.
*/
private boolean isSpecial;
/**
* This indicates if the research should use a circular icon border. Usually used for "passive" research
* that doesn't have recipes and grants passive effects, or that unlock automatically.
*/
private boolean isRound;
/**
* Stub research cannot be discovered by normal means, but can be unlocked via the sibling system.
*/
private boolean isStub;
/**
* This indicated that the research is completely hidden and cannot be discovered by any
* player-controlled means. The recipes will never show up in the thaumonomicon.
* Usually used to unlock "hidden" recipes via sibling unlocking, like
* the various cap and rod combos for wands.
*/
private boolean isVirtual;
/**
* Hidden research does not display in the thaumonomicon until discovered
*/
private boolean isHidden;
/**
* Concealed research does not display in the thaumonomicon until parent researches are discovered.
*/
private boolean isConcealed;
/**
* Lost research can only be discovered via knowledge fragments
*/
private boolean isLost;
/**
* These research items will automatically unlock for all players on game start
*/
private boolean isAutoUnlock;
private ResearchPage[] pages = null;
public ResearchItem(String par1, String par2)
{
this.key = par1;
this.category = par2;
this.tags = new AspectList();
this.icon_resource = null;
this.icon_item = null;
this.displayColumn = 0;
this.displayRow = 0;
this.setVirtual();
}
public ResearchItem(String par1, String par2, AspectList tags, int par3, int par4, int par5, ResourceLocation icon)
{
this.key = par1;
this.category = par2;
this.tags = tags;
this.icon_resource = icon;
this.icon_item = null;
this.displayColumn = par3;
this.displayRow = par4;
this.complexity = par5;
if (complexity < 1)
{
this.complexity = 1;
}
if (complexity > 5)
{
this.complexity = 5;
}
}
public ResearchItem(String par1, String par2, AspectList tags, int par3, int par4, int par5, ItemStack icon)
{
this.key = par1;
this.category = par2;
this.tags = tags;
this.icon_item = icon;
this.icon_resource = null;
this.displayColumn = par3;
this.displayRow = par4;
this.complexity = par5;
if (complexity < 0)
{
this.complexity = 0;
}
if (complexity > 5)
{
this.complexity = 5;
}
}
public ResearchItem setSpecial()
{
this.isSpecial = true;
return this;
}
public ResearchItem setStub()
{
this.isStub = true;
return this;
}
public ResearchItem setHidden()
{
this.isHidden = true;
return this;
}
public ResearchItem setConcealed()
{
this.isConcealed = true;
return this;
}
public ResearchItem setLost()
{
this.isLost = true;
return this;
}
public ResearchItem setVirtual()
{
this.isVirtual = true;
return this;
}
public ResearchItem setParents(String... par)
{
this.parents = par;
return this;
}
public ResearchItem setParentsHidden(String... par)
{
this.parentsHidden = par;
return this;
}
public ResearchItem setSiblings(String... sib)
{
this.siblings = sib;
return this;
}
public ResearchItem setPages(ResearchPage... par)
{
this.pages = par;
return this;
}
public ResearchPage[] getPages()
{
return pages;
}
public ResearchItem registerResearchItem()
{
ResearchCategories.addResearch(this);
return this;
}
@SideOnly(Side.CLIENT)
public String getName()
{
return StatCollector.translateToLocal("tc.research_name." + key);
}
@SideOnly(Side.CLIENT)
public String getText()
{
return StatCollector.translateToLocal("tc.research_text." + key);
}
@SideOnly(Side.CLIENT)
public boolean isSpecial()
{
return this.isSpecial;
}
public boolean isStub()
{
return this.isStub;
}
public boolean isHidden()
{
return this.isHidden;
}
public boolean isConcealed()
{
return this.isConcealed;
}
public boolean isLost()
{
return this.isLost;
}
public boolean isVirtual()
{
return this.isVirtual;
}
public boolean isAutoUnlock()
{
return isAutoUnlock;
}
public ResearchItem setAutoUnlock()
{
this.isAutoUnlock = true;
return this;
}
public boolean isRound()
{
return isRound;
}
public ResearchItem setRound()
{
this.isRound = true;
return this;
}
public int getComplexity()
{
return complexity;
}
public ResearchItem setComplexity(int complexity)
{
this.complexity = complexity;
return this;
}
/**
* @return the aspect aspects ordinal with the highest value. Used to determine scroll color and similar things
*/
public Aspect getResearchPrimaryTag()
{
Aspect aspect = null;
int highest = 0;
if (tags != null)
for (Aspect tag: tags.getAspects())
{
if (tags.getAmount(tag) > highest)
{
aspect = tag;
highest = tags.getAmount(tag);
};
}
return aspect;
}
}

View file

@ -0,0 +1,198 @@
package thaumcraft.api.research;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import thaumcraft.api.aspects.AspectList;
import thaumcraft.api.crafting.CrucibleRecipe;
import thaumcraft.api.crafting.IArcaneRecipe;
import thaumcraft.api.crafting.InfusionEnchantmentRecipe;
import thaumcraft.api.crafting.InfusionRecipe;
public class ResearchPage
{
public static enum PageType
{
TEXT,
TEXT_CONCEALED,
IMAGE,
CRUCIBLE_CRAFTING,
ARCANE_CRAFTING,
ASPECTS,
NORMAL_CRAFTING,
INFUSION_CRAFTING,
COMPOUND_CRAFTING,
INFUSION_ENCHANTMENT
}
public PageType type = PageType.TEXT;
public String text = null;
public String research = null;
public ResourceLocation image = null;
public AspectList aspects = null;
public Object recipe = null;
public ItemStack recipeOutput = null;
/**
* @param text this can (but does not have to) be a reference to a localization variable, not the actual text.
*/
public ResearchPage(String text)
{
this.type = PageType.TEXT;
this.text = text;
}
/**
* @param research this page will only be displayed if the player has discovered this research
* @param text this can (but does not have to) be a reference to a localization variable, not the actual text.
*/
public ResearchPage(String research, String text)
{
this.type = PageType.TEXT_CONCEALED;
this.research = research;
this.text = text;
}
/**
* @param recipe a vanilla crafting recipe.
*/
public ResearchPage(IRecipe recipe)
{
this.type = PageType.NORMAL_CRAFTING;
this.recipe = recipe;
this.recipeOutput = recipe.getRecipeOutput();
}
/**
* @param recipe a collection of vanilla crafting recipes.
*/
public ResearchPage(IRecipe[] recipe)
{
this.type = PageType.NORMAL_CRAFTING;
this.recipe = recipe;
}
/**
* @param recipe a collection of arcane crafting recipes.
*/
public ResearchPage(IArcaneRecipe[] recipe)
{
this.type = PageType.ARCANE_CRAFTING;
this.recipe = recipe;
}
/**
* @param recipe a collection of infusion crafting recipes.
*/
public ResearchPage(InfusionRecipe[] recipe)
{
this.type = PageType.INFUSION_CRAFTING;
this.recipe = recipe;
}
/**
* @param recipe a compound crafting recipe.
*/
public ResearchPage(List recipe)
{
this.type = PageType.COMPOUND_CRAFTING;
this.recipe = recipe;
}
/**
* @param recipe an arcane worktable crafting recipe.
*/
public ResearchPage(IArcaneRecipe recipe)
{
this.type = PageType.ARCANE_CRAFTING;
this.recipe = recipe;
this.recipeOutput = recipe.getRecipeOutput();
}
/**
* @param recipe an alchemy crafting recipe.
*/
public ResearchPage(CrucibleRecipe recipe)
{
this.type = PageType.CRUCIBLE_CRAFTING;
this.recipe = recipe;
this.recipeOutput = recipe.recipeOutput;
}
/**
* @param recipe an infusion crafting recipe.
*/
public ResearchPage(InfusionRecipe recipe)
{
this.type = PageType.INFUSION_CRAFTING;
this.recipe = recipe;
if (recipe.recipeOutput instanceof ItemStack)
{
this.recipeOutput = (ItemStack) recipe.recipeOutput;
}
else
{
this.recipeOutput = recipe.recipeInput;
}
}
/**
* @param recipe an infusion crafting recipe.
*/
public ResearchPage(InfusionEnchantmentRecipe recipe)
{
this.type = PageType.INFUSION_ENCHANTMENT;
this.recipe = recipe;
// if (recipe.recipeOutput instanceof ItemStack) {
// this.recipeOutput = (ItemStack) recipe.recipeOutput;
// } else {
// this.recipeOutput = recipe.recipeInput;
// }
}
/**
* @param image
* @param caption this can (but does not have to) be a reference to a localization variable, not the actual text.
*/
public ResearchPage(ResourceLocation image, String caption)
{
this.type = PageType.IMAGE;
this.image = image;
this.text = caption;
}
/**
* This function should really not be called directly - used internally
*/
public ResearchPage(AspectList as)
{
this.type = PageType.ASPECTS;
this.aspects = as;
}
/**
* returns a localized text of the text field (if one exists). Returns the text field itself otherwise.
* @return
*/
public String getTranslatedText()
{
String ret = "";
if (text != null)
{
ret = StatCollector.translateToLocal(text);
if (ret.isEmpty())
{
ret = text;
}
}
return ret;
}
}

View file

@ -0,0 +1,55 @@
package thaumcraft.api.research;
import net.minecraft.entity.Entity;
public class ScanResult
{
public byte type = 0; //1=blocks,2=entities,3=phenomena
public int blockId;
public int blockMeta;
public Entity entity;
public String phenomena;
public ScanResult(byte type, int blockId, int blockMeta, Entity entity,
String phenomena)
{
super();
this.type = type;
this.blockId = blockId;
this.blockMeta = blockMeta;
this.entity = entity;
this.phenomena = phenomena;
}
@Override
public boolean equals(Object obj)
{
if (obj instanceof ScanResult)
{
ScanResult sr = (ScanResult) obj;
if (type != sr.type)
{
return false;
}
if (type == 1
&& (blockId != sr.blockId || blockMeta != sr.blockMeta))
{
return false;
}
if (type == 2 && entity.entityId != sr.entity.entityId)
{
return false;
}
if (type == 3 && !phenomena.equals(sr.phenomena))
{
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,59 @@
package thaumcraft.api.wands;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Icon;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.World;
import thaumcraft.api.aspects.AspectList;
public interface IWandFocus
{
public enum WandFocusAnimation
{
WAVE, CHARGE;
}
/**
* @return The color the focus should be changed to.
*/
public int getFocusColor();
/**
* @return An icon that will be drawn as a block inside the focus "block".
*/
Icon getFocusDepthLayerIcon();
public Icon getOrnament();
public WandFocusAnimation getAnimation();
/**
* Gets the amount of vis used per aspect per click or tick. This cost is actually listed as
* a hundredth of a single point of vis, so a cost of 100 will equal one vis per tick/click.
* It is returned as an AspectList to allow for multiple vis types in different ratios.
*/
public AspectList getVisCost();
public boolean isVisCostPerTick();
public ItemStack onFocusRightClick(ItemStack itemstack, World world, EntityPlayer player, MovingObjectPosition movingobjectposition);
public void onUsingFocusTick(ItemStack itemstack, EntityPlayer player, int count);
public void onPlayerStoppedUsingFocus(ItemStack itemstack, World world, EntityPlayer player, int count);
/**
* Helper method to determine in what order foci should be iterated through when
* the user presses the 'change focus' keybinding.
* @return a string of characters that foci will be sorted against.
* For example AA00 will be placed before FG12
* <br>As a guide build the sort string from two alphanumeric characters followed by
* two numeric characters based on... whatever.
*/
public String getSortingHelper(ItemStack itemstack);
boolean onFocusBlockStartBreak(ItemStack itemstack, int x, int y, int z, EntityPlayer player);
public boolean acceptsEnchant(int id);
}

View file

@ -0,0 +1,17 @@
package thaumcraft.api.wands;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
/**
*
* @author azanor
*
* Implemented by a class that you wish to be called whenever a wand with this rod performs its
* update tick.
*
*/
public interface IWandRodOnUpdate
{
void onUpdate(ItemStack itemstack, EntityPlayer player);
}

View file

@ -0,0 +1,11 @@
package thaumcraft.api.wands;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public interface IWandTriggerManager
{
public boolean performTrigger(World world, ItemStack wand, EntityPlayer player,
int x, int y, int z, int side, int event);
}

View file

@ -0,0 +1,24 @@
package thaumcraft.api.wands;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
/**
*
* @author azanor
*
* Add this to a tile entity that you wish wands to interact with in some way.
*
*/
public interface IWandable
{
public int onWandRightClick(World world, ItemStack wandstack, EntityPlayer player, int x, int y, int z, int side, int md);
public ItemStack onWandRightClick(World world, ItemStack wandstack, EntityPlayer player);
public void onUsingWandTick(ItemStack wandstack, EntityPlayer player, int count);
public void onWandStoppedUsing(ItemStack wandstack, World world, EntityPlayer player, int count);
}

View file

@ -0,0 +1,185 @@
package thaumcraft.api.wands;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumRarity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Icon;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.StatCollector;
import net.minecraft.world.World;
import thaumcraft.api.ThaumcraftApi;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class ItemFocusBasic extends Item implements IWandFocus
{
public ItemFocusBasic(int i)
{
super(i);
maxStackSize = 1;
canRepair = false;
this.setMaxDamage(1);
}
public Icon icon;
@SideOnly(Side.CLIENT)
@Override
public Icon getIconFromDamage(int par1)
{
return icon;
}
@Override
public boolean isItemTool(ItemStack par1ItemStack)
{
return true;
}
@Override
public boolean isDamageable()
{
return true;
}
@Override
public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean par4)
{
AspectList al = this.getVisCost();
if (al != null && al.size() > 0)
{
list.add(StatCollector.translateToLocal(isVisCostPerTick() ? "item.Focus.cost2" : "item.Focus.cost1"));
for (Aspect aspect: al.getAspectsSorted())
{
DecimalFormat myFormatter = new DecimalFormat("#####.##");
String amount = myFormatter.format(al.getAmount(aspect) / 100f);
list.add(" \u00A7" + aspect.getChatcolor() + aspect.getName() + "\u00A7r x " + amount);
}
}
}
@Override
public int getItemEnchantability()
{
return 5;
}
@Override
public EnumRarity getRarity(ItemStack itemstack)
{
return EnumRarity.rare;
}
@Override
public int getFocusColor()
{
// TODO Auto-generated method stub
return 0;
}
@Override
public AspectList getVisCost()
{
// TODO Auto-generated method stub
return null;
}
@Override
public ItemStack onFocusRightClick(ItemStack itemstack, World world,
EntityPlayer player, MovingObjectPosition movingobjectposition)
{
// TODO Auto-generated method stub
return null;
}
@Override
public void onUsingFocusTick(ItemStack itemstack, EntityPlayer player,
int count)
{
// TODO Auto-generated method stub
}
@Override
public void onPlayerStoppedUsingFocus(ItemStack itemstack, World world,
EntityPlayer player, int count)
{
// TODO Auto-generated method stub
}
/**
* Just insert two alphanumeric characters before this string in your focus item class
*/
@Override
public String getSortingHelper(ItemStack itemstack)
{
Map<Integer, Integer> ench = EnchantmentHelper.getEnchantments(itemstack);
String out = "";
for (Integer lvl: ench.values())
{
out = out + lvl + "";
}
return out;
}
@Override
public boolean isVisCostPerTick()
{
return false;
}
@Override
public Icon getOrnament()
{
// TODO Auto-generated method stub
return null;
}
@Override
public boolean onFocusBlockStartBreak(ItemStack itemstack, int x, int y,
int z, EntityPlayer player)
{
// TODO Auto-generated method stub
return false;
}
@Override
public WandFocusAnimation getAnimation()
{
return WandFocusAnimation.WAVE;
}
@Override
public Icon getFocusDepthLayerIcon()
{
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see thaumcraft.api.wands.IWandFocus#acceptsEnchant(int)
* By default fortune is off for all wands
*/
@Override
public boolean acceptsEnchant(int id)
{
if (id == ThaumcraftApi.enchantFrugal ||
id == ThaumcraftApi.enchantPotency)
{
return true;
}
return false;
}
}

View file

@ -0,0 +1,133 @@
package thaumcraft.api.wands;
import java.util.LinkedHashMap;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import thaumcraft.api.aspects.Aspect;
/**
* This class is used to keep the material information for the various caps.
* It is also used to generate the wand recipes ingame.
* @author Azanor
*
*/
public class WandCap
{
private String tag;
/**
* Cost to craft this wand. Combined with the rod cost.
*/
private int craftCost;
/**
* the amount by which all aspect costs are multiplied
*/
float baseCostModifier;
/**
* specifies a list of primal aspects that use the special discount figure instead of the normal discount.
*/
List<Aspect> specialCostModifierAspects;
/**
* the amount by which the specified aspect costs are multiplied
*/
float specialCostModifier;
/**
* The texture that will be used for the ingame wand cap
*/
ResourceLocation texture;
/**
* the actual item that makes up this cap and will be used to generate the wand recipes
*/
ItemStack item;
public static LinkedHashMap<String, WandCap> caps = new LinkedHashMap<String, WandCap>();
public WandCap(String tag, float discount, ItemStack item, int craftCost)
{
this.setTag(tag);
this.baseCostModifier = discount;
this.specialCostModifierAspects = null;
texture = new ResourceLocation("thaumcraft", "textures/models/wand_cap_" + getTag() + ".png");
this.item = item;
this.setCraftCost(craftCost);
caps.put(tag, this);
}
public WandCap(String tag, float discount, List<Aspect> specialAspects, float discountSpecial, ItemStack item, int craftCost)
{
this.setTag(tag);
this.baseCostModifier = discount;
this.specialCostModifierAspects = specialAspects;
this.specialCostModifier = discountSpecial;
texture = new ResourceLocation("thaumcraft", "textures/models/wand_cap_" + getTag() + ".png");
this.item = item;
this.setCraftCost(craftCost);
caps.put(tag, this);
}
public float getBaseCostModifier()
{
return baseCostModifier;
}
public List<Aspect> getSpecialCostModifierAspects()
{
return specialCostModifierAspects;
}
public float getSpecialCostModifier()
{
return specialCostModifier;
}
public ResourceLocation getTexture()
{
return texture;
}
public void setTexture(ResourceLocation texture)
{
this.texture = texture;
}
public String getTag()
{
return tag;
}
public void setTag(String tag)
{
this.tag = tag;
}
public ItemStack getItem()
{
return item;
}
public void setItem(ItemStack item)
{
this.item = item;
}
public int getCraftCost()
{
return craftCost;
}
public void setCraftCost(int craftCost)
{
this.craftCost = craftCost;
}
// Some examples:
// WandCap WAND_CAP_IRON = new WandCap("iron", 1.1f, Arrays.asList(Aspect.ORDER),1, new ItemStack(ConfigItems.itemWandCap,1,0),1);
// WandCap WAND_CAP_GOLD = new WandCap("gold", 1f, new ItemStack(ConfigItems.itemWandCap,1,1),3);
}

View file

@ -0,0 +1,168 @@
package thaumcraft.api.wands;
import java.util.LinkedHashMap;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
/**
*
* @author Azanor
*
* This class is used to keep the material information for the various rods.
* It is also used to generate the wand recipes ingame.
*
*/
public class WandRod
{
private String tag;
/**
* Cost to craft this wand. Combined with the rod cost.
*/
private int craftCost;
/**
* The amount of vis that can be stored - this number is actually multiplied
* by 100 for use by the wands internals
*/
int capacity;
/**
* The texture that will be used for the ingame wand rod
*/
ResourceLocation texture;
/**
* the actual item that makes up this rod and will be used to generate the wand recipes
*/
ItemStack item;
/**
* A class that will be called whenever the wand onUpdate tick is run
*/
IWandRodOnUpdate onUpdate;
/**
* Does the rod glow in the dark?
*/
boolean glow;
public static LinkedHashMap<String, WandRod> rods = new LinkedHashMap<String, WandRod>();
public WandRod(String tag, int capacity, ItemStack item, int craftCost, ResourceLocation texture)
{
this.setTag(tag);
this.capacity = capacity;
this.texture = texture;
this.item = item;
this.setCraftCost(craftCost);
rods.put(tag, this);
}
public WandRod(String tag, int capacity, ItemStack item, int craftCost, IWandRodOnUpdate onUpdate, ResourceLocation texture)
{
this.setTag(tag);
this.capacity = capacity;
this.texture = texture;
this.item = item;
this.setCraftCost(craftCost);
rods.put(tag, this);
this.onUpdate = onUpdate;
}
public WandRod(String tag, int capacity, ItemStack item, int craftCost)
{
this.setTag(tag);
this.capacity = capacity;
this.texture = new ResourceLocation("thaumcraft", "textures/models/wand_rod_" + getTag() + ".png");
this.item = item;
this.setCraftCost(craftCost);
rods.put(tag, this);
}
public WandRod(String tag, int capacity, ItemStack item, int craftCost, IWandRodOnUpdate onUpdate)
{
this.setTag(tag);
this.capacity = capacity;
this.texture = new ResourceLocation("thaumcraft", "textures/models/wand_rod_" + getTag() + ".png");
this.item = item;
this.setCraftCost(craftCost);
rods.put(tag, this);
this.onUpdate = onUpdate;
}
public String getTag()
{
return tag;
}
public void setTag(String tag)
{
this.tag = tag;
}
public int getCapacity()
{
return capacity;
}
public void setCapacity(int capacity)
{
this.capacity = capacity;
}
public ResourceLocation getTexture()
{
return texture;
}
public void setTexture(ResourceLocation texture)
{
this.texture = texture;
}
public ItemStack getItem()
{
return item;
}
public void setItem(ItemStack item)
{
this.item = item;
}
public int getCraftCost()
{
return craftCost;
}
public void setCraftCost(int craftCost)
{
this.craftCost = craftCost;
}
public IWandRodOnUpdate getOnUpdate()
{
return onUpdate;
}
public void setOnUpdate(IWandRodOnUpdate onUpdate)
{
this.onUpdate = onUpdate;
}
public boolean isGlowing()
{
return glow;
}
public void setGlowing(boolean hasGlow)
{
this.glow = hasGlow;
}
// Some examples:
// WandRod WAND_ROD_WOOD = new WandRod("wood",25,new ItemStack(Item.stick),1);
// WandRod WAND_ROD_BLAZE = new WandRod("blaze",100,new ItemStack(Item.blazeRod),7,new WandRodBlazeOnUpdate());
}

View file

@ -0,0 +1,83 @@
package thaumcraft.api.wands;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
/**
* This class serves a similar function to IWandable in that it allows wands to interact
* with object in the world. In this case it is most useful for adding interaction with non-mod
* blocks where you can't control what happens in their code.
* Example where it is used is in crafting the thaumonomicon from a bookshelf and the
* crucible from a cauldron
*
* @author azanor
*
*/
public class WandTriggerRegistry
{
/**
* Registers an action to perform when a casting wand right clicks on a specific block.
* A manager class needs to be created that implements IWandTriggerManager.
* @param manager
* @param event a logical number that you can use to differentiate different events or actions
* @param blockid
* @param meta send -1 as a wildcard value for all possible meta values
*/
public static void registerWandBlockTrigger(IWandTriggerManager manager, int event, int blockid, int meta)
{
triggers.put(Arrays.asList(blockid, meta),
Arrays.asList(manager, event));
}
private static HashMap<List<Integer>, List> triggers = new HashMap<List<Integer>, List>();
public static boolean hasTrigger(int blockid, int meta)
{
if (triggers.containsKey(Arrays.asList(blockid, meta)) ||
triggers.containsKey(Arrays.asList(blockid, -1)))
{
return true;
}
return false;
}
/**
* This is called by the onItemUseFirst function in wands.
* Parameters and return value functions like you would expect for that function.
* @param world
* @param wand
* @param player
* @param x
* @param y
* @param z
* @param side
* @param blockid
* @param meta
* @return
*/
public static boolean performTrigger(World world, ItemStack wand, EntityPlayer player,
int x, int y, int z, int side, int blockid, int meta)
{
List l = triggers.get(Arrays.asList(blockid, meta));
if (l == null)
{
l = triggers.get(Arrays.asList(blockid, -1));
}
if (l == null)
{
return false;
}
IWandTriggerManager manager = (IWandTriggerManager) l.get(0);
int event = (Integer) l.get(1);
return manager.performTrigger(world, wand, player, x, y, z, side, event);
}
}