@Mod(modid=UniqueCrops.MOD_ID, name=UniqueCrops.MOD_NAME, version=UniqueCrops.VERSION)
public class UniqueCrops {

	public static final String MOD_ID = "uniquecrops";
	public static final String MOD_NAME = "Unique Crops";
	public static final String VERSION = "0.2.02";
	
	@SidedProxy(clientSide="com.bafomdad.uniquecrops.proxies.ClientProxy", serverSide="com.bafomdad.uniquecrops.proxies.CommonProxy")
	public static CommonProxy proxy;
	
	@Mod.Instance(MOD_ID)
	public static UniqueCrops instance;
	
	public static UCTab TAB = new UCTab();
	public static UCConfig config;
	
	public static boolean baublesLoaded = Loader.isModLoaded("Baubles");
	
	@Mod.EventHandler
	public void preInit(FMLPreInitializationEvent event) {
		
		config = new UCConfig();
		config.loadConfig(event);
		
		proxy.preInit(event);
		proxy.initAllModels();
		proxy.checkResource();
		NetworkRegistry.INSTANCE.registerGuiHandler(instance, new GuiHandler());
	}
	
	@Mod.EventHandler
	public void init(FMLInitializationEvent event) {
		
		proxy.init(event);
	}
	
	@Mod.EventHandler
	public void postInit(FMLPostInitializationEvent event) {
		
		proxy.postInit(event);
	}
} public class TileMusicaPlant extends TileBaseUC implements ITickable {
	
	private List<Beat> beats = new ArrayList<Beat>();
	private long lastBeat = 0L;
	private int musicStrength;

	@Override
	public void update() {

		IBlockState state = worldObj.getBlockState(getPos());
		if (state == null || (state != null && state.getBlock() != UCBlocks.cropMusica))
			return;
		
		if (getBlockType() != null && !((Musica)getBlockType()).canDance(state))
			return;
		
		if (this.worldObj.isRemote || (beats.isEmpty() || beats.size() == 0))
			return;
		
		for (int i = 0; i < beats.size(); i++) {
			Beat beat = beats.get(i);
			listenAndRemove(beat, i);
			
			List<Integer> timelist = new ArrayList<Integer>();

			int elapsedtime = (int)beat.getTimeElapsed(worldObj.getTotalWorldTime(), beat.getTime());
			if (beat.getTime() != lastBeat && elapsedtime % 2 == 0 /*&& (lastBeat - elapsedtime) % 2 == 0*/)
				timelist.add(elapsedtime);

			if (!timelist.isEmpty() && !beats.isEmpty()) {
				if (worldObj.getTotalWorldTime() % 10 == 0 && lastBeat > 0) {
					int randomtick = (worldObj.rand.nextInt(100) + 5) - timelist.size();
					if (randomtick < this.getPercussion().getTimeElapsed(worldObj.getTotalWorldTime(), lastBeat)) {
						
						((Musica)this.blockType).addAge(worldObj, getPos(), state, 1);
						return;
					}
				}
			}
		}
		if (lastBeat == 0L && this.getPercussion() != null)
			lastBeat = this.getPercussion().getTime();
	}
	
	@Override
	public void readCustomNBT(NBTTagCompound tag) {
		
		NBTTagList taglist = tag.getTagList(UCStrings.TAG_BEATLIST, 10);
		for (int i = 0; i < taglist.tagCount(); i++) {
			NBTTagCompound tag2 = taglist.getCompoundTagAt(i);
			Note tagnote = Note.values()[tag2.getInteger(UCStrings.TAG_NOTE)];
			Instrument taginst = Instrument.values()[tag2.getInteger(UCStrings.TAG_INST)];
			Octave tagoct = Octave.values()[tag2.getInteger(UCStrings.TAG_OCT)];
			long tagtime = tag2.getLong(UCStrings.TAG_TIME);
			this.setNote(tagnote, taginst, tagoct, tagtime);
		}
	}
	
	@Override
	public void writeCustomNBT(NBTTagCompound tag) {
		
		if (!beats.isEmpty() || beats.size() > 0)
		{
			NBTTagList taglist = new NBTTagList();
			for (int i = 0; i < beats.size(); i++) {
				Beat beat = beats.get(i);
				NBTTagCompound tag2 = new NBTTagCompound();
				tag2.setInteger(UCStrings.TAG_NOTE, beat.note);
				tag2.setInteger(UCStrings.TAG_INST, beat.instrument);
				tag2.setInteger(UCStrings.TAG_OCT, beat.octave);
				tag2.setLong(UCStrings.TAG_TIME, beat.worldtime);
				taglist.appendTag(tag2);
			}
			tag.setTag(UCStrings.TAG_BEATLIST, taglist);
		}
	}
	
	public List<Beat> getBeats() {
		
		return beats;
	}
	
	public boolean canAddNote() {
		
		return this.beats.size() < 12;
	}
	
	public Beat setNote(Note note, Instrument instrument, Octave octave, long time) {
		
		Beat beat = new Beat(note, instrument, octave, time);
		beats.add(beat);
		return beat;
	}
	
	public Beat setNewBeatTime(int index, long newtime) {
		
		Beat beat = beats.get(index);
		beat.worldtime = newtime;
		return beat;
	}
	
	public void clearBeats() {
		
		beats.clear();
	}
	
	public void listenAndRemove(Beat beat, int index) {
		
		long diff = beat.getTimeElapsed(worldObj.getTotalWorldTime(), beat.getTime());
		if (diff > 50) {
			if (beat.getTime() == lastBeat)
				lastBeat = 0L;
			beats.remove(index);
		}
	}
	
	public boolean isPercussion(Instrument instrument) {
		
		return instrument == Instrument.SNARE || instrument == Instrument.BASSDRUM;
	}
	
	public Beat getPercussion() {
		
		for (Beat beat : beats) {
			if (isPercussion(beat.getInstrument()))
				return beat;
		}
		return null;
	}
	
	public static class Beat {
		
		int note, instrument, octave;
		long worldtime;
		
		public Beat(Note note, Instrument instrument, Octave octave, long worldtime) {
			
			this.note = note.ordinal();
			this.instrument = instrument.ordinal();
			this.octave = octave.ordinal();
			this.worldtime = worldtime;
		}
		
		public Note getNote() {
			
			return Note.values()[note];
		}
		
		public Instrument getInstrument() {
			
			return Instrument.values()[instrument];
		}
		
		public Octave getOctave() {
			
			return Octave.values()[octave];
		}
		
		public long getTime() {
			
			return worldtime;
		}
		
		public long getTimeElapsed(long newtime, long oldtime) {
			
			if (newtime < oldtime)
				return (oldtime - newtime);
			
			return (newtime - oldtime);
		}
		
		public boolean beatMatches(Beat newbeat) {
			
			return getNote().equals(newbeat.getNote()) && getInstrument().equals(newbeat.getInstrument()) && getOctave().equals(newbeat.getOctave());
		}
		
		@Override
		public String toString() {
			
			return "[Note: " + getNote() + " / Instrument: " + getInstrument() + " / Octave: " + getOctave() + " / Time: " + getTime() + "]";
		}
	}
	
	public static enum BPM {
		
		EMPTY(0, 0),
		LARGO(40, 60),
		ADAGIO(66, 76),
		MODERATO(108, 120),
		PRESTO(168, 200);
		
		int minRange;
		int maxRange;
		
		private BPM(int min, int max) {
			
			this.minRange = min;
			this.maxRange = max;
		}
		
		public static BPM getType(int time) {
			
			for (BPM e : values()) {
				if (matches(e, time))
					return e;
			}
			return EMPTY;
		}
		
		private static boolean matches(BPM bpm, int time) {
			
			return bpm.minRange < time && time > bpm.maxRange;
		}
	}
} public static class Beat {
		
	int note, instrument, octave;
	long worldtime;
		
	public Beat(Note note, Instrument instrument, Octave octave, long worldtime) {
			
		this.note = note.ordinal();
		this.instrument = instrument.ordinal();
		this.octave = octave.ordinal();
		this.worldtime = worldtime;
	}
		
	public Note getNote() {
			
		return Note.values()[note];
	}
		
	public Instrument getInstrument() {
			
		return Instrument.values()[instrument];
	}
		
	public Octave getOctave() {
			
		return Octave.values()[octave];
	}
		
	public long getTime() {
			
		return worldtime;
	}
		
	public long getTimeElapsed(long newtime, long oldtime) {
			
		if (newtime < oldtime)
			return (oldtime - newtime);
			
		return (newtime - oldtime);
	}
		
	public boolean beatMatches(Beat newbeat) {
			
		return getNote().equals(newbeat.getNote()) && getInstrument().equals(newbeat.getInstrument()) && getOctave().equals(newbeat.getOctave());
	}
		
	@Override
	public String toString() {
			
		return "[Note: " + getNote() + " / Instrument: " + getInstrument() + " / Octave: " + getOctave() + " / Time: " + getTime() + "]";
	}
} public enum EnumItems implements IStringSerializable {
	
	GUIDE("guidebook"),
	DISCOUNT("discountbook"),
	PLUM("dirigibleplum"),
	CINDERLEAF("cinderleaf"),
	TIMEDUST("timedust"),
	LILYTWINE("lilytwine"),
	GOLDENRODS("goldenrods"),
	PRENUGGET("prenugget"),
	PREGEM("pregem"),
	ESSENCE("essence"),
	TIMEMEAL("timemeal"),
	INVISITWINE("invisitwine"),
	INVISIFEATHER("invisifeather"),
	POTIONSPLASH("potionreversesplash"),
	SLIPPER("slipperglass"),
	WEEPINGTEAR("weepingtear"),
	WEEPINGEYE("weepingeye"),
	MILLENNIUMEYE("millenniumeye"),
	UPGRADE("upgradebook"),
	EGGUPGRADE("eggupgrade"),
	EASYBADGE("easybadge"),
	DOGRESIDUE("dogresidue"),
	ABSTRACT("abstract"),
	LEGALSTUFF("legalstuff"),
	EULA("eulabook"),
	DUMMYITEM("dummy"),
	PIXELS("pixels");

	final String name;
	
	EnumItems(String name) {
		
		this.name = name;
	}
	
	@Override
	public String getName() {

		return name;
	}
} public class GrowthSteps {
	
	private String desc;
	private Condition cond;
	private int index;
	private static Random rand = new Random();
	public static String TAG_GROWTHSTAGES = "UC_FeroxiaGrowth";

	public GrowthSteps(String desc, Condition cond, int index) {
		
		this.desc = desc;
		this.cond = cond;
		this.index = index;
	}
	
	public String getDescription() {
		
		return desc;
	}
	
	public Condition getCondition() {
		
		return cond;
	}
	
	public int getIndex() {
		
		return index;
	}
	
	public static void generateSteps(EntityPlayer player) {
		
		NBTTagCompound tag = player.getEntityData();
		if (rand.nextInt(200) == 0) {
			if (tag.hasKey(TAG_GROWTHSTAGES))
				tag.removeTag(TAG_GROWTHSTAGES);
			
			NBTTagList taglist = new NBTTagList();
			NBTTagCompound tag2 = new NBTTagCompound();
			tag2.setInteger("stage0", 19);
			taglist.appendTag(tag2);
			tag.setTag(TAG_GROWTHSTAGES, taglist);
			return;
		}
		List<GrowthSteps> copysteps = new ArrayList<GrowthSteps>();
		for (int k = 0; k < Feroxia.steps.size(); k++) {
			copysteps.add(Feroxia.steps.get(k));
		}
		copysteps.remove(copysteps.size() - 1);
		NBTTagList taglist = new NBTTagList();
		for (int i = 0; i < 7; ++i) {
			NBTTagCompound tag2 = new NBTTagCompound();
			Collections.shuffle(copysteps);
			int index = copysteps.get(0).getIndex();
			copysteps.remove(0);
			tag2.setInteger("stage" + i, index);
			taglist.appendTag(tag2);
		}
		tag.setTag(TAG_GROWTHSTAGES, taglist);
		UCUtils.updateBook(player);
	}
	
	public static TileFeroxia getTile(World world, BlockPos pos) {
		
		TileEntity tile = world.getTileEntity(pos);
		if (tile != null && tile instanceof TileFeroxia)
			return (TileFeroxia)tile;
		
		return null;
	}
	
	public static interface Condition {
		
		public boolean canAdvance(World world, BlockPos pos, IBlockState state);
	}
	
	public static class MoonPhase implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {
			
			return world.getCurrentMoonPhaseFactor() == 1.0F;
		}
	}
	
	public static class HasTorch implements Condition {
		
		int range = 10;

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			if (getTile(world, pos) == null)
				return false;
			
			List<EntityPlayer> players = world.getEntitiesWithinAABB(EntityPlayer.class, new AxisAlignedBB(pos.add(-range, -range, -range), pos.add(range, range, range)));
			for (EntityPlayer player : players) {
				if (player.getUniqueID().equals(getTile(world, pos).getOwner())) {
					ItemStack hand = player.getHeldItemMainhand();
					ItemStack offhand = player.getHeldItemOffhand();
					if ((hand != null && hand.getItem() == Item.getItemFromBlock(Blocks.TORCH)) || (offhand != null && offhand.getItem() == Item.getItemFromBlock(Blocks.TORCH)))
						return true;
				}
			}
			return false;
		}
	}
	
	public static class LikesDarkness implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			return world.getLightFromNeighbors(pos.up()) < 3 && world.isAirBlock(pos.up());
		}
	}
	
	public static class DryFarmland implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			return world.getBlockState(pos.down()).getBlock() == Blocks.FARMLAND && ((BlockFarmland)world.getBlockState(pos.down()).getBlock()).getMetaFromState(world.getBlockState(pos.down())) == 0;
		}
	}
	
	public static class UnderFarmland implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			return world.getBlockState(pos.up()).getBlock() == Blocks.FARMLAND;
		}
	}
	
	public static class BurningPlayer implements Condition {

		int range = 10;
		
		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			if (getTile(world, pos) == null)
				return false;
			
			List<EntityPlayer> players = world.getEntitiesWithinAABB(EntityPlayer.class, new AxisAlignedBB(pos.add(-range, -range, -range), pos.add(range, range, range)));
			for (EntityPlayer player : players) {
				if (player.getUniqueID().equals(getTile(world, pos).getOwner())) {
					if (player.isBurning() && !player.isImmuneToFire())
						return true;
				}
			}
			return false;
		}
	}
	
	public static class HellWorld implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			return world.provider.getDimension() == -1;
		}
	}
	
	public static class LikesHeights implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			return pos.getY() > 100;
		}
	}
	
	public static class LikesLilypads implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			int lilypads = 0;
			for (EnumFacing facing : EnumFacing.HORIZONTALS) {
				Block lilypad = world.getBlockState(pos.offset(facing)).getBlock();
				if (lilypad != null && (lilypad == Blocks.WATERLILY || lilypad == UCBlocks.lavalily))
					lilypads++;
			}
			return lilypads >= 4;
		}
	}
	
	public static class ThirstyPlant implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			List<EntityItem> items = world.getEntitiesWithinAABB(EntityItem.class, new AxisAlignedBB(pos, pos.add(1, 1, 1)));
			for (EntityItem item : items) {
				if (!item.isDead && item.getEntityItem() != null) {
					if (item.getEntityItem().getItem() == Items.WATER_BUCKET)
					{
						UCPacketHandler.sendToNearbyPlayers(world, pos, new PacketUCEffect(EnumParticleTypes.WATER_DROP, pos.getX(), pos.getY(), pos.getZ(), 6));
						item.setEntityItemStack(new ItemStack(Items.BUCKET, 1, 0));
						return true;
					}
				}
			}
			return false;
		}
	}
	
	public static class HungryPlant implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			List<EntityItem> items = world.getEntitiesWithinAABB(EntityItem.class, new AxisAlignedBB(pos, pos.add(1, 1, 1)));
			for (EntityItem item : items) {
				if (!item.isDead && item.getEntityItem() != null) {
					if (item.getEntityItem().getItem() instanceof ItemFood)
					{
						UCPacketHandler.sendToNearbyPlayers(world, pos, new PacketUCEffect(EnumParticleTypes.CLOUD, pos.getX(), pos.getY(), pos.getZ(), 6));
						item.getEntityItem().stackSize--;
						if (item.getEntityItem().stackSize <= 0)
							item.setDead();
						return true;
					}
				}
			}
			return false;
		}
	}
	
	public static class LikesChicken implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {
			
			Entity item = null, chicken = null;
			List<Entity> entities = world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(pos.add(-3, 0, -3), pos.add(3, 1, 3)));
			for (Entity ent : entities) {
				if (!ent.isDead) {
					if (ent instanceof EntityChicken)
						chicken = ent;
					if (ent instanceof EntityItem && ((EntityItem)ent).getEntityItem().getItem() == Items.BOWL)
						item = ent;
					if (item != null && chicken != null)
						break;
				}
			}
			if (chicken != null && item != null) {
				AxisAlignedBB aabb = new AxisAlignedBB(chicken.getPosition().add(0, 0, 0), chicken.getPosition().add(1, 1, 1));
				List<Entity> list = world.getEntitiesWithinAABBExcludingEntity(chicken, aabb);
				for (Entity entity : list) {
					if (entity != null && entity == item) {
						EntityItem ei = new EntityItem(item.worldObj, item.posX, item.posY, item.posZ, new ItemStack(UCItems.teriyaki));
						((EntityItem)item).getEntityItem().stackSize--;
						if (((EntityItem)item).getEntityItem().stackSize <= 0)
							item.setDead();
						chicken.setDead();
						UCPacketHandler.sendToNearbyPlayers(world, pos, new PacketUCEffect(EnumParticleTypes.EXPLOSION_NORMAL, chicken.posX, chicken.posY + 0.5D, chicken.posZ, 3));
						if (!world.isRemote)
							world.spawnEntityInWorld(ei);
						return true;
					}
				}
			}
			else if (chicken != null) {
				UCPacketHandler.sendToNearbyPlayers(world, pos, new PacketUCEffect(EnumParticleTypes.HEART, chicken.posX, chicken.posY + 1D, chicken.posZ, 3));
				return true;
			}
			return false;
		}
	}
	
	public static class RequiresRedstone implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			for (EnumFacing facing : EnumFacing.VALUES) {
				int powersignal = world.getRedstonePower(pos.offset(facing), facing);
				if (powersignal >= 8)
					return true;
			}
			return false;
		}
	}
	
	public static class VampirePlant implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			int sunlight = world.getLightFor(EnumSkyBlock.SKY, pos);
			return sunlight == 0;
		}
	}
	
	public static class FullBrightness implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			return world.getLightFromNeighbors(pos) >= 13;
		}
	}
	
	public static class LikesWarts implements Condition {

		int range = 1;
		
		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			int warts = 0;
			Iterable<BlockPos> poslist = BlockPos.getAllInBox(pos.add(-range, 0, -range), pos.add(range, 0, range));
			Iterator posit = poslist.iterator();
			while (posit.hasNext()) {
				BlockPos looppos = (BlockPos)posit.next();
				if (!world.isAirBlock(looppos) && world.getBlockState(looppos).getBlock() == Blocks.NETHER_WART) {
					warts++;
				}
			}
			return warts == 8;
		}
	}
	
	public static class LikesCooking implements Condition {
		
		int range = 6;

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			Iterable<BlockPos> poslist = BlockPos.getAllInBox(pos.add(-range, -2, -range), pos.add(range, 2, range));
			Iterator iter = poslist.iterator();
			while (iter.hasNext()) {
				BlockPos posit = (BlockPos)iter.next();
				TileEntity tile = world.getTileEntity(posit);
				if (tile != null && tile instanceof TileEntityFurnace) {
					return ((TileEntityFurnace)tile).getField(2) > 0;
				}
			}
			return false;
		}
	}
	
	public static class LikesBrewing implements Condition {

		int range = 6;
		
		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {
			
			Iterable<BlockPos> poslist = BlockPos.getAllInBox(pos.add(-range, -2, -range), pos.add(range, 2, range));
			Iterator iter = poslist.iterator();
			while (iter.hasNext()) {
				BlockPos posit = (BlockPos)iter.next();
				TileEntity tile = world.getTileEntity(posit);
				if (tile != null && tile instanceof TileEntityBrewingStand) {
					return ((TileEntityBrewingStand)tile).getField(0) > 0;
				}
			}
			return false;
		}
	}
	
	public static class CheckerBoard implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			BlockPos[] neighbors = new BlockPos[] { pos.add(1, 0, 1), pos.add(-1, 0, -1), pos.add(1, 0, -1), pos.add(-1, 0, 1) };
			BlockPos[] noneighbors = new BlockPos[] { pos.offset(EnumFacing.EAST), pos.offset(EnumFacing.NORTH), pos.offset(EnumFacing.SOUTH), pos.offset(EnumFacing.WEST) };
			int crops = 0;
			for (BlockPos looppos1 : neighbors) {
				if (world.getBlockState(looppos1).getBlock() == UCBlocks.cropFeroxia)
					crops++;
			}
			for (BlockPos looppos2 : noneighbors) {
				if (world.getBlockState(looppos2).getBlock() == UCBlocks.cropFeroxia)
					crops--;
			}
			return crops == 4;
		}
	}
	
	public static class SacrificeSelf implements Condition {

		@Override
		public boolean canAdvance(World world, BlockPos pos, IBlockState state) {

			TileEntity tile = world.getTileEntity(pos);
			if (tile != null && tile instanceof TileFeroxia) {
				TileFeroxia te = (TileFeroxia)tile;
				EntityPlayer player = UCUtils.getPlayerFromUUID(te.getOwner().toString());
				if (!world.isRemote && player != null && world.getPlayerEntityByUUID(te.getOwner()) != null) {
					NBTTagCompound tag = player.getEntityData();
					if (!tag.hasKey("hasSacrificed"))
					{
						player.addChatMessage(new TextComponentString(TextFormatting.RED + "The savage plant whispers: \"The time is right to perform a self sacrifice.\""));
						tag.setBoolean("hasSacrificed", false);
						return false;
					}
					if (tag.hasKey("hasSacrificed") && tag.getBoolean("hasSacrificed"))
					{
						tag.removeTag("hasSacrificed");
						world.setBlockState(pos, ((Feroxia)state.getBlock()).withAge(7), 2);
						GrowthSteps.generateSteps(player);
						return false;
					}
				}
			}
			return false;
		}
	}
} public class NBTUtils {

	/** Checks if an ItemStack has a Tag Compound **/
	public static boolean detectNBT(ItemStack stack) {
		return stack.hasTagCompound();
	}

	/** Tries to initialize an NBT Tag Compound in an ItemStack,
	 * this will not do anything if the stack already has a tag
	 * compound **/
	public static void initNBT(ItemStack stack) {
		if(!detectNBT(stack))
			injectNBT(stack, new NBTTagCompound());
	}

	/** Injects an NBT Tag Compound to an ItemStack, no checks
	 * are made previously **/
	public static void injectNBT(ItemStack stack, NBTTagCompound nbt) {
		stack.setTagCompound(nbt);
	}

	/** Gets the NBTTagCompound in an ItemStack. Tries to init it
	 * previously in case there isn't one present **/
	public static NBTTagCompound getNBT(ItemStack stack) {
		initNBT(stack);
		return stack.getTagCompound();
	}

	// SETTERS ///////////////////////////////////////////////////////////////////

	public static void setBoolean(ItemStack stack, String tag, boolean b) {
		getNBT(stack).setBoolean(tag, b);
	}

	public static void setByte(ItemStack stack, String tag, byte b) {
		getNBT(stack).setByte(tag, b);
	}
	
	public static void setByteArray(ItemStack stack, String tag, byte[] b) {
		
		getNBT(stack).setByteArray(tag, b);
	}

	public static void setShort(ItemStack stack, String tag, short s) {
		getNBT(stack).setShort(tag, s);
	}

	public static void setInt(ItemStack stack, String tag, int i) {
		getNBT(stack).setInteger(tag, i);
	}

	public static void setLong(ItemStack stack, String tag, long l) {
		getNBT(stack).setLong(tag, l);
	}

	public static void setFloat(ItemStack stack, String tag, float f) {
		getNBT(stack).setFloat(tag, f);
	}

	public static void setDouble(ItemStack stack, String tag, double d) {
		getNBT(stack).setDouble(tag, d);
	}

	public static void setCompound(ItemStack stack, String tag, NBTTagCompound cmp) {
		if(!tag.equalsIgnoreCase("ench")) // not override the enchantments
			getNBT(stack).setTag(tag, cmp);
	}

	public static void setString(ItemStack stack, String tag, String s) {
		getNBT(stack).setString(tag, s);
	}

	public static void setList(ItemStack stack, String tag, NBTTagList list) {
		getNBT(stack).setTag(tag, list);
	}
	
	public static void setIntArray(ItemStack stack, String key, int[] val) {
		
		getCompound(stack, key, true).setIntArray(key, val);
	}

	// GETTERS ///////////////////////////////////////////////////////////////////
	
	public static int[] getIntArray(ItemStack stack, String key) {
		
		return detectNBT(stack) ? getCompound(stack, key, true).getIntArray(key) : new int[0];
	}

	public static boolean verifyExistance(ItemStack stack, String tag) {
		return stack != null && getNBT(stack).hasKey(tag);
	}

	public static boolean getBoolean(ItemStack stack, String tag, boolean defaultExpected) {
		return verifyExistance(stack, tag) ? getNBT(stack).getBoolean(tag) : defaultExpected;
	}

	public static byte getByte(ItemStack stack, String tag, byte defaultExpected) {
		return verifyExistance(stack, tag) ? getNBT(stack).getByte(tag) : defaultExpected;
	}
	
	public static byte[] getByteArray(ItemStack stack, String tag) {
		
		return verifyExistance(stack, tag) ? getNBT(stack).getByteArray(tag) : null;
	}

	public static short getShort(ItemStack stack, String tag, short defaultExpected) {
		return verifyExistance(stack, tag) ? getNBT(stack).getShort(tag) : defaultExpected;
	}

	public static int getInt(ItemStack stack, String tag, int defaultExpected) {
		return verifyExistance(stack, tag) ? getNBT(stack).getInteger(tag) : defaultExpected;
	}

	public static long getLong(ItemStack stack, String tag, long defaultExpected) {
		return verifyExistance(stack, tag) ? getNBT(stack).getLong(tag) : defaultExpected;
	}

	public static float getFloat(ItemStack stack, String tag, float defaultExpected) {
		return verifyExistance(stack, tag) ? getNBT(stack).getFloat(tag) : defaultExpected;
	}

	public static double getDouble(ItemStack stack, String tag, double defaultExpected) {
		return verifyExistance(stack, tag) ? getNBT(stack).getDouble(tag) : defaultExpected;
	}

	/** If nullifyOnFail is true it'll return null if it doesn't find any
	 * compounds, otherwise it'll return a new one. **/
	public static NBTTagCompound getCompound(ItemStack stack, String tag, boolean nullifyOnFail) {
		return verifyExistance(stack, tag) ? getNBT(stack).getCompoundTag(tag) : nullifyOnFail ? null : new NBTTagCompound();
	}

	public static String getString(ItemStack stack, String tag, String defaultExpected) {
		return verifyExistance(stack, tag) ? getNBT(stack).getString(tag) : defaultExpected;
	}

	public static NBTTagList getList(ItemStack stack, String tag, int objtype, boolean nullifyOnFail) {
		return verifyExistance(stack, tag) ? getNBT(stack).getTagList(tag, objtype) : nullifyOnFail ? null : new NBTTagList();
	}
} public class SeedBehavior {

	public static boolean canPlantCrop(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumFacing side, Block cropBlock) {
		
		if (side != EnumFacing.UP)
			return false;
		
		if (!world.isRemote && cropBlock instanceof BlockCropsBase && !((BlockCropsBase)cropBlock).canPlantCrop()) {
			UCPacketHandler.sendToNearbyPlayers(world, pos, new PacketUCEffect(EnumParticleTypes.BARRIER, pos.getX(), pos.getY() + 2, pos.getZ(), 0));
			return false;
		}
		else if (player.canPlayerEdit(pos, side, stack) && player.canPlayerEdit(pos.offset(EnumFacing.UP), side, stack)) {
			IBlockState state = world.getBlockState(pos);
			if (state.getBlock().canSustainPlant(state, world, pos, EnumFacing.UP, (IPlantable)stack.getItem()) && world.isAirBlock(pos.offset(EnumFacing.UP))) {
				if (cropBlock == UCBlocks.cropCollis) {
					if (!world.provider.isSurfaceWorld() || pos.getY() <= 100)
						return false;
				}
				if (cropBlock == UCBlocks.cropCinderbella) {
					long time = world.getWorldTime() % 24000L;
					if (time >= 18000)
						return false;
					
					BlockPos pos1 = pos.add(0, 1, 0);
					int pumpkins = 0;
					for (EnumFacing facing : EnumFacing.HORIZONTALS) {
						IBlockState pumpkin = world.getBlockState(pos1.offset(facing));
						if (pumpkin.getBlock() != null && pumpkin.getBlock() == Blocks.PUMPKIN && !world.isRemote) {
							pumpkins++;
						}
					}
					if (pumpkins >= 4) {
						cropBlock.onBlockPlacedBy(world, pos.offset(side), cropBlock.getDefaultState(), player, stack);
						return true;
					}
				}
				if (cropBlock == UCBlocks.cropFeroxia) {
					cropBlock.onBlockPlacedBy(world, pos.offset(side), cropBlock.getDefaultState(), player, stack);
					return true;
				}
				if (cropBlock == UCBlocks.cropEula) {
					player.openGui(UniqueCrops.instance, 1, world, (int)player.posX, (int)player.posY, (int)player.posZ);
				}
				if (cropBlock == UCBlocks.cropAbstract) {
					player.renderBrokenItemStack(stack);
					if (!player.worldObj.isRemote)
						setAbstractCropGrowth(player, true);
					return true;
				}
				if (cropBlock == UCBlocks.cropPetramia && pos.offset(side).getY() >= 10) {
					return false;
				}
				world.setBlockState(pos.offset(side), cropBlock.getDefaultState(), 3);
				return true;
			}
		}
		return false;
	}
	
	public static final String TAG_ABSTRACT = "UC_tagAbstractGrowth";
	
	public static void setAbstractCropGrowth(EntityPlayer player, boolean add) {
		
		NBTTagCompound tag = player.getEntityData();
		if (!tag.hasKey(TAG_ABSTRACT) && add) {
			tag.setInteger(TAG_ABSTRACT, 1);
			return;
		}
		if (add) {
			tag.setInteger(TAG_ABSTRACT, tag.getInteger(TAG_ABSTRACT) + 1);
		}
		else if (!add) {
			int value = tag.getInteger(TAG_ABSTRACT);
			if (player.worldObj.rand.nextInt(5) == 0)
				tag.setInteger(TAG_ABSTRACT, value - 1);
		}
		if (tag.getInteger(TAG_ABSTRACT) <= 0)
			tag.removeTag(TAG_ABSTRACT);
	}
} public class Feroxia extends BlockCropsBase implements ITileEntityProvider {
	
	public static List<GrowthSteps> steps = new ArrayList<GrowthSteps>();

	public Feroxia() {
		
		super(EnumCrops.SAVAGEPLANT, false, UCConfig.cropFeroxia);
		this.clickHarvest = false;
		GameRegistry.registerTileEntity(TileFeroxia.class, "TileFeroxia");
		init();
	}
	
	private void init() {
		
		steps.add(new GrowthSteps(UCStrings.MOON, new GrowthSteps.MoonPhase(), 0));
		steps.add(new GrowthSteps(UCStrings.BURNINGPLAYER, new GrowthSteps.BurningPlayer(), 1));
		steps.add(new GrowthSteps(UCStrings.DRYFARMLAND, new GrowthSteps.DryFarmland(), 2));
		steps.add(new GrowthSteps(UCStrings.HASTORCH, new GrowthSteps.HasTorch(), 3));
		steps.add(new GrowthSteps(UCStrings.HELLWORLD, new GrowthSteps.HellWorld(), 4));
		steps.add(new GrowthSteps(UCStrings.DARKNESS, new GrowthSteps.LikesDarkness(), 5));
		steps.add(new GrowthSteps(UCStrings.LIKESHEIGHTS, new GrowthSteps.LikesHeights(), 6));
		steps.add(new GrowthSteps(UCStrings.UNDERFARMLAND, new GrowthSteps.UnderFarmland(), 7));
		steps.add(new GrowthSteps(UCStrings.LILYPADS, new GrowthSteps.LikesLilypads(), 8));
		steps.add(new GrowthSteps(UCStrings.HUNGRYPLANT, new GrowthSteps.HungryPlant(), 9));
		steps.add(new GrowthSteps(UCStrings.THIRSTYPLANT, new GrowthSteps.ThirstyPlant(), 10));
		steps.add(new GrowthSteps(UCStrings.LIKESCHICKEN, new GrowthSteps.LikesChicken(), 11));
		steps.add(new GrowthSteps(UCStrings.REDSTONE, new GrowthSteps.RequiresRedstone(), 12));
		steps.add(new GrowthSteps(UCStrings.VAMPIREPLANT, new GrowthSteps.VampirePlant(), 13));
		steps.add(new GrowthSteps(UCStrings.FULLBRIGHTNESS, new GrowthSteps.FullBrightness(), 14));
		steps.add(new GrowthSteps(UCStrings.LIKESWARTS, new GrowthSteps.LikesWarts(), 15));
		steps.add(new GrowthSteps(UCStrings.LIKESCOOKING, new GrowthSteps.LikesCooking(), 16));
		steps.add(new GrowthSteps(UCStrings.LIKESBREWING, new GrowthSteps.LikesBrewing(), 17));
		steps.add(new GrowthSteps(UCStrings.LIKESCHECKERS, new GrowthSteps.CheckerBoard(), 18));
		steps.add(new GrowthSteps(UCStrings.SELFSACRIFICE, new GrowthSteps.SacrificeSelf(), 19));
	}
	
	@Override
	public Item getSeed() {
		
		return UCItems.seedsFeroxia;
	}
	
	@Override
	public Item getCrop() {
		
		return UCItems.generic;
	}
	
    public int quantityDropped(IBlockState state, int fortune, Random random) {
        
    	if (this.getAge(state) < getMaxAge())
    		return 0;
    	
    	return random.nextInt(4) + 2;
    }
	
	@Override
	public int damageDropped(IBlockState state) {
		
		if (getAge(state) < getMaxAge())
			return 1;
		
		return EnumItems.ESSENCE.ordinal();
	}
	
	public boolean isFullyGrown(World world, BlockPos pos, IBlockState state) {
		
		return this.getAge(state) >= this.getMaxAge();
	}
	
	@Override
    public boolean canBlockStay(World worldIn, BlockPos pos, IBlockState state) {
       
    	IBlockState soil = worldIn.getBlockState(pos.down());
        return soil.getBlock().canSustainPlant(soil, worldIn, pos.down(), net.minecraft.util.EnumFacing.UP, this);
    }
	
	@Override
    public void updateTick(World world, BlockPos pos, IBlockState state, Random rand) {
		
		if (this.getAge(state) >= getMaxAge() || world.isRemote)
			return;
		
		if (!this.canBlockStay(world, pos, state)) {
			EntityItem ei = new EntityItem(world, pos.getX() + 0.5, pos.getY() + 0.1, pos.getZ() + 0.5, new ItemStack(this.getSeed()));
			world.spawnEntityInWorld(ei);
			world.setBlockToAir(pos);
			return;
		}
		TileEntity tile = world.getTileEntity(pos);
		if (tile == null || (tile != null && !(tile instanceof TileFeroxia)))
			return;
		
		TileFeroxia te = (TileFeroxia)tile;
		if (te.getOwner() == null || (te.getOwner() != null && UCUtils.getPlayerFromUUID(te.getOwner().toString()) == null))
			return;
		
		NBTTagList taglist = UCUtils.getServerTaglist(UCUtils.getPlayerFromUUID(te.getOwner().toString()).getEntityId());
		if (taglist == null)
			return;
		NBTTagCompound tag = taglist.getCompoundTagAt(this.getAge(state));
		int stage = tag.getInteger("stage" + this.getAge(state));
		
		if (!steps.get(stage).getCondition().canAdvance(world, pos, state)) {
			return;
		}
        int i = this.getAge(state);

        if (i < this.getMaxAge()) {
            float f = getGrowthChance(this, world, pos);
            if (rand.nextInt((int)(25.0F / f) + 1) == 0)
            	world.setBlockState(pos, this.withAge(i + 1), 2);
        }
	}
	
    @Override
    public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) {
    
    	world.setBlockState(pos, state.getBlock().getDefaultState(), 2);
    	TileEntity te = world.getTileEntity(pos);
    	if (te != null && te instanceof TileFeroxia) {
    		if (placer instanceof EntityPlayer && !(placer instanceof FakePlayer))
    		{
        		((TileFeroxia)te).setOwner(placer.getUniqueID());
        		if (!world.isRemote && !placer.getEntityData().hasKey(GrowthSteps.TAG_GROWTHSTAGES)) {
        			GrowthSteps.generateSteps((EntityPlayer)placer);
        		}
    		}
    	}
    }

	@Override
	public TileEntity createNewTileEntity(World world, int meta) {

		return new TileFeroxia();
	}
} public class UCBlocks {

	// CROPS
	public static BlockCropsBase
		cropNormal,
		cropPrecision,
		cropKnowledge,
		cropDirigible,
		cropMillennium,
		cropEnderlily,
		cropCollis,
		cropWeepingbells,
		cropInvisibilia,
		cropMaryjane,
		cropMusica,
		cropCinderbella,
		cropMerlinia,
		cropFeroxia,
		cropEula,
		cropCobblonia,
		cropDyeius,
		cropAbstract,
		cropWafflonia,
		cropDevilsnare,
		cropPixelsius,
		cropArtisia,
		cropPetramia,
		cropMalleatoris;
	
	public static Block oldCobble, oldCobbleMoss, oldGravel, oldGrass, oldBrick;
	public static Block hourglass, totemhead, lavalily, darkBlock;
	
	public static void init() {
		
		cropNormal = new Normal();
		cropPrecision = new Precision();
		cropKnowledge = new Knowledge();
		cropDirigible = new Dirigible();
		cropMillennium = new Millennium();
		cropEnderlily = new Enderlily();
		cropCollis = new Collis();
		cropInvisibilia = new Invisibilia();
		cropMaryjane = new MaryJane();
		cropWeepingbells = new WeepingBells();
		cropMusica = new Musica();
		cropCinderbella = new Cinderbella();
		cropMerlinia = new Merlinia();
		cropFeroxia = new Feroxia();
		cropEula = new Eula();
		cropCobblonia = new Cobblonia();
		cropDyeius = new Dyeius();
		cropAbstract = new Abstract();
		cropWafflonia = new Wafflonia();
		cropDevilsnare = new DevilSnare();
		cropPixelsius = new Pixelsius();
		cropArtisia = new Artisia();
		cropPetramia = new Petramia();
		cropMalleatoris = new Malleatoris();
		
		oldCobble = new BlockOldStone("cobble");
		oldCobbleMoss = new BlockOldStone("cobblemoss");
		oldBrick = new BlockOldStone("brick");
		oldGravel = new BlockOldGravel();
		oldGrass = new BlockOldGrass();
		hourglass = new BlockHourglass();
		totemhead = new BlockTotemhead();
		lavalily = new BlockLavaLily();
		darkBlock = new BlockDarkBlock();
	}
	
	@SideOnly(Side.CLIENT)
	public static void initModels() {
	
		registerBlockModel(oldCobble);
		registerBlockModel(oldCobbleMoss);
		registerBlockModel(oldBrick);
		registerBlockModel(oldGravel);
		registerBlockModel(oldGrass);
		registerBlockModel(hourglass);
		registerBlockModel(totemhead);
		registerBlockModel(lavalily);
		registerBlockModel(darkBlock);
		
		ClientRegistry.bindTileEntitySpecialRenderer(TileArtisia.class, new RenderCraftItem());
	}
	
	private static void registerBlockModel(Block block) {
		
		ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(block), 0, new ModelResourceLocation(block.getRegistryName(), "inventory"));
	}
} public class UCItems {

	// SEEDS
	public static Item 
		seedsNormal,
		seedsPrecision,
		seedsKnowledge,
		seedsDirigible,
		seedsMillennium,
		seedsEnderlily,
		seedsCollis,
		seedsInvisibilia,
		seedsMaryjane,
		seedsWeepingbells,
		seedsMusica,
		seedsCinderbella,
		seedsMerlinia,
		seedsFeroxia,
		seedsEula,
		seedsCobblonia,
		seedsDyeius,
		seedsAbstract,
		seedsWafflonia,
		seedsDevilsnare,
		seedsPixelsius,
		seedsArtisia,
		seedsPetramia,
		seedsMalleatoris;
	
	public static ItemGeneric generic;
	public static Item largeplum;
	public static Item teriyaki;
	public static Item heart;
	public static Item potionreverse;
	public static Item goldenbread;
	public static Item dietpills;
	public static Item waffle;
	public static Item endersnooker;
	
	public static Item edibleDiamond;
	public static Item edibleLapis;
	public static Item edibleEmerald;
	public static Item edibleIngotIron;
	public static Item edibleIngotGold;
	public static Item edibleNuggetGold;
	
	public static ItemArmor glasses3D;
	public static ItemArmor poncho;
	public static ItemArmor slippers;
	public static ItemArmor pixelglasses;
	public static ItemTool precisionPick;
	public static ItemTool precisionAxe;
	public static ItemTool precisionShovel;
	
	public static final ItemArmor.ArmorMaterial glassesmaterial = EnumHelper.addArmorMaterial("3dglasses", "uniquecrops:3dglasses", 200, new int[] { 0, 0, 0, 0 }, 10, SoundEvents.ITEM_ARMOR_EQUIP_GENERIC, 0F);
	public static final ItemArmor.ArmorMaterial pixelmaterial = EnumHelper.addArmorMaterial("pixelglasses", "uniquecrops:pixelglasses", 200, new int[] { 0, 0, 0, 0 }, 10, SoundEvents.ITEM_ARMOR_EQUIP_GENERIC, 0F);
	public static final ItemArmor.ArmorMaterial ponchomaterial = EnumHelper.addArmorMaterial("poncho", "uniquecrops:poncho", 112, new int[] { 1, 2, 1, 1 }, 0, SoundEvents.ITEM_ARMOR_EQUIP_LEATHER, 0F);
	public static final ItemArmor.ArmorMaterial slippermaterial = EnumHelper.addArmorMaterial("slippers", "uniquecrops:slippers", 90, new int[] { 1, 1, 1, 1 }, 0, SoundEvents.ITEM_ARMOR_EQUIP_GOLD, 0F);
	
	public static void init() {
		
		UCBaubles.init();
		
		seedsNormal = new ItemSeedsUC(UCBlocks.cropNormal);
		seedsPrecision = new ItemSeedsUC(UCBlocks.cropPrecision);
		seedsKnowledge = new ItemSeedsUC(UCBlocks.cropKnowledge);
		seedsDirigible = new ItemSeedsUC(UCBlocks.cropDirigible);
		seedsMillennium = new ItemSeedsUC(UCBlocks.cropMillennium);
		seedsEnderlily = new ItemSeedsUC(UCBlocks.cropEnderlily);
		seedsCollis = new ItemSeedsUC(UCBlocks.cropCollis);
		seedsInvisibilia = new ItemSeedsUC(UCBlocks.cropInvisibilia);
		seedsMaryjane = new ItemSeedsUC(UCBlocks.cropMaryjane);
		seedsWeepingbells = new ItemSeedsUC(UCBlocks.cropWeepingbells);
		seedsMusica = new ItemSeedsUC(UCBlocks.cropMusica);
		seedsCinderbella = new ItemSeedsUC(UCBlocks.cropCinderbella);
		seedsMerlinia = new ItemSeedsUC(UCBlocks.cropMerlinia);
		seedsFeroxia = new ItemSeedsUC(UCBlocks.cropFeroxia);
		seedsEula = new ItemSeedsUC(UCBlocks.cropEula);
		seedsCobblonia = new ItemSeedsUC(UCBlocks.cropCobblonia);
		seedsDyeius = new ItemSeedsUC(UCBlocks.cropDyeius);
		seedsAbstract = new ItemSeedsUC(UCBlocks.cropAbstract);
		seedsWafflonia = new ItemSeedsUC(UCBlocks.cropWafflonia);
		seedsDevilsnare = new ItemSeedsUC(UCBlocks.cropDevilsnare);
		seedsPixelsius = new ItemSeedsUC(UCBlocks.cropPixelsius);
		seedsArtisia = new ItemSeedsUC(UCBlocks.cropArtisia);
		seedsPetramia = new ItemSeedsUC(UCBlocks.cropPetramia);
		seedsMalleatoris = new ItemSeedsUC(UCBlocks.cropMalleatoris);
		
		generic = new ItemGeneric();
		largeplum = new ItemGenericFood(1, 0.6F, true, "largeplum");
		teriyaki = new ItemGenericFood(16, 1.0F, false, "teriyaki").setContainerItem(Items.BOWL);
		heart = new ItemGenericFood(0, 0F, true, "heart");
		potionreverse = new ItemGenericFood(0, 0F, true, "reversepotion");
		goldenbread = new ItemGenericFood(4, 0.3F, false, "goldenbread");
		dietpills = new ItemGenericFood(-4, 0, true, "dietpills");
		waffle = new ItemGenericFood(8, 1.0F, false, "waffle");
		endersnooker = new ItemEnderSnooker();
		
		edibleDiamond = new ItemEdibleMetal(EnumEdibleMetal.GEM, "diamond");
		edibleEmerald = new ItemEdibleMetal(EnumEdibleMetal.GEM, "emerald");
		edibleLapis = new ItemEdibleMetal(EnumEdibleMetal.NUGGET, "lapis");
		edibleIngotIron = new ItemEdibleMetal(EnumEdibleMetal.INGOT, "ironingot");
		edibleIngotGold = new ItemEdibleMetal(EnumEdibleMetal.INGOT, "goldingot");
		edibleNuggetGold = new ItemEdibleMetal(EnumEdibleMetal.NUGGET, "goldnugget");
		
		glasses3D = new Item3DGlasses(glassesmaterial, 1, EntityEquipmentSlot.HEAD);
		pixelglasses = new ItemPixelGlasses(pixelmaterial, 1, EntityEquipmentSlot.HEAD);
		poncho = new ItemPoncho(ponchomaterial, 1, EntityEquipmentSlot.CHEST);
		slippers = new ItemGlassSlippers(slippermaterial, 2, EntityEquipmentSlot.FEET);
		precisionPick = new ItemPrecisionPick();
		precisionAxe = new ItemPrecisionAxe();
		precisionShovel = new ItemPrecisionShovel();
		
		OreDictionary.registerOre("gemDiamond", edibleDiamond);
		OreDictionary.registerOre("gemEmerald", edibleEmerald);
		OreDictionary.registerOre("gemLapis", edibleLapis);
		OreDictionary.registerOre("ingotIron", edibleIngotIron);
		OreDictionary.registerOre("ingotGold", edibleIngotGold);
		OreDictionary.registerOre("nuggetGold", edibleNuggetGold);
	}
	
	@SideOnly(Side.CLIENT)
	public static void initModels() {
		
		UCBaubles.initModels();
		
		registerItemModel(seedsNormal);
		registerItemModel(seedsPrecision);
		registerItemModel(seedsKnowledge);
		registerItemModel(seedsDirigible);
		registerItemModel(seedsMillennium);
		registerItemModel(seedsEnderlily);
		registerItemModel(seedsCollis);
		registerItemModel(seedsInvisibilia);
		registerItemModel(seedsMaryjane);
		registerItemModel(seedsWeepingbells);
		registerItemModel(seedsMusica);
		registerItemModel(seedsCinderbella);
		registerItemModel(seedsMerlinia);
		registerItemModel(seedsFeroxia);
		registerItemModel(seedsEula);
		registerItemModel(seedsCobblonia);
		registerItemModel(seedsDyeius);
		registerItemModel(seedsAbstract);
		registerItemModel(seedsWafflonia);
		registerItemModel(seedsDevilsnare);
		registerItemModel(seedsPixelsius);
		registerItemModel(seedsArtisia);
		registerItemModel(seedsPetramia);
		registerItemModel(seedsMalleatoris);
		
		for (int i = 0; i < EnumItems.values().length; ++i)
			ModelLoader.setCustomModelResourceLocation(generic, i, new ModelResourceLocation(generic.getRegistryName() + "." + EnumItems.values()[i].getName(), "inventory"));
			
		registerItemModel(largeplum);
		registerItemModel(teriyaki);
		registerItemModel(heart);
		registerItemModel(potionreverse);
		registerItemModel(goldenbread);
		registerItemModel(dietpills);
		registerItemModel(waffle);
		
		registerItemModel(edibleDiamond);
		registerItemModel(edibleEmerald);
		registerItemModel(edibleLapis);
		registerItemModel(edibleIngotIron);
		registerItemModel(edibleIngotGold);
		registerItemModel(edibleNuggetGold);
		
		registerItemModel(endersnooker);
		registerItemModel(glasses3D);
		registerItemModel(poncho);
		registerItemModel(slippers);
		registerItemModel(pixelglasses);
		registerItemModel(precisionPick);
		registerItemModel(precisionAxe);
		registerItemModel(precisionShovel);
	}
	
	private static void registerItemModel(Item item) {
		
		ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(item.getRegistryName(), "inventory"));
	}
} public class ItemGeneric extends Item implements IFuelHandler {
	
	private static final String[] FIELD_G = new String[] { "attackCooldown", "field_188501_c", "uo" };
	private static final String[] FUSETIME = new String[] { "fuseTime", "field_82225_f", "yp" };
	public static String TAG_DISCOUNT = "UC_tagDiscount";
	public static String TAG_UPGRADE = "UC_tagUpgrade";
	public static String TAG_OVERCLUCK = "UC_tagEggUpgrade";
	private int range = 5;

	public ItemGeneric() {
		
		setRegistryName("generic");
		setUnlocalizedName(UniqueCrops.MOD_ID + ".generic");
		setCreativeTab(UniqueCrops.TAB);
		setHasSubtypes(true);
		setMaxDamage(0);
		GameRegistry.register(this);
		GameRegistry.registerFuelHandler(this);
	}
	
	@Override
	public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean whatisthis) {
		
		switch(stack.getItemDamage()) {
			case 0: list.add(I18n.format(UCStrings.TOOLTIP + "guidebook")); break;
			case 1: list.add(I18n.format(UCStrings.TOOLTIP + "discountbook")); break;
			case 14: list.add(I18n.format(UCStrings.TOOLTIP + "slipperglass")); break;
			case 18: list.add(I18n.format(UCStrings.TOOLTIP + "upgradebook")); break;
			case 19: list.add(I18n.format(UCStrings.TOOLTIP + "eggupgrade")); break;
			case 20: list.add(I18n.format(UCStrings.TOOLTIP + "easybadge")); break;
			case 24: list.add(I18n.format(UCStrings.TOOLTIP + "eulabook")); break;
		}
	}
	
	public String getUnlocalizedName(ItemStack stack) {
		
		return getUnlocalizedName() + "." + EnumItems.values()[stack.getItemDamage()].getName();
	}
	
	@SideOnly(Side.CLIENT)
	public void getSubItems(Item item, CreativeTabs tabs, List list) {
		
		for (int i = 0; i < EnumItems.values().length; ++i)
			list.add(new ItemStack(item, 1, i));
	}
	
	@SideOnly(Side.CLIENT)
	public boolean hasEffect(ItemStack stack) {
		
		if (stack.getItemDamage() == 1 || stack.getItemDamage() == 13)
			return true;
		
		return false;
	}
	
	public ItemStack createStack(EnumItems item, int stacksize) {
		
		return new ItemStack(this, stacksize, item.ordinal());
	}
	
	public ItemStack createStack(EnumItems item) {
		
		return createStack(item, 1);
	}
	
	@Override
	public boolean hasCustomEntity(ItemStack stack) {
		
		return stack.getItemDamage() == 2;
	}
	
	@Override
	public Entity createEntity(World world, Entity location, ItemStack stack) {
		
		if (location instanceof EntityItem) {
			EntityItemPlum plum = new EntityItemPlum(world, (EntityItem)location, stack);
			return plum;
		}
		return null;
	}
	
	public EnumActionResult onItemUse(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
		
		if (stack.getItemDamage() == EnumItems.TIMEMEAL.ordinal() && player.canPlayerEdit(pos, facing, stack)) {
			Block crops = world.getBlockState(pos).getBlock();
			if (crops != null && crops instanceof BlockCrops) {
				if (crops != UCBlocks.cropMerlinia)
					world.setBlockState(pos, ((BlockCrops)crops).withAge(0), 2);
				else if (crops == UCBlocks.cropMerlinia)
					((Merlinia)crops).merliniaGrowth(world, pos, world.rand.nextInt(1) + 1);
				else if (crops instanceof BlockNetherWart)
					((BlockNetherWart)crops).updateTick(world, pos, world.getBlockState(pos), world.rand);
				if (!player.capabilities.isCreativeMode && !player.worldObj.isRemote)
					stack.stackSize--;
				UCPacketHandler.sendToNearbyPlayers(world, pos, new PacketUCEffect(EnumParticleTypes.VILLAGER_HAPPY, pos.getX() - 0.5D, pos.getY(), pos.getZ() - 0.5D, 6));
				return EnumActionResult.SUCCESS;
			}
		}
		return super.onItemUse(stack, player, world, pos, hand, facing, hitX, hitY, hitZ);
	}
	
	@Override
	public ActionResult<ItemStack> onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand) {

		if (stack.getItemDamage() == EnumItems.GUIDE.ordinal() && hand == EnumHand.MAIN_HAND && !player.isSneaking()) {
			if (!world.isRemote && (!player.getEntityData().hasKey(GrowthSteps.TAG_GROWTHSTAGES) || (player.getEntityData().hasKey(GrowthSteps.TAG_GROWTHSTAGES) && !stack.getTagCompound().hasKey(GrowthSteps.TAG_GROWTHSTAGES))))
				UCUtils.updateBook(player);
			player.openGui(UniqueCrops.instance, 0, world, (int)player.posX, (int)player.posY, (int)player.posZ);
			return new ActionResult(EnumActionResult.SUCCESS, stack);
		}
		if (stack.getItemDamage() == EnumItems.POTIONSPLASH.ordinal()) {
	        if (!player.capabilities.isCreativeMode)
	            --stack.stackSize;

	        world.playSound((EntityPlayer)null, player.posX, player.posY, player.posZ, SoundEvents.ENTITY_SPLASH_POTION_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));
	        if (!world.isRemote)
	        {
	            EntityCustomPotion entitypotion = new EntityCustomPotion(world, player, stack);
	            entitypotion.setHeadingFromThrower(player, player.rotationPitch, player.rotationYaw, -20.0F, 0.5F, 1.0F);
	            world.spawnEntityInWorld(entitypotion);
	        }
	        return new ActionResult(EnumActionResult.SUCCESS, stack);
		}
		if (stack.getItemDamage() == EnumItems.WEEPINGEYE.ordinal()) {
	        if (!player.capabilities.isCreativeMode)
	            --stack.stackSize;

	        world.playSound((EntityPlayer)null, player.posX, player.posY, player.posZ, SoundEvents.ENTITY_ENDERPEARL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));
	        if (!world.isRemote)
	        {
	            EntityItemWeepingEye eye = new EntityItemWeepingEye(world, player.posX, player.posY + 1.5D, player.posZ);
	            eye.setHeadingFromThrower(player, player.rotationPitch, player.rotationYaw, 0.0F, 1.5F, 1.0F);
	            world.spawnEntityInWorld(eye);
	        }
	        return new ActionResult(EnumActionResult.SUCCESS, stack);
		}
		if (stack.getItemDamage() == EnumItems.DOGRESIDUE.ordinal()) {
			boolean canFill = false;
			for (int i = 0; i < player.inventory.getSizeInventory() - player.inventory.armorInventory.length; i++) {
				ItemStack loopstack = player.inventory.getStackInSlot(i);
				if (loopstack == null) {
					player.inventory.setInventorySlotContents(i, new ItemStack(this, 1, 21));
					canFill = true;
				}
			}
			if (!world.isRemote)
			{
				if (canFill)
					player.addChatMessage(new TextComponentString("The rest of your inventory filled up with dog residue."));
				else
					player.addChatMessage(new TextComponentString("You finished using it. An uneasy silence fills the room."));
			}
			return new ActionResult(EnumActionResult.SUCCESS, stack);
		}
		if (stack.getItemDamage() == EnumItems.EULA.ordinal()) {
	        if (!player.capabilities.isCreativeMode)
	            --stack.stackSize;

	        world.playSound((EntityPlayer)null, player.posX, player.posY, player.posZ, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.NEUTRAL, 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));
	        if (!world.isRemote)
	        {
	            EntityEulaBook entitybook = new EntityEulaBook(world, player, stack);
	            entitybook.setHeadingFromThrower(player, player.rotationPitch, player.rotationYaw, -20.0F, 0.5F, 1.0F);
	            world.spawnEntityInWorld(entitybook);
	        }
	        return new ActionResult(EnumActionResult.SUCCESS, stack);
		}
		return new ActionResult(EnumActionResult.PASS, stack);
	}
	
	@Override
	public boolean itemInteractionForEntity(ItemStack stack, EntityPlayer player, EntityLivingBase elb, EnumHand hand) {
		
		if (stack.getItemDamage() == 19 && elb instanceof EntityChicken) {
			NBTTagCompound tag = elb.getEntityData();
			if (!elb.isChild() && !tag.hasKey(TAG_OVERCLUCK))
			{
				tag.setInteger(TAG_OVERCLUCK, elb.worldObj.rand.nextInt(60) + 900);
				if (!player.capabilities.isCreativeMode)
					stack.stackSize--;
				return true;
			}
		}
		return super.itemInteractionForEntity(stack, player, elb, hand);
	}
	
	@Override
    public void onUpdate(ItemStack stack, World world, Entity entity, int itemSlot, boolean isSelected) {
		
		if (stack.getItemDamage() != 20)
			return;
		
		if (!(entity instanceof EntityPlayer) || (entity instanceof FakePlayer))
			return;
		
		if (itemSlot < ((EntityPlayer)entity).inventory.getHotbarSize()) {
			List<EntityLiving> entities = entity.worldObj.getEntitiesWithinAABB(EntityLiving.class, new AxisAlignedBB(entity.getPosition().add(-range, -range, -range), entity.getPosition().add(range, range, range)));
			
			for (EntityLiving ent : entities) {
				List<EntityAITaskEntry> entries = new ArrayList(ent.tasks.taskEntries);
				entries.addAll(new ArrayList(ent.targetTasks.taskEntries));
				
				for (EntityAITaskEntry entry : entries) {
					if (entry.action instanceof EntityAIAttackRangedBow) {
						makeSkellyShootSlower((EntityAIAttackRangedBow)entry.action);
					}
				}
				if (ent instanceof EntityCreeper)
					ReflectionHelper.setPrivateValue(EntityCreeper.class, (EntityCreeper)ent, 60, this.FUSETIME);
			}
		}
	}
	
	private void makeSkellyShootSlower(EntityAIAttackRangedBow aiEntry) {
		
		int timeShoot = ReflectionHelper.getPrivateValue(EntityAIAttackRangedBow.class, aiEntry, this.FIELD_G);
		
		if (timeShoot == 40) 
			ReflectionHelper.setPrivateValue(EntityAIAttackRangedBow.class, aiEntry, 100, this.FIELD_G);
	}
	
	@Override
    public int getItemStackLimit(ItemStack stack) {
    	
		if (stack.getUnlocalizedName().contains("book") || stack.getItemDamage() == 21)
			return 1;
		
		return super.getItemStackLimit(stack);
    }

	@Override
	public int getBurnTime(ItemStack fuel) {
		
		if (fuel.getItem() == this && fuel.getItemDamage() == 3)
			return 16000;
		
		return 0;
	}
}
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.item.EntityFallingBlock;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntityGuardian;
import net.minecraft.entity.monster.EntityShulker;
import net.minecraft.entity.monster.EntitySkeleton;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.entity.passive.EntityChicken;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Enchantments;
import net.minecraft.init.Items;
import net.minecraft.init.MobEffects;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityMobSpawner;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.AnvilUpdateEvent;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.event.entity.player.AnvilRepairEvent;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.NoteBlockEvent;
import net.minecraftforge.fml.common.eventhandler.Event.Result;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.items.ItemHandlerHelper;
import com.bafomdad.uniquecrops.UniqueCrops;
import com.bafomdad.uniquecrops.api.IBookUpgradeable;
import com.bafomdad.uniquecrops.blocks.tiles.TileMusicaPlant;
import com.bafomdad.uniquecrops.blocks.tiles.TileMusicaPlant.Beat;
import com.bafomdad.uniquecrops.core.EnumItems;
import com.bafomdad.uniquecrops.core.GrowthSteps;
import com.bafomdad.uniquecrops.core.NBTUtils;
import com.bafomdad.uniquecrops.core.SeedBehavior;
import com.bafomdad.uniquecrops.crops.Feroxia;
import com.bafomdad.uniquecrops.init.UCBlocks;
import com.bafomdad.uniquecrops.init.UCItems;
import com.bafomdad.uniquecrops.items.ItemGeneric;
package com.bafomdad.uniquecrops.events;




