context: #region Header
  // **********
  // ServUO - CraftItem.cs
  // **********
  #endregion
  
  #region References
  using System;
  using System.Collections.Generic;
  using System.Collections;
  using Server.Commands;
  using Server.Engines.Plants;
  using Server.Factions;
  using Server.Items;
  using Server.Mobiles;
  using Server.Engines.Quests;
  using daat99;
  #endregion
  
  namespace Server.Engines.Craft
  {
  	public enum ConsumeType
  	{
  		All,
  		Half,
  		None
  	}
  
  	public interface ICraftable
  	{
  		int OnCraft(
  			int quality,
  			bool makersMark,
  			Mobile from,
  			CraftSystem craftSystem,
  			Type typeRes,
  			BaseTool tool,
  			CraftItem craftItem,
  			int resHue);
  	}
  
  	public class CraftItem
  	{
  		private readonly CraftResCol m_arCraftRes;
  		private readonly CraftSkillCol m_arCraftSkill;
  		private readonly Type m_Type;
          public double MinSkillOffset { get; set; }
  
  		private readonly string m_GroupNameString;
  		private readonly int m_GroupNameNumber;
  
  		private readonly string m_NameString;
  		private readonly int m_NameNumber;
  
  		private BeverageType m_RequiredBeverage;
  
  		private bool m_NeedHeat;
  		private bool m_NeedOven;
  		private bool m_NeedMill;
  
  		private bool m_UseSubRes2;
  
  		private bool m_ForceNonExceptional;
  
  		public bool ForceNonExceptional { get { return m_ForceNonExceptional; } set { m_ForceNonExceptional = value; } }
  
  		public Expansion RequiredExpansion { get; set; }
  
          #region SA
          public bool RequiresBasketWeaving { get; set; }
          public bool RequiresResTarget { get; set; }
          public bool RequiresMechanicalLife { get; set; }
          #endregion
  
          #region TOL
          private object m_Data;
          private int m_DisplayID;
  
          public object Data
          {
              get { return m_Data; }
              set { m_Data = value; }
          }
  
          public int DisplayID
          {
              get { return m_DisplayID; }
              set { m_DisplayID = value; }
          }
          #endregion
  
          private Recipe m_Recipe;
  
  		public Recipe Recipe { get { return m_Recipe; } }
  
  		public void AddRecipe(int id, CraftSystem system)
  		{
  			if (m_Recipe != null)
  			{
  				Console.WriteLine(
  					"Warning: Attempted add of recipe #{0} to the crafting of {1} in CraftSystem {2}.", id, m_Type.Name, system);
  				return;
  			}
  
  			m_Recipe = new Recipe(id, system, this);
  		}
  
  		private static readonly Dictionary<Type, int> _itemIds = new Dictionary<Type, int>();
  
  		public static int ItemIDOf(Type type)
  		{
  			int itemId;
  
  			if (!_itemIds.TryGetValue(type, out itemId))
  			{
  				if (type == typeof(FactionExplosionTrap))
  				{
  					itemId = 14034;
  				}
  				else if (type == typeof(FactionGasTrap))
  				{
  					itemId = 4523;
  				}
  				else if (type == typeof(FactionSawTrap))
  				{
  					itemId = 4359;
  				}
  				else if (type == typeof(FactionSpikeTrap))
  				{
  					itemId = 4517;
  				}
  					#region Mondain's Legacy
  				else if (type == typeof(ArcaneBookshelfSouthDeed))
  				{
  					itemId = 0x2DEF;
  				}
  				else if (type == typeof(ArcaneBookshelfEastDeed))
  				{
  					itemId = 0x2DF0;
  				}
  				else if (type == typeof(OrnateElvenChestSouthDeed))
  				{
  					itemId = 0x2DE9;
  				}
  				else if (type == typeof(OrnateElvenChestEastDeed))
  				{
  					itemId = 0x2DEA;
  				}
  				else if (type == typeof(ElvenWashBasinSouthDeed) ||
  					type == typeof(ElvenWashBasinSouthAddonWithDrawer))
  				{
  					itemId = 0x2D0B;
  				}
  				else if (type == typeof(ElvenWashBasinEastDeed) ||
  					type == typeof(ElvenWashBasinEastAddonWithDrawer))
  				{
  					itemId = 0x2D0C;
  				}
  				else if (type == typeof(ElvenDresserSouthDeed))
  				{
  					itemId = 0x2D09;
  				}
  				else if (type == typeof(ElvenDresserEastDeed))
  				{
  					itemId = 0x2D0A;
  				}
  				#endregion
  
  				if (itemId == 0)
  				{
  					var attrs = type.GetCustomAttributes(typeof(CraftItemIDAttribute), false);
  
  					if (attrs.Length > 0)
  					{
  						CraftItemIDAttribute craftItemID = (CraftItemIDAttribute)attrs[0];
  						itemId = craftItemID.ItemID;
  					}
  				}
  
  				if (itemId == 0)
  				{
  					Item item = null;
  
  					try
  					{
  						item = Activator.CreateInstance(type) as Item;
  					}
  					catch
  					{ }
  
  					if (item != null)
  					{
  						itemId = item.ItemID;
  						item.Delete();
  					}
  				}
  
  				_itemIds[type] = itemId;
  			}
  
  			return itemId;
  		}
  
  		public CraftItem(Type type, TextDefinition groupName, TextDefinition name)
  		{
  			m_arCraftRes = new CraftResCol();
  			m_arCraftSkill = new CraftSkillCol();
  
  			m_Type = type;
  
  			m_GroupNameString = groupName;
  			m_NameString = name;
  
  			m_GroupNameNumber = groupName;
  			m_NameNumber = name;
  
  			m_RequiredBeverage = BeverageType.Water;
  		}
  
  		public BeverageType RequiredBeverage { get { return m_RequiredBeverage; } set { m_RequiredBeverage = value; } }
  
  		public void AddRes(Type type, TextDefinition name, int amount)
  		{
  			AddRes(type, name, amount, "");
  		}
  
  		public void AddRes(Type type, TextDefinition name, int amount, TextDefinition message)
  		{
  			CraftRes craftRes = new CraftRes(type, name, amount, message);
  			m_arCraftRes.Add(craftRes);
  		}
  
  		public void AddSkill(SkillName skillToMake, double minSkill, double maxSkill)
  		{
  			CraftSkill craftSkill = new CraftSkill(skillToMake, minSkill, maxSkill);
  			m_arCraftSkill.Add(craftSkill);
  		}
  
  		public int Mana { get; set; }
  		public int Hits { get; set; }
  		public int Stam { get; set; }
  		public bool UseSubRes2 { get { return m_UseSubRes2; } set { m_UseSubRes2 = value; } }
  		public bool UseAllRes { get; set; }
  		public bool ForceTypeRes { get; set; }
  		public bool NeedHeat { get { return m_NeedHeat; } set { m_NeedHeat = value; } }
  		public bool NeedOven { get { return m_NeedOven; } set { m_NeedOven = value; } }
  		public bool NeedMill { get { return m_NeedMill; } set { m_NeedMill = value; } }
  		public Type ItemType { get { return m_Type; } }
  		public int ItemHue { get; set; }
  		public string GroupNameString { get { return m_GroupNameString; } }
  		public int GroupNameNumber { get { return m_GroupNameNumber; } }
  		public string NameString { get { return m_NameString; } }
  		public int NameNumber { get { return m_NameNumber; } }
  		public CraftResCol Resources { get { return m_arCraftRes; } }
  		public CraftSkillCol Skills { get { return m_arCraftSkill; } }
  
  		public bool ConsumeAttributes(Mobile from, ref object message, bool consume)
  		{
  			bool consumMana = false;
  			bool consumHits = false;
  			bool consumStam = false;
  
  			if (Hits > 0 && from.Hits < Hits)
  			{
  				message = "You lack the required hit points to make that.";
  				return false;
  			}
  			else
  			{
  				consumHits = consume;
  			}
  
  			if (Mana > 0)
  			{
                  if (ManaPhasingOrb.IsInManaPhase(from))
                  {
                      if (consume)
                          ManaPhasingOrb.RemoveFromTable(from);
                      return true;
                  }
  
                  if (from.Mana < Mana)
                  {
                      message = "You lack the required mana to make that.";
                      return false;
                  }
  				else
  				{
  					consumMana = consume;
  				}
  			}
  
  
  			if (Stam > 0 && from.Stam < Stam)
  			{
  				message = "You lack the required stamina to make that.";
  				return false;
  			}
  			else
  			{
  				consumStam = consume;
  			}
  
  			if (consumMana)
  			{
  				from.Mana -= Mana;
  			}
  
  			if (consumHits)
  			{
  				from.Hits -= Hits;
  			}
  
  			if (consumStam)
  			{
  				from.Stam -= Stam;
  			}
  
  			return true;
  		}
  
  		#region Tables
  		private static readonly int[] m_HeatSources = new[]
  		{
  			0x461, 0x48E, // Sandstone oven/fireplace
  			0x92B, 0x96C, // Stone oven/fireplace
  			0xDE3, 0xDE9, // Campfire
  			0xFAC, 0xFAC, // Firepit
  			0x184A, 0x184C, // Heating stand (left)
  			0x184E, 0x1850, // Heating stand (right)
  			0x398C, 0x399F, // Fire field
  			0x2DDB, 0x2DDC, //Elven stove
  			0x19AA, 0x19BB, // Veteran Reward Brazier
  			0x197A, 0x19A9, // Large Forge 
  			0x0FB1, 0x0FB1, // Small Forge
  			0x2DD8, 0x2DD8 // Elven Forge
  		};
  
  		private static readonly int[] m_Ovens = new[]
  		{
  			0x461, 0x46F, // Sandstone oven
  			0x92B, 0x93F, // Stone oven
  			0x2DDB, 0x2DDC //Elven stove
  		};
  
  		private static readonly int[] m_Mills = new[]
  		{
  			0x1920, 0x1921, 0x1922, 0x1923, 0x1924, 0x1295, 0x1926, 0x1928, 0x192C, 0x192D, 0x192E, 0x129F, 0x1930, 0x1931,
  			0x1932, 0x1934
  		};
  
          private static Type[][] m_TypesTable = daat99.ResourceHelper.GetTypesTable(); //daat99 OWLTR
  
  		private static readonly Type[] m_ColoredItemTable = new[]
  		{
  			#region Mondain's Legacy
  			typeof(BaseContainer), typeof(ParrotPerchAddonDeed),
  			#endregion
  
  			typeof(BaseWeapon), typeof(BaseArmor), typeof(BaseClothing), typeof(BaseJewel), typeof(DragonBardingDeed),
  			typeof(BaseAddonDeed), typeof(BaseAddon),
  
              #region Stygian Abyss
              typeof(PlantPigment), typeof(SoftenedReeds), typeof(DryReeds), typeof(PlantClippings),
              typeof(MedusaLightScales), typeof(MedusaDarkScales)
              #endregion
  			//daat99 OWLTR start - colored containers
  			, typeof( BaseContainer )
  			//daat99 OWLTR end - colored containers
  		};
  
  		private static readonly Type[] m_ColoredResourceTable = new[]
  		{
  			#region Mondain's Legacy
  			typeof(Board), typeof(Log),
  			#endregion
  			typeof(BaseIngot), typeof(BaseOre), typeof(BaseLeather), typeof(BaseHides), typeof(AbyssalCloth), typeof(UncutCloth), typeof(Cloth),
  			typeof(BaseGranite), typeof(BaseScales), typeof(PlantClippings), typeof(DryReeds), typeof(SoftenedReeds),
  			typeof(PlantPigment), typeof(BaseContainer)
  		};
  
  		private static readonly Type[] m_MarkableTable = new[]
  		{
  			#region Mondain's Legacy
  			typeof(BlueDiamondRing), typeof(BrilliantAmberBracelet), typeof(DarkSapphireBracelet), typeof(EcruCitrineRing),
  			typeof(FireRubyBracelet), typeof(PerfectEmeraldRing), typeof(TurqouiseRing), typeof(WhitePearlBracelet),
  			typeof(BaseContainer), typeof(CraftableFurniture),
  			#endregion
  
  			typeof(BaseArmor), typeof(BaseWeapon), typeof(BaseClothing), typeof(BaseInstrument), typeof(BaseTool),
  			typeof(BaseHarvestTool), typeof(BaseQuiver), typeof(DragonBardingDeed), typeof(Fukiya), typeof(FukiyaDarts),
  			typeof(Shuriken), typeof(Spellbook), typeof(Runebook), typeof(ShortMusicStand), typeof(TallMusicStand),
  			typeof(RedHangingLantern), typeof(WhiteHangingLantern), typeof(BambooScreen), typeof(ShojiScreen), typeof(Easle),
  			typeof(FishingPole), typeof(Stool), typeof(FootStool), typeof(WoodenBench), typeof(WoodenThrone), typeof(Throne),
  			typeof(BambooChair), typeof(WoodenChair), typeof(FancyWoodenChairCushion), typeof(WoodenChairCushion),
  			typeof(Nightstand), typeof(LargeTable), typeof(WritingTable), typeof(YewWoodTable), typeof(PlainLowTable),
  			typeof(ElegantLowTable), typeof(Dressform), typeof(BasePlayerBB), typeof(BaseContainer), typeof(BarrelStaves),
  			typeof(BarrelLid), typeof(Clippers)
  		};
  
  		private static readonly Dictionary<Type, Type> m_ResourceConversionTable = new Dictionary<Type, Type>()
  		{
  			{ typeof(Board), typeof(Log) },
  			{ typeof(HeartwoodBoard), typeof(HeartwoodLog) },
  			{ typeof(BloodwoodBoard), typeof(BloodwoodLog) },
  			{ typeof(FrostwoodBoard), typeof(FrostwoodLog) },
  			{ typeof(OakBoard), typeof(OakLog) },
  			{ typeof(AshBoard), typeof(AshLog) },
  			{ typeof(YewBoard), typeof(YewLog) },
  			//Daat99 Woods
  			{ typeof(EbonyBoard), typeof(EbonyLog) },
  			{ typeof(BambooBoard), typeof(BambooLog) },
  			{ typeof(PurpleHeartBoard), typeof(PurpleHeartLog) },
  			{ typeof(RedwoodBoard), typeof(RedwoodLog) },
  			{ typeof(PetrifiedBoard), typeof(PetrifiedLog) },
  			//Daat99 End
  			{ typeof(Leather), typeof(Hides) },
  			{ typeof(SpinedLeather), typeof(SpinedHides) },
  			{ typeof(HornedLeather), typeof(HornedHides) },
  			{ typeof(BarbedLeather), typeof(BarbedHides) },
  			//Daat 99 Leathers
  			{ typeof(PolarLeather), typeof(PolarHides) },
  			{ typeof(SyntheticLeather), typeof(SyntheticHides) },
  			{ typeof(BlazeLeather), typeof(BlazeHides) },
  			{ typeof(DaemonicLeather), typeof(DaemonicHides) },
  			{ typeof(ShadowLeather), typeof(ShadowHides) },
  			{ typeof(FrostLeather), typeof(FrostHides) },
  			{ typeof(EtherealLeather), typeof(EtherealHides) },
  		};
  
  		private static Type[] m_NeverColorTable = new[] {typeof(OrcHelm)};
  		#endregion
  
  		public bool IsMarkable(Type type)
  		{
  			if (m_ForceNonExceptional) //Don't even display the stuff for marking if it can't ever be exceptional.
  			{
  				return false;
  			}
  
  			for (int i = 0; i < m_MarkableTable.Length; ++i)
  			{
  				if (type == m_MarkableTable[i] || type.IsSubclassOf(m_MarkableTable[i]))
  				{
  					return true;
  				}
  			}
  
  			return false;
  		}
  
  		public static bool RetainsColor(Type type)
  		{
  			bool inItemTable = false;
  
  			for (int i = 0; !inItemTable && i < m_ColoredItemTable.Length; ++i)
  			{
  				inItemTable = (type == m_ColoredItemTable[i] || type.IsSubclassOf(m_ColoredItemTable[i]));
  			}
  
  			return inItemTable;
  		}
  
  		public bool RetainsColorFrom(CraftSystem system, Type type)
  		{
  			if (system.RetainsColorFrom(this, type))
  			{
  				return true;
  			}
  
  			bool inItemTable = false, inResourceTable = false;
  
  			for (int i = 0; !inItemTable && i < m_ColoredItemTable.Length; ++i)
  			{
  				inItemTable = (m_Type == m_ColoredItemTable[i] || m_Type.IsSubclassOf(m_ColoredItemTable[i]));
  			}
  
  			for (int i = 0; inItemTable && !inResourceTable && i < m_ColoredResourceTable.Length; ++i)
  			{
  				inResourceTable = (type == m_ColoredResourceTable[i] || type.IsSubclassOf(m_ColoredResourceTable[i]));
  			}
  
  			return (inItemTable && inResourceTable);
  		}
  
  		public bool Find(Mobile from, int[] itemIDs)
  		{
  			Map map = from.Map;
  
  			if (map == null)
  			{
  				return false;
  			}
  
  			IPooledEnumerable eable = map.GetItemsInRange(from.Location, 2);
  
  			foreach (Item item in eable)
  			{
  				if ((item.Z + 16) > from.Z && (from.Z + 16) > item.Z && Find(item.ItemID, itemIDs))
  				{
  					eable.Free();
  					return true;
  				}
  			}
  
  			eable.Free();
  
  			for (int x = -2; x <= 2; ++x)
  			{
  				for (int y = -2; y <= 2; ++y)
  				{
  					int vx = from.X + x;
  					int vy = from.Y + y;
  
  					var tiles = map.Tiles.GetStaticTiles(vx, vy, true);
  
  					for (int i = 0; i < tiles.Length; ++i)
  					{
  						int z = tiles[i].Z;
  						int id = tiles[i].ID;
  
  						if ((z + 16) > from.Z && (from.Z + 16) > z && Find(id, itemIDs))
  						{
  							return true;
  						}
  					}
  				}
  			}
  
  			return false;
  		}
  
  		public bool Find(int itemID, int[] itemIDs)
  		{
  			bool contains = false;
  
  			for (int i = 0; !contains && i < itemIDs.Length; i += 2)
  			{
  				contains = (itemID >= itemIDs[i] && itemID <= itemIDs[i + 1]);
  			}
  
  			return contains;
  		}
  
  		public bool IsQuantityType(Type[][] types)
  		{
  			for (int i = 0; i < types.Length; ++i)
  			{
  				var check = types[i];
  
  				for (int j = 0; j < check.Length; ++j)
  				{
  					if (typeof(IHasQuantity).IsAssignableFrom(check[j]))
  					{
  						return true;
  					}
  				}
  			}
  
  			return false;
  		}
  
          #region SA
          public bool IsPlantHueType(Type[][] types)
          {
              for (int i = 0; i < types.Length; ++i)
              {
                  Type[] check = types[i];
  
                  for (int j = 0; j < check.Length; ++j)
                  {
                      if (typeof(IPlantHue).IsAssignableFrom(check[j]))
                          return true;
                      else if (typeof(IPigmentHue).IsAssignableFrom(check[j]))
                          return true;
                  }
              }
  
              return false;
          }
  
          public int ConsumeQuantityByPlantHue(Mobile from, CraftSystem craftSystem, Container cont, Type[][] types, int[] amounts)
          {
              if (types.Length != amounts.Length)
                  throw new ArgumentException();
  
              CraftContext context = craftSystem.GetContext(from);
  
              if (context == null)
                  return 0;
  
              Item[][] items = new Item[types.Length][];
              int[] totals = new int[types.Length];
  
              for (int i = 0; i < types.Length; ++i)
              {
                  items[i] = cont.FindItemsByType(types[i], true);
  
                  for (int j = 0; j < items[i].Length; ++j)
                  {
                      IPlantHue plantHue = items[i][j] as IPlantHue;
                      IPigmentHue pigmentHue = items[i][j] as IPigmentHue;
  
                      if (plantHue != null && plantHue.PlantHue != context.RequiredPlantHue)
                          continue;
                      else if (pigmentHue != null && pigmentHue.PigmentHue != context.RequiredPigmentHue)
                          continue;
  
                      totals[i] += items[i][j].Amount;
                  }
  
                  if (totals[i] < amounts[i])
                      return i;
              }
  
              for (int i = 0; i < types.Length; ++i)
              {
                  int need = amounts[i];
  
                  for (int j = 0; j < items[i].Length; ++j)
                  {
                      Item item = items[i][j];
                      IPlantHue ph = item as IPlantHue;
                      IPigmentHue pigh = item as IPigmentHue;
  
                      int theirAmount = item.Amount;
  
                      if (ph != null && ph.PlantHue != context.RequiredPlantHue)
                          continue;
                      else if (pigh != null && pigh.PigmentHue != context.RequiredPigmentHue)
                          continue;
  
                      if (theirAmount < need)
                      {
                          OnResourceConsumed(item, theirAmount);
  
                          item.Delete();
                          need -= theirAmount;
                      }
                      else
                      {
                          OnResourceConsumed(item, need);
  
                          item.Consume(need);
                          break;
                      }
                  }
              }
  
              return -1;
          }
          #endregion
  
  		public int ConsumeQuantity(Container cont, Type[][] types, int[] amounts)
  		{
  			if (types.Length != amounts.Length)
  			{
  				throw new ArgumentException();
  			}
  
  			var items = new Item[types.Length][];
  			var totals = new int[types.Length];
  
  			for (int i = 0; i < types.Length; ++i)
  			{
  				items[i] = cont.FindItemsByType(types[i], true);
  
  				for (int j = 0; j < items[i].Length; ++j)
  				{
  					IHasQuantity hq = items[i][j] as IHasQuantity;
  
  					if (hq == null)
  					{
  						totals[i] += items[i][j].Amount;
  					}
  					else
  					{
  						if (hq is BaseBeverage && ((BaseBeverage)hq).Content != m_RequiredBeverage)
  						{
  							continue;
  						}
  
  						totals[i] += hq.Quantity;
  					}
  				}
  
  				if (totals[i] < amounts[i])
  				{
  					return i;
  				}
  			}
  
  			for (int i = 0; i < types.Length; ++i)
  			{
  				int need = amounts[i];
  
  				for (int j = 0; j < items[i].Length; ++j)
  				{
  					Item item = items[i][j];
  					IHasQuantity hq = item as IHasQuantity;
  
  					if (hq == null)
  					{
  						int theirAmount = item.Amount;
  
  						if (theirAmount < need)
  						{
  							item.Delete();
  							need -= theirAmount;
  						}
  						else
  						{
  							item.Consume(need);
  							break;
  						}
  					}
  					else
  					{
  						if (hq is BaseBeverage && ((BaseBeverage)hq).Content != m_RequiredBeverage)
  						{
  							continue;
  						}
  
  						int theirAmount = hq.Quantity;
  
  						if (theirAmount < need)
  						{
  							hq.Quantity -= theirAmount;
  							need -= theirAmount;
  						}
  						else
  						{
  							hq.Quantity -= need;
  							break;
  						}
  					}
  				}
  			}
  
  			return -1;
  		}
  
  		public int GetQuantity(Container cont, Type[] types)
  		{
  			var items = cont.FindItemsByType(types, true);
  
  			int amount = 0;
  
  			for (int i = 0; i < items.Length; ++i)
  			{
  				IHasQuantity hq = items[i] as IHasQuantity;
  
  				if (hq == null)
  				{
  					amount += items[i].Amount;
  				}
  				else
  				{
  					if (hq is BaseBeverage && ((BaseBeverage)hq).Content != m_RequiredBeverage)
  					{
  						continue;
  					}
  
  					amount += hq.Quantity;
  				}
  			}
  
  			return amount;
  		}
  
          #region SA
          public int GetPlantHueAmount(Mobile from, CraftSystem craftSystem, Container cont, Type[] types)
          {
              Item[] items = cont.FindItemsByType(types, true);
              CraftContext context = craftSystem.GetContext(from);
  
              int amount = 0;
  
              for (int i = 0; i < items.Length; ++i)
              {
                  IPlantHue ph = items[i] as IPlantHue;
                  IPigmentHue pigh = items[i] as IPigmentHue;
  
                  if (context == null || (ph != null && ph.PlantHue != context.RequiredPlantHue))
                      continue;
                  else if (context == null || (pigh != null && pigh.PigmentHue != context.RequiredPigmentHue))
                      continue;
  
                  amount += items[i].Amount;
              }
  
              return amount;
          }
          #endregion
  
  		public bool ConsumeRes(
  			Mobile from,
  			Type typeRes,
  			CraftSystem craftSystem,
  			ref int resHue,
  			ref int maxAmount,
  			ConsumeType consumeType,
  			ref object message)
  		{
  			return ConsumeRes(from, typeRes, craftSystem, ref resHue, ref maxAmount, consumeType, ref message, false);
  		}
  
  		public bool ConsumeRes(
  			Mobile from,
  			Type typeRes,
  			CraftSystem craftSystem,
  			ref int resHue,
  			ref int maxAmount,
  			ConsumeType consumeType,
  			ref object message,
  			bool isFailure)
  		{
  			Container ourPack = from.Backpack;
  
  			if (ourPack == null)
  			{
  				return false;
  			}
  
  			if (m_NeedHeat && !Find(from, m_HeatSources))
  			{
  				message = 1044487; // You must be near a fire source to cook.
  				return false;
  			}
  
  			if (m_NeedOven && !Find(from, m_Ovens))
  			{
  				message = 1044493; // You must be near an oven to bake that.
  				return false;
  			}
  
  			if (m_NeedMill && !Find(from, m_Mills))
  			{
  				message = 1044491; // You must be near a flour mill to do that.
  				return false;
  			}
  
  			var types = new Type[m_arCraftRes.Count][];
  			var amounts = new int[m_arCraftRes.Count];
  
  			maxAmount = int.MaxValue;
  
  			CraftSubResCol resCol = (m_UseSubRes2 ? craftSystem.CraftSubRes2 : craftSystem.CraftSubRes);
  
  			for (int i = 0; i < types.Length; ++i)
  			{
  				CraftRes craftRes = m_arCraftRes.GetAt(i);
  				Type baseType = craftRes.ItemType;
  
  				if (typeRes != null && ForceTypeRes)
  				{
  					Type outType;
  					if (m_ResourceConversionTable.TryGetValue(typeRes, out outType))
  						baseType = outType;
  				}
  
  				// Resource Mutation
  				if ((baseType == resCol.ResType) && (typeRes != null))
  				{
  					baseType = typeRes;
  
  					CraftSubRes subResource = resCol.SearchFor(baseType);
  
  					if (subResource != null && from.Skills[craftSystem.MainSkill].Base < subResource.RequiredSkill)
  					{
  						message = subResource.Message;
  						return false;
  					}
  				}
  				// ******************
  
  				for (int j = 0; types[i] == null && j < m_TypesTable.Length; ++j)
  				{
  					if (m_TypesTable[j][0] == baseType)
  					{
  						types[i] = m_TypesTable[j];
  					}
  				}
  
  				if (types[i] == null)
  				{
  					types[i] = new[] {baseType};
  				}
  
  				amounts[i] = craftRes.Amount;
  
  				// For stackable items that can ben crafted more than one at a time
  				if (UseAllRes)
  				{
  					int tempAmount = ourPack.GetAmount(types[i]);
                      //daat99 OWLTR start - craft from storage
                      ulong amount = 0;
                      for (int j = 0; j < types[i].Length && amount <= (ulong)amounts[i]; ++j)
                      {
                          amount = MasterStorageUtils.GetPlayersStorageItemCount(from as PlayerMobile, types[i][j]);
                      }
                      if (amount > int.MaxValue || amount + (ulong)tempAmount > int.MaxValue)
                          tempAmount = int.MaxValue;
                      else
                          tempAmount = tempAmount + (int)amount;
                      tempAmount = Math.Min(100, tempAmount /= amounts[i]); //limit "craft all" to 100 items.
                      //daat99 OWLTR end - craft from storage
  					tempAmount /= amounts[i];
  					if (tempAmount < maxAmount)
  					{
  						maxAmount = tempAmount;
  
  						if (maxAmount == 0)
  						{
  							CraftRes res = m_arCraftRes.GetAt(i);
  
  							if (res.MessageNumber > 0)
  							{
  								message = res.MessageNumber;
  							}
  							else if (!String.IsNullOrEmpty(res.MessageString))
  							{
  								message = res.MessageString;
  							}
  							else
  							{
  								message = 502925; // You don't have the resources required to make that item.
  							}
  
  							return false;
  						}
  					}
  				}
  				// ****************************
  
  				if (isFailure && !craftSystem.ConsumeOnFailure(from, types[i][0], this))
  				{
  					amounts[i] = 0;
  				}
  			}
  
  			// We adjust the amount of each resource to consume the max posible
  			if (UseAllRes)
  			{
  				for (int i = 0; i < amounts.Length; ++i)
  				{
  					amounts[i] *= maxAmount;
  				}
  			}
  			else
  			{
  				maxAmount = -1;
  			}
  
  			Item consumeExtra = null;
  
  			if (m_NameNumber == 1041267)
  			{
  				// Runebooks are a special case, they need a blank recall rune
  				var runes = ourPack.FindItemsByType<RecallRune>();
  
  				for (int i = 0; i < runes.Count; ++i)
  				{
  					RecallRune rune = runes[i];
  
  
gt: 					if (rune != null && !rune.Marked)