using System; using System.Collections.Generic; using System.IO; using System.Linq; using Server.Commands; using Server.Mobiles; using Server.Items; using Server.Engines.VendorSearching; using Server.Gumps; using Server.Network; using Server.Engines.Points; using Server.Multis; namespace Server.Engines.UOStore { public enum StoreCategory { None, Featured, Character, Equipment, Decorations, Mounts, Misc, Cart } public enum SortBy { Name, PriceLower, PriceHigher, Newest, Oldest } public static class UltimaStore { public static readonly string FilePath = Path.Combine("Saves/Misc", "UltimaStore.bin"); public static bool Enabled { get { return Configuration.Enabled; } set { Configuration.Enabled = value; } } public static List Entries { get; private set; } public static Dictionary> PendingItems { get; private set; } private static UltimaStoreContainer _UltimaStoreContainer; public static UltimaStoreContainer UltimaStoreContainer { get { if (_UltimaStoreContainer != null && _UltimaStoreContainer.Deleted) { _UltimaStoreContainer = null; } return _UltimaStoreContainer ?? (_UltimaStoreContainer = new UltimaStoreContainer()); } } static UltimaStore() { Entries = new List(); PendingItems = new Dictionary>(); PlayerProfiles = new Dictionary(); } public static void Configure() { PacketHandlers.Register(0xFA, 1, true, UOStoreRequest); CommandSystem.Register("Store", AccessLevel.Player, e => OpenStore(e.Mobile as PlayerMobile)); EventSink.WorldSave += OnSave; EventSink.WorldLoad += OnLoad; } public static void Initialize() { // Featured StoreCategory cat = StoreCategory.Featured; Register(1109616, 1158384, 0x7818, 0, 0, 1500, cat); Register(1158404, 1158405, 0x2A93, 0, 2598, 1000, cat, ConstructSoulstone); //Register(1158368, 1158369, 0, 0x9CCB, 0, 2000, cat); Register(1125133, 1158015, 0xA095, 0, 0, 600, cat); //Register(1157606, 1157604, 0, 0x9CC9, 0, 300, cat); Register(new TextDefinition[] { 1156614, 1156615 }, 1156679, 0x2AAA, 0, 0, 2500, cat); // Character cat = StoreCategory.Character; Register(new TextDefinition[] { 1158741, 1156615 }, 1158740, 0x2AAA, 0, 0, 600, cat); Register(1158780, 1158781, 0xA276, 0, 0, 600, cat); //Register(1158368, 1158369, 0, 0x9CCB, 0, 2000, cat); Register(1125133, 1158015, 0xA095, 0, 0, 600, cat); Register(1125135, 1158015, 0xA097, 0, 0, 600, cat); Register(1157608, 1157609, 0x2AAA, 0, 0, 500, cat); Register(new TextDefinition[] { 1156614, 1156615 }, 1156679, 0x2AAA, 0, 0, 2500, cat); Register(new TextDefinition[] { 1156612, 1156615 }, 1156677, 0x2AAA, 0, 0, 2000, cat); Register(1149822, 1156676, 0, 0x9C7A, 0, 400, cat); Register(new TextDefinition[] { 1071387, 1071439 }, 1156676, 0, 0x9C78, 0, 400, cat, ConstructHairDye); // Lemon Lime Register(new TextDefinition[] { 1071387, 1071470 }, 1156676, 0, 0x9C6D, 0, 400, cat, ConstructHairDye); // Yew Brown Register(new TextDefinition[] { 1071387, 1071471 }, 1156676, 0, 0x9C6E, 0, 400, cat, ConstructHairDye); // Bloodwood Red Register(new TextDefinition[] { 1071387, 1071438 }, 1156676, 0, 0x9C6F, 0, 400, cat, ConstructHairDye); // Vivid Blue Register(new TextDefinition[] { 1071387, 1071469 }, 1156676, 0, 0x9C71, 0, 400, cat, ConstructHairDye); // Ash Blonde Register(new TextDefinition[] { 1071387, 1071472 }, 1156676, 0, 0x9C72, 0, 400, cat, ConstructHairDye); // Heartwood Green Register(new TextDefinition[] { 1071387, 1071472 }, 1156676, 0, 0x9C85, 0, 400, cat, ConstructHairDye); // Oak Blonde Register(new TextDefinition[] { 1071387, 1071474 }, 1156676, 0, 0x9C70, 0, 400, cat, ConstructHairDye); // Sacred White Register(new TextDefinition[] { 1071387, 1071473 }, 1156676, 0, 0x9C73, 0, 400, cat, ConstructHairDye); // Frostwood Ice Green Register(new TextDefinition[] { 1071387, 1071440 }, 1156676, 0, 0x9C76, 0, 400, cat, ConstructHairDye); // Fiery Blonde Register(new TextDefinition[] { 1071387, 1071437 }, 1156676, 0, 0x9C77, 0, 400, cat, ConstructHairDye); // Bitter Brown Register(new TextDefinition[] { 1071387, 1071442 }, 1156676, 0, 0x9C74, 0, 400, cat, ConstructHairDye); // Gnaw's Twisted Blue Register(new TextDefinition[] { 1071387, 1071441 }, 1156676, 0, 0x9C75, 0, 400, cat, ConstructHairDye); // Dusk Black Register(new TextDefinition[] { 1156609, 1156615 }, 1156642, 0x2AAA, 0, 0, 1000, cat); Register(new TextDefinition[] { 1156608, 1156615 }, 1156641, 0x2AAA, 0, 0, 1000, cat); // Equipment cat = StoreCategory.Equipment; Register(1109616, 1158384, 0x7818, 0, 0, 1500, cat); Register(1125155, 1158016, 0xA0AB, 0, 0, 1500, cat, ConstructRobe); Register(1125155, 1158016, 0xA0AC, 0, 0, 1500, cat, ConstructRobe); Register(1125155, 1158016, 0xA0AD, 0, 0, 1500, cat, ConstructRobe); Register(1125155, 1158016, 0xA0AE, 0, 0, 1500, cat, ConstructRobe); Register(1125155, 1158016, 0xA0AF, 0, 0, 1500, cat, ConstructRobe); Register(new TextDefinition[] { 1071249, 1157275 }, 1156671, 0, 0x9CBF, 0, 400, cat, ConstructHaochisPigment); // Heartwood Sienna Register(new TextDefinition[] { 1071249, 1157274 }, 1156671, 0, 0x9CBD, 0, 400, cat, ConstructHaochisPigment); // Campion White Register(new TextDefinition[] { 1071249, 1157273 }, 1156671, 0, 0x9CC2, 0, 400, cat, ConstructHaochisPigment); // Yewish Pine Register(new TextDefinition[] { 1071249, 1157272 }, 1156671, 0, 0x9CC0, 0, 400, cat, ConstructHaochisPigment); // Minocian Fire Register(new TextDefinition[] { 1071249, 1157269 }, 1156671, 0, 0x9CC1, 0, 400, cat, ConstructHaochisPigment); // Celtic Lime Register(new TextDefinition[] { 1070933, 1070994 }, 1156906, 0, 0x9CA8, 0, 400, cat, ConstructPigments); // Nox Green Register(new TextDefinition[] { 1070933, 1079584 }, 1156906, 0, 0x9CAF, 0, 400, cat, ConstructPigments); // Midnight Coal Register(new TextDefinition[] { 1070933, 1070995 }, 1156906, 0, 0x9CA5, 0, 400, cat, ConstructPigments); // Rum Red Register(new TextDefinition[] { 1070933, 1079580 }, 1156906, 0, 0x9CA4, 0, 400, cat, ConstructPigments); // Coal Register(new TextDefinition[] { 1070933, 1079582 }, 1156906, 0, 0x9CA3, 0, 400, cat, ConstructPigments); // Storm Bronze Register(new TextDefinition[] { 1070933, 1079581 }, 1156906, 0, 0x9CA2, 0, 400, cat, ConstructPigments); // Faded Gold Register(new TextDefinition[] { 1070933, 1070988 }, 1156906, 0, 0x9CA1, 0, 400, cat, ConstructPigments); // Violet Courage Purple Register(new TextDefinition[] { 1070933, 1079585 }, 1156906, 0, 0x9CA2, 0, 400, cat, ConstructPigments); // Faded Bronze Register(new TextDefinition[] { 1070933, 1070996 }, 1156906, 0, 0x9C9F, 0, 400, cat, ConstructPigments); // Fire Orange Register(new TextDefinition[] { 1070933, 1079586 }, 1156906, 0, 0x9C9E, 0, 400, cat, ConstructPigments); // Faded Rose Register(new TextDefinition[] { 1070933, 1079583 }, 1156906, 0, 0x9CA7, 0, 400, cat, ConstructPigments); // Rose Register(new TextDefinition[] { 1070933, 1079587 }, 1156906, 0, 0x9CA9, 0, 400, cat, ConstructPigments); // Deep Rose Register(new TextDefinition[] { 1070933, 1070990 }, 1156906, 0, 0x9CAA, 0, 400, cat, ConstructPigments); // Luna White Register(1157009, 1156908, 0x4B9D, 0, 0, 500, cat); Register(new TextDefinition[] { 1070933, 1070992 }, 1156906, 0, 0x9CAF, 0, 400, cat, ConstructPigments); // Shadow Dancer Black Register(new TextDefinition[] { 1070933, 1070989 }, 1156906, 0, 0x9CAE, 0, 400, cat, ConstructPigments); // Invulnerability Blue Register(new TextDefinition[] { 1070933, 1070991 }, 1156906, 0, 0x9CAD, 0, 400, cat, ConstructPigments); // Dryad Green Register(new TextDefinition[] { 1070933, 1070993 }, 1156906, 0, 0x9CAC, 0, 400, cat, ConstructPigments); // Berserker Red Register(new TextDefinition[] { 1070933, 1079579 }, 1156906, 0, 0x9CAB, 0, 400, cat, ConstructPigments); // Faded Coal Register(new TextDefinition[] { 1070933, 1070987 }, 1156906, 0, 0x9C9D, 0, 400, cat, ConstructPigments); // Paragon Gold Register(new TextDefinition[] { 1071249, 1071246 }, 1156671, 0, 0x9CAF, 0, 400, cat, ConstructHaochisPigment); // Ninja Black Register(new TextDefinition[] { 1071249, 1018352 }, 1156671, 0, 0x9C83, 0, 400, cat, ConstructHaochisPigment); // Olive Register(new TextDefinition[] { 1071249, 1071247 }, 1156671, 0, 0x9C7D, 0, 400, cat, ConstructHaochisPigment); // Dark Reddish Brown Register(new TextDefinition[] { 1071249, 1071245 }, 1156671, 0, 0x9C85, 0, 400, cat, ConstructHaochisPigment); // Yellow Register(new TextDefinition[] { 1071249, 1071244 }, 1156671, 0, 0x9C80, 0, 400, cat, ConstructHaochisPigment); // Pretty Pink Register(new TextDefinition[] { 1071249, 1071248 }, 1156671, 0, 0x9C81, 0, 400, cat, ConstructHaochisPigment); // Midnight Blue Register(new TextDefinition[] { 1071249, 1023856 }, 1156671, 0, 0x9C7F, 0, 400, cat, ConstructHaochisPigment); // Emerald Register(new TextDefinition[] { 1071249, 1115467 }, 1156671, 0, 0x9C82, 0, 400, cat, ConstructHaochisPigment); // Smoky Gold Register(new TextDefinition[] { 1071249, 1115468 }, 1156671, 0, 0x9C7E, 0, 400, cat, ConstructHaochisPigment); // Ghost's Grey Register(new TextDefinition[] { 1071249, 1115471 }, 1156671, 0, 0x9C84, 0, 400, cat, ConstructHaochisPigment); // Ocean Blue Register(1071499, 1156664, 0, 0x9C63, 0, 400, cat); Register(1071498, 1156663, 0x13F8, 0, 0, 500, cat); Register(new TextDefinition[] { 1157010, 1075202 }, 1156967, 0x2F59, 0, 0, 100, cat); Register(1075201, 1156971, 0x2B02, 0, 0, 100, cat); Register(new TextDefinition[] { 1157010, 1031670 }, 1156970, 0x2F59, 0, 0, 100, cat); Register(new TextDefinition[] { 1157010, 1031672 }, 1156969, 0x2F59, 0, 0, 100, cat); Register(1062911, 1156956, 0x1411, 0, 0x2C, 100, cat); Register(1062915, 1156957, 0x26C3, 0, 0x504, 100, cat); Register(1062923, 1156959, 0x236C, 0, 0, 100, cat); Register(1062921, 1156962, 0xF61, 0, 0x482, 100, cat); Register(1075196, 1156963, 0x2B01, 0, 0, 100, cat); Register(1078148, 1156965, 0x2253, 0, 0, 100, cat); Register(new TextDefinition[] { 1157010, 1031671 }, 1156966, 0x2F59, 0, 0, 100, cat); Register(new TextDefinition[] { 1156821, 1156822 }, 1156659, 0, 0x9C66, 0, 200, cat, ConstructEarrings); // Physcial Register(1071092, 1156659, 0, 0x9C66, 0, 200, cat, ConstructEarrings); // Fire Register(1071093, 1156659, 0, 0x9C66, 0, 200, cat, ConstructEarrings); // Cold Register(1071094, 1156659, 0, 0x9C66, 0, 200, cat, ConstructEarrings); // Poison Register(1071095, 1156659, 0, 0x9C66, 0, 200, cat, ConstructEarrings); // Energy Register(1079727, 1156643, 0x2684, 0, 0x455, 1000, cat); // decorations cat = StoreCategory.Decorations; Register(1158970, 1158971, 0, 0x9CE8, 0, 1200, cat); Register(1158859, 1158857, 0xA207, 0, 0, 400, cat); Register(1158859, 1158857, 0xA1F7, 0, 0, 400, cat); Register(1157897, 1157898, 0, 0x9CD7, 0, 600, cat); Register(1157889, 1157890, 0, 0x9CD8, 0, 700, cat); Register(1157206, 1157898, 0, 0x9CBA, 0, 300, cat); Register(1157207, 1157898, 0, 0x9CBA, 0, 500, cat); Register(new TextDefinition[] { 1074482, 1156915 }, 1156974, 0x2A79, 0, 0, 100, cat); Register(new TextDefinition[] { 1074482, 1156914 }, 1156974, 0x2A77, 0, 0, 100, cat); Register(new TextDefinition[] { 1074482, 1156913 }, 1156974, 0x2A75, 0, 0, 100, cat); Register(new TextDefinition[] { 1074482, 1156912 }, 1156974, 0x2A73, 0, 0, 100, cat); Register(new TextDefinition[] { 1074482, 1156911 }, 1156974, 0x2A71, 0, 0, 100, cat); Register(1074480, 1156973, 0x2A65, 0, 0, 100, cat); Register(1074481, 1156972, 0x2A69, 0, 0, 100, cat); Register(1074479, 1156955, 0x2A5D, 0, 0, 100, cat); Register(1075198, 1156968, 0x2AF9, 0, 0, 100, cat); Register(1074801, 1156975, 0, 0x9C8D, 0, 100, cat); Register(1076257, 1156950, 0xC17, 0, 0, 100, cat); Register(1076267, 1156949, 0, 0x9CB9, 0, 100, cat); Register(1076265, 1156943, 0x3DAA, 0, 0, 100, cat); Register(1076263, 1156945, 0, 0x9C8F, 0, 100, cat); Register(1076262, 1156946, 0xC12, 0, 0, 100, cat); Register(1076260, 1156947, 0, 0x9C90, 0, 100, cat); Register(1076258, 1156948, 0xC14, 0, 0, 100, cat); Register(1074818, 1156954, 0, 0x9C8E, 0, 100, cat); Register(1074800, 1156953, 0x2A7B, 0, 0, 100, cat); Register(1076261, 1156951, 0xC24, 0, 0, 100, cat); Register(1076259, 1156952, 0xC1B, 0, 0, 100, cat); Register(1075197, 1156964, 0x2AC0, 0, 0, 100, cat); Register(1062917, 1156961, 0x234E, 0, 0, 100, cat); Register(1062913, 1156960, 0x234D, 0, 0, 100, cat); Register(1062919, 1156958, 0, 0x9C97, 0, 100, cat); Register(1041245, 1156907, 0, 0x9CB8, 0, 200, cat); Register(1151583, 1156909, 0x9706, 0, 0, 500, cat); Register(new TextDefinition[] { 1062096, 1157015 }, 1156916, 0, 0x9CB5, 0, 200, cat, ConstructMiniHouseDeed); // two story wood & plaster Register(new TextDefinition[] { 1062096, 1011317 }, 1156916, 0x22F5, 0, 0, 200, cat, ConstructMiniHouseDeed); // small stone tower Register(new TextDefinition[] { 1062096, 1011307 }, 1156916, 0x22E0, 0, 0, 200, cat, ConstructMiniHouseDeed); // wood and plaster house Register(new TextDefinition[] { 1062096, 1011308 }, 1156916, 0x22E1, 0, 0, 200, cat, ConstructMiniHouseDeed); // thathed-roof cottage Register(new TextDefinition[] { 1062096, 1011312 }, 1156916, 0, 0x9CB2, 0, 200, cat, ConstructMiniHouseDeed); // Tower Register(new TextDefinition[] { 1062096, 1011313 }, 1156916, 0, 0x9CB1, 0, 200, cat, ConstructMiniHouseDeed); // Small stone keep Register(new TextDefinition[] { 1062096, 1011314 }, 1156916, 0, 0x9CB0, 0, 200, cat, ConstructMiniHouseDeed); // Castle Register(1076272, 1156936, 0, 0x9C96, 0, 100, cat); Register(1076279, 1156935, 0, 0x9C9B, 0, 100, cat); Register(1076280, 1156934, 0, 0x9C93, 0, 100, cat); Register(new TextDefinition[] { 1157012, 1157013 }, 1156933, 0x118E, 0, 0, 100, cat); Register(new TextDefinition[] { 1062096, 1011320 }, 1156916, 0x22F3, 0, 0, 200, cat, ConstructMiniHouseDeed); // sanstone house with patio Register(new TextDefinition[] { 1062096, 1011316 }, 1156916, 0, 0x9CB3, 0, 200, cat, ConstructMiniHouseDeed); // marble house with patio Register(new TextDefinition[] { 1062096, 1011319 }, 1156916, 0x2300, 0, 0, 200, cat, ConstructMiniHouseDeed); // two story villa Register(new TextDefinition[] { 1062096, 1157014 }, 1156916, 0, 0x9CB6, 0, 200, cat, ConstructMiniHouseDeed); // two story stone & plaster Register(new TextDefinition[] { 1062096, 1011315 }, 1156916, 0, 0x9CB4, 0, 200, cat, ConstructMiniHouseDeed); // Large house with patio Register(new TextDefinition[] { 1062096, 1011309 }, 1156916, 0, 0x9CB7, 0, 200, cat, ConstructMiniHouseDeed); // brick house Register(new TextDefinition[] { 1062096, 1011304 }, 1156916, 0x22C9, 0, 0, 200, cat, ConstructMiniHouseDeed); // field stone house Register(new TextDefinition[] { 1062096, 1011306 }, 1156916, 0x22DF, 0, 0, 200, cat, ConstructMiniHouseDeed); // wooden house Register(new TextDefinition[] { 1062096, 1011305 }, 1156916, 0x22DE, 0, 0, 200, cat, ConstructMiniHouseDeed); // small brick house Register(new TextDefinition[] { 1062096, 1011303 }, 1156916, 0x22E1, 0, 0, 200, cat, ConstructMiniHouseDeed); // stone and plaster house Register(new TextDefinition[] { 1062096, 1011318 }, 1156916, 0x22FB, 0, 0, 200, cat, ConstructMiniHouseDeed); // two-story log cabin Register(new TextDefinition[] { 1062096, 1011321 }, 1156916, 0x22F6, 0, 0, 200, cat, ConstructMiniHouseDeed); // small stone workshop Register(new TextDefinition[] { 1062096, 1011322 }, 1156916, 0x22F4, 0, 0, 200, cat, ConstructMiniHouseDeed); // small marble workshop Register(1076276, 1156932, 0x118C, 0, 0, 100, cat); Register(1076268, 1156940, 0, 0x9C91, 0, 100, cat); Register(1076288, 1156924, 0x1249, 0, 0, 100, cat); Register(1076286, 1156923, 0x1EA3, 0, 0, 100, cat); Register(1076284, 1156922, 0, 0x9C9A, 0, 100, cat); Register(1076282, 1156921, 0x3D98, 0, 0, 100, cat); Register(1076287, 1156920, 0x2FDE, 0, 0, 100, cat); Register(1076285, 1156919, 0x3D8E, 0, 0, 100, cat); Register(1076283, 1156918, 0, 0x9C94, 0, 100, cat); Register(1076608, 1156917, 0x1E34, 0, 0, 100, cat); Register(1076271, 1156937, 0, 0x9C95, 0, 100, cat); Register(1076269, 1156938, 0, 0x9C8C, 0, 100, cat); Register(1024656, 1156941, 0x125E, 0, 0, 100, cat); Register(1076266, 1156942, 0x3D86, 0, 0, 100, cat); Register(1076270, 1156939, 0, 0x9C98, 0, 100, cat); Register(1076784, 1156925, 0x26EE, 0, 0, 100, cat); Register(1076786, 1156926, 0xD9C, 0, 0, 100, cat); Register(1076264, 1156944, 0xC19, 0, 0, 100, cat); Register(1076277, 1156930, 0x118E, 0, 0, 100, cat); Register(1074027, 1156931, 0, 0x9C9C, 0, 100, cat); Register(1076785, 1156927, 0xD98, 0, 0, 100, cat); Register(new TextDefinition[] { 1157011, 1157013 }, 1156929, 0x118B, 0, 0, 100, cat); Register(1076274, 1156928 , 0, 0x9C92, 0, 100, cat); Register(new TextDefinition[] { 1150359, 1156688 }, 1156680, 0, 0x9C8B, 0, 2000, cat, ConstructRaisedGarden); Register(new TextDefinition[] { 1156683, 1156826 }, 1156668, 0x40B9, 0, 1201, 1000, cat); Register(1026641, 1156670, 0x14F0, 0, 0, 600, cat); Register(1071400, 1156660, 0x2CFD, 0, 0, 200, cat); Register(1071401, 1156661, 0x2D01, 0, 0, 200, cat); Register(1071105, 1156658, 0x224A, 0, 0, 200, cat); Register(1071088, 1156649, 0, 0x9C88, 0, 200, cat); Register(1071089, 1156650, 0xB22, 0, 0, 200, cat, ConstructLampPost); Register(1071090, 1156651, 0x14E7, 0, 0, 200, cat, ConstructHitchingPost); Register(1071096, 1156653, 0x1174, 0, 0, 200, cat); Register(1071102, 1156655, 0x0A9D, 0, 0, 200, cat); Register(1071103, 1156656, 0, 0x9C8A, 0, 200, cat); Register(1071104, 1156657, 0, 0x9C87, 0, 200, cat); // mounts cat = StoreCategory.Mounts; Register(1159165, 1159166, 0xA335, 0, 0, 1000, cat); Register(1158462, 1158738, 0xA138, 0, 0, 1000, cat); Register(1158082, 1158433, 0xA0C0, 0, 0, 1000, cat); Register(1124685, 1157373, 0x9ED5, 0, 0, 1000, cat); Register(1157214, 1157305, 0x9E35, 0, 0, 1000, cat); Register(1075187, 1156646, 0x2D9C, 0, 0, 1000, cat); // misc cat = StoreCategory.Misc; Register(1158404, 1158405, 0x2A93, 0, 2598, 1000, cat, ConstructSoulstone); Register(1071116, 1157603, 0, 0x9CC6, 0, 200, cat, ConstructBOBCoverOne); //TODO: UndeadWeddingBundle, TotemOfChromaticFortune, Register(1157314, 1157372, 0, 0x9CC3, 0, 600, cat); Register(1157177, 1157306, 0, 0x9CBB, 0, 1000, cat); Register(1152921, 1156678, 0, 0x9CBC, 0, 500, cat); Register(new TextDefinition[] { 1149868, 1156686 }, 1156674, 0, 0x9C65, 0, 1000, cat, ConstructForgedMetal); Register(new TextDefinition[] { 1149868, 1156687 }, 1156675, 0, 0x9C65, 0, 600, cat, ConstructForgedMetal); Register(1115358, 1156669, 0, 0x9C62, 0, 600, cat); Register(1150100, 1156673, 0, 0x9C6A, 0, 1200, cat); Register(1078835, 1158405, 0x2ADC, 0, 0, 1000, cat, ConstructSoulstone); Register(1078834, 1158405, 0x2A93, 0, 0, 1000, cat, ConstructSoulstone); Register(new TextDefinition[] { 1156827, 1156681 }, 1156666, 0, 0x9C67, 0, 300, cat, ConstructMerchantsTrinket); Register(new TextDefinition[] { 1156828, 1156682 }, 1156667, 0, 0x9C67, 0, 500, cat, ConstructMerchantsTrinket); Register(1080547, 1156652, 0, 0x9C65, 0, 200, cat); Register(1071116, 1156654, 0, 0x9CC6, 0, 200, cat, ConstructBOBCoverTwo); } public static void Register(TextDefinition name, int tooltip, int itemID, int gumpID, int hue, int cost, StoreCategory cat, Func constructor = null) where T : Item { Register(typeof(T), name, tooltip, itemID, gumpID, hue, cost, cat, constructor); } public static void Register(Type itemType, TextDefinition name, int tooltip, int itemID, int gumpID, int hue, int cost, StoreCategory cat, Func constructor = null) { Register(new StoreEntry(itemType, name, tooltip, itemID, gumpID, hue, cost, cat, constructor)); } public static void Register(TextDefinition[] name, int tooltip, int itemID, int gumpID, int hue, int cost, StoreCategory cat, Func constructor = null) where T : Item { Register(typeof(T), name, tooltip, itemID, gumpID, hue, cost, cat, constructor); } public static void Register(Type itemType, TextDefinition[] name, int tooltip, int itemID, int gumpID, int hue, int cost, StoreCategory cat, Func constructor = null) { Register(new StoreEntry(itemType, name, tooltip, itemID, gumpID, hue, cost, cat, constructor)); } public static void Register(StoreEntry entry) { Entries.Add(entry); } public static bool CanSearch(Mobile m) { return m != null && m.Region.GetLogoutDelay(m) <= TimeSpan.Zero; } public static void UOStoreRequest(NetState state, PacketReader pvSrc) { OpenStore(state.Mobile as PlayerMobile); } public static void OpenStore(PlayerMobile user) { if (user == null || user.NetState == null) { return; } if (!Enabled || (Configuration.Expansion != Expansion.None && Core.Expansion < Configuration.Expansion)) { // The promo code redemption system is currently unavailable. Please try again later. user.SendLocalizedMessage(1062904); return; } if (Configuration.CurrencyImpl == CurrencyType.None) { // The promo code redemption system is currently unavailable. Please try again later. user.SendLocalizedMessage(1062904); return; } if (!user.NetState.UltimaStore) { user.SendMessage("You must update Ultima Online in order to use the in game store."); return; } if (user.AccessLevel < AccessLevel.Counselor && !CanSearch(user)) { // Before using the in game store, you must be in a safe log-out location // such as an inn or a house which has you on its Owner, Co-owner, or Friends list. user.SendLocalizedMessage(1156586); return; } if (!user.HasGump(typeof(UltimaStoreGump))) { BaseGump.SendGump(new UltimaStoreGump(user)); } } #region Constructors public static Item ConstructHairDye(Mobile m, StoreEntry entry) { var info = NaturalHairDye.Table.FirstOrDefault(x => x.Localization == entry.Name[1].Number); if(info != null) { return new NaturalHairDye(info.Type); } return null; } public static Item ConstructHaochisPigment(Mobile m, StoreEntry entry) { var info = HaochisPigment.Table.FirstOrDefault(x => x.Localization == entry.Name[1].Number); if (info != null) { return new HaochisPigment(info.Type, 50); } return null; } public static Item ConstructPigments(Mobile m, StoreEntry entry) { PigmentType type = PigmentType.None; for (int i = 0; i < PigmentsOfTokuno.Table.Length; i++) { if (PigmentsOfTokuno.Table[i][1] == entry.Name[1].Number) { type = (PigmentType)i; break; } } if (type != PigmentType.None) { return new PigmentsOfTokuno(type, 50); } return null; } public static Item ConstructEarrings(Mobile m, StoreEntry entry) { AosElementAttribute ele = AosElementAttribute.Physical; switch (entry.Name[0].Number) { case 1071092: ele = AosElementAttribute.Fire; break; case 1071093: ele = AosElementAttribute.Cold; break; case 1071094: ele = AosElementAttribute.Poison; break; case 1071095: ele = AosElementAttribute.Energy; break; } return new EarringsOfProtection(ele); } public static Item ConstructRobe(Mobile m, StoreEntry entry) { return new HoodedBritanniaRobe(entry.ItemID); } public static Item ConstructMiniHouseDeed(Mobile m, StoreEntry entry) { int label = entry.Name[1].Number; switch (label) { default: for (int i = 0; i < MiniHouseInfo.Info.Length; i++) { if (MiniHouseInfo.Info[i].LabelNumber == entry.Name[1].Number) { var type = (MiniHouseType)i; return new MiniHouseDeed(type); } } return null; case 1157015: return new MiniHouseDeed(MiniHouseType.TwoStoryWoodAndPlaster); case 1157014: return new MiniHouseDeed(MiniHouseType.TwoStoryStoneAndPlaster); } } public static Item ConstructRaisedGarden(Mobile m, StoreEntry entry) { var bag = new Bag(); bag.DropItem(new RaisedGardenDeed()); bag.DropItem(new RaisedGardenDeed()); bag.DropItem(new RaisedGardenDeed()); return bag; } public static Item ConstructLampPost(Mobile m, StoreEntry entry) { var item = new LampPost2 { Movable = true, LootType = LootType.Blessed }; return item; } public static Item ConstructForgedMetal(Mobile m, StoreEntry entry) { switch (entry.Name[1].Number) { case 1156686: return new ForgedMetalOfArtifacts(10); case 1156687: return new ForgedMetalOfArtifacts(5); } return null; } public static Item ConstructSoulstone(Mobile m, StoreEntry entry) { switch (entry.Name[0].Number) { case 1078835: return new SoulstoneToken(SoulstoneType.Blue); case 1078834: return new SoulstoneToken(SoulstoneType.Green); case 1158404: return new SoulstoneToken(SoulstoneType.Violet); } return null; } public static Item ConstructMerchantsTrinket(Mobile m, StoreEntry entry) { switch(entry.Name[0].Number) { case 1156827: return new MerchantsTrinket(false); case 1156828: return new MerchantsTrinket(true); } return null; } public static Item ConstructBOBCoverOne(Mobile m, StoreEntry entry) { return new BagOfBulkOrderCovers(12, 25); } public static Item ConstructBOBCoverTwo(Mobile m, StoreEntry entry) { return new BagOfBulkOrderCovers(1, 11); } public static Item ConstructHitchingPost(Mobile m, StoreEntry entry) { return new HitchingPost(false); } #endregion public static void AddPendingItem(Mobile m, Item item) { if (!PendingItems.TryGetValue(m, out List list)) { PendingItems[m] = list = new List(); } if (!list.Contains(item)) { list.Add(item); } UltimaStoreContainer.DropItem(item); } public static bool HasPendingItem(PlayerMobile pm) { return PendingItems.ContainsKey(pm); } public static void CheckPendingItem(Mobile m) { if (PendingItems.TryGetValue(m, out List list)) { var index = list.Count; while (--index >= 0) { if (index >= list.Count) { continue; } var item = list[index]; if (item != null) { if (m.Backpack != null && m.Alive && m.Backpack.TryDropItem(m, item, false)) { if (item is IPromotionalToken && ((IPromotionalToken)item).ItemName != null) { // A token has been placed in your backpack. Double-click it to redeem your ~1_PROMO~. m.SendLocalizedMessage(1075248, ((IPromotionalToken)item).ItemName.ToString()); } else if (item.LabelNumber > 0 || item.Name != null) { var name = item.LabelNumber > 0 ? ("#" + item.LabelNumber) : item.Name; // Your purchase of ~1_ITEM~ has been placed in your backpack. m.SendLocalizedMessage(1156844, name); } else { // Your purchased item has been placed in your backpack. m.SendLocalizedMessage(1156843); } list.RemoveAt(index); } } else { list.RemoveAt(index); } } if (list.Count == 0 && PendingItems.Remove(m)) { list.TrimExcess(); } } } public static List GetSortedList(string searchString) { var list = new List(); list.AddRange(Entries.Where(e => Insensitive.Contains(GetStringName(e.Name), searchString))); return list; } public static string GetStringName(TextDefinition[] text) { var str = string.Empty; foreach (var td in text) { if (td.Number > 0 && VendorSearch.StringList != null) { str += String.Format("{0} ", VendorSearch.StringList.GetString(td.Number)); } else if (!String.IsNullOrWhiteSpace(td.String)) { str += String.Format("{0} ", td.String); } } return str; } public static string GetStringName(TextDefinition text) { var str = text.String; if (text.Number > 0 && VendorSearch.StringList != null) { str = VendorSearch.StringList.GetString(text.Number); } return str ?? String.Empty; } public static List GetList(StoreCategory cat) { return Entries.Where(e => e.Category == cat).ToList(); } public static void SortList(List list, SortBy sort) { switch (sort) { case SortBy.Name: list.Sort((a, b) => String.CompareOrdinal(GetStringName(a.Name), GetStringName(b.Name))); break; case SortBy.PriceLower: list.Sort((a, b) => a.Price.CompareTo(b.Price)); break; case SortBy.PriceHigher: list.Sort((a, b) => b.Price.CompareTo(a.Price)); break; case SortBy.Newest: break; case SortBy.Oldest: list.Reverse(); break; } } public static int CartCount(Mobile m) { var profile = GetProfile(m, false); if (profile != null) { return profile.Cart.Count; } return 0; } public static int GetSubTotal(Dictionary cart) { if (cart == null || cart.Count == 0) { return 0; } var sub = 0.0; foreach (var kvp in cart) { sub += kvp.Key.Cost * kvp.Value; } return (int)sub; } public static int GetCurrency(Mobile m, bool sendMessage = false) { switch (Configuration.CurrencyImpl) { case CurrencyType.Sovereigns: { if (m is PlayerMobile) { return ((PlayerMobile)m).AccountSovereigns; } } break; case CurrencyType.Gold: return Banker.GetBalance(m); case CurrencyType.PointsSystem: { var sys = PointsSystem.GetSystemInstance(Configuration.PointsImpl); if (sys != null) { return (int)Math.Min(Int32.MaxValue, sys.GetPoints(m)); } } break; case CurrencyType.Custom: return Configuration.GetCustomCurrency(m); } return 0; } public static void TryPurchase(Mobile m) { var cart = GetCart(m); var total = GetSubTotal(cart); if (cart == null || cart.Count == 0 || total == 0) { // Purchase failed due to your cart being empty. m.SendLocalizedMessage(1156842); } else if (total > GetCurrency(m, true)) { if (m is PlayerMobile) { BaseGump.SendGump(new NoFundsGump((PlayerMobile)m)); } } else { var subtotal = 0; var fail = false; var remove = new List(); foreach (var entry in cart) { for (var i = 0; i < entry.Value; i++) { if (!entry.Key.Construct(m)) { fail = true; try { using (var op = File.AppendText("UltimaStoreError.log")) { op.WriteLine("Bad Constructor: {0}", entry.Key.ItemType.Name); Utility.WriteConsoleColor(ConsoleColor.Red, "[Ultima Store]: Bad Constructor: {0}", entry.Key.ItemType.Name); } } catch { } } else { remove.Add(entry.Key); subtotal += entry.Key.Cost; } } } if (subtotal > 0) { DeductCurrency(m, subtotal); } var profile = GetProfile(m); foreach (var entry in remove) { profile.RemoveFromCart(entry); } if (fail) { // Failed to process one of your items. Please check your cart and try again. m.SendLocalizedMessage(1156853); } } } /// /// Should have already passed GetCurrency /// /// /// public static int DeductCurrency(Mobile m, int amount) { switch (Configuration.CurrencyImpl) { case CurrencyType.Sovereigns: { if (m is PlayerMobile && ((PlayerMobile)m).WithdrawSovereigns(amount)) { return amount; } } break; case CurrencyType.Gold: { if (Banker.Withdraw(m, amount, true)) { return amount; } } break; case CurrencyType.PointsSystem: { var sys = PointsSystem.GetSystemInstance(Configuration.PointsImpl); if (sys != null && sys.DeductPoints(m, amount, true)) { return amount; } } break; case CurrencyType.Custom: return Configuration.DeductCustomCurrecy(m, amount); } return 0; } #region Player Persistence public static Dictionary PlayerProfiles { get; private set; } public static PlayerProfile GetProfile(Mobile m, bool create = true) { PlayerProfile profile; if ((!PlayerProfiles.TryGetValue(m, out profile) || profile == null) && create) { PlayerProfiles[m] = profile = new PlayerProfile(m); } return profile; } public static Dictionary GetCart(Mobile m) { var profile = GetProfile(m, false); if (profile != null) { return profile.Cart; } return null; } public static void OnSave(WorldSaveEventArgs e) { Persistence.Serialize(FilePath, Serialize); } public static void OnLoad() { Persistence.Deserialize(FilePath, Deserialize); } private static void Serialize(GenericWriter writer) { writer.Write(0); writer.Write(_UltimaStoreContainer); writer.Write(PendingItems.Count); foreach (var kvp in PendingItems) { writer.Write(kvp.Key); writer.WriteItemList(kvp.Value, true); } writer.Write(PlayerProfiles.Count); foreach (var pe in PlayerProfiles) { pe.Value.Serialize(writer); } } private static void Deserialize(GenericReader reader) { reader.ReadInt(); _UltimaStoreContainer = reader.ReadItem(); var count = reader.ReadInt(); for (var i = 0; i < count; i++) { var m = reader.ReadMobile(); var list = reader.ReadStrongItemList(); if (m != null && list.Count > 0) { PendingItems[m] = list; } } count = reader.ReadInt(); for (var i = 0; i < count; i++) { var pe = new PlayerProfile(reader); if (pe.Player != null) { PlayerProfiles[pe.Player] = pe; } } } #endregion } [DeleteConfirm("This is the Ultima Store item display container. You should not delete this.")] public sealed class UltimaStoreContainer : Container { private static readonly List _DisplayItems = new List(); public override bool Decays { get { return false; } } public override string DefaultName { get { return "Ultima Store Display Container"; } } public UltimaStoreContainer() : base(0) // No Draw { Movable = false; Visible = false; Internalize(); } public UltimaStoreContainer(Serial serial) : base(serial) { } public void AddDisplayItem(Item item) { if (item == null) { return; } if (!_DisplayItems.Contains(item)) { _DisplayItems.Add(item); } DropItem(item); } public Item FindDisplayItem(Type t) { var item = GetDisplayItem(t); if (item == null) { item = Loot.Construct(t); if (item != null) { AddDisplayItem(item); } } return item; } public Item GetDisplayItem(Type t) { return _DisplayItems.FirstOrDefault(x => x.GetType() == t); } public override void Serialize(GenericWriter writer) { base.Serialize(writer); writer.Write(0); writer.WriteItemList(_DisplayItems, true); } public override void Deserialize(GenericReader reader) { base.Deserialize(reader); reader.ReadInt(); var list = reader.ReadStrongItemList(); if (list.Count > 0) { Timer.DelayCall(o => o.ForEach(AddDisplayItem), list); } } } }