public bool CraftItem(ExplorerConstants.Items.IDS item)
		{
			//Oops, not a craftable item
			if (!ExplorerConstants.Items.CraftingRecipes.ContainsKey(item))
				return false;

			//First, a quick check for amounts
			if (ExplorerConstants.Items.CraftingRecipes[item].Any(x => ItemAmount(x.Key) < x.Value))
				return false;

			//Now get rid of all the items
			foreach (var craftItem in ExplorerConstants.Items.CraftingRecipes[item])
				RemoveItem(craftItem.Key, craftItem.Value);

			//Get the new item
			GetItem(item, 1);

			return true;
		}
		public bool EquipItem(ExplorerConstants.Items.IDS item)
		{
			if (ItemAmount(item) == 0)
				return false;
			else if (item == equipped)
				return true;	//Just do nothing if it's the same

			//if (inventory.ContainsKey(equipped) && inventory[equipped] > 0 && equipped == ExplorerConstants.Items.IDS.Torch && equippedSteps > 0)
			//	inventory[equipped]--;

			equipped = item;
			//equippedSteps = 0;
			return true;
		}
		public bool ValidLayer(ExplorerConstants.Map.Layers layer)
		{
			return (int)layer >= 0 && (int)layer < ExplorerConstants.Map.MapLayers;
		}
		public bool RemoveItem(ExplorerConstants.Items.IDS item, int amount = 1)
		{
			if (!inventory.ContainsKey(item) || inventory[item] < amount)
				return false;

			inventory[item] -= amount;

			if (ExplorerConstants.Items.AfterUseLeftovers.ContainsKey(item))
				GetItem(ExplorerConstants.Items.AfterUseLeftovers[item].Item1,
					ExplorerConstants.Items.AfterUseLeftovers[item].Item2 * amount);

			return true;
		}
		public ItemBlueprint(ExplorerConstants.Items.IDS id, string displayName, string shorthand, int types, char displayCharacter = '?', int color = 0x0000000, 
			int stamina = 1, int minYield = 1, int maxYield = 1, ExplorerConstants.Map.Layers layer = ExplorerConstants.Map.Layers.ObjectLayer)
		{
			DisplayName = displayName;
			ShorthandName = shorthand;
			DisplayCharacter = displayCharacter;
			Types = types;
			Layer = layer;
			StaminaRequired = stamina;
			MinYield = minYield;
			MaxYield = maxYield;
			ID = id;

			//Assume 0 alpha is actually full alpha
			if (color > 0 && (color >> 24) == 0)
				color += unchecked((int)0xFF000000);

			PixelColor = Color.FromArgb(color);

			CheckAttributes();
		}
		public ExplorerConstants.Items.IDS GetObject(int blockX, int blockY, ExplorerConstants.Map.Layers layer)
		{
			CheckBlock(blockX, blockY);
			CheckLayer(layer);

			return ExplorerConstants.Items.IntToID(worldData[blockX, blockY, (int)layer]);
		}
		public bool CanPutObject(ExplorerConstants.Items.IDS item, int blockX, int blockY)
		{
			if (!ValidBlock(blockX, blockY) || cave)
				return false;

			//It MUST be the top object. For instance, if a statue is currently on grass and then you place a solid
			//block (such as water) underneath it, how does that work? It doesn't
			ExplorerConstants.Items.IDS topObject = GetTopObject(blockX, blockY);
			ItemBlueprint itemInfo = ExplorerConstants.Items.AllBlueprints[item];

			return (itemInfo.CanPlace || ExplorerConstants.Items.Transformations.Where(x => x.Value == item).Any(x => ExplorerConstants.Items.AllBlueprints[x.Key].CanPlace)) && 
				ExplorerConstants.Items.CanReplace(topObject, item);
		}
      public int TransferFromStorage(ExplorerConstants.Items.IDS item, int amount, 
         Dictionary<ExplorerConstants.Items.IDS, int> storage = null)
      {
         if (storage == null)
            storage = this.userStorage;

         return GeneralTransfer(item, amount, storage, inventory);
      }
		//This function will NOT place objects in any of the following: owned acres, caves, the spawn,
		//invalid blocks,
		public bool SafePutCannotOwn(ExplorerConstants.Items.IDS item, int blockX, int blockY)
		{
			Tuple<int, int> acre = ConvertToAcre(blockX, blockY);
			if (!ValidBlock(blockX, blockY) || !ValidAcre(acre.Item1, acre.Item2) ||
				GetOwner(acre.Item1, acre.Item2) != 0 || IsSpawn(acre.Item1, acre.Item2) ||
				IsCaveEntrance(blockX, blockY))
				return false;

			worldData[blockX, blockY, (int)ExplorerConstants.Items.AllBlueprints[item].Layer] = (byte)item;
			return true;
		}
		public bool PutObject(ExplorerConstants.Items.IDS item, int blockX, int blockY)
		{
			if (!CanPutObject(item, blockX, blockY))
				return false;

			int layer = (int)ExplorerConstants.Items.AllBlueprints[item].Layer;

			//Now just set the world data
			worldData[blockX, blockY, layer] = (byte)item;

			if (ExplorerConstants.Items.AllBlueprints[item].ShouldSetMetaTimestamp)
				SetBlockMeta(blockX, blockY, DateTime.Now.Ticks);

			return true;
		}
		public bool ForcePut(ExplorerConstants.Items.IDS item, int blockX, int blockY)
		{
			if (!ValidBlock(blockX, blockY))
				return false;

			worldData[blockX, blockY, (int)ExplorerConstants.Items.AllBlueprints[item].Layer] = (byte)item;
			return true;
		}
		//A nasty function for completely removing whatever was in the given layer at the given position.
		//You're probably looking for something else, like "PickupObject"
		public bool ForceRemoval(ExplorerConstants.Map.Layers layer, int blockX, int blockY)
		{
			if (!ValidBlock(blockX, blockY) || !ValidLayer(layer))
				return false;

			worldData[blockX, blockY, (int)layer] = 0;
			return true;
		}
		//This will not throw any exceptions, so if you're accessing bad areas, you'll get default data.
		//This may not be what you want; suggest using the safe version in order to catch bad accesses.
		public ExplorerConstants.Items.IDS GetObjectUnsafe(int blockX, int blockY, ExplorerConstants.Map.Layers layer)
		{
			if (ValidBlock(blockX, blockY))
				return ExplorerConstants.Items.IntToID(worldData[blockX, blockY, (int)layer]);
			else
				return ExplorerConstants.Items.IDS.Empty;
		}
		public int ItemAmount(ExplorerConstants.Items.IDS item)
		{
			if (!inventory.ContainsKey(item))
				return 0;

			return inventory[item];
		}
		public bool IsClose(ExplorerConstants.Items.IDS item, int blockX, int blockY)
		{
			for (int i = -1; i <= 1; i++)
			{
				for (int j = -1; j <= 1; j++)
				{
					if (ValidBlock(blockX + i, blockY + j) && GetObject(blockX + i, blockY + j, ExplorerConstants.Items.AllBlueprints[item].Layer) == item)
						return true;
				}
			}

			return false;
		}
      /// <summary>
      /// Transfer FROM bank1 INTO bank2
      /// </summary>
      /// <returns><c>true</c>, if transfer was generaled, <c>false</c> otherwise.</returns>
      /// <param name="item">Item.</param>
      /// <param name="amount">Amount.</param>
      /// <param name="bank1">Bank1.</param>
      /// <param name="bank2">Bank2.</param>
      private static int GeneralTransfer(ExplorerConstants.Items.IDS item, int amount,
         Dictionary<ExplorerConstants.Items.IDS, int> bank1,
         Dictionary<ExplorerConstants.Items.IDS, int> bank2)
      {
         //Make sure both the storage and inventory have the item in question.
         if (!bank1.ContainsKey(item))
            bank1.Add(item, 0);
         if (!bank2.ContainsKey(item))
            bank2.Add(item, 0);

         //Can't transfer what you don't have.
         if(bank1[item] < 1)
            return -1;

         amount = Math.Min(amount, bank1[item]);

         bank1[item] -= amount;
         bank2[item] += amount;

         return amount;
             }
		public Tuple<int, int> FindFirstItem(ExplorerConstants.Items.IDS item, int acreX, int acreY)
		{
			Tuple<int, int> location = Tuple.Create(-1, -1);

			if (ValidAcre(acreX, acreY))
			{
				for (int i = ExplorerConstants.Map.AcreWidth - 1; i >= 0; i--)
				{
					for (int j = ExplorerConstants.Map.AcreHeight - 1; j >= 0; j--)
					{
						int x = acreX * ExplorerConstants.Map.AcreWidth + i;
						int y = acreY * ExplorerConstants.Map.AcreHeight + j;
						if (GetObject(x, y, ExplorerConstants.Items.AllBlueprints[item].Layer) == item)
							location = Tuple.Create(x, y);
					}
				}
			}

			return location;
		}
		//The amount is taken care of automatically
		private void GetItem(ExplorerConstants.Items.IDS ID, int forceAmount = 0)
		{
			ItemBlueprint itemInfo = ExplorerConstants.Items.AllBlueprints[ID];
			int amount = itemInfo.MinYield + random.Next(1 + itemInfo.MaxYield - itemInfo.MinYield);

			//Even if I accidentally call this function for unobtainable items, it
			//STILL won't give you the item
			if (!itemInfo.CanObtain)
				return;

			if(!materialsCollected.ContainsKey(ID))
				materialsCollected.Add(ID, 0);
			if(!inventory.ContainsKey(ID))
				inventory.Add(ID, 0);

			if (forceAmount > 0)
				amount = forceAmount;

			materialsCollected[ID] += amount;
			inventory[ID] += amount;

			//Get extra items if necessary. This also chains?
			if(ExplorerConstants.Items.GetExtra.ContainsKey(ID))
			{
				var info = ExplorerConstants.Items.GetExtra[ID];
				GetItem(info.Item1, info.Item2 + random.Next(1 + info.Item3 - info.Item2));
			}
		}
		public void GetAcreLightMap(int acreX, int acreY, byte[,] lightMap, Tuple<int, int> extraLightSourceLocation, ExplorerConstants.Items.IDS extraLightSource = ExplorerConstants.Items.IDS.Torch, bool doublePass = false)
		{
			//Assume infinitely dark (for caves)
			byte overallLevel = (byte)ExplorerConstants.Light.Levels.FullDark;
			int acresAcross = lightMap.GetLength(0) / ExplorerConstants.Map.AcreWidth;
			int acresDown = lightMap.GetLength(1) / ExplorerConstants.Map.AcreHeight;

			//If it's not a cave, increase the light level depending on the time of day
			if (!cave)
			{
				if (worldTime.TotalHours >= 23 || worldTime.TotalHours < 3)
					overallLevel = (byte)ExplorerConstants.Light.Levels.FullDark;
				else if (worldTime.TotalHours >= 20 || worldTime.TotalHours < 6)
					overallLevel = (byte)ExplorerConstants.Light.Levels.HalfLight;
				else
					overallLevel = (byte)ExplorerConstants.Light.Levels.FullLight;
			}

			for (int i = lightMap.GetLength(0) - 1; i >= 0; --i)
				for (int j = lightMap.GetLength(1) - 1; j >= 0; --j)
					lightMap[i, j] = overallLevel;

			//We're working with just two (no, actually one) light level for now. This may change later
			for (int i = 0; i < (doublePass ? 2 : 1); i++)
			{
				float fullness = 1.0f;
				byte lightLevel = (byte)(doublePass ? ExplorerConstants.Light.Levels.HalfLight : ExplorerConstants.Light.Levels.FullLight);

				if (i == 1)
				{
					fullness = ExplorerConstants.Light.LightReduction;
					lightLevel = (byte)ExplorerConstants.Light.Levels.FullLight;
				}

				if (lightLevel > overallLevel)
				{
					for (int acreI = -1; acreI < acresAcross + 1; acreI++)
					{
						for (int acreJ = -1; acreJ < acresDown + 1; acreJ++)
						{
							for (int blockX = 0; blockX < ExplorerConstants.Map.AcreWidth; blockX++)
							{
								for (int blockY = 0; blockY < ExplorerConstants.Map.AcreHeight; blockY++)
								{
									ExplorerConstants.Items.IDS ID = GetObjectUnsafe((acreX + acreI) * ExplorerConstants.Map.AcreWidth + blockX, (acreY + acreJ) * ExplorerConstants.Map.AcreHeight + blockY, ExplorerConstants.Map.Layers.ObjectLayer);

									//WARNING! If any light sources can be stood on, this will OVERWRITE them with the given
									//light source! Use with caution!
									if (acreI == 0 && acreJ == 0 && blockX == extraLightSourceLocation.Item1 && blockY == extraLightSourceLocation.Item2)
										ID = extraLightSource;

									if (ExplorerConstants.Light.Sources.ContainsKey(ID))
									{
										float sourceWidth = (int)(ExplorerConstants.Light.Sources[ID] * fullness);
										for (int x = -(int)(sourceWidth / 2); x <= (int)(sourceWidth / 2); x++)
										{
											for (int y = -(int)(sourceWidth / 2); y <= (int)(sourceWidth / 2); y++)
											{
												if((Math.Pow(x, 2) + Math.Pow(y, 2)) <= Math.Pow(sourceWidth / 2, 2))
												{
													int realX = (blockX + acreI * ExplorerConstants.Map.AcreWidth) + x;
													int realY = (blockY + acreJ * ExplorerConstants.Map.AcreWidth) + y;

													if (realX >= 0 && realY >= 0 && realX < lightMap.GetLength(0) && realY < lightMap.GetLength(1))
														lightMap[realX, realY] = lightLevel;
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
		private bool ShouldSpawn(double mapData, ExplorerConstants.Generation.GenerationData data)//double sparseness, double curve, double lowestValue, double range, bool inverted)
		{
			/*Math.Pow(random.NextDouble(), data.Curve)*/
			//MathExtensions.ExponentialRandomFinite(data.Curve, random)
			bool curveSpawn = true;

			if (data.Curve != 0)
			{
				if (data.Inverted)
					curveSpawn = random.NextDouble() < (1 - Math.Pow(((mapData - data.Lower) / data.Range), 1 / data.Curve));
				else if (!data.Inverted)
					curveSpawn = random.NextDouble() < Math.Pow(((mapData - data.Lower) / data.Range), data.Curve);
			}

			return curveSpawn && random.NextDouble() < data.Sparseness;
		}
		public void CheckLayer(ExplorerConstants.Map.Layers layer)
		{
			if (!ValidLayer(layer))
				throw new Exception("Cannot retrieve this layer: " + layer);
		}