// // 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.DataModel.Configuration.Items; using MUnique.OpenMU.GameLogic.Attributes; using MUnique.OpenMU.Persistence.Initialization.Items; using MUnique.OpenMU.Persistence.Initialization.Skills; using MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix; using MUnique.OpenMU.PlugIns; /// /// This update completes the elf master tree and fixes some of its skill values. It also adds the missing extra projectile (4th) on some higher level (cross)bows. /// [PlugIn] [Display(Name = PlugInName, Description = PlugInDescription)] [Guid("D1E2F3A4-B5C6-7D8E-9F0A-1B2C3D4E5F6A")] public class FinishElfMasterTreePlugIn : UpdatePlugInBase { /// /// The plug in name. /// internal const string PlugInName = "Finish Elf Master Tree PlugIn"; /// /// The plug in description. /// internal const string PlugInDescription = "This update completes the elf master tree and fixes some of its skill values. It also adds the missing extra projectile (4th) on some higher level (cross)bows."; /// public override UpdateVersion Version => UpdateVersion.FinishElfMasterTree; /// public override string DataInitializationKey => DataInitialization.Id; /// public override string Name => PlugInName; /// public override string Description => PlugInDescription; /// public override bool IsMandatory => true; /// public override DateTime CreatedAt => new(2026, 7, 22, 16, 0, 0, DateTimeKind.Utc); /// protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) { // Create new Stats var extraProjectiles = context.CreateNew(Stats.ExtraProjectiles.Id, Stats.ExtraProjectiles.Designation, Stats.ExtraProjectiles.Description); gameConfiguration.Attributes.Add(extraProjectiles); var greaterDefenseBonus = context.CreateNew(Stats.GreaterDefenseBonus.Id, Stats.GreaterDefenseBonus.Designation, Stats.GreaterDefenseBonus.Description); gameConfiguration.Attributes.Add(greaterDefenseBonus); var greaterDamageBonus = Stats.GreaterDamageBonus.GetPersistent(gameConfiguration); // Update Greater Damage effect var greaterDamageEffect = gameConfiguration.MagicEffects.First(e => e.Number == (short)MagicEffectNumber.GreaterDamage); var greaterDamagePowerUp2 = context.CreateNew(); greaterDamageEffect.PowerUpDefinitions.Add(greaterDamagePowerUp2); greaterDamagePowerUp2.TargetAttribute = greaterDamageBonus; greaterDamagePowerUp2.Boost = context.CreateNew(); greaterDamagePowerUp2.Boost.ConstantValue.Value = 1f; greaterDamagePowerUp2.Boost.ConstantValue.AggregateType = AggregateType.Multiplicate; // Update Greater Defense effect var greaterDefenseEffect = gameConfiguration.MagicEffects.First(e => e.Number == (short)MagicEffectNumber.GreaterDefense); if (greaterDefenseEffect.PowerUpDefinitions.FirstOrDefault() is PowerUpDefinition defensePowerUp) { defensePowerUp.TargetAttribute = greaterDefenseBonus; defensePowerUp.Boost?.ConstantValue.AggregateType = AggregateType.AddRaw; } var greaterDefensePowerUp2 = context.CreateNew(); greaterDefenseEffect.PowerUpDefinitions.Add(greaterDefensePowerUp2); greaterDefensePowerUp2.TargetAttribute = greaterDefenseBonus; greaterDefensePowerUp2.Boost = context.CreateNew(); greaterDefensePowerUp2.Boost.ConstantValue.Value = 1f; greaterDefensePowerUp2.Boost.ConstantValue.AggregateType = AggregateType.Multiplicate; // Update Infinity Arrow effect var infinityArrowEffect = gameConfiguration.MagicEffects.First(e => e.Number == (short)MagicEffectNumber.InfiniteArrow); if (infinityArrowEffect.PowerUpDefinitions.FirstOrDefault(pud => pud.TargetAttribute == Stats.AttackDamageIncrease) is PowerUpDefinition infinityArrowPowerUp) { infinityArrowPowerUp.Boost?.ConstantValue.Value = 1; infinityArrowPowerUp.Boost?.ConstantValue.AggregateType = AggregateType.Multiplicate; } // Update 4-arrow (cross)bows var affectedBows = new short[] { 18, 19, 22, 23, 24 }; var bows = gameConfiguration.Items.Where(i => i.Group == (byte)ItemGroups.Bows && affectedBows.Contains(i.Number)); foreach (var bow in bows) { bow.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(context, gameConfiguration, extraProjectiles, 1, AggregateType.AddRaw)); } // Update master skills if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.DefenseIncreaseStr)?.MasterDefinition is { } defenseIncreaseStr) { defenseIncreaseStr.ValueFormula = $"{SkillsInitializer.Formula502} / 100"; defenseIncreaseStr.TargetAttribute = greaterDefenseBonus; defenseIncreaseStr.Aggregation = AggregateType.Multiplicate; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.TripleShotMastery)?.MasterDefinition is { } tripleShotMastery) { tripleShotMastery.ReplacedSkill = gameConfiguration.Skills.First(s => s.Number == (short)SkillNumber.TripleShotStrengthener); tripleShotMastery.TargetAttribute = extraProjectiles; tripleShotMastery.Aggregation = AggregateType.AddRaw; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.SummonedMonsterStr2)?.MasterDefinition is { } summonedMonsterStr2) { summonedMonsterStr2.ValueFormula = SkillsInitializer.Formula6020Value; summonedMonsterStr2.Root = gameConfiguration.MasterSkillRoots.First(s => s.Name == "Middle Root"); summonedMonsterStr2.Rank = 3; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.AttackIncreaseStr)?.MasterDefinition is { } attackIncreaseStr) { attackIncreaseStr.ValueFormula = $"{SkillsInitializer.Formula502} / 100"; attackIncreaseStr.TargetAttribute = greaterDamageBonus; attackIncreaseStr.Aggregation = AggregateType.Multiplicate; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.AttackIncreaseMastery)?.MasterDefinition is { } attackIncreaseMastery) { attackIncreaseMastery.ReplacedSkill = gameConfiguration.Skills.First(s => s.Number == (short)SkillNumber.AttackIncreaseStr); attackIncreaseMastery.ValueFormula = $"{SkillsInitializer.Formula502} / 100"; attackIncreaseMastery.TargetAttribute = greaterDamageBonus; attackIncreaseMastery.Aggregation = AggregateType.Multiplicate; attackIncreaseMastery.ExtendsDuration = true; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.DefenseIncreaseMastery)?.MasterDefinition is { } defenseIncreaseMastery) { defenseIncreaseMastery.ReplacedSkill = gameConfiguration.Skills.First(s => s.Number == (short)SkillNumber.DefenseIncreaseStr); defenseIncreaseMastery.ValueFormula = $"{SkillsInitializer.Formula502} / 100"; defenseIncreaseMastery.TargetAttribute = greaterDefenseBonus; defenseIncreaseMastery.Aggregation = AggregateType.Multiplicate; defenseIncreaseMastery.ExtendsDuration = true; } if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.InfinityArrowStr)?.MasterDefinition is { } infinityArrowStr) { infinityArrowStr.ValueFormula = $"{SkillsInitializer.Formula120} / 100"; } } private ItemBasePowerUpDefinition CreateItemBasePowerUpDefinition(IContext context, GameConfiguration gameConfiguration, AttributeDefinition attributeDefinition, float value, AggregateType aggregateType) { var powerUpDefinition = context.CreateNew(); powerUpDefinition.TargetAttribute = attributeDefinition.GetPersistent(gameConfiguration); powerUpDefinition.BaseValue = value; powerUpDefinition.AggregateType = aggregateType; return powerUpDefinition; } }