using System; using System.Collections; using System.Collections.Generic; using Server; using Server.Items; using Server.Misc; using Server.Mobiles; using Server.Commands; 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 CraftResCol m_arCraftRes; private CraftSkillCol m_arCraftSkill; private Type m_Type; private string m_GroupNameString; private int m_GroupNameNumber; private string m_NameString; private int m_NameNumber; private int m_Mana; private int m_Hits; private int m_Stam; private bool m_UseAllRes; private bool m_NeedHeat; private bool m_NeedOven; private bool m_NeedMill; private bool m_ForceNonExceptional; public bool ForceNonExceptional { get { return m_ForceNonExceptional; } set { m_ForceNonExceptional = value; } } private Expansion m_RequiredExpansion; public Expansion RequiredExpansion { get { return m_RequiredExpansion; } set { m_RequiredExpansion = value; } } private static Dictionary _itemIds = new Dictionary(); public static int ItemIDOf( Type type ) { int itemId; if ( !_itemIds.TryGetValue( type, out itemId ) ) { if ( itemId == 0 ) { object[] 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; } 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( Trades skillToMake, double minSkill, double maxSkill ) { CraftSkill craftSkill = new CraftSkill( skillToMake, minSkill, maxSkill ); m_arCraftSkill.Add( craftSkill ); } public int Mana { get { return m_Mana; } set { m_Mana = value; } } public int Hits { get { return m_Hits; } set { m_Hits = value; } } public int Stam { get { return m_Stam; } set { m_Stam = value; } } public bool UseAllRes { get { return m_UseAllRes; } set { m_UseAllRes = value; } } 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 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 && 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 int[] m_HeatSources = new int[] { 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 0x197A, 0x19A9, // Large Forge 0x0FB1, 0x0FB1/ // Small Forge 0x3E4, 0x3E5, 0x3E6, 0x3E7, 0x3E8, 0x3E9, // Bonfire 0x29FD, 0x29FE, 0x29FF, 0x2A00, 0x2A01, 0x2A02, 0x2A03 // Stone Firepit }; private static int[] m_Ovens = new int[] { 0x461, 0x46F, // Sandstone oven 0x92B, 0x93F // Stone oven }; private static int[] m_Mills = new int[] { 0x1920, 0x1921, 0x1922, 0x1923, 0x1924, 0x1295, 0x1926, 0x1928, 0x192C, 0x192D, 0x192E, 0x129F, 0x1930, 0x1931, 0x1932, 0x1934 }; private static Type[][] m_TypesTable = new Type[][] { new Type[]{ typeof( WoodBoard ) }, new Type[]{ typeof( Leather ), typeof( Hides ) }, new Type[]{ typeof( BlankMap ), typeof( BlankScroll ) }, new Type[]{ typeof( Cloth ), typeof( UncutCloth ) }, new Type[]{ typeof( CheeseWheel ), typeof( CheeseWedge ) }, new Type[]{ typeof( Pumpkin ), typeof( SmallPumpkin ) }, new Type[]{ typeof( WoodenBowlOfPeas ), typeof( PewterBowlOfPeas ) } }; private static Type[] m_ColoredItemTable = new Type[] { typeof( BaseWeapon ), typeof( BaseArmor ), typeof( BaseClothing ), typeof( BaseJewel ) }; private static Type[] m_ColoredResourceTable = new Type[] { typeof( BaseIngot ), typeof( BaseOre ), typeof( BaseLeather ), typeof( BaseHides ), typeof( UncutCloth ), typeof( Cloth ) }; private static Type[] m_MarkableTable = new Type[] { typeof( BaseArmor ), typeof( BaseWeapon ), typeof( BaseClothing ), typeof( BaseInstrument ), typeof( BaseTool ), typeof( BaseHarvestTool ), typeof( Spellbook ) }; #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 bool RetainsColorFrom( CraftSystem system, Type type ) { if (DefTailoring.IsNonColorable(m_Type)) { return false; } 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; StaticTile[] 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 ) { Type[] check = types[i]; for ( int j = 0; j < check.Length; ++j ) { if ( typeof( IHasQuantity ).IsAssignableFrom( check[j] ) ) return true; } } return false; } public int ConsumeQuantity( Container cont, Type[][] types, int[] amounts ) { if ( types.Length != amounts.Length ) throw new ArgumentException(); 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 ) { IHasQuantity hq = items[i][j] as IHasQuantity; if ( hq == null ) { totals[i] += items[i][j].Amount; } else { if ( hq is BaseBeverage && ((BaseBeverage)hq).Content != BeverageType.Water ) 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 != BeverageType.Water ) 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 ) { Item[] 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 != BeverageType.Water ) continue; amount += hq.Quantity; } } return amount; } 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; } Type[][] types = new Type[m_arCraftRes.Count][]; int[] amounts = new int[m_arCraftRes.Count]; maxAmount = int.MaxValue; CraftSubResCol resCol = ( craftSystem.CraftSubRes ); for ( int i = 0; i < types.Length; ++i ) { CraftRes craftRes = m_arCraftRes.GetAt( i ); Type baseType = craftRes.ItemType; // Resource Mutation if ( (baseType == resCol.ResType) && ( typeRes != null ) ) { baseType = typeRes; CraftSubRes subResource = resCol.SearchFor( baseType ); if ( subResource != null && SkillCheck.TradeSkill( from, craftSystem.MainSkill, false ) < 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 Type[]{ 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] ); 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; int index = 0; // Consume ALL if ( consumeType == ConsumeType.All ) { m_ResHue = 0; m_ResAmount = 0; m_System = craftSystem; if ( IsQuantityType( types ) ) index = ConsumeQuantity( ourPack, types, amounts ); else index = ourPack.ConsumeTotalGrouped( types, amounts, true, new OnItemConsumed( OnResourceConsumed ), new CheckItemGroup( CheckHueGrouping ) ); resHue = m_ResHue; } // Consume Half ( for use all resource craft type ) else if ( consumeType == ConsumeType.Half ) { for ( int i = 0; i < amounts.Length; i++ ) { amounts[i] /= 2; if ( amounts[i] < 1 ) amounts[i] = 1; } m_ResHue = 0; m_ResAmount = 0; m_System = craftSystem; if ( IsQuantityType( types ) ) index = ConsumeQuantity( ourPack, types, amounts ); else index = ourPack.ConsumeTotalGrouped( types, amounts, true, new OnItemConsumed( OnResourceConsumed ), new CheckItemGroup( CheckHueGrouping ) ); resHue = m_ResHue; } else // ConstumeType.None ( it's basicaly used to know if the crafter has enough resource before starting the process ) { index = -1; if ( IsQuantityType( types ) ) { for ( int i = 0; i < types.Length; i++ ) { if ( GetQuantity( ourPack, types[i] ) < amounts[i] ) { index = i; break; } } } else { for ( int i = 0; i < types.Length; i++ ) { if ( ourPack.GetBestGroupAmount( types[i], true, new CheckItemGroup( CheckHueGrouping ) ) < amounts[i] ) { index = i; break; } } } } if ( index == -1 ) { if ( consumeType != ConsumeType.None ) if ( consumeExtra != null ) consumeExtra.Delete(); return true; } else { CraftRes res = m_arCraftRes.GetAt( index ); if ( res.MessageNumber > 0 ) message = res.MessageNumber; else if ( res.MessageString != null && res.MessageString != String.Empty ) message = res.MessageString; else message = 502925; // You don't have the resources required to make that item. return false; } } private int m_ResHue; private int m_ResAmount; private CraftSystem m_System; private void OnResourceConsumed( Item item, int amount ) { if ( !RetainsColorFrom( m_System, item.GetType() ) ) return; if ( amount >= m_ResAmount ) { m_ResHue = item.Hue; m_ResAmount = amount; } } private int CheckHueGrouping( Item a, Item b ) { return b.Hue.CompareTo( a.Hue ); } public double GetExceptionalChance( CraftSystem system, double chance, Mobile from ) { if( m_ForceNonExceptional ) return 0.0; double bonus = 0.0; switch ( system.ECA ) { default: case CraftECA.ChanceMinusSixty: chance -= 0.6; break; case CraftECA.FiftyPercentChanceMinusTenPercent: chance = chance * 0.5 - 0.1; break; case CraftECA.ChanceMinusSixtyToFourtyFive: { double offset = 0.60 - ((SkillCheck.TradeSkill( from, system.MainSkill, false ) - 95.0) * 0.03); if ( offset < 0.45 ) offset = 0.45; else if ( offset > 0.60 ) offset = 0.60; chance -= offset; break; } } if ( chance > 0 ) return chance + bonus; return chance; } public bool CheckSkills( Mobile from, Type typeRes, CraftSystem craftSystem, ref int quality, ref bool allRequiredSkills ) { double chance = GetSuccessChance( from, typeRes, craftSystem, ref allRequiredSkills ); if ( GetExceptionalChance( craftSystem, chance, from ) > Utility.RandomDouble() ) quality = 2; return ( chance > Utility.RandomDouble() ); } public double GetSuccessChance( Mobile from, Type typeRes, CraftSystem craftSystem, ref bool allRequiredSkills ) { double minMainSkill = 0.0; double maxMainSkill = 0.0; double valMainSkill = 0.0; allRequiredSkills = true; for ( int i = 0; i < m_arCraftSkill.Count; i++) { CraftSkill craftSkill = m_arCraftSkill.GetAt(i); double minSkill = craftSkill.MinSkill; double maxSkill = craftSkill.MaxSkill; double valSkill = SkillCheck.TradeSkill( from, craftSkill.SkillToMake, false ); if ( valSkill < minSkill ) allRequiredSkills = false; if ( craftSkill.SkillToMake == craftSystem.MainSkill ) { minMainSkill = minSkill; maxMainSkill = maxSkill; valMainSkill = valSkill; } } double chance; if ( allRequiredSkills ) chance = craftSystem.GetChanceAtMin( this ) + ((valMainSkill - minMainSkill) / (maxMainSkill - minMainSkill) * (1.0 - craftSystem.GetChanceAtMin( this ))); else chance = 0.0; if ( allRequiredSkills && valMainSkill == maxMainSkill ) chance = 1.0; return chance; } public void Craft( Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool ) { if ( from.BeginAction( typeof( CraftSystem ) ) ) { bool allRequiredSkills = true; double chance = GetSuccessChance( from, typeRes, craftSystem, ref allRequiredSkills ); if ( allRequiredSkills && chance >= 0.0 ) { int badCraft = craftSystem.CanCraft( from, tool, m_Type ); if( badCraft <= 0 ) { int resHue = 0; int maxAmount = 0; object message = null; if( ConsumeRes( from, typeRes, craftSystem, ref resHue, ref maxAmount, ConsumeType.None, ref message ) ) { message = null; if( ConsumeAttributes( from, ref message, false ) ) { CraftContext context = craftSystem.GetContext( from ); if( context != null ) context.OnMade( this ); int iMin = craftSystem.MinCraftEffect; int iMax = (craftSystem.MaxCraftEffect - iMin) + 1; int iRandom = Utility.Random( iMax ); iRandom += iMin + 1; new InternalTimer( from, craftSystem, this, typeRes, tool, iRandom ).Start(); } else { from.EndAction( typeof( CraftSystem ) ); from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); } } else { from.EndAction( typeof( CraftSystem ) ); from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); } } else { from.EndAction( typeof( CraftSystem ) ); from.SendGump( new CraftGump( from, craftSystem, tool, badCraft ) ); } } else { from.EndAction( typeof( CraftSystem ) ); from.SendGump( new CraftGump( from, craftSystem, tool, 1044153 ) ); // You don't have the required skills to attempt this item. } } else { from.SendLocalizedMessage( 500119 ); // You must wait to perform another action } } public void CompleteCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CustomCraft customCraft ) { int badCraft = craftSystem.CanCraft( from, tool, m_Type ); if ( badCraft > 0 ) { if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, badCraft ) ); else from.SendLocalizedMessage( badCraft ); return; } int checkResHue = 0, checkMaxAmount = 0; object checkMessage = null; // Not enough resource to craft it if ( !ConsumeRes( from, typeRes, craftSystem, ref checkResHue, ref checkMaxAmount, ConsumeType.None, ref checkMessage ) ) { if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, checkMessage ) ); else if ( checkMessage is int && (int)checkMessage > 0 ) from.SendLocalizedMessage( (int)checkMessage ); else if ( checkMessage is string ) from.SendMessage( (string)checkMessage ); return; } else if ( !ConsumeAttributes( from, ref checkMessage, false ) ) { if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, checkMessage ) ); else if ( checkMessage is int && (int)checkMessage > 0 ) from.SendLocalizedMessage( (int)checkMessage ); else if ( checkMessage is string ) from.SendMessage( (string)checkMessage ); return; } bool toolBroken = false; int ignored = 1; int endquality = 1; bool allRequiredSkills = true; if ( CheckSkills( from, typeRes, craftSystem, ref ignored, ref allRequiredSkills ) ) { // Resource int resHue = 0; int maxAmount = 0; object message = null; // Not enough resource to craft it if ( !ConsumeRes( from, typeRes, craftSystem, ref resHue, ref maxAmount, ConsumeType.All, ref message ) ) { if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); else if ( message is int && (int)message > 0 ) from.SendLocalizedMessage( (int)message ); else if ( message is string ) from.SendMessage( (string)message ); return; } else if ( !ConsumeAttributes( from, ref message, true ) ) { if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); else if ( message is int && (int)message > 0 ) from.SendLocalizedMessage( (int)message ); else if ( message is string ) from.SendMessage( (string)message ); return; } tool.UsesRemaining--; if ( tool.UsesRemaining < 1 ) toolBroken = true; if ( toolBroken ) tool.Delete(); int num = 0; Item item; if ( customCraft != null ) { item = customCraft.CompleteCraft( out num ); } else if ( typeof( MapItem ).IsAssignableFrom( ItemType ) && from.Map != Map.Britannia ) { item = new IndecipherableMap(); from.SendLocalizedMessage( 1070800 ); // The map you create becomes mysteriously indecipherable. } else { item = Activator.CreateInstance( ItemType ) as Item; } if ( item != null ) { if( item is ICraftable ) endquality = ((ICraftable)item).OnCraft( quality, makersMark, from, craftSystem, typeRes, tool, this, resHue ); else if ( item.Hue == 0 ) item.Hue = resHue; if ( maxAmount > 0 ) { if ( !item.Stackable && item is IUsesRemaining ) ((IUsesRemaining)item).UsesRemaining *= maxAmount; else item.Amount = maxAmount; } from.AddToBackpack( item ); if( from.AccessLevel > AccessLevel.Player ) CommandLogging.WriteLine( from, "Crafting {0} with craft system {1}", CommandLogging.Format( item ), craftSystem.GetType().Name ); //from.PlaySound( 0x57 ); } if ( num == 0 ) num = craftSystem.PlayEndingEffect( from, false, true, toolBroken, endquality, makersMark, this ); if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, num ) ); else if ( num > 0 ) from.SendLocalizedMessage( num ); } else if ( !allRequiredSkills ) { if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, 1044153 ) ); else from.SendLocalizedMessage( 1044153 ); // You don't have the required skills to attempt this item. } else { ConsumeType consumeType = ( UseAllRes ? ConsumeType.Half : ConsumeType.All ); int resHue = 0; int maxAmount = 0; object message = null; // Not enough resource to craft it if ( !ConsumeRes( from, typeRes, craftSystem, ref resHue, ref maxAmount, consumeType, ref message, true ) ) { if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); else if ( message is int && (int)message > 0 ) from.SendLocalizedMessage( (int)message ); else if ( message is string ) from.SendMessage( (string)message ); return; } tool.UsesRemaining--; if ( tool.UsesRemaining < 1 ) toolBroken = true; if ( toolBroken ) tool.Delete(); // SkillCheck failed. int num = craftSystem.PlayEndingEffect( from, true, true, toolBroken, endquality, false, this ); if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, num ) ); else if ( num > 0 ) from.SendLocalizedMessage( num ); } } private class InternalTimer : Timer { private Mobile m_From; private int m_iCount; private int m_iCountMax; private CraftItem m_CraftItem; private CraftSystem m_CraftSystem; private Type m_TypeRes; private BaseTool m_Tool; public InternalTimer( Mobile from, CraftSystem craftSystem, CraftItem craftItem, Type typeRes, BaseTool tool, int iCountMax ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( craftSystem.Delay ), iCountMax ) { m_From = from; m_CraftItem = craftItem; m_iCount = 0; m_iCountMax = iCountMax; m_CraftSystem = craftSystem; m_TypeRes = typeRes; m_Tool = tool; } protected override void OnTick() { m_iCount++; m_From.DisruptiveAction(); if ( m_iCount < m_iCountMax ) { m_CraftSystem.PlayCraftEffect( m_From ); } else { m_From.EndAction( typeof( CraftSystem ) ); int badCraft = m_CraftSystem.CanCraft( m_From, m_Tool, m_CraftItem.m_Type ); if ( badCraft > 0 ) { if ( m_Tool != null && !m_Tool.Deleted && m_Tool.UsesRemaining > 0 ) m_From.SendGump( new CraftGump( m_From, m_CraftSystem, m_Tool, badCraft ) ); else m_From.SendLocalizedMessage( badCraft ); return; } int quality = 1; bool allRequiredSkills = true; m_CraftItem.CheckSkills( m_From, m_TypeRes, m_CraftSystem, ref quality, ref allRequiredSkills ); CraftContext context = m_CraftSystem.GetContext( m_From ); if ( context == null ) return; if ( typeof( CustomCraft ).IsAssignableFrom( m_CraftItem.ItemType ) ) { CustomCraft cc = null; try{ cc = Activator.CreateInstance( m_CraftItem.ItemType, new object[] { m_From, m_CraftItem, m_CraftSystem, m_TypeRes, m_Tool, quality } ) as CustomCraft; } catch{} if ( cc != null ) cc.EndCraftAction(); return; } bool makersMark = false; if ( quality == 2 && SkillCheck.TradeSkill( m_From, m_CraftSystem.MainSkill, false ) >= 100.0 ) makersMark = m_CraftItem.IsMarkable( m_CraftItem.ItemType ); if ( makersMark && context.MarkOption == CraftMarkOption.PromptForMark ) { m_From.SendGump( new QueryMakersMarkGump( quality, m_From, m_CraftItem, m_CraftSystem, m_TypeRes, m_Tool ) ); } else { if ( context.MarkOption == CraftMarkOption.DoNotMark ) makersMark = false; m_CraftItem.CompleteCraft( quality, makersMark, m_From, m_CraftSystem, m_TypeRes, m_Tool, null ); } } } } } }