2292 lines
65 KiB
C#
2292 lines
65 KiB
C#
#region References
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
using Server.Commands;
|
|
using Server.Engines.Plants;
|
|
using Server.Factions;
|
|
using Server.Items;
|
|
using Server.Mobiles;
|
|
using Server.Engines.Quests;
|
|
#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,
|
|
ITool tool,
|
|
CraftItem craftItem,
|
|
int resHue);
|
|
}
|
|
|
|
public class CraftItem
|
|
{
|
|
/// <summary>
|
|
/// this delegate will handle all crafting functions,
|
|
/// such as resource check, actual crafting, etc.
|
|
/// For use for abnormal crafting, ie combine cloth, etc.
|
|
/// </summary>
|
|
public Action<Mobile, CraftItem, ITool> TryCraft { get; set; }
|
|
|
|
/// <summary>
|
|
/// this func will create complex items that may require args, or other
|
|
/// things to create that Activator may not be able to accomidate.
|
|
/// </summary>
|
|
public Func<Mobile, CraftItem, ITool, Item> CreateItem { get; set; }
|
|
|
|
public Func<Mobile, ConsumeType, int> ConsumeResCallback { get; set; }
|
|
|
|
public Type ItemType { get; private set; }
|
|
public string GroupNameString { get; private set; }
|
|
public int GroupNameNumber { get; private set; }
|
|
public string NameString { get; private set; }
|
|
public int NameNumber { get; private set; }
|
|
public CraftResCol Resources { get; private set; }
|
|
public CraftSkillCol Skills { get; private set; }
|
|
|
|
public BeverageType RequiredBeverage { get; set; }
|
|
|
|
public int ForceSuccessChance { get; set; } = -1;
|
|
|
|
public double MinSkillOffset { get; set; }
|
|
public bool ForceNonExceptional { get; set; }
|
|
public bool ForceExceptional { get; set; }
|
|
public Expansion RequiredExpansion { get; set; }
|
|
public ThemePack RequiredThemePack { get; set; }
|
|
|
|
public bool RequiresBasketWeaving { get; set; }
|
|
public bool RequiresResTarget { get; set; }
|
|
public bool RequiresMechanicalLife { get; set; }
|
|
|
|
public object Data { get; set; }
|
|
public int DisplayID { get; set; }
|
|
public Recipe Recipe { get; set; }
|
|
|
|
public int Mana { get; set; }
|
|
public int Hits { get; set; }
|
|
public int Stam { get; set; }
|
|
public bool UseSubRes2 { get; set; }
|
|
public bool UseAllRes { get; set; }
|
|
public bool ForceTypeRes { get; set; }
|
|
|
|
public bool NeedHeat { get; set; }
|
|
public bool NeedOven { get; set; }
|
|
public bool NeedMaker { get; set; }
|
|
public bool NeedMill { get; set; }
|
|
public bool NeedWater { get; set; }
|
|
public int ItemHue { get; set; }
|
|
|
|
public Action<Mobile, Item, ITool> MutateAction { get; set; }
|
|
|
|
public void AddRecipe(int id, CraftSystem system)
|
|
{
|
|
if (Recipe != null)
|
|
{
|
|
Console.WriteLine(
|
|
"Warning: Attempted add of recipe #{0} to the crafting of {1} in CraftSystem {2}.", id, ItemType.Name, system);
|
|
return;
|
|
}
|
|
|
|
Recipe = new Recipe(id, system, this);
|
|
}
|
|
|
|
public CraftItem(Type type, TextDefinition groupName, TextDefinition name)
|
|
{
|
|
Resources = new CraftResCol();
|
|
Skills = new CraftSkillCol();
|
|
|
|
ItemType = type;
|
|
|
|
GroupNameString = groupName;
|
|
NameString = name;
|
|
|
|
GroupNameNumber = groupName;
|
|
NameNumber = name;
|
|
|
|
RequiredBeverage = BeverageType.Water;
|
|
}
|
|
|
|
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);
|
|
Resources.Add(craftRes);
|
|
}
|
|
|
|
public void AddSkill(SkillName skillToMake, double minSkill, double maxSkill)
|
|
{
|
|
CraftSkill craftSkill = new CraftSkill(skillToMake, minSkill, maxSkill);
|
|
Skills.Add(craftSkill);
|
|
}
|
|
|
|
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 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 (from.Backpack != null && m_System is DefInscription)
|
|
{
|
|
Item item = from.Backpack.FindItemByType(typeof(ChronicleOfTheGargoyleQueen1));
|
|
|
|
if (item != null && item is ChronicleOfTheGargoyleQueen1 && ((ChronicleOfTheGargoyleQueen1)item).Charges > 0)
|
|
{
|
|
if (consume)
|
|
((ChronicleOfTheGargoyleQueen1)item).Charges--;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
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 int[] m_HeatSources =
|
|
{
|
|
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
|
|
0xA2A4, 0xA2A5, 0xA2A8, 0xA2A9 // Wood Stove
|
|
};
|
|
|
|
private static int[] m_Ovens =
|
|
{
|
|
0x461, 0x46F, // Sandstone oven
|
|
0x92B, 0x93F, // Stone oven
|
|
0x2DDB, 0x2DDC, //Elven stove
|
|
};
|
|
|
|
private static int[] m_Makers =
|
|
{
|
|
0x9A96, 0x9A96 // steam powered beverage maker
|
|
};
|
|
|
|
private static readonly int[] m_Mills =
|
|
{
|
|
0x1920, 0x1921, 0x1922, 0x1923, 0x1924, 0x1295, 0x1926, 0x1928, 0x192C, 0x192D, 0x192E, 0x129F, 0x1930, 0x1931,
|
|
0x1932, 0x1934
|
|
};
|
|
|
|
private static int[] m_WaterSources =
|
|
{
|
|
0xB41, 0xB44,
|
|
0xE7B, 0xE7B,
|
|
0xFFA, 0xFFA,
|
|
0x154D, 0x154D,
|
|
0x99CA, 0x99CB,
|
|
0x9A14, 0x9A19,
|
|
0xA2AF, 0xA2B9,
|
|
0x2AC0, 0x2AC5
|
|
};
|
|
|
|
private static readonly Type[][] ItemTypesTable =
|
|
{
|
|
new[] {typeof(Board), typeof(Log)},
|
|
new[] {typeof(HeartwoodBoard), typeof(HeartwoodLog)},
|
|
new[] {typeof(BloodwoodBoard), typeof(BloodwoodLog)},
|
|
new[] {typeof(FrostwoodBoard), typeof(FrostwoodLog)},
|
|
new[] {typeof(OakBoard), typeof(OakLog)},
|
|
new[] {typeof(AshBoard), typeof(AshLog)},
|
|
new[] {typeof(YewBoard), typeof(YewLog)},
|
|
new[] {typeof(Leather), typeof(Hides)},
|
|
new[] {typeof(SpinedLeather), typeof(SpinedHides)},
|
|
new[] {typeof(HornedLeather), typeof(HornedHides)},
|
|
new[] {typeof(BarbedLeather), typeof(BarbedHides)},
|
|
new[] {typeof(BlankMap), typeof(BlankScroll)},
|
|
new[] {typeof(Cloth), typeof(UncutCloth), typeof(AbyssalCloth)},
|
|
new[] {typeof(CheeseWheel), typeof(CheeseWedge)},
|
|
new[] {typeof(Pumpkin), typeof(SmallPumpkin)},
|
|
new[] {typeof(WoodenBowlOfPeas), typeof(PewterBowlOfPeas)},
|
|
new[] { typeof( CrystallineFragments ), typeof( BrokenCrystals ), typeof( ShatteredCrystals ), typeof( ScatteredCrystals ), typeof( CrushedCrystals ), typeof( JaggedCrystals ), typeof( AncientPotteryFragments ) },
|
|
new[] { typeof( MedusaDarkScales ), typeof( MedusaLightScales ), typeof( RedScales ), typeof( BlueScales ), typeof( BlackScales ), typeof( YellowScales ), typeof( GreenScales ), typeof( WhiteScales ) },
|
|
new[] { typeof(Sausage), typeof(CookableSausage) },
|
|
new[] { typeof(Lettuce), typeof(FarmableLettuce) },
|
|
new[] { typeof(DarkYarn), typeof(LightYarn) }
|
|
};
|
|
|
|
private static readonly Type[] m_ColoredItemTable =
|
|
{
|
|
#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
|
|
};
|
|
|
|
private static readonly Type[] m_ClothColoredItemTable =
|
|
{
|
|
typeof( GozaMatSouthDeed ), typeof( GozaMatEastDeed ),
|
|
typeof( SquareGozaMatSouthDeed ), typeof( SquareGozaMatEastDeed ),
|
|
typeof( BrocadeGozaMatSouthDeed ), typeof( BrocadeGozaMatEastDeed ),
|
|
typeof( BrocadeSquareGozaMatSouthDeed ), typeof( BrocadeSquareGozaMatEastDeed ),
|
|
typeof( Tessen )
|
|
};
|
|
|
|
private static readonly Type[] m_ColoredResourceTable =
|
|
{
|
|
#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 =
|
|
{
|
|
#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(ShortMusicStandLeft), typeof(ShortMusicStandRight),
|
|
typeof(TallMusicStandLeft), typeof(TallMusicStandRight), typeof(EasleNorth), typeof(EasleEast), typeof(EasleSouth),
|
|
typeof(RedHangingLantern), typeof(WhiteHangingLantern), typeof(BambooScreen), typeof(ShojiScreen),
|
|
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(DressformFront), typeof(DressformSide), typeof(BasePlayerBB), typeof(BarrelStaves),
|
|
typeof(BarrelLid), typeof(Clippers), typeof(Scissors),
|
|
|
|
typeof(KeyRing), typeof(Key), typeof(Globe), typeof(Spyglass), typeof(Lantern), typeof(Candelabra), typeof(Scales), typeof(BroadcastCrystal), typeof(TerMurStyleCandelabra),
|
|
typeof(BaseUtensil), typeof(BaseBeverage),
|
|
|
|
typeof(FruitBowl), typeof(SackFlour), typeof(Dough), typeof(SweetDough), typeof(CocoaButter), typeof(CocoaLiquor),
|
|
typeof(Food)
|
|
};
|
|
|
|
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) },
|
|
{ typeof(Leather), typeof(Hides) },
|
|
{ typeof(SpinedLeather), typeof(SpinedHides) },
|
|
{ typeof(HornedLeather), typeof(HornedHides) },
|
|
{ typeof(BarbedLeather), typeof(BarbedHides) },
|
|
};
|
|
|
|
private static Type[] m_NeverColorTable = new[] {typeof(OrcHelm)};
|
|
#endregion
|
|
|
|
public bool IsMarkable(Type type)
|
|
{
|
|
if (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 = (ItemType == m_ColoredItemTable[i] || ItemType.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 RetainsColorFromCloth(Item item)
|
|
{
|
|
Type t = item.GetType();
|
|
|
|
foreach (var type in m_ClothColoredItemTable)
|
|
{
|
|
if (type == t)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
private bool FindWater(Mobile m)
|
|
{
|
|
Map map = m.Map;
|
|
|
|
if (map == null)
|
|
return false;
|
|
|
|
IPooledEnumerable eable = map.GetItemsInRange(m.Location, 2);
|
|
|
|
foreach (Item item in eable)
|
|
{
|
|
if (item is AddonComponent)
|
|
{
|
|
var addon = ((AddonComponent)item).Addon;
|
|
|
|
if (addon is KoiPondAddon || addon is DragonTurtleFountainAddon || addon is WaterWheelAddon)
|
|
{
|
|
eable.Free();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
eable.Free();
|
|
return false;
|
|
}
|
|
|
|
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 != 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 != 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 != 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 (ourPack.TotalItems >= ourPack.MaxItems || ourPack.TotalWeight >= ourPack.MaxWeight)
|
|
{
|
|
message = 1048147; // Your backpack can't hold anything else.
|
|
return false;
|
|
}
|
|
|
|
if (ConsumeResCallback != null)
|
|
{
|
|
int resMessage = ConsumeResCallback(from, consumeType);
|
|
|
|
if (resMessage > 0)
|
|
{
|
|
message = resMessage;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (NeedHeat && !Find(from, m_HeatSources))
|
|
{
|
|
message = 1044487; // You must be near a fire source to cook.
|
|
return false;
|
|
}
|
|
|
|
if (NeedOven && !Find(from, m_Ovens))
|
|
{
|
|
message = 1044493; // You must be near an oven to bake that.
|
|
return false;
|
|
}
|
|
|
|
if (NeedMaker && !Find(from, m_Makers))
|
|
{
|
|
message = 1155732; // You must be near a steam powered beverage maker to do that.
|
|
return false;
|
|
}
|
|
|
|
if (NeedMill && !Find(from, m_Mills))
|
|
{
|
|
message = 1044491; // You must be near a flour mill to do that.
|
|
return false;
|
|
}
|
|
|
|
if (NeedWater && !Find(from, m_WaterSources) && !FindWater(from))
|
|
{
|
|
message = 1158882; // You must be near a water source such as a water trough to craft this item.
|
|
return false;
|
|
}
|
|
|
|
var types = new Type[Resources.Count][];
|
|
var amounts = new int[Resources.Count];
|
|
|
|
maxAmount = int.MaxValue;
|
|
|
|
CraftSubResCol resCol = (UseSubRes2 ? craftSystem.CraftSubRes2 : craftSystem.CraftSubRes);
|
|
MasterCraftsmanTalisman talisman = null;
|
|
|
|
for (int i = 0; i < types.Length; ++i)
|
|
{
|
|
CraftRes craftRes = Resources.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 < ItemTypesTable.Length; ++j)
|
|
{
|
|
if (ItemTypesTable[j][0] == baseType)
|
|
{
|
|
types[i] = ItemTypesTable[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]);
|
|
tempAmount /= amounts[i];
|
|
|
|
if (tempAmount < maxAmount)
|
|
{
|
|
maxAmount = tempAmount;
|
|
|
|
if (maxAmount == 0)
|
|
{
|
|
CraftRes res = Resources.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 && (talisman != null || !craftSystem.ConsumeOnFailure(from, types[i][0], this, ref talisman)))
|
|
{
|
|
amounts[i] = 0;
|
|
}
|
|
}
|
|
|
|
if (talisman != null)
|
|
{
|
|
talisman.Charges--;
|
|
}
|
|
|
|
// We adjust the amount of each resource to consume the max posible
|
|
if (UseAllRes && consumeType != ConsumeType.Half)
|
|
{
|
|
for (int i = 0; i < amounts.Length; ++i)
|
|
{
|
|
amounts[i] *= maxAmount;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
maxAmount = -1;
|
|
}
|
|
|
|
Item consumeExtra = null;
|
|
|
|
if (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];
|
|
|
|
if (rune != null && !rune.Marked)
|
|
{
|
|
consumeExtra = rune;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (consumeExtra == null)
|
|
{
|
|
message = 1044253; // You don't have the components needed to make that.
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int index = 0;
|
|
|
|
// Consume ALL
|
|
if (consumeType == ConsumeType.All)
|
|
{
|
|
m_ResHue = 0;
|
|
m_ResAmount = 0;
|
|
m_System = craftSystem;
|
|
CaddelliteCraft = true;
|
|
|
|
if (IsQuantityType(types))
|
|
{
|
|
index = ConsumeQuantity(ourPack, types, amounts);
|
|
}
|
|
else if (IsPlantHueType(types))
|
|
{
|
|
index = ConsumeQuantityByPlantHue(from, craftSystem, ourPack, types, amounts);
|
|
}
|
|
else
|
|
{
|
|
index = ourPack.ConsumeTotalGrouped(types, amounts, true, ResourceValidator, OnResourceConsumed, 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 if (IsPlantHueType(types))
|
|
{
|
|
index = ConsumeQuantityByPlantHue(from, craftSystem, ourPack, types, amounts);
|
|
}
|
|
else
|
|
{
|
|
index = ourPack.ConsumeTotalGrouped(types, amounts, true, ResourceValidator, OnResourceConsumed, 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 if (IsPlantHueType(types))
|
|
{
|
|
CraftContext c = craftSystem.GetContext(from);
|
|
|
|
for (int i = 0; i < types.Length; i++)
|
|
{
|
|
if (GetPlantHueAmount(from, craftSystem, ourPack, types[i]) < amounts[i])
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < types.Length; i++)
|
|
{
|
|
if (ourPack.GetBestGroupAmount(types[i], true, CheckHueGrouping) < amounts[i])
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (index == -1)
|
|
{
|
|
if (consumeType != ConsumeType.None)
|
|
{
|
|
if (consumeExtra != null)
|
|
{
|
|
consumeExtra.Delete();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
CraftRes res = Resources.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_ClothHue;
|
|
private int m_ResAmount;
|
|
private CraftSystem m_System;
|
|
|
|
public bool CaddelliteCraft { get; private set; }
|
|
|
|
#region Plant Pigments
|
|
private PlantHue m_PlantHue = PlantHue.None;
|
|
private PlantPigmentHue m_PlantPigmentHue = PlantPigmentHue.None;
|
|
#endregion
|
|
|
|
private void OnResourceConsumed(Item item, int amount)
|
|
{
|
|
#region Plant Pigments
|
|
if (item is IPlantHue)
|
|
{
|
|
m_PlantHue = ((IPlantHue)item).PlantHue;
|
|
}
|
|
else if (item is IPigmentHue)
|
|
{
|
|
m_PlantPigmentHue = ((IPigmentHue)item).PigmentHue;
|
|
}
|
|
#endregion
|
|
|
|
if (!RetainsColorFrom(m_System, item.GetType()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (item is Cloth || item is UncutCloth || item is AbyssalCloth)
|
|
{
|
|
m_ClothHue = item.Hue;
|
|
}
|
|
|
|
if (amount >= m_ResAmount)
|
|
{
|
|
m_ResHue = item.Hue;
|
|
m_ResAmount = amount;
|
|
}
|
|
|
|
if (CaddelliteCraft && (!item.HasSocket<Caddellite>() || !Server.Engines.Points.PointsSystem.Khaldun.InSeason))
|
|
{
|
|
CaddelliteCraft = false;
|
|
}
|
|
}
|
|
|
|
private int CheckHueGrouping(Item a, Item b)
|
|
{
|
|
return b.Hue.CompareTo(a.Hue);
|
|
}
|
|
|
|
public bool ResourceValidator(Item item)
|
|
{
|
|
// VvV items or Faction Items cannot be used as resources
|
|
if ((item is IVvVItem && ((IVvVItem)item).IsVvVItem) || (item is IFactionItem && ((IFactionItem)item).FactionItemState != null))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public double GetExceptionalChance(CraftSystem system, double chance, Mobile from)
|
|
{
|
|
if (ForceNonExceptional)
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
if (ForceExceptional)
|
|
{
|
|
bool allRequiredSkills = false;
|
|
GetSuccessChance(from, null, system, false, ref allRequiredSkills);
|
|
|
|
if (allRequiredSkills)
|
|
return 100.0;
|
|
}
|
|
|
|
double bonus = 0.0;
|
|
|
|
if (from.Talisman is BaseTalisman)
|
|
{
|
|
BaseTalisman talisman = (BaseTalisman)from.Talisman;
|
|
|
|
if (talisman.CheckSkill(system))
|
|
{
|
|
bonus = talisman.ExceptionalBonus / 100.0;
|
|
}
|
|
}
|
|
|
|
MasterChefsApron apron = from.FindItemOnLayer(Layer.MiddleTorso) as MasterChefsApron;
|
|
|
|
if (apron != null)
|
|
{
|
|
bonus += apron.Bonus / 100.0;
|
|
}
|
|
|
|
if (WoodworkersBench.HasBonus(from, system.MainSkill))
|
|
{
|
|
bonus += .3;
|
|
}
|
|
|
|
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 - ((from.Skills[system.MainSkill].Value - 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, int maxAmount)
|
|
{
|
|
return CheckSkills(from, typeRes, craftSystem, ref quality, ref allRequiredSkills, true, maxAmount);
|
|
}
|
|
|
|
public bool CheckSkills(
|
|
Mobile from, Type typeRes, CraftSystem craftSystem, ref int quality, ref bool allRequiredSkills, bool gainSkills, int maxAmount)
|
|
{
|
|
double chance = GetSuccessChance(from, typeRes, craftSystem, gainSkills, ref allRequiredSkills, maxAmount);
|
|
|
|
if (GetExceptionalChance(craftSystem, chance, from) > Utility.RandomDouble())
|
|
{
|
|
quality = 2;
|
|
}
|
|
|
|
return (chance > Utility.RandomDouble());
|
|
}
|
|
|
|
public double GetSuccessChance(Mobile from, Type typeRes, CraftSystem craftSystem, bool gainSkills, ref bool allRequiredSkills)
|
|
{
|
|
return GetSuccessChance(from, typeRes, craftSystem, gainSkills, ref allRequiredSkills, 1);
|
|
}
|
|
|
|
public double GetSuccessChance(Mobile from, Type typeRes, CraftSystem craftSystem, bool gainSkills, ref bool allRequiredSkills, int maxAmount)
|
|
{
|
|
if (ForceSuccessChance > -1)
|
|
{
|
|
return ((double)ForceSuccessChance / 100.0);
|
|
}
|
|
|
|
double minMainSkill = 0.0;
|
|
double maxMainSkill = 0.0;
|
|
double valMainSkill = 0.0;
|
|
|
|
allRequiredSkills = true;
|
|
|
|
for (int i = 0; i < Skills.Count; i++)
|
|
{
|
|
CraftSkill craftSkill = Skills.GetAt(i);
|
|
|
|
double minSkill = craftSkill.MinSkill - MinSkillOffset;
|
|
double maxSkill = craftSkill.MaxSkill;
|
|
double valSkill = from.Skills[craftSkill.SkillToMake].Value;
|
|
|
|
if (valSkill < minSkill)
|
|
{
|
|
allRequiredSkills = false;
|
|
}
|
|
|
|
if (craftSkill.SkillToMake == craftSystem.MainSkill)
|
|
{
|
|
minMainSkill = minSkill;
|
|
maxMainSkill = maxSkill;
|
|
valMainSkill = valSkill;
|
|
}
|
|
|
|
if (gainSkills && !UseAllRes) // This is a passive check. Success chance is entirely dependant on the main skill
|
|
{
|
|
from.CheckSkill(craftSkill.SkillToMake, minSkill, maxSkill);
|
|
}
|
|
}
|
|
|
|
double chance;
|
|
|
|
if (allRequiredSkills)
|
|
{
|
|
chance = craftSystem.GetChanceAtMin(this) +
|
|
((valMainSkill - minMainSkill) / (maxMainSkill - minMainSkill) * (1.0 - craftSystem.GetChanceAtMin(this)));
|
|
}
|
|
else
|
|
{
|
|
chance = 0.0;
|
|
}
|
|
|
|
if (allRequiredSkills && from.Talisman is BaseTalisman)
|
|
{
|
|
BaseTalisman talisman = (BaseTalisman)from.Talisman;
|
|
|
|
if (talisman.CheckSkill(craftSystem))
|
|
{
|
|
chance += talisman.SuccessBonus / 100.0;
|
|
}
|
|
}
|
|
|
|
if (WoodworkersBench.HasBonus(from, craftSystem.MainSkill))
|
|
{
|
|
chance += .5;
|
|
}
|
|
|
|
if (allRequiredSkills && valMainSkill == maxMainSkill)
|
|
{
|
|
chance = 1.0;
|
|
}
|
|
|
|
return chance;
|
|
}
|
|
|
|
private void MultipleSkillCheck(Mobile from, int amount)
|
|
{
|
|
for (int i = 0; i < Skills.Count; i++)
|
|
{
|
|
CraftSkill craftSkill = Skills.GetAt(i);
|
|
|
|
Server.Misc.SkillCheck.CheckSkill(from, craftSkill.SkillToMake, craftSkill.MinSkill - MinSkillOffset, craftSkill.MaxSkill, amount);
|
|
}
|
|
}
|
|
|
|
public void Craft(Mobile from, CraftSystem craftSystem, Type typeRes, ITool tool)
|
|
{
|
|
if (from.BeginAction(typeof(CraftSystem)))
|
|
{
|
|
if (RequiredExpansion == Expansion.None ||
|
|
(from.NetState != null && from.NetState.SupportsExpansion(RequiredExpansion)))
|
|
{
|
|
bool allRequiredSkills = true;
|
|
double chance = GetSuccessChance(from, typeRes, craftSystem, false, ref allRequiredSkills);
|
|
|
|
if (allRequiredSkills && chance >= 0.0)
|
|
{
|
|
if (Recipe == null || !(from is PlayerMobile) || ((PlayerMobile)from).HasRecipe(Recipe))
|
|
{
|
|
if (!RequiresBasketWeaving || (from is PlayerMobile && ((PlayerMobile)from).BasketWeaving))
|
|
{
|
|
if (!RequiresMechanicalLife || (from is PlayerMobile && ((PlayerMobile)from).MechanicalLife))
|
|
{
|
|
int badCraft = craftSystem.CanCraft(from, tool, ItemType);
|
|
|
|
if (badCraft <= 0)
|
|
{
|
|
if (RequiresResTarget && NeedsResTarget(from, craftSystem))
|
|
{
|
|
from.Target = new ChooseResTarget(from, this, craftSystem, typeRes, tool);
|
|
from.SendMessage("Choose the resource you would like to use.");
|
|
return;
|
|
}
|
|
|
|
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();
|
|
return;
|
|
}
|
|
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, 1113034)); // You haven't read the Mechanical Life Manual. Talking to Sutek might help!
|
|
}
|
|
}
|
|
else
|
|
{
|
|
from.EndAction(typeof(CraftSystem));
|
|
from.SendGump(new CraftGump(from, craftSystem, tool, 1112253)); // You haven't learned basket weaving. Perhaps studying a book would help!
|
|
}
|
|
}
|
|
else
|
|
{
|
|
from.EndAction(typeof(CraftSystem));
|
|
from.SendGump(new CraftGump(from, craftSystem, tool, 1072847)); // You must learn that recipe from a scroll.
|
|
}
|
|
}
|
|
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.EndAction(typeof(CraftSystem));
|
|
from.SendGump(new CraftGump(from, craftSystem, tool, RequiredExpansionMessage(RequiredExpansion)));
|
|
//The {0} expansion is required to attempt this item.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(500119); // You must wait to perform another action
|
|
}
|
|
|
|
AutoCraftTimer.EndTimer(from);
|
|
}
|
|
|
|
private object RequiredExpansionMessage(Expansion expansion)
|
|
{
|
|
switch (expansion)
|
|
{
|
|
case Expansion.SE:
|
|
return 1063307; // The "Samurai Empire" expansion is required to attempt this item.
|
|
case Expansion.ML:
|
|
return 1072650; // The "Mondain's Legacy" expansion is required to attempt this item.
|
|
case Expansion.SA:
|
|
return 1094731; // You must have the Stygian Abyss expansion pack to use this feature.
|
|
case Expansion.HS:
|
|
return 1116295; // You must have the High Seas booster pack to use this feature
|
|
case Expansion.TOL:
|
|
return 1155875; // You must have the Time of Legends expansion to use this feature.
|
|
default:
|
|
return String.Format("The \"{0}\" expansion is required to attempt this item.", ExpansionInfo.GetInfo(expansion).Name);
|
|
}
|
|
}
|
|
|
|
public void CompleteCraft(
|
|
int quality,
|
|
bool makersMark,
|
|
Mobile from,
|
|
CraftSystem craftSystem,
|
|
Type typeRes,
|
|
ITool tool,
|
|
CustomCraft customCraft)
|
|
{
|
|
int badCraft = craftSystem.CanCraft(from, tool, ItemType);
|
|
|
|
if (badCraft > 0)
|
|
{
|
|
if (tool != null && !tool.Deleted && tool.UsesRemaining > 0)
|
|
{
|
|
from.SendGump(new CraftGump(from, craftSystem, tool, badCraft));
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(badCraft);
|
|
}
|
|
|
|
AutoCraftTimer.EndTimer(from);
|
|
|
|
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);
|
|
}
|
|
|
|
AutoCraftTimer.EndTimer(from);
|
|
|
|
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);
|
|
}
|
|
|
|
AutoCraftTimer.EndTimer(from);
|
|
|
|
return;
|
|
}
|
|
|
|
bool toolBroken = false;
|
|
|
|
int ignored = 1;
|
|
int endquality = 1;
|
|
|
|
bool allRequiredSkills = true;
|
|
|
|
if (CheckSkills(from, typeRes, craftSystem, ref ignored, ref allRequiredSkills, checkMaxAmount))
|
|
{
|
|
// 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);
|
|
}
|
|
|
|
AutoCraftTimer.EndTimer(from);
|
|
|
|
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);
|
|
}
|
|
|
|
AutoCraftTimer.EndTimer(from);
|
|
|
|
return;
|
|
}
|
|
|
|
if (UseAllRes && maxAmount > 0)
|
|
{
|
|
MultipleSkillCheck(from, maxAmount);
|
|
}
|
|
|
|
if (craftSystem is DefBlacksmithy)
|
|
{
|
|
AncientSmithyHammer hammer = from.FindItemOnLayer(Layer.OneHanded) as AncientSmithyHammer;
|
|
if (hammer != null && hammer != tool)
|
|
{
|
|
#region Mondain's Legacy
|
|
if (hammer is HammerOfHephaestus)
|
|
{
|
|
if (hammer.UsesRemaining > 0)
|
|
{
|
|
hammer.UsesRemaining--;
|
|
}
|
|
|
|
if (hammer.UsesRemaining < 1)
|
|
{
|
|
from.PlaceInBackpack(hammer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hammer.UsesRemaining--;
|
|
|
|
if (hammer.UsesRemaining < 1)
|
|
{
|
|
hammer.Delete();
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|
|
|
|
int num = 0;
|
|
|
|
Item item;
|
|
if (customCraft != null)
|
|
{
|
|
item = customCraft.CompleteCraft(out num);
|
|
}
|
|
else if (!Core.SA && typeof(MapItem).IsAssignableFrom(ItemType) && from.Map != Map.Trammel && from.Map != Map.Felucca)
|
|
{
|
|
item = new IndecipherableMap();
|
|
from.SendLocalizedMessage(1070800); // The map you create becomes mysteriously indecipherable.
|
|
}
|
|
else if (CreateItem != null)
|
|
{
|
|
item = CreateItem(from, this, tool);
|
|
}
|
|
else
|
|
{
|
|
item = Activator.CreateInstance(ItemType) as Item;
|
|
}
|
|
|
|
if (item != null)
|
|
{
|
|
#region Mondain's Legacy
|
|
if (item is Board)
|
|
{
|
|
Type resourceType = typeRes;
|
|
|
|
if (resourceType == null)
|
|
{
|
|
resourceType = Resources.GetAt(0).ItemType;
|
|
}
|
|
|
|
CraftResource thisResource = CraftResources.GetFromType(resourceType);
|
|
Item oldItem = item;
|
|
|
|
switch (thisResource)
|
|
{
|
|
case CraftResource.OakWood:
|
|
item = new OakBoard();
|
|
break;
|
|
case CraftResource.AshWood:
|
|
item = new AshBoard();
|
|
break;
|
|
case CraftResource.YewWood:
|
|
item = new YewBoard();
|
|
break;
|
|
case CraftResource.Heartwood:
|
|
item = new HeartwoodBoard();
|
|
break;
|
|
case CraftResource.Bloodwood:
|
|
item = new BloodwoodBoard();
|
|
break;
|
|
case CraftResource.Frostwood:
|
|
item = new FrostwoodBoard();
|
|
break;
|
|
default:
|
|
item = new Board();
|
|
break;
|
|
}
|
|
|
|
if (item != oldItem)
|
|
{
|
|
oldItem.Delete();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region High Seas
|
|
if (Core.HS && item is MapItem)
|
|
((MapItem)item).Facet = from.Map;
|
|
#endregion
|
|
|
|
CraftContext context = craftSystem.GetContext(from);
|
|
int originalHue = item.Hue;
|
|
|
|
if (item is ICraftable)
|
|
{
|
|
endquality = ((ICraftable)item).OnCraft(quality, makersMark, from, craftSystem, typeRes, tool, this, resHue);
|
|
}
|
|
else if (item is Food)
|
|
{
|
|
((Food)item).PlayerConstructed = true;
|
|
}
|
|
else if (item.Hue == 0)
|
|
{
|
|
item.Hue = resHue;
|
|
}
|
|
|
|
if (item.Hue == 0 && RetainsColorFromCloth(item) && m_ClothHue != 0)
|
|
{
|
|
item.Hue = m_ClothHue;
|
|
}
|
|
|
|
// This takes into account for natural hues, ie plant hues
|
|
if (item.Hue != originalHue && context.DoNotColor)
|
|
{
|
|
item.Hue = originalHue;
|
|
}
|
|
|
|
if (maxAmount > 0)
|
|
{
|
|
if (!item.Stackable && item is IUsesRemaining)
|
|
{
|
|
((IUsesRemaining)item).UsesRemaining *= maxAmount;
|
|
}
|
|
else
|
|
{
|
|
item.Amount = maxAmount;
|
|
}
|
|
}
|
|
|
|
#region Plant Pigments
|
|
if (m_PlantHue != PlantHue.None)
|
|
{
|
|
if (item is IPlantHue)
|
|
((IPlantHue)item).PlantHue = m_PlantHue;
|
|
else if (item is IPigmentHue)
|
|
((IPigmentHue)item).PigmentHue = PlantPigmentHueInfo.HueFromPlantHue(m_PlantHue);
|
|
}
|
|
else if (m_PlantPigmentHue != PlantPigmentHue.None && item is IPigmentHue)
|
|
{
|
|
((IPigmentHue)item).PigmentHue = m_PlantPigmentHue;
|
|
}
|
|
|
|
if (context.QuestOption == CraftQuestOption.QuestItem)
|
|
{
|
|
PlayerMobile px = from as PlayerMobile;
|
|
|
|
if (!QuestHelper.CheckItem(px, item))
|
|
from.SendLocalizedMessage(1072355, null, 0x23); // That item does not match any of your quest criteria
|
|
}
|
|
|
|
context.RequiredPigmentHue = PlantPigmentHue.None;
|
|
context.RequiredPlantHue = PlantHue.None;
|
|
|
|
m_PlantHue = PlantHue.None;
|
|
m_PlantPigmentHue = PlantPigmentHue.None;
|
|
#endregion
|
|
|
|
MutateAction?.Invoke(from,item,tool);
|
|
|
|
if (CaddelliteCraft)
|
|
{
|
|
Caddellite.TryInfuse(from, item, craftSystem);
|
|
}
|
|
|
|
if (tool is Item && ((Item)tool).Parent is Container)
|
|
{
|
|
Container cntnr = (Container)((Item)tool).Parent;
|
|
|
|
if (!cntnr.TryDropItem(from, item, false))
|
|
{
|
|
if(cntnr != from.Backpack)
|
|
from.AddToBackpack(item);
|
|
else
|
|
item.MoveToWorld(from.Location, from.Map);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
from.AddToBackpack(item);
|
|
}
|
|
|
|
EventSink.InvokeCraftSuccess(new CraftSuccessEventArgs(from, item, tool is Item ? (Item)tool : null));
|
|
|
|
if (from.IsStaff())
|
|
{
|
|
CommandLogging.WriteLine(
|
|
from, "Crafting {0} with craft system {1}", CommandLogging.Format(item), craftSystem.GetType().Name);
|
|
}
|
|
}
|
|
|
|
tool.UsesRemaining--;
|
|
|
|
#region Mondain's Legacy
|
|
if (tool is HammerOfHephaestus)
|
|
{
|
|
if (tool.UsesRemaining < 1)
|
|
{
|
|
tool.UsesRemaining = 0;
|
|
}
|
|
}
|
|
#endregion
|
|
else
|
|
{
|
|
if (tool.UsesRemaining < 1 && tool.BreakOnDepletion)
|
|
{
|
|
toolBroken = true;
|
|
}
|
|
|
|
if (toolBroken)
|
|
{
|
|
tool.Delete();
|
|
}
|
|
}
|
|
|
|
if (num == 0)
|
|
{
|
|
num = craftSystem.PlayEndingEffect(from, false, true, toolBroken, endquality, makersMark, this);
|
|
}
|
|
|
|
bool queryFactionImbue = false;
|
|
int availableSilver = 0;
|
|
FactionItemDefinition def = null;
|
|
Faction faction = null;
|
|
|
|
if (item is IFactionItem)
|
|
{
|
|
def = FactionItemDefinition.Identify(item);
|
|
|
|
if (def != null)
|
|
{
|
|
faction = Faction.Find(from);
|
|
|
|
if (faction != null)
|
|
{
|
|
Town town = Town.FromRegion(from.Region);
|
|
|
|
if (town != null && town.Owner == faction)
|
|
{
|
|
Container pack = from.Backpack;
|
|
|
|
if (pack != null)
|
|
{
|
|
availableSilver = pack.GetAmount(typeof(Silver));
|
|
|
|
if (availableSilver >= def.SilverCost)
|
|
{
|
|
queryFactionImbue = Faction.IsNearType(from, def.VendorType, 12);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Scroll imbuing
|
|
|
|
if (queryFactionImbue)
|
|
{
|
|
from.SendGump(new FactionImbueGump(quality, item, from, craftSystem, tool, num, availableSilver, faction, def));
|
|
}
|
|
else 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.
|
|
}
|
|
|
|
AutoCraftTimer.EndTimer(from);
|
|
}
|
|
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);
|
|
}
|
|
|
|
AutoCraftTimer.EndTimer(from);
|
|
|
|
return;
|
|
}
|
|
|
|
tool.UsesRemaining--;
|
|
|
|
if (tool.UsesRemaining < 1 && tool.BreakOnDepletion)
|
|
{
|
|
toolBroken = true;
|
|
}
|
|
|
|
if (toolBroken)
|
|
{
|
|
tool.Delete();
|
|
}
|
|
|
|
if (UseAllRes)
|
|
{
|
|
MultipleSkillCheck(from, 1);
|
|
}
|
|
|
|
// 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 readonly Mobile m_From;
|
|
private int m_iCount;
|
|
private readonly int m_iCountMax;
|
|
private readonly CraftItem m_CraftItem;
|
|
private readonly CraftSystem m_CraftSystem;
|
|
private readonly Type ItemTypeRes;
|
|
private readonly ITool m_Tool;
|
|
private bool m_AutoCraft;
|
|
|
|
public InternalTimer(
|
|
Mobile from, CraftSystem craftSystem, CraftItem craftItem, Type typeRes, ITool 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;
|
|
ItemTypeRes = typeRes;
|
|
m_Tool = tool;
|
|
m_AutoCraft = AutoCraftTimer.HasTimer(from);
|
|
}
|
|
|
|
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.ItemType);
|
|
|
|
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);
|
|
}
|
|
|
|
AutoCraftTimer.EndTimer(m_From);
|
|
|
|
return;
|
|
}
|
|
|
|
int quality = 1;
|
|
bool allRequiredSkills = true;
|
|
|
|
m_CraftItem.CheckSkills(m_From, ItemTypeRes, m_CraftSystem, ref quality, ref allRequiredSkills, false, 1);
|
|
|
|
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, ItemTypeRes, m_Tool, quality}) as
|
|
CustomCraft;
|
|
}
|
|
catch
|
|
{ }
|
|
|
|
if (cc != null)
|
|
{
|
|
cc.EndCraftAction();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
bool makersMark = false;
|
|
|
|
if (quality == 2 && m_From.Skills[m_CraftSystem.MainSkill].Base >= 100.0)
|
|
{
|
|
makersMark = m_CraftItem.IsMarkable(m_CraftItem.ItemType);
|
|
}
|
|
|
|
if (makersMark && context.MarkOption == CraftMarkOption.PromptForMark && !m_AutoCraft)
|
|
{
|
|
m_From.SendGump(new QueryMakersMarkGump(quality, m_From, m_CraftItem, m_CraftSystem, ItemTypeRes, m_Tool));
|
|
}
|
|
else
|
|
{
|
|
if (context.MarkOption == CraftMarkOption.DoNotMark)
|
|
{
|
|
makersMark = false;
|
|
}
|
|
|
|
m_CraftItem.CompleteCraft(quality, makersMark, m_From, m_CraftSystem, ItemTypeRes, m_Tool, null);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region SA
|
|
public static void RemoveResTarget(Mobile from)
|
|
{
|
|
if (m_HasTarget.Contains(from))
|
|
m_HasTarget.Remove(from);
|
|
}
|
|
|
|
public static void AddResTarget(Mobile from)
|
|
{
|
|
if (!m_HasTarget.Contains(from))
|
|
m_HasTarget.Add(from);
|
|
}
|
|
|
|
public static bool HasResTarget(Mobile from)
|
|
{
|
|
return m_HasTarget.Contains(from);
|
|
}
|
|
|
|
private static List<Mobile> m_HasTarget = new List<Mobile>();
|
|
|
|
public bool NeedsResTarget(Mobile from, CraftSystem craftSystem)
|
|
{
|
|
CraftContext context = craftSystem.GetContext(from);
|
|
|
|
if (context == null || HasResTarget(from))
|
|
return false;
|
|
|
|
Type[][] types = new Type[Resources.Count][];
|
|
Container pack = from.Backpack;
|
|
PlantHue hue = PlantHue.None;
|
|
PlantPigmentHue phue = PlantPigmentHue.None;
|
|
|
|
for (int i = 0; i < types.Length; ++i)
|
|
{
|
|
CraftRes craftRes = Resources.GetAt(i);
|
|
Type type = craftRes.ItemType;
|
|
|
|
if (pack != null)
|
|
{
|
|
Item[] items = pack.FindItemsByType(type);
|
|
|
|
if (items != null && items.Length > 0 && items[0] is IPlantHue)
|
|
hue = ((IPlantHue)items[0]).PlantHue;
|
|
else if (items != null && items.Length > 0 && items[0] is IPigmentHue)
|
|
phue = ((IPigmentHue)items[0]).PigmentHue;
|
|
|
|
foreach (Item item in items)
|
|
{
|
|
if (item is IPlantHue && ((IPlantHue)item).PlantHue != hue)
|
|
return true;
|
|
else if (item is IPigmentHue && ((IPigmentHue)item).PigmentHue != phue)
|
|
return true;
|
|
}
|
|
|
|
if (hue != PlantHue.None)
|
|
context.RequiredPlantHue = hue;
|
|
else if (phue != PlantPigmentHue.None)
|
|
context.RequiredPigmentHue = phue;
|
|
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public class ChooseResTarget : Server.Targeting.Target
|
|
{
|
|
private CraftItem m_CraftItem;
|
|
private CraftSystem m_CraftSystem;
|
|
private Type ItemTypeRes;
|
|
private ITool m_Tool;
|
|
|
|
public ChooseResTarget(Mobile from, CraftItem craftitem, CraftSystem craftSystem, Type typeRes, ITool tool)
|
|
: base(-1, false, Server.Targeting.TargetFlags.None)
|
|
{
|
|
m_CraftItem = craftitem;
|
|
m_CraftSystem = craftSystem;
|
|
ItemTypeRes = typeRes;
|
|
m_Tool = tool;
|
|
|
|
CraftItem.AddResTarget(from);
|
|
}
|
|
|
|
protected override void OnTarget(Mobile from, object targeted)
|
|
{
|
|
CraftContext context = m_CraftSystem.GetContext(from);
|
|
|
|
if (context != null && targeted is IPlantHue)
|
|
context.RequiredPlantHue = ((IPlantHue)targeted).PlantHue;
|
|
else if (context != null && targeted is IPigmentHue)
|
|
context.RequiredPigmentHue = ((IPigmentHue)targeted).PigmentHue;
|
|
|
|
from.EndAction(typeof(CraftSystem));
|
|
m_CraftItem.Craft(from, m_CraftSystem, ItemTypeRes, m_Tool);
|
|
}
|
|
|
|
protected override void OnTargetCancel(Mobile from, Server.Targeting.TargetCancelType cancelType)
|
|
{
|
|
from.EndAction(typeof(CraftSystem));
|
|
from.SendGump(new CraftGump(from, m_CraftSystem, m_Tool, null));
|
|
}
|
|
|
|
protected override void OnTargetFinish(Mobile from)
|
|
{
|
|
CraftItem.RemoveResTarget(from);
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|