public class UCEventHandlerServer {
	
//	private static final String[] ENCHCOST = new String[] { "maximumCost", "field_82854_e", "abf" };
	private int cost;
	private int range = 5;
	
	@SubscribeEvent
	public void updateAnvilCost(AnvilUpdateEvent event) {
		
		ItemStack left = event.getLeft();
		ItemStack right = event.getRight();
		
		if (left == null || right == null)
			return;
		
		if ((left.getItem() == Items.ENCHANTED_BOOK && right.getItem() != Items.ENCHANTED_BOOK) || (left.getItem() != Items.ENCHANTED_BOOK && right.getItem() == Items.ENCHANTED_BOOK))
		{
			ItemStack output = updateRepairOutput(left, right);
			ItemStack toCheck = (left.getItem() != Items.ENCHANTED_BOOK) ? left.copy() : right.copy();
			if (output != null && checkNBT(toCheck))
			{
				int newCost = this.cost;
				if (newCost > 5)
				{
					newCost = newCost - 5;
					event.setOutput(output.copy());
					event.setCost(newCost);
				}
			}
			return;
		}
		else if ((left.getItem() == UCItems.generic && left.getItemDamage() == 18 && right.getItem() instanceof IBookUpgradeable) || (left.getItem() instanceof IBookUpgradeable && right.getItem() == UCItems.generic && right.getItemDamage() == 18))
		{
			ItemStack output = (left.getItem() instanceof IBookUpgradeable) ? left.copy(): right.copy();
			if (output != null) {
				ItemStack newcopy = output.copy();
				if (NBTUtils.getInt(newcopy, ItemGeneric.TAG_UPGRADE, -1) >= 10)
					return;
				
				if (!newcopy.hasTagCompound() || (newcopy.hasTagCompound() && !newcopy.getTagCompound().hasKey(ItemGeneric.TAG_UPGRADE))) {
					NBTUtils.setInt(newcopy, ItemGeneric.TAG_UPGRADE, 1);
				}
				else {
					int upgradelevel = newcopy.getTagCompound().getInteger(ItemGeneric.TAG_UPGRADE);
					NBTUtils.setInt(newcopy, ItemGeneric.TAG_UPGRADE, ++upgradelevel);
				}
				event.setOutput(newcopy);
				event.setCost(5);
			}
			return;
		}
		else if (left.getItem() != null && left.getItem() != null) {
			
			ItemStack output = updateRepairOutput(left, right);
			if (output != null && checkNBT(output)) {
				int newCost = this.cost;
				if (newCost > 5)
				{
					newCost = newCost - 5;
					event.setOutput(output.copy());
					event.setCost(newCost);
				}
			}
		}
	}
	
