Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/DataModel/Configuration/DropItemGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public enum SpecialItemType
/// The money special item type.
/// </summary>
Money,

/// <summary>
/// The jewel special item type.
/// </summary>
Jewel,
}

/// <summary>
Expand Down
22 changes: 20 additions & 2 deletions src/GameLogic/DefaultDropGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public class DefaultDropGenerator : IDropGenerator
/// </summary>
public static readonly int BaseMoneyDrop = 7;

private static readonly int DropLevelMaxGap = 12;

private readonly IRandomizer _randomizer;

/// <summary>
Expand Down Expand Up @@ -433,7 +435,23 @@ private void AddRandomExcOptions(Item item)
else
{
var monsterLevel = (int)monster[Stats.Level];
var filteredPossibleItems = selectedGroup.PossibleItems.Where(it => it.DropLevel == 0 || ((it.DropLevel <= monsterLevel) && (it.DropLevel > monsterLevel - 12))).ToArray();
List<ItemDefinition> filteredPossibleItems;

if (selectedGroup.ItemType == SpecialItemType.Jewel)
{
filteredPossibleItems = [.. selectedGroup.PossibleItems.Where(it => it.DropLevel <= monsterLevel)];

if (monsterLevel > 66)
{
// Jewel of Chaos doesn't drop after a certain monster level
filteredPossibleItems.RemoveAll(it => it.Group == 12 && it.Number == 15);
Comment on lines +444 to +447

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for the 'Jewel of Chaos' not dropping after monster level 66 is hardcoded directly into the drop generation. Consider externalizing this rule into a configurable setting or a data-driven approach, especially if similar exceptions might arise for other items in the future.

}
}
else
{
filteredPossibleItems = [.. selectedGroup.PossibleItems.Where(it => it.DropLevel == 0 || (it.DropLevel <= monsterLevel && it.DropLevel > monsterLevel - DropLevelMaxGap))];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After adding the DropLevelMaxGap constant, the previous thread disappeared: #697 (comment)

}

return this.GenerateItemDrop(selectedGroup, filteredPossibleItems);
}
}
Expand Down Expand Up @@ -490,7 +508,7 @@ private void AddRandomExcOptions(Item item)
return this._droppableItemsPerMonsterLevel[monsterLevel]
??= (from it in this._droppableItems
where (it.DropLevel <= monsterLevel)
&& (it.DropLevel > monsterLevel - 12)
&& (it.DropLevel > monsterLevel - DropLevelMaxGap)
&& (!socketItems || it.MaximumSockets > 0)
select it).ToList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ private void AddItemDropGroups()
var jewelsDropItemGroup = this.Context.CreateNew<DropItemGroup>();
jewelsDropItemGroup.SetGuid(4);
jewelsDropItemGroup.Chance = 0.001;
jewelsDropItemGroup.ItemType = SpecialItemType.RandomItem;
jewelsDropItemGroup.ItemType = SpecialItemType.Jewel;
jewelsDropItemGroup.Description = "The jewels drop item group (0.1 % drop chance)";
this.GameConfiguration.DropItemGroups.Add(jewelsDropItemGroup);
BaseMapInitializer.RegisterDefaultDropItemGroup(jewelsDropItemGroup);
Expand Down
11 changes: 11 additions & 0 deletions src/Persistence/Initialization/InitializerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,15 @@ protected IncreasableItemOption CreateItemOption(int number, AttributeDefinition

return itemOption;
}

