From c1d8606167c15393bcda346ecbd46fbb86e4f0e3 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sat, 17 May 2025 03:30:07 -0700 Subject: [PATCH] fix: Refactors Custom Hairstylist (#2188) --- .../Mobiles/Vendors/NPC/CustomHairstylist.cs | 1144 +++++++---------- 1 file changed, 500 insertions(+), 644 deletions(-) diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/CustomHairstylist.cs b/Projects/UOContent/Mobiles/Vendors/NPC/CustomHairstylist.cs index 819224578..ae45ad6d1 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/CustomHairstylist.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/CustomHairstylist.cs @@ -5,680 +5,536 @@ using Server.Gumps; using Server.Items; using Server.Network; -namespace Server.Mobiles +namespace Server.Mobiles; + +[SerializationGenerator(0, false)] +public partial class CustomHairstylist : BaseVendor { - [SerializationGenerator(0, false)] - public partial class CustomHairstylist : BaseVendor + private static readonly HairstylistBuyInfo[] _sellList = + [ + new( + 1018357, // New Hair (50000 gold) + 50000, + false, + (from, vendor, price) => + new ChangeHairstyleGump(from, vendor, price, false, ChangeHairstyleEntry.HairEntries) + ), + new( + 1018358, // New Beard (50000 gold) + 50000, + true, + (from, vendor, price) => + new ChangeHairstyleGump(from, vendor, price, true, ChangeHairstyleEntry.BeardEntries) + ), + new( + 1018359, // Normal Hair Dye (50 gold) + 50, + false, + (_, vendor, price) => + new ChangeHairHueGump(vendor, price, true, true, ChangeHairHueEntry.RegularEntries) + ), + new( + 1018360, // Bright Hair Dye (500000 gold) + 500000, + false, + (_, vendor, price) => + new ChangeHairHueGump(vendor, price, true, true, ChangeHairHueEntry.BrightEntries) + ), + new( + 1018361, // Hair Only Dye (30000 gold) + 30000, + false, + (_, vendor, price) => + new ChangeHairHueGump(vendor, price, true, false, ChangeHairHueEntry.RegularEntries) + ), + new( + 1018362, // Beard Only Dye (30000 gold) + 30000, + true, + (_, vendor, price) => + new ChangeHairHueGump(vendor, price, false, true, ChangeHairHueEntry.RegularEntries) + ), + new( + 1018363, // Bright Hair Only Dye (500000 gold) + 500000, + false, + (_, vendor, price) => + new ChangeHairHueGump(vendor, price, true, false, ChangeHairHueEntry.BrightEntries) + ), + new( + 1018364, // Bright Beard Only Dye (500000 gold) + 500000, + true, + (_, vendor, price) => + new ChangeHairHueGump(vendor, price, false, true, ChangeHairHueEntry.BrightEntries) + ) + ]; + + [Constructible] + public CustomHairstylist() : base("the hairstylist") { - public static readonly object From = new(); - public static readonly object Vendor = new(); - public static readonly object Price = new(); - - private static readonly HairstylistBuyInfo[] m_SellList = - { - new( - 1018357, - 50000, - false, - typeof(ChangeHairstyleGump), - new[] - { From, Vendor, Price, false, ChangeHairstyleEntry.HairEntries } - ), - new( - 1018358, - 50000, - true, - typeof(ChangeHairstyleGump), - new[] - { From, Vendor, Price, true, ChangeHairstyleEntry.BeardEntries } - ), - new( - 1018359, - 50, - false, - typeof(ChangeHairHueGump), - new[] - { From, Vendor, Price, true, true, ChangeHairHueEntry.RegularEntries } - ), - new( - 1018360, - 500000, - false, - typeof(ChangeHairHueGump), - new[] - { From, Vendor, Price, true, true, ChangeHairHueEntry.BrightEntries } - ), - new( - 1018361, - 30000, - false, - typeof(ChangeHairHueGump), - new[] - { From, Vendor, Price, true, false, ChangeHairHueEntry.RegularEntries } - ), - new( - 1018362, - 30000, - true, - typeof(ChangeHairHueGump), - new[] - { From, Vendor, Price, false, true, ChangeHairHueEntry.RegularEntries } - ), - new( - 1018363, - 500000, - false, - typeof(ChangeHairHueGump), - new[] - { From, Vendor, Price, true, false, ChangeHairHueEntry.BrightEntries } - ), - new( - 1018364, - 500000, - true, - typeof(ChangeHairHueGump), - new[] - { From, Vendor, Price, false, true, ChangeHairHueEntry.BrightEntries } - ) - }; - - [Constructible] - public CustomHairstylist() : base("the hairstylist") - { - } - - protected override List SBInfos { get; } = new(); - - public override bool ClickTitle => false; - - public override bool IsActiveBuyer => false; - public override bool IsActiveSeller => true; - - public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; - - public override bool OnBuyItems(Mobile buyer, List list) => false; - - public override void VendorBuy(Mobile from) - { - from.SendGump(new HairstylistBuyGump(from, this, m_SellList)); - } - - public override int GetHairHue() => Utility.RandomBrightHue(); - - public override void InitOutfit() - { - base.InitOutfit(); - - AddItem(new Robe(Utility.RandomPinkHue())); - } - - public override void InitSBInfo() - { - } } - public class HairstylistBuyInfo + protected override List SBInfos { get; } = []; + + public override bool ClickTitle => false; + public override bool IsActiveBuyer => false; + public override bool IsActiveSeller => true; + + public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; + + public override bool OnBuyItems(Mobile buyer, List list) => false; + + public override void VendorBuy(Mobile from) => from.SendGump(new HairstylistBuyGump(from, this, _sellList)); + + public override int GetHairHue() => Utility.RandomBrightHue(); + + public override void InitOutfit() { - public HairstylistBuyInfo(int title, int price, bool facialHair, Type gumpType, object[] args) - { - Title = title; - Price = price; - FacialHair = facialHair; - GumpType = gumpType; - GumpArgs = args; - } + base.InitOutfit(); - public HairstylistBuyInfo(string title, int price, bool facialHair, Type gumpType, object[] args) - { - TitleString = title; - Price = price; - FacialHair = facialHair; - GumpType = gumpType; - GumpArgs = args; - } - - public int Title { get; } - - public string TitleString { get; } - - public int Price { get; } - - public bool FacialHair { get; } - - public Type GumpType { get; } - - public object[] GumpArgs { get; } + AddItem(new Robe(Utility.RandomPinkHue())); } - public class HairstylistBuyGump : Gump + public override void InitSBInfo() { - private readonly Mobile m_From; - private readonly HairstylistBuyInfo[] m_SellList; - private readonly Mobile m_Vendor; - public override bool Singleton => true; - public HairstylistBuyGump(Mobile from, Mobile vendor, HairstylistBuyInfo[] sellList) : base(50, 50) + } +} + +public class HairstylistBuyInfo +{ + public HairstylistBuyInfo( + TextDefinition title, int price, bool facialHair, Func gumpFunction + ) + { + Title = title; + Price = price; + FacialHair = facialHair; + GumpFactoryFn = gumpFunction; + } + + public TextDefinition Title { get; } + + public int Price { get; } + + public bool FacialHair { get; } + + public Func GumpFactoryFn { get; } +} + +public class HairstylistBuyGump : DynamicGump +{ + private readonly Mobile _from; + private readonly HairstylistBuyInfo[] _sellList; + private readonly Mobile _vendor; + public override bool Singleton => true; + + public HairstylistBuyGump(Mobile from, Mobile vendor, HairstylistBuyInfo[] sellList) : base(50, 50) + { + _from = from; + _vendor = vendor; + _sellList = sellList; + + var gumps = from.GetGumps(); + + gumps.Close(); + gumps.Close(); + } + + protected override void BuildLayout(ref DynamicGumpBuilder builder) + { + var isFemale = _from.Female || _from.Body.IsFemale; + + var balance = Banker.GetBalance(_from); + var canAfford = 0; + + for (var i = 0; i < _sellList.Length; ++i) { - m_From = from; - m_Vendor = vendor; - m_SellList = sellList; - - var gumps = from.GetGumps(); - - gumps.Close(); - gumps.Close(); - - var isFemale = from.Female || from.Body.IsFemale; - - var balance = Banker.GetBalance(from); - var canAfford = 0; - - for (var i = 0; i < sellList.Length; ++i) + var buyInfo = _sellList[i]; + if (balance >= buyInfo.Price && (!buyInfo.FacialHair || !isFemale)) { - if (balance >= sellList[i].Price && (!sellList[i].FacialHair || !isFemale)) - { - ++canAfford; - } - } - - AddPage(0); - - AddBackground(50, 10, 450, 100 + canAfford * 25, 2600); - - AddHtmlLocalized(100, 40, 350, 20, 1018356); // Choose your hairstyle change: - - var index = 0; - - for (var i = 0; i < sellList.Length; ++i) - { - if (balance >= sellList[i].Price && (!sellList[i].FacialHair || !isFemale)) - { - if (sellList[i].TitleString != null) - { - AddHtml(140, 75 + index * 25, 300, 20, sellList[i].TitleString); - } - else - { - AddHtmlLocalized(140, 75 + index * 25, 300, 20, sellList[i].Title); - } - - AddButton(100, 75 + index++ * 25, 4005, 4007, 1 + i); - } + ++canAfford; } } - public override void OnResponse(NetState sender, in RelayInfo info) + builder.AddPage(); + builder.AddBackground(50, 10, 450, 100 + canAfford * 25, 2600); + builder.AddHtmlLocalized(100, 40, 350, 20, 1018356); // Choose your hairstyle change: + + var index = 0; + + for (var i = 0; i < _sellList.Length; ++i) { - var index = info.ButtonID - 1; - - if (index >= 0 && index < m_SellList.Length) + var buyInfo = _sellList[i]; + if (balance >= buyInfo.Price && (!buyInfo.FacialHair || !isFemale)) { - var buyInfo = m_SellList[index]; - - var balance = Banker.GetBalance(m_From); - - var isFemale = m_From.Female || m_From.Body.IsFemale; - - if (buyInfo.FacialHair && isFemale) - { - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1010639, m_From.NetState); - } - else if (balance >= buyInfo.Price) - { - try - { - var origArgs = buyInfo.GumpArgs; - var args = new object[origArgs.Length]; - - for (var i = 0; i < args.Length; ++i) - { - if (origArgs[i] == CustomHairstylist.Price) - { - args[i] = m_SellList[index].Price; - } - else if (origArgs[i] == CustomHairstylist.From) - { - args[i] = m_From; - } - else if (origArgs[i] == CustomHairstylist.Vendor) - { - args[i] = m_Vendor; - } - else - { - args[i] = origArgs[i]; - } - } - - var g = buyInfo.GumpType.CreateInstance(args); - - m_From.SendGump(g); - } - catch - { - // ignored - } - } - else - { - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, m_From.NetState); - } + buyInfo.Title.AddHtmlText(ref builder, 140, 75 + index * 25, 300, 20); + builder.AddButton(100, 75 + index++ * 25, 4005, 4007, 1 + i); } } } - public class ChangeHairHueEntry + public override void OnResponse(NetState sender, in RelayInfo info) { - public static readonly ChangeHairHueEntry[] BrightEntries = - { - new("*****", 12, 10), - new("*****", 32, 5), - new("*****", 38, 8), - new("*****", 54, 3), - new("*****", 62, 10), - new("*****", 81, 2), - new("*****", 89, 2), - new("*****", 1153, 2) - }; + var index = info.ButtonID - 1; - public static readonly ChangeHairHueEntry[] RegularEntries = + if (index < 0 || index >= _sellList.Length) { - new("*****", 1602, 26), - new("*****", 1628, 27), - new("*****", 1502, 32), - new("*****", 1302, 32), - new("*****", 1402, 32), - new("*****", 1202, 24), - new("*****", 2402, 29), - new("*****", 2213, 6), - new("*****", 1102, 8), - new("*****", 1110, 8), - new("*****", 1118, 16), - new("*****", 1134, 16) - }; - - public ChangeHairHueEntry(string name, int[] hues) - { - Name = name; - Hues = hues; + return; } - public ChangeHairHueEntry(string name, int start, int count) + var balance = Banker.GetBalance(_from); + var isFemale = _from.Female || _from.Body.IsFemale; + + var buyInfo = _sellList[index]; + if (buyInfo.FacialHair && isFemale) { - Name = name; - - Hues = new int[count]; - - for (var i = 0; i < count; ++i) - { - Hues[i] = start + i; - } + _vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1010639, _from.NetState); } - - public string Name { get; } - - public int[] Hues { get; } - } - - public class ChangeHairHueGump : Gump - { - private readonly ChangeHairHueEntry[] m_Entries; - private readonly bool m_FacialHair; - private readonly Mobile m_From; - private readonly bool m_Hair; - private readonly int m_Price; - private readonly Mobile m_Vendor; - - public override bool Singleton => true; - - public ChangeHairHueGump( - Mobile from, Mobile vendor, int price, bool hair, bool facialHair, - ChangeHairHueEntry[] entries - ) : base(50, 50) + else if (balance >= buyInfo.Price) { - m_From = from; - m_Vendor = vendor; - m_Price = price; - m_Hair = hair; - m_FacialHair = facialHair; - m_Entries = entries; - - AddPage(0); - - AddBackground(100, 10, 350, 370, 2600); - AddBackground(120, 54, 110, 270, 5100); - - AddHtmlLocalized(155, 25, 240, 30, 1011013); //
Hair Color Selection Menu
- - AddHtmlLocalized(150, 330, 220, 35, 1011014); // Dye my hair this color! - AddButton(380, 330, 4005, 4007, 1); - - for (var i = 0; i < entries.Length; ++i) - { - var entry = entries[i]; - - AddLabel(130, 59 + i * 22, entry.Hues[0] - 1, entry.Name); - AddButton(207, 60 + i * 22, 5224, 5224, 0, GumpButtonType.Page, 1 + i); - } - - for (var i = 0; i < entries.Length; ++i) - { - var entry = entries[i]; - var hues = entry.Hues; - var name = entry.Name; - - AddPage(1 + i); - - for (var j = 0; j < hues.Length; ++j) - { - AddLabel(278 + j / 16 * 80, 52 + j % 16 * 17, hues[j] - 1, name); - AddRadio(260 + j / 16 * 80, 52 + j % 16 * 17, 210, 211, false, j * entries.Length + i); - } - } + _from.SendGump(buyInfo.GumpFactoryFn(_from, _vendor, buyInfo.Price)); } - - public override void OnResponse(NetState sender, in RelayInfo info) + else { - if (info.ButtonID == 1) - { - var switches = info.Switches; - - if (switches.Length > 0) - { - var index = switches[0] % m_Entries.Length; - var offset = switches[0] / m_Entries.Length; - - if (index >= 0 && index < m_Entries.Length) - { - if (offset >= 0 && offset < m_Entries[index].Hues.Length) - { - if (m_Hair && m_From.HairItemID > 0 || m_FacialHair && m_From.FacialHairItemID > 0) - { - if (!Banker.Withdraw(m_From, m_Price)) - { - m_Vendor.PrivateOverheadMessage( - MessageType.Regular, - 0x3B2, - 1042293, // You cannot afford my services for that style. - m_From.NetState - ); - return; - } - - var hue = m_Entries[index].Hues[offset]; - - if (m_Hair) - { - m_From.HairHue = hue; - } - - if (m_FacialHair) - { - m_From.FacialHairHue = hue; - } - } - else - { - m_Vendor.PrivateOverheadMessage( - MessageType.Regular, - 0x3B2, - 502623, // You have no hair to dye and you cannot use this. - m_From.NetState - ); - } - } - } - } - else - { - // You decide not to change your hairstyle. - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); - } - } - else - { - // You decide not to change your hairstyle. - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); - } - } - } - - public class ChangeHairstyleEntry - { - public static readonly ChangeHairstyleEntry[] HairEntries = - { - new(50700, 70 - 137, 20 - 60, 0x203B), - new(60710, 193 - 260, 18 - 60, 0x2045), - new(50703, 316 - 383, 25 - 60, 0x2044), - new(60708, 70 - 137, 75 - 125, 0x203C), - new(60900, 193 - 260, 85 - 125, 0x2047), - new(60713, 320 - 383, 85 - 125, 0x204A), - new(60702, 70 - 137, 140 - 190, 0x203D), - new(60707, 193 - 260, 140 - 190, 0x2049), - new(60901, 315 - 383, 150 - 190, 0x2048), - new(0, 0, 0, 0) - }; - - public static readonly ChangeHairstyleEntry[] BeardEntries = - { - new(50800, 120 - 187, 30 - 80, 0x2040), - new(50904, 243 - 310, 33 - 80, 0x204B), - new(50906, 120 - 187, 100 - 150, 0x204D), - new(50801, 243 - 310, 95 - 150, 0x203E), - new(50802, 120 - 187, 173 - 220, 0x203F), - new(50905, 243 - 310, 165 - 220, 0x204C), - new(50808, 120 - 187, 242 - 290, 0x2041), - new(0, 0, 0, 0) - }; - - public ChangeHairstyleEntry(int gumpID, int x, int y, int itemID) - { - GumpID = gumpID; - X = x; - Y = y; - ItemID = itemID; - } - - public int ItemID { get; } - - public int GumpID { get; } - - public int X { get; } - - public int Y { get; } - } - - public class ChangeHairstyleGump : Gump - { - private readonly ChangeHairstyleEntry[] m_Entries; - private readonly bool m_FacialHair; - private readonly Mobile m_From; - private readonly int m_Price; - private readonly Mobile m_Vendor; - - public override bool Singleton => true; - - public ChangeHairstyleGump( - Mobile from, Mobile vendor, int price, bool facialHair, ChangeHairstyleEntry[] entries - ) : base(50, 50) - { - m_From = from; - m_Vendor = vendor; - m_Price = price; - m_FacialHair = facialHair; - m_Entries = entries; - - var gumps = from.GetGumps(); - - gumps.Close(); - gumps.Close(); - - var tableWidth = m_FacialHair ? 2 : 3; - var tableHeight = (entries.Length + tableWidth - (m_FacialHair ? 1 : 2)) / tableWidth; - var offsetWidth = 123; - var offsetHeight = m_FacialHair ? 70 : 65; - - AddPage(0); - - AddBackground(0, 0, 81 + tableWidth * offsetWidth, 105 + tableHeight * offsetHeight, 2600); - - AddButton(45, 45 + tableHeight * offsetHeight, 4005, 4007, 1); - AddHtmlLocalized(77, 45 + tableHeight * offsetHeight, 90, 35, 1006044); // Ok - - AddButton(81 + tableWidth * offsetWidth - 180, 45 + tableHeight * offsetHeight, 4005, 4007, 0); - AddHtmlLocalized( - 81 + tableWidth * offsetWidth - 148, - 45 + tableHeight * offsetHeight, - 90, - 35, - 1006045 - ); // Cancel - - if (!facialHair) - { - AddHtmlLocalized(50, 15, 350, 20, 1018353); //
New Hairstyle
- } - else - { - AddHtmlLocalized(55, 15, 200, 20, 1018354); //
New Beard
- } - - for (var i = 0; i < entries.Length; ++i) - { - var xTable = i % tableWidth; - var yTable = i / tableWidth; - - if (entries[i].GumpID != 0) - { - AddRadio(40 + xTable * offsetWidth, 70 + yTable * offsetHeight, 208, 209, false, i); - AddBackground(87 + xTable * offsetWidth, 50 + yTable * offsetHeight, 50, 50, 2620); - AddImage( - 87 + xTable * offsetWidth + entries[i].X, - 50 + yTable * offsetHeight + entries[i].Y, - entries[i].GumpID - ); - } - else if (!facialHair) - { - AddRadio(40 + (xTable + 1) * offsetWidth, 240, 208, 209, false, i); - AddHtmlLocalized(60 + (xTable + 1) * offsetWidth, 240, 85, 35, 1011064); // Bald - } - else - { - AddRadio(40 + xTable * offsetWidth, 70 + yTable * offsetHeight, 208, 209, false, i); - AddHtmlLocalized(60 + xTable * offsetWidth, 70 + yTable * offsetHeight, 85, 35, 1011064); // Bald - } - } - } - - public override void OnResponse(NetState sender, in RelayInfo info) - { - if (m_FacialHair && (m_From.Female || m_From.Body.IsFemale)) - { - return; - } - - if (m_From.Race == Race.Elf) - { - m_From.SendMessage("This isn't implemented for elves yet. Sorry!"); - return; - } - - if (info.ButtonID == 1) - { - var switches = info.Switches; - - if (switches.Length > 0) - { - var index = switches[0]; - - if (index >= 0 && index < m_Entries.Length) - { - var entry = m_Entries[index]; - - (m_From as PlayerMobile)?.SetHairMods(-1, -1); - - var hairID = m_From.HairItemID; - var facialHairID = m_From.FacialHairItemID; - - if (entry.ItemID == 0) - { - if (m_FacialHair ? facialHairID == 0 : hairID == 0) - { - return; - } - - if (Banker.Withdraw(m_From, m_Price)) - { - if (m_FacialHair) - { - m_From.FacialHairItemID = 0; - } - else - { - m_From.HairItemID = 0; - } - } - else - { - m_Vendor.PrivateOverheadMessage( - MessageType.Regular, - 0x3B2, - 1042293, // You cannot afford my services for that style. - m_From.NetState - ); - } - } - else - { - if (m_FacialHair) - { - if (facialHairID > 0 && facialHairID == entry.ItemID) - { - return; - } - } - else - { - if (hairID > 0 && hairID == entry.ItemID) - { - return; - } - } - - if (Banker.Withdraw(m_From, m_Price)) - { - if (m_FacialHair) - { - m_From.FacialHairItemID = entry.ItemID; - } - else - { - m_From.HairItemID = entry.ItemID; - } - } - else - { - m_Vendor.PrivateOverheadMessage( - MessageType.Regular, - 0x3B2, - 1042293, - m_From.NetState - ); // You cannot afford my services for that style. - } - } - } - } - else - { - // You decide not to change your hairstyle. - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); - } - } - else - { - // You decide not to change your hairstyle. - m_Vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, m_From.NetState); - } + _vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, _from.NetState); + } + } +} + +public class ChangeHairHueEntry +{ + public static readonly ChangeHairHueEntry[] BrightEntries = + [ + new("*****", 12, 10), + new("*****", 32, 5), + new("*****", 38, 8), + new("*****", 54, 3), + new("*****", 62, 10), + new("*****", 81, 2), + new("*****", 89, 2), + new("*****", 1153, 2) + ]; + + public static readonly ChangeHairHueEntry[] RegularEntries = + [ + new("*****", 1602, 26), + new("*****", 1628, 27), + new("*****", 1502, 32), + new("*****", 1302, 32), + new("*****", 1402, 32), + new("*****", 1202, 24), + new("*****", 2402, 29), + new("*****", 2213, 6), + new("*****", 1102, 8), + new("*****", 1110, 8), + new("*****", 1118, 16), + new("*****", 1134, 16) + ]; + + public ChangeHairHueEntry(string name, int[] hues) + { + Name = name; + Hues = hues; + } + + public ChangeHairHueEntry(string name, int start, int count) + { + Name = name; + + Hues = new int[count]; + + for (var i = 0; i < count; ++i) + { + Hues[i] = start + i; + } + } + + public string Name { get; } + + public int[] Hues { get; } +} + +public class ChangeHairHueGump : DynamicGump +{ + private readonly ChangeHairHueEntry[] _entries; + private readonly bool _facialHair; + private readonly bool _hair; + private readonly int _price; + private readonly Mobile _vendor; + + public override bool Singleton => true; + + public ChangeHairHueGump( + Mobile vendor, int price, bool hair, bool facialHair, ChangeHairHueEntry[] entries + ) : base(50, 50) + { + _vendor = vendor; + _price = price; + _hair = hair; + _facialHair = facialHair; + _entries = entries; + } + + protected override void BuildLayout(ref DynamicGumpBuilder builder) + { + builder.AddPage(); + + builder.AddBackground(100, 10, 350, 370, 2600); + builder.AddBackground(120, 54, 110, 270, 5100); + + builder.AddHtmlLocalized(155, 25, 240, 30, 1011013); //
Hair Color Selection Menu
+ + builder.AddHtmlLocalized(150, 330, 220, 35, 1011014); // Dye my hair this color! + builder.AddButton(380, 330, 4005, 4007, 1); + + for (var i = 0; i < _entries.Length; ++i) + { + var entry = _entries[i]; + + builder.AddLabel(130, 59 + i * 22, entry.Hues[0] - 1, entry.Name); + builder.AddButton(207, 60 + i * 22, 5224, 5224, 0, GumpButtonType.Page, 1 + i); + } + + for (var i = 0; i < _entries.Length; ++i) + { + var entry = _entries[i]; + var hues = entry.Hues; + var name = entry.Name; + + builder.AddPage(1 + i); + + for (var j = 0; j < hues.Length; ++j) + { + var page = Math.DivRem(j, 16, out var index); + builder.AddLabel(278 + page * 80, 52 + index * 17, hues[j] - 1, name); + builder.AddRadio(260 + page * 80, 52 + index * 17, 210, 211, false, j * _entries.Length + i); + } + } + } + + public override void OnResponse(NetState sender, in RelayInfo info) + { + var from = sender.Mobile; + + var switches = info.Switches; + if (info.ButtonID != 1 || switches.Length <= 0) + { + // You decide not to change your hairstyle. + _vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, from.NetState); + return; + } + + var offset = Math.DivRem(switches[0], _entries.Length, out var index); + + if (index < 0 || index >= _entries.Length || offset < 0 || offset >= _entries[index].Hues.Length) + { + return; + } + + if ((!_hair || from.HairItemID <= 0) && (!_facialHair || from.FacialHairItemID <= 0)) + { + // You have no hair to dye and you cannot use this. + _vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 502623, sender); + return; + } + + if (!Banker.Withdraw(from, _price)) + { + // You cannot afford my services for that style. + _vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, sender); + return; + } + + var hue = _entries[index].Hues[offset]; + + if (_hair) + { + from.HairHue = hue; + } + + if (_facialHair) + { + from.FacialHairHue = hue; + } + } +} + +public class ChangeHairstyleEntry +{ + public static readonly ChangeHairstyleEntry[] HairEntries = + [ + new(50700, 70 - 137, 20 - 60, 0x203B), + new(60710, 193 - 260, 18 - 60, 0x2045), + new(50703, 316 - 383, 25 - 60, 0x2044), + new(60708, 70 - 137, 75 - 125, 0x203C), + new(60900, 193 - 260, 85 - 125, 0x2047), + new(60713, 320 - 383, 85 - 125, 0x204A), + new(60702, 70 - 137, 140 - 190, 0x203D), + new(60707, 193 - 260, 140 - 190, 0x2049), + new(60901, 315 - 383, 150 - 190, 0x2048), + new(0, 0, 0, 0) + ]; + + public static readonly ChangeHairstyleEntry[] BeardEntries = + [ + new(50800, 120 - 187, 30 - 80, 0x2040), + new(50904, 243 - 310, 33 - 80, 0x204B), + new(50906, 120 - 187, 100 - 150, 0x204D), + new(50801, 243 - 310, 95 - 150, 0x203E), + new(50802, 120 - 187, 173 - 220, 0x203F), + new(50905, 243 - 310, 165 - 220, 0x204C), + new(50808, 120 - 187, 242 - 290, 0x2041), + new(0, 0, 0, 0) + ]; + + public ChangeHairstyleEntry(int gumpID, int x, int y, int itemID) + { + GumpID = gumpID; + X = x; + Y = y; + ItemID = itemID; + } + + public int ItemID { get; } + + public int GumpID { get; } + + public int X { get; } + + public int Y { get; } +} + +public class ChangeHairstyleGump : DynamicGump +{ + private readonly ChangeHairstyleEntry[] _entries; + private readonly bool _facialHair; + private readonly Mobile _from; + private readonly int _price; + private readonly Mobile _vendor; + + public override bool Singleton => true; + + public ChangeHairstyleGump(Mobile from, Mobile vendor, int price, bool facialHair, ChangeHairstyleEntry[] entries) + : base(50, 50) + { + _from = from; + _vendor = vendor; + _price = price; + _facialHair = facialHair; + _entries = entries; + + var gumps = from.GetGumps(); + + gumps.Close(); + gumps.Close(); + } + + protected override void BuildLayout(ref DynamicGumpBuilder builder) + { + var tableWidth = _facialHair ? 2 : 3; + var tableHeight = (_entries.Length + tableWidth - (_facialHair ? 1 : 2)) / tableWidth; + const int offsetWidth = 123; + var offsetHeight = _facialHair ? 70 : 65; + var tableWidthOffset = 81 + tableWidth * offsetWidth; + var tableHeightOffset = 45 + tableHeight * offsetHeight; + + builder.AddPage(); + + builder.AddBackground(0, 0, tableWidthOffset, 60 + tableHeightOffset, 2600); + + builder.AddButton(45, tableHeightOffset, 4005, 4007, 1); + builder.AddHtmlLocalized(77, tableHeightOffset, 90, 35, 1006044); // Ok + + builder.AddButton(tableWidthOffset - 180, tableHeightOffset, 4005, 4007, 0); + // Cancel + builder.AddHtmlLocalized(tableWidthOffset - 148, tableHeightOffset, 90, 35, 1006045); + + if (!_facialHair) + { + builder.AddHtmlLocalized(50, 15, 350, 20, 1018353); //
New Hairstyle
+ } + else + { + builder.AddHtmlLocalized(55, 15, 200, 20, 1018354); //
New Beard
+ } + + for (var i = 0; i < _entries.Length; ++i) + { + var yTable = Math.DivRem(i, tableWidth, out var xTable); + var xOffset = xTable * offsetWidth; + var yOffset = yTable * offsetHeight; + var entry = _entries[i]; + + if (entry.GumpID != 0) + { + builder.AddRadio(40 + xOffset, 70 + yOffset, 208, 209, false, i); + builder.AddBackground(87 + xOffset, 50 + yOffset, 50, 50, 2620); + builder.AddImage(87 + xOffset + entry.X, 50 + yOffset + entry.Y, entry.GumpID); + } + else if (!_facialHair) + { + builder.AddRadio(40 + (xTable + 1) * offsetWidth, 240, 208, 209, false, i); + builder. AddHtmlLocalized(60 + (xTable + 1) * offsetWidth, 240, 85, 35, 1011064); // Bald + } + else + { + builder.AddRadio(40 + xOffset, 70 + yOffset, 208, 209, false, i); + builder.AddHtmlLocalized(60 + xOffset, 70 + yOffset, 85, 35, 1011064); // Bald + } + } + } + + public override void OnResponse(NetState sender, in RelayInfo info) + { + if (_facialHair && (_from.Female || _from.Body.IsFemale)) + { + return; + } + + if (_from.Race == Race.Elf) + { + _from.SendMessage("This isn't implemented for elves yet. Sorry!"); + return; + } + + var switches = info.Switches; + + if (info.ButtonID != 1 || switches.Length <= 0) + { + // You decide not to change your hairstyle. + _vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1013009, _from.NetState); + return; + } + + var index = switches[0]; + + if (index < 0 || index >= _entries.Length) + { + return; + } + + var entry = _entries[index]; + + (_from as PlayerMobile)?.SetHairMods(-1, -1); + + if ((_facialHair ? _from.FacialHairItemID : _from.HairItemID) == entry.ItemID) + { + return; + } + + if (!Banker.Withdraw(_from, _price)) + { + // You cannot afford my services for that style. + _vendor.PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042293, _from.NetState); + } + else if (_facialHair) + { + _from.FacialHairItemID = entry.ItemID; + } + else + { + _from.HairItemID = entry.ItemID; } } }