	@SubscribeEvent
	public void setUpgradeChance(AnvilRepairEvent event) {
		
		ItemStack output = event.getItemResult();
		EntityPlayer player = event.getEntityPlayer();
		if (output == null)
			return;
		if (player == null)
			return;
		
		if (player.worldObj.isRemote)
			return;
		
		if (output.getItem() instanceof IBookUpgradeable) {
			int upgradelevel = NBTUtils.getInt(output, ItemGeneric.TAG_UPGRADE, -1);
			if (upgradelevel == 10) {
				Random rand = new Random();
				if (rand.nextBoolean() == false && !player.worldObj.isRemote) {
					player.addChatMessage(new TextComponentString(TextFormatting.RED + "You attempt to refine this item, but it breaks.."));
					output.stackSize = 0;
				}
			}
		}
	}
	
	@SubscribeEvent
	public void noteBlockPlayEvent(NoteBlockEvent.Play event) {
		
		if (event.getWorld().isRemote)
			return;
		
		BlockPos epos = event.getPos();
		int range = 10;
		for (BlockPos pos : BlockPos.getAllInBoxMutable(epos.add(-range, -2, -range), epos.add(range, 2, range))) {
			TileEntity te = event.getWorld().getTileEntity(pos);
			if (te != null && te instanceof TileMusicaPlant) {
				TileMusicaPlant plant = (TileMusicaPlant)te;
				if (plant.getBeats().size() > 0)
				{
					for (int i = 0; i < plant.getBeats().size(); i++) {
						Beat beat = plant.getBeats().get(i);
						if (beat.beatMatches(new Beat(event.getNote(), event.getInstrument(), event.getOctave(), event.getWorld().getTotalWorldTime()))) {
							plant.setNewBeatTime(i, event.getWorld().getTotalWorldTime());
							return;
						}
					}
				}
				if (plant.canAddNote())
					plant.setNote(event.getNote(), event.getInstrument(), event.getOctave(), event.getWorld().getTotalWorldTime());
			}
		}
	}
	
	@SubscribeEvent
	public void checkHarvestedCrops(BlockEvent.HarvestDropsEvent event) {
		
		Block crop = event.getState().getBlock();
		if (event.getHarvester() != null && event.getHarvester().capabilities.isCreativeMode)
			return;
		
		if (crop == UCBlocks.cropInvisibilia) {
			if (event.getHarvester() == null) 
			{
				event.getDrops().clear();
				event.setResult(Result.DEFAULT);
			}
		}
		if (crop == UCBlocks.cropFeroxia && ((Feroxia)crop).isFullyGrown(event.getWorld(), event.getPos(), event.getState())) {