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 ) );
+ }
+ }
+ }
+}