diff --git a/src/AttributeSystem/AggregateType.cs b/src/AttributeSystem/AggregateType.cs
index 6f5a6fa8c..660211fff 100644
--- a/src/AttributeSystem/AggregateType.cs
+++ b/src/AttributeSystem/AggregateType.cs
@@ -23,4 +23,9 @@ public enum AggregateType
/// Adds the value to the final value.
///
AddFinal,
+
+ ///
+ /// Adds only the highest available value to the raw base value (jewelry element resistance).
+ ///
+ Maximum,
}
\ No newline at end of file
diff --git a/src/AttributeSystem/ComposableAttribute.cs b/src/AttributeSystem/ComposableAttribute.cs
index 4423689e1..b8907c5c0 100644
--- a/src/AttributeSystem/ComposableAttribute.cs
+++ b/src/AttributeSystem/ComposableAttribute.cs
@@ -61,6 +61,8 @@ private float GetAndCacheValue()
var rawValues = this.Elements.Where(e => e.AggregateType == AggregateType.AddRaw).Sum(e => e.Value);
var multiValues = this.Elements.Where(e => e.AggregateType == AggregateType.Multiplicate).Select(e => e.Value).Concat(Enumerable.Repeat(1.0F, 1)).Aggregate((a, b) => a * b);
var finalValues = this.Elements.Where(e => e.AggregateType == AggregateType.AddFinal).Sum(e => e.Value);
+ var maxValues = this.Elements.Where(e => e.AggregateType == AggregateType.Maximum).MaxBy(e => e.Value)?.Value ?? 0;
+ rawValues += maxValues;
if (multiValues == 0 && this.Elements.All(e => e.AggregateType != AggregateType.Multiplicate))
{
@@ -75,7 +77,7 @@ private float GetAndCacheValue()
// nothing to do
}
- this._cachedValue = (rawValues * multiValues + finalValues);
+ this._cachedValue = (rawValues * multiValues) + finalValues;
return this._cachedValue.Value;
}
diff --git a/src/GameLogic/InventoryStorage.cs b/src/GameLogic/InventoryStorage.cs
index a0805a57b..12fb47c2d 100644
--- a/src/GameLogic/InventoryStorage.cs
+++ b/src/GameLogic/InventoryStorage.cs
@@ -8,7 +8,7 @@ namespace MUnique.OpenMU.GameLogic;
using MUnique.OpenMU.GameLogic.Attributes;
using MUnique.OpenMU.GameLogic.Views.World;
using MUnique.OpenMU.PlugIns;
-using static OpenMU.DataModel.InventoryConstants;
+using static MUnique.OpenMU.DataModel.InventoryConstants;
///
/// The storage of an inventory of a player, which also contains equippable slots. This class also manages the powerups which get created by equipped items.
@@ -166,8 +166,9 @@ await this._player.ForEachWorldObserverAsync(
this._player.Attributes.ItemPowerUps.Add(item, factory.GetPowerUps(item, this._player.Attributes).ToList());
// reset player equipped ammunition amount
- if (this.EquippedAmmunitionItem is { } ammoItem) {
- this._player.Attributes[Stats.AmmunitionAmount] = (float) ammoItem.Durability;
+ if (this.EquippedAmmunitionItem is { } ammoItem)
+ {
+ this._player.Attributes[Stats.AmmunitionAmount] = (float)ammoItem.Durability;
}
}
}
diff --git a/src/GameLogic/ItemExtensions.cs b/src/GameLogic/ItemExtensions.cs
index a8cbb23bd..6a6f63441 100644
--- a/src/GameLogic/ItemExtensions.cs
+++ b/src/GameLogic/ItemExtensions.cs
@@ -124,13 +124,25 @@ public static bool IsShield(this Item item)
return item.Definition?.Group == ShieldItemGroup;
}
+ ///
+ /// Determines whether this item is a jewelry (pendant or ring) item.
+ ///
+ /// The item.
+ ///
+ /// true if the specified item is jewelry; otherwise, false.
+ ///
+ public static bool IsJewelry(this Item item)
+ {
+ return item.ItemSlot >= InventoryConstants.PendantSlot && item.ItemSlot <= InventoryConstants.Ring2Slot;
+ }
+
///
/// Determines whether this instance is a is weapon which deals physical damage.
///
/// The item.
/// The minimum physical damage of the weapon.
///
- /// true if this instance is a is weapon which deals physical damage; otherwise, false.
+ /// true if this instance is a weapon which deals physical damage; otherwise, false.
///
public static bool IsPhysicalWeapon(this Item item, [NotNullWhen(true)] out float? minimumDmg)
{
@@ -144,7 +156,7 @@ public static bool IsPhysicalWeapon(this Item item, [NotNullWhen(true)] out floa
/// The item.
/// The staff rise percentage of the weapon.
///
- /// true if this instance is a is weapon which deals wizardry damage; otherwise, false.
+ /// true if this instance is a weapon which deals wizardry damage; otherwise, false.
///
public static bool IsWizardryWeapon(this Item item, [NotNullWhen(true)] out float? staffRise)
{
diff --git a/src/GameLogic/ItemPowerUpFactory.cs b/src/GameLogic/ItemPowerUpFactory.cs
index 63af2ff0a..7159e8f73 100644
--- a/src/GameLogic/ItemPowerUpFactory.cs
+++ b/src/GameLogic/ItemPowerUpFactory.cs
@@ -184,12 +184,20 @@ private IEnumerable GetBasePowerUpWrappers(Item item, AttributeS
attribute.ThrowNotInitializedProperty(attribute.BaseValueElement is null, nameof(attribute.BaseValueElement));
attribute.ThrowNotInitializedProperty(attribute.TargetAttribute is null, nameof(attribute.TargetAttribute));
- yield return new PowerUpWrapper(attribute.BaseValueElement, attribute.TargetAttribute, attributeHolder);
+ var levelBonusElmt = (attribute.BonusPerLevelTable?.BonusPerLevel ?? Enumerable.Empty())
+ .FirstOrDefault(bonus => bonus.Level == item.Level)?
+ .GetAdditionalValueElement(attribute.AggregateType);
- var levelBonus = (attribute.BonusPerLevelTable?.BonusPerLevel ?? Enumerable.Empty()).FirstOrDefault(bonus => bonus.Level == item.Level);
- if (levelBonus is not null)
+ if (levelBonusElmt is null)
{
- yield return new PowerUpWrapper(levelBonus.GetAdditionalValueElement(attribute.AggregateType), attribute.TargetAttribute, attributeHolder);
+ yield return new PowerUpWrapper(attribute.BaseValueElement, attribute.TargetAttribute, attributeHolder);
+ }
+ else
+ {
+ yield return new PowerUpWrapper(
+ new CombinedElement(attribute.BaseValueElement, levelBonusElmt),
+ attribute.TargetAttribute,
+ attributeHolder);
}
}
@@ -253,7 +261,7 @@ private IEnumerable CreateExcellentAndAncientBasePowerUpWrappers
var baseDropLevel = item.Definition!.DropLevel;
var ancientDropLevel = item.Definition!.CalculateDropLevel(true, false, 0);
- if (InventoryConstants.IsDefenseItemSlot(item.ItemSlot))
+ if (InventoryConstants.IsDefenseItemSlot(item.ItemSlot) && !item.IsJewelry())
{
var baseDefense = (int)(item.Definition?.BasePowerUpAttributes.FirstOrDefault(a => a.TargetAttribute == Stats.DefenseBase)?.BaseValue ?? 0);
var additionalDefense = (baseDefense * 12 / baseDropLevel) + (baseDropLevel / 5) + 4;
diff --git a/src/Persistence/Initialization/Items/OptionExtensions.cs b/src/Persistence/Initialization/Items/OptionExtensions.cs
index 7ff273a35..651cd89ce 100644
--- a/src/Persistence/Initialization/Items/OptionExtensions.cs
+++ b/src/Persistence/Initialization/Items/OptionExtensions.cs
@@ -80,6 +80,6 @@ public static ItemOptionDefinition ExcellentPhysicalAttackOptions(this GameConfi
/// The excellent wizardry attack options.
public static ItemOptionDefinition ExcellentWizardryAttackOptions(this GameConfiguration gameConfiguration)
{
- return gameConfiguration.ItemOptions.First(o => o.Name == ExcellentOptions.PhysicalAttackOptionsName);
+ return gameConfiguration.ItemOptions.First(o => o.Name == ExcellentOptions.WizardryAttackOptionsName);
}
}
\ No newline at end of file
diff --git a/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugIn075.cs b/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugIn075.cs
new file mode 100644
index 000000000..6992be509
--- /dev/null
+++ b/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugIn075.cs
@@ -0,0 +1,24 @@
+//
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace MUnique.OpenMU.Persistence.Initialization.Updates;
+
+using System.Runtime.InteropServices;
+using MUnique.OpenMU.AttributeSystem;
+using MUnique.OpenMU.PlugIns;
+
+///
+/// This update fixes the wings damage absorption and increase bonus level tables values for a (sum) calculation, instead of a compound calculation
+/// for version 075.
+///
+[PlugIn(PlugInName, PlugInDescription)]
+[Guid("3821267A-9C37-40E5-B023-BAB1A8E4DAB7")]
+public class FixWingsDmgRatesUpdatePlugIn075 : FixWingsDmgRatesUpdatePlugInBase
+{
+ ///
+ public override string DataInitializationKey => Version075.DataInitialization.Id;
+
+ ///
+ public override UpdateVersion Version => UpdateVersion.FixWingsDmgRatesPlugIn075;
+}
\ No newline at end of file
diff --git a/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugIn095d.cs b/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugIn095d.cs
new file mode 100644
index 000000000..9c3192a95
--- /dev/null
+++ b/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugIn095d.cs
@@ -0,0 +1,24 @@
+//
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace MUnique.OpenMU.Persistence.Initialization.Updates;
+
+using System.Runtime.InteropServices;
+using MUnique.OpenMU.AttributeSystem;
+using MUnique.OpenMU.PlugIns;
+
+///
+/// This update fixes the wings damage absorption and increase bonus level tables values for a (sum) calculation, instead of a compound calculation
+/// for version 095d.
+///
+[PlugIn(PlugInName, PlugInDescription)]
+[Guid("F45FA4D0-B19B-48E2-9592-A37F3B36348A")]
+public class FixWingsDmgRatesUpdatePlugIn095D : FixWingsDmgRatesUpdatePlugInBase
+{
+ ///
+ public override string DataInitializationKey => Version095d.DataInitialization.Id;
+
+ ///
+ public override UpdateVersion Version => UpdateVersion.FixWingsDmgRatesPlugIn095d;
+}
\ No newline at end of file
diff --git a/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugInBase.cs b/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugInBase.cs
new file mode 100644
index 000000000..8a8c0d58b
--- /dev/null
+++ b/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugInBase.cs
@@ -0,0 +1,59 @@
+//
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace MUnique.OpenMU.Persistence.Initialization.Updates;
+
+using MUnique.OpenMU.AttributeSystem;
+using MUnique.OpenMU.DataModel.Configuration;
+
+///
+/// This update fixes the wings damage absorption and increase bonus level tables values for a (sum) calculation, instead of a compound calculation.
+///
+public abstract class FixWingsDmgRatesUpdatePlugInBase : UpdatePlugInBase
+{
+ ///
+ /// The plug in name.
+ ///
+ internal const string PlugInName = "Fix Wings Damage Rates";
+
+ ///
+ /// The plug in description.
+ ///
+ internal const string PlugInDescription = "This update fixes the wings damage absorption and increase bonus level tables values.";
+
+ ///
+ public override string Name => PlugInName;
+
+ ///
+ public override string Description => PlugInDescription;
+
+ ///
+ public override bool IsMandatory => true;
+
+ ///
+ public override DateTime CreatedAt => new(2023, 10, 8, 16, 0, 0, DateTimeKind.Utc);
+
+ ///
+ protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration)
+ {
+ string dmgAbsorbCommonName = "Wing absorb";
+ string dmgIncreaseCommonName = "Damage Increase (1st and 3rd Wings)";
+ string dmgIncrease2ndWingsName = "Damage Increase (2nd Wings)";
+
+ string[] wingDmgTableNames = [dmgAbsorbCommonName, dmgIncrease2ndWingsName, dmgIncreaseCommonName];
+
+ foreach (var tableName in wingDmgTableNames)
+ {
+ var bonusEntries = gameConfiguration.ItemLevelBonusTables.FirstOrDefault(ilbt => ilbt.Name == tableName)?.BonusPerLevel;
+
+ if (bonusEntries is not null)
+ {
+ foreach (var bonusEntry in bonusEntries)
+ {
+ bonusEntry.AdditionalValue -= 1.0f;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugInSeason6.cs b/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugInSeason6.cs
new file mode 100644
index 000000000..8adabb9ca
--- /dev/null
+++ b/src/Persistence/Initialization/Updates/FixWingsDmgRatesUpdatePlugInSeason6.cs
@@ -0,0 +1,24 @@
+//
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace MUnique.OpenMU.Persistence.Initialization.Updates;
+
+using System.Runtime.InteropServices;
+using MUnique.OpenMU.AttributeSystem;
+using MUnique.OpenMU.PlugIns;
+
+///
+/// This update fixes the wings damage absorption and increase bonus level tables values for a (sum) calculation, instead of a compound calculation
+/// for season 6.
+///
+[PlugIn(PlugInName, PlugInDescription)]
+[Guid("03F49890-CB0E-40B7-A590-174BBA1962F4")]
+public class FixWingsDmgRatesUpdatePlugInSeason6 : FixWingsDmgRatesUpdatePlugInBase
+{
+ ///
+ public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id;
+
+ ///
+ public override UpdateVersion Version => UpdateVersion.FixWingsDmgRatesPlugInSeason6;
+}
\ No newline at end of file
diff --git a/src/Persistence/Initialization/Updates/UpdateVersion.cs b/src/Persistence/Initialization/Updates/UpdateVersion.cs
index b66aae1d0..923421ea1 100644
--- a/src/Persistence/Initialization/Updates/UpdateVersion.cs
+++ b/src/Persistence/Initialization/Updates/UpdateVersion.cs
@@ -164,4 +164,19 @@ public enum UpdateVersion
/// The version of the .
///
FixMaxManaAndAbilityJewelryOptionsSeason6 = 31,
+
+ ///
+ /// The version of the .
+ ///
+ FixWingsDmgRatesPlugIn075 = 32,
+
+ ///
+ /// The version of the .
+ ///
+ FixWingsDmgRatesPlugIn095d = 33,
+
+ ///
+ /// The version of the .
+ ///
+ FixWingsDmgRatesPlugInSeason6 = 34,
}
\ No newline at end of file
diff --git a/src/Persistence/Initialization/Version075/Items/Jewelery.cs b/src/Persistence/Initialization/Version075/Items/Jewelery.cs
index 407d6db53..60b584ea0 100644
--- a/src/Persistence/Initialization/Version075/Items/Jewelery.cs
+++ b/src/Persistence/Initialization/Version075/Items/Jewelery.cs
@@ -5,7 +5,6 @@
namespace MUnique.OpenMU.Persistence.Initialization.Version075.Items;
using MUnique.OpenMU.AttributeSystem;
-using MUnique.OpenMU.DataModel.Attributes;
using MUnique.OpenMU.DataModel.Configuration;
using MUnique.OpenMU.DataModel.Configuration.Items;
using MUnique.OpenMU.GameLogic.Attributes;
@@ -29,6 +28,9 @@ public Jewelery(IContext context, GameConfiguration gameConfiguration)
{
}
+ ///
+ protected override int MaximumOptionLevel => 3;
+
///
public sealed override void Initialize()
{
@@ -162,8 +164,9 @@ protected ItemDefinition CreateJewelery(byte number, int slot, bool dropsFromMon
if (resistanceAttribute != null)
{
- var powerUp = this.CreateItemBasePowerUpDefinition(resistanceAttribute, 0.1f, AggregateType.AddRaw);
+ var powerUp = this.CreateItemBasePowerUpDefinition(resistanceAttribute, 0.1f, AggregateType.Maximum);
powerUp.BonusPerLevelTable = this._resistancesBonusTable;
+ item.BasePowerUpAttributes.Add(powerUp);
}
foreach (var characterClass in this.GameConfiguration.CharacterClasses)
diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Wings.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Wings.cs
index 18e0abbe4..53415b041 100644
--- a/src/Persistence/Initialization/VersionSeasonSix/Items/Wings.cs
+++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Wings.cs
@@ -166,7 +166,7 @@ private ItemDefinition CreateWing(byte number, byte width, byte height, string n
if (damageIncreaseInitial > 0)
{
- var powerUp = this.CreateItemBasePowerUpDefinition(Stats.AttackDamageIncrease, 1f + damageIncreaseInitial / 100f, AggregateType.Multiplicate);
+ var powerUp = this.CreateItemBasePowerUpDefinition(Stats.AttackDamageIncrease, 1f + (damageIncreaseInitial / 100f), AggregateType.Multiplicate);
powerUp.BonusPerLevelTable = damageIncreasePerLevel;
wing.BasePowerUpAttributes.Add(powerUp);
}
diff --git a/src/Persistence/Initialization/WingsInitializerBase.cs b/src/Persistence/Initialization/WingsInitializerBase.cs
index 0749b3538..09de38071 100644
--- a/src/Persistence/Initialization/WingsInitializerBase.cs
+++ b/src/Persistence/Initialization/WingsInitializerBase.cs
@@ -81,10 +81,9 @@ protected ItemLevelBonusTable CreateAbsorbBonusPerLevel()
{
IEnumerable Generate()
{
- yield return 1f;
- for (int level = 1; level <= this.MaximumItemLevel; level++)
+ for (int level = 0; level <= this.MaximumItemLevel; level++)
{
- yield return 1f - (0.02f * level);
+ yield return -0.02f * level;
}
}
@@ -95,10 +94,9 @@ protected ItemLevelBonusTable CreateDamageIncreaseBonusPerLevelFirstAndThirdWing
{
IEnumerable Generate()
{
- yield return 1f;
- for (int level = 1; level <= this.MaximumItemLevel; level++)
+ for (int level = 0; level <= this.MaximumItemLevel; level++)
{
- yield return 1f + (0.02f * level);
+ yield return 0.02f * level;
}
}
@@ -109,10 +107,9 @@ protected ItemLevelBonusTable CreateDamageIncreaseBonusPerLevelSecondWings()
{
IEnumerable Generate()
{
- yield return 1;
- for (int level = 1; level <= this.MaximumItemLevel; level++)
+ for (int level = 0; level <= this.MaximumItemLevel; level++)
{
- yield return 1 + (0.01f * level);
+ yield return 0.01f * level;
}
}