Skip to content

Commit ee532da

Browse files
Fix enchant scroll applying single-level stats instead of cumulative (#674)
* Fix enchant scroll applying single-level stats instead of cumulative EnchantScrollHandler.HandleEnchant only called GetEnchant for the target level, giving e.g. only level 11's bonus instead of the sum of levels 1 through 11. HandlePreview also computed deltas from current enchant level instead of absolute cumulative values, showing wrong stats when using a scroll on an already-enchanted item. Both now use GetCumulativeEnchant which sums per-level rates from 1 through the target level, matching manual Ophelia/Peachy enchanting. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: enchant scroll preview floor and in-place enchant update Clamp preview minimum to item's current enchant level (Math.Max) since enchant scrolls never decrease enchant level. Update enchant properties in-place instead of replacing the ItemEnchant object to preserve persisted fields (EnchantExp, EnchantCharges, Charges, Tradeable). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6c7235b commit ee532da

1 file changed

Lines changed: 32 additions & 26 deletions

File tree

Maple2.Server.Game/PacketHandlers/EnchantScrollHandler.cs

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -62,31 +62,17 @@ private void HandlePreview(GameSession session, IByteReader packet) {
6262
return;
6363
}
6464

65-
int minEnchant = Math.Min(item.Enchant?.Enchants ?? 0, metadata.Enchants.Min());
66-
int maxEnchant = metadata.Enchants.Max();
67-
Dictionary<BasicAttribute, BasicOption> minOptions = [];
68-
Dictionary<BasicAttribute, BasicOption> maxOptions = [];
69-
for (int i = minEnchant; i < maxEnchant; i++) {
70-
// add to dictionaries
71-
int targetEnchant = i - 1;
72-
ItemEnchant result = ItemEnchantManager.GetEnchant(session, item, i + 1);
73-
foreach ((BasicAttribute attribute, BasicOption option) in result.BasicOptions) {
74-
if (minOptions.TryGetValue(attribute, out BasicOption currentOption)) {
75-
minOptions[attribute] = currentOption + option;
76-
} else {
77-
minOptions[attribute] = option;
78-
}
79-
}
80-
81-
result = ItemEnchantManager.GetEnchant(session, item, i - 1);
82-
foreach ((BasicAttribute attribute, BasicOption option) in result.BasicOptions) {
83-
if (maxOptions.TryGetValue(attribute, out BasicOption currentOption)) {
84-
maxOptions[attribute] = currentOption + option;
85-
} else {
86-
maxOptions[attribute] = option;
87-
}
88-
}
65+
Dictionary<BasicAttribute, BasicOption> minOptions;
66+
Dictionary<BasicAttribute, BasicOption> maxOptions;
67+
if (metadata.Type == EnchantScrollType.Random) {
68+
int minRoll = Math.Max(metadata.Enchants.Min(), item.Enchant?.Enchants ?? 0);
69+
minOptions = GetCumulativeEnchant(session, item, minRoll).BasicOptions;
70+
maxOptions = GetCumulativeEnchant(session, item, metadata.Enchants.Max()).BasicOptions;
71+
} else {
72+
minOptions = GetCumulativeEnchant(session, item, metadata.Enchants.Max()).BasicOptions;
73+
maxOptions = minOptions;
8974
}
75+
9076
session.Send(EnchantScrollPacket.Preview(item, metadata.Type, minOptions, maxOptions));
9177
}
9278

@@ -122,8 +108,12 @@ private void HandleEnchant(GameSession session, IByteReader packet) {
122108
// Ensure that you cannot randomize an enchant lower than current item.
123109
item.Enchant ??= new ItemEnchant();
124110
if (enchantLevel > item.Enchant.Enchants) {
125-
item.Enchant = ItemEnchantManager.GetEnchant(session, item, enchantLevel);
126-
item.Enchant.Enchants = enchantLevel;
111+
ItemEnchant computed = GetCumulativeEnchant(session, item, enchantLevel);
112+
item.Enchant.Enchants = computed.Enchants;
113+
item.Enchant.BasicOptions.Clear();
114+
foreach ((BasicAttribute attribute, BasicOption option) in computed.BasicOptions) {
115+
item.Enchant.BasicOptions[attribute] = option;
116+
}
127117
}
128118

129119
session.Send(EnchantScrollPacket.Enchant(item));
@@ -151,6 +141,22 @@ private static EnchantScrollError IsCompatibleScroll(Item item, EnchantScrollMet
151141
return s_enchantscroll_ok;
152142
}
153143

144+
private static ItemEnchant GetCumulativeEnchant(GameSession session, Item item, int targetLevel) {
145+
var cumulative = new ItemEnchant();
146+
for (int i = 1; i <= targetLevel; i++) {
147+
ItemEnchant levelEnchant = ItemEnchantManager.GetEnchant(session, item, i);
148+
foreach ((BasicAttribute attribute, BasicOption option) in levelEnchant.BasicOptions) {
149+
if (cumulative.BasicOptions.TryGetValue(attribute, out BasicOption existing)) {
150+
cumulative.BasicOptions[attribute] = existing + option;
151+
} else {
152+
cumulative.BasicOptions[attribute] = option;
153+
}
154+
}
155+
}
156+
cumulative.Enchants = targetLevel;
157+
return cumulative;
158+
}
159+
154160
private bool TryGetMetadata(GameSession session, long scrollUid, [NotNullWhen(true)] out EnchantScrollMetadata? metadata) {
155161
Item? scroll = session.Item.Inventory.Get(scrollUid);
156162
if (scroll == null) {

0 commit comments

Comments
 (0)