diff --git a/src/AttributeSystem/ComposableAttribute.cs b/src/AttributeSystem/ComposableAttribute.cs index 405020505..90183b6fa 100644 --- a/src/AttributeSystem/ComposableAttribute.cs +++ b/src/AttributeSystem/ComposableAttribute.cs @@ -11,6 +11,8 @@ public class ComposableAttribute : BaseAttribute, IComposableAttribute { private readonly IList _elementList; + private float? _maximumValue; + private float? _cachedValue; /// @@ -18,10 +20,12 @@ public class ComposableAttribute : BaseAttribute, IComposableAttribute /// /// The definition. /// Type of the aggregate. - public ComposableAttribute(AttributeDefinition definition, AggregateType aggregateType = AggregateType.AddRaw) + /// The inner maximum value. + public ComposableAttribute(AttributeDefinition definition, AggregateType aggregateType = AggregateType.AddRaw, float? maximumValue = null) : base(definition, aggregateType) { this._elementList = new List(); + this._maximumValue = maximumValue; } /// @@ -78,6 +82,11 @@ private float GetAndCacheValue() } var newValue = (rawValues * multiValues) + finalValues; + if (this._maximumValue.HasValue) + { + newValue = Math.Min(this._maximumValue.Value, newValue); + } + if (this.Definition.MaximumValue.HasValue) { newValue = Math.Min(this.Definition.MaximumValue.Value, newValue); diff --git a/src/DataModel/Attributes/PowerUpDefinitionValue.cs b/src/DataModel/Attributes/PowerUpDefinitionValue.cs index 3ebbc5854..c8227fed0 100644 --- a/src/DataModel/Attributes/PowerUpDefinitionValue.cs +++ b/src/DataModel/Attributes/PowerUpDefinitionValue.cs @@ -27,6 +27,11 @@ public partial class PowerUpDefinitionValue [MemberOfAggregate] public virtual ICollection RelatedValues { get; protected set; } = null!; + /// + /// Gets or sets the maximum allowable value. + /// + public float? MaximumValue { get; set; } + /// public override string ToString() { diff --git a/src/DataModel/Configuration/MagicEffectDefinition.cs b/src/DataModel/Configuration/MagicEffectDefinition.cs index 4d5598294..2d4f1d0e6 100644 --- a/src/DataModel/Configuration/MagicEffectDefinition.cs +++ b/src/DataModel/Configuration/MagicEffectDefinition.cs @@ -51,18 +51,69 @@ public partial class MagicEffectDefinition /// public bool SendDuration { get; set; } + /// + /// Gets or sets a value indicating whether the duration of the effect depends on the target's level. + /// + public bool DurationDependsOnTargetLevel { get; set; } + + /// + /// Gets or sets a value by which the effect target's (monster) level should be divided in case is true. + /// + public float MonsterTargetLevelDivisor { get; set; } = 1f; + + /// + /// Gets or sets a value by which the effect target's (player) level should be divided in case is true. + /// + public float PlayerTargetLevelDivisor { get; set; } = 1f; + + /// + /// Gets or sets the chance of applying the effect, in decimals. + /// + /// + /// Results in a value of 1.0 if not set. + /// + [MemberOfAggregate] + public virtual PowerUpDefinitionValue? Chance { get; set; } + + /// + /// Gets or sets the chance of applying the effect in PvP, in decimals. + /// + /// + /// Results in the same value as if not set. + /// + [MemberOfAggregate] + public virtual PowerUpDefinitionValue? ChancePvp { get; set; } + /// /// Gets or sets the duration which describes how long the apply, in seconds. /// [MemberOfAggregate] public virtual PowerUpDefinitionValue? Duration { get; set; } + /// + /// Gets or sets the duration which describes how long the apply to PvP, in seconds. + /// + /// + /// Results in the same value as if not set. + /// + [MemberOfAggregate] + public virtual PowerUpDefinitionValue? DurationPvp { get; set; } + /// /// Gets or sets the power up definitions which are used to create the actual power up element. /// [MemberOfAggregate] public virtual ICollection PowerUpDefinitions { get; protected set; } = null!; + /// + /// Gets or sets the power up definitions which are used to create the actual power up element for PvP. + /// + /// + /// Results in the same collection as if not set. + /// + [MemberOfAggregate] + public virtual ICollection PowerUpDefinitionsPvp { get; protected set; } = null!; + /// public override string ToString() { diff --git a/src/DataModel/Entities/SkillEntry.cs b/src/DataModel/Entities/SkillEntry.cs index 29a498700..87e280262 100644 --- a/src/DataModel/Entities/SkillEntry.cs +++ b/src/DataModel/Entities/SkillEntry.cs @@ -49,6 +49,12 @@ public int Level [Transient] public (AttributeDefinition Target, IElement BuffPowerUp)[]? PowerUps { get; set; } + /// + /// Gets or sets the PvP power up element of this skill of this player. It is a "cached" element which will be created on demand and can be applied multiple times. + /// + [Transient] + public (AttributeDefinition Target, IElement BuffPowerUp)[]? PowerUpsPvp { get; set; } + /// /// Gets or sets the duration of the . /// @@ -58,6 +64,33 @@ public int Level [Transient] public IElement? PowerUpDuration { get; set; } + /// + /// Gets or sets the duration of the for PvP. + /// + /// + /// It is an IElement, because the duration can be dependent from the player attributes. + /// + [Transient] + public IElement? PowerUpDurationPvp { get; set; } + + /// + /// Gets or sets the chance of applying the . + /// + /// + /// It is an IElement, because the duration can be dependent from the player attributes. + /// + [Transient] + public IElement? PowerUpChance { get; set; } + + /// + /// Gets or sets the chance of applying the for PvP. + /// + /// + /// It is an IElement, because the duration can be dependent from the player attributes. + /// + [Transient] + public IElement? PowerUpChancePvp { get; set; } + /// /// Gets or sets the attributes, if this skill has attribute relationships. /// diff --git a/src/DataModel/GameConfigurationHelper.cs b/src/DataModel/GameConfigurationHelper.cs index a3110f95d..9a5a03a86 100644 --- a/src/DataModel/GameConfigurationHelper.cs +++ b/src/DataModel/GameConfigurationHelper.cs @@ -46,6 +46,7 @@ public static class GameConfigurationHelper .Concat(c.ItemOptions.SelectMany(o => o.PossibleOptions.Select(p => p.PowerUpDefinition).WhereNotNull())) .Concat(c.ItemOptions.SelectMany(o => o.PossibleOptions.SelectMany(p => p.LevelDependentOptions.Select(l => l.PowerUpDefinition).WhereNotNull()))) .Concat(c.MagicEffects.SelectMany(m => m.PowerUpDefinitions)) + .Concat(c.MagicEffects.SelectMany(m => m.PowerUpDefinitionsPvp)) }, { typeof(ItemBasePowerUpDefinition), c => c.Items.SelectMany(i => i.BasePowerUpAttributes) }, { typeof(ItemDropItemGroup), c => c.Items.SelectMany(i => i.DropItems) }, @@ -65,7 +66,10 @@ public static class GameConfigurationHelper { typeof(JewelMix), c => c.JewelMixes }, { typeof(MagicEffectDefinition), c => c.MagicEffects }, { - typeof(PowerUpDefinitionValue), c => c.MagicEffects.Select(e => e.Duration).WhereNotNull() + typeof(PowerUpDefinitionValue), c => c.MagicEffects.Select(e => e.Duration) + .Concat(c.MagicEffects.Select(e => e.DurationPvp)) + .Concat(c.MagicEffects.Select(e => e.Chance)) + .Concat(c.MagicEffects.Select(e => e.ChancePvp)).WhereNotNull() .Concat(Enumerables![typeof(PowerUpDefinition)](c).OfType().Select(p => p.Boost).WhereNotNull()) }, { typeof(SimpleElement), c => Enumerables![typeof(PowerUpDefinitionValue)](c).OfType().Select(v => v.ConstantValue).WhereNotNull() }, diff --git a/src/GameLogic/AttackableExtensions.cs b/src/GameLogic/AttackableExtensions.cs index 582a6c22d..63684c730 100644 --- a/src/GameLogic/AttackableExtensions.cs +++ b/src/GameLogic/AttackableExtensions.cs @@ -64,6 +64,11 @@ public static async ValueTask CalculateDamageAsync(this IAttacker attac { var defenseAttribute = defender.GetDefenseAttribute(attacker); defense = (int)defender.Attributes[defenseAttribute]; + defense -= (int)(defense * defender.Attributes[Stats.InnovationDefDecrement]); + if (defense < 0) + { + defense = 0; + } } attacker.GetBaseDmg(skill, out int baseMinDamage, out int baseMaxDamage, out DamageType damageType); @@ -309,7 +314,15 @@ public static async ValueTask ApplyMagicEffectAsync(this IAttackable target, IAt player.CreateMagicEffectPowerUp(skillEntry); } - await target.ApplyMagicEffectAsync(attacker, skillEntry.Skill!.MagicEffectDef!, skillEntry.PowerUpDuration!, skillEntry.PowerUps!).ConfigureAwait(false); + float chance = target is Player ? skillEntry.PowerUpChancePvp!.Value : skillEntry.PowerUpChance!.Value; + if (!Rand.NextRandomBool(Convert.ToDouble(chance))) + { + return; + } + + var duration = target is Player ? skillEntry.PowerUpDurationPvp! : skillEntry.PowerUpDuration!; + var powerUps = target is Player ? skillEntry.PowerUpsPvp! : skillEntry.PowerUps!; + await target.ApplyMagicEffectAsync(attacker, skillEntry.Skill!.MagicEffectDef!, duration, powerUps).ConfigureAwait(false); } /// @@ -356,6 +369,11 @@ public static async ValueTask ApplyRegenerationAsync(this IAttackable target, Pl /// The success of the appliance. public static async ValueTask TryApplyElementalEffectsAsync(this IAttackable target, IAttacker attacker, SkillEntry skillEntry) { + if (!target.IsAlive) + { + return false; + } + skillEntry.ThrowNotInitializedProperty(skillEntry.Skill is null, nameof(skillEntry.Skill)); var modifier = skillEntry.Skill.ElementalModifierTarget; if (modifier is null) @@ -389,7 +407,7 @@ public static async ValueTask TryApplyElementalEffectsAsync(this IAttackab } /// - /// Applies the elemental effects of a players skill to the target. + /// Applies the elemental effects of a monster's skill to the target. /// /// The target. /// The attacker. @@ -402,6 +420,11 @@ public static async ValueTask TryApplyElementalEffectsAsync(this IAttackab /// public static async ValueTask TryApplyElementalEffectsAsync(this IAttackable target, IAttacker attacker, Skill skill, IElement? powerUp, IElement? duration, AttributeDefinition? targetAttribute) { + if (!target.IsAlive) + { + return false; + } + var modifier = skill.ElementalModifierTarget; if (modifier is null) { @@ -445,7 +468,7 @@ public static void ApplyAmmunitionConsumption(this IAttacker attacker, HitInfo h { if (!hitInfo.Attributes.HasFlag(DamageAttributes.Reflected) && attacker.Attributes[Stats.AmmunitionConsumptionRate] > 0.0) { - // Every hit needs ammo. Failed hits don't need ammo. + // Every hit needs ammo, missed or not if (attacker.Attributes[Stats.AmmunitionAmount] < attacker.Attributes[Stats.AmmunitionConsumptionRate]) { return; @@ -773,15 +796,32 @@ private static void GetBaseDmg(this IAttacker attacker, SkillEntry? skill, out i /// The power ups of the effect. private static async ValueTask ApplyMagicEffectAsync(this IAttackable target, IAttacker attacker, MagicEffectDefinition magicEffectDefinition, IElement duration, params (AttributeDefinition Target, IElement Boost)[] powerUps) { + float finalDuration = duration.Value; + + if (magicEffectDefinition.DurationDependsOnTargetLevel) + { + var divisor = target is Player ? magicEffectDefinition.PlayerTargetLevelDivisor : magicEffectDefinition.MonsterTargetLevelDivisor; + if (divisor != 0) + { + finalDuration -= target.Attributes[Stats.Level] / divisor; + } + } + + TimeSpan durationSpan = TimeSpan.FromSeconds(finalDuration); + if (durationSpan < TimeSpan.FromSeconds(1)) + { + return; + } + var isPoisonEffect = magicEffectDefinition.PowerUpDefinitions.Any(e => e.TargetAttribute == Stats.IsPoisoned); var magicEffect = isPoisonEffect - ? new PoisonMagicEffect(powerUps[0].Boost, magicEffectDefinition, TimeSpan.FromSeconds(duration.Value), attacker, target) - : new MagicEffect(TimeSpan.FromSeconds(duration.Value), magicEffectDefinition, powerUps.Select(p => new MagicEffect.ElementWithTarget(p.Boost, p.Target)).ToArray()); + ? new PoisonMagicEffect(powerUps[0].Boost, magicEffectDefinition, durationSpan, attacker, target) + : new MagicEffect(durationSpan, magicEffectDefinition, powerUps.Select(p => new MagicEffect.ElementWithTarget(p.Boost, p.Target)).ToArray()); await target.MagicEffectList.AddEffectAsync(magicEffect).ConfigureAwait(false); if (target is ISupportWalk walkSupporter && walkSupporter.IsWalking - && magicEffectDefinition.PowerUpDefinitions.Any(e => e.TargetAttribute == Stats.IsFrozen || e.TargetAttribute == Stats.IsStunned)) + && magicEffectDefinition.PowerUpDefinitions.Any(e => e.TargetAttribute == Stats.IsFrozen || e.TargetAttribute == Stats.IsStunned || e.TargetAttribute == Stats.IsAsleep)) { await walkSupporter.StopWalkingAsync().ConfigureAwait(false); diff --git a/src/GameLogic/Attributes/AttributeSystemExtensions.cs b/src/GameLogic/Attributes/AttributeSystemExtensions.cs index bb75c8116..b91d655bf 100644 --- a/src/GameLogic/Attributes/AttributeSystemExtensions.cs +++ b/src/GameLogic/Attributes/AttributeSystemExtensions.cs @@ -18,6 +18,11 @@ public static class AttributeSystemExtensions /// private static AttributeDefinition DurationDummy { get; } = new(new Guid("23D069C3-24D8-4277-8FDC-D82F0AF64037"), "Duration Dummy", "A dummy attribute to be used internally for durations."); + /// + /// Gets the attribute for a dummy attribute to be used internally for chances. + /// + private static AttributeDefinition ChanceDummy { get; } = new(new Guid("E6B9E6A5-5800-40EA-80B7-14C2C06392A6"), "Chance Dummy", "A dummy attribute to be used internally for chances."); + /// /// Creates a new element on this attribute system with the specified power up value. /// @@ -29,6 +34,17 @@ public static IElement CreateDurationElement(this IAttributeSystem attributeSyst return attributeSystem.CreateElement(powerUpDefinition, DurationDummy); } + /// + /// Creates a new element on this attribute system with the specified power up value. + /// + /// The attribute system. + /// The power up definition. + /// The added element. + public static IElement CreateChanceElement(this IAttributeSystem attributeSystem, PowerUpDefinitionValue powerUpDefinition) + { + return attributeSystem.CreateElement(powerUpDefinition, ChanceDummy); + } + /// /// Creates a new element on this attribute system with the specified power up value. /// @@ -70,7 +86,7 @@ public static IElement CreateElement(this IAttributeSystem attributeSystem, Powe elements = elements.Concat(value.ConstantValue.GetAsEnumerable()); } - var composableResult = new ComposableAttribute(targetDefinition, result.AggregateType); + var composableResult = new ComposableAttribute(targetDefinition, result.AggregateType, value.MaximumValue); elements.ForEach(element => composableResult.AddElement(element)); return composableResult; diff --git a/src/GameLogic/Attributes/Stats.cs b/src/GameLogic/Attributes/Stats.cs index 1349bb9b8..0d2e0bded 100644 --- a/src/GameLogic/Attributes/Stats.cs +++ b/src/GameLogic/Attributes/Stats.cs @@ -638,7 +638,7 @@ public class Stats /// /// Gets the explosion skill MST bonus damage, which rises with fire tome strengthener and is added late stage. /// - public static AttributeDefinition ExplosionBonusDmg { get; } = new(new Guid("543E01C2-5C61-4473-ACF9-8A63A987A230"), "Explosion Bonus Damage (MST)", "The explosion skill (book of samut) bonus damage, which rises with fire stome strengthener and is added at a late stage."); + public static AttributeDefinition ExplosionBonusDmg { get; } = new(new Guid("543E01C2-5C61-4473-ACF9-8A63A987A230"), "Explosion Bonus Damage (MST)", "The explosion skill (book of samut) bonus damage, which rises with fire tome strengthener and is added at a late stage."); /// /// Gets the requiem skill MST bonus damage, which rises with wind tome strengthener and is added late stage. @@ -920,6 +920,11 @@ public class Stats /// Only applies to physical damage. public static AttributeDefinition WeaknessPhysDmgDecrement { get; } = new(new Guid("37497650-139B-4DA1-9FB6-27AEB8F04CF6"), "Weakness Physical Damage Decrement", "The inflicted physical damage decrement due to the magic effects of weakness or killing blow skills, which is multiplied with the final damage and subtracted from it."); + /// + /// Gets the innovation defense decrement due to Summoner's innovation skill attribute definition. + /// + public static AttributeDefinition InnovationDefDecrement { get; } = new(new Guid("D8B3B1C9-B409-4A07-8F4D-8F315DCB173A"), "Innovation Defense Decrement", "The defense decrement due to the magic effect of innovation skill, which is multiplied with the final defense and subtracted from it."); + /// /// Gets the 'is shield equipped' attribute definition. /// @@ -943,7 +948,12 @@ public class Stats /// /// Gets the attribute definition, which defines if a player has stun effect applied. /// - public static AttributeDefinition IsStunned { get; } = new(new Guid("22C86BAF-7F27-478D-8075-E4465C2859DD"), "Is stunned", "The player is poisoned and loses health"); + public static AttributeDefinition IsStunned { get; } = new(new Guid("22C86BAF-7F27-478D-8075-E4465C2859DD"), "Is stunned", "The player is stunned and can't move."); + + /// + /// Gets the attribute definition, which defines if a player has asleep effect applied. + /// + public static AttributeDefinition IsAsleep { get; } = new(new Guid("0518F532-7A8F-4491-8A23-98B620608CB3"), "Is asleep", "The player is asleep and can't move until hit."); /// /// Gets the ice resistance attribute definition. Value range from 0 to 1. @@ -1226,6 +1236,11 @@ public class Stats /// public static AttributeDefinition FullyRecoverHealthAfterHitChance { get; } = new(new Guid("3CA72C07-9C2C-4FC5-8BCB-9BD737F83664"), "Chance to fully recover health when getting hit", "3rd Wing Option"); + /// + /// Gets the fully reflect damage after hit chance definition. + /// + public static AttributeDefinition FullyReflectDamageAfterHitChance { get; } = new(new Guid("1F7C1E04-4FBD-4FCB-A6C2-EB51A91D8C3E"), "Chance to fully reflect damage when getting hit", "3rd Wing Option"); + /// /// Gets the health loss after hit definition. /// diff --git a/src/GameLogic/MagicEffectsList.cs b/src/GameLogic/MagicEffectsList.cs index a6bf17fb1..54ad80a60 100644 --- a/src/GameLogic/MagicEffectsList.cs +++ b/src/GameLogic/MagicEffectsList.cs @@ -5,6 +5,7 @@ namespace MUnique.OpenMU.GameLogic; using System.Collections; +using MUnique.OpenMU.AttributeSystem; using MUnique.OpenMU.GameLogic.Views.World; using Nito.AsyncEx; @@ -93,6 +94,23 @@ public async ValueTask ClearAllEffectsAsync() } } + /// + /// Clear the effects that produce a specific stat. + /// + /// The stat produced by effect + public async ValueTask ClearAllEffectsProducingSpecificStatAsync(AttributeDefinition stat) + { + var effects = this.ActiveEffects.Values.ToArray(); + + foreach (var effect in effects) + { + if (effect.PowerUpElements.Any(p => p.Target == stat)) + { + await effect.DisposeAsync().ConfigureAwait(false); + } + } + } + /// /// Clears the effects after death of the player. /// diff --git a/src/GameLogic/NPC/AttackableNpcBase.cs b/src/GameLogic/NPC/AttackableNpcBase.cs index 04b0462fc..722d7a372 100644 --- a/src/GameLogic/NPC/AttackableNpcBase.cs +++ b/src/GameLogic/NPC/AttackableNpcBase.cs @@ -106,10 +106,21 @@ public int Health } var hitInfo = await attacker.CalculateDamageAsync(this, skill, isCombo, damageFactor).ConfigureAwait(false); + + if (skill?.Skill is not { } attackSkill || attackSkill.DamageType != DamageType.Fenrir) + { + attacker.ApplyAmmunitionConsumption(hitInfo); + } + await this.HitAsync(hitInfo, attacker, skill?.Skill).ConfigureAwait(false); + if (hitInfo.HealthDamage > 0) { - attacker.ApplyAmmunitionConsumption(hitInfo); + if (this.Attributes[Stats.IsAsleep] > 0) + { + await this.MagicEffectList.ClearAllEffectsProducingSpecificStatAsync(Stats.IsAsleep).ConfigureAwait(false); + } + if (attacker is Player player) { await player.AfterHitTargetAsync().ConfigureAwait(false); diff --git a/src/GameLogic/NPC/BasicMonsterIntelligence.cs b/src/GameLogic/NPC/BasicMonsterIntelligence.cs index cda2728fc..ec5001894 100644 --- a/src/GameLogic/NPC/BasicMonsterIntelligence.cs +++ b/src/GameLogic/NPC/BasicMonsterIntelligence.cs @@ -218,7 +218,7 @@ private async ValueTask TickAsync() return; } - if (this.Monster.Attributes[Stats.IsStunned] > 0) + if (this.Monster.Attributes[Stats.IsStunned] > 0 || this.Monster.Attributes[Stats.IsAsleep] > 0) { return; } diff --git a/src/GameLogic/Player.cs b/src/GameLogic/Player.cs index c569bf6d2..2ce747927 100644 --- a/src/GameLogic/Player.cs +++ b/src/GameLogic/Player.cs @@ -628,6 +628,11 @@ public bool IsAnySelfDefenseActive() var hitInfo = await attacker.CalculateDamageAsync(this, skill, isCombo, damageFactor).ConfigureAwait(false); + if (skill?.Skill is not { } attackSkill || attackSkill.DamageType != DamageType.Fenrir) + { + attacker.ApplyAmmunitionConsumption(hitInfo); + } + if (hitInfo is { HealthDamage: 0, ShieldDamage: 0 }) { await this.InvokeViewPlugInAsync(p => p.ShowHitAsync(this, hitInfo)).ConfigureAwait(false); @@ -639,7 +644,10 @@ public bool IsAnySelfDefenseActive() return hitInfo; } - attacker.ApplyAmmunitionConsumption(hitInfo); + if (this.Attributes[Stats.IsAsleep] > 0) + { + await this.MagicEffectList.ClearAllEffectsProducingSpecificStatAsync(Stats.IsAsleep).ConfigureAwait(false); + } if (Rand.NextRandomBool(this.Attributes[Stats.FullyRecoverHealthAfterHitChance])) { @@ -1229,7 +1237,7 @@ public async ValueTask WalkToAsync(Point target, Memory steps) return; } - if (attributes[Stats.IsFrozen] > 0 || attributes[Stats.IsStunned] > 0) + if (attributes[Stats.IsFrozen] > 0 || attributes[Stats.IsStunned] > 0 || attributes[Stats.IsAsleep] > 0) { return; } @@ -1461,17 +1469,31 @@ public void CreateMagicEffectPowerUp(SkillEntry skillEntry) throw new InvalidOperationException($"Skill {skill.Name} ({skill.Number}) has no duration in MagicEffectDef."); } - int i = 0; var result = new (AttributeDefinition Target, IElement BuffPowerUp)[skill.MagicEffectDef.PowerUpDefinitions.Count]; + var resultPvp = new (AttributeDefinition Target, IElement BuffPowerUp)[skill.MagicEffectDef.PowerUpDefinitionsPvp.Count]; var durationElement = this.Attributes!.CreateDurationElement(skill.MagicEffectDef.Duration); - AddSkillPowersToResult(skill); + var durationElementPvp = skill.MagicEffectDef.DurationPvp is { } durationPvp ? this.Attributes!.CreateDurationElement(durationPvp) : durationElement; + var chanceElement = skill.MagicEffectDef.Chance is { } chance ? this.Attributes!.CreateChanceElement(chance) : new ConstantElement(1.0f); + var chanceElementPvp = skill.MagicEffectDef.ChancePvp is { } chancePvp ? this.Attributes!.CreateChanceElement(chancePvp) : chanceElement; + AddSkillPowersToResult(skill.MagicEffectDef.PowerUpDefinitions, ref result); + AddSkillPowersToResult(skill.MagicEffectDef.PowerUpDefinitionsPvp, ref resultPvp); skillEntry.PowerUpDuration = durationElement; + skillEntry.PowerUpDurationPvp = durationElementPvp; + skillEntry.PowerUpChance = chanceElement; + skillEntry.PowerUpChancePvp = chanceElementPvp; skillEntry.PowerUps = result; + skillEntry.PowerUpsPvp = resultPvp.Count() > 0 ? resultPvp : result; - void AddSkillPowersToResult(Skill skill) + void AddSkillPowersToResult(ICollection powerUps, ref (AttributeDefinition Target, IElement BuffPowerUp)[] result) { + if (powerUps.Count() == 0) + { + return; + } + + int i = 0; var durationExtended = false; - foreach (var powerUpDef in skill.MagicEffectDef!.PowerUpDefinitions) + foreach (var powerUpDef in powerUps) { IElement powerUp; if (skillEntry.Level > 0) @@ -2037,10 +2059,33 @@ private async ValueTask HitAsync(HitInfo hitInfo, IAttacker attacker, Skill? ski return; } - var reflectPercentage = this.Attributes[Stats.DamageReflection]; - if (reflectPercentage > 0 && attacker is IAttackable attackableAttacker) + if (attacker is IAttackable or AttackerSurrogate) + { + var attackableAttacker = (attacker as AttackerSurrogate)?.Owner ?? (IAttackable)attacker; + + var reflectPercentage = this.Attributes[Stats.DamageReflection]; + if (reflectPercentage > 0) + { + var reflectedDamage = (hitInfo.HealthDamage + hitInfo.ShieldDamage) * reflectPercentage; + ReflectDamage((int)reflectedDamage, attackableAttacker); + } + + if (attacker is not AttackerSurrogate) + { + // Raven does not cause full reflect. + var fullReflectPercentage = this.Attributes[Stats.FullyReflectDamageAfterHitChance]; + if (fullReflectPercentage > 0 && Rand.NextRandomBool(fullReflectPercentage)) + { + var reflectedDamage = attackableAttacker is Player + ? hitInfo.HealthDamage + hitInfo.ShieldDamage + : attackableAttacker.Attributes[Stats.MaximumPhysBaseDmg]; + ReflectDamage((int)reflectedDamage, attackableAttacker); + } + } + } + + void ReflectDamage(int reflectedDamage, IAttackable attackable) { - var reflectedDamage = (int)((hitInfo.HealthDamage + hitInfo.ShieldDamage) * reflectPercentage); if (reflectedDamage <= 0) { return; @@ -2049,9 +2094,9 @@ private async ValueTask HitAsync(HitInfo hitInfo, IAttacker attacker, Skill? ski _ = Task.Run(async () => { await Task.Delay(500).ConfigureAwait(false); - if (attackableAttacker.IsAlive) + if (attackable.IsAlive) { - await attackableAttacker.ReflectDamageAsync(this, (uint)reflectedDamage).ConfigureAwait(false); + await attackable.ReflectDamageAsync(this, (uint)reflectedDamage).ConfigureAwait(false); } }); } diff --git a/src/GameLogic/PlayerActions/HitAction.cs b/src/GameLogic/PlayerActions/HitAction.cs index 1f3303335..49795a39c 100644 --- a/src/GameLogic/PlayerActions/HitAction.cs +++ b/src/GameLogic/PlayerActions/HitAction.cs @@ -32,6 +32,12 @@ public async ValueTask HitAsync(Player player, IAttackable target, byte attackAn return; } + if (attributes[Stats.IsAsleep] > 0) + { + player.Logger.LogWarning($"Probably Hacker - player {player} is attacking in asleep state"); + return; + } + if (player.IsAtSafezone()) { player.Logger.LogWarning($"Probably Hacker - player {player} is attacking from safezone"); diff --git a/src/GameLogic/PlayerActions/Skills/AreaSkillAttackAction.cs b/src/GameLogic/PlayerActions/Skills/AreaSkillAttackAction.cs index b01459d57..caf326a3d 100644 --- a/src/GameLogic/PlayerActions/Skills/AreaSkillAttackAction.cs +++ b/src/GameLogic/PlayerActions/Skills/AreaSkillAttackAction.cs @@ -46,7 +46,7 @@ public async ValueTask AttackAsync(Player player, ushort extraTargetId, ushort s return; } - if (skill.SkillType is SkillType.AreaSkillAutomaticHits or SkillType.AreaSkillExplicitTarget + if (skill.SkillType is SkillType.AreaSkillAutomaticHits or SkillType.AreaSkillExplicitTarget or SkillType.Buff || (skill.SkillType is SkillType.AreaSkillExplicitHits && hitImplicitlyForExplicitSkill)) { // todo: delayed automatic hits, like evil spirit, flame, triple shot... when hitImplicitlyForExplicitSkill = true. @@ -70,6 +70,12 @@ private async ValueTask PerformAutomaticHitsAsync(Player player, ushort extraTar return; } + if (attributes[Stats.IsAsleep] > 0) + { + player.Logger.LogWarning("Probably Hacker - player {player} is attacking in sleep state", player); + return; + } + if (player.IsAtSafezone()) { player.Logger.LogWarning("Probably Hacker - player {player} is attacking from safezone", player); @@ -123,13 +129,18 @@ private async ValueTask PerformAutomaticHitsAsync(Player player, ushort extraTar for (int attackRound = 0; attackRound < areaSkillSettings.MaximumNumberOfHitsPerTarget; attackRound++) { - if (attackCount > maxAttacks) + if (attackCount >= maxAttacks) { break; } foreach (var target in targets) { + if (attackCount >= maxAttacks) + { + break; + } + if (target.Id == extraTargetId) { extraTarget = target; @@ -243,6 +254,12 @@ private async ValueTask ApplySkillAsync(Player player, SkillEntry skillEntry, IA { skillEntry.ThrowNotInitializedProperty(skillEntry.Skill is null, nameof(skillEntry.Skill)); + if (skillEntry.Skill.SkillType == SkillType.Buff) + { + await target.ApplyMagicEffectAsync(player, skillEntry).ConfigureAwait(false); + return; + } + var hitInfo = await target.AttackByAsync(player, skillEntry, isCombo).ConfigureAwait(false); await target.TryApplyElementalEffectsAsync(player, skillEntry).ConfigureAwait(false); var baseSkill = skillEntry.GetBaseSkill(); diff --git a/src/GameLogic/PlayerActions/Skills/ChainLightningSkillPlugIn.cs b/src/GameLogic/PlayerActions/Skills/ChainLightningSkillPlugIn.cs index 5f9891965..68cf24200 100644 --- a/src/GameLogic/PlayerActions/Skills/ChainLightningSkillPlugIn.cs +++ b/src/GameLogic/PlayerActions/Skills/ChainLightningSkillPlugIn.cs @@ -28,6 +28,11 @@ public async ValueTask AfterTargetGotAttackedAsync(IAttacker attacker, IAttackab { bool FilterTarget(IAttackable attackable) { + if (!attackable.IsAlive) + { + return false; + } + if (attackable is Monster { SummonedBy: null } or Destructible) { return true; diff --git a/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs b/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs index a3c823f08..a8feddda6 100644 --- a/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs +++ b/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs @@ -7,14 +7,13 @@ namespace MUnique.OpenMU.GameLogic.PlayerActions.Skills; using System.Runtime.InteropServices; using MUnique.OpenMU.GameLogic.Attributes; using MUnique.OpenMU.GameLogic.PlugIns; -using MUnique.OpenMU.GameLogic.Views.Character; using MUnique.OpenMU.Pathfinding; using MUnique.OpenMU.PlugIns; /// /// Handles the drain life skill of the summoner class. Additionally to the attacked target, it regains life for damage dealt. /// -[PlugIn(nameof(ChainLightningSkillPlugIn), "Handles the drain life skill of the summoner class. Additionally to the attacked target, it regains life for damage dealt.")] +[PlugIn(nameof(DrainLifeSkillPlugIn), "Handles the drain life skill of the summoner class. Additionally to the attacked target, it regains life for damage dealt.")] [Guid("9A5A5671-3A8C-4C01-984F-1A8F8E0E7BDA")] public class DrainLifeSkillPlugIn : IAreaSkillPlugIn { diff --git a/src/GameLogic/PlayerActions/Skills/SkillCancellationTokenSource.cs b/src/GameLogic/PlayerActions/Skills/SkillCancellationTokenSource.cs index 12dcafc8b..25b873b40 100644 --- a/src/GameLogic/PlayerActions/Skills/SkillCancellationTokenSource.cs +++ b/src/GameLogic/PlayerActions/Skills/SkillCancellationTokenSource.cs @@ -1,4 +1,4 @@ -// +// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // @@ -9,7 +9,7 @@ namespace MUnique.OpenMU.GameLogic.PlayerActions.Skills; /// /// A which allows to specify an explicit target when cancelling the nova skill. /// -/// +/// public class SkillCancellationTokenSource : CancellationTokenSource { /// diff --git a/src/GameLogic/PlayerActions/Skills/TargetedSkillDefaultPlugin.cs b/src/GameLogic/PlayerActions/Skills/TargetedSkillDefaultPlugin.cs index 4bd07b93a..e4dcddb32 100644 --- a/src/GameLogic/PlayerActions/Skills/TargetedSkillDefaultPlugin.cs +++ b/src/GameLogic/PlayerActions/Skills/TargetedSkillDefaultPlugin.cs @@ -58,6 +58,12 @@ public override async ValueTask PerformSkillAsync(Player player, IAttackable tar return; } + if (attributes[Stats.IsAsleep] > 0) + { + player.Logger.LogWarning($"Probably Hacker - player {player} is attacking in asleep state"); + return; + } + var skillEntry = player.SkillList?.GetSkill(skillId); var skill = skillEntry?.Skill; if (skill is null || skill.SkillType == SkillType.PassiveBoost) diff --git a/src/Persistence/BasicModel/MagicEffectDefinition.Generated.cs b/src/Persistence/BasicModel/MagicEffectDefinition.Generated.cs index 74c97cdc1..f91b5a046 100644 --- a/src/Persistence/BasicModel/MagicEffectDefinition.Generated.cs +++ b/src/Persistence/BasicModel/MagicEffectDefinition.Generated.cs @@ -46,6 +46,63 @@ protected set } } + /// + /// Gets the raw collection of . + /// + [System.Text.Json.Serialization.JsonPropertyName("powerUpDefinitionsPvp")] + public ICollection RawPowerUpDefinitionsPvp { get; } = new List(); + + /// + [System.Text.Json.Serialization.JsonIgnore] + public override ICollection PowerUpDefinitionsPvp + { + get => base.PowerUpDefinitionsPvp ??= new CollectionAdapter(this.RawPowerUpDefinitionsPvp); + protected set + { + this.PowerUpDefinitionsPvp.Clear(); + foreach (var item in value) + { + this.PowerUpDefinitionsPvp.Add(item); + } + } + } + + /// + /// Gets the raw object of . + /// + [System.Text.Json.Serialization.JsonPropertyName("chance")] + public PowerUpDefinitionValue RawChance + { + get => base.Chance as PowerUpDefinitionValue; + set => base.Chance = value; + } + + /// + [System.Text.Json.Serialization.JsonIgnore] + public override MUnique.OpenMU.DataModel.Attributes.PowerUpDefinitionValue Chance + { + get => base.Chance; + set => base.Chance = value; + } + + /// + /// Gets the raw object of . + /// + [System.Text.Json.Serialization.JsonPropertyName("chancePvp")] + public PowerUpDefinitionValue RawChancePvp + { + get => base.ChancePvp as PowerUpDefinitionValue; + set => base.ChancePvp = value; + } + + /// + [System.Text.Json.Serialization.JsonIgnore] + public override MUnique.OpenMU.DataModel.Attributes.PowerUpDefinitionValue ChancePvp + { + get => base.ChancePvp; + set => base.ChancePvp = value; + } + /// /// Gets the raw object of . /// @@ -64,6 +121,24 @@ public override MUnique.OpenMU.DataModel.Attributes.PowerUpDefinitionValue Durat set => base.Duration = value; } + /// + /// Gets the raw object of . + /// + [System.Text.Json.Serialization.JsonPropertyName("durationPvp")] + public PowerUpDefinitionValue RawDurationPvp + { + get => base.DurationPvp as PowerUpDefinitionValue; + set => base.DurationPvp = value; + } + + /// + [System.Text.Json.Serialization.JsonIgnore] + public override MUnique.OpenMU.DataModel.Attributes.PowerUpDefinitionValue DurationPvp + { + get => base.DurationPvp; + set => base.DurationPvp = value; + } + /// public override MUnique.OpenMU.DataModel.Configuration.MagicEffectDefinition Clone(MUnique.OpenMU.DataModel.Configuration.GameConfiguration gameConfiguration) { diff --git a/src/Persistence/EntityFramework/Extensions/ModelBuilder/SkillExtensions.cs b/src/Persistence/EntityFramework/Extensions/ModelBuilder/SkillExtensions.cs index a3d588695..85ac56266 100644 --- a/src/Persistence/EntityFramework/Extensions/ModelBuilder/SkillExtensions.cs +++ b/src/Persistence/EntityFramework/Extensions/ModelBuilder/SkillExtensions.cs @@ -19,7 +19,11 @@ internal static class SkillExtensions public static void Apply(this EntityTypeBuilder builder) { builder.Ignore(s => s.PowerUps); + builder.Ignore(s => s.PowerUpsPvp); builder.Ignore(s => s.PowerUpDuration); + builder.Ignore(s => s.PowerUpDurationPvp); + builder.Ignore(s => s.PowerUpChance); + builder.Ignore(s => s.PowerUpChancePvp); builder.Ignore(s => s.Attributes); } diff --git a/src/Persistence/EntityFramework/Migrations/20251211145710_AddMagicEffectChanceAndOthers.Designer.cs b/src/Persistence/EntityFramework/Migrations/20251211145710_AddMagicEffectChanceAndOthers.Designer.cs new file mode 100644 index 000000000..72a886110 --- /dev/null +++ b/src/Persistence/EntityFramework/Migrations/20251211145710_AddMagicEffectChanceAndOthers.Designer.cs @@ -0,0 +1,5176 @@ +// +using System; +using MUnique.OpenMU.Persistence.EntityFramework; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MUnique.OpenMU.Persistence.EntityFramework.Migrations +{ + [DbContext(typeof(EntityDataContext))] + [Migration("20251211145710_AddMagicEffectChanceAndOthers")] + partial class AddMagicEffectChanceAndOthers + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChatBanUntil") + .HasColumnType("timestamp with time zone"); + + b.Property("EMail") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsTemplate") + .HasColumnType("boolean"); + + b.Property("IsVaultExtended") + .HasColumnType("boolean"); + + b.Property("LoginName") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegistrationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("TimeZone") + .HasColumnType("smallint"); + + b.Property("VaultId") + .HasColumnType("uuid"); + + b.Property("VaultPassword") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("LoginName") + .IsUnique(); + + b.HasIndex("VaultId") + .IsUnique(); + + b.ToTable("Account", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AccountCharacterClass", b => + { + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("AccountId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("AccountCharacterClass", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("FullAncientSetEquipped") + .HasColumnType("boolean"); + + b.Property("Pose") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("AppearanceData", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AreaSkillSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DelayBetweenHits") + .HasColumnType("interval"); + + b.Property("DelayPerOneDistance") + .HasColumnType("interval"); + + b.Property("FrustumDistance") + .HasColumnType("real"); + + b.Property("FrustumEndWidth") + .HasColumnType("real"); + + b.Property("FrustumStartWidth") + .HasColumnType("real"); + + b.Property("HitChancePerDistanceMultiplier") + .HasColumnType("real"); + + b.Property("MaximumNumberOfHitsPerAttack") + .HasColumnType("integer"); + + b.Property("MaximumNumberOfHitsPerTarget") + .HasColumnType("integer"); + + b.Property("MinimumNumberOfHitsPerTarget") + .HasColumnType("integer"); + + b.Property("TargetAreaDiameter") + .HasColumnType("real"); + + b.Property("UseDeferredHits") + .HasColumnType("boolean"); + + b.Property("UseFrustumFilter") + .HasColumnType("boolean"); + + b.Property("UseTargetAreaFilter") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AreaSkillSettings", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Designation") + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MaximumValue") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("AttributeDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRelationship", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AggregateType") + .HasColumnType("integer"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("InputAttributeId") + .HasColumnType("uuid"); + + b.Property("InputOperand") + .HasColumnType("real"); + + b.Property("InputOperator") + .HasColumnType("integer"); + + b.Property("OperandAttributeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionValueId") + .HasColumnType("uuid"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.HasIndex("InputAttributeId"); + + b.HasIndex("OperandAttributeId"); + + b.HasIndex("PowerUpDefinitionValueId"); + + b.HasIndex("SkillId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("AttributeRelationship", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeId") + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("MinimumValue") + .HasColumnType("integer"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("SkillId1") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AttributeId"); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("SkillId"); + + b.HasIndex("SkillId1"); + + b.ToTable("AttributeRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GroundId") + .HasColumnType("uuid"); + + b.Property("LeftGoalId") + .HasColumnType("uuid"); + + b.Property("LeftTeamSpawnPointX") + .HasColumnType("smallint"); + + b.Property("LeftTeamSpawnPointY") + .HasColumnType("smallint"); + + b.Property("RightGoalId") + .HasColumnType("uuid"); + + b.Property("RightTeamSpawnPointX") + .HasColumnType("smallint"); + + b.Property("RightTeamSpawnPointY") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GroundId") + .IsUnique(); + + b.HasIndex("LeftGoalId") + .IsUnique(); + + b.HasIndex("RightGoalId") + .IsUnique(); + + b.ToTable("BattleZoneDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("CharacterSlot") + .HasColumnType("smallint"); + + b.Property("CharacterStatus") + .HasColumnType("integer"); + + b.Property("CreateDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CurrentMapId") + .HasColumnType("uuid"); + + b.Property("Experience") + .HasColumnType("bigint"); + + b.Property("InventoryExtensions") + .HasColumnType("integer"); + + b.Property("InventoryId") + .HasColumnType("uuid"); + + b.Property("IsStoreOpened") + .HasColumnType("boolean"); + + b.Property("KeyConfiguration") + .HasColumnType("bytea"); + + b.Property("LevelUpPoints") + .HasColumnType("integer"); + + b.Property("MasterExperience") + .HasColumnType("bigint"); + + b.Property("MasterLevelUpPoints") + .HasColumnType("integer"); + + b.Property("MuHelperConfiguration") + .HasColumnType("bytea"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("PlayerKillCount") + .HasColumnType("integer"); + + b.Property("Pose") + .HasColumnType("smallint"); + + b.Property("PositionX") + .HasColumnType("smallint"); + + b.Property("PositionY") + .HasColumnType("smallint"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("StateRemainingSeconds") + .HasColumnType("integer"); + + b.Property("StoreName") + .HasColumnType("text"); + + b.Property("UsedFruitPoints") + .HasColumnType("integer"); + + b.Property("UsedNegFruitPoints") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CharacterClassId"); + + b.HasIndex("CurrentMapId"); + + b.HasIndex("InventoryId") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Character", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CanGetCreated") + .HasColumnType("boolean"); + + b.Property("ComboDefinitionId") + .HasColumnType("uuid"); + + b.Property("CreationAllowedFlag") + .HasColumnType("smallint"); + + b.Property("FruitCalculation") + .HasColumnType("integer"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("HomeMapId") + .HasColumnType("uuid"); + + b.Property("IsMasterClass") + .HasColumnType("boolean"); + + b.Property("LevelRequirementByCreation") + .HasColumnType("smallint"); + + b.Property("LevelWarpRequirementReductionPercent") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("NextGenerationClassId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ComboDefinitionId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("HomeMapId"); + + b.HasIndex("NextGenerationClassId"); + + b.ToTable("CharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterDropItemGroup", b => + { + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.HasKey("CharacterId", "DropItemGroupId"); + + b.HasIndex("DropItemGroupId"); + + b.ToTable("CharacterDropItemGroup", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActiveQuestId") + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("ClientActionPerformed") + .HasColumnType("boolean"); + + b.Property("Group") + .HasColumnType("smallint"); + + b.Property("LastFinishedQuestId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ActiveQuestId"); + + b.HasIndex("CharacterId"); + + b.HasIndex("LastFinishedQuestId"); + + b.ToTable("CharacterQuestState", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientCleanUpInterval") + .HasColumnType("interval"); + + b.Property("ClientTimeout") + .HasColumnType("interval"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("MaximumConnections") + .HasColumnType("integer"); + + b.Property("RoomCleanUpInterval") + .HasColumnType("interval"); + + b.Property("ServerId") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("ChatServerDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerEndpoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChatServerDefinitionId") + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("NetworkPort") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ChatServerDefinitionId"); + + b.HasIndex("ClientId"); + + b.ToTable("ChatServerEndpoint", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CombinationBonusRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemOptionCombinationBonusId") + .HasColumnType("uuid"); + + b.Property("MinimumCount") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemOptionCombinationBonusId"); + + b.HasIndex("OptionTypeId"); + + b.ToTable("CombinationBonusRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConfigurationUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("InstalledAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ConfigurationUpdate", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConfigurationUpdateState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrentInstalledVersion") + .HasColumnType("integer"); + + b.Property("InitializationKey") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("ConfigurationUpdateState", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConnectServerDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CheckMaxConnectionsPerAddress") + .HasColumnType("boolean"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("ClientListenerPort") + .HasColumnType("integer"); + + b.Property("CurrentPatchVersion") + .HasColumnType("bytea"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("DisconnectOnUnknownPacket") + .HasColumnType("boolean"); + + b.Property("ListenerBacklog") + .HasColumnType("integer"); + + b.Property("MaxConnections") + .HasColumnType("integer"); + + b.Property("MaxConnectionsPerAddress") + .HasColumnType("integer"); + + b.Property("MaxFtpRequests") + .HasColumnType("integer"); + + b.Property("MaxIpRequests") + .HasColumnType("integer"); + + b.Property("MaxServerListRequests") + .HasColumnType("integer"); + + b.Property("MaximumReceiveSize") + .HasColumnType("smallint"); + + b.Property("PatchAddress") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServerId") + .HasColumnType("smallint"); + + b.Property("Timeout") + .HasColumnType("interval"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ConnectServerDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConstValueAttribute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("ConstValueAttribute", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Chance") + .HasColumnType("double precision"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("ItemLevel") + .HasColumnType("smallint"); + + b.Property("ItemType") + .HasColumnType("integer"); + + b.Property("MaximumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MinimumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MonsterId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MonsterId"); + + b.ToTable("DropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroupItemDefinition", b => + { + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("DropItemGroupId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("DropItemGroupItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DuelArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DuelConfigurationId") + .HasColumnType("uuid"); + + b.Property("FirstPlayerGateId") + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("smallint"); + + b.Property("SecondPlayerGateId") + .HasColumnType("uuid"); + + b.Property("SpectatorsGateId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DuelConfigurationId"); + + b.HasIndex("FirstPlayerGateId"); + + b.HasIndex("SecondPlayerGateId"); + + b.HasIndex("SpectatorsGateId"); + + b.ToTable("DuelArea", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DuelConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EntranceFee") + .HasColumnType("integer"); + + b.Property("ExitId") + .HasColumnType("uuid"); + + b.Property("MaximumScore") + .HasColumnType("integer"); + + b.Property("MaximumSpectatorsPerDuelRoom") + .HasColumnType("integer"); + + b.Property("MinimumCharacterLevel") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ExitId"); + + b.ToTable("DuelConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.EnterGate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("LevelRequirement") + .HasColumnType("smallint"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("TargetGateId") + .HasColumnType("uuid"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("TargetGateId"); + + b.ToTable("EnterGate", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Direction") + .HasColumnType("integer"); + + b.Property("IsSpawnGate") + .HasColumnType("boolean"); + + b.Property("MapId") + .HasColumnType("uuid"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("MapId"); + + b.ToTable("ExitGate", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Friend", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Accepted") + .HasColumnType("boolean"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("FriendId") + .HasColumnType("uuid"); + + b.Property("RequestOpen") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasAlternateKey("CharacterId", "FriendId"); + + b.ToTable("Friend", "friend"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Episode") + .HasColumnType("smallint"); + + b.Property("Language") + .HasColumnType("integer"); + + b.Property("Season") + .HasColumnType("smallint"); + + b.Property("Serial") + .HasColumnType("bytea"); + + b.Property("Version") + .HasColumnType("bytea"); + + b.HasKey("Id"); + + b.ToTable("GameClientDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AreaSkillHitsPlayer") + .HasColumnType("boolean"); + + b.Property("CharacterNameRegex") + .HasColumnType("text"); + + b.Property("ClampMoneyOnPickup") + .HasColumnType("boolean"); + + b.Property("DamagePerOneItemDurability") + .HasColumnType("double precision"); + + b.Property("DamagePerOnePetDurability") + .HasColumnType("double precision"); + + b.Property("DuelConfigurationId") + .HasColumnType("uuid"); + + b.Property("ExperienceFormula") + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasDefaultValue("if(level == 0, 0, if(level < 256, 10 * (level + 8) * (level - 1) * (level - 1), (10 * (level + 8) * (level - 1) * (level - 1)) + (1000 * (level - 247) * (level - 256) * (level - 256))))"); + + b.Property("ExperienceRate") + .HasColumnType("real"); + + b.Property("HitsPerOneItemDurability") + .HasColumnType("double precision"); + + b.Property("InfoRange") + .HasColumnType("smallint"); + + b.Property("ItemDropDuration") + .ValueGeneratedOnAdd() + .HasColumnType("interval") + .HasDefaultValue(new TimeSpan(0, 0, 1, 0, 0)); + + b.Property("LetterSendPrice") + .HasColumnType("integer"); + + b.Property("MasterExperienceFormula") + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasDefaultValue("(505 * level * level * level) + (35278500 * level) + (228045 * level * level)"); + + b.Property("MaximumCharactersPerAccount") + .HasColumnType("smallint"); + + b.Property("MaximumInventoryMoney") + .HasColumnType("integer"); + + b.Property("MaximumItemOptionLevelDrop") + .HasColumnType("smallint"); + + b.Property("MaximumLetters") + .HasColumnType("integer"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MaximumMasterLevel") + .HasColumnType("smallint"); + + b.Property("MaximumPartySize") + .HasColumnType("smallint"); + + b.Property("MaximumPasswordLength") + .HasColumnType("integer"); + + b.Property("MaximumVaultMoney") + .HasColumnType("integer"); + + b.Property("MinimumMonsterLevelForMasterExperience") + .HasColumnType("smallint"); + + b.Property("PreventExperienceOverflow") + .HasColumnType("boolean"); + + b.Property("RecoveryInterval") + .HasColumnType("integer"); + + b.Property("ShouldDropMoney") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("DuelConfigurationId") + .IsUnique(); + + b.ToTable("GameConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BattleZoneId") + .HasColumnType("uuid"); + + b.Property("Discriminator") + .HasColumnType("integer"); + + b.Property("ExpMultiplier") + .HasColumnType("double precision"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SafezoneMapId") + .HasColumnType("uuid"); + + b.Property("TerrainData") + .HasColumnType("bytea"); + + b.HasKey("Id"); + + b.HasIndex("BattleZoneId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("SafezoneMapId"); + + b.ToTable("GameMapDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinitionDropItemGroup", b => + { + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.HasKey("GameMapDefinitionId", "DropItemGroupId"); + + b.HasIndex("DropItemGroupId"); + + b.ToTable("GameMapDefinitionDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumPlayers") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("GameServerConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfigurationGameMapDefinition", b => + { + b.Property("GameServerConfigurationId") + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("GameServerConfigurationId", "GameMapDefinitionId"); + + b.HasIndex("GameMapDefinitionId"); + + b.ToTable("GameServerConfigurationGameMapDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExperienceRate") + .HasColumnType("real"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("PvpEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("ServerConfigurationId") + .HasColumnType("uuid"); + + b.Property("ServerID") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("ServerConfigurationId"); + + b.ToTable("GameServerDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerEndpoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AlternativePublishedPort") + .HasColumnType("integer"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("GameServerDefinitionId") + .HasColumnType("uuid"); + + b.Property("NetworkPort") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.HasIndex("GameServerDefinitionId"); + + b.ToTable("GameServerEndpoint", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllianceGuildId") + .HasColumnType("uuid"); + + b.Property("HostilityId") + .HasColumnType("uuid"); + + b.Property("Logo") + .HasColumnType("bytea"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.Property("Notice") + .HasColumnType("text"); + + b.Property("Score") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AllianceGuildId"); + + b.HasIndex("HostilityId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Guild", "guild"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GuildMember", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("GuildId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GuildId"); + + b.ToTable("GuildMember", "guild"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemOptionDefinitionId") + .HasColumnType("uuid"); + + b.Property("LevelType") + .HasColumnType("integer"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.Property("Weight") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ItemOptionDefinitionId"); + + b.HasIndex("OptionTypeId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("IncreasableItemOption", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Durability") + .HasColumnType("double precision"); + + b.Property("HasSkill") + .HasColumnType("boolean"); + + b.Property("ItemSlot") + .HasColumnType("smallint"); + + b.Property("ItemStorageId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("smallint"); + + b.Property("PetExperience") + .HasColumnType("integer"); + + b.Property("SocketCount") + .HasColumnType("integer"); + + b.Property("StorePrice") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DefinitionId"); + + b.HasIndex("ItemStorageId"); + + b.ToTable("Item", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AppearanceDataId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSlot") + .HasColumnType("smallint"); + + b.Property("Level") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AppearanceDataId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("ItemAppearance", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearanceItemOptionType", b => + { + b.Property("ItemAppearanceId") + .HasColumnType("uuid"); + + b.Property("ItemOptionTypeId") + .HasColumnType("uuid"); + + b.HasKey("ItemAppearanceId", "ItemOptionTypeId"); + + b.HasIndex("ItemOptionTypeId"); + + b.ToTable("ItemAppearanceItemOptionType", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemBasePowerUpDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AggregateType") + .HasColumnType("integer"); + + b.Property("BaseValue") + .HasColumnType("real"); + + b.Property("BonusPerLevelTableId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BonusPerLevelTableId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("ItemBasePowerUpDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCrafting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemCraftingHandlerClassName") + .IsRequired() + .HasColumnType("text"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MonsterDefinitionId"); + + b.HasIndex("SimpleCraftingSettingsId") + .IsUnique(); + + b.ToTable("ItemCrafting", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddPercentage") + .HasColumnType("smallint"); + + b.Property("FailResult") + .HasColumnType("integer"); + + b.Property("MaximumAmount") + .HasColumnType("smallint"); + + b.Property("MaximumItemLevel") + .HasColumnType("smallint"); + + b.Property("MinimumAmount") + .HasColumnType("smallint"); + + b.Property("MinimumItemLevel") + .HasColumnType("smallint"); + + b.Property("NpcPriceDivisor") + .HasColumnType("integer"); + + b.Property("Reference") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.Property("SuccessResult") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SimpleCraftingSettingsId"); + + b.ToTable("ItemCraftingRequiredItem", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemDefinition", b => + { + b.Property("ItemCraftingRequiredItemId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemCraftingRequiredItemId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("ItemCraftingRequiredItemItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemOptionType", b => + { + b.Property("ItemCraftingRequiredItemId") + .HasColumnType("uuid"); + + b.Property("ItemOptionTypeId") + .HasColumnType("uuid"); + + b.HasKey("ItemCraftingRequiredItemId", "ItemOptionTypeId"); + + b.HasIndex("ItemOptionTypeId"); + + b.ToTable("ItemCraftingRequiredItemItemOptionType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingResultItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddLevel") + .HasColumnType("smallint"); + + b.Property("Durability") + .HasColumnType("smallint"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("RandomMaximumLevel") + .HasColumnType("smallint"); + + b.Property("RandomMinimumLevel") + .HasColumnType("smallint"); + + b.Property("Reference") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("SimpleCraftingSettingsId"); + + b.ToTable("ItemCraftingResultItem", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConsumeEffectId") + .HasColumnType("uuid"); + + b.Property("DropLevel") + .HasColumnType("smallint"); + + b.Property("DropsFromMonsters") + .HasColumnType("boolean"); + + b.Property("Durability") + .HasColumnType("smallint"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Group") + .HasColumnType("smallint"); + + b.Property("Height") + .HasColumnType("smallint"); + + b.Property("IsAmmunition") + .HasColumnType("boolean"); + + b.Property("IsBoundToCharacter") + .HasColumnType("boolean"); + + b.Property("ItemSlotId") + .HasColumnType("uuid"); + + b.Property("MaximumItemLevel") + .HasColumnType("smallint"); + + b.Property("MaximumSockets") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("PetExperienceFormula") + .HasColumnType("text"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("StorageLimitPerCharacter") + .HasColumnType("integer"); + + b.Property("Value") + .HasColumnType("integer"); + + b.Property("Width") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ConsumeEffectId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("ItemSlotId"); + + b.HasIndex("SkillId"); + + b.ToTable("ItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionCharacterClass", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("ItemDefinitionCharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemOptionDefinition", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemOptionDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "ItemOptionDefinitionId"); + + b.HasIndex("ItemOptionDefinitionId"); + + b.ToTable("ItemDefinitionItemOptionDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemSetGroup", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSetGroupId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "ItemSetGroupId"); + + b.HasIndex("ItemSetGroupId"); + + b.ToTable("ItemDefinitionItemSetGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Chance") + .HasColumnType("double precision"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("DropEffect") + .HasColumnType("integer"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemLevel") + .HasColumnType("smallint"); + + b.Property("ItemType") + .HasColumnType("integer"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MaximumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MinimumLevel") + .HasColumnType("smallint"); + + b.Property("MinimumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MoneyAmount") + .HasColumnType("integer"); + + b.Property("MonsterId") + .HasColumnType("uuid"); + + b.Property("RequiredCharacterLevel") + .HasColumnType("smallint"); + + b.Property("SourceItemLevel") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("MonsterId"); + + b.ToTable("ItemDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroupItemDefinition", b => + { + b.Property("ItemDropItemGroupId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemDropItemGroupId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("ItemDropItemGroupItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemItemOfItemSet", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ItemOfItemSetId") + .HasColumnType("uuid"); + + b.HasKey("ItemId", "ItemOfItemSetId"); + + b.HasIndex("ItemOfItemSetId"); + + b.ToTable("ItemItemOfItemSet", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemLevelBonusTable", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOfItemSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AncientSetDiscriminator") + .HasColumnType("integer"); + + b.Property("BonusOptionId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSetGroupId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BonusOptionId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("ItemSetGroupId"); + + b.ToTable("ItemOfItemSet", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OptionTypeId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("ItemOption", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AppliesMultipleTimes") + .HasColumnType("boolean"); + + b.Property("BonusId") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("BonusId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionCombinationBonus", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddChance") + .HasColumnType("real"); + + b.Property("AddsRandomly") + .HasColumnType("boolean"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MaximumOptionsPerItem") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ItemOptionId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.HasIndex("ItemOptionId"); + + b.ToTable("ItemOptionLink", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionOfLevel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IncreasableItemOptionId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("RequiredItemLevel") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IncreasableItemOptionId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("ItemOptionOfLevel", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("IsVisible") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AlwaysApplies") + .HasColumnType("boolean"); + + b.Property("CountDistinct") + .HasColumnType("boolean"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MinimumItemCount") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OptionsId") + .HasColumnType("uuid"); + + b.Property("SetLevel") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("OptionsId"); + + b.ToTable("ItemSetGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("RawItemSlots") + .HasColumnType("text") + .HasColumnName("ItemSlots") + .HasAnnotation("Relational:JsonPropertyName", "itemSlots"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemSlotType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Money") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ItemStorage", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.JewelMix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MixedJewelId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SingleJewelId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MixedJewelId"); + + b.HasIndex("SingleJewelId"); + + b.ToTable("JewelMix", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterBody", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Animation") + .HasColumnType("smallint"); + + b.Property("HeaderId") + .HasColumnType("uuid"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("Rotation") + .HasColumnType("smallint"); + + b.Property("SenderAppearanceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("HeaderId"); + + b.HasIndex("SenderAppearanceId") + .IsUnique(); + + b.ToTable("LetterBody", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("LetterDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ReadFlag") + .HasColumnType("boolean"); + + b.Property("ReceiverId") + .HasColumnType("uuid"); + + b.Property("SenderName") + .HasColumnType("text"); + + b.Property("Subject") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ReceiverId"); + + b.ToTable("LetterHeader", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LevelBonus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdditionalValue") + .HasColumnType("real"); + + b.Property("ItemLevelBonusTableId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemLevelBonusTableId"); + + b.ToTable("LevelBonus", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChanceId") + .HasColumnType("uuid"); + + b.Property("ChancePvpId") + .HasColumnType("uuid"); + + b.Property("DurationDependsOnTargetLevel") + .HasColumnType("boolean"); + + b.Property("DurationId") + .HasColumnType("uuid"); + + b.Property("DurationPvpId") + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("InformObservers") + .HasColumnType("boolean"); + + b.Property("MonsterTargetLevelDivisor") + .HasColumnType("real"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("PlayerTargetLevelDivisor") + .HasColumnType("real"); + + b.Property("SendDuration") + .HasColumnType("boolean"); + + b.Property("StopByDeath") + .HasColumnType("boolean"); + + b.Property("SubType") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ChanceId") + .IsUnique(); + + b.HasIndex("ChancePvpId") + .IsUnique(); + + b.HasIndex("DurationId") + .IsUnique(); + + b.HasIndex("DurationPvpId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("MagicEffectDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Aggregation") + .HasColumnType("integer"); + + b.Property("DisplayValueFormula") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExtendsDuration") + .HasColumnType("boolean"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MinimumLevel") + .HasColumnType("smallint"); + + b.Property("Rank") + .HasColumnType("smallint"); + + b.Property("ReplacedSkillId") + .HasColumnType("uuid"); + + b.Property("RootId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.Property("ValueFormula") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ReplacedSkillId"); + + b.HasIndex("RootId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("MasterSkillDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinitionSkill", b => + { + b.Property("MasterSkillDefinitionId") + .HasColumnType("uuid"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("MasterSkillDefinitionId", "SkillId"); + + b.HasIndex("SkillId"); + + b.ToTable("MasterSkillDefinitionSkill", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillRoot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("MasterSkillRoot", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("MiniGameDefinitionId") + .HasColumnType("uuid"); + + b.Property("MinimumTargetLevel") + .HasColumnType("smallint"); + + b.Property("MultiplyKillsByPlayers") + .HasColumnType("boolean"); + + b.Property("NumberOfKills") + .HasColumnType("smallint"); + + b.Property("SpawnAreaId") + .HasColumnType("uuid"); + + b.Property("Target") + .HasColumnType("integer"); + + b.Property("TargetDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MiniGameDefinitionId"); + + b.HasIndex("SpawnAreaId") + .IsUnique(); + + b.HasIndex("TargetDefinitionId"); + + b.ToTable("MiniGameChangeEvent", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowParty") + .HasColumnType("boolean"); + + b.Property("ArePlayerKillersAllowedToEnter") + .HasColumnType("boolean"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EnterDuration") + .HasColumnType("interval"); + + b.Property("EntranceFee") + .HasColumnType("integer"); + + b.Property("EntranceId") + .HasColumnType("uuid"); + + b.Property("ExitDuration") + .HasColumnType("interval"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("GameDuration") + .HasColumnType("interval"); + + b.Property("GameLevel") + .HasColumnType("smallint"); + + b.Property("MapCreationPolicy") + .HasColumnType("integer"); + + b.Property("MaximumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MaximumPlayerCount") + .HasColumnType("integer"); + + b.Property("MaximumSpecialCharacterLevel") + .HasColumnType("integer"); + + b.Property("MinimumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MinimumSpecialCharacterLevel") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequiresMasterClass") + .HasColumnType("boolean"); + + b.Property("SaveRankingStatistics") + .HasColumnType("boolean"); + + b.Property("TicketItemId") + .HasColumnType("uuid"); + + b.Property("TicketItemLevel") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EntranceId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("TicketItemId"); + + b.ToTable("MiniGameDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameRankingEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("GameInstanceId") + .HasColumnType("uuid"); + + b.Property("MiniGameId") + .HasColumnType("uuid"); + + b.Property("Rank") + .HasColumnType("integer"); + + b.Property("Score") + .HasColumnType("integer"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CharacterId"); + + b.HasIndex("MiniGameId"); + + b.ToTable("MiniGameRankingEntry", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemRewardId") + .HasColumnType("uuid"); + + b.Property("MiniGameDefinitionId") + .HasColumnType("uuid"); + + b.Property("Rank") + .HasColumnType("integer"); + + b.Property("RequiredKillId") + .HasColumnType("uuid"); + + b.Property("RequiredSuccess") + .HasColumnType("integer"); + + b.Property("RewardAmount") + .HasColumnType("integer"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemRewardId"); + + b.HasIndex("MiniGameDefinitionId"); + + b.HasIndex("RequiredKillId"); + + b.ToTable("MiniGameReward", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameSpawnWave", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EndTime") + .HasColumnType("interval"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("MiniGameDefinitionId") + .HasColumnType("uuid"); + + b.Property("StartTime") + .HasColumnType("interval"); + + b.Property("WaveNumber") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("MiniGameDefinitionId"); + + b.ToTable("MiniGameSpawnWave", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameTerrainChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EndX") + .HasColumnType("smallint"); + + b.Property("EndY") + .HasColumnType("smallint"); + + b.Property("IsClientUpdateRequired") + .HasColumnType("boolean"); + + b.Property("MiniGameChangeEventId") + .HasColumnType("uuid"); + + b.Property("SetTerrainAttribute") + .HasColumnType("boolean"); + + b.Property("StartX") + .HasColumnType("smallint"); + + b.Property("StartY") + .HasColumnType("smallint"); + + b.Property("TerrainAttribute") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("MiniGameChangeEventId"); + + b.ToTable("MiniGameTerrainChange", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterAttribute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeDefinitionId") + .HasColumnType("uuid"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("AttributeDefinitionId"); + + b.HasIndex("MonsterDefinitionId"); + + b.ToTable("MonsterAttribute", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttackDelay") + .HasColumnType("interval"); + + b.Property("AttackRange") + .HasColumnType("smallint"); + + b.Property("AttackSkillId") + .HasColumnType("uuid"); + + b.Property("Attribute") + .HasColumnType("smallint"); + + b.Property("Designation") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("IntelligenceTypeName") + .HasColumnType("text"); + + b.Property("MerchantStoreId") + .HasColumnType("uuid"); + + b.Property("MoveDelay") + .HasColumnType("interval"); + + b.Property("MoveRange") + .HasColumnType("smallint"); + + b.Property("NpcWindow") + .HasColumnType("integer"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("NumberOfMaximumItemDrops") + .HasColumnType("integer"); + + b.Property("ObjectKind") + .HasColumnType("integer"); + + b.Property("RespawnDelay") + .HasColumnType("interval"); + + b.Property("ViewRange") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AttackSkillId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MerchantStoreId") + .IsUnique(); + + b.ToTable("MonsterDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinitionDropItemGroup", b => + { + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.HasKey("MonsterDefinitionId", "DropItemGroupId"); + + b.HasIndex("DropItemGroupId"); + + b.ToTable("MonsterDefinitionDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterSpawnArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Direction") + .HasColumnType("integer"); + + b.Property("GameMapId") + .HasColumnType("uuid"); + + b.Property("MaximumHealthOverride") + .HasColumnType("integer"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Quantity") + .HasColumnType("smallint"); + + b.Property("SpawnTrigger") + .HasColumnType("integer"); + + b.Property("WaveNumber") + .HasColumnType("smallint"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GameMapId"); + + b.HasIndex("MonsterDefinitionId"); + + b.ToTable("MonsterSpawnArea", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PlugInConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CustomConfiguration") + .HasColumnType("text"); + + b.Property("CustomPlugInSource") + .HasColumnType("text"); + + b.Property("ExternalAssemblyName") + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("TypeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("PlugInConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BoostId") + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("MagicEffectDefinitionId") + .HasColumnType("uuid"); + + b.Property("MagicEffectDefinitionId1") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BoostId") + .IsUnique(); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("MagicEffectDefinitionId"); + + b.HasIndex("MagicEffectDefinitionId1"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("PowerUpDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AggregateType") + .HasColumnType("integer"); + + b.Property("MaximumValue") + .HasColumnType("real"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.ToTable("PowerUpDefinitionValue", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Group") + .HasColumnType("smallint"); + + b.Property("MaximumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MinimumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("QualifiedCharacterId") + .HasColumnType("uuid"); + + b.Property("QuestGiverId") + .HasColumnType("uuid"); + + b.Property("RefuseNumber") + .HasColumnType("smallint"); + + b.Property("Repeatable") + .HasColumnType("boolean"); + + b.Property("RequiredStartMoney") + .HasColumnType("integer"); + + b.Property("RequiresClientAction") + .HasColumnType("boolean"); + + b.Property("StartingNumber") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("MonsterDefinitionId"); + + b.HasIndex("QualifiedCharacterId"); + + b.HasIndex("QuestGiverId"); + + b.ToTable("QuestDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestItemRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("MinimumNumber") + .HasColumnType("integer"); + + b.Property("QuestDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DropItemGroupId"); + + b.HasIndex("ItemId"); + + b.HasIndex("QuestDefinitionId"); + + b.ToTable("QuestItemRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MinimumNumber") + .HasColumnType("integer"); + + b.Property("MonsterId") + .HasColumnType("uuid"); + + b.Property("QuestDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MonsterId"); + + b.HasIndex("QuestDefinitionId"); + + b.ToTable("QuestMonsterKillRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirementState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterQuestStateId") + .HasColumnType("uuid"); + + b.Property("KillCount") + .HasColumnType("integer"); + + b.Property("RequirementId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterQuestStateId"); + + b.HasIndex("RequirementId"); + + b.ToTable("QuestMonsterKillRequirementState", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeRewardId") + .HasColumnType("uuid"); + + b.Property("ItemRewardId") + .HasColumnType("uuid"); + + b.Property("QuestDefinitionId") + .HasColumnType("uuid"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.Property("SkillRewardId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AttributeRewardId"); + + b.HasIndex("ItemRewardId") + .IsUnique(); + + b.HasIndex("QuestDefinitionId"); + + b.HasIndex("SkillRewardId"); + + b.ToTable("QuestReward", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("Rectangle", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumSuccessPercent") + .HasColumnType("smallint"); + + b.Property("Money") + .HasColumnType("integer"); + + b.Property("MoneyPerFinalSuccessPercentage") + .HasColumnType("integer"); + + b.Property("MultipleAllowed") + .HasColumnType("boolean"); + + b.Property("NpcPriceDivisor") + .HasColumnType("integer"); + + b.Property("ResultItemExcellentOptionChance") + .HasColumnType("smallint"); + + b.Property("ResultItemLuckOptionChance") + .HasColumnType("smallint"); + + b.Property("ResultItemMaxExcOptionCount") + .HasColumnType("smallint"); + + b.Property("ResultItemSelect") + .HasColumnType("integer"); + + b.Property("ResultItemSkillChance") + .HasColumnType("smallint"); + + b.Property("SuccessPercent") + .HasColumnType("smallint"); + + b.Property("SuccessPercentageAdditionForAncientItem") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForExcellentItem") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForGuardianItem") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForLuck") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForSocketItem") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("SimpleCraftingSettings", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AreaSkillSettingsId") + .HasColumnType("uuid"); + + b.Property("AttackDamage") + .HasColumnType("integer"); + + b.Property("DamageType") + .HasColumnType("integer"); + + b.Property("ElementalModifierTargetId") + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("ImplicitTargetRange") + .HasColumnType("smallint"); + + b.Property("MagicEffectDefId") + .HasColumnType("uuid"); + + b.Property("MasterDefinitionId") + .HasColumnType("uuid"); + + b.Property("MovesTarget") + .HasColumnType("boolean"); + + b.Property("MovesToTarget") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("Range") + .HasColumnType("smallint"); + + b.Property("SkillType") + .HasColumnType("integer"); + + b.Property("Target") + .HasColumnType("integer"); + + b.Property("TargetRestriction") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AreaSkillSettingsId") + .IsUnique(); + + b.HasIndex("ElementalModifierTargetId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MagicEffectDefId"); + + b.HasIndex("MasterDefinitionId") + .IsUnique(); + + b.ToTable("Skill", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillCharacterClass", b => + { + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("SkillId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("SkillCharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumCompletionTime") + .HasColumnType("interval"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("SkillComboDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsFinalStep") + .HasColumnType("boolean"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("SkillComboDefinitionId") + .HasColumnType("uuid"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SkillComboDefinitionId"); + + b.HasIndex("SkillId"); + + b.ToTable("SkillComboStep", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterId"); + + b.HasIndex("SkillId"); + + b.ToTable("SkillEntry", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttribute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CharacterId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("StatAttribute", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttributeDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeId") + .HasColumnType("uuid"); + + b.Property("BaseValue") + .HasColumnType("real"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("IncreasableByPlayer") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("AttributeId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("StatAttributeDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SystemConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AutoStart") + .HasColumnType("boolean"); + + b.Property("AutoUpdateSchema") + .HasColumnType("boolean"); + + b.Property("IpResolver") + .HasColumnType("integer"); + + b.Property("IpResolverParameter") + .HasColumnType("text"); + + b.Property("ReadConsoleInput") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("SystemConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.WarpInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Costs") + .HasColumnType("integer"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("GateId") + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("LevelRequirement") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("GateId"); + + b.ToTable("WarpInfo", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawVault") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", "VaultId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawVault"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AccountCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", "Account") + .WithMany("JoinedUnlockedCharacterClasses") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("CharacterClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawCharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId"); + + b.Navigation("RawCharacterClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawAttributes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRelationship", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", null) + .WithMany("RawAttributeCombinations") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawInputAttribute") + .WithMany() + .HasForeignKey("InputAttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawOperandAttribute") + .WithMany() + .HasForeignKey("OperandAttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", null) + .WithMany("RawRelatedValues") + .HasForeignKey("PowerUpDefinitionValueId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", null) + .WithMany("RawAttributeRelationships") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawInputAttribute"); + + b.Navigation("RawOperandAttribute"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttribute") + .WithMany() + .HasForeignKey("AttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawMapRequirements") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", null) + .WithMany("RawRequirements") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", null) + .WithMany("RawConsumeRequirements") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", null) + .WithMany("RawRequirements") + .HasForeignKey("SkillId1") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", "RawGround") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "GroundId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", "RawLeftGoal") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "LeftGoalId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", "RawRightGoal") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "RightGoalId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawGround"); + + b.Navigation("RawLeftGoal"); + + b.Navigation("RawRightGoal"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", null) + .WithMany("RawCharacters") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawCharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawCurrentMap") + .WithMany() + .HasForeignKey("CurrentMapId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawInventory") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "InventoryId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawCharacterClass"); + + b.Navigation("RawCurrentMap"); + + b.Navigation("RawInventory"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", "RawComboDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "ComboDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawCharacterClasses") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawHomeMap") + .WithMany() + .HasForeignKey("HomeMapId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawNextGenerationClass") + .WithMany() + .HasForeignKey("NextGenerationClassId"); + + b.Navigation("RawComboDefinition"); + + b.Navigation("RawHomeMap"); + + b.Navigation("RawNextGenerationClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "Character") + .WithMany("JoinedDropItemGroups") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Character"); + + b.Navigation("DropItemGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", "RawActiveQuest") + .WithMany() + .HasForeignKey("ActiveQuestId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawQuestStates") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", "RawLastFinishedQuest") + .WithMany() + .HasForeignKey("LastFinishedQuestId"); + + b.Navigation("RawActiveQuest"); + + b.Navigation("RawLastFinishedQuest"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerEndpoint", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerDefinition", null) + .WithMany("RawEndpoints") + .HasForeignKey("ChatServerDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", "RawClient") + .WithMany() + .HasForeignKey("ClientId"); + + b.Navigation("RawClient"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CombinationBonusRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", null) + .WithMany("RawRequirements") + .HasForeignKey("ItemOptionCombinationBonusId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "RawOptionType") + .WithMany() + .HasForeignKey("OptionTypeId"); + + b.Navigation("RawOptionType"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConnectServerDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", "RawClient") + .WithMany() + .HasForeignKey("ClientId"); + + b.Navigation("RawClient"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConstValueAttribute", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany("RawBaseAttributeValues") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.Navigation("CharacterClass"); + + b.Navigation("RawDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawDropItemGroups") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonster") + .WithMany() + .HasForeignKey("MonsterId"); + + b.Navigation("RawMonster"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroupItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany("JoinedPossibleItems") + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DropItemGroup"); + + b.Navigation("ItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DuelArea", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DuelConfiguration", null) + .WithMany("RawDuelAreas") + .HasForeignKey("DuelConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawFirstPlayerGate") + .WithMany() + .HasForeignKey("FirstPlayerGateId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawSecondPlayerGate") + .WithMany() + .HasForeignKey("SecondPlayerGateId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawSpectatorsGate") + .WithMany() + .HasForeignKey("SpectatorsGateId"); + + b.Navigation("RawFirstPlayerGate"); + + b.Navigation("RawSecondPlayerGate"); + + b.Navigation("RawSpectatorsGate"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DuelConfiguration", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawExit") + .WithMany() + .HasForeignKey("ExitId"); + + b.Navigation("RawExit"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.EnterGate", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawEnterGates") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawTargetGate") + .WithMany() + .HasForeignKey("TargetGateId"); + + b.Navigation("RawTargetGate"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawMap") + .WithMany("RawExitGates") + .HasForeignKey("MapId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawMap"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DuelConfiguration", "RawDuelConfiguration") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", "DuelConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawDuelConfiguration"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "RawBattleZone") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "BattleZoneId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMaps") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawSafezoneMap") + .WithMany() + .HasForeignKey("SafezoneMapId"); + + b.Navigation("RawBattleZone"); + + b.Navigation("RawSafezoneMap"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinitionDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "GameMapDefinition") + .WithMany("JoinedDropItemGroups") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DropItemGroup"); + + b.Navigation("GameMapDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfigurationGameMapDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "GameMapDefinition") + .WithMany() + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", "GameServerConfiguration") + .WithMany("JoinedMaps") + .HasForeignKey("GameServerConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GameMapDefinition"); + + b.Navigation("GameServerConfiguration"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", "RawGameConfiguration") + .WithMany() + .HasForeignKey("GameConfigurationId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", "RawServerConfiguration") + .WithMany() + .HasForeignKey("ServerConfigurationId"); + + b.Navigation("RawGameConfiguration"); + + b.Navigation("RawServerConfiguration"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerEndpoint", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", "RawClient") + .WithMany() + .HasForeignKey("ClientId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", null) + .WithMany("RawEndpoints") + .HasForeignKey("GameServerDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawClient"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", "RawAllianceGuild") + .WithMany() + .HasForeignKey("AllianceGuildId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", "RawHostility") + .WithMany() + .HasForeignKey("HostilityId"); + + b.Navigation("RawAllianceGuild"); + + b.Navigation("RawHostility"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GuildMember", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", null) + .WithMany("RawMembers") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "Character") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Character"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", null) + .WithMany("RawPossibleOptions") + .HasForeignKey("ItemOptionDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "RawOptionType") + .WithMany() + .HasForeignKey("OptionTypeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawPowerUpDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", "PowerUpDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawOptionType"); + + b.Navigation("RawPowerUpDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawItemStorage") + .WithMany("RawItems") + .HasForeignKey("ItemStorageId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawDefinition"); + + b.Navigation("RawItemStorage"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", null) + .WithMany("RawEquippedItems") + .HasForeignKey("AppearanceDataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.Navigation("RawDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearanceItemOptionType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", "ItemAppearance") + .WithMany("JoinedVisibleOptions") + .HasForeignKey("ItemAppearanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "ItemOptionType") + .WithMany() + .HasForeignKey("ItemOptionTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemAppearance"); + + b.Navigation("ItemOptionType"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemBasePowerUpDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", "RawBonusPerLevelTable") + .WithMany() + .HasForeignKey("BonusPerLevelTableId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", null) + .WithMany("RawBasePowerUpAttributes") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawBonusPerLevelTable"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCrafting", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", null) + .WithMany("RawItemCraftings") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", "RawSimpleCraftingSettings") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCrafting", "SimpleCraftingSettingsId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawSimpleCraftingSettings"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", null) + .WithMany("RawRequiredItems") + .HasForeignKey("SimpleCraftingSettingsId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", "ItemCraftingRequiredItem") + .WithMany("JoinedPossibleItems") + .HasForeignKey("ItemCraftingRequiredItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemCraftingRequiredItem"); + + b.Navigation("ItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemOptionType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", "ItemCraftingRequiredItem") + .WithMany("JoinedRequiredItemOptions") + .HasForeignKey("ItemCraftingRequiredItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "ItemOptionType") + .WithMany() + .HasForeignKey("ItemOptionTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemCraftingRequiredItem"); + + b.Navigation("ItemOptionType"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingResultItem", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", null) + .WithMany("RawResultItems") + .HasForeignKey("SimpleCraftingSettingsId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "RawConsumeEffect") + .WithMany() + .HasForeignKey("ConsumeEffectId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItems") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", "RawItemSlot") + .WithMany() + .HasForeignKey("ItemSlotId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawConsumeEffect"); + + b.Navigation("RawItemSlot"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany("JoinedQualifiedCharacters") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CharacterClass"); + + b.Navigation("ItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemOptionDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany("JoinedPossibleItemOptions") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", "ItemOptionDefinition") + .WithMany() + .HasForeignKey("ItemOptionDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemDefinition"); + + b.Navigation("ItemOptionDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemSetGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany("JoinedPossibleItemSetGroups") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", "ItemSetGroup") + .WithMany() + .HasForeignKey("ItemSetGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemDefinition"); + + b.Navigation("ItemSetGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", null) + .WithMany("RawDropItems") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonster") + .WithMany() + .HasForeignKey("MonsterId"); + + b.Navigation("RawMonster"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroupItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", "ItemDropItemGroup") + .WithMany("JoinedPossibleItems") + .HasForeignKey("ItemDropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemDefinition"); + + b.Navigation("ItemDropItemGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemItemOfItemSet", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", "Item") + .WithMany("JoinedItemSetGroups") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOfItemSet", "ItemOfItemSet") + .WithMany() + .HasForeignKey("ItemOfItemSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemOfItemSet"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemLevelBonusTables") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOfItemSet", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", "RawBonusOption") + .WithMany() + .HasForeignKey("BonusOptionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", "RawItemSetGroup") + .WithMany("RawItems") + .HasForeignKey("ItemSetGroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawBonusOption"); + + b.Navigation("RawItemDefinition"); + + b.Navigation("RawItemSetGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOption", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "RawOptionType") + .WithMany() + .HasForeignKey("OptionTypeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawPowerUpDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOption", "PowerUpDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawOptionType"); + + b.Navigation("RawPowerUpDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawBonus") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", "BonusId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemOptionCombinationBonuses") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawBonus"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemOptions") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionLink", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", null) + .WithMany("RawItemOptions") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", "RawItemOption") + .WithMany() + .HasForeignKey("ItemOptionId"); + + b.Navigation("RawItemOption"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionOfLevel", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", null) + .WithMany("RawLevelDependentOptions") + .HasForeignKey("IncreasableItemOptionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawPowerUpDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionOfLevel", "PowerUpDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawPowerUpDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemOptionTypes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemSetGroups") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", "RawOptions") + .WithMany() + .HasForeignKey("OptionsId"); + + b.Navigation("RawOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemSlotTypes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.JewelMix", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawJewelMixes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawMixedJewel") + .WithMany() + .HasForeignKey("MixedJewelId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawSingleJewel") + .WithMany() + .HasForeignKey("SingleJewelId"); + + b.Navigation("RawMixedJewel"); + + b.Navigation("RawSingleJewel"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterBody", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterHeader", "RawHeader") + .WithMany() + .HasForeignKey("HeaderId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", "RawSenderAppearance") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterBody", "SenderAppearanceId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawHeader"); + + b.Navigation("RawSenderAppearance"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterHeader", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "Receiver") + .WithMany("RawLetters") + .HasForeignKey("ReceiverId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Receiver"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LevelBonus", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", null) + .WithMany("RawBonusPerLevel") + .HasForeignKey("ItemLevelBonusTableId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawChance") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "ChanceId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawChancePvp") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "ChancePvpId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawDuration") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "DurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawDurationPvp") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "DurationPvpId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMagicEffects") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawChance"); + + b.Navigation("RawChancePvp"); + + b.Navigation("RawDuration"); + + b.Navigation("RawDurationPvp"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawReplacedSkill") + .WithMany() + .HasForeignKey("ReplacedSkillId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillRoot", "RawRoot") + .WithMany() + .HasForeignKey("RootId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawReplacedSkill"); + + b.Navigation("RawRoot"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinitionSkill", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", "MasterSkillDefinition") + .WithMany("JoinedRequiredMasterSkills") + .HasForeignKey("MasterSkillDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "Skill") + .WithMany() + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MasterSkillDefinition"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillRoot", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMasterSkillRoots") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", null) + .WithMany("RawChangeEvents") + .HasForeignKey("MiniGameDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterSpawnArea", "RawSpawnArea") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", "SpawnAreaId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawTargetDefinition") + .WithMany() + .HasForeignKey("TargetDefinitionId"); + + b.Navigation("RawSpawnArea"); + + b.Navigation("RawTargetDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawEntrance") + .WithMany() + .HasForeignKey("EntranceId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMiniGameDefinitions") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawTicketItem") + .WithMany() + .HasForeignKey("TicketItemId"); + + b.Navigation("RawEntrance"); + + b.Navigation("RawTicketItem"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameRankingEntry", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "RawCharacter") + .WithMany() + .HasForeignKey("CharacterId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", "RawMiniGame") + .WithMany() + .HasForeignKey("MiniGameId"); + + b.Navigation("RawCharacter"); + + b.Navigation("RawMiniGame"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameReward", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "RawItemReward") + .WithMany() + .HasForeignKey("ItemRewardId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", null) + .WithMany("RawRewards") + .HasForeignKey("MiniGameDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawRequiredKill") + .WithMany() + .HasForeignKey("RequiredKillId"); + + b.Navigation("RawItemReward"); + + b.Navigation("RawRequiredKill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameSpawnWave", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", null) + .WithMany("RawSpawnWaves") + .HasForeignKey("MiniGameDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameTerrainChange", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", null) + .WithMany("RawTerrainChanges") + .HasForeignKey("MiniGameChangeEventId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterAttribute", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttributeDefinition") + .WithMany() + .HasForeignKey("AttributeDefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", null) + .WithMany("RawAttributes") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttributeDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawAttackSkill") + .WithMany() + .HasForeignKey("AttackSkillId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMonsters") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawMerchantStore") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "MerchantStoreId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttackSkill"); + + b.Navigation("RawMerchantStore"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinitionDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "MonsterDefinition") + .WithMany("JoinedDropItemGroups") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DropItemGroup"); + + b.Navigation("MonsterDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterSpawnArea", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawGameMap") + .WithMany("RawMonsterSpawns") + .HasForeignKey("GameMapId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonsterDefinition") + .WithMany() + .HasForeignKey("MonsterDefinitionId"); + + b.Navigation("RawGameMap"); + + b.Navigation("RawMonsterDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PlugInConfiguration", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawPlugInConfigurations") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawBoost") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "BoostId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawCharacterPowerUpDefinitions") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", null) + .WithMany("RawPowerUpDefinitions") + .HasForeignKey("MagicEffectDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", null) + .WithMany("RawPowerUpDefinitionsPvp") + .HasForeignKey("MagicEffectDefinitionId1") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("FK_PowerUpDefinition_MagicEffectDefinition_MagicEffectDefinit~1"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawBoost"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", null) + .WithMany("RawQuests") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawQualifiedCharacter") + .WithMany() + .HasForeignKey("QualifiedCharacterId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawQuestGiver") + .WithMany() + .HasForeignKey("QuestGiverId"); + + b.Navigation("RawQualifiedCharacter"); + + b.Navigation("RawQuestGiver"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestItemRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "RawDropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawItem") + .WithMany() + .HasForeignKey("ItemId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", null) + .WithMany("RawRequiredItems") + .HasForeignKey("QuestDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawDropItemGroup"); + + b.Navigation("RawItem"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonster") + .WithMany() + .HasForeignKey("MonsterId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", null) + .WithMany("RawRequiredMonsterKills") + .HasForeignKey("QuestDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawMonster"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirementState", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", null) + .WithMany("RawRequirementStates") + .HasForeignKey("CharacterQuestStateId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirement", "RawRequirement") + .WithMany() + .HasForeignKey("RequirementId"); + + b.Navigation("RawRequirement"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestReward", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttributeReward") + .WithMany() + .HasForeignKey("AttributeRewardId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", "RawItemReward") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestReward", "ItemRewardId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", null) + .WithMany("RawRewards") + .HasForeignKey("QuestDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkillReward") + .WithMany() + .HasForeignKey("SkillRewardId"); + + b.Navigation("RawAttributeReward"); + + b.Navigation("RawItemReward"); + + b.Navigation("RawSkillReward"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AreaSkillSettings", "RawAreaSkillSettings") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "AreaSkillSettingsId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawElementalModifierTarget") + .WithMany() + .HasForeignKey("ElementalModifierTargetId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawSkills") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "RawMagicEffectDef") + .WithMany() + .HasForeignKey("MagicEffectDefId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", "RawMasterDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "MasterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAreaSkillSettings"); + + b.Navigation("RawElementalModifierTarget"); + + b.Navigation("RawMagicEffectDef"); + + b.Navigation("RawMasterDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "Skill") + .WithMany("JoinedQualifiedCharacters") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CharacterClass"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboStep", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", null) + .WithMany("RawSteps") + .HasForeignKey("SkillComboDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillEntry", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawLearnedSkills") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttribute", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", null) + .WithMany("RawAttributes") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawAttributes") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.Navigation("RawDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttributeDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttribute") + .WithMany() + .HasForeignKey("AttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", null) + .WithMany("RawStatAttributes") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.WarpInfo", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawWarpList") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawGate") + .WithMany() + .HasForeignKey("GateId"); + + b.Navigation("RawGate"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.Navigation("JoinedUnlockedCharacterClasses"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawCharacters"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.Navigation("RawEquippedItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawLearnedSkills"); + + b.Navigation("RawLetters"); + + b.Navigation("RawQuestStates"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", b => + { + b.Navigation("RawAttributeCombinations"); + + b.Navigation("RawBaseAttributeValues"); + + b.Navigation("RawStatAttributes"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", b => + { + b.Navigation("RawRequirementStates"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerDefinition", b => + { + b.Navigation("RawEndpoints"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", b => + { + b.Navigation("JoinedPossibleItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DuelConfiguration", b => + { + b.Navigation("RawDuelAreas"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", b => + { + b.Navigation("RawAttributes"); + + b.Navigation("RawCharacterClasses"); + + b.Navigation("RawDropItemGroups"); + + b.Navigation("RawItemLevelBonusTables"); + + b.Navigation("RawItemOptionCombinationBonuses"); + + b.Navigation("RawItemOptionTypes"); + + b.Navigation("RawItemOptions"); + + b.Navigation("RawItemSetGroups"); + + b.Navigation("RawItemSlotTypes"); + + b.Navigation("RawItems"); + + b.Navigation("RawJewelMixes"); + + b.Navigation("RawMagicEffects"); + + b.Navigation("RawMaps"); + + b.Navigation("RawMasterSkillRoots"); + + b.Navigation("RawMiniGameDefinitions"); + + b.Navigation("RawMonsters"); + + b.Navigation("RawPlugInConfigurations"); + + b.Navigation("RawSkills"); + + b.Navigation("RawWarpList"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawCharacterPowerUpDefinitions"); + + b.Navigation("RawEnterGates"); + + b.Navigation("RawExitGates"); + + b.Navigation("RawMapRequirements"); + + b.Navigation("RawMonsterSpawns"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", b => + { + b.Navigation("JoinedMaps"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.Navigation("RawEndpoints"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.Navigation("RawMembers"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.Navigation("RawLevelDependentOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.Navigation("JoinedItemSetGroups"); + + b.Navigation("RawItemOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.Navigation("JoinedVisibleOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.Navigation("JoinedPossibleItems"); + + b.Navigation("JoinedRequiredItemOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.Navigation("JoinedPossibleItemOptions"); + + b.Navigation("JoinedPossibleItemSetGroups"); + + b.Navigation("JoinedQualifiedCharacters"); + + b.Navigation("RawBasePowerUpAttributes"); + + b.Navigation("RawDropItems"); + + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.Navigation("JoinedPossibleItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.Navigation("RawBonusPerLevel"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.Navigation("RawPossibleOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.Navigation("RawItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", b => + { + b.Navigation("RawItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.Navigation("RawPowerUpDefinitions"); + + b.Navigation("RawPowerUpDefinitionsPvp"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => + { + b.Navigation("JoinedRequiredMasterSkills"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", b => + { + b.Navigation("RawTerrainChanges"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", b => + { + b.Navigation("RawChangeEvents"); + + b.Navigation("RawRewards"); + + b.Navigation("RawSpawnWaves"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawItemCraftings"); + + b.Navigation("RawQuests"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", b => + { + b.Navigation("RawRelatedValues"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", b => + { + b.Navigation("RawRequiredItems"); + + b.Navigation("RawRequiredMonsterKills"); + + b.Navigation("RawRewards"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", b => + { + b.Navigation("RawRequiredItems"); + + b.Navigation("RawResultItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", b => + { + b.Navigation("JoinedQualifiedCharacters"); + + b.Navigation("RawAttributeRelationships"); + + b.Navigation("RawConsumeRequirements"); + + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", b => + { + b.Navigation("RawSteps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Persistence/EntityFramework/Migrations/20251211145710_AddMagicEffectChanceAndOthers.cs b/src/Persistence/EntityFramework/Migrations/20251211145710_AddMagicEffectChanceAndOthers.cs new file mode 100644 index 000000000..f5cd08e42 --- /dev/null +++ b/src/Persistence/EntityFramework/Migrations/20251211145710_AddMagicEffectChanceAndOthers.cs @@ -0,0 +1,225 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MUnique.OpenMU.Persistence.EntityFramework.Migrations +{ + /// + public partial class AddMagicEffectChanceAndOthers : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "MaximumValue", + schema: "config", + table: "PowerUpDefinitionValue", + type: "real", + nullable: true); + + migrationBuilder.AddColumn( + name: "MagicEffectDefinitionId1", + schema: "config", + table: "PowerUpDefinition", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "ChanceId", + schema: "config", + table: "MagicEffectDefinition", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "ChancePvpId", + schema: "config", + table: "MagicEffectDefinition", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "DurationDependsOnTargetLevel", + schema: "config", + table: "MagicEffectDefinition", + type: "boolean", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "DurationPvpId", + schema: "config", + table: "MagicEffectDefinition", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "MonsterTargetLevelDivisor", + schema: "config", + table: "MagicEffectDefinition", + type: "real", + nullable: false, + defaultValue: 0f); + + migrationBuilder.AddColumn( + name: "PlayerTargetLevelDivisor", + schema: "config", + table: "MagicEffectDefinition", + type: "real", + nullable: false, + defaultValue: 0f); + + migrationBuilder.CreateIndex( + name: "IX_PowerUpDefinition_MagicEffectDefinitionId1", + schema: "config", + table: "PowerUpDefinition", + column: "MagicEffectDefinitionId1"); + + migrationBuilder.CreateIndex( + name: "IX_MagicEffectDefinition_ChanceId", + schema: "config", + table: "MagicEffectDefinition", + column: "ChanceId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_MagicEffectDefinition_ChancePvpId", + schema: "config", + table: "MagicEffectDefinition", + column: "ChancePvpId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_MagicEffectDefinition_DurationPvpId", + schema: "config", + table: "MagicEffectDefinition", + column: "DurationPvpId", + unique: true); + + migrationBuilder.AddForeignKey( + name: "FK_MagicEffectDefinition_PowerUpDefinitionValue_ChanceId", + schema: "config", + table: "MagicEffectDefinition", + column: "ChanceId", + principalSchema: "config", + principalTable: "PowerUpDefinitionValue", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_MagicEffectDefinition_PowerUpDefinitionValue_ChancePvpId", + schema: "config", + table: "MagicEffectDefinition", + column: "ChancePvpId", + principalSchema: "config", + principalTable: "PowerUpDefinitionValue", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_MagicEffectDefinition_PowerUpDefinitionValue_DurationPvpId", + schema: "config", + table: "MagicEffectDefinition", + column: "DurationPvpId", + principalSchema: "config", + principalTable: "PowerUpDefinitionValue", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_PowerUpDefinition_MagicEffectDefinition_MagicEffectDefinit~1", + schema: "config", + table: "PowerUpDefinition", + column: "MagicEffectDefinitionId1", + principalSchema: "config", + principalTable: "MagicEffectDefinition", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_MagicEffectDefinition_PowerUpDefinitionValue_ChanceId", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropForeignKey( + name: "FK_MagicEffectDefinition_PowerUpDefinitionValue_ChancePvpId", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropForeignKey( + name: "FK_MagicEffectDefinition_PowerUpDefinitionValue_DurationPvpId", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropForeignKey( + name: "FK_PowerUpDefinition_MagicEffectDefinition_MagicEffectDefinit~1", + schema: "config", + table: "PowerUpDefinition"); + + migrationBuilder.DropIndex( + name: "IX_PowerUpDefinition_MagicEffectDefinitionId1", + schema: "config", + table: "PowerUpDefinition"); + + migrationBuilder.DropIndex( + name: "IX_MagicEffectDefinition_ChanceId", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropIndex( + name: "IX_MagicEffectDefinition_ChancePvpId", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropIndex( + name: "IX_MagicEffectDefinition_DurationPvpId", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropColumn( + name: "MaximumValue", + schema: "config", + table: "PowerUpDefinitionValue"); + + migrationBuilder.DropColumn( + name: "MagicEffectDefinitionId1", + schema: "config", + table: "PowerUpDefinition"); + + migrationBuilder.DropColumn( + name: "ChanceId", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropColumn( + name: "ChancePvpId", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropColumn( + name: "DurationDependsOnTargetLevel", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropColumn( + name: "DurationPvpId", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropColumn( + name: "MonsterTargetLevelDivisor", + schema: "config", + table: "MagicEffectDefinition"); + + migrationBuilder.DropColumn( + name: "PlayerTargetLevelDivisor", + schema: "config", + table: "MagicEffectDefinition"); + } + } +} diff --git a/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs b/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs index 902947166..b04972c73 100644 --- a/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs +++ b/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs @@ -2214,15 +2214,30 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property("ChanceId") + .HasColumnType("uuid"); + + b.Property("ChancePvpId") + .HasColumnType("uuid"); + + b.Property("DurationDependsOnTargetLevel") + .HasColumnType("boolean"); + b.Property("DurationId") .HasColumnType("uuid"); + b.Property("DurationPvpId") + .HasColumnType("uuid"); + b.Property("GameConfigurationId") .HasColumnType("uuid"); b.Property("InformObservers") .HasColumnType("boolean"); + b.Property("MonsterTargetLevelDivisor") + .HasColumnType("real"); + b.Property("Name") .IsRequired() .HasColumnType("text"); @@ -2230,6 +2245,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Number") .HasColumnType("smallint"); + b.Property("PlayerTargetLevelDivisor") + .HasColumnType("real"); + b.Property("SendDuration") .HasColumnType("boolean"); @@ -2241,9 +2259,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); + b.HasIndex("ChanceId") + .IsUnique(); + + b.HasIndex("ChancePvpId") + .IsUnique(); + b.HasIndex("DurationId") .IsUnique(); + b.HasIndex("DurationPvpId") + .IsUnique(); + b.HasIndex("GameConfigurationId"); b.ToTable("MagicEffectDefinition", "config"); @@ -2805,6 +2832,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("MagicEffectDefinitionId") .HasColumnType("uuid"); + b.Property("MagicEffectDefinitionId1") + .HasColumnType("uuid"); + b.Property("TargetAttributeId") .HasColumnType("uuid"); @@ -2817,6 +2847,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("MagicEffectDefinitionId"); + b.HasIndex("MagicEffectDefinitionId1"); + b.HasIndex("TargetAttributeId"); b.ToTable("PowerUpDefinition", "config"); @@ -2831,6 +2863,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("AggregateType") .HasColumnType("integer"); + b.Property("MaximumValue") + .HasColumnType("real"); + b.Property("Value") .HasColumnType("real"); @@ -4356,17 +4391,38 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawChance") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "ChanceId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawChancePvp") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "ChancePvpId") + .OnDelete(DeleteBehavior.Cascade); + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawDuration") .WithOne() .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "DurationId") .OnDelete(DeleteBehavior.Cascade); + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawDurationPvp") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "DurationPvpId") + .OnDelete(DeleteBehavior.Cascade); + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) .WithMany("RawMagicEffects") .HasForeignKey("GameConfigurationId") .OnDelete(DeleteBehavior.Cascade); + b.Navigation("RawChance"); + + b.Navigation("RawChancePvp"); + b.Navigation("RawDuration"); + + b.Navigation("RawDurationPvp"); }); modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => @@ -4604,6 +4660,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("MagicEffectDefinitionId") .OnDelete(DeleteBehavior.Cascade); + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", null) + .WithMany("RawPowerUpDefinitionsPvp") + .HasForeignKey("MagicEffectDefinitionId1") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("FK_PowerUpDefinition_MagicEffectDefinition_MagicEffectDefinit~1"); + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") .WithMany() .HasForeignKey("TargetAttributeId"); @@ -5035,6 +5097,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => { b.Navigation("RawPowerUpDefinitions"); + + b.Navigation("RawPowerUpDefinitionsPvp"); }); modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => diff --git a/src/Persistence/EntityFramework/Model/ExtendedTypeContext.Generated.cs b/src/Persistence/EntityFramework/Model/ExtendedTypeContext.Generated.cs index fb9921ed0..88fc1437c 100644 --- a/src/Persistence/EntityFramework/Model/ExtendedTypeContext.Generated.cs +++ b/src/Persistence/EntityFramework/Model/ExtendedTypeContext.Generated.cs @@ -162,8 +162,12 @@ protected override void OnModelCreating(Microsoft.EntityFrameworkCore.ModelBuild modelBuilder.Entity().HasMany(entity => entity.RawMapRequirements).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasMany(entity => entity.RawCharacterPowerUpDefinitions).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasMany(entity => entity.RawEndpoints).WithOne().OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity().HasOne(entity => entity.RawChance).WithOne().OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity().HasOne(entity => entity.RawChancePvp).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasOne(entity => entity.RawDuration).WithOne().OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity().HasOne(entity => entity.RawDurationPvp).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasMany(entity => entity.RawPowerUpDefinitions).WithOne().OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity().HasMany(entity => entity.RawPowerUpDefinitionsPvp).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasOne(entity => entity.RawSpawnArea).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasMany(entity => entity.RawTerrainChanges).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasMany(entity => entity.RawRewards).WithOne().OnDelete(DeleteBehavior.Cascade); diff --git a/src/Persistence/EntityFramework/Model/MagicEffectDefinition.Generated.cs b/src/Persistence/EntityFramework/Model/MagicEffectDefinition.Generated.cs index 3ec14e756..fa20be3df 100644 --- a/src/Persistence/EntityFramework/Model/MagicEffectDefinition.Generated.cs +++ b/src/Persistence/EntityFramework/Model/MagicEffectDefinition.Generated.cs @@ -37,6 +37,67 @@ internal partial class MagicEffectDefinition : MUnique.OpenMU.DataModel.Configur [NotMapped] public override ICollection PowerUpDefinitions => base.PowerUpDefinitions ??= new CollectionAdapter(this.RawPowerUpDefinitions); + /// + /// Gets the raw collection of . + /// + public ICollection RawPowerUpDefinitionsPvp { get; } = new EntityFramework.List(); + + /// + [NotMapped] + public override ICollection PowerUpDefinitionsPvp => base.PowerUpDefinitionsPvp ??= new CollectionAdapter(this.RawPowerUpDefinitionsPvp); + + /// + /// Gets or sets the identifier of . + /// + public Guid? ChanceId { get; set; } + + /// + /// Gets the raw object of . + /// + [ForeignKey(nameof(ChanceId))] + public PowerUpDefinitionValue RawChance + { + get => base.Chance as PowerUpDefinitionValue; + set => base.Chance = value; + } + + /// + [NotMapped] + public override MUnique.OpenMU.DataModel.Attributes.PowerUpDefinitionValue Chance + { + get => base.Chance;set + { + base.Chance = value; + this.ChanceId = this.RawChance?.Id; + } + } + + /// + /// Gets or sets the identifier of . + /// + public Guid? ChancePvpId { get; set; } + + /// + /// Gets the raw object of . + /// + [ForeignKey(nameof(ChancePvpId))] + public PowerUpDefinitionValue RawChancePvp + { + get => base.ChancePvp as PowerUpDefinitionValue; + set => base.ChancePvp = value; + } + + /// + [NotMapped] + public override MUnique.OpenMU.DataModel.Attributes.PowerUpDefinitionValue ChancePvp + { + get => base.ChancePvp;set + { + base.ChancePvp = value; + this.ChancePvpId = this.RawChancePvp?.Id; + } + } + /// /// Gets or sets the identifier of . /// @@ -63,6 +124,32 @@ public override MUnique.OpenMU.DataModel.Attributes.PowerUpDefinitionValue Durat } } + /// + /// Gets or sets the identifier of . + /// + public Guid? DurationPvpId { get; set; } + + /// + /// Gets the raw object of . + /// + [ForeignKey(nameof(DurationPvpId))] + public PowerUpDefinitionValue RawDurationPvp + { + get => base.DurationPvp as PowerUpDefinitionValue; + set => base.DurationPvp = value; + } + + /// + [NotMapped] + public override MUnique.OpenMU.DataModel.Attributes.PowerUpDefinitionValue DurationPvp + { + get => base.DurationPvp;set + { + base.DurationPvp = value; + this.DurationPvpId = this.RawDurationPvp?.Id; + } + } + /// public override MUnique.OpenMU.DataModel.Configuration.MagicEffectDefinition Clone(MUnique.OpenMU.DataModel.Configuration.GameConfiguration gameConfiguration) { diff --git a/src/Persistence/Initialization/Items/ExcellentOptions.cs b/src/Persistence/Initialization/Items/ExcellentOptions.cs index bc05e0bdc..63b5cdba3 100644 --- a/src/Persistence/Initialization/Items/ExcellentOptions.cs +++ b/src/Persistence/Initialization/Items/ExcellentOptions.cs @@ -123,7 +123,7 @@ private void CreateDefenseOptions() definition.PossibleOptions.Add(this.CreateExcellentOption(1, Stats.MoneyAmountRate, 1.4f, AggregateType.Multiplicate, ItemOptionDefinitionNumbers.ExcellentDefense)); definition.PossibleOptions.Add(this.CreateExcellentOption(2, Stats.DefenseRatePvm, 1.1f, AggregateType.Multiplicate, ItemOptionDefinitionNumbers.ExcellentDefense)); - definition.PossibleOptions.Add(this.CreateExcellentOption(3, Stats.DamageReflection, 0.04f, AggregateType.AddRaw, ItemOptionDefinitionNumbers.ExcellentDefense)); + definition.PossibleOptions.Add(this.CreateExcellentOption(3, Stats.DamageReflection, 0.05f, AggregateType.AddRaw, ItemOptionDefinitionNumbers.ExcellentDefense)); definition.PossibleOptions.Add(this.CreateExcellentOption(4, Stats.ArmorDamageDecrease, 0.04f, AggregateType.AddRaw, ItemOptionDefinitionNumbers.ExcellentDefense)); definition.PossibleOptions.Add(this.CreateExcellentOption(5, Stats.MaximumMana, 1.04f, AggregateType.Multiplicate, ItemOptionDefinitionNumbers.ExcellentDefense)); definition.PossibleOptions.Add(this.CreateExcellentOption(6, Stats.MaximumHealth, 1.04f, AggregateType.Multiplicate, ItemOptionDefinitionNumbers.ExcellentDefense)); diff --git a/src/Persistence/Initialization/Skills/InnovationEffectInitializer.cs b/src/Persistence/Initialization/Skills/InnovationEffectInitializer.cs new file mode 100644 index 000000000..254a2ec3c --- /dev/null +++ b/src/Persistence/Initialization/Skills/InnovationEffectInitializer.cs @@ -0,0 +1,129 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.Skills; + +using MUnique.OpenMU.AttributeSystem; +using MUnique.OpenMU.DataModel.Attributes; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.GameLogic.Attributes; + +/// +/// Initializer for the innovation effect. +/// +public class InnovationEffectInitializer : InitializerBase +{ + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public InnovationEffectInitializer(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + public override void Initialize() + { + var magicEffect = this.Context.CreateNew(); + this.GameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (short)MagicEffectNumber.Innovation; + magicEffect.Name = "Innovation Effect"; + magicEffect.InformObservers = true; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = true; + magicEffect.DurationDependsOnTargetLevel = true; + magicEffect.MonsterTargetLevelDivisor = 20; + magicEffect.PlayerTargetLevelDivisor = 150; + + // Chance % = 32 + (Energy / 50) + (Book Rise / 6) + magicEffect.Chance = this.Context.CreateNew(); + magicEffect.Chance.ConstantValue.Value = 0.32f; // 32% + + var chancePerEnergy = this.Context.CreateNew(); + chancePerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + chancePerEnergy.InputOperator = InputOperator.Multiply; + chancePerEnergy.InputOperand = 1f / 5000f; // 50 energy adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerEnergy); + + var chancePerBookRise = this.Context.CreateNew(); + chancePerBookRise.InputAttribute = Stats.BookRise.GetPersistent(this.GameConfiguration); + chancePerBookRise.InputOperator = InputOperator.Multiply; + chancePerBookRise.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerBookRise); + + // Chance PvP % = 17 + (Energy / 50) + (Book Rise / 6) + magicEffect.ChancePvp = this.Context.CreateNew(); + magicEffect.ChancePvp.ConstantValue.Value = 0.17f; // 17% + + var chancePerEnergyPvp = this.Context.CreateNew(); + chancePerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + chancePerEnergyPvp.InputOperator = InputOperator.Multiply; + chancePerEnergyPvp.InputOperand = 1f / 5000f; // 50 energy adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerEnergyPvp); + + var chancePerBookRisePvp = this.Context.CreateNew(); + chancePerBookRisePvp.InputAttribute = Stats.BookRise.GetPersistent(this.GameConfiguration); + chancePerBookRisePvp.InputOperator = InputOperator.Multiply; + chancePerBookRisePvp.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerBookRisePvp); + + // Duration = 4 + (Energy / 100) + magicEffect.Duration = this.Context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 4; // 4 Seconds + magicEffect.Duration.MaximumValue = 44; // 44 Seconds (based on 4k total energy cap) + + var durationPerEnergy = this.Context.CreateNew(); + durationPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + durationPerEnergy.InputOperator = InputOperator.Multiply; + durationPerEnergy.InputOperand = 1f / 100f; // 100 energy adds 1s + magicEffect.Duration.RelatedValues.Add(durationPerEnergy); + + // Duration PvP = 5 + (Energy / 300) + ((Level - Target's Level) / 150) + magicEffect.DurationPvp = this.Context.CreateNew(); + magicEffect.DurationPvp.ConstantValue.Value = 5; // 5 Seconds + magicEffect.DurationPvp.MaximumValue = 18; // 18 Seconds (based on 4k total energy cap) + + var durationPerEnergyPvp = this.Context.CreateNew(); + durationPerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + durationPerEnergyPvp.InputOperator = InputOperator.Multiply; + durationPerEnergyPvp.InputOperand = 1f / 300f; // 300 energy adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerEnergyPvp); + + var durationPerLevelPvp = this.Context.CreateNew(); + durationPerLevelPvp.InputAttribute = Stats.Level.GetPersistent(this.GameConfiguration); + durationPerLevelPvp.InputOperator = InputOperator.Multiply; + durationPerLevelPvp.InputOperand = 1f / 150f; // 150 levels adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerLevelPvp); + + // Defense decrease % (applies last) = 20 + (Energy / 90) + var decDefPowerUpDefinition = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(decDefPowerUpDefinition); + decDefPowerUpDefinition.TargetAttribute = Stats.InnovationDefDecrement.GetPersistent(this.GameConfiguration); + decDefPowerUpDefinition.Boost = this.Context.CreateNew(); + decDefPowerUpDefinition.Boost.ConstantValue.Value = 0.20f; // 20% decrease + decDefPowerUpDefinition.Boost.MaximumValue = 0.64f; // 64% decrease (based on 4k total energy cap) + + var decDefPerEnergy = this.Context.CreateNew(); + decDefPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + decDefPerEnergy.InputOperator = InputOperator.Multiply; + decDefPerEnergy.InputOperand = 1f / 9000f; // 90 energy further decreases 1% + decDefPowerUpDefinition.Boost.RelatedValues.Add(decDefPerEnergy); + + // Defense decrease PvP % (applies last) = 12 + (Energy / 110) + var decDefPowerUpDefinitionPvp = this.Context.CreateNew(); + magicEffect.PowerUpDefinitionsPvp.Add(decDefPowerUpDefinitionPvp); + decDefPowerUpDefinitionPvp.TargetAttribute = Stats.InnovationDefDecrement.GetPersistent(this.GameConfiguration); + decDefPowerUpDefinitionPvp.Boost = this.Context.CreateNew(); + decDefPowerUpDefinitionPvp.Boost.ConstantValue.Value = 0.12f; // 12% decrease + decDefPowerUpDefinitionPvp.Boost.MaximumValue = 0.48f; // 48% decrease (based on 4k total energy cap) + + var decDefPerEnergyPvp = this.Context.CreateNew(); + decDefPerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + decDefPerEnergyPvp.InputOperator = InputOperator.Multiply; + decDefPerEnergyPvp.InputOperand = 1f / 11000f; // 110 energy further decreases 1% + decDefPowerUpDefinitionPvp.Boost.RelatedValues.Add(decDefPerEnergyPvp); + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Skills/MagicEffectNumber.cs b/src/Persistence/Initialization/Skills/MagicEffectNumber.cs index d5c0dca2e..28275b5b5 100644 --- a/src/Persistence/Initialization/Skills/MagicEffectNumber.cs +++ b/src/Persistence/Initialization/Skills/MagicEffectNumber.cs @@ -12,6 +12,14 @@ internal enum MagicEffectNumber : short { #region Artificial effects which don't end up as an actual magic effect, but regenerate something + /// + /// The Weakness (Summoner) skill effect number. + /// + /// + /// Internal. Proxy of . + /// + WeaknessSummoner = -4, + /// /// The shield recover skill effect number. /// @@ -236,10 +244,15 @@ internal enum MagicEffectNumber : short Blind = 0x49, /// - /// The weakness effect, which decreases the attacker's physical damage. + /// The weakness effect, which decreases the physical damage. /// Weakness = 0x4C, + /// + /// The innovation effect, which decreases the defense. + /// + Innovation = 0x4D, + /// /// The cherry blossom wine effect (+ 700 Mana). /// diff --git a/src/Persistence/Initialization/Skills/ReflectionEffectInitializer.cs b/src/Persistence/Initialization/Skills/ReflectionEffectInitializer.cs new file mode 100644 index 000000000..0cd51aa8d --- /dev/null +++ b/src/Persistence/Initialization/Skills/ReflectionEffectInitializer.cs @@ -0,0 +1,63 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.Skills; + +using MUnique.OpenMU.AttributeSystem; +using MUnique.OpenMU.DataModel.Attributes; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.GameLogic.Attributes; + +/// +/// Initializer for the reflection buff effect. +/// +public class ReflectionEffectInitializer : InitializerBase +{ + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public ReflectionEffectInitializer(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + public override void Initialize() + { + var magicEffect = this.Context.CreateNew(); + this.GameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (short)MagicEffectNumber.Reflection; + magicEffect.Name = "Reflection Effect"; + magicEffect.InformObservers = true; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = true; + + // Duration = 30 + (Energy / 24) + magicEffect.Duration = this.Context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 30; // 30 Seconds + magicEffect.Duration.MaximumValue = 180; + + var durationPerEnergy = this.Context.CreateNew(); + durationPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + durationPerEnergy.InputOperator = InputOperator.Multiply; + durationPerEnergy.InputOperand = 1f / 24; // 24 energy adds 1s + magicEffect.Duration.RelatedValues.Add(durationPerEnergy); + + // Reflection % = 30 + (Energy / 42) + var incReflectPowerUpDefinition = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(incReflectPowerUpDefinition); + incReflectPowerUpDefinition.TargetAttribute = Stats.DamageReflection.GetPersistent(this.GameConfiguration); + incReflectPowerUpDefinition.Boost = this.Context.CreateNew(); + incReflectPowerUpDefinition.Boost.ConstantValue.Value = 0.3f; // 30% increase + incReflectPowerUpDefinition.Boost.MaximumValue = 0.6f; // 60% increase + + var incReflectPerEnergy = this.Context.CreateNew(); + incReflectPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + incReflectPerEnergy.InputOperator = InputOperator.Multiply; + incReflectPerEnergy.InputOperand = 1f / 4200f; // 42 energy further increases 1% + incReflectPowerUpDefinition.Boost.RelatedValues.Add(incReflectPerEnergy); + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Skills/SleepEffectInitializer.cs b/src/Persistence/Initialization/Skills/SleepEffectInitializer.cs new file mode 100644 index 000000000..c75397351 --- /dev/null +++ b/src/Persistence/Initialization/Skills/SleepEffectInitializer.cs @@ -0,0 +1,107 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.Skills; + +using MUnique.OpenMU.AttributeSystem; +using MUnique.OpenMU.DataModel.Attributes; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.GameLogic.Attributes; + +/// +/// Initializer for the sleep effect. +/// +public class SleepEffectInitializer : InitializerBase +{ + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public SleepEffectInitializer(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + public override void Initialize() + { + var magicEffect = this.Context.CreateNew(); + this.GameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (short)MagicEffectNumber.Sleep; + magicEffect.Name = "Sleep Effect"; + magicEffect.InformObservers = true; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = true; + magicEffect.DurationDependsOnTargetLevel = true; + magicEffect.MonsterTargetLevelDivisor = 20; + magicEffect.PlayerTargetLevelDivisor = 100; + + // Chance % = 20 + (Energy / 30) + (Book Rise / 6) + magicEffect.Chance = this.Context.CreateNew(); + magicEffect.Chance.ConstantValue.Value = 0.2f; // 20% + + var chancePerEnergy = this.Context.CreateNew(); + chancePerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + chancePerEnergy.InputOperator = InputOperator.Multiply; + chancePerEnergy.InputOperand = 1f / 3000f; // 30 energy adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerEnergy); + + var chancePerBookRise = this.Context.CreateNew(); + chancePerBookRise.InputAttribute = Stats.BookRise.GetPersistent(this.GameConfiguration); + chancePerBookRise.InputOperator = InputOperator.Multiply; + chancePerBookRise.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerBookRise); + + // Chance PvP % = 15 + (Energy / 37) + (Book Rise / 6) + magicEffect.ChancePvp = this.Context.CreateNew(); + magicEffect.ChancePvp.ConstantValue.Value = 0.15f; // 15% + + var chancePerEnergyPvp = this.Context.CreateNew(); + chancePerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + chancePerEnergyPvp.InputOperator = InputOperator.Multiply; + chancePerEnergyPvp.InputOperand = 1f / 3700f; // 37 energy adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerEnergyPvp); + + var chancePerBookRisePvp = this.Context.CreateNew(); + chancePerBookRisePvp.InputAttribute = Stats.BookRise.GetPersistent(this.GameConfiguration); + chancePerBookRisePvp.InputOperator = InputOperator.Multiply; + chancePerBookRisePvp.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerBookRisePvp); + + // Duration = 5 + (Energy / 100) + magicEffect.Duration = this.Context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 5; // 5 Seconds + magicEffect.Duration.MaximumValue = 20; + + var durationPerEnergy = this.Context.CreateNew(); + durationPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + durationPerEnergy.InputOperator = InputOperator.Multiply; + durationPerEnergy.InputOperand = 1f / 100f; // 100 energy adds 1s + magicEffect.Duration.RelatedValues.Add(durationPerEnergy); + + // Duration = 4 + (Energy / 250) + ((Level - Target's Level) / 100) + magicEffect.DurationPvp = this.Context.CreateNew(); + magicEffect.DurationPvp.ConstantValue.Value = 4; // 4 Seconds + magicEffect.DurationPvp.MaximumValue = 10; + + var durationPerEnergyPvp = this.Context.CreateNew(); + durationPerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + durationPerEnergyPvp.InputOperator = InputOperator.Multiply; + durationPerEnergyPvp.InputOperand = 1f / 250f; // 250 energy adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerEnergyPvp); + + var durationPerLevelPvp = this.Context.CreateNew(); + durationPerLevelPvp.InputAttribute = Stats.Level.GetPersistent(this.GameConfiguration); + durationPerLevelPvp.InputOperator = InputOperator.Multiply; + durationPerLevelPvp.InputOperand = 1f / 100f; // 100 levels adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerLevelPvp); + + var isAsleep = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(isAsleep); + isAsleep.TargetAttribute = Stats.IsAsleep.GetPersistent(this.GameConfiguration); + isAsleep.Boost = this.Context.CreateNew(); + isAsleep.Boost.ConstantValue.Value = 1; + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Skills/WeaknessEffectInitializer.cs b/src/Persistence/Initialization/Skills/WeaknessEffectInitializer.cs index da97fc783..e9680766b 100644 --- a/src/Persistence/Initialization/Skills/WeaknessEffectInitializer.cs +++ b/src/Persistence/Initialization/Skills/WeaknessEffectInitializer.cs @@ -10,7 +10,7 @@ namespace MUnique.OpenMU.Persistence.Initialization.Skills; using MUnique.OpenMU.GameLogic.Attributes; /// -/// Initializer for the weakness effect, which can result from Killing Blow (RF) or Weakness (Sum) skills. +/// Initializer for the weakness effect which results from Killing Blow (RF) skill. /// public class WeaknessEffectInitializer : InitializerBase { @@ -30,14 +30,18 @@ public override void Initialize() var magicEffect = this.Context.CreateNew(); this.GameConfiguration.MagicEffects.Add(magicEffect); magicEffect.Number = (short)MagicEffectNumber.Weakness; - magicEffect.Name = "Weakness Effect"; + magicEffect.Name = "Weakness Effect (Killing Blow)"; magicEffect.InformObservers = true; magicEffect.SendDuration = false; magicEffect.StopByDeath = true; magicEffect.Duration = this.Context.CreateNew(); magicEffect.Duration.ConstantValue.Value = 10; // 10 seconds - // Target's physical damage decreases by 5% + // Chance to apply the effect + magicEffect.Chance = this.Context.CreateNew(); + magicEffect.Chance.ConstantValue.Value = 0.1f; // 10% + + // Physical damage decreases by 5% var decDmgPowerUpDefinition = this.Context.CreateNew(); magicEffect.PowerUpDefinitions.Add(decDmgPowerUpDefinition); decDmgPowerUpDefinition.TargetAttribute = Stats.WeaknessPhysDmgDecrement.GetPersistent(this.GameConfiguration); diff --git a/src/Persistence/Initialization/Skills/WeaknessSummonerEffectInitializer.cs b/src/Persistence/Initialization/Skills/WeaknessSummonerEffectInitializer.cs new file mode 100644 index 000000000..1b5e51091 --- /dev/null +++ b/src/Persistence/Initialization/Skills/WeaknessSummonerEffectInitializer.cs @@ -0,0 +1,129 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.Skills; + +using MUnique.OpenMU.AttributeSystem; +using MUnique.OpenMU.DataModel.Attributes; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.GameLogic.Attributes; + +/// +/// Initializer for the weakness effect which results from Weakness (Summoner) skill. +/// +public class WeaknessSummonerEffectInitializer : InitializerBase +{ + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public WeaknessSummonerEffectInitializer(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + public override void Initialize() + { + var magicEffect = this.Context.CreateNew(); + this.GameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (short)MagicEffectNumber.WeaknessSummoner; + magicEffect.Name = "Weakness Effect (Summoner)"; + magicEffect.InformObservers = true; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = true; + magicEffect.DurationDependsOnTargetLevel = true; + magicEffect.MonsterTargetLevelDivisor = 20; + magicEffect.PlayerTargetLevelDivisor = 150; + + // Chance % = 32 + (Energy / 50) + (Book Rise / 6) + magicEffect.Chance = this.Context.CreateNew(); + magicEffect.Chance.ConstantValue.Value = 0.32f; // 32% + + var chancePerEnergy = this.Context.CreateNew(); + chancePerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + chancePerEnergy.InputOperator = InputOperator.Multiply; + chancePerEnergy.InputOperand = 1f / 5000f; // 50 energy adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerEnergy); + + var chancePerBookRise = this.Context.CreateNew(); + chancePerBookRise.InputAttribute = Stats.BookRise.GetPersistent(this.GameConfiguration); + chancePerBookRise.InputOperator = InputOperator.Multiply; + chancePerBookRise.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerBookRise); + + // Chance % = 17 + (Energy / 50) + (Book Rise / 6) + magicEffect.ChancePvp = this.Context.CreateNew(); + magicEffect.ChancePvp.ConstantValue.Value = 0.17f; // 17% + + var chancePerEnergyPvp = this.Context.CreateNew(); + chancePerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + chancePerEnergyPvp.InputOperator = InputOperator.Multiply; + chancePerEnergyPvp.InputOperand = 1f / 5000f; // 50 energy adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerEnergyPvp); + + var chancePerBookRisePvp = this.Context.CreateNew(); + chancePerBookRisePvp.InputAttribute = Stats.BookRise.GetPersistent(this.GameConfiguration); + chancePerBookRisePvp.InputOperator = InputOperator.Multiply; + chancePerBookRisePvp.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerBookRisePvp); + + // Duration = 4 + (Energy / 100) + magicEffect.Duration = this.Context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 4; // 4 Seconds + magicEffect.Duration.MaximumValue = 44; // 44 Seconds (based on 4k total energy cap) + + var durationPerEnergy = this.Context.CreateNew(); + durationPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + durationPerEnergy.InputOperator = InputOperator.Multiply; + durationPerEnergy.InputOperand = 1f / 100f; // 100 energy adds 1s + magicEffect.Duration.RelatedValues.Add(durationPerEnergy); + + // Duration = 5 + (Energy / 300) + ((Level - Target's Level) / 150) + magicEffect.DurationPvp = this.Context.CreateNew(); + magicEffect.DurationPvp.ConstantValue.Value = 5; // 5 Seconds + magicEffect.DurationPvp.MaximumValue = 18; // 18 Seconds (based on 4k total energy cap) + + var durationPerEnergyPvp = this.Context.CreateNew(); + durationPerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + durationPerEnergyPvp.InputOperator = InputOperator.Multiply; + durationPerEnergyPvp.InputOperand = 1f / 300f; // 300 energy adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerEnergyPvp); + + var durationPerLevelPvp = this.Context.CreateNew(); + durationPerLevelPvp.InputAttribute = Stats.Level.GetPersistent(this.GameConfiguration); + durationPerLevelPvp.InputOperator = InputOperator.Multiply; + durationPerLevelPvp.InputOperand = 1f / 150f; // 150 levels adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerLevelPvp); + + // Phys damage decrease % = 4 + (Energy / 58) + var decDmgPowerUpDefinition = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(decDmgPowerUpDefinition); + decDmgPowerUpDefinition.TargetAttribute = Stats.WeaknessPhysDmgDecrement.GetPersistent(this.GameConfiguration); + decDmgPowerUpDefinition.Boost = this.Context.CreateNew(); + decDmgPowerUpDefinition.Boost.ConstantValue.Value = 0.04f; // 4% decrease + decDmgPowerUpDefinition.Boost.MaximumValue = 0.73f; // 73% decrease (based on 4k total energy cap) + + var decDmgPerEnergy = this.Context.CreateNew(); + decDmgPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + decDmgPerEnergy.InputOperator = InputOperator.Multiply; + decDmgPerEnergy.InputOperand = 1f / 5800f; // 58 energy further decreases 1% + decDmgPowerUpDefinition.Boost.RelatedValues.Add(decDmgPerEnergy); + + // Phys damage decrease PvP % = 3 + (Energy / 93) + var decDmgPowerUpDefinitionPvp = this.Context.CreateNew(); + magicEffect.PowerUpDefinitionsPvp.Add(decDmgPowerUpDefinitionPvp); + decDmgPowerUpDefinitionPvp.TargetAttribute = Stats.WeaknessPhysDmgDecrement.GetPersistent(this.GameConfiguration); + decDmgPowerUpDefinitionPvp.Boost = this.Context.CreateNew(); + decDmgPowerUpDefinitionPvp.Boost.ConstantValue.Value = 0.03f; // 3% decrease + decDmgPowerUpDefinitionPvp.Boost.MaximumValue = 0.46f; // 46% decrease (based on 4k total energy cap) + + var decDmgPerEnergyPvp = this.Context.CreateNew(); + decDmgPerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(this.GameConfiguration); + decDmgPerEnergyPvp.InputOperator = InputOperator.Multiply; + decDmgPerEnergyPvp.InputOperand = 1f / 9300f; // 93 energy further decreases 1% + decDmgPowerUpDefinitionPvp.Boost.RelatedValues.Add(decDmgPerEnergyPvp); + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Updates/AddSummonerBuffSkillsPlugIn.cs b/src/Persistence/Initialization/Updates/AddSummonerBuffSkillsPlugIn.cs new file mode 100644 index 000000000..c3b8da1dd --- /dev/null +++ b/src/Persistence/Initialization/Updates/AddSummonerBuffSkillsPlugIn.cs @@ -0,0 +1,484 @@ +// +// 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.Attributes; +using MUnique.OpenMU.Persistence.Initialization.Skills; +using MUnique.OpenMU.PlugIns; + +/// +/// This update adds the Sleep, Innovation, Damage Reflection and Weakness Summoner buff skills. It also fixes the 3rd wing full reflect option. +/// +[PlugIn(PlugInName, PlugInDescription)] +[Guid("B1E2D6C3-1F4A-4D7C-8C2E-3F6D9A7B8E2F")] +public class AddSummonerBuffSkillsPlugIn : UpdatePlugInBase +{ + /// + /// The plug in name. + /// + internal const string PlugInName = "Add Summoner Buff Skills"; + + /// + /// The plug in description. + /// + internal const string PlugInDescription = "This update adds the Sleep, Innovation, Damage Reflection and Weakness Summoner buff skills. It also fixes the 3rd wing full reflect option."; + + /// + public override string Name => PlugInName; + + /// + public override string Description => PlugInDescription; + + /// + public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id; + + /// + public override UpdateVersion Version => UpdateVersion.AddSummonerBuffSkills; + + /// + public override bool IsMandatory => true; + + /// + public override DateTime CreatedAt => new(2025, 12, 29, 16, 0, 0, DateTimeKind.Utc); + + /// + protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) + { + // Add new attributes + var innovationDefDecrement = context.CreateNew(Stats.InnovationDefDecrement.Id, Stats.InnovationDefDecrement.Designation, Stats.InnovationDefDecrement.Description); + gameConfiguration.Attributes.Add(innovationDefDecrement); + var isAsleep = context.CreateNew(Stats.IsAsleep.Id, Stats.IsAsleep.Designation, Stats.IsAsleep.Description); + gameConfiguration.Attributes.Add(isAsleep); + var fullyReflectDamageAfterHitChance = context.CreateNew(Stats.FullyReflectDamageAfterHitChance.Id, Stats.FullyReflectDamageAfterHitChance.Designation, Stats.FullyReflectDamageAfterHitChance.Description); + gameConfiguration.Attributes.Add(fullyReflectDamageAfterHitChance); + + // Fix reflect excellent option + var excDefenseOptionsId = new Guid("00000083-0012-0000-0000-000000000000"); + if (gameConfiguration.ItemOptions.FirstOrDefault(io => io.GetId() == excDefenseOptionsId) is { } excDefenseOptions) + { + if (excDefenseOptions.PossibleOptions.FirstOrDefault(p => p.PowerUpDefinition?.TargetAttribute == Stats.DamageReflection) is { } dmgReflection) + { + dmgReflection.PowerUpDefinition!.Boost!.ConstantValue.Value = 0.05f; + } + } + + // Update Weakness magic effect + if (gameConfiguration.MagicEffects.FirstOrDefault(m => m.Number == (short)MagicEffectNumber.Weakness) is { } weaknessEffect) + { + weaknessEffect.Chance = context.CreateNew(); + weaknessEffect.Chance.ConstantValue.Value = 0.1f; // 10% + } + + var innovationEffect = this.CreateInnovationMagicEffect(context, gameConfiguration); + var reflectionEffect = this.CreateReflectionMagicEffect(context, gameConfiguration); + var sleepEffect = this.CreateSleepMagicEffect(context, gameConfiguration); + var weaknessSummonerEffect = this.CreateWeaknessSummonerMagicEffect(context, gameConfiguration); + + // Update 3rd wing reflect option + var thirWingOptionDefId = new Guid("00000083-0067-0000-0000-000000000000"); + if (gameConfiguration.ItemOptions.FirstOrDefault(io => io.GetId() == thirWingOptionDefId) is { } thirWingOptionDef + && thirWingOptionDef.PossibleOptions.FirstOrDefault(po => po.PowerUpDefinition?.TargetAttribute == Stats.DamageReflection) is { } reflectOpt + && reflectOpt.PowerUpDefinition is not null) + { + reflectOpt.PowerUpDefinition.TargetAttribute = fullyReflectDamageAfterHitChance; + } + + // Update existing skills + if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.Innovation) is { } innovation) + { + innovation.MagicEffectDef = innovationEffect; + innovation.SkillType = SkillType.Buff; + innovation.AreaSkillSettings = + this.AddAreaSkillSettings(context, false, 0, 0, 0, maximumHitsPerAttack: 5, useTargetAreaFilter: true, targetAreaDiameter: 10); + } + + if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.DamageReflection) is { } damageReflection) + { + damageReflection.MagicEffectDef = reflectionEffect; + damageReflection.SkillType = SkillType.Buff; + } + + if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.Sleep) is { } sleep) + { + sleep.MagicEffectDef = sleepEffect; + sleep.SkillType = SkillType.Buff; + } + + if (gameConfiguration.Skills.FirstOrDefault(s => s.Number == (short)SkillNumber.Weakness) is { } weakness) + { + weakness.MagicEffectDef = weaknessSummonerEffect; + weakness.SkillType = SkillType.Buff; + weakness.AreaSkillSettings = + this.AddAreaSkillSettings(context, false, 0, 0, 0, maximumHitsPerAttack: 5, useTargetAreaFilter: true, targetAreaDiameter: 10); + } + } + + private MagicEffectDefinition CreateInnovationMagicEffect(IContext context, GameConfiguration gameConfiguration) + { + var magicEffect = context.CreateNew(); + gameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (short)MagicEffectNumber.Innovation; + magicEffect.Name = "Innovation Effect"; + magicEffect.InformObservers = true; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = true; + magicEffect.DurationDependsOnTargetLevel = true; + magicEffect.MonsterTargetLevelDivisor = 20; + magicEffect.PlayerTargetLevelDivisor = 150; + + // Chance % = 32 + (Energy / 50) + (Book Rise / 6) + magicEffect.Chance = context.CreateNew(); + magicEffect.Chance.ConstantValue.Value = 0.32f; // 32% + + var chancePerEnergy = context.CreateNew(); + chancePerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + chancePerEnergy.InputOperator = InputOperator.Multiply; + chancePerEnergy.InputOperand = 1f / 5000f; // 50 energy adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerEnergy); + + var chancePerBookRise = context.CreateNew(); + chancePerBookRise.InputAttribute = Stats.BookRise.GetPersistent(gameConfiguration); + chancePerBookRise.InputOperator = InputOperator.Multiply; + chancePerBookRise.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerBookRise); + + // Chance PvP % = 17 + (Energy / 50) + (Book Rise / 6) + magicEffect.ChancePvp = context.CreateNew(); + magicEffect.ChancePvp.ConstantValue.Value = 0.17f; // 17% + + var chancePerEnergyPvp = context.CreateNew(); + chancePerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + chancePerEnergyPvp.InputOperator = InputOperator.Multiply; + chancePerEnergyPvp.InputOperand = 1f / 5000f; // 50 energy adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerEnergyPvp); + + var chancePerBookRisePvp = context.CreateNew(); + chancePerBookRisePvp.InputAttribute = Stats.BookRise.GetPersistent(gameConfiguration); + chancePerBookRisePvp.InputOperator = InputOperator.Multiply; + chancePerBookRisePvp.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerBookRisePvp); + + // Duration = 4 + (Energy / 100) + magicEffect.Duration = context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 4; // 4 Seconds + magicEffect.Duration.MaximumValue = 44; // 44 Seconds (based on 4k total energy cap) + + var durationPerEnergy = context.CreateNew(); + durationPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + durationPerEnergy.InputOperator = InputOperator.Multiply; + durationPerEnergy.InputOperand = 1f / 100f; // 100 energy adds 1s + magicEffect.Duration.RelatedValues.Add(durationPerEnergy); + + magicEffect.DurationPvp = context.CreateNew(); + magicEffect.DurationPvp.ConstantValue.Value = 5; // 5 Seconds + magicEffect.DurationPvp.MaximumValue = 18; // 18 Seconds (based on 4k total energy cap) + + // Duration PvP = 5 + (Energy / 300) + ((Level - Target's Level) / 150) + var durationPerEnergyPvp = context.CreateNew(); + durationPerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + durationPerEnergyPvp.InputOperator = InputOperator.Multiply; + durationPerEnergyPvp.InputOperand = 1f / 300f; // 300 energy adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerEnergyPvp); + + var durationPerLevelPvp = context.CreateNew(); + durationPerLevelPvp.InputAttribute = Stats.Level.GetPersistent(gameConfiguration); + durationPerLevelPvp.InputOperator = InputOperator.Multiply; + durationPerLevelPvp.InputOperand = 1f / 150f; // 150 levels adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerLevelPvp); + + // Defense decrease % (applies last) = 20 + (Energy / 90) + var decDefPowerUpDefinition = context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(decDefPowerUpDefinition); + decDefPowerUpDefinition.TargetAttribute = Stats.InnovationDefDecrement.GetPersistent(gameConfiguration); + decDefPowerUpDefinition.Boost = context.CreateNew(); + decDefPowerUpDefinition.Boost.ConstantValue.Value = 0.20f; // 20% decrease + decDefPowerUpDefinition.Boost.MaximumValue = 0.64f; // 64% decrease (based on 4k total energy cap) + + var decDefPerEnergy = context.CreateNew(); + decDefPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + decDefPerEnergy.InputOperator = InputOperator.Multiply; + decDefPerEnergy.InputOperand = 1f / 9000f; // 90 energy further decreases 0.01 + decDefPowerUpDefinition.Boost.RelatedValues.Add(decDefPerEnergy); + + // Defense decrease PvP % (applies last) = 12 + (Energy / 110) + var decDefPowerUpDefinitionPvp = context.CreateNew(); + magicEffect.PowerUpDefinitionsPvp.Add(decDefPowerUpDefinitionPvp); + decDefPowerUpDefinitionPvp.TargetAttribute = Stats.InnovationDefDecrement.GetPersistent(gameConfiguration); + decDefPowerUpDefinitionPvp.Boost = context.CreateNew(); + decDefPowerUpDefinitionPvp.Boost.ConstantValue.Value = 0.12f; // 12% decrease + decDefPowerUpDefinitionPvp.Boost.MaximumValue = 0.48f; // 48% decrease (based on 4k total energy cap) + + var decDefPerEnergyPvp = context.CreateNew(); + decDefPerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + decDefPerEnergyPvp.InputOperator = InputOperator.Multiply; + decDefPerEnergyPvp.InputOperand = 1f / 11000f; // 110 energy further decreases 0.01 + decDefPowerUpDefinitionPvp.Boost.RelatedValues.Add(decDefPerEnergyPvp); + + return magicEffect; + } + + private MagicEffectDefinition CreateReflectionMagicEffect(IContext context, GameConfiguration gameConfiguration) + { + var magicEffect = context.CreateNew(); + gameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (short)MagicEffectNumber.Reflection; + magicEffect.Name = "Reflection Effect"; + magicEffect.InformObservers = true; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = true; + + // Duration = 30 + (Energy / 24) + magicEffect.Duration = context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 30; // 30 Seconds + magicEffect.Duration.MaximumValue = 180; + + var durationPerEnergy = context.CreateNew(); + durationPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + durationPerEnergy.InputOperator = InputOperator.Multiply; + durationPerEnergy.InputOperand = 1f / 24; // 24 energy adds 1s + magicEffect.Duration.RelatedValues.Add(durationPerEnergy); + + // Reflection % = 30 + (Energy / 42) + var incReflectPowerUpDefinition = context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(incReflectPowerUpDefinition); + incReflectPowerUpDefinition.TargetAttribute = Stats.DamageReflection.GetPersistent(gameConfiguration); + incReflectPowerUpDefinition.Boost = context.CreateNew(); + incReflectPowerUpDefinition.Boost.ConstantValue.Value = 0.3f; // 30% increase + incReflectPowerUpDefinition.Boost.MaximumValue = 0.6f; + + var incReflectPerEnergy = context.CreateNew(); + incReflectPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + incReflectPerEnergy.InputOperator = InputOperator.Multiply; + incReflectPerEnergy.InputOperand = 1f / 4200f; // 42 energy further increases 0.01 + incReflectPowerUpDefinition.Boost.RelatedValues.Add(incReflectPerEnergy); + + return magicEffect; + } + + private MagicEffectDefinition CreateSleepMagicEffect(IContext context, GameConfiguration gameConfiguration) + { + var magicEffect = context.CreateNew(); + gameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (short)MagicEffectNumber.Sleep; + magicEffect.Name = "Sleep Effect"; + magicEffect.InformObservers = true; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = true; + magicEffect.DurationDependsOnTargetLevel = true; + magicEffect.MonsterTargetLevelDivisor = 20; + magicEffect.PlayerTargetLevelDivisor = 100; + + // Chance % = 20 + (Energy / 30) + (Book Rise / 6) + magicEffect.Chance = context.CreateNew(); + magicEffect.Chance.ConstantValue.Value = 0.2f; // 20% + + var chancePerEnergy = context.CreateNew(); + chancePerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + chancePerEnergy.InputOperator = InputOperator.Multiply; + chancePerEnergy.InputOperand = 1f / 3000f; // 30 energy adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerEnergy); + + var chancePerBookRise = context.CreateNew(); + chancePerBookRise.InputAttribute = Stats.BookRise.GetPersistent(gameConfiguration); + chancePerBookRise.InputOperator = InputOperator.Multiply; + chancePerBookRise.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerBookRise); + + // Chance PvP % = 15 + (Energy / 37) + (Book Rise / 6) + magicEffect.ChancePvp = context.CreateNew(); + magicEffect.ChancePvp.ConstantValue.Value = 0.15f; // 15% + + var chancePerEnergyPvp = context.CreateNew(); + chancePerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + chancePerEnergyPvp.InputOperator = InputOperator.Multiply; + chancePerEnergyPvp.InputOperand = 1f / 3700f; // 37 energy adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerEnergyPvp); + + var chancePerBookRisePvp = context.CreateNew(); + chancePerBookRisePvp.InputAttribute = Stats.BookRise.GetPersistent(gameConfiguration); + chancePerBookRisePvp.InputOperator = InputOperator.Multiply; + chancePerBookRisePvp.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerBookRisePvp); + + // Duration = 5 + (Energy / 100) + magicEffect.Duration = context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 5; // 5 Seconds + magicEffect.Duration.MaximumValue = 20; // 20 Seconds + + var durationPerEnergy = context.CreateNew(); + durationPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + durationPerEnergy.InputOperator = InputOperator.Multiply; + durationPerEnergy.InputOperand = 1f / 100f; // 100 energy adds 1s + magicEffect.Duration.RelatedValues.Add(durationPerEnergy); + + // Duration = 4 + (Energy / 250) + ((Level - Target's Level) / 100) + magicEffect.DurationPvp = context.CreateNew(); + magicEffect.DurationPvp.ConstantValue.Value = 4; // 4 Seconds + magicEffect.DurationPvp.MaximumValue = 10; // 10 Seconds + + var durationPerEnergyPvp = context.CreateNew(); + durationPerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + durationPerEnergyPvp.InputOperator = InputOperator.Multiply; + durationPerEnergyPvp.InputOperand = 1f / 250f; // 250 energy adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerEnergyPvp); + + var durationPerLevelPvp = context.CreateNew(); + durationPerLevelPvp.InputAttribute = Stats.Level.GetPersistent(gameConfiguration); + durationPerLevelPvp.InputOperator = InputOperator.Multiply; + durationPerLevelPvp.InputOperand = 1f / 100f; // 100 levels adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerLevelPvp); + + var isAsleep = context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(isAsleep); + isAsleep.TargetAttribute = Stats.IsAsleep.GetPersistent(gameConfiguration); + isAsleep.Boost = context.CreateNew(); + isAsleep.Boost.ConstantValue.Value = 1; + + return magicEffect; + } + + private MagicEffectDefinition CreateWeaknessSummonerMagicEffect(IContext context, GameConfiguration gameConfiguration) + { + var magicEffect = context.CreateNew(); + gameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (short)MagicEffectNumber.Weakness; // We will map skill to effect by hand in this update, so we use this number instead of WeaknessSummoner + magicEffect.Name = "Weakness Effect (Summoner)"; + magicEffect.InformObservers = true; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = true; + magicEffect.DurationDependsOnTargetLevel = true; + magicEffect.MonsterTargetLevelDivisor = 20; + magicEffect.PlayerTargetLevelDivisor = 150; + + // Chance % = 32 + (Energy / 50) + (Book Rise / 6) + magicEffect.Chance = context.CreateNew(); + magicEffect.Chance.ConstantValue.Value = 0.32f; // 32% + + var chancePerEnergy = context.CreateNew(); + chancePerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + chancePerEnergy.InputOperator = InputOperator.Multiply; + chancePerEnergy.InputOperand = 1f / 5000f; // 50 energy adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerEnergy); + + var chancePerBookRise = context.CreateNew(); + chancePerBookRise.InputAttribute = Stats.BookRise.GetPersistent(gameConfiguration); + chancePerBookRise.InputOperator = InputOperator.Multiply; + chancePerBookRise.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.Chance.RelatedValues.Add(chancePerBookRise); + + // Chance % = 17 + (Energy / 50) + (Book Rise / 6) + magicEffect.ChancePvp = context.CreateNew(); + magicEffect.ChancePvp.ConstantValue.Value = 0.17f; // 17% + + var chancePerEnergyPvp = context.CreateNew(); + chancePerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + chancePerEnergyPvp.InputOperator = InputOperator.Multiply; + chancePerEnergyPvp.InputOperand = 1f / 5000f; // 50 energy adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerEnergyPvp); + + var chancePerBookRisePvp = context.CreateNew(); + chancePerBookRisePvp.InputAttribute = Stats.BookRise.GetPersistent(gameConfiguration); + chancePerBookRisePvp.InputOperator = InputOperator.Multiply; + chancePerBookRisePvp.InputOperand = 1f / 600f; // 6 book rise adds 1% chance + magicEffect.ChancePvp.RelatedValues.Add(chancePerBookRisePvp); + + // Duration = 4 + (Energy / 100) + magicEffect.Duration = context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 4; // 4 Seconds + magicEffect.Duration.MaximumValue = 44; // 44 Seconds (based on 4k total energy cap) + + var durationPerEnergy = context.CreateNew(); + durationPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + durationPerEnergy.InputOperator = InputOperator.Multiply; + durationPerEnergy.InputOperand = 1f / 100f; // 100 energy adds 1s + magicEffect.Duration.RelatedValues.Add(durationPerEnergy); + + // Duration = 5 + (Energy / 300) + ((Level - Target's Level) / 150) + magicEffect.DurationPvp = context.CreateNew(); + magicEffect.DurationPvp.ConstantValue.Value = 5; // 5 Seconds + magicEffect.DurationPvp.MaximumValue = 18; // 18 Seconds (based on 4k total energy cap) + + var durationPerEnergyPvp = context.CreateNew(); + durationPerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + durationPerEnergyPvp.InputOperator = InputOperator.Multiply; + durationPerEnergyPvp.InputOperand = 1f / 300f; // 300 energy adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerEnergyPvp); + + var durationPerLevelPvp = context.CreateNew(); + durationPerLevelPvp.InputAttribute = Stats.Level.GetPersistent(gameConfiguration); + durationPerLevelPvp.InputOperator = InputOperator.Multiply; + durationPerLevelPvp.InputOperand = 1f / 150f; // 150 levels adds 1s + magicEffect.DurationPvp.RelatedValues.Add(durationPerLevelPvp); + + // Phys damage decrease % = 4 + (Energy / 58) + var decDmgPowerUpDefinition = context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(decDmgPowerUpDefinition); + decDmgPowerUpDefinition.TargetAttribute = Stats.WeaknessPhysDmgDecrement.GetPersistent(gameConfiguration); + decDmgPowerUpDefinition.Boost = context.CreateNew(); + decDmgPowerUpDefinition.Boost.ConstantValue.Value = 0.04f; // 4% decrease + decDmgPowerUpDefinition.Boost.MaximumValue = 0.73f; // 73% decrease (based on 4k total energy cap) + + var decDmgPerEnergy = context.CreateNew(); + decDmgPerEnergy.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + decDmgPerEnergy.InputOperator = InputOperator.Multiply; + decDmgPerEnergy.InputOperand = 1f / 5800f; // 58 energy further decreases 0.01 + decDmgPowerUpDefinition.Boost.RelatedValues.Add(decDmgPerEnergy); + + // Phys damage decrease PvP % = 3 + (Energy / 93) + var decDmgPowerUpDefinitionPvp = context.CreateNew(); + magicEffect.PowerUpDefinitionsPvp.Add(decDmgPowerUpDefinitionPvp); + decDmgPowerUpDefinitionPvp.TargetAttribute = Stats.WeaknessPhysDmgDecrement.GetPersistent(gameConfiguration); + decDmgPowerUpDefinitionPvp.Boost = context.CreateNew(); + decDmgPowerUpDefinitionPvp.Boost.ConstantValue.Value = 0.03f; // 3% decrease + decDmgPowerUpDefinitionPvp.Boost.MaximumValue = 0.46f; // 46% decrease (based on 4k total energy cap) + + var decDmgPerEnergyPvp = context.CreateNew(); + decDmgPerEnergyPvp.InputAttribute = Stats.TotalEnergy.GetPersistent(gameConfiguration); + decDmgPerEnergyPvp.InputOperator = InputOperator.Multiply; + decDmgPerEnergyPvp.InputOperand = 1f / 9300f; // 93 energy further decreases 0.01 + decDmgPowerUpDefinitionPvp.Boost.RelatedValues.Add(decDmgPerEnergyPvp); + + return magicEffect; + } + + private AreaSkillSettings AddAreaSkillSettings( + IContext context, + bool useFrustumFilter, + float frustumStartWidth, + float frustumEndWidth, + float frustumDistance, + bool useDeferredHits = false, + TimeSpan delayPerOneDistance = default, + TimeSpan delayBetweenHits = default, + int minimumHitsPerTarget = 1, + int maximumHitsPerTarget = 1, + int maximumHitsPerAttack = default, + float hitChancePerDistanceMultiplier = 1.0f, + bool useTargetAreaFilter = false, + float targetAreaDiameter = default) + { + var areaSkillSettings = context.CreateNew(); + + areaSkillSettings.UseFrustumFilter = useFrustumFilter; + areaSkillSettings.FrustumStartWidth = frustumStartWidth; + areaSkillSettings.FrustumEndWidth = frustumEndWidth; + areaSkillSettings.FrustumDistance = frustumDistance; + areaSkillSettings.UseTargetAreaFilter = useTargetAreaFilter; + areaSkillSettings.TargetAreaDiameter = targetAreaDiameter; + areaSkillSettings.UseDeferredHits = useDeferredHits; + areaSkillSettings.DelayPerOneDistance = delayPerOneDistance; + areaSkillSettings.DelayBetweenHits = delayBetweenHits; + areaSkillSettings.MinimumNumberOfHitsPerTarget = minimumHitsPerTarget; + areaSkillSettings.MaximumNumberOfHitsPerTarget = maximumHitsPerTarget; + areaSkillSettings.MaximumNumberOfHitsPerAttack = maximumHitsPerAttack; + areaSkillSettings.HitChancePerDistanceMultiplier = hitChancePerDistanceMultiplier; + + return areaSkillSettings; + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Updates/UpdateVersion.cs b/src/Persistence/Initialization/Updates/UpdateVersion.cs index 35a6e9b1b..02468a338 100644 --- a/src/Persistence/Initialization/Updates/UpdateVersion.cs +++ b/src/Persistence/Initialization/Updates/UpdateVersion.cs @@ -334,4 +334,9 @@ public enum UpdateVersion /// The version of the . /// FixSkillMultipliers = 65, + + /// + /// The version of the . + /// + AddSummonerBuffSkills = 66, } \ No newline at end of file diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Wings.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Wings.cs index 8f4e31980..bde53646b 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Wings.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Wings.cs @@ -277,7 +277,7 @@ private ItemOptionDefinition CreateThirdClassWingOptions() definition.MaximumOptionsPerItem = 1; definition.PossibleOptions.Add(this.CreateWingOption(1, Stats.DefenseIgnoreChance, 0.05f, AggregateType.AddRaw)); // Ignore opponent's defensive power by 5% - definition.PossibleOptions.Add(this.CreateWingOption(2, Stats.DamageReflection, 0.05f, AggregateType.AddRaw)); // Ignore opponent's defensive power by 5% + definition.PossibleOptions.Add(this.CreateWingOption(2, Stats.FullyReflectDamageAfterHitChance, 0.05f, AggregateType.AddRaw)); // Fully reflect the damage when hit by 5% definition.PossibleOptions.Add(this.CreateWingOption(3, Stats.FullyRecoverHealthAfterHitChance, 0.05f, AggregateType.AddRaw)); // Fully restore health when hit by 5% definition.PossibleOptions.Add(this.CreateWingOption(4, Stats.FullyRecoverManaAfterHitChance, 0.05f, AggregateType.AddRaw)); // Fully recover mana when hit by 5% diff --git a/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs b/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs index b698e0ea7..c7d4f5390 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs @@ -67,6 +67,10 @@ internal class SkillsInitializer : SkillsInitializerBase { SkillNumber.ExpansionofWizardry, MagicEffectNumber.WizEnhance }, { SkillNumber.Berserker, MagicEffectNumber.Berserker }, { SkillNumber.KillingBlow, MagicEffectNumber.Weakness }, + { SkillNumber.Sleep, MagicEffectNumber.Sleep }, + { SkillNumber.Weakness, MagicEffectNumber.WeaknessSummoner }, + { SkillNumber.Innovation, MagicEffectNumber.Innovation }, + { SkillNumber.DamageReflection, MagicEffectNumber.Reflection }, }; private readonly IDictionary _masterSkillRoots; @@ -188,11 +192,13 @@ public override void Initialize() this.CreateSkill(SkillNumber.ShieldBurn, "Shield-Burn", CharacterClasses.All, distance: 3, manaConsumption: 30, elementalModifier: ElementalType.Ice, cooldownMinutes: 5); this.CreateSkill(SkillNumber.DrainLife, "Drain Life", CharacterClasses.AllSummoners, DamageType.Wizardry, 35, 6, manaConsumption: 50, energyRequirement: 150, skillType: SkillType.AreaSkillExplicitTarget); this.CreateSkill(SkillNumber.ChainLightning, "Chain Lightning", CharacterClasses.AllSummoners, DamageType.Wizardry, 70, 6, manaConsumption: 85, energyRequirement: 245, skillType: SkillType.AreaSkillExplicitTarget, skillTarget: SkillTarget.Explicit); - this.CreateSkill(SkillNumber.DamageReflection, "Damage Reflection", CharacterClasses.AllSummoners, distance: 5, abilityConsumption: 10, manaConsumption: 40, energyRequirement: 375); + this.CreateSkill(SkillNumber.DamageReflection, "Damage Reflection", CharacterClasses.AllSummoners, distance: 5, abilityConsumption: 10, manaConsumption: 40, energyRequirement: 375, skillType: SkillType.Buff); this.CreateSkill(SkillNumber.Berserker, "Berserker", CharacterClasses.AllSummoners, distance: 5, abilityConsumption: 50, manaConsumption: 100, energyRequirement: 620, skillType: SkillType.Buff, targetRestriction: SkillTargetRestriction.Self); - this.CreateSkill(SkillNumber.Sleep, "Sleep", CharacterClasses.AllSummoners, distance: 6, abilityConsumption: 3, manaConsumption: 20, energyRequirement: 180); - this.CreateSkill(SkillNumber.Weakness, "Weakness", CharacterClasses.AllSummoners, distance: 6, abilityConsumption: 15, manaConsumption: 50, energyRequirement: 663); - this.CreateSkill(SkillNumber.Innovation, "Innovation", CharacterClasses.AllSummoners, distance: 6, abilityConsumption: 15, manaConsumption: 70, energyRequirement: 912); + this.CreateSkill(SkillNumber.Sleep, "Sleep", CharacterClasses.AllSummoners, distance: 6, abilityConsumption: 3, manaConsumption: 20, energyRequirement: 180, skillType: SkillType.Buff); + this.CreateSkill(SkillNumber.Weakness, "Weakness", CharacterClasses.AllSummoners, distance: 6, abilityConsumption: 15, manaConsumption: 50, energyRequirement: 663, skillType: SkillType.Buff); + this.AddAreaSkillSettings(SkillNumber.Weakness, false, 0, 0, 0, maximumHitsPerAttack: 5, useTargetAreaFilter: true, targetAreaDiameter: 10); + this.CreateSkill(SkillNumber.Innovation, "Innovation", CharacterClasses.AllSummoners, distance: 6, abilityConsumption: 15, manaConsumption: 70, energyRequirement: 912, skillType: SkillType.Buff); + this.AddAreaSkillSettings(SkillNumber.Innovation, false, 0, 0, 0, maximumHitsPerAttack: 5, useTargetAreaFilter: true, targetAreaDiameter: 10); this.CreateSkill(SkillNumber.Explosion223, "Explosion", CharacterClasses.AllSummoners, DamageType.Curse, 40, 6, 5, 90, energyRequirement: 100, elementalModifier: ElementalType.Fire); // Book of Samut's skill this.CreateSkill(SkillNumber.Requiem, "Requiem", CharacterClasses.AllSummoners, DamageType.Curse, 65, 6, 10, 110, energyRequirement: 99, elementalModifier: ElementalType.Wind); // Book of Neil's skill this.CreateSkill(SkillNumber.Pollution, "Pollution", CharacterClasses.AllSummoners, DamageType.Curse, 80, 6, 15, 120, energyRequirement: 115, elementalModifier: ElementalType.Lightning); // Book of Lagle's skill @@ -244,7 +250,7 @@ public override void Initialize() this.CreateSkill(SkillNumber.MonsterAttackSdInc, "Monster Attack SD Inc", CharacterClasses.AllMastersExceptFistMaster, damage: 11, skillType: SkillType.PassiveBoost); this.CreateSkill(SkillNumber.MonsterAttackLifeInc, "Monster Attack Life Inc", CharacterClasses.AllMastersExceptFistMaster, damage: 6, skillType: SkillType.PassiveBoost); this.CreateSkill(SkillNumber.SwellLifeProficiency, "Swell Life Proficiency", CharacterClasses.BladeMaster, damage: 7, abilityConsumption: 28, manaConsumption: 26, levelRequirement: 120); - this.CreateSkill(SkillNumber.MinimumAttackPowerInc, "Minimum Attack Power Inc", CharacterClasses.BladeMaster | CharacterClasses.DuelMaster |CharacterClasses.LordEmperor, DamageType.Physical, 22, skillType: SkillType.PassiveBoost); + this.CreateSkill(SkillNumber.MinimumAttackPowerInc, "Minimum Attack Power Inc", CharacterClasses.BladeMaster | CharacterClasses.DuelMaster | CharacterClasses.LordEmperor, DamageType.Physical, 22, skillType: SkillType.PassiveBoost); this.CreateSkill(SkillNumber.MonsterAttackManaInc, "Monster Attack Mana Inc", CharacterClasses.AllMastersExceptFistMaster, damage: 6, skillType: SkillType.PassiveBoost); this.CreateSkill(SkillNumber.PvPAttackRate, "PvP Attack Rate", CharacterClasses.AllMastersExceptFistMaster, damage: 14, skillType: SkillType.PassiveBoost); @@ -662,6 +668,10 @@ private void InitializeEffects() new BlessPotionEffectInitializer(this.Context, this.GameConfiguration).Initialize(); new BerserkerEffectInitializer(this.Context, this.GameConfiguration).Initialize(); new WeaknessEffectInitializer(this.Context, this.GameConfiguration).Initialize(); + new SleepEffectInitializer(this.Context, this.GameConfiguration).Initialize(); + new WeaknessSummonerEffectInitializer(this.Context, this.GameConfiguration).Initialize(); + new InnovationEffectInitializer(this.Context, this.GameConfiguration).Initialize(); + new ReflectionEffectInitializer(this.Context, this.GameConfiguration).Initialize(); } private void MapSkillsToEffects() @@ -671,6 +681,17 @@ private void MapSkillsToEffects() var skill = this.GameConfiguration.Skills.First(s => s.Number == (short)effectOfSkill.Key); var effect = this.GameConfiguration.MagicEffects.First(e => e.Number == (short)effectOfSkill.Value); skill.MagicEffectDef = effect; + + // After the mapping, we override the internal effect number to the client's + switch (effect.Number) + { + case (short)MagicEffectNumber.WeaknessSummoner: + effect.Number = (short)MagicEffectNumber.Weakness; + break; + default: + // no change needed + break; + } } } @@ -739,7 +760,7 @@ private void InitializeMasterSkillData() this.AddMasterSkillDefinition(SkillNumber.SpearMastery, SkillNumber.SpearStrengthener, SkillNumber.Undefined, 3, 3, SkillNumber.Undefined, 20, Formula120); this.AddMasterSkillDefinition(SkillNumber.SwellLifeStrengt, SkillNumber.SwellLife, SkillNumber.Undefined, 3, 4, SkillNumber.SwellLife, 20, Formula181); - this.AddPassiveMasterSkillDefinition(SkillNumber.ManaReduction, Stats.ManaUsageReduction, AggregateType.AddRaw, Formula722Value, Formula722, 4, 3); + this.AddPassiveMasterSkillDefinition(SkillNumber.ManaReduction, Stats.ManaUsageReduction, AggregateType.AddRaw, Formula722Value, Formula722, 4, 3); this.AddPassiveMasterSkillDefinition(SkillNumber.MonsterAttackSdInc, Stats.ShieldAfterMonsterKillMultiplier, AggregateType.AddFinal, Formula914, 4, 3); this.AddPassiveMasterSkillDefinition(SkillNumber.MonsterAttackLifeInc, Stats.HealthAfterMonsterKillMultiplier, AggregateType.AddFinal, Formula4319, 4, 3); this.AddMasterSkillDefinition(SkillNumber.SwellLifeProficiency, SkillNumber.SwellLifeStrengt, SkillNumber.Undefined, 3, 5, SkillNumber.SwellLife, 20, Formula181);