//
// 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.PlugIns;
///
/// This update fixes jewelery items and pet options related to damage, and jewelery resistance values.
///
[PlugIn]
[Display(Name = PlugInName, Description = PlugInDescription)]
[Guid("DD5B0424-89DB-4DE4-A1BB-B294F2C1FCE6")]
public class FixJeweleryPetsDamageCalcsPlugInSeason6 : FixJeweleryPetsDamageCalcsPlugInBase
{
///
/// The plug in description.
///
internal new const string PlugInName = "Fix Jewelery and Pets Damage Calculations";
///
/// The plug in description.
///
internal new const string PlugInDescription = "This update fixes jewelery items and pet options related to damage, and jewelery resistance values.";
///
public override string Name => PlugInName;
///
public override string Description => PlugInDescription;
///
public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id;
///
public override UpdateVersion Version => UpdateVersion.FixJeweleryPetsDamageCalcsSeason6;
///
protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration)
{
await base.ApplyAsync(context, gameConfiguration).ConfigureAwait(false);
var jeweleryItemSlots = gameConfiguration.ItemSlotTypes.Where(st => st.ItemSlots.Contains(9) || st.ItemSlots.Contains(10));
var petItemSlot = gameConfiguration.ItemSlotTypes.First(st => st.ItemSlots.Contains(8));
var miscItems = gameConfiguration.Items.Where(i => i.Group == (byte)ItemGroups.Misc1);
var jewelery = miscItems.Where(i => jeweleryItemSlots.Contains(i.ItemSlot));
var pets = miscItems.Where(i => petItemSlot.Equals(i.ItemSlot));
// Remove next season rings
foreach (var jeweleryItem in jewelery.ToList())
{
if (jeweleryItem.Number is 163 or 164 or 165)
{
gameConfiguration.Items.Remove(jeweleryItem);
}
}
// Update jewelery
#pragma warning disable SA1116, SA1117 // Parameters must be on same line or separate lines
var eliteSkeletonRing = jewelery.First(i => i.Number == 39);
this.AddLevelRequirement(context, gameConfiguration, eliteSkeletonRing, 10);
if (eliteSkeletonRing.PossibleItemOptions.FirstOrDefault() is { } eliteSkeletonRingItemOptDef)
{
CreateItemBasePowerUps(eliteSkeletonRing,
(Stats.DefenseBase, 1.1f, AggregateType.Multiplicate));
CreateItemOptionDefinition(eliteSkeletonRingItemOptDef, "Elite Skeleton Transformation Ring", ItemOptionDefinitionNumbers.EliteSkeletonTransformationRing,
(Stats.MaximumHealth, 0, AggregateType.AddRaw, (Stats.Level, 1)));
}
var jackOlanternRing = jewelery.First(i => i.Number == 40);
this.AddLevelRequirement(context, gameConfiguration, jackOlanternRing, 10);
var christmasRing = jewelery.First(i => i.Number == 41);
CreateItemBasePowerUps(christmasRing,
(Stats.BaseDamageBonus, 20, AggregateType.AddRaw));
var gameMasterRing = jewelery.First(i => i.Number == 42);
CreateItemBasePowerUps(gameMasterRing,
(Stats.IceDamageBonus, 255, AggregateType.AddRaw),
(Stats.PoisonDamageBonus, 255, AggregateType.AddRaw),
(Stats.LightningDamageBonus, 255, AggregateType.AddRaw),
(Stats.FireDamageBonus, 255, AggregateType.AddRaw),
(Stats.EarthDamageBonus, 255, AggregateType.AddRaw),
(Stats.WindDamageBonus, 255, AggregateType.AddRaw),
(Stats.WaterDamageBonus, 255, AggregateType.AddRaw),
(Stats.IceResistance, 255, AggregateType.Maximum),
(Stats.PoisonResistance, 255, AggregateType.Maximum),
(Stats.LightningResistance, 255, AggregateType.Maximum),
(Stats.FireResistance, 255, AggregateType.Maximum),
(Stats.EarthResistance, 255, AggregateType.Maximum),
(Stats.WindResistance, 255, AggregateType.Maximum),
(Stats.WaterResistance, 255, AggregateType.Maximum));
var snowmanRing = jewelery.First(i => i.Number == 68);
this.AddLevelRequirement(context, gameConfiguration, snowmanRing, 10);
var pandaRing = jewelery.First(i => i.Number == 76);
pandaRing.PossibleItemOptions.Clear();
CreateItemBasePowerUps(pandaRing,
(Stats.BaseDamageBonus, 30, AggregateType.AddRaw),
(Stats.CurseBaseDmg, 30, AggregateType.AddRaw),
(Stats.MoneyAmountRate, 1.5f, AggregateType.Multiplicate),
(Stats.FinalDamageBonus, 30, AggregateType.AddRaw));
var skeletonRing = jewelery.First(i => i.Number == 122);
if (skeletonRing.PossibleItemOptions.FirstOrDefault() is { } skeletonRingItemOptDef)
{
CreateItemBasePowerUps(skeletonRing,
(Stats.BaseDamageBonus, 40, AggregateType.AddRaw),
(Stats.CurseBaseDmg, 40, AggregateType.AddRaw));
CreateItemOptionDefinition(skeletonRingItemOptDef, "Skeleton Transformation Ring", ItemOptionDefinitionNumbers.SkeletonTransformationRing,
(Stats.BonusExperienceRate, 0, AggregateType.AddRaw, (Stats.IsPetSkeletonEquipped, 0.3f)));
}
var wizardsRing = jewelery.First(i => i.Number == 20);
wizardsRing.PossibleItemOptions.Clear();
CreateItemBasePowerUps(wizardsRing,
(Stats.MinimumPhysBaseDmg, 1.1f, AggregateType.Multiplicate),
(Stats.MaximumPhysBaseDmg, 1.1f, AggregateType.Multiplicate),
(Stats.AttackSpeedAny, 10f, AggregateType.AddRaw),
(Stats.MinimumWizBaseDmg, 1.1f, AggregateType.Multiplicate),
(Stats.MaximumWizBaseDmg, 1.1f, AggregateType.Multiplicate));
// Update pets
var demon = pets.First(i => i.Number == 64);
demon.BasePowerUpAttributes.Clear();
CreateItemBasePowerUps(demon,
(Stats.MinimumPhysBaseDmg, 1.4f, AggregateType.Multiplicate),
(Stats.MaximumPhysBaseDmg, 1.4f, AggregateType.Multiplicate),
(Stats.MinimumWizBaseDmg, 1.4f, AggregateType.Multiplicate),
(Stats.MaximumWizBaseDmg, 1.4f, AggregateType.Multiplicate),
(Stats.MinimumCurseBaseDmg, 1.4f, AggregateType.Multiplicate),
(Stats.MaximumCurseBaseDmg, 1.4f, AggregateType.Multiplicate),
(Stats.AttackSpeedAny, 10f, AggregateType.AddRaw));
var panda = pets.First(i => i.Number == 80);
panda.BasePowerUpAttributes.Clear();
CreateItemBasePowerUps(panda,
(Stats.BonusExperienceRate, 0.5f, AggregateType.AddRaw),
(Stats.DefenseFinal, 50f, AggregateType.AddRaw));
var unicorn = pets.First(i => i.Number == 106);
unicorn.BasePowerUpAttributes.Clear();
CreateItemBasePowerUps(unicorn,
(Stats.MoneyAmountRate, 1.5f, AggregateType.Multiplicate),
(Stats.DefenseFinal, 50f, AggregateType.AddRaw));
var skeleton = pets.First(i => i.Number == 123);
skeleton.BasePowerUpAttributes.Clear();
CreateItemBasePowerUps(skeleton,
(Stats.MinimumPhysBaseDmg, 1.2f, AggregateType.Multiplicate),
(Stats.MaximumPhysBaseDmg, 1.2f, AggregateType.Multiplicate),
(Stats.MinimumWizBaseDmg, 1.2f, AggregateType.Multiplicate),
(Stats.MaximumWizBaseDmg, 1.2f, AggregateType.Multiplicate),
(Stats.MinimumCurseBaseDmg, 1.2f, AggregateType.Multiplicate),
(Stats.MaximumCurseBaseDmg, 1.2f, AggregateType.Multiplicate),
(Stats.AttackSpeedAny, 10f, AggregateType.AddRaw),
(Stats.BonusExperienceRate, 0.3f, AggregateType.AddRaw),
(Stats.IsPetSkeletonEquipped, 1, AggregateType.AddRaw));
#pragma warning restore SA1116, SA1117
void CreateItemBasePowerUps(ItemDefinition item, params (AttributeDefinition AttributeDefinition, float Value, AggregateType AggregateType)[] powerUps)
{
foreach (var (attributeDefinition, value, aggregateType) in powerUps)
{
var powerUpDefinition = context.CreateNew();
powerUpDefinition.TargetAttribute = attributeDefinition.GetPersistent(gameConfiguration);
powerUpDefinition.BaseValue = value;
powerUpDefinition.AggregateType = aggregateType;
item.BasePowerUpAttributes.Add(powerUpDefinition);
}
}
void CreateItemOptionDefinition(ItemOptionDefinition itemOptionDef, string name, short number, (AttributeDefinition TargetOption, float Value, AggregateType AggregateType, (AttributeDefinition SourceAttribute, float Multiplier)) option)
{
itemOptionDef.Name = name;
foreach (var possibleOption in itemOptionDef.PossibleOptions.ToList())
{
if (possibleOption.PowerUpDefinition?.TargetAttribute != option.TargetOption)
{
itemOptionDef.PossibleOptions.Remove(possibleOption);
}
}
if (itemOptionDef.PossibleOptions.Count == 0)
{
itemOptionDef.PossibleOptions.Add(CreateItemOption(option.TargetOption, option.Value, option.AggregateType, number, (option.Item4.SourceAttribute, option.Item4.Multiplier)));
}
else
{
// Update existing option
var possibleOption = itemOptionDef.PossibleOptions.First();
possibleOption.PowerUpDefinition!.Boost!.ConstantValue.Value = option.Value;
possibleOption.PowerUpDefinition.Boost.ConstantValue.AggregateType = option.AggregateType;
var attributeRelationship = context.CreateNew();
attributeRelationship.SetGuid(number, option.TargetOption.Id.ExtractFirstTwoBytes(), 0);
attributeRelationship.InputAttribute = option.Item4.SourceAttribute.GetPersistent(gameConfiguration);
attributeRelationship.InputOperator = InputOperator.Multiply;
attributeRelationship.InputOperand = option.Item4.Multiplier;
possibleOption.PowerUpDefinition.Boost.RelatedValues.Add(attributeRelationship);
}
// Always add all options "randomly" when it drops ;)
itemOptionDef.AddChance = 1.0f;
itemOptionDef.AddsRandomly = true;
itemOptionDef.MaximumOptionsPerItem = 1;
}
IncreasableItemOption CreateItemOption(AttributeDefinition targetOption, float value, AggregateType aggregateType, short number, (AttributeDefinition? SourceAttribute, float Multiplier) relatedAttribute)
{
var itemOption = context.CreateNew();
itemOption.SetGuid(number, targetOption.Id.ExtractFirstTwoBytes());
itemOption.PowerUpDefinition = context.CreateNew();
itemOption.PowerUpDefinition.TargetAttribute = targetOption.GetPersistent(gameConfiguration);
itemOption.PowerUpDefinition.Boost = context.CreateNew();
itemOption.PowerUpDefinition.Boost.ConstantValue.Value = value;
itemOption.PowerUpDefinition.Boost.ConstantValue.AggregateType = aggregateType;
if (relatedAttribute.SourceAttribute is not null)
{
var attributeRelationship = context.CreateNew();
attributeRelationship.SetGuid(number, targetOption.Id.ExtractFirstTwoBytes(), 0);
attributeRelationship.InputAttribute = relatedAttribute.SourceAttribute.GetPersistent(gameConfiguration);
attributeRelationship.InputOperator = InputOperator.Multiply;
attributeRelationship.InputOperand = relatedAttribute.Multiplier;
itemOption.PowerUpDefinition.Boost.RelatedValues.Add(attributeRelationship);
}
return itemOption;
}
// Update skills
if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.PoisonResistanceInc)?.MasterDefinition is { } poisonResistanceInc)
{
poisonResistanceInc.ValueFormula = poisonResistanceInc.DisplayValueFormula;
}
if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.LightningResistanceInc)?.MasterDefinition is { } lightningResistanceInc)
{
lightningResistanceInc.ValueFormula = lightningResistanceInc.DisplayValueFormula;
}
if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.IceResistanceIncrease)?.MasterDefinition is { } iceResistanceIncrease)
{
iceResistanceIncrease.ValueFormula = iceResistanceIncrease.DisplayValueFormula;
}
}
}