/// <summary>
/// Register the jewel (or jewel-like item) in the drop item group for jewels.
/// </summary>
/// <param name="item">The jewel you want to register.</param>
protected void AddItemToJewelItemDrop(ItemDefinition item)
{
var id = GuidHelper.CreateGuid<DropItemGroup>(4);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The magic number 4 used in GuidHelper.CreateGuid<DropItemGroup>(4) to identify the jewel drop group should be replaced with a named constant for improved readability and maintainability.

var jewelsItemDrop = this.GameConfiguration.DropItemGroups.First(x => x.GetId() == id);
jewelsItemDrop.PossibleItems.Add(item);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// <copyright file="RemoveJewelDropLevelGapPlugIn075.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>

namespace MUnique.OpenMU.Persistence.Initialization.Updates;

using System.Runtime.InteropServices;
using MUnique.OpenMU.DataModel.Configuration;
using MUnique.OpenMU.PlugIns;

/// <summary>
/// This update removes the existing drop level gap condition for jewels and similar items that should always drop.
/// </summary>
[PlugIn]
[Display(Name = PlugInName, Description = PlugInDescription)]
[Guid("CD958BC1-F17A-4C60-B66D-BD29D49B6ADA")]
public class RemoveJewelDropLevelGapPlugIn075 : RemoveJewelDropLevelGapPlugInBase
{
/// <inheritdoc />
public override string DataInitializationKey => Version075.DataInitialization.Id;

/// <inheritdoc />
public override UpdateVersion Version => UpdateVersion.RemoveJewelDropLevelGap075;

/// <inheritdoc />
protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration)
{
await base.ApplyAsync(context, gameConfiguration).ConfigureAwait(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// <copyright file="RemoveJewelDropLevelGapPlugIn095d.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>

namespace MUnique.OpenMU.Persistence.Initialization.Updates;

using System.Runtime.InteropServices;
using MUnique.OpenMU.DataModel.Configuration;
using MUnique.OpenMU.PlugIns;

/// <summary>
/// This update removes the existing drop level gap condition for jewels and similar items that should always drop.
/// </summary>
[PlugIn]
[Display(Name = PlugInName, Description = PlugInDescription)]
[Guid("6614E91E-5749-478A-96A4-3240E7C1280E")]
public class RemoveJewelDropLevelGapPlugIn095D : RemoveJewelDropLevelGapPlugInBase
{
/// <inheritdoc />
public override string DataInitializationKey => Version095d.DataInitialization.Id;

/// <inheritdoc />
public override UpdateVersion Version => UpdateVersion.RemoveJewelDropLevelGap095d;

/// <inheritdoc />
protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration)
{
await base.ApplyAsync(context, gameConfiguration).ConfigureAwait(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// <copyright file="RemoveJewelDropLevelGapPlugInBase.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>

namespace MUnique.OpenMU.Persistence.Initialization.Updates;

using MUnique.OpenMU.DataModel.Configuration;
using MUnique.OpenMU.Persistence.Initialization.Items;

/// <summary>
/// This update removes the existing drop level gap condition for jewels and similar items that should always drop.
/// </summary>
public abstract class RemoveJewelDropLevelGapPlugInBase : UpdatePlugInBase
{
/// <summary>
/// The plug in name.
/// </summary>
internal const string PlugInName = "Remove Jewel Drop Level Gap";

/// <summary>
/// The plug in description.
/// </summary>
internal const string PlugInDescription = "This update removes the existing drop level gap condition for jewels and similar items that should always drop.";

/// <inheritdoc />
public override string Name => PlugInName;

/// <inheritdoc />
public override string Description => PlugInDescription;

/// <inheritdoc />
public override bool IsMandatory => true;

/// <inheritdoc />
public override DateTime CreatedAt => new(2026, 3, 5, 16, 0, 0, DateTimeKind.Utc);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The CreatedAt property is set to a future date (2026, 3, 5). This property should reflect the actual date when this plugin was created or introduced into the codebase, not a future date.


/// <inheritdoc />
protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration)
{
var jewelsDropGroupId = new Guid("00000200-0004-0000-0000-000000000000");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The GUID string "00000200-0004-0000-0000-000000000000" for jewelsDropGroupId is a magic string. It would be beneficial to define this as a named constant to enhance readability and reduce the risk of errors if the GUID needs to be referenced elsewhere.

var jewelsDropGroup = gameConfiguration.DropItemGroups.First(x => x.GetId() == jewelsDropGroupId);
jewelsDropGroup.ItemType = SpecialItemType.Jewel;

Dictionary<ItemGroups, List<int>> itemGroupToItemNumbers = new()
{
{ ItemGroups.Misc1, [0, 1, 2] }, // angel, imp, uniria
{ ItemGroups.Misc2, [9, 10] }, // alcohol, town portal scroll
Comment on lines +46 to +47

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The item numbers 0, 1, 2 for ItemGroups.Misc1 and 9, 10 for ItemGroups.Misc2 are magic numbers. Consider defining these as named constants or enum members to make the code more self-documenting and easier to understand, especially for items like 'angel', 'imp', 'uniria', 'alcohol', and 'town portal scroll'.

};
foreach (var entry in itemGroupToItemNumbers)
{
var items = gameConfiguration.Items.Where(i => i.Group == (int)entry.Key && entry.Value.Contains(i.Number));
foreach (var item in items)
{
jewelsDropGroup.PossibleItems.Add(item);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// <copyright file="RemoveJewelDropLevelGapPlugInSeason6.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>

namespace MUnique.OpenMU.Persistence.Initialization.Updates;

using System.Runtime.InteropServices;
using MUnique.OpenMU.DataModel.Configuration;
using MUnique.OpenMU.PlugIns;

/// <summary>
/// This update removes the existing drop level gap condition for jewels and similar items that should always drop.
/// </summary>
[PlugIn]
[Display(Name = PlugInName, Description = PlugInDescription)]
[Guid("AB1C9F8B-5E3B-4F2A-BDCD-9C0F1E5A6B7C")]
public class RemoveJewelDropLevelGapPlugInSeason6 : RemoveJewelDropLevelGapPlugInBase
{
/// <inheritdoc />
public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id;

/// <inheritdoc />
public override UpdateVersion Version => UpdateVersion.RemoveJewelDropLevelGapSeason6;

/// <inheritdoc />
protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration)
{
await base.ApplyAsync(context, gameConfiguration).ConfigureAwait(false);

var jewelOfGuardianDropGroupId = new Guid("00000200-001f-0001-0000-000000000000");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The GUID string "00000200-001f-0001-0000-000000000000" for jewelOfGuardianDropGroupId is a magic string. It should be defined as a named constant for better readability and maintainability.

if (gameConfiguration.DropItemGroups.FirstOrDefault(x => x.GetId() == jewelOfGuardianDropGroupId) is { } jewelOfGuardianDropGroup)
{
jewelOfGuardianDropGroup.ItemType = SpecialItemType.Jewel;
}
}
}
15 changes: 15 additions & 0 deletions src/Persistence/Initialization/Updates/UpdateVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -344,4 +344,19 @@ public enum UpdateVersion
/// The version of the <see cref="AddProjectileCountToTripleShotUpdatePlugIn"/>.
/// </summary>
AddProjectileCountToTripleShot = 67,

/// <summary>
/// The version of the <see cref="RemoveJewelDropLevelGapPlugIn075"/>.
/// </summary>
RemoveJewelDropLevelGap075 = 68,

/// <summary>
/// The version of the <see cref="RemoveJewelDropLevelGapPlugIn095D"/>.
/// </summary>
RemoveJewelDropLevelGap095d = 69,

/// <summary>
/// The version of the <see cref="RemoveJewelDropLevelGapPlugInSeason6"/>.
/// </summary>
RemoveJewelDropLevelGapSeason6 = 70,
}
11 changes: 0 additions & 11 deletions src/Persistence/Initialization/Version075/Items/Jewels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,6 @@ public override void Initialize()
this.GameConfiguration.Items.Add(this.CreateJewelOfChaos());
}

/// <summary>
/// Register the jewel in the drop item group for jewels.
/// </summary>
/// <param name="item">The jewel you want to register.</param>
protected void AddItemToJewelItemDrop(ItemDefinition item)
{
var id = GuidHelper.CreateGuid<DropItemGroup>(4);
var jewelsItemDrop = this.GameConfiguration.DropItemGroups.First(x => x.GetId() == id);
jewelsItemDrop.PossibleItems.Add(item);
}

/// <summary>
/// Creates an <see cref="ItemDefinition"/> for the 'Jewel of Bless'.
/// </summary>
Expand Down
9 changes: 6 additions & 3 deletions src/Persistence/Initialization/Version075/Items/Pets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ public Pets(IContext context, GameConfiguration gameConfiguration)
/// <inheritdoc />
public override void Initialize()
{
this.CreatePet(0, "Guardian Angel", 23, (Stats.DamageReceiveDecrement, 0.8f, AggregateType.Multiplicate), (Stats.MaximumHealth, 50f, AggregateType.AddRaw));
this.CreatePet(1, "Imp", 28, (Stats.AttackDamageIncrease, 1.3f, AggregateType.Multiplicate));
this.CreatePet(2, "Horn of Uniria", 25);
var angel = this.CreatePet(0, "Guardian Angel", 23, (Stats.DamageReceiveDecrement, 0.8f, AggregateType.Multiplicate), (Stats.MaximumHealth, 50f, AggregateType.AddRaw));
this.AddItemToJewelItemDrop(angel);
var imp = this.CreatePet(1, "Imp", 28, (Stats.AttackDamageIncrease, 1.3f, AggregateType.Multiplicate));
this.AddItemToJewelItemDrop(imp);
var uniria = this.CreatePet(2, "Horn of Uniria", 25);
this.AddItemToJewelItemDrop(uniria);
}

private ItemDefinition CreatePet(byte number, string name, int dropLevelAndLevelRequirement, params (AttributeDefinition, float, AggregateType)[] basePowerUps)
Expand Down
2 changes: 2 additions & 0 deletions src/Persistence/Initialization/Version075/Items/Potions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ private ItemDefinition CreateAlcohol()
alcohol.Height = 2;
alcohol.SetGuid(alcohol.Group, alcohol.Number);
alcohol.ConsumeEffect = this.GameConfiguration.MagicEffects.First(effect => effect.Number == (short)MagicEffectNumber.Alcohol);
this.AddItemToJewelItemDrop(alcohol);
return alcohol;
}

Expand Down Expand Up @@ -230,6 +231,7 @@ private ItemDefinition CreateTownPortalScroll()
definition.Width = 1;
definition.Height = 2;
definition.SetGuid(definition.Group, definition.Number);
this.AddItemToJewelItemDrop(definition);
return definition;
}
}
9 changes: 6 additions & 3 deletions src/Persistence/Initialization/Version095d/Items/Pets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ public Pets(IContext context, GameConfiguration gameConfiguration)
/// <inheritdoc />
public override void Initialize()
{
this.CreatePet(0, 0, "Guardian Angel", 23, true, (Stats.DamageReceiveDecrement, 0.8f, AggregateType.Multiplicate), (Stats.MaximumHealth, 50f, AggregateType.AddRaw));
this.CreatePet(1, 0, "Imp", 28, true, (Stats.AttackDamageIncrease, 1.3f, AggregateType.Multiplicate));
this.CreatePet(2, 0, "Horn of Uniria", 25, true);
var angel = this.CreatePet(0, 0, "Guardian Angel", 23, true, (Stats.DamageReceiveDecrement, 0.8f, AggregateType.Multiplicate), (Stats.MaximumHealth, 50f, AggregateType.AddRaw));
this.AddItemToJewelItemDrop(angel);
var imp = this.CreatePet(1, 0, "Imp", 28, true, (Stats.AttackDamageIncrease, 1.3f, AggregateType.Multiplicate));
this.AddItemToJewelItemDrop(imp);
var uniria = this.CreatePet(2, 0, "Horn of Uniria", 25, true);
this.AddItemToJewelItemDrop(uniria);

var dinorant = this.CreatePet(3, SkillNumber.FireBreath, "Horn of Dinorant", 110, false, (Stats.IsDinorantEquipped, 1, AggregateType.AddRaw), (Stats.DamageReceiveDecrement, 0.9f, AggregateType.Multiplicate), (Stats.AttackDamageIncrease, 1.15f, AggregateType.Multiplicate));
this.AddDinorantOptions(dinorant);
Expand Down
9 changes: 6 additions & 3 deletions src/Persistence/Initialization/VersionSeasonSix/Items/Pets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,15 @@ public Pets(IContext context, GameConfiguration gameConfiguration)
public override void Initialize()
{
#pragma warning disable SA1117 // Parameters should be on same line or separete lines
this.CreatePet(0, 0, 1, 1, "Guardian Angel", 23, true, true,
var angel = this.CreatePet(0, 0, 1, 1, "Guardian Angel", 23, true, true,
(Stats.DamageReceiveDecrement, 0.8f, AggregateType.Multiplicate),
(Stats.MaximumHealth, 50f, AggregateType.AddRaw));
this.CreatePet(1, 0, 1, 1, "Imp", 28, true, true,
this.AddItemToJewelItemDrop(angel);
var imp = this.CreatePet(1, 0, 1, 1, "Imp", 28, true, true,
(Stats.AttackDamageIncrease, 1.3f, AggregateType.Multiplicate));
this.CreatePet(2, 0, 1, 1, "Horn of Uniria", 25, true, true);
this.AddItemToJewelItemDrop(imp);
var uniria = this.CreatePet(2, 0, 1, 1, "Horn of Uniria", 25, true, true);
this.AddItemToJewelItemDrop(uniria);

var dinorant = this.CreatePet(3, SkillNumber.FireBreath, 1, 1, "Horn of Dinorant", 110, false, true,
(Stats.IsDinorantEquipped, 1, AggregateType.AddRaw),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ private ItemDefinition CreateAlcohol()
alcohol.Height = 2;
alcohol.SetGuid(alcohol.Group, alcohol.Number);
alcohol.ConsumeEffect = this.GameConfiguration.MagicEffects.First(effect => effect.Number == (short)MagicEffectNumber.Alcohol);
this.AddItemToJewelItemDrop(alcohol);
return alcohol;
}

Expand Down Expand Up @@ -375,6 +376,7 @@ private ItemDefinition CreateTownPortalScroll()
definition.Width = 1;
definition.Height = 2;
definition.SetGuid(definition.Group, definition.Number);
this.AddItemToJewelItemDrop(definition);
return definition;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ protected override void InitializeDropItemGroups()
var jewelsDropItemGroup = this.Context.CreateNew<DropItemGroup>();
jewelsDropItemGroup.SetGuid(this.MapNumber, 1);
jewelsDropItemGroup.Chance = 0.001;
jewelsDropItemGroup.ItemType = SpecialItemType.RandomItem;
jewelsDropItemGroup.ItemType = SpecialItemType.Jewel;
jewelsDropItemGroup.Description = "Jewel of Guardian";

var jewelOfGuardian = this.GameConfiguration.Items.First(y => y.Group == 14 && y.Number == 31);
Expand Down