diff --git a/Maple2.Server.Game/PacketHandlers/ChangeAttributesScrollHandler.cs b/Maple2.Server.Game/PacketHandlers/ChangeAttributesScrollHandler.cs index cd3fab69f..fa2b5830c 100644 --- a/Maple2.Server.Game/PacketHandlers/ChangeAttributesScrollHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ChangeAttributesScrollHandler.cs @@ -111,11 +111,6 @@ private void HandleChange(GameSession session, IByteReader packet) { return; } - if (!TableMetadata.ItemOptionRandomTable.Options.TryGetValue(changeItem.Metadata.Option.RandomId, changeItem.Rarity, out ItemOption? itemOptionMetadata)) { - session.Send(ChangeAttributesScrollPacket.Error(ChangeAttributesScrollError.s_itemremake_scroll_error_impossible_item)); - return; - } - if (itemRemakeScrollMetadata.RollAttribute) { // Randomize attributes. if (lockItem != null) { @@ -138,24 +133,27 @@ private void HandleChange(GameSession session, IByteReader packet) { } } } else { - ItemStats.Option changeOption = changeItem.Stats[ItemStats.Type.Random]; - - if (!ItemStatsCalc.RandomizeValues(changeItem, itemOptionMetadata, ref changeOption)) { - session.Send(ChangeAttributesScrollPacket.Error(ChangeAttributesScrollError.s_itemremake_scroll_error_server_fail_remake)); - return; - } - - // Restore locked attribute values. + // Fixed attributes. if (lockItem != null) { - ItemStats.Option option = item.Stats[ItemStats.Type.Random]; + // Restore locked attribute values. if (isSpecialAttribute) { - var specialAttribute = (SpecialAttribute) attribute; - changeOption.Special[specialAttribute] = option.Special[specialAttribute]; + if (!ItemStatsCalc.UpdateFixedOption(ref changeItem, new LockOption((SpecialAttribute) attribute, true))) { + session.Send(ChangeAttributesPacket.Error(ChangeAttributesError.s_itemremake_error_server_default)); + return; + } } else { - var basicAttribute = (BasicAttribute) attribute; - changeOption.Basic[basicAttribute] = option.Basic[basicAttribute]; + if (!ItemStatsCalc.UpdateFixedOption(ref changeItem, new LockOption((BasicAttribute) attribute, true))) { + session.Send(ChangeAttributesPacket.Error(ChangeAttributesError.s_itemremake_error_server_default)); + return; + } + } + } else { + if (!ItemStatsCalc.UpdateFixedOption(ref changeItem)) { + session.Send(ChangeAttributesPacket.Error(ChangeAttributesError.s_itemremake_error_server_default)); + return; } } + } // Try to consume both items. diff --git a/Maple2.Server.Game/Util/ItemStatsCalculator.cs b/Maple2.Server.Game/Util/ItemStatsCalculator.cs index 263698a4f..a3830687e 100644 --- a/Maple2.Server.Game/Util/ItemStatsCalculator.cs +++ b/Maple2.Server.Game/Util/ItemStatsCalculator.cs @@ -184,6 +184,48 @@ public bool UpdateRandomOption(ref Item item, params LockOption[] presets) { return true; } + public bool UpdateFixedOption(ref Item item, params LockOption[] presets) { + if (item.Metadata.Option == null || item.Stats == null) { + return false; + } + + ItemStats.Option option = item.Stats[ItemStats.Type.Random]; + if (option.Count == 0) { + return false; + } + + // Get fixed options (with right MultiplyFactor) + if (!TableMetadata.ItemOptionRandomTable.Options.TryGetValue(item.Metadata.Option.RandomId, item.Rarity, out ItemOption? itemOption)) { + return false; + } + var statResult = new Dictionary(option.Basic); + var specialResult = new Dictionary(option.Special); + var fixedOption = new ItemStats.Option(statResult, specialResult, multiplyFactor: itemOption.MultiplyFactor); + + if (!RandomizeValues(item, itemOption, ref fixedOption)) { + return false; + } + + // Restore locked values. + foreach (LockOption lockOption in presets) { + if (lockOption.TryGet(out BasicAttribute basic, out bool lockBasicValue)) { + if (lockBasicValue) { + Debug.Assert(option.Basic.ContainsKey(basic), "Missing basic attribute after using lock."); + fixedOption.Basic[basic] = option.Basic[basic]; + } + } else if (lockOption.TryGet(out SpecialAttribute special, out bool lockSpecialValue)) { + if (lockSpecialValue) { + Debug.Assert(option.Special.ContainsKey(special), "Missing special attribute after using lock."); + fixedOption.Special[special] = option.Special[special]; + } + } + } + + // Update item with result. + item.Stats[ItemStats.Type.Random] = fixedOption; + return true; + } + /// Item /// Item's Random Option Metadata ///