1161 lines
30 KiB
C#
1161 lines
30 KiB
C#
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<Type, int> _itemIds = new Dictionary<Type, int>();
|
|
|
|
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 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|