From 791f82b4d0982e6097391ebb49c755daa4d4072f Mon Sep 17 00:00:00 2001 From: WarrentyExpired Date: Fri, 7 Aug 2026 19:25:55 -0400 Subject: [PATCH] #W# Added Crafting Queue and Crafting skill list. --- Scripts/Engines/Craft/Core/CraftGump.cs | 25 +- Scripts/Engines/Craft/Core/CraftGumpItem.cs | 63 ++++- Scripts/Engines/Craft/Core/CraftItem.cs | 256 +++++++++++++++++- .../Craft/Core/CraftItemSkillListGump.cs | 162 +++++++++++ Scripts/Engines/Craft/Core/CraftQueue.cs | 153 +++++++++++ .../Craft/Core/CraftQueueAmountGump.cs | 66 +++++ Scripts/Engines/Craft/Core/CraftQueueGump.cs | 191 +++++++++++++ 7 files changed, 911 insertions(+), 5 deletions(-) create mode 100644 Scripts/Engines/Craft/Core/CraftItemSkillListGump.cs create mode 100644 Scripts/Engines/Craft/Core/CraftQueue.cs create mode 100644 Scripts/Engines/Craft/Core/CraftQueueAmountGump.cs create mode 100644 Scripts/Engines/Craft/Core/CraftQueueGump.cs diff --git a/Scripts/Engines/Craft/Core/CraftGump.cs b/Scripts/Engines/Craft/Core/CraftGump.cs index 5bb081f..a85276f 100644 --- a/Scripts/Engines/Craft/Core/CraftGump.cs +++ b/Scripts/Engines/Craft/Core/CraftGump.cs @@ -96,6 +96,16 @@ namespace Server.Engines.Craft } // **************************************** + // --- CraftItemSkillListGump Button --- + AddButton( 410, 342, 4005, 4007, GetButtonID( 6, 9 ), GumpButtonType.Reply, 0 ); + AddHtml( 445, 345, 80, 18, "SKILLS", false, false ); + // ------------------------------------------------------- + + // --- Crafting Queue Button --- + AddButton( 410, 362, 4005, 4007, GetButtonID( 6, 10 ), GumpButtonType.Reply, 0 ); + AddHtml( 445, 365, 80, 18, "QUEUE", false, false ); + // ------------------------------------------------------- + // Enhance option if ( craftSystem.CanEnhance ) { @@ -607,13 +617,24 @@ namespace Server.Engines.Craft if ( system.CanEnhance ) Enhance.BeginTarget( m_From, system, m_Tool ); + break; + } + case 9: // Skill List + { + m_From.SendGump( new CraftGump( m_From, system, m_Tool, null, m_Page ) ); + m_From.SendGump( new CraftItemSkillListGump( m_From, system, m_Tool ) ); + + break; + } + case 10: // Crafting Queue + { + m_From.SendGump( new CraftQueueGump( m_From, system, m_Tool ) ); break; } } - break; } } } } -} \ No newline at end of file +} diff --git a/Scripts/Engines/Craft/Core/CraftGumpItem.cs b/Scripts/Engines/Craft/Core/CraftGumpItem.cs index ecaec78..5eff1d0 100644 --- a/Scripts/Engines/Craft/Core/CraftGumpItem.cs +++ b/Scripts/Engines/Craft/Core/CraftGumpItem.cs @@ -74,7 +74,10 @@ namespace Server.Engines.Craft AddButton( 270, 387, 4005, 4007, 1, GumpButtonType.Reply, 0 ); AddHtmlLocalized( 305, 390, 150, 18, 1044151, LabelColor, false, false ); // MAKE NOW } - + // --- Add to queue --- + AddButton( 385, 387, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtml( 415, 390, 150, 18, "ADD TO QUEUE", false, false ); + // --------------------------------------------- if ( craftItem.NameNumber > 0 ) AddHtmlLocalized( 330, 40, 180, 18, craftItem.NameNumber, LabelColor, false, false ); else @@ -256,6 +259,24 @@ namespace Server.Engines.Craft CraftGump craftGump = new CraftGump( m_From, m_CraftSystem, m_Tool, null ); m_From.SendGump( craftGump ); } + // Add to Queue Button + else if ( info.ButtonID == 2 ) + { + Type typeRes = null; + CraftContext context = m_CraftSystem.GetContext( m_From ); + + if ( context != null ) + { + CraftSubResCol res = ( m_CraftItem.UseSubRes2 ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes ); + int resIndex = ( m_CraftItem.UseSubRes2 ? context.LastResourceIndex2 : context.LastResourceIndex ); + + if ( resIndex > -1 ) + typeRes = res.GetAt( resIndex ).ItemType; + } + m_From.SendGump( new QueueAmountGump( m_From, m_CraftSystem, m_CraftItem, typeRes, m_Tool ) ); + //m_From.SendMessage( 0x35, "How many would you like to add to the queue?" ); + //m_From.Prompt = new QueuePrompt( m_From, m_CraftSystem, m_CraftItem, typeRes, m_Tool ); + } else // Make Button { int num = m_CraftSystem.CanCraft( m_From, m_Tool, m_CraftItem.ItemType ); @@ -284,4 +305,42 @@ namespace Server.Engines.Craft } } } -} \ No newline at end of file + public class QueuePrompt : Server.Prompts.Prompt + { + private Mobile m_From; + private CraftSystem m_System; + private CraftItem m_Item; + private Type m_ResType; + private BaseTool m_Tool; + + public QueuePrompt( Mobile from, CraftSystem system, CraftItem item, Type resType, BaseTool tool ) + { + m_From = from; + m_System = system; + m_Item = item; + m_ResType = resType; + m_Tool = tool; + } + + public override void OnResponse( Mobile from, string text ) + { + int amount = 0; + + // Try to parse the text into a number + if ( int.TryParse( text, out amount ) && amount > 0 ) + { + CraftQueue queue = CraftQueueManager.GetQueue( from, m_System ); + queue.Entries.Add( new CraftQueueEntry( m_Item, m_ResType, amount ) ); + + from.SendMessage( 0x35, "Added {0} of that item to your crafting queue.", amount ); + } + else + { + from.SendMessage( 0x22, "Invalid amount. Must be a number greater than 0." ); + } + + // Send them back to the main menu so they can queue more items! + from.SendGump( new CraftGump( from, m_System, m_Tool, null ) ); + } + } +} diff --git a/Scripts/Engines/Craft/Core/CraftItem.cs b/Scripts/Engines/Craft/Core/CraftItem.cs index bbd8785..3c95a8e 100644 --- a/Scripts/Engines/Craft/Core/CraftItem.cs +++ b/Scripts/Engines/Craft/Core/CraftItem.cs @@ -1064,7 +1064,7 @@ namespace Server.Engines.Craft } } - public void CompleteCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CustomCraft customCraft ) + /*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 ); @@ -1292,6 +1292,260 @@ namespace Server.Engines.Craft else if ( num > 0 ) from.SendLocalizedMessage( num ); } + }*/ + + 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 ( !CraftQueueManager.CheckQueue( from, craftSystem, tool, 1, false, badCraft ) ) + { + 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 ( !CraftQueueManager.CheckQueue( from, craftSystem, tool, 1, false, 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 ( !CraftQueueManager.CheckQueue( from, craftSystem, tool, 1, false, 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; + } + + bool toolBroken = false; + int ignored = 1; + int endquality = 1; + bool allRequiredSkills = true; + + if ( CheckSkills( from, typeRes, craftSystem, ref ignored, ref allRequiredSkills ) ) + { + 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 ( !CraftQueueManager.CheckQueue( from, craftSystem, tool, 1, false, 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 ( !CraftQueueManager.CheckQueue( from, craftSystem, tool, 1, false, 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; + } + + tool.UsesRemaining--; + + if ( craftSystem is DefBlacksmithy ) + { + AncientSmithyHammer hammer = from.FindItemOnLayer( Layer.OneHanded ) as AncientSmithyHammer; + if ( hammer != null && hammer != tool ) + { + hammer.UsesRemaining--; + if ( hammer.UsesRemaining < 1 ) + hammer.Delete(); + } + } + + if ( tool.UsesRemaining < 1 && tool.BreakOnDepletion ) + 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.Trammel && from.Map != Map.Felucca ) + { + 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 ); + Container pack = from.Backpack; + SalvageBag craftBag = pack != null ? pack.FindItemByType( typeof( SalvageBag ) ) as SalvageBag : null; + + if ( craftBag != null && craftBag.TryDropItem( from, item, false ) ) + { + } + else + { + from.AddToBackpack( item ); + } + + if( from.AccessLevel > AccessLevel.Player ) + CommandLogging.WriteLine( from, "Crafting {0} with craft system {1}", CommandLogging.Format( item ), craftSystem.GetType().Name ); + } + + 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 ); + } + } + } + } + } + + if ( queryFactionImbue ) + { + // Halt queue for Faction Imbuing decisions + CraftQueueManager.CheckQueue( from, craftSystem, tool, endquality, true, "Faction Imbue" ); + from.SendGump( new FactionImbueGump( quality, item, from, craftSystem, tool, num, availableSilver, faction, def ) ); + } + else if ( !CraftQueueManager.CheckQueue( from, craftSystem, tool, endquality, true, toolBroken ? (object) 1044038 : (object)null ) ) + { + 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 ( !CraftQueueManager.CheckQueue( from, craftSystem, tool, 1, false, 1044153 ) ) + { + 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; + + if ( !ConsumeRes( from, typeRes, craftSystem, ref resHue, ref maxAmount, consumeType, ref message, true ) ) + { + if ( !CraftQueueManager.CheckQueue( from, craftSystem, tool, 1, false, 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; + } + + tool.UsesRemaining--; + + if ( tool.UsesRemaining < 1 && tool.BreakOnDepletion ) + toolBroken = true; + + if ( toolBroken ) + tool.Delete(); + + int num = craftSystem.PlayEndingEffect( from, true, true, toolBroken, endquality, false, this ); + + if ( !CraftQueueManager.CheckQueue( from, craftSystem, tool, endquality, false, toolBroken ? (object)1044038 : (object)null ) ) + { + 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 diff --git a/Scripts/Engines/Craft/Core/CraftItemSkillListGump.cs b/Scripts/Engines/Craft/Core/CraftItemSkillListGump.cs new file mode 100644 index 0000000..ce51027 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftItemSkillListGump.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using Server.Gumps; +using Server.Network; +using Server.Items; +using System.Linq; +using Server.Mobiles; + +namespace Server.Engines.Craft +{ + public class CraftItemSkillListGump : Gump + { + private const int PAGE_BUTTON_OFFSET = 100; + private const int SHOW_ITEM_INFO_OFFSET = 10000; + + private readonly Mobile m_From; + private readonly CraftSystem m_CraftSystem; + private readonly BaseTool m_Tool; + private readonly List m_CraftItems; + private readonly int m_PageNumber; + + public CraftItemSkillListGump(Mobile from, CraftSystem craftSystem, BaseTool tool, List craftItems, int pageNumber) : base(572, 40) + { + m_From = from; + m_CraftSystem = craftSystem; + m_Tool = tool; + m_CraftItems = craftItems; + m_PageNumber = pageNumber; + + const int HORIZONTAL_LINE = 2700; + const int BORDER_WIDTH = 2; + const int ITEM_HEIGHT = 30; + const int INFO_WINDOW_WIDTH = 300; + AddImageTiled(0, 0, INFO_WINDOW_WIDTH, 400, 2702); + + const int LOCK_COLUMN_X = 5; + const int NAME_COLUMN_X = LOCK_COLUMN_X + 33; + const int SKILL_COLUMN_WIDTH = NAME_COLUMN_X + 30; + const int SKILL_COLUMN_X = INFO_WINDOW_WIDTH - SKILL_COLUMN_WIDTH; + const int ITEM_START_Y = 2 * ITEM_HEIGHT; + + // Fixed: Replaced HtmlColors.OFFWHITE with standard UO 0x7FFF + TextDefinition.AddHtmlText(this, LOCK_COLUMN_X, 30, INFO_WINDOW_WIDTH, 20, "Craft these items for skill gains", false, false, 0x7FFF, 0x7FFF); + TextDefinition.AddHtmlText(this, SKILL_COLUMN_X, 10, SKILL_COLUMN_WIDTH, 40, "Max Skill", false, false, 0x7FFF, 0x7FFF); + + const int ITEMS_PER_PAGE = 10; + var maxPages = (int)Math.Ceiling((double)m_CraftItems.Count / ITEMS_PER_PAGE); + int lineIndex = 0; + var toSkip = (pageNumber - 1) * ITEMS_PER_PAGE; + foreach (var craftItem in m_CraftItems.Skip(toSkip).Take(ITEMS_PER_PAGE)) + { + for (int k = 0; k < craftItem.Skills.Count; k++) + { + CraftSkill skill = craftItem.Skills.GetAt(k); + if (skill.SkillToMake == craftSystem.MainSkill) + { + var y = ITEM_START_Y + (lineIndex * ITEM_HEIGHT); + // Add border above item + if (0 < lineIndex) // Skip the first + AddImageTiled(10, y - 7, INFO_WINDOW_WIDTH - 15, BORDER_WIDTH, HORIZONTAL_LINE); + + // Fixed: Removed missing CliLocTable and used core TextDefinition + TextDefinition name = craftItem.NameString == null ? new TextDefinition(craftItem.NameNumber) : new TextDefinition(craftItem.NameString); + var hasRecipe = craftItem.Recipe == null || (from is PlayerMobile && ((PlayerMobile)from).HasRecipe( craftItem.Recipe )); + + if (!hasRecipe) + { + AddImage(LOCK_COLUMN_X + 8, y + 3, 2092); // Lock icon + // Fixed: AddTooltip requires a cliloc integer, not a string! + AddTooltip(1073620); // "You have not learned this recipe." + } + else + { + AddButton(LOCK_COLUMN_X, y - 2, 4011, 4012, SHOW_ITEM_INFO_OFFSET + toSkip + lineIndex, GumpButtonType.Reply, 0); // Info icon + } + + // Fixed: Replaced HtmlColors.OFFWHITE with standard UO 0x7FFF + TextDefinition.AddHtmlText(this, NAME_COLUMN_X, y, SKILL_COLUMN_X - 20, 20, name, false, false, 0x7FFF, 0x7FFF); + TextDefinition.AddHtmlText(this, SKILL_COLUMN_X, y, SKILL_COLUMN_WIDTH, 20, String.Format("{0:F1}", skill.MaxSkill), false, false, 0x7FFF, 0x7FFF); + + lineIndex++; + break; + } + } + } + + // Add page buttons + if (maxPages != 1) + { + AddButton(NAME_COLUMN_X, 365, 4014, 4015, PAGE_BUTTON_OFFSET + (pageNumber == 1 ? maxPages : pageNumber - 1), GumpButtonType.Reply, 0); // Previous + AddButton(SKILL_COLUMN_X, 365, 4005, 4006, PAGE_BUTTON_OFFSET + (pageNumber == maxPages ? 1 : pageNumber + 1), GumpButtonType.Reply, 0); // Next + } + } + + public CraftItemSkillListGump(Mobile from, CraftSystem craftSystem, BaseTool tool) : this(from, craftSystem, tool, CreateItemList(from, craftSystem), 1) + { + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 0) return; + + if (SHOW_ITEM_INFO_OFFSET <= info.ButtonID) + { + var itemIndex = info.ButtonID - SHOW_ITEM_INFO_OFFSET; + var item = m_CraftItems[itemIndex]; + + sender.Mobile.SendGump(new CraftItemSkillListGump(m_From, m_CraftSystem, m_Tool, m_CraftItems, m_PageNumber)); + var itemInfoGump = new CraftGumpItem(sender.Mobile, m_CraftSystem, item, m_Tool); + sender.Mobile.SendGump(itemInfoGump); + } + else if (PAGE_BUTTON_OFFSET <= info.ButtonID) + { + var pageNumber = info.ButtonID - PAGE_BUTTON_OFFSET; + sender.Mobile.SendGump(new CraftItemSkillListGump(m_From, m_CraftSystem, m_Tool, m_CraftItems, pageNumber)); + } + } + + public static List CreateItemList(Mobile from, CraftSystem craftSystem) + { + var craftItems = new List(); + for (int i = 0; i < craftSystem.CraftGroups.Count; i++) + { + var group = craftSystem.CraftGroups.GetAt(i); + + for (int j = 0; j < group.CraftItems.Count; j++) + { + var craftItem = group.CraftItems.GetAt(j); + + bool hasSkills = true; + for (int k = 0; k < craftItem.Skills.Count; k++) + { + CraftSkill skill = craftItem.Skills.GetAt(k); + if ( + from.Skills[skill.SkillToMake].Value < skill.MinSkill // Filter items you can't succeed on + || skill.MaxSkill <= from.Skills[skill.SkillToMake].Value // Filter items you can longer gain from + ) + { + hasSkills = false; + break; + } + } + + if (hasSkills) + craftItems.Add(craftItem); + } + } + + // Sort by max skill descending + return craftItems.OrderByDescending(craftItem => + { + for (int k = 0; k < craftItem.Skills.Count; k++) + { + CraftSkill skill = craftItem.Skills.GetAt(k); + if (skill.SkillToMake == craftSystem.MainSkill) return skill.MaxSkill; + } + + return 0; + }).ToList(); + } + } +} diff --git a/Scripts/Engines/Craft/Core/CraftQueue.cs b/Scripts/Engines/Craft/Core/CraftQueue.cs new file mode 100644 index 0000000..886fa0f --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftQueue.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.Craft; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class CraftQueueEntry + { + public CraftItem CraftItem { get; set; } + public Type ResourceType { get; set; } + public int TargetAmount { get; set; } + public int AmountMade { get; set; } + public int AmountFailed { get; set; } + public int AmountExceptional { get; set; } + public bool IsCompleted { get; set; } + + public CraftQueueEntry( CraftItem item, Type resType, int target ) + { + CraftItem = item; + ResourceType = resType; + TargetAmount = target; + IsCompleted = false; + } + } + + public class CraftQueue + { + public List Entries { get; set; } + public bool IsPaused { get; set; } + + public CraftQueue() + { + Entries = new List(); + IsPaused = true; // Always start paused so they can safely build the list + } + } + + public static class CraftQueueManager + { + private static Dictionary> m_Data = new Dictionary>(); + + // Here is the GetQueue method that went missing! + public static CraftQueue GetQueue( Mobile m, CraftSystem system ) + { + if ( !m_Data.ContainsKey( m ) ) + m_Data[m] = new Dictionary(); + + if ( !m_Data[m].ContainsKey( system ) ) + m_Data[m][system] = new CraftQueue(); + + return m_Data[m][system]; + } + + public static bool CheckQueue( Mobile from, CraftSystem system, BaseTool tool, int endquality, bool success, object haltMessage ) + { + CraftQueue queue = GetQueue( from, system ); + + if ( queue.IsPaused || queue.Entries.Count == 0 ) + return false; + + // --- AVATARS CONQUEST: Seamless Auto-Tool Replacement --- + if ( haltMessage is int && (int)haltMessage == 1044038 ) + { + BaseTool replacement = from.Backpack != null ? from.Backpack.FindItemByType( tool.GetType() ) as BaseTool : null; + + if ( replacement != null && !replacement.Deleted && replacement.UsesRemaining > 0 ) + { + tool = replacement; // Swap to the new tool + haltMessage = null; // Erase the error message so the queue doesn't pause! + from.SendMessage( 0x35, "Your tool broke, but you automatically equipped a new one!" ); + } + } + + // 1. Tally stats for the item that just finished + CraftQueueEntry current = queue.Entries.Find( e => !e.IsCompleted ); + + if ( current != null ) + { + if ( success ) + { + current.AmountMade++; // <--- The ONLY place it counts up now! + + if ( endquality == 2 ) + current.AmountExceptional++; + + if ( current.AmountMade >= current.TargetAmount ) + { + current.IsCompleted = true; + from.SendMessage( 0x3E, "Queue task complete: " + current.CraftItem.NameString ); + } + } + else + { + // If it wasn't a success and it isn't just a broken tool, count it as a failure + if ( haltMessage is int && (int)haltMessage == 1044038 ) + { + // The item WAS successfully made, the tool just broke, so don't count a failure + } + else + { + current.AmountFailed++; + + // Also check completion on failure if we want to stop after X attempts + if ( (current.AmountMade + current.AmountFailed) >= current.TargetAmount ) + { + current.IsCompleted = true; + from.SendMessage( 0x3E, "Queue task complete (with failures): " + current.CraftItem.NameString ); + } + } + } + } + + if ( haltMessage != null ) + { + queue.IsPaused = true; + from.SendMessage( 0x22, "Queue paused: Missing materials, tool broke, or skill too low." ); + from.CloseGump( typeof( CraftQueueGump ) ); + from.SendGump( new CraftQueueGump( from, system, tool ) ); + return false; + } + + // Refresh UI + from.CloseGump( typeof( CraftQueueGump ) ); + from.SendGump( new CraftQueueGump( from, system, tool ) ); + + // 2. Logic to find the NEXT thing to craft + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), delegate() + { + CraftQueue currentQueue = GetQueue( from, system ); + + // Find the next incomplete item + CraftQueueEntry next = currentQueue.Entries.Find( e => !e.IsCompleted ); + + if ( !currentQueue.IsPaused && next != null && from.NetState != null && tool != null && !tool.Deleted ) + { + // Execute the craft call for the NEXT item + next.CraftItem.Craft( from, system, next.ResourceType, tool ); + } + else if ( next == null ) // All entries completed + { + currentQueue.IsPaused = true; + from.SendMessage( 0x3E, "All crafting queue tasks are finished." ); + from.CloseGump( typeof( CraftQueueGump ) ); + from.SendGump( new CraftQueueGump( from, system, tool ) ); + } + }); + + return true; + } + } +} diff --git a/Scripts/Engines/Craft/Core/CraftQueueAmountGump.cs b/Scripts/Engines/Craft/Core/CraftQueueAmountGump.cs new file mode 100644 index 0000000..9171a92 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftQueueAmountGump.cs @@ -0,0 +1,66 @@ +using System; +using Server.Gumps; +using Server.Network; +using Server.Engines.Craft; +using Server.Items; +namespace Server.Engines.Craft +{ + public class QueueAmountGump : Gump + { + private Mobile m_From; + private CraftSystem m_System; + private CraftItem m_Item; + private Type m_ResType; + private BaseTool m_Tool; + + public QueueAmountGump( Mobile from, CraftSystem system, CraftItem item, Type resType, BaseTool tool ) : base( 200, 200 ) + { + m_From = from; + m_System = system; + m_Item = item; + m_ResType = resType; + m_Tool = tool; + + // Match the theme: 5054 background, 2624 tiles + AddBackground( 0, 0, 250, 160, 5054 ); + AddImageTiled( 10, 10, 230, 22, 2624 ); + AddAlphaRegion( 10, 10, 230, 140 ); + + AddHtml( 10, 12, 230, 20, "
AMOUNT TO QUEUE
", false, false ); + + // Input Box + AddImageTiled( 50, 50, 150, 25, 2624 ); + AddTextEntry( 55, 52, 140, 20, 0x480, 1, "1" ); + + // Buttons + AddButton( 40, 110, 4005, 4007, 1, GumpButtonType.Reply, 0 ); // OK + AddLabel( 70, 113, 0x480, "ADD " ); + + AddButton( 150, 110, 4017, 4019, 0, GumpButtonType.Reply, 0 ); // CANCEL + AddLabel( 185, 113, 0x480, "CANCEL " ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + { + TextRelay relay = info.GetTextEntry( 1 ); + int amount = 0; + + if ( relay != null && int.TryParse( relay.Text, out amount ) && amount > 0 ) + { + CraftQueue queue = CraftQueueManager.GetQueue( m_From, m_System ); + queue.Entries.Add( new CraftQueueEntry( m_Item, m_ResType, amount ) ); + m_From.SendMessage( 0x35, "Added {0} of that item to your queue.", amount ); + } + else + { + m_From.SendMessage( 0x22, "Invalid amount." ); + } + } + + // Always return to the craft gump + m_From.SendGump( new CraftGump( m_From, m_System, m_Tool, null ) ); + } + } +} diff --git a/Scripts/Engines/Craft/Core/CraftQueueGump.cs b/Scripts/Engines/Craft/Core/CraftQueueGump.cs new file mode 100644 index 0000000..58d8352 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftQueueGump.cs @@ -0,0 +1,191 @@ +using System; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class CraftQueueGump : Gump + { + private Mobile m_From; + private CraftSystem m_System; + private BaseTool m_Tool; + private CraftQueue m_Queue; + + public CraftQueueGump( Mobile from, CraftSystem system, BaseTool tool ) : base( 40, 40 ) + { + m_From = from; + m_System = system; + m_Tool = tool; + m_Queue = CraftQueueManager.GetQueue( from, system ); + + AddPage( 0 ); + AddBackground( 0, 0, 600, 440, 5054 ); + AddImageTiled( 10, 10, 580, 22, 2624 ); + AddImageTiled( 10, 37, 580, 360, 2624 ); + AddImageTiled( 10, 402, 580, 28, 2624 ); + AddAlphaRegion( 10, 10, 580, 420 ); + + AddHtml( 10, 12, 580, 20, "
CRAFTING QUEUE
", false, false ); + + // Column Headers + AddHtml( 15, 40, 150, 20, "Item", false, false ); + AddHtml( 165, 40, 100, 20, "Material", false, false ); + AddHtml( 275, 40, 50, 20, "Target", false, false ); + AddHtml( 335, 40, 50, 20, "Made", false, false ); + AddHtml( 395, 40, 50, 20, "Fail", false, false ); + AddHtml( 455, 40, 50, 20, "Exc", false, false ); + AddHtml( 515, 40, 50, 20, "Remove", false, false ); + + int y = 60; + + for ( int i = 0; i < m_Queue.Entries.Count; i++ ) + { + CraftQueueEntry entry = m_Queue.Entries[i]; + int statusHue = entry.IsCompleted ? 0x3E : 0x480; + if ( entry.CraftItem.NameNumber > 0 ) + AddHtmlLocalized( 15, y, 140, 20, entry.CraftItem.NameNumber, 0x7FFF, false, false ); + else + AddLabel( 15, y, statusHue, entry.CraftItem.NameString ); + // --- MANUAL RESOURCE OVERRIDE --- + string resName = "Default"; + + if (entry.ResourceType != null) + { + resName = entry.ResourceType.Name; + } + else + { + // Clean up the system name + string systemName = m_System.GetType().Name.Replace("Def", "").Replace("Craft", ""); + + // Hardcode the base materials + if (systemName == "Blacksmithy") + resName = "Iron Ingot"; + else if (systemName == "Carpentry" || systemName == "Bowcraft") + resName = "Board"; + else if (systemName == "Tailoring") + { + bool requiresCloth = false; + + // Look at the first ingredient required to make this item + if (entry.CraftItem.Resources.Count > 0) + { + Type reqType = entry.CraftItem.Resources.GetAt(0).ItemType; + if (reqType == typeof(Server.Items.Cloth) || reqType == typeof(Server.Items.UncutCloth)) + { + requiresCloth = true; + } + } + + if (requiresCloth) + resName = "Cloth"; + else + resName = "Leather"; + } + } + + // Render as pure white (1152) using the standard AddLabel method + AddLabel(165, y, 1152, resName); + AddLabel( 275, y, 0x480, entry.TargetAmount.ToString() ); + AddLabel( 335, y, 0x35, entry.AmountMade.ToString() ); + AddLabel( 395, y, 0x22, entry.AmountFailed.ToString() ); + AddLabel( 455, y, 0x3E, entry.AmountExceptional.ToString() ); + + AddButton( 525, y + 3, 4017, 4019, 100 + i, GumpButtonType.Reply, 0 ); + + y += 20; + if ( y > 380 ) break; + } + + // Footer Buttons + AddButton( 15, 405, 4014, 4016, 0, GumpButtonType.Reply, 0 ); + AddHtml( 50, 407, 100, 20, "BACK", false, false ); + + // Dynamic Play/Pause Button + AddButton( 250, 405, m_Queue.IsPaused ? 4005 : 4011, m_Queue.IsPaused ? 4007 : 4012, 1, GumpButtonType.Reply, 0 ); + AddHtml( 285, 407, 100, 20, m_Queue.IsPaused ? "PLAY QUEUE" : "PAUSE QUEUE", false, false ); + + AddButton( 450, 405, 4017, 4019, 2, GumpButtonType.Reply, 0 ); + AddHtml( 485, 407, 100, 20, "CLEAR ALL", false, false ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 0 ) // Back + { + m_From.SendGump( new CraftGump( m_From, m_System, m_Tool, null ) ); + } + else if ( info.ButtonID == 1 ) // Play/Pause Toggle + { + m_Queue.IsPaused = !m_Queue.IsPaused; + + if ( !m_Queue.IsPaused && m_Queue.Entries.Count > 0 ) + { + // --- AVATARS CONQUEST: Auto-Tool Replacement --- + if ( m_Tool == null || m_Tool.Deleted || m_Tool.UsesRemaining <= 0 ) + { + // Try to find a replacement tool of the exact same type in their backpack + BaseTool replacement = m_From.Backpack != null ? m_From.Backpack.FindItemByType( m_Tool.GetType() ) as BaseTool : null; + + if ( replacement != null && !replacement.Deleted && replacement.UsesRemaining > 0 ) + { + m_Tool = replacement; // Swap the broken tool for the new one! + m_From.SendMessage( 0x35, "Equipped a new tool from your backpack." ); + } + else + { + m_From.SendMessage( 0x22, "You do not have a working tool to continue crafting." ); + m_Queue.IsPaused = true; + m_From.SendGump( new CraftQueueGump( m_From, m_System, m_Tool ) ); + return; + } + } + // ----------------------------------------------- + + m_From.SendMessage( 0x35, "Crafting queue started." ); + + // Make sure we grab the next INCOMPLETE item, not just the top of the list + CraftQueueEntry next = m_Queue.Entries.Find( e => !e.IsCompleted ); + + if ( next != null ) + { + next.CraftItem.Craft( m_From, m_System, next.ResourceType, m_Tool ); + return; // Exit here so it doesn't reopen the gump + } + else + { + m_From.SendMessage( 0x3E, "Queue is already completely finished." ); + m_Queue.IsPaused = true; + } + } + else if ( !m_Queue.IsPaused && m_Queue.Entries.Count == 0 ) + { + m_From.SendMessage( 0x22, "Your queue is empty." ); + m_Queue.IsPaused = true; + } + else + { + m_From.SendMessage( 0x22, "Crafting queue paused." ); + } + + m_From.SendGump( new CraftQueueGump( m_From, m_System, m_Tool ) ); + } + else if ( info.ButtonID == 2 ) // Clear All + { + m_Queue.Entries.Clear(); + m_From.SendGump( new CraftQueueGump( m_From, m_System, m_Tool ) ); + } + else if ( info.ButtonID >= 100 ) // Remove specific item + { + int index = info.ButtonID - 100; + if ( index >= 0 && index < m_Queue.Entries.Count ) + { + m_Queue.Entries.RemoveAt( index ); + } + m_From.SendGump( new CraftQueueGump( m_From, m_System, m_Tool ) ); + } + } + } +}