mirror of
https://github.com/GTNewHorizons/ForbiddenMagic.git
synced 2026-11-11 15:57:37 +00:00
Bugfixes and stuff
This commit is contained in:
1 parent
0f75db6587
commit
ffabe6945e
27 files changed
+1057
-349
No files matched your search
@@ -0,0 +1,108 @@
|
||||
package thaumcraft.api;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
public class BlockCoordinates implements Comparable
|
||||
{
|
||||
public int x;
|
||||
|
||||
/** the y coordinate */
|
||||
public int y;
|
||||
|
||||
/** the z coordinate */
|
||||
public int z;
|
||||
|
||||
public BlockCoordinates() {}
|
||||
|
||||
public BlockCoordinates(int par1, int par2, int par3)
|
||||
{
|
||||
this.x = par1;
|
||||
this.y = par2;
|
||||
this.z = par3;
|
||||
}
|
||||
|
||||
public BlockCoordinates(TileEntity tile)
|
||||
{
|
||||
this.x = tile.xCoord;
|
||||
this.y = tile.yCoord;
|
||||
this.z = tile.zCoord;
|
||||
}
|
||||
|
||||
public BlockCoordinates(BlockCoordinates par1ChunkCoordinates)
|
||||
{
|
||||
this.x = par1ChunkCoordinates.x;
|
||||
this.y = par1ChunkCoordinates.y;
|
||||
this.z = par1ChunkCoordinates.z;
|
||||
}
|
||||
|
||||
public boolean equals(Object par1Obj)
|
||||
{
|
||||
if (!(par1Obj instanceof BlockCoordinates))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockCoordinates coordinates = (BlockCoordinates)par1Obj;
|
||||
return this.x == coordinates.x && this.y == coordinates.y && this.z == coordinates.z ;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return this.x + this.y << 8 + this.z << 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the coordinate with another coordinate
|
||||
*/
|
||||
public int compareWorldCoordinate(BlockCoordinates par1)
|
||||
{
|
||||
return this.y == par1.y ? (this.z == par1.z ? this.x - par1.x : this.z - par1.z) : this.y - par1.y;
|
||||
}
|
||||
|
||||
public void set(int par1, int par2, int par3, int d)
|
||||
{
|
||||
this.x = par1;
|
||||
this.y = par2;
|
||||
this.z = par3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the squared distance between this coordinates and the coordinates given as argument.
|
||||
*/
|
||||
public float getDistanceSquared(int par1, int par2, int par3)
|
||||
{
|
||||
float f = (float)(this.x - par1);
|
||||
float f1 = (float)(this.y - par2);
|
||||
float f2 = (float)(this.z - par3);
|
||||
return f * f + f1 * f1 + f2 * f2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the squared distance between this coordinates and the ChunkCoordinates given as argument.
|
||||
*/
|
||||
public float getDistanceSquaredToWorldCoordinates(BlockCoordinates par1ChunkCoordinates)
|
||||
{
|
||||
return this.getDistanceSquared(par1ChunkCoordinates.x, par1ChunkCoordinates.y, par1ChunkCoordinates.z);
|
||||
}
|
||||
|
||||
public int compareTo(Object par1Obj)
|
||||
{
|
||||
return this.compareWorldCoordinate((BlockCoordinates)par1Obj);
|
||||
}
|
||||
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
this.x = nbt.getInteger("b_x");
|
||||
this.y = nbt.getInteger("b_y");
|
||||
this.z = nbt.getInteger("b_z");
|
||||
}
|
||||
|
||||
public void writeNBT(NBTTagCompound nbt) {
|
||||
nbt.setInteger("b_x",x);
|
||||
nbt.setInteger("b_y",y);
|
||||
nbt.setInteger("b_z",z);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package thaumcraft.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IArchitect {
|
||||
|
||||
/**
|
||||
* Returns a list of blocks that should be highlighted in world.
|
||||
*/
|
||||
public ArrayList<BlockCoordinates> getArchitectBlocks(ItemStack stack, World world,
|
||||
int x, int y, int z, int side, EntityPlayer player);
|
||||
|
||||
/**
|
||||
* which axis should be displayed.
|
||||
*/
|
||||
public boolean showAxis(ItemStack stack, World world, EntityPlayer player, int side, EnumAxis axis);
|
||||
|
||||
public enum EnumAxis {
|
||||
X, // east / west
|
||||
Y, // up / down
|
||||
Z; // north / south
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,9 @@ import thaumcraft.api.crafting.InfusionEnchantmentRecipe;
|
||||
import thaumcraft.api.crafting.InfusionRecipe;
|
||||
import thaumcraft.api.crafting.ShapedArcaneRecipe;
|
||||
import thaumcraft.api.crafting.ShapelessArcaneRecipe;
|
||||
import thaumcraft.api.internal.DummyInternalMethodHandler;
|
||||
import thaumcraft.api.internal.IInternalMethodHandler;
|
||||
import thaumcraft.api.internal.WeightedRandomLoot;
|
||||
import thaumcraft.api.research.IScanEventHandler;
|
||||
import thaumcraft.api.research.ResearchCategories;
|
||||
import thaumcraft.api.research.ResearchCategoryList;
|
||||
@@ -62,6 +65,9 @@ public class ThaumcraftApi {
|
||||
*/
|
||||
public static ArrayList<Block> portableHoleBlackList = new ArrayList<Block>();
|
||||
|
||||
//Internal (Do not alter this unless you like pretty explosions)
|
||||
//Calling methods from this will only work properly once Thaumcraft is past the FMLPreInitializationEvent phase.
|
||||
public static IInternalMethodHandler internalMethods = new DummyInternalMethodHandler();
|
||||
|
||||
//RESEARCH/////////////////////////////////////////
|
||||
public static ArrayList<IScanEventHandler> scanEventhandlers = new ArrayList<IScanEventHandler>();
|
||||
@@ -323,6 +329,7 @@ public class ThaumcraftApi {
|
||||
//ASPECTS////////////////////////////////////////
|
||||
|
||||
public static ConcurrentHashMap<List,AspectList> objectTags = new ConcurrentHashMap<List,AspectList>();
|
||||
public static ConcurrentHashMap<List,int[]> groupedObjectTags = new ConcurrentHashMap<List,int[]>();
|
||||
|
||||
/**
|
||||
* Checks to see if the passed item/block already has aspects associated with it.
|
||||
@@ -370,8 +377,12 @@ public class ThaumcraftApi {
|
||||
*/
|
||||
public static void registerObjectTag(ItemStack item, int[] meta, AspectList aspects) {
|
||||
if (aspects==null) aspects=new AspectList();
|
||||
try {
|
||||
objectTags.put(Arrays.asList(item.getItem(),meta), aspects);
|
||||
try {
|
||||
objectTags.put(Arrays.asList(item.getItem(),meta[0]), aspects);
|
||||
for (int m:meta) {
|
||||
groupedObjectTags.put(Arrays.asList(item.getItem(),m), meta);
|
||||
}
|
||||
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
@@ -456,6 +467,32 @@ public class ThaumcraftApi {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//LOOT BAGS //////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Used to add possible loot to treasure bags. As a reference, the weight of gold coins are 2000
|
||||
* and a diamond is 50.
|
||||
* The weights are the same for all loot bag types - the only difference is how many items the bag
|
||||
* contains.
|
||||
* @param item
|
||||
* @param weight
|
||||
* @param bagTypes array of which type of bag to add this loot to. Multiple types can be specified
|
||||
* 0 = common, 1 = uncommon, 2 = rare
|
||||
*/
|
||||
public static void addLootBagItem(ItemStack item, int weight, int... bagTypes) {
|
||||
if (bagTypes==null || bagTypes.length==0)
|
||||
WeightedRandomLoot.lootBagCommon.add(new WeightedRandomLoot(item,weight));
|
||||
else {
|
||||
for (int rarity:bagTypes) {
|
||||
switch(rarity) {
|
||||
case 0: WeightedRandomLoot.lootBagCommon.add(new WeightedRandomLoot(item,weight)); break;
|
||||
case 1: WeightedRandomLoot.lootBagUncommon.add(new WeightedRandomLoot(item,weight)); break;
|
||||
case 2: WeightedRandomLoot.lootBagRare.add(new WeightedRandomLoot(item,weight)); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//CROPS //////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -515,9 +552,9 @@ public class ThaumcraftApi {
|
||||
* in your @Mod.Init method using the "dimensionBlacklist" string message in the format "[dimension]:[level]"
|
||||
* The level values are as follows:
|
||||
* [0] stop all tc spawning and generation
|
||||
* [1] allow ore and node generation
|
||||
* [1] allow ore and node generation (and node special features)
|
||||
* [2] allow mob spawning
|
||||
* [3] allow ore and node gen + mob spawning
|
||||
* [3] allow ore and node gen + mob spawning (and node special features)
|
||||
* Example:
|
||||
* FMLInterModComms.sendMessage("Thaumcraft", "dimensionBlacklist", "15:1");
|
||||
*/
|
||||
@@ -528,9 +565,9 @@ public class ThaumcraftApi {
|
||||
* in your @Mod.Init method using the "biomeBlacklist" string message in the format "[biome id]:[level]"
|
||||
* The level values are as follows:
|
||||
* [0] stop all tc spawning and generation
|
||||
* [1] allow ore and node generation
|
||||
* [1] allow ore and node generation (and node special features)
|
||||
* [2] allow mob spawning
|
||||
* [3] allow ore and node gen + mob spawning
|
||||
* [3] allow ore and node gen + mob spawning (and node special features)
|
||||
* Example:
|
||||
* FMLInterModComms.sendMessage("Thaumcraft", "biomeBlacklist", "180:2");
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package thaumcraft.api;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
@@ -15,7 +18,6 @@ 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 {
|
||||
|
||||
@@ -25,13 +27,37 @@ public class ThaumcraftApiHelper {
|
||||
if (tag!=null)
|
||||
temp2.add(tag, temp.getAmount(tag));
|
||||
}
|
||||
while (temp2!=null && temp2.size()>10) {
|
||||
while (temp2!=null && temp2.size()>6) {
|
||||
Aspect lowest = null;
|
||||
int low = Integer.MAX_VALUE;
|
||||
float low = Short.MAX_VALUE;
|
||||
for (Aspect tag:temp2.getAspects()) {
|
||||
if (tag==null) continue;
|
||||
if (temp2.getAmount(tag)<low) {
|
||||
low = temp2.getAmount(tag);
|
||||
float ta=temp2.getAmount(tag);
|
||||
if (tag.isPrimal()) {
|
||||
ta *= .9f;
|
||||
} else {
|
||||
if (!tag.getComponents()[0].isPrimal()) {
|
||||
ta *= 1.1f;
|
||||
if (!tag.getComponents()[0].getComponents()[0].isPrimal()) {
|
||||
ta *= 1.05f;
|
||||
}
|
||||
if (!tag.getComponents()[0].getComponents()[1].isPrimal()) {
|
||||
ta *= 1.05f;
|
||||
}
|
||||
}
|
||||
if (!tag.getComponents()[1].isPrimal()) {
|
||||
ta *= 1.1f;
|
||||
if (!tag.getComponents()[1].getComponents()[0].isPrimal()) {
|
||||
ta *= 1.05f;
|
||||
}
|
||||
if (!tag.getComponents()[1].getComponents()[1].isPrimal()) {
|
||||
ta *= 1.05f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ta<low) {
|
||||
low = ta;
|
||||
lowest = tag;
|
||||
}
|
||||
}
|
||||
@@ -49,75 +75,32 @@ public class ThaumcraftApiHelper {
|
||||
return s1.getItem() == s2.getItem() && 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;
|
||||
return ThaumcraftApi.internalMethods.isResearchComplete(username, researchkey);
|
||||
}
|
||||
|
||||
public static boolean hasDiscoveredAspect(String username, Aspect aspect) {
|
||||
return ThaumcraftApi.internalMethods.hasDiscoveredAspect(username, aspect);
|
||||
}
|
||||
|
||||
public static AspectList getDiscoveredAspects(String username) {
|
||||
return ThaumcraftApi.internalMethods.getDiscoveredAspects(username);
|
||||
}
|
||||
|
||||
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;
|
||||
return ThaumcraftApi.internalMethods.getStackInRowAndColumn(instance, row, column);
|
||||
}
|
||||
|
||||
public static AspectList getObjectAspects(ItemStack is) {
|
||||
AspectList ot = null;
|
||||
try {
|
||||
if(getObjectTags == null) {
|
||||
Class fake = Class.forName("thaumcraft.common.lib.crafting.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.crafting.ThaumcraftCraftingManager method getObjectTags");
|
||||
}
|
||||
return ot;
|
||||
return ThaumcraftApi.internalMethods.getObjectAspects(is);
|
||||
}
|
||||
|
||||
public static AspectList getBonusObjectTags(ItemStack is,AspectList ot) {
|
||||
|
||||
try {
|
||||
if(getBonusTags == null) {
|
||||
Class fake = Class.forName("thaumcraft.common.lib.crafting.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.crafting.ThaumcraftCraftingManager method getBonusTags");
|
||||
}
|
||||
return ot;
|
||||
return ThaumcraftApi.internalMethods.getBonusObjectTags(is, ot);
|
||||
}
|
||||
|
||||
public static AspectList generateTags(Item item, int meta) {
|
||||
try {
|
||||
if(generateTags == null) {
|
||||
Class fake = Class.forName("thaumcraft.common.lib.crafting.ThaumcraftCraftingManager");
|
||||
generateTags = fake.getMethod("generateTags", Item.class, int.class);
|
||||
}
|
||||
return (AspectList) generateTags.invoke(null, item, meta);
|
||||
} catch(Exception ex) {
|
||||
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.crafting.ThaumcraftCraftingManager method generateTags");
|
||||
}
|
||||
return null;
|
||||
return ThaumcraftApi.internalMethods.generateTags(item, meta);
|
||||
}
|
||||
|
||||
public static boolean containsMatch(boolean strict, ItemStack[] inputs, ItemStack... targets)
|
||||
@@ -210,7 +193,7 @@ public class ThaumcraftApiHelper {
|
||||
return allCompoundAspects.get(amount);
|
||||
}
|
||||
|
||||
static Method consumeVisFromWand;
|
||||
|
||||
/**
|
||||
* Use to subtract vis from a wand for most operations
|
||||
* Wands store vis differently so "real" vis costs need to be multiplied by 100 before calling this method
|
||||
@@ -224,22 +207,9 @@ public class ThaumcraftApiHelper {
|
||||
*/
|
||||
public static boolean consumeVisFromWand(ItemStack wand, EntityPlayer player,
|
||||
AspectList cost, boolean doit, boolean crafting) {
|
||||
boolean ot = false;
|
||||
try {
|
||||
if(consumeVisFromWand == null) {
|
||||
Class fake = Class.forName("thaumcraft.common.items.wands.ItemWandCasting");
|
||||
consumeVisFromWand = fake.getMethod("consumeAllVis",
|
||||
ItemStack.class, EntityPlayer.class, AspectList.class, boolean.class, boolean.class);
|
||||
}
|
||||
ot = (Boolean) consumeVisFromWand.invoke(
|
||||
consumeVisFromWand.getDeclaringClass().cast(wand.getItem()), wand, player, cost, doit, crafting);
|
||||
} catch(Exception ex) {
|
||||
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.items.wands.ItemWandCasting method consumeAllVis");
|
||||
}
|
||||
return ot;
|
||||
return ThaumcraftApi.internalMethods.consumeVisFromWand(wand, player, cost, doit, crafting);
|
||||
}
|
||||
|
||||
static Method consumeVisFromWandCrafting;
|
||||
/**
|
||||
* Subtract vis for use by a crafting mechanic. Costs are calculated slightly
|
||||
* differently and things like the frugal enchant is ignored
|
||||
@@ -252,22 +222,9 @@ public class ThaumcraftApiHelper {
|
||||
*/
|
||||
public static boolean consumeVisFromWandCrafting(ItemStack wand, EntityPlayer player,
|
||||
AspectList cost, boolean doit) {
|
||||
boolean ot = false;
|
||||
try {
|
||||
if(consumeVisFromWandCrafting == null) {
|
||||
Class fake = Class.forName("thaumcraft.common.items.wands.ItemWandCasting");
|
||||
consumeVisFromWandCrafting = fake.getMethod("consumeAllVisCrafting",
|
||||
ItemStack.class, EntityPlayer.class, AspectList.class, boolean.class);
|
||||
}
|
||||
ot = (Boolean) consumeVisFromWandCrafting.invoke(
|
||||
consumeVisFromWandCrafting.getDeclaringClass().cast(wand.getItem()), wand, player, cost, doit);
|
||||
} catch(Exception ex) {
|
||||
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.items.wands.ItemWandCasting method consumeAllVisCrafting");
|
||||
}
|
||||
return ot;
|
||||
return ThaumcraftApi.internalMethods.consumeVisFromWandCrafting(wand, player, cost, doit);
|
||||
}
|
||||
|
||||
static Method consumeVisFromInventory;
|
||||
/**
|
||||
* Subtract vis from a wand the player is carrying. Works like consumeVisFromWand in that actual vis
|
||||
* costs should be multiplied by 100. The costs are handled like crafting however and things like
|
||||
@@ -277,22 +234,10 @@ public class ThaumcraftApiHelper {
|
||||
* @return was the vis successfully subtracted
|
||||
*/
|
||||
public static boolean consumeVisFromInventory(EntityPlayer player, AspectList cost) {
|
||||
boolean ot = false;
|
||||
try {
|
||||
if(consumeVisFromInventory == null) {
|
||||
Class fake = Class.forName("thaumcraft.common.items.wands.WandManager");
|
||||
consumeVisFromInventory = fake.getMethod("consumeVisFromInventory",
|
||||
EntityPlayer.class, AspectList.class);
|
||||
}
|
||||
ot = (Boolean) consumeVisFromInventory.invoke(null, player, cost);
|
||||
} catch(Exception ex) {
|
||||
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.items.wands.WandManager method consumeVisFromInventory");
|
||||
}
|
||||
return ot;
|
||||
return ThaumcraftApi.internalMethods.consumeVisFromInventory(player, cost);
|
||||
}
|
||||
|
||||
|
||||
static Method addWarpToPlayer;
|
||||
/**
|
||||
* This adds permanents or temporary warp to a player. It will automatically be synced clientside
|
||||
* @param player the player using the wand
|
||||
@@ -300,20 +245,9 @@ public class ThaumcraftApiHelper {
|
||||
* @param temporary add temporary warp instead of permanent
|
||||
*/
|
||||
public static void addWarpToPlayer(EntityPlayer player, int amount, boolean temporary) {
|
||||
boolean ot = false;
|
||||
try {
|
||||
if(addWarpToPlayer == null) {
|
||||
Class fake = Class.forName("thaumcraft.common.Thaumcraft");
|
||||
addWarpToPlayer = fake.getMethod("addWarpToPlayer",
|
||||
EntityPlayer.class, int.class, boolean.class);
|
||||
}
|
||||
addWarpToPlayer.invoke(null, player, amount, temporary);
|
||||
} catch(Exception ex) {
|
||||
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.Thaumcraft method addWarpToPlayer");
|
||||
}
|
||||
ThaumcraftApi.internalMethods.addWarpToPlayer(player, amount, temporary);
|
||||
}
|
||||
|
||||
static Method addStickyWarpToPlayer;
|
||||
/**
|
||||
* This "sticky" warp to a player. Sticky warp is permanent warp that can be removed.
|
||||
* It will automatically be synced clientside
|
||||
@@ -321,16 +255,213 @@ public class ThaumcraftApiHelper {
|
||||
* @param amount how much warp to add. Can have negative amounts.
|
||||
*/
|
||||
public static void addStickyWarpToPlayer(EntityPlayer player, int amount) {
|
||||
boolean ot = false;
|
||||
try {
|
||||
if(addStickyWarpToPlayer == null) {
|
||||
Class fake = Class.forName("thaumcraft.common.Thaumcraft");
|
||||
addStickyWarpToPlayer = fake.getMethod("addStickyWarpToPlayer",
|
||||
EntityPlayer.class, int.class);
|
||||
ThaumcraftApi.internalMethods.addStickyWarpToPlayer(player, amount);
|
||||
}
|
||||
|
||||
public static MovingObjectPosition rayTraceIgnoringSource(World world, Vec3 v1, Vec3 v2,
|
||||
boolean bool1, boolean bool2, boolean bool3)
|
||||
{
|
||||
if (!Double.isNaN(v1.xCoord) && !Double.isNaN(v1.yCoord) && !Double.isNaN(v1.zCoord))
|
||||
{
|
||||
if (!Double.isNaN(v2.xCoord) && !Double.isNaN(v2.yCoord) && !Double.isNaN(v2.zCoord))
|
||||
{
|
||||
int i = MathHelper.floor_double(v2.xCoord);
|
||||
int j = MathHelper.floor_double(v2.yCoord);
|
||||
int k = MathHelper.floor_double(v2.zCoord);
|
||||
int l = MathHelper.floor_double(v1.xCoord);
|
||||
int i1 = MathHelper.floor_double(v1.yCoord);
|
||||
int j1 = MathHelper.floor_double(v1.zCoord);
|
||||
Block block = world.getBlock(l, i1, j1);
|
||||
int k1 = world.getBlockMetadata(l, i1, j1);
|
||||
|
||||
MovingObjectPosition movingobjectposition2 = null;
|
||||
k1 = 200;
|
||||
|
||||
while (k1-- >= 0)
|
||||
{
|
||||
if (Double.isNaN(v1.xCoord) || Double.isNaN(v1.yCoord) || Double.isNaN(v1.zCoord))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (l == i && i1 == j && j1 == k)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean flag6 = true;
|
||||
boolean flag3 = true;
|
||||
boolean flag4 = true;
|
||||
double d0 = 999.0D;
|
||||
double d1 = 999.0D;
|
||||
double d2 = 999.0D;
|
||||
|
||||
if (i > l)
|
||||
{
|
||||
d0 = (double)l + 1.0D;
|
||||
}
|
||||
else if (i < l)
|
||||
{
|
||||
d0 = (double)l + 0.0D;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag6 = false;
|
||||
}
|
||||
|
||||
if (j > i1)
|
||||
{
|
||||
d1 = (double)i1 + 1.0D;
|
||||
}
|
||||
else if (j < i1)
|
||||
{
|
||||
d1 = (double)i1 + 0.0D;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag3 = false;
|
||||
}
|
||||
|
||||
if (k > j1)
|
||||
{
|
||||
d2 = (double)j1 + 1.0D;
|
||||
}
|
||||
else if (k < j1)
|
||||
{
|
||||
d2 = (double)j1 + 0.0D;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag4 = false;
|
||||
}
|
||||
|
||||
double d3 = 999.0D;
|
||||
double d4 = 999.0D;
|
||||
double d5 = 999.0D;
|
||||
double d6 = v2.xCoord - v1.xCoord;
|
||||
double d7 = v2.yCoord - v1.yCoord;
|
||||
double d8 = v2.zCoord - v1.zCoord;
|
||||
|
||||
if (flag6)
|
||||
{
|
||||
d3 = (d0 - v1.xCoord) / d6;
|
||||
}
|
||||
|
||||
if (flag3)
|
||||
{
|
||||
d4 = (d1 - v1.yCoord) / d7;
|
||||
}
|
||||
|
||||
if (flag4)
|
||||
{
|
||||
d5 = (d2 - v1.zCoord) / d8;
|
||||
}
|
||||
|
||||
boolean flag5 = false;
|
||||
byte b0;
|
||||
|
||||
if (d3 < d4 && d3 < d5)
|
||||
{
|
||||
if (i > l)
|
||||
{
|
||||
b0 = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
b0 = 5;
|
||||
}
|
||||
|
||||
v1.xCoord = d0;
|
||||
v1.yCoord += d7 * d3;
|
||||
v1.zCoord += d8 * d3;
|
||||
}
|
||||
else if (d4 < d5)
|
||||
{
|
||||
if (j > i1)
|
||||
{
|
||||
b0 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
b0 = 1;
|
||||
}
|
||||
|
||||
v1.xCoord += d6 * d4;
|
||||
v1.yCoord = d1;
|
||||
v1.zCoord += d8 * d4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (k > j1)
|
||||
{
|
||||
b0 = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
b0 = 3;
|
||||
}
|
||||
|
||||
v1.xCoord += d6 * d5;
|
||||
v1.yCoord += d7 * d5;
|
||||
v1.zCoord = d2;
|
||||
}
|
||||
|
||||
Vec3 vec32 = Vec3.createVectorHelper(v1.xCoord, v1.yCoord, v1.zCoord);
|
||||
l = (int)(vec32.xCoord = (double)MathHelper.floor_double(v1.xCoord));
|
||||
|
||||
if (b0 == 5)
|
||||
{
|
||||
--l;
|
||||
++vec32.xCoord;
|
||||
}
|
||||
|
||||
i1 = (int)(vec32.yCoord = (double)MathHelper.floor_double(v1.yCoord));
|
||||
|
||||
if (b0 == 1)
|
||||
{
|
||||
--i1;
|
||||
++vec32.yCoord;
|
||||
}
|
||||
|
||||
j1 = (int)(vec32.zCoord = (double)MathHelper.floor_double(v1.zCoord));
|
||||
|
||||
if (b0 == 3)
|
||||
{
|
||||
--j1;
|
||||
++vec32.zCoord;
|
||||
}
|
||||
|
||||
Block block1 = world.getBlock(l, i1, j1);
|
||||
int l1 = world.getBlockMetadata(l, i1, j1);
|
||||
|
||||
if (!bool2 || block1.getCollisionBoundingBoxFromPool(world, l, i1, j1) != null)
|
||||
{
|
||||
if (block1.canCollideCheck(l1, bool1))
|
||||
{
|
||||
MovingObjectPosition movingobjectposition1 = block1.collisionRayTrace(world, l, i1, j1, v1, v2);
|
||||
|
||||
if (movingobjectposition1 != null)
|
||||
{
|
||||
return movingobjectposition1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
movingobjectposition2 = new MovingObjectPosition(l, i1, j1, b0, v1, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bool3 ? movingobjectposition2 : null;
|
||||
}
|
||||
addStickyWarpToPlayer.invoke(null, player, amount);
|
||||
} catch(Exception ex) {
|
||||
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.Thaumcraft method addStickyWarpToPlayer");
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,14 +181,14 @@ public class Aspect {
|
||||
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 MIND = new Aspect("cognitio",0xffc2b3, new Aspect[] {FIRE, 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[] {PLANT, MAN});
|
||||
public static final Aspect MINE = new Aspect("perfodio",0xdcd2d8, new Aspect[] {MAN, EARTH});
|
||||
public static final Aspect TOOL = new Aspect("instrumentum",0x4040ee, new Aspect[] {MAN, ORDER});
|
||||
public static final Aspect HARVEST = new Aspect("meto",0xeead82, new Aspect[] {CROP, TOOL});
|
||||
public static final Aspect WEAPON = new Aspect("telum",0xc05050, new Aspect[] {TOOL, ENTROPY});
|
||||
public static final Aspect WEAPON = new Aspect("telum",0xc05050, new Aspect[] {TOOL, FIRE});
|
||||
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});
|
||||
|
||||
@@ -84,7 +84,7 @@ public class AspectList implements Serializable {
|
||||
*/
|
||||
public Aspect[] getAspectsSorted() {
|
||||
try {
|
||||
Aspect[] out = aspects.keySet().toArray(new Aspect[1]);
|
||||
Aspect[] out = aspects.keySet().toArray(new Aspect[]{});
|
||||
boolean change=false;
|
||||
do {
|
||||
change=false;
|
||||
@@ -215,6 +215,18 @@ public class AspectList implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public AspectList add(AspectList in) {
|
||||
for (Aspect a:in.getAspects())
|
||||
this.add(a, in.getAmount(a));
|
||||
return this;
|
||||
}
|
||||
|
||||
public AspectList merge(AspectList in) {
|
||||
for (Aspect a:in.getAspects())
|
||||
this.merge(a, in.getAmount(a));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the list of aspects from nbt
|
||||
* @param nbttagcompound
|
||||
|
||||
@@ -69,13 +69,16 @@ public class InfusionRecipe
|
||||
return ii.size()==0?true:false;
|
||||
}
|
||||
|
||||
protected boolean areItemStacksEqual(ItemStack stack0, ItemStack stack1, boolean fuzzy)
|
||||
public static 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=ThaumcraftApiHelper.areItemStackTagsEqualForCrafting(stack0, stack1);
|
||||
|
||||
//nbt
|
||||
boolean t1=ThaumcraftApiHelper.areItemStackTagsEqualForCrafting(stack0, stack1);
|
||||
if (!t1) return false;
|
||||
|
||||
if (fuzzy) {
|
||||
int od = OreDictionary.getOreID(stack0);
|
||||
if (od!=-1) {
|
||||
@@ -84,7 +87,12 @@ public class InfusionRecipe
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return stack0.getItem() != stack1.getItem() ? false : (stack0.getItemDamage() != stack1.getItemDamage() ? false : stack0.stackSize <= stack0.getMaxStackSize() );
|
||||
|
||||
//damage
|
||||
boolean damage = stack0.getItemDamage() == stack1.getItemDamage() ||
|
||||
stack1.getItemDamage() == OreDictionary.WILDCARD_VALUE;
|
||||
|
||||
return stack0.getItem() != stack1.getItem() ? false : (!damage ? false : stack0.stackSize <= stack0.getMaxStackSize() );
|
||||
}
|
||||
|
||||
public Object getRecipeOutput() {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package thaumcraft.api.entities;
|
||||
|
||||
public interface IEldritchMob {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package thaumcraft.api.internal;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import thaumcraft.api.aspects.Aspect;
|
||||
import thaumcraft.api.aspects.AspectList;
|
||||
|
||||
public class DummyInternalMethodHandler implements IInternalMethodHandler {
|
||||
|
||||
@Override
|
||||
public void generateVisEffect(int dim, int x, int y, int z, int x2, int y2, int z2, int color) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResearchComplete(String username, String researchkey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDiscoveredAspect(String username, Aspect aspect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AspectList getDiscoveredAspects(String username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInRowAndColumn(Object instance, int row, int column) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AspectList getObjectAspects(ItemStack is) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AspectList getBonusObjectTags(ItemStack is, AspectList ot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AspectList generateTags(Item item, int meta) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean consumeVisFromWand(ItemStack wand, EntityPlayer player,
|
||||
AspectList cost, boolean doit, boolean crafting) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean consumeVisFromWandCrafting(ItemStack wand,
|
||||
EntityPlayer player, AspectList cost, boolean doit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean consumeVisFromInventory(EntityPlayer player, AspectList cost) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWarpToPlayer(EntityPlayer player, int amount, boolean temporary) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStickyWarpToPlayer(EntityPlayer player, int amount) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package thaumcraft.api.internal;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import thaumcraft.api.aspects.Aspect;
|
||||
import thaumcraft.api.aspects.AspectList;
|
||||
|
||||
public interface IInternalMethodHandler {
|
||||
|
||||
public void generateVisEffect(int dim, int x, int y, int z, int x2, int y2, int z2, int color);
|
||||
public boolean isResearchComplete(String username, String researchkey);
|
||||
public ItemStack getStackInRowAndColumn(Object instance, int row, int column);
|
||||
public AspectList getObjectAspects(ItemStack is);
|
||||
public AspectList getBonusObjectTags(ItemStack is,AspectList ot);
|
||||
public AspectList generateTags(Item item, int meta);
|
||||
public boolean consumeVisFromWand(ItemStack wand, EntityPlayer player, AspectList cost, boolean doit, boolean crafting);
|
||||
public boolean consumeVisFromWandCrafting(ItemStack wand,EntityPlayer player, AspectList cost, boolean doit);
|
||||
public boolean consumeVisFromInventory(EntityPlayer player, AspectList cost);
|
||||
public void addWarpToPlayer(EntityPlayer player, int amount,boolean temporary);
|
||||
public void addStickyWarpToPlayer(EntityPlayer player, int amount);
|
||||
public boolean hasDiscoveredAspect(String username, Aspect aspect);
|
||||
public AspectList getDiscoveredAspects(String username);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package thaumcraft.api.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.WeightedRandom;
|
||||
|
||||
|
||||
public class WeightedRandomLoot extends WeightedRandom.Item {
|
||||
|
||||
/** The Item/Block ID to generate in the bag. */
|
||||
public ItemStack item;
|
||||
|
||||
public WeightedRandomLoot(ItemStack stack, int weight)
|
||||
{
|
||||
super(weight);
|
||||
this.item = stack;
|
||||
}
|
||||
|
||||
public static ArrayList<WeightedRandomLoot> lootBagCommon = new ArrayList<WeightedRandomLoot>();
|
||||
public static ArrayList<WeightedRandomLoot> lootBagUncommon = new ArrayList<WeightedRandomLoot>();
|
||||
public static ArrayList<WeightedRandomLoot> lootBagRare = new ArrayList<WeightedRandomLoot>();
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
@API(owner = "Thaumcraft", apiVersion = "4.2.0.0", provides = "Thaumcraft|API")
|
||||
@API(owner = "Thaumcraft", apiVersion = "4.2.2.0", provides = "Thaumcraft|API")
|
||||
package thaumcraft.api;
|
||||
|
||||
import cpw.mods.fml.common.API;
|
||||
@@ -91,8 +91,7 @@ public class ResearchItem
|
||||
*/
|
||||
private boolean isVirtual;
|
||||
|
||||
@Deprecated
|
||||
private boolean isLost;
|
||||
|
||||
|
||||
/**
|
||||
* Concealed research does not display in the thaumonomicon until parent researches are discovered.
|
||||
@@ -104,6 +103,11 @@ public class ResearchItem
|
||||
*/
|
||||
private boolean isHidden;
|
||||
|
||||
/**
|
||||
* This is the same as isHidden, except it cannot be discovered with knowledge fragments, only scanning.
|
||||
*/
|
||||
private boolean isLost;
|
||||
|
||||
/**
|
||||
* These research items will automatically unlock for all players on game start
|
||||
*/
|
||||
@@ -179,7 +183,6 @@ public class ResearchItem
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ResearchItem setLost()
|
||||
{
|
||||
this.isLost = true;
|
||||
@@ -290,7 +293,6 @@ public class ResearchItem
|
||||
return this.isStub;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean isLost()
|
||||
{
|
||||
return this.isLost;
|
||||
|
||||
@@ -136,7 +136,7 @@ public abstract class TileVisNode extends TileThaumcraft {
|
||||
//check for changes
|
||||
if (!nodeRefresh && children.size()>0) {
|
||||
for (WeakReference<TileVisNode> n:children) {
|
||||
if (n==null || n.get()==null) {
|
||||
if (n==null || n.get()==null || !VisNetHandler.canNodeBeSeen(this, n.get())) {
|
||||
nodeRefresh=true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package thaumcraft.api.visnet;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.MovingObjectPosition.MovingObjectType;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.World;
|
||||
import thaumcraft.api.ThaumcraftApi;
|
||||
import thaumcraft.api.ThaumcraftApiHelper;
|
||||
import thaumcraft.api.WorldCoordinates;
|
||||
import thaumcraft.api.aspects.Aspect;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
|
||||
public class VisNetHandler {
|
||||
|
||||
@@ -59,17 +62,8 @@ public class VisNetHandler {
|
||||
return drainedAmount;
|
||||
}
|
||||
|
||||
static Method generateVisEffect;
|
||||
public static void generateVisEffect(int dim, int x, int y, int z, int x2, int y2, int z2, int color) {
|
||||
try {
|
||||
if(generateVisEffect == null) {
|
||||
Class fake = Class.forName("thaumcraft.common.lib.Utils");
|
||||
generateVisEffect = fake.getMethod("generateVisEffect", int.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class);
|
||||
}
|
||||
generateVisEffect.invoke(null, dim, x,y,z,x2,y2,z2,color);
|
||||
} catch(Exception ex) {
|
||||
FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.Utils method generateVisEffect");
|
||||
}
|
||||
ThaumcraftApi.internalMethods.generateVisEffect(dim, x, y, z, x2, y2, z2, color);
|
||||
}
|
||||
|
||||
public static HashMap<Integer, HashMap<WorldCoordinates, WeakReference<TileVisNode>>> sources = new HashMap<Integer, HashMap<WorldCoordinates, WeakReference<TileVisNode>>>();
|
||||
@@ -114,17 +108,21 @@ public class VisNetHandler {
|
||||
if (r > 0) {
|
||||
nearby.add(new Object[] { source, r - vn.getRange() * 2 });
|
||||
}
|
||||
|
||||
nearby = findClosestNodes(vn, source, nearby);
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
float dist = Float.MAX_VALUE;
|
||||
TileVisNode closest = null;
|
||||
if (nearby.size() > 0) {
|
||||
for (Object[] o : nearby) {
|
||||
if ((Float) o[1] < dist) {// && canNodeBeSeen(vn,(TileVisNode)
|
||||
// o[0])) {
|
||||
if ((Float) o[1] < dist &&
|
||||
(vn.getAttunement() == -1 || ((TileVisNode) o[0]).getAttunement() == -1 ||
|
||||
vn.getAttunement() == ((TileVisNode) o[0]).getAttunement())//) {
|
||||
&& canNodeBeSeen(vn,(TileVisNode)o[0])) {
|
||||
dist = (Float) o[1];
|
||||
closest = (TileVisNode) o[0];
|
||||
closest = (TileVisNode) o[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,26 +135,24 @@ public class VisNetHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
static ArrayList<WorldCoordinates> cache = new ArrayList<WorldCoordinates>();
|
||||
public static ArrayList<Object[]> findClosestNodes(TileVisNode target,
|
||||
TileVisNode root, ArrayList<Object[]> in) {
|
||||
TileVisNode closestChild = null;
|
||||
TileVisNode parent, ArrayList<Object[]> in) {
|
||||
|
||||
if (cache.size() > 512 || cache.contains(new WorldCoordinates(parent))) return in;
|
||||
cache.add(new WorldCoordinates(parent));
|
||||
|
||||
for (WeakReference<TileVisNode> childWR : parent.getChildren()) {
|
||||
TileVisNode child = childWR.get();
|
||||
|
||||
for (WeakReference<TileVisNode> child : root.getChildren()) {
|
||||
TileVisNode n = child.get();
|
||||
|
||||
if (n != null
|
||||
&& !n.equals(target)
|
||||
&& !n.equals(root)
|
||||
&& (target.getAttunement() == -1 || n.getAttunement() == -1 || n
|
||||
.getAttunement() == target.getAttunement())) {
|
||||
|
||||
float r2 = inRange(n.getWorldObj(), n.getLocation(),
|
||||
if (child != null && !child.equals(target) && !child.equals(parent)) {
|
||||
float r2 = inRange(child.getWorldObj(), child.getLocation(),
|
||||
target.getLocation(), target.getRange());
|
||||
if (r2 > 0) {
|
||||
in.add(new Object[] { n, r2 });
|
||||
in.add(new Object[] { child, r2 });
|
||||
}
|
||||
|
||||
in = findClosestNodes(target, n, in);
|
||||
|
||||
in = findClosestNodes(target, child, in);
|
||||
}
|
||||
}
|
||||
return in;
|
||||
@@ -238,20 +234,15 @@ public class VisNetHandler {
|
||||
return list;
|
||||
}
|
||||
|
||||
// public static boolean canNodeBeSeen(TileVisNode source,TileVisNode
|
||||
// target)
|
||||
// {
|
||||
// double d = Math.sqrt(source.getDistanceFrom(target.xCoord, target.yCoord,
|
||||
// target.zCoord));
|
||||
// double xd = (source.xCoord-target.xCoord) / d;
|
||||
// double yd = (source.yCoord-target.yCoord) / d;
|
||||
// double zd = (source.zCoord-target.zCoord) / d;
|
||||
// return source.getWorldObj().rayTraceBlocks(
|
||||
// Vec3.createVectorHelper(source.xCoord-xd+.5+.5, source.yCoord-yd,
|
||||
// source.zCoord-zd),
|
||||
// Vec3.createVectorHelper(target.xCoord+.5, target.yCoord+.5,
|
||||
// target.zCoord+.5)) == null;
|
||||
// }
|
||||
public static boolean canNodeBeSeen(TileVisNode source,TileVisNode target)
|
||||
{
|
||||
MovingObjectPosition mop = ThaumcraftApiHelper.rayTraceIgnoringSource(source.getWorldObj(),
|
||||
Vec3.createVectorHelper(source.xCoord+.5, source.yCoord+.5,source.zCoord+.5),
|
||||
Vec3.createVectorHelper(target.xCoord+.5, target.yCoord+.5,target.zCoord+.5),
|
||||
false, true, false);
|
||||
return mop == null || (mop.typeOfHit==MovingObjectType.BLOCK &&
|
||||
mop.blockX==target.xCoord && mop.blockY==target.yCoord && mop.blockZ==target.zCoord);
|
||||
}
|
||||
|
||||
// public static HashMap<WorldCoordinates,WeakReference<TileVisNode>>
|
||||
// noderef = new HashMap<WorldCoordinates,WeakReference<TileVisNode>>();
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package thaumcraft.api.wands;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.StatCollector;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import thaumcraft.api.aspects.Aspect;
|
||||
import thaumcraft.api.aspects.AspectList;
|
||||
|
||||
public class FocusUpgradeType {
|
||||
|
||||
public static FocusUpgradeType[] types = new FocusUpgradeType[20];
|
||||
|
||||
public short id;
|
||||
|
||||
public ResourceLocation icon;
|
||||
|
||||
public String name;
|
||||
|
||||
public String text;
|
||||
|
||||
/**
|
||||
* What aspects are used to calculate the cost of this upgrade. The amounts given is ignored, just the type is used for the calculation.
|
||||
*/
|
||||
public AspectList aspects;
|
||||
|
||||
|
||||
|
||||
public FocusUpgradeType(int id, ResourceLocation icon, String name, String text, AspectList aspects) {
|
||||
this.id = (short) id;
|
||||
this.icon = icon;
|
||||
this.name = name;
|
||||
this.text = text;
|
||||
this.aspects = aspects;
|
||||
|
||||
if (id<types.length && types[id]!=null) {
|
||||
LogManager.getLogger("THAUMCRAFT").fatal("Focus Upgrade id "+id+" already occupied. Ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
// allocate space
|
||||
if (id>=types.length) {
|
||||
FocusUpgradeType[] temp = new FocusUpgradeType[id+1];
|
||||
System.arraycopy(types, 0, temp, 0, id);
|
||||
types = temp;
|
||||
}
|
||||
|
||||
types[id] = this;
|
||||
}
|
||||
|
||||
public String getLocalizedName() {
|
||||
return StatCollector.translateToLocal(name);
|
||||
}
|
||||
|
||||
public String getLocalizedText() {
|
||||
return StatCollector.translateToLocal(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof FocusUpgradeType) {
|
||||
return this.id == ((FocusUpgradeType)obj).id;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
// basic upgrade types
|
||||
public static FocusUpgradeType potency = new FocusUpgradeType( 0,
|
||||
new ResourceLocation("thaumcraft", "textures/foci/potency.png"),
|
||||
"focus.upgrade.potency.name","focus.upgrade.potency.text",
|
||||
new AspectList().add(Aspect.WEAPON,1));
|
||||
|
||||
public static FocusUpgradeType frugal = new FocusUpgradeType( 1,
|
||||
new ResourceLocation("thaumcraft", "textures/foci/frugal.png"),
|
||||
"focus.upgrade.frugal.name","focus.upgrade.frugal.text",
|
||||
new AspectList().add(Aspect.HUNGER,1));
|
||||
|
||||
public static FocusUpgradeType treasure = new FocusUpgradeType( 2,
|
||||
new ResourceLocation("thaumcraft", "textures/foci/treasure.png"),
|
||||
"focus.upgrade.treasure.name","focus.upgrade.treasure.text",
|
||||
new AspectList().add(Aspect.GREED,1));
|
||||
|
||||
public static FocusUpgradeType enlarge = new FocusUpgradeType( 3,
|
||||
new ResourceLocation("thaumcraft", "textures/foci/enlarge.png"),
|
||||
"focus.upgrade.enlarge.name","focus.upgrade.enlarge.text",
|
||||
new AspectList().add(Aspect.TRAVEL,1));
|
||||
|
||||
public static FocusUpgradeType alchemistsfire = new FocusUpgradeType( 4,
|
||||
new ResourceLocation("thaumcraft", "textures/foci/alchemistsfire.png"),
|
||||
"focus.upgrade.alchemistsfire.name","focus.upgrade.alchemistsfire.text",
|
||||
new AspectList().add(Aspect.ENERGY,1).add(Aspect.SLIME,1));
|
||||
|
||||
public static FocusUpgradeType alchemistsfrost = new FocusUpgradeType( 5,
|
||||
new ResourceLocation("thaumcraft", "textures/foci/alchemistsfrost.png"),
|
||||
"focus.upgrade.alchemistsfrost.name","focus.upgrade.alchemistsfrost.text",
|
||||
new AspectList().add(Aspect.COLD,1).add(Aspect.TRAP,1));
|
||||
|
||||
public static FocusUpgradeType architect = new FocusUpgradeType( 6,
|
||||
new ResourceLocation("thaumcraft", "textures/foci/architect.png"),
|
||||
"focus.upgrade.architect.name","focus.upgrade.architect.text",
|
||||
new AspectList().add(Aspect.CRAFT,1));
|
||||
|
||||
public static FocusUpgradeType extend = new FocusUpgradeType( 7,
|
||||
new ResourceLocation("thaumcraft", "textures/foci/extend.png"),
|
||||
"focus.upgrade.extend.name","focus.upgrade.extend.text",
|
||||
new AspectList().add(Aspect.EXCHANGE,1));
|
||||
|
||||
public static FocusUpgradeType silktouch = new FocusUpgradeType( 8,
|
||||
new ResourceLocation("thaumcraft", "textures/foci/silktouch.png"),
|
||||
"focus.upgrade.silktouch.name","focus.upgrade.silktouch.text",
|
||||
new AspectList().add(Aspect.GREED,1));
|
||||
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package thaumcraft.api.wands;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IIcon;
|
||||
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".
|
||||
*/
|
||||
IIcon getFocusDepthLayerIcon();
|
||||
|
||||
public IIcon 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);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,25 +1,26 @@
|
||||
package thaumcraft.api.wands;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.LinkedHashMap;
|
||||
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.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IIcon;
|
||||
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 abstract class ItemFocusBasic extends Item {
|
||||
|
||||
public ItemFocusBasic ()
|
||||
{
|
||||
@@ -37,130 +38,222 @@ public class ItemFocusBasic extends Item implements IWandFocus {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemTool(ItemStack par1ItemStack)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDamageable() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInformation(ItemStack stack,EntityPlayer player, List list, boolean par4) {
|
||||
AspectList al = this.getVisCost();
|
||||
AspectList al = this.getVisCost(stack);
|
||||
if (al!=null && al.size()>0) {
|
||||
list.add(StatCollector.translateToLocal(isVisCostPerTick()?"item.Focus.cost2":"item.Focus.cost1"));
|
||||
list.add(StatCollector.translateToLocal(isVisCostPerTick(stack)?"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);
|
||||
|
||||
list.add(" \u00A7"+aspect.getChatcolor()+aspect.getName()+"\u00A7r x "+ amount);
|
||||
}
|
||||
}
|
||||
addFocusInformation(stack,player,list,par4);
|
||||
}
|
||||
|
||||
public void addFocusInformation(ItemStack focusstack,EntityPlayer player, List list, boolean par4) {
|
||||
LinkedHashMap<Short, Integer> map = new LinkedHashMap<Short, Integer>();
|
||||
for (short id:this.getAppliedUpgrades(focusstack)) {
|
||||
if (id>=0) {
|
||||
int amt = 1;
|
||||
if (map.containsKey(id)) {
|
||||
amt = map.get(id) + 1;
|
||||
}
|
||||
map.put(id, amt);
|
||||
}
|
||||
}
|
||||
for (Short id:map.keySet()) {
|
||||
list.add(EnumChatFormatting.DARK_PURPLE +FocusUpgradeType.types[id].getLocalizedName()+
|
||||
(map.get(id)>1?" "+StatCollector.translateToLocal("enchantment.level." + map.get(id)):""));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemEnchantability() {
|
||||
return 5;
|
||||
/**
|
||||
* Purely for display on the focus tooltip (see addInformation method above)
|
||||
*/
|
||||
public boolean isVisCostPerTick(ItemStack focusstack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EnumRarity getRarity(ItemStack itemstack)
|
||||
public EnumRarity getRarity(ItemStack focusstack)
|
||||
{
|
||||
return EnumRarity.rare;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* What color will the focus orb be rendered on the held wand
|
||||
*/
|
||||
public abstract int getFocusColor(ItemStack focusstack);
|
||||
|
||||
|
||||
@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) {
|
||||
/**
|
||||
* Does the focus have ornamentation like the focus of the nine hells. Ornamentation is a standard icon rendered in a cross around the focus
|
||||
*/
|
||||
public IIcon getOrnament(ItemStack focusstack) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsingFocusTick(ItemStack itemstack, EntityPlayer player,
|
||||
int count) {
|
||||
// TODO Auto-generated method stub
|
||||
/**
|
||||
* An icon to be rendered inside the focus itself
|
||||
*/
|
||||
public IIcon getFocusDepthLayerIcon(ItemStack focusstack) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerStoppedUsingFocus(ItemStack itemstack, World world,
|
||||
EntityPlayer player, int count) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
public enum WandFocusAnimation {
|
||||
WAVE, CHARGE;
|
||||
}
|
||||
|
||||
public WandFocusAnimation getAnimation(ItemStack focusstack) {
|
||||
return WandFocusAnimation.WAVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
public String getSortingHelper(ItemStack focusstack) {
|
||||
String out="";
|
||||
for (Integer lvl:ench.values()) {
|
||||
out = out + lvl + "";
|
||||
for (short id:this.getAppliedUpgrades(focusstack)) {
|
||||
out = out + id;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* How much vis does this focus consume per activation.
|
||||
*/
|
||||
public abstract AspectList getVisCost(ItemStack focusstack);
|
||||
|
||||
/**
|
||||
* This returns how many milliseconds must pass before the focus can be activated again.
|
||||
*/
|
||||
public int getActivationCooldown(ItemStack focusstack) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by foci like equal trade to determine their area in artchitect mode
|
||||
*/
|
||||
public int getMaxAreaSize(ItemStack focusstack) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* What upgrades can be applied to this focus for ranks 1 to 5
|
||||
*/
|
||||
public abstract FocusUpgradeType[] getPossibleUpgradesByRank(ItemStack focusstack, int rank);
|
||||
|
||||
/**
|
||||
* What upgrades does the focus currently have
|
||||
*/
|
||||
public short[] getAppliedUpgrades(ItemStack focusstack) {
|
||||
short[] l = new short[] {-1,-1,-1,-1,-1};
|
||||
NBTTagList nbttaglist = getFocusUpgradeTagList(focusstack);
|
||||
if (nbttaglist == null)
|
||||
{
|
||||
return l;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < nbttaglist.tagCount(); ++j)
|
||||
{
|
||||
if (j>=5) break;
|
||||
l[j] = nbttaglist.getCompoundTagAt(j).getShort("id");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisCostPerTick() {
|
||||
return false;
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean applyUpgrade(ItemStack focusstack, FocusUpgradeType type, int rank) {
|
||||
short[] upgrades = getAppliedUpgrades(focusstack);
|
||||
if (upgrades[rank-1]!=-1 || rank<1 || rank>5) {
|
||||
return false;
|
||||
}
|
||||
upgrades[rank-1] = type.id;
|
||||
setFocusUpgradeTagList(focusstack, upgrades);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to define custom logic about which upgrades can be applied. This can be used to set up upgrade "trees"
|
||||
* that make certain upgrades available only when others are unlocked first, when certain research is completed, or similar logic.
|
||||
*
|
||||
*/
|
||||
public boolean canApplyUpgrade(ItemStack focusstack, EntityPlayer player, FocusUpgradeType type, int rank) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIcon getOrnament() {
|
||||
/**
|
||||
* Does this focus have the passed upgrade type
|
||||
*/
|
||||
public boolean isUpgradedWith(ItemStack focusstack, FocusUpgradeType focusUpgradetype) {
|
||||
return getUpgradeLevel(focusstack,focusUpgradetype)>0;
|
||||
}
|
||||
|
||||
/**
|
||||
* What level is the passed upgrade type on the focus. If it is not present it returns 0
|
||||
*/
|
||||
public int getUpgradeLevel(ItemStack focusstack, FocusUpgradeType focusUpgradetype) {
|
||||
short[] list = getAppliedUpgrades(focusstack);
|
||||
int level=0;
|
||||
for (short id:list) {
|
||||
if (id == focusUpgradetype.id)
|
||||
{
|
||||
level++;
|
||||
}
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
public ItemStack onFocusRightClick(ItemStack wandstack, World world,EntityPlayer player, MovingObjectPosition movingobjectposition) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFocusBlockStartBreak(ItemStack itemstack, int x, int y,
|
||||
int z, EntityPlayer player) {
|
||||
|
||||
public void onUsingFocusTick(ItemStack wandstack, EntityPlayer player,int count) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public void onPlayerStoppedUsingFocus(ItemStack wandstack, World world, EntityPlayer player, int count) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public boolean onFocusBlockStartBreak(ItemStack wandstack, int x, int y,int z, EntityPlayer player) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WandFocusAnimation getAnimation() {
|
||||
return WandFocusAnimation.WAVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIcon getFocusDepthLayerIcon() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal helper methods
|
||||
*/
|
||||
private NBTTagList getFocusUpgradeTagList(ItemStack focusstack)
|
||||
{
|
||||
return focusstack.stackTagCompound == null ? null : focusstack.stackTagCompound.getTagList("upgrade", 10);
|
||||
}
|
||||
|
||||
private void setFocusUpgradeTagList(ItemStack focusstack, short[] upgrades) {
|
||||
if (!focusstack.hasTagCompound())
|
||||
focusstack.setTagCompound(new NBTTagCompound());
|
||||
NBTTagCompound nbttagcompound = focusstack.getTagCompound();
|
||||
NBTTagList tlist = new NBTTagList();
|
||||
nbttagcompound.setTag("upgrade", tlist);
|
||||
for (short id : upgrades) {
|
||||
NBTTagCompound f = new NBTTagCompound();
|
||||
f.setShort("id", id);
|
||||
tlist.appendTag(f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user