diff --git a/Scripts/Engines/Craft/Core/CraftGump.cs b/Scripts/Engines/Craft/Core/CraftGump.cs index 3bda0cc..8acf7bb 100644 --- a/Scripts/Engines/Craft/Core/CraftGump.cs +++ b/Scripts/Engines/Craft/Core/CraftGump.cs @@ -72,6 +72,8 @@ namespace Server.Engines.Craft AddButton( 270, 402, 4005, 4007, GetButtonID( 6, 2 ), GumpButtonType.Reply, 0 ); AddHtmlLocalized( 305, 405, 150, 18, 1044013, LabelColor, false, false ); // MAKE LAST + AddButton( 270, 382, 4005, 4007, GetButtonID( 6, 7 ), GumpButtonType.Reply, 0 ); + AddHtml( 305, 385, 150, 18, "CRAFT QUEUE", false, false ); // Caft Queue // Mark option if ( craftSystem.MarkOption ) { @@ -527,13 +529,17 @@ namespace Server.Engines.Craft m_From.SendGump( new CraftGump( m_From, m_CraftSystem, m_Tool, null, m_Page ) ); + break; + } + case 7: + { + m_From.SendGump( new CraftQueueGump( m_From, m_CraftSystem, 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 8a54d9f..b108cbd 100644 --- a/Scripts/Engines/Craft/Core/CraftGumpItem.cs +++ b/Scripts/Engines/Craft/Core/CraftGumpItem.cs @@ -63,6 +63,10 @@ namespace Server.Engines.Craft AddButton( 15, 387, 4014, 4016, 0, GumpButtonType.Reply, 0 ); AddHtmlLocalized( 50, 390, 150, 18, 1044150, LabelColor, false, false ); // BACK + // --- ADD TO QUEUE BUTTON --- + AddButton( 270, 367, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtml( 305, 370, 150, 18, "ADD TO QUEUE", false, false ); + AddButton( 270, 387, 4005, 4007, 1, GumpButtonType.Reply, 0 ); AddHtmlLocalized( 305, 390, 150, 18, 1044151, LabelColor, false, false ); // MAKE NOW @@ -213,6 +217,14 @@ namespace Server.Engines.Craft CraftGump craftGump = new CraftGump( m_From, m_CraftSystem, m_Tool, null ); m_From.SendGump( craftGump ); } + else if ( info.ButtonID == 2 ) + { + CraftQueue.AddEntry( m_From, m_CraftSystem, m_CraftItem, m_Tool ); + m_From.SendMessage( "Item added to your crafting queue." ); + + // Refresh the gump so they can keep clicking it if they want + m_From.SendGump( new CraftGumpItem( m_From, m_CraftSystem, m_CraftItem, m_Tool ) ); + } else // Make Button { int num = m_CraftSystem.CanCraft( m_From, m_Tool, m_CraftItem.ItemType ); @@ -241,4 +253,4 @@ namespace Server.Engines.Craft } } } -} \ No newline at end of file +} diff --git a/Scripts/Engines/Craft/Core/CraftItem.cs b/Scripts/Engines/Craft/Core/CraftItem.cs index b967d71..6e08c27 100644 --- a/Scripts/Engines/Craft/Core/CraftItem.cs +++ b/Scripts/Engines/Craft/Core/CraftItem.cs @@ -920,6 +920,7 @@ namespace Server.Engines.Craft // Not enough resource to craft it if ( !ConsumeRes( from, typeRes, craftSystem, ref checkResHue, ref checkMaxAmount, ConsumeType.None, ref checkMessage ) ) { + CraftQueue.Pause( from, "Missing resources." ); if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, checkMessage ) ); else if ( checkMessage is int && (int)checkMessage > 0 ) @@ -959,6 +960,7 @@ namespace Server.Engines.Craft // Not enough resource to craft it if ( !ConsumeRes( from, typeRes, craftSystem, ref resHue, ref maxAmount, ConsumeType.All, ref message ) ) { + CraftQueue.Pause( from, "Missing resources." ); if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); else if ( message is int && (int)message > 0 ) @@ -1026,6 +1028,8 @@ namespace Server.Engines.Craft CommandLogging.WriteLine( from, "Crafting {0} with craft system {1}", CommandLogging.Format( item ), craftSystem.GetType().Name ); //from.PlaySound( 0x57 ); + // --- QUEUE SUCCESS HOOK --- + CraftQueue.HandleResult( from, true, quality == 2 ); } if ( num == 0 ) @@ -1075,6 +1079,9 @@ namespace Server.Engines.Craft // SkillCheck failed. int num = craftSystem.PlayEndingEffect( from, true, true, toolBroken, endquality, false, this ); + // --- QUEUE FAIL HOOK --- + CraftQueue.HandleResult( from, false, false ); + if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) from.SendGump( new CraftGump( from, craftSystem, tool, num ) ); else if ( num > 0 ) diff --git a/Scripts/Engines/Craft/Core/CraftQueue.cs b/Scripts/Engines/Craft/Core/CraftQueue.cs new file mode 100644 index 0000000..b8f0ca6 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftQueue.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.Craft; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class CraftQueueEntry + { + public CraftSystem System { get; set; } + public CraftItem Item { get; set; } + public BaseTool Tool { get; set; } + public int Amount { get; set; } + public int Made { get; set; } + public int Failed { get; set; } + public int Exceptional { get; set; } + + public CraftQueueEntry( CraftSystem system, CraftItem item, BaseTool tool ) + { + System = system; + Item = item; + Tool = tool; + Amount = 1; + Made = 0; + Failed = 0; + Exceptional = 0; + } + } + + public class CraftQueue + { + private static Dictionary m_Queues = new Dictionary(); + + public List Entries { get; set; } + public bool IsPaused { get; set; } + + public CraftQueue() + { + Entries = new List(); + IsPaused = true; // Now defaults to Paused so the first click says "START" + } + + public static CraftQueue GetQueue( Mobile m ) + { + if ( !m_Queues.ContainsKey( m ) ) + m_Queues[m] = new CraftQueue(); + + return m_Queues[m]; + } + + public static void AddEntry( Mobile m, CraftSystem system, CraftItem item, BaseTool tool ) + { + CraftQueue queue = GetQueue( m ); + queue.Entries.Add( new CraftQueueEntry( system, item, tool ) ); + } + + public static void Pause( Mobile m, string reason ) + { + CraftQueue queue = GetQueue( m ); + if ( !queue.IsPaused ) + { + queue.IsPaused = true; + m.SendMessage( 0x20, $"Crafting queue paused: {reason}" ); + } + } + + public static void HandleResult( Mobile from, bool success, bool exceptional ) + { + CraftQueue queue = GetQueue( from ); + + if ( queue.IsPaused || queue.Entries.Count == 0 ) + return; + + // Find the first item that still needs crafting + CraftQueueEntry entry = null; + foreach ( var e in queue.Entries ) + { + if ( e.Amount > 0 ) + { + entry = e; + break; + } + } + + if ( entry == null ) return; + + // Tally the stats + if ( success ) + { + entry.Made++; + if ( exceptional ) + entry.Exceptional++; + } + else + { + entry.Failed++; + } + + // Decrement the remaining amount + entry.Amount--; + + // Fire the next craft automatically! + Timer.DelayCall( TimeSpan.FromSeconds( 1.5 ), new TimerStateCallback( ProcessQueue ), from ); + } + + public static void ProcessQueue( object state ) + { + Mobile from = (Mobile)state; + CraftQueue queue = GetQueue( from ); + + if ( queue.IsPaused ) + return; + + // Find the active item + CraftQueueEntry entry = null; + foreach ( var e in queue.Entries ) + { + if ( e.Amount > 0 ) + { + entry = e; + break; + } + } + + if ( entry == null ) + { + from.SendMessage( 0x480, "Your crafting queue is complete!" ); + queue.IsPaused = true; // Auto-pause for the next time they use it + return; + } + + // Safety Check: Did the tool break? + if ( entry.Tool == null || entry.Tool.Deleted || entry.Tool.UsesRemaining <= 0 ) + { + Type toolType = entry.Tool != null ? entry.Tool.GetType() : null; + BaseTool newTool = null; + + // Search the player's backpack for a valid replacement tool + if ( toolType != null && from.Backpack != null ) + { + Item[] tools = from.Backpack.FindItemsByType( toolType ); + foreach ( Item t in tools ) + { + BaseTool bt = t as BaseTool; + if ( bt != null && !bt.Deleted && bt.UsesRemaining > 0 ) + { + newTool = bt; + break; // Found a valid spare! + } + } + } + + if ( newTool != null ) + { + // Swap the broken tool out for the spare and keep going! + entry.Tool = newTool; + from.SendMessage( 0x480, "A broken tool was replaced with a spare from your backpack." ); + } + else + { + // No spares found. Pause so they can go get one. + Pause( from, "Tool broken. Please place a new one in your backpack and hit Start." ); + return; + } + } + + // Figure out what resource (wood, ingot type, etc) they had selected + CraftContext context = entry.System.GetContext( from ); + Type typeRes = null; + if ( context != null ) + { + CraftSubResCol res = entry.System.CraftSubRes; + int resIndex = context.LastResourceIndex; + if ( resIndex > -1 && resIndex < res.Count ) + typeRes = res.GetAt( resIndex ).ItemType; + } + + // Close existing gumps so the screen doesn't spam + from.CloseGump( typeof( CraftGump ) ); + from.CloseGump( typeof( CraftQueueGump ) ); + from.CloseGump( typeof( CraftGumpItem ) ); + + // Start the next craft! + entry.Item.Craft( from, entry.System, typeRes, entry.Tool ); + } + } +} diff --git a/Scripts/Engines/Craft/Core/CraftQueueGump.cs b/Scripts/Engines/Craft/Core/CraftQueueGump.cs new file mode 100644 index 0000000..aa30a58 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftQueueGump.cs @@ -0,0 +1,149 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class CraftQueueGump : Gump + { + private Mobile m_From; + private CraftSystem m_CraftSystem; + private BaseTool m_Tool; + + private const int LabelHue = 0x480; + private const int LabelColor = 0x7FFF; + + public CraftQueueGump( Mobile from, CraftSystem craftSystem, BaseTool tool ) : base( 40, 40 ) + { + m_From = from; + m_CraftSystem = craftSystem; + m_Tool = tool; + + from.CloseGump( typeof( CraftQueueGump ) ); + from.CloseGump( typeof( CraftGump ) ); + + CraftQueue queue = CraftQueue.GetQueue( from ); + + AddPage( 0 ); + AddBackground( 0, 0, 530, 437, 5054 ); + AddImageTiled( 10, 10, 510, 22, 2624 ); + AddAlphaRegion( 10, 10, 510, 417 ); + + AddHtml( 10, 12, 510, 20, "
CRAFTING QUEUE MANAGER
", false, false ); + + // Back Button + AddButton( 15, 402, 4014, 4016, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, 405, 150, 18, 1044150, LabelColor, false, false ); // BACK + + // Play / Pause Button + string playPauseStr = queue.IsPaused ? "START QUEUE" : "PAUSE QUEUE"; + AddButton( 200, 402, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtml( 235, 405, 150, 18, $"{playPauseStr}", false, false ); + + // Update Quantities Button + AddButton( 380, 402, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtml( 415, 405, 150, 18, "UPDATE QTY", false, false ); + + // Main List Background + AddImageTiled( 10, 40, 510, 350, 2624 ); + + // Column Headers + AddHtml( 50, 45, 150, 18, "Item Name", false, false ); + AddHtml( 230, 45, 50, 18, "Target", false, false ); + AddHtml( 310, 45, 200, 18, "Made / Fail / Exc", false, false ); + + // Loop through the queue entries (Displaying up to 10 for clean UI) + for ( int i = 0; i < queue.Entries.Count && i < 10; i++ ) + { + CraftQueueEntry entry = queue.Entries[i]; + int y = 70 + (i * 30); + + // Remove Item Button (Little red X) + AddButton( 15, y, 4020, 4022, 10 + i, GumpButtonType.Reply, 0 ); + + // Item Name + if ( entry.Item.NameNumber > 0 ) + AddHtmlLocalized( 50, y, 170, 18, entry.Item.NameNumber, LabelColor, false, false ); + else + AddLabel( 50, y, LabelHue, entry.Item.NameString ); + + // Text Entry Box for Amount (Dark background) + if ( entry.Amount > 0 ) + { + AddImageTiled( 230, y, 50, 20, 0xBBC ); + AddTextEntry( 230, y, 50, 20, LabelHue, i, entry.Amount.ToString() ); + } + else + { + // If the item finishes, show a green DONE label instead of the text box + AddLabel( 230, y, 68, "DONE" ); + } + + // Statistics + AddLabel( 310, y, LabelHue, $"{entry.Made} / {entry.Failed} / {entry.Exceptional}" ); + } + + if ( queue.Entries.Count == 0 ) + { + AddHtml( 10, 100, 510, 20, "
Your crafting queue is currently empty.
", false, false ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + CraftQueue queue = CraftQueue.GetQueue( from ); + + // Always read and save any typed text amounts before processing buttons + for ( int i = 0; i < queue.Entries.Count && i < 10; i++ ) + { + TextRelay relay = info.GetTextEntry( i ); + if ( relay != null ) + { + int amount; + if ( int.TryParse( relay.Text, out amount ) && amount >= 0 ) + { + queue.Entries[i].Amount = amount; + } + } + } + + if ( info.ButtonID == 0 ) // Back + { + from.SendGump( new CraftGump( from, m_CraftSystem, m_Tool, null ) ); + } + else if ( info.ButtonID == 1 ) // Toggle Pause + { + queue.IsPaused = !queue.IsPaused; + from.SendGump( new CraftQueueGump( from, m_CraftSystem, m_Tool ) ); + + if ( !queue.IsPaused ) + { + from.SendMessage( 0x480, "Crafting queue started." ); + CraftQueue.ProcessQueue( from ); + } + else + { + from.SendMessage( 0x20, "Crafting queue paused." ); + } + } + else if ( info.ButtonID == 2 ) // Update Qty + { + from.SendMessage( 0x480, "Queue quantities updated." ); + from.SendGump( new CraftQueueGump( from, m_CraftSystem, m_Tool ) ); + } + else if ( info.ButtonID >= 10 ) // Remove item from queue + { + int index = info.ButtonID - 10; + if ( index >= 0 && index < queue.Entries.Count ) + { + queue.Entries.RemoveAt( index ); + from.SendMessage( 0x20, "Item removed from queue." ); + } + from.SendGump( new CraftQueueGump( from, m_CraftSystem, m_Tool ) ); + } + } + } +}