diff --git a/src/Persistence/Initialization/Updates/AddMissingMerchantStoresPlugIn.cs b/src/Persistence/Initialization/Updates/AddMissingMerchantStoresPlugIn.cs new file mode 100644 index 000000000..e8efb1d73 --- /dev/null +++ b/src/Persistence/Initialization/Updates/AddMissingMerchantStoresPlugIn.cs @@ -0,0 +1,88 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.Updates; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.PlugIns; + +/// +/// This update gives a merchant store to a merchant NPC which has a merchant window +/// but no items assigned, so talking to it opens an empty (non-working) shop. +/// +/// +/// Affected NPC: Christine the General Goods Merchant (545) in the Loren Market. She is given a +/// clone of the general-goods (potion girl) store carried by Thompson the Merchant (231). +/// Two other NPCs in that window state are intentionally left out: Moss The Merchant (492) is the +/// gambler and Market Union Member Julia (547) is a warp NPC, so a general-goods store would not +/// fit either of them. +/// +[PlugIn] +[Display(Name = PlugInName, Description = PlugInDescription)] +[Guid("f78d6e1d-1cb5-45f7-912d-54b2cb1220eb")] +public class AddMissingMerchantStoresPlugIn : UpdatePlugInBase +{ + /// + /// The plug in name. + /// + internal const string PlugInName = "Add missing merchant stores"; + + /// + /// The plug in description. + /// + internal const string PlugInDescription = "Gives a general-goods store to Christine the General Goods Merchant (545), which had a shop window but no items, cloned from Thompson the Merchant (231)."; + + /// + /// The number of the NPC whose store is cloned for the empty merchants. + /// + private const short StoreSourceNpcNumber = 231; // Thompson the Merchant - carries the general-goods (potion girl) store + + /// + /// The numbers of the NPCs which have a merchant window but no store. + /// + private static readonly short[] EmptyMerchantNpcNumbers = [545]; + + /// + public override UpdateVersion Version => UpdateVersion.AddMissingMerchantStores; + + /// + public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id; + + /// + public override string Name => PlugInName; + + /// + public override string Description => PlugInDescription; + + /// + public override bool IsMandatory => false; + + /// + public override DateTime CreatedAt => new(2026, 06, 17, 0, 0, 0, DateTimeKind.Utc); + + /// + protected override ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) + { + var storeSource = gameConfiguration.Monsters.FirstOrDefault(m => m.Number == StoreSourceNpcNumber); + if (storeSource?.MerchantStore is null) + { + return default; + } + + foreach (var number in EmptyMerchantNpcNumbers) + { + var npc = gameConfiguration.Monsters.FirstOrDefault(m => m.Number == number); + if (npc is null || npc.MerchantStore is not null) + { + continue; + } + + npc.MerchantStore = storeSource.MerchantStore.Clone(gameConfiguration); + npc.MerchantStore.SetGuid(npc.Number); + } + + return default; + } +} diff --git a/src/Persistence/Initialization/Updates/UpdateVersion.cs b/src/Persistence/Initialization/Updates/UpdateVersion.cs index 3778ac172..735fa22f8 100644 --- a/src/Persistence/Initialization/Updates/UpdateVersion.cs +++ b/src/Persistence/Initialization/Updates/UpdateVersion.cs @@ -437,4 +437,9 @@ public enum UpdateVersion /// The version of the . /// AddMovementSpeedAttributesSeason6 = 86, + + /// + /// The version of the . + /// + AddMissingMerchantStores = 87, } diff --git a/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs b/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs index b4bcefd2f..d3a887639 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs @@ -941,6 +941,7 @@ public override void Initialize() def.Designation = "Christine the General Goods Merchant"; def.NpcWindow = NpcWindow.Merchant; def.ObjectKind = NpcObjectKind.PassiveNpc; + def.MerchantStore = this.CreatePotionGirlItemStorage(def.Number); def.SetGuid(def.Number); this.GameConfiguration.Monsters.Add(def); }