diff --git a/Maple2.File.Ingest/MapperExtensions.cs b/Maple2.File.Ingest/MapperExtensions.cs index 3c422ace5..c85875d2c 100644 --- a/Maple2.File.Ingest/MapperExtensions.cs +++ b/Maple2.File.Ingest/MapperExtensions.cs @@ -432,7 +432,7 @@ public static Dictionary> ToDictionary } var option = new ItemOption( - MultiplyFactor: entry.multiply_factor, + MultiplyFactor: entry.multiply_factor == 0 ? 1 : entry.multiply_factor, NumPick: new ItemOption.Range(entry.optionNumPick[0], entry.optionNumPick[1]), Entries: optionEntries.ToArray()); if (results[entry.code].ContainsKey(entry.grade)) { diff --git a/Maple2.Model/Game/Item/ItemStats.cs b/Maple2.Model/Game/Item/ItemStats.cs index 187a6c291..0be743414 100644 --- a/Maple2.Model/Game/Item/ItemStats.cs +++ b/Maple2.Model/Game/Item/ItemStats.cs @@ -100,11 +100,14 @@ public class Option { public readonly Dictionary Basic; public readonly Dictionary Special; + public readonly float MultiplyFactor; + public int Count => Basic.Count + Special.Count; - public Option(Dictionary? basicOption = null, Dictionary? specialOption = null) { + public Option(Dictionary? basicOption = null, Dictionary? specialOption = null, float multiplyFactor = 1) { Basic = basicOption ?? new Dictionary(); Special = specialOption ?? new Dictionary(); + MultiplyFactor = multiplyFactor; } public override string ToString() { diff --git a/Maple2.Server.Game/Commands/ItemCommand.cs b/Maple2.Server.Game/Commands/ItemCommand.cs index 3e6165a3c..32c91885e 100644 --- a/Maple2.Server.Game/Commands/ItemCommand.cs +++ b/Maple2.Server.Game/Commands/ItemCommand.cs @@ -28,18 +28,20 @@ public ItemCommand(GameSession session, ItemMetadataStorage itemStorage) : base( var amount = new Option(["--amount", "-a"], () => 1, "Amount of the item."); var rarity = new Option(["--rarity", "-r"], () => 1, "Rarity of the item."); var drop = new Option(["--drop"], "Drop item instead of adding to inventory"); + var rollMax = new Option(["--roll-max"], () => false, "Max roll stats."); AddArgument(id); AddOption(amount); AddOption(rarity); AddOption(drop); - this.SetHandler(Handle, id, amount, rarity, drop); + AddOption(rollMax); + this.SetHandler(Handle, id, amount, rarity, drop, rollMax); } - private void Handle(InvocationContext ctx, int itemId, int amount, int rarity, bool drop) { + private void Handle(InvocationContext ctx, int itemId, int amount, int rarity, bool drop, bool rollMax) { try { rarity = Math.Clamp(rarity, 1, MAX_RARITY); - Item? item = session.Field.ItemDrop.CreateItem(itemId, rarity); + Item? item = session.Field.ItemDrop.CreateItem(itemId, rarity, rollMax: rollMax); if (item == null) { ctx.Console.Error.WriteLine($"Invalid Item: {itemId}"); return; diff --git a/Maple2.Server.Game/Manager/Items/ItemDropManager.cs b/Maple2.Server.Game/Manager/Items/ItemDropManager.cs index 276d69dd5..e7c00e7cf 100644 --- a/Maple2.Server.Game/Manager/Items/ItemDropManager.cs +++ b/Maple2.Server.Game/Manager/Items/ItemDropManager.cs @@ -290,7 +290,7 @@ private bool IsItemJobRecommended(int itemId, JobCode job) { return itemMetadata.Limit.JobRecommends.Contains(job) || itemMetadata.Limit.JobRecommends.Contains(JobCode.None); } - public Item? CreateItem(int itemId, int rarity = -1, int amount = 1) { + public Item? CreateItem(int itemId, int rarity = -1, int amount = 1, bool rollMax = false) { if (!field.ItemMetadata.TryGet(itemId, out ItemMetadata? itemMetadata)) { return null; } @@ -304,7 +304,7 @@ private bool IsItemJobRecommended(int itemId, JobCode job) { } var item = new Item(itemMetadata, rarity, amount); - item.Stats = field.ItemStatsCalc.GetStats(item); + item.Stats = field.ItemStatsCalc.GetStats(item, rollMax); item.Socket = field.ItemStatsCalc.GetSockets(item); if (item.Appearance != null) { diff --git a/Maple2.Server.Game/Util/ItemStatsCalculator.cs b/Maple2.Server.Game/Util/ItemStatsCalculator.cs index 8f8ca8f63..5eed7a701 100644 --- a/Maple2.Server.Game/Util/ItemStatsCalculator.cs +++ b/Maple2.Server.Game/Util/ItemStatsCalculator.cs @@ -18,7 +18,7 @@ public sealed class ItemStatsCalculator { // ReSharper restore All #endregion - public ItemStats? GetStats(Item item) { + public ItemStats? GetStats(Item item, bool rollMax = false) { if (item.Metadata.Option == null) { return null; } @@ -36,7 +36,7 @@ public sealed class ItemStatsCalculator { } if (GetRandomOption(item, out ItemStats.Option? option)) { - RandomizeValues(item.Type, ref option); + RandomizeValues(item.Type, ref option, rollMax); stats[ItemStats.Type.Random] = option; } @@ -106,30 +106,30 @@ public bool UpdateRandomOption(ref Item item, params LockOption[] presets) { } // TODO: These should technically be weighted towards the lower end. - public bool RandomizeValues(in ItemType type, ref ItemStats.Option option) { + public bool RandomizeValues(in ItemType type, ref ItemStats.Option option, bool rollMax = false) { ItemEquipVariationTable? table = GetVariationTable(type); if (table == null) { return false; } foreach (BasicAttribute attribute in option.Basic.Keys) { - int index = Random.Shared.Next(2, 18); + int index = rollMax ? 17 : Random.Shared.Next(2, 18); if (table.Values.TryGetValue(attribute, out int[]? values)) { int value = values.ElementAtOrDefault(index); - option.Basic[attribute] = new BasicOption(value); + option.Basic[attribute] = new BasicOption((int) (value * option.MultiplyFactor)); } else if (table.Rates.TryGetValue(attribute, out float[]? rates)) { float rate = rates.ElementAtOrDefault(index); - option.Basic[attribute] = new BasicOption(rate); + option.Basic[attribute] = new BasicOption(rate * option.MultiplyFactor); } } foreach (SpecialAttribute attribute in option.Special.Keys) { - int index = Random.Shared.Next(2, 18); + int index = rollMax ? 17 : Random.Shared.Next(2, 18); if (table.SpecialValues.TryGetValue(attribute, out int[]? values)) { int value = values.ElementAtOrDefault(index); - option.Special[attribute] = new SpecialOption(0f, value); + option.Special[attribute] = new SpecialOption(0f, value * option.MultiplyFactor); } else if (table.SpecialRates.TryGetValue(attribute, out float[]? rates)) { float rate = rates.ElementAtOrDefault(index); - option.Special[attribute] = new SpecialOption(rate); + option.Special[attribute] = new SpecialOption(rate * option.MultiplyFactor); } } @@ -251,7 +251,7 @@ private static ItemStats.Option RandomItemOption(ItemOption option, int count = int total = count < 0 ? Random.Shared.Next(option.NumPick.Min, option.NumPick.Max + 1) : count; if (total == 0) { - return new ItemStats.Option(statResult, specialResult); + return new ItemStats.Option(statResult, specialResult, multiplyFactor: option.MultiplyFactor); } // Ensures that there are enough options to choose. total = Math.Min(total, option.Entries.Length); @@ -276,7 +276,7 @@ private static ItemStats.Option RandomItemOption(ItemOption option, int count = } } - return new ItemStats.Option(statResult, specialResult); + return new ItemStats.Option(statResult, specialResult, multiplyFactor: option.MultiplyFactor); // Helper function bool AddResult(ItemOption.Entry entry, IDictionary statDict, IDictionary specialDict) {