From 45d179dae060bb0cde18453e0071464e880e4aff Mon Sep 17 00:00:00 2001 From: Eduardo <6845999+eduardosmaniotto@users.noreply.github.com> Date: Wed, 3 Jun 2026 14:00:59 -0300 Subject: [PATCH] Implement missing Lahap jewel combine/dismantle tax --- .../PlayerActions/Items/ItemStackAction.cs | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/GameLogic/PlayerActions/Items/ItemStackAction.cs b/src/GameLogic/PlayerActions/Items/ItemStackAction.cs index 4af072a5d..e9c5fa69e 100644 --- a/src/GameLogic/PlayerActions/Items/ItemStackAction.cs +++ b/src/GameLogic/PlayerActions/Items/ItemStackAction.cs @@ -11,10 +11,13 @@ namespace MUnique.OpenMU.GameLogic.PlayerActions.Items; /// public class ItemStackAction { + private const int CombineFeePerTen = 500_000; + private const int DismantleFee = 1_000_000; + /// /// Stacks several items to one stacked item. /// - /// The player which is stacking. + /// The player that is stacking. /// The id of the stacking. /// The size of the requested stack. public async ValueTask StackItemsAsync(Player player, byte stackId, byte stackSize) @@ -39,6 +42,13 @@ public async ValueTask StackItemsAsync(Player player, byte stackId, byte stackSi var jewels = player.Inventory.Items.Where(item => item.Definition == mix.SingleJewel).Take(stackSize).ToList(); if (jewels.Count == stackSize) { + var fee = GetCombineFee(stackSize); + if (!player.TryRemoveMoney(fee)) + { + await player.ShowLocalizedBlueMessageAsync(nameof(PlayerMessage.NotEnoughMoney)).ConfigureAwait(false); + return; + } + foreach (var jewel in jewels) { await player.Inventory.RemoveItemAsync(jewel).ConfigureAwait(false); @@ -51,6 +61,7 @@ public async ValueTask StackItemsAsync(Player player, byte stackId, byte stackSi stacked.Durability = 1; await player.Inventory.AddItemAsync(stacked).ConfigureAwait(false); await player.InvokeViewPlugInAsync(p => p.ItemAppearAsync(stacked)).ConfigureAwait(false); + await player.InvokeViewPlugInAsync(p => p.UpdateMoneyAsync()).ConfigureAwait(false); } else { @@ -59,7 +70,7 @@ public async ValueTask StackItemsAsync(Player player, byte stackId, byte stackSi } /// - /// Unstacks the stacked item from the specified slot. + /// Unstack the stacked item from the specified slot. /// /// The player. /// The stack identifier. @@ -91,6 +102,12 @@ public async ValueTask UnstackItemsAsync(Player player, byte stackId, byte slot) return; } + if (!player.TryRemoveMoney(DismantleFee)) + { + await player.ShowLocalizedBlueMessageAsync(nameof(PlayerMessage.NotEnoughMoney)).ConfigureAwait(false); + return; + } + byte pieces = (byte)((stacked.Level + 1) * 10); var freeSlots = player.Inventory!.FreeSlots.Take(pieces).ToList(); @@ -111,13 +128,17 @@ public async ValueTask UnstackItemsAsync(Player player, byte stackId, byte slot) await player.Inventory.AddItemAsync(freeSlot, jewel).ConfigureAwait(false); await player.InvokeViewPlugInAsync(p => p.ItemAppearAsync(jewel)).ConfigureAwait(false); } + + await player.InvokeViewPlugInAsync(p => p.UpdateMoneyAsync()).ConfigureAwait(false); } + private static int GetCombineFee(byte stackSize) => (stackSize / 10) * CombineFeePerTen; + private bool IsCorrectNpcOpened(Player player) { if (player.OpenedNpc is null || player.OpenedNpc.Definition.NpcWindow != NpcWindow.Lahap) { - player.Logger.LogWarning("Probably Hacker tried to Mix/Unmix Jewels without talking to Lahap. Dupe Method. Acc: [{0}] Character: [{1}]", player.Account?.LoginName, player.SelectedCharacter?.Name); + player.Logger.LogWarning("Probably Hacker tried to Combine/Dismantle Jewels without talking to Lahap. Dupe Method. Acc: [{accountName}] Character: [{characterName}]", player.Account?.LoginName, player.SelectedCharacter?.Name); return false; } @@ -129,7 +150,7 @@ private bool IsCorrectNpcOpened(Player player) var mix = player.GameContext.Configuration.JewelMixes.FirstOrDefault(m => m.Number == mixId); if (mix is null) { - player.Logger.LogWarning($"Unkown mix type [{mixId}], Player Name: [{player.SelectedCharacter?.Name}], Account Name: [{player.Account?.LoginName}]"); + player.Logger.LogWarning("Unknown mix type [{mixType}], Player Name: [{characterName}], Account Name: [{accountName}]", mixId, player.SelectedCharacter?.Name, player.Account?.LoginName); } return mix;