// // 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.DataModel.Attributes; using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.GameLogic; using MUnique.OpenMU.GameLogic.Attributes; using MUnique.OpenMU.Persistence.Initialization.Skills; using MUnique.OpenMU.PlugIns; /// /// This update fixes character stats, magic effects, and options related to defense. /// [PlugIn] [Display(Name = PlugInName, Description = PlugInDescription)] [Guid("447FA95B-091B-4950-B1F3-F4EB6D20DE19")] public class FixDefenseCalcsPlugInSeason6 : FixDefenseCalcsPlugInBase { /// public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id; /// public override UpdateVersion Version => UpdateVersion.FixDefenseCalcsSeason6; /// protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) { // Update Anonymous Leather ancient set obsolete option prior to its removal var shieldBlockDamageDecrementId = new Guid("DAC6690B-5922-4446-BCE5-5E701BE62EC1"); var anonymousLeatherOptsId = new Guid("00000083-0029-0002-0100-000000000000"); var anonymousLeatherOpts = gameConfiguration.ItemOptions.FirstOrDefault(i => i.GetId() == anonymousLeatherOptsId); if (gameConfiguration.Attributes.FirstOrDefault(a => a.Id == shieldBlockDamageDecrementId) is { } shieldBlockDamageDecrement && anonymousLeatherOpts?.PossibleOptions.FirstOrDefault(opt => opt.PowerUpDefinition?.TargetAttribute == shieldBlockDamageDecrement) is { } shieldBlockDamageDecrementOpt) { shieldBlockDamageDecrementOpt.PowerUpDefinition!.TargetAttribute = Stats.DefenseIncreaseWithEquippedShield.GetPersistent(gameConfiguration); } await base.ApplyAsync(context, gameConfiguration).ConfigureAwait(false); var defenseBase = Stats.DefenseBase.GetPersistent(gameConfiguration); var defenseFinal = Stats.DefenseFinal.GetPersistent(gameConfiguration); var defensePvm = Stats.DefensePvm.GetPersistent(gameConfiguration); var defensePvp = Stats.DefensePvp.GetPersistent(gameConfiguration); var shieldItemDefenseIncrease = Stats.ShieldItemDefenseIncrease.GetPersistent(gameConfiguration); var bonusDefenseRateWithShield = Stats.BonusDefenseRateWithShield.GetPersistent(gameConfiguration); var excellentDamageChance = Stats.ExcellentDamageChance.GetPersistent(gameConfiguration); var excellentDamageBonus = Stats.ExcellentDamageBonus.GetPersistent(gameConfiguration); // Update attribute combinations gameConfiguration.CharacterClasses.ForEach(charClass => { if (charClass.AttributeCombinations.FirstOrDefault(attrCombo => attrCombo.TargetAttribute == Stats.MaximumShield && attrCombo.InputAttribute == Stats.DefenseBase) is { } defenseBaseToMaximumShield) { defenseBaseToMaximumShield.InputOperand = 1; defenseBaseToMaximumShield.InputAttribute = defenseFinal; } }); // Update magic effects var defenseReductionEffect = gameConfiguration.MagicEffects.FirstOrDefault(m => m.Number == (short)MagicEffectNumber.DefenseReduction); if (defenseReductionEffect is not null) { defenseReductionEffect.PowerUpDefinitions.Clear(); var reducePvmDefenseEffect = context.CreateNew(); defenseReductionEffect.PowerUpDefinitions.Add(reducePvmDefenseEffect); reducePvmDefenseEffect.TargetAttribute = defensePvm; reducePvmDefenseEffect.Boost = context.CreateNew(); reducePvmDefenseEffect.Boost.ConstantValue.Value = 0.9f; reducePvmDefenseEffect.Boost.ConstantValue.AggregateType = AggregateType.Multiplicate; var reducePvpDefenseEffect = context.CreateNew(); defenseReductionEffect.PowerUpDefinitions.Add(reducePvpDefenseEffect); reducePvpDefenseEffect.TargetAttribute = defensePvp; reducePvpDefenseEffect.Boost = context.CreateNew(); reducePvpDefenseEffect.Boost.ConstantValue.Value = 0.9f; reducePvpDefenseEffect.Boost.ConstantValue.AggregateType = AggregateType.Multiplicate; } var jackOlanternCry = gameConfiguration.Items.FirstOrDefault(m => m.Group == 14 && m.Number == 48); if (jackOlanternCry?.ConsumeEffect is { } effect) { foreach (var powerUp in effect.PowerUpDefinitions) { powerUp.TargetAttribute = defenseFinal; powerUp.Boost!.ConstantValue.Value = 100 / 2; powerUp.Boost.ConstantValue.AggregateType = AggregateType.AddFinal; } } // Update options var ancientSetsOpts = gameConfiguration.ItemOptions.Where(io => io.Name.ValueInNeutralLanguageAsSpan.EndsWith("(Ancient Set)")); foreach (var ancientSetOpts in ancientSetsOpts) { if (ancientSetOpts.PossibleOptions.FirstOrDefault(o => o.PowerUpDefinition?.TargetAttribute == defenseBase) is { } defenseBaseAncOpt) { defenseBaseAncOpt.PowerUpDefinition!.Boost!.ConstantValue.AggregateType = AggregateType.AddFinal; } } var anubisLegendaryOptsId = new Guid("00000083-0029-0013-0100-000000000000"); var anubisLegendaryOpts = gameConfiguration.ItemOptions.FirstOrDefault(i => i.GetId() == anubisLegendaryOptsId); if (anubisLegendaryOpts?.PossibleOptions.FirstOrDefault(opt => opt.PowerUpDefinition?.TargetAttribute == excellentDamageChance && opt.PowerUpDefinition.Boost?.ConstantValue.Value == 20.0f) is { } excellentDamageChanceOpt) { excellentDamageChanceOpt.PowerUpDefinition!.TargetAttribute = excellentDamageBonus; } var pantsGuardianOptions = gameConfiguration.ItemOptions.FirstOrDefault(o => o.Name == "Guardian Option (Pants)"); if (pantsGuardianOptions is not null && pantsGuardianOptions.PossibleOptions.FirstOrDefault(o => o.PowerUpDefinition?.TargetAttribute == defenseBase) is { } defenseOpt) { defenseOpt.PowerUpDefinition!.TargetAttribute = defensePvp; defenseOpt.PowerUpDefinition.Boost!.ConstantValue.Value = 200 / 2; } var harmonyDefOptions = gameConfiguration.ItemOptions.FirstOrDefault(o => o.Name == "Harmony Defense Options"); if (harmonyDefOptions is not null && harmonyDefOptions.PossibleOptions.FirstOrDefault(o => o.Number == 1) is { } defenseBaseOpt) { foreach (var level in defenseBaseOpt.LevelDependentOptions) { level.PowerUpDefinition!.Boost!.ConstantValue.AggregateType = AggregateType.AddFinal; } } var socketOptionsWaterId = new Guid("00000083-0033-0000-0000-000000000000"); var waterSocketOptions = gameConfiguration.ItemOptions.FirstOrDefault(o => o.GetId() == socketOptionsWaterId); if (waterSocketOptions is not null) { if (waterSocketOptions.PossibleOptions.FirstOrDefault(o => o.Number == 1) is { } defenseBaseSockOpt) { foreach (var level in defenseBaseSockOpt.LevelDependentOptions) { level.PowerUpDefinition!.TargetAttribute = defenseFinal; } } if (waterSocketOptions.PossibleOptions.FirstOrDefault(o => o.Number == 2) is { } shieldItemdefenseSockOpt) { foreach (var level in shieldItemdefenseSockOpt.LevelDependentOptions) { level.PowerUpDefinition!.TargetAttribute = shieldItemDefenseIncrease; } } } var socketBonusOptionsArmorsId = new Guid("00000083-0031-0003-0000-000000000000"); var socketArmorsBonusOptions = gameConfiguration.ItemOptions.FirstOrDefault(o => o.GetId() == socketBonusOptionsArmorsId); if (socketArmorsBonusOptions is not null && socketArmorsBonusOptions.PossibleOptions.FirstOrDefault(o => o.Number == 4) is { } defenseBaseSockBonusOpt) { defenseBaseSockBonusOpt.PowerUpDefinition!.TargetAttribute = defenseFinal; } // Update master skills if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.DefenseIncrease)?.MasterDefinition is { } defenseIncrease) { defenseIncrease.Aggregation = AggregateType.AddFinal; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.IncreasesDefense)?.MasterDefinition is { } increasesDefense) { increasesDefense.Aggregation = AggregateType.AddFinal; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.DefenseSuccessRateInc)?.MasterDefinition is { } defenseSuccessRateInc) { string formula120 = "(1 + (((((((level - 30) ^ 3) + 25000) / 499) / 50) * 100) / 12))"; defenseSuccessRateInc.ValueFormula = $"1 + {formula120} / 100"; defenseSuccessRateInc.Aggregation = AggregateType.Multiplicate; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.ShieldMasteryGrandMaster)?.MasterDefinition is { } shieldMasteryGrandMaster) { shieldMasteryGrandMaster.TargetAttribute = bonusDefenseRateWithShield; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.ShieldMasteryHighElf)?.MasterDefinition is { } shieldMasteryHighElf) { shieldMasteryHighElf.TargetAttribute = bonusDefenseRateWithShield; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.ShieldMastery)?.MasterDefinition is { } shieldMastery) { shieldMastery.TargetAttribute = bonusDefenseRateWithShield; } } }