From aff8615c79027601c31f523d853b20682ab28f96 Mon Sep 17 00:00:00 2001 From: sven-n Date: Thu, 17 Oct 2024 21:41:02 +0200 Subject: [PATCH 01/11] Added missing attack speed and magic speed stats --- src/GameLogic/Attributes/Stats.cs | 10 + .../UpdateCharacterStatsExtendedPlugIn.cs | 2 +- .../CharacterClasses/ClassDarkKnight.cs | 1 + .../CharacterClasses/ClassDarkLord.cs | 3 + .../CharacterClasses/ClassDarkWizard.cs | 3 + .../CharacterClasses/ClassFairyElf.cs | 3 + .../CharacterClasses/ClassMagicGladiator.cs | 1 + .../CharacterClasses/ClassRageFighter.cs | 3 + .../CharacterClasses/ClassSummoner.cs | 1 + .../Items/ArmorInitializerBase.cs | 46 ++++ .../Initialization/Version075/Items/Armors.cs | 60 ++--- .../Version095d/Items/Armors.cs | 60 ++--- .../VersionSeasonSix/Items/Armors.cs | 220 +++++++++--------- .../VersionSeasonSix/Items/Weapons.cs | 2 +- 14 files changed, 243 insertions(+), 172 deletions(-) diff --git a/src/GameLogic/Attributes/Stats.cs b/src/GameLogic/Attributes/Stats.cs index 6a28bbf6f..d37a7bd08 100644 --- a/src/GameLogic/Attributes/Stats.cs +++ b/src/GameLogic/Attributes/Stats.cs @@ -286,6 +286,16 @@ public class Stats /// public static AttributeDefinition AttackSpeed { get; } = new (new Guid("BACC1115-1E8B-4E62-B952-8F8DDB58A949"), "Attack Speed", string.Empty); + /// + /// Gets the magic speed attribute definition which is used for some skills. + /// + public static AttributeDefinition MagicSpeed { get; } = new(new Guid("AE32AA45-9C18-43B3-9F7B-648FD7F4B0AD"), "Magic Speed", string.Empty); + + /// + /// Gets the walk speed attribute definition. + /// + public static AttributeDefinition WalkSpeed { get; } = new(new Guid("9CDDC598-E5F3-4372-9294-505455E4A40B"), "Walk Speed", string.Empty); + /// /// Gets the attack damage increase attribute definition. /// diff --git a/src/GameServer/RemoteView/Character/UpdateCharacterStatsExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateCharacterStatsExtendedPlugIn.cs index 0cd9a8e28..cffd101c9 100644 --- a/src/GameServer/RemoteView/Character/UpdateCharacterStatsExtendedPlugIn.cs +++ b/src/GameServer/RemoteView/Character/UpdateCharacterStatsExtendedPlugIn.cs @@ -65,7 +65,7 @@ await connection.SendCharacterInformationExtendedAsync( (ushort)this._player.SelectedCharacter.UsedNegFruitPoints, this._player.SelectedCharacter.GetMaximumFruitPoints(), (ushort)this._player.Attributes[Stats.AttackSpeed], - (ushort)this._player.Attributes[Stats.AttackSpeed], // todo: implement MagicSpeed + (ushort)this._player.Attributes[Stats.MagicSpeed], 200, // todo: This is the maximum attack speed, make configurable. (byte)this._player.SelectedCharacter.InventoryExtensions) .ConfigureAwait(false); diff --git a/src/Persistence/Initialization/CharacterClasses/ClassDarkKnight.cs b/src/Persistence/Initialization/CharacterClasses/ClassDarkKnight.cs index f4c44aba4..7f25c1f55 100644 --- a/src/Persistence/Initialization/CharacterClasses/ClassDarkKnight.cs +++ b/src/Persistence/Initialization/CharacterClasses/ClassDarkKnight.cs @@ -51,6 +51,7 @@ protected CharacterClass CreateDarkKnight(CharacterClassNumber number, string na result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.DefenseRatePvm, 1.0f / 3, Stats.TotalAgility)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackSpeed, 1.0f / 15, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MagicSpeed, 1.0f / 20, Stats.TotalAgility)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvm, 5, Stats.Level)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvm, 1.5f, Stats.TotalAgility)); diff --git a/src/Persistence/Initialization/CharacterClasses/ClassDarkLord.cs b/src/Persistence/Initialization/CharacterClasses/ClassDarkLord.cs index 43bab4230..10d3352b6 100644 --- a/src/Persistence/Initialization/CharacterClasses/ClassDarkLord.cs +++ b/src/Persistence/Initialization/CharacterClasses/ClassDarkLord.cs @@ -62,6 +62,9 @@ private CharacterClass CreateDarkLord(CharacterClassNumber number, string name, result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvm, 1.0f / 6, Stats.TotalStrength)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvm, 1.0f / 10, Stats.TotalLeadership)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackSpeed, 1.0f / 10, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MagicSpeed, 1.0f / 10, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.15f, Stats.TotalEnergy)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.1f, Stats.TotalVitality)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.2f, Stats.TotalAgility)); diff --git a/src/Persistence/Initialization/CharacterClasses/ClassDarkWizard.cs b/src/Persistence/Initialization/CharacterClasses/ClassDarkWizard.cs index d380f0e36..5bc5c8ddc 100644 --- a/src/Persistence/Initialization/CharacterClasses/ClassDarkWizard.cs +++ b/src/Persistence/Initialization/CharacterClasses/ClassDarkWizard.cs @@ -55,6 +55,9 @@ protected CharacterClass CreateDarkWizard(CharacterClassNumber number, string na result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvm, 1.5f, Stats.TotalAgility)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvm, 0.25f, Stats.TotalStrength)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackSpeed, 1.0f / 20, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MagicSpeed, 1.0f / 10, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.2f, Stats.TotalEnergy)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.3f, Stats.TotalVitality)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.4f, Stats.TotalAgility)); diff --git a/src/Persistence/Initialization/CharacterClasses/ClassFairyElf.cs b/src/Persistence/Initialization/CharacterClasses/ClassFairyElf.cs index 1c9d82677..e8184a94d 100644 --- a/src/Persistence/Initialization/CharacterClasses/ClassFairyElf.cs +++ b/src/Persistence/Initialization/CharacterClasses/ClassFairyElf.cs @@ -55,6 +55,9 @@ protected CharacterClass CreateFairyElf(CharacterClassNumber number, string name result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvm, 1.5f, Stats.TotalAgility)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvm, 0.25f, Stats.TotalStrength)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackSpeed, 1.0f / 50, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MagicSpeed, 1.0f / 50, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.2f, Stats.TotalEnergy)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.3f, Stats.TotalVitality)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.2f, Stats.TotalAgility)); diff --git a/src/Persistence/Initialization/CharacterClasses/ClassMagicGladiator.cs b/src/Persistence/Initialization/CharacterClasses/ClassMagicGladiator.cs index bacaba85e..98c765400 100644 --- a/src/Persistence/Initialization/CharacterClasses/ClassMagicGladiator.cs +++ b/src/Persistence/Initialization/CharacterClasses/ClassMagicGladiator.cs @@ -61,6 +61,7 @@ protected CharacterClass CreateMagicGladiator(CharacterClassNumber number, strin result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.DefenseRatePvm, 1.0f / 3, Stats.TotalAgility)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackSpeed, 1.0f / 15, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MagicSpeed, 1.0f / 20, Stats.TotalAgility)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvm, 5, Stats.Level)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvm, 1.5f, Stats.TotalAgility)); diff --git a/src/Persistence/Initialization/CharacterClasses/ClassRageFighter.cs b/src/Persistence/Initialization/CharacterClasses/ClassRageFighter.cs index d8b8162bf..517eaf727 100644 --- a/src/Persistence/Initialization/CharacterClasses/ClassRageFighter.cs +++ b/src/Persistence/Initialization/CharacterClasses/ClassRageFighter.cs @@ -63,6 +63,9 @@ private CharacterClass CreateRageFighter(CharacterClassNumber number, string nam result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvp, 3, Stats.Level)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvp, 1.0f / 5, Stats.TotalEnergy)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackSpeed, 1.0f / 9, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MagicSpeed, 1.0f / 9, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 1.0f, Stats.TotalEnergy)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.3f, Stats.TotalVitality)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.2f, Stats.TotalAgility)); diff --git a/src/Persistence/Initialization/CharacterClasses/ClassSummoner.cs b/src/Persistence/Initialization/CharacterClasses/ClassSummoner.cs index b7ef3011f..edd00f973 100644 --- a/src/Persistence/Initialization/CharacterClasses/ClassSummoner.cs +++ b/src/Persistence/Initialization/CharacterClasses/ClassSummoner.cs @@ -65,6 +65,7 @@ private CharacterClass CreateSummoner(CharacterClassNumber number, string name, result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackRatePvp, 3, Stats.Level)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.AttackSpeed, 1.0f / 20, Stats.TotalAgility)); + result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MagicSpeed, 1.0f / 20, Stats.TotalAgility)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.15f, Stats.TotalEnergy)); result.AttributeCombinations.Add(this.CreateAttributeRelationship(Stats.MaximumAbility, 0.3f, Stats.TotalVitality)); diff --git a/src/Persistence/Initialization/Items/ArmorInitializerBase.cs b/src/Persistence/Initialization/Items/ArmorInitializerBase.cs index 30980cbcf..dddd63281 100644 --- a/src/Persistence/Initialization/Items/ArmorInitializerBase.cs +++ b/src/Persistence/Initialization/Items/ArmorInitializerBase.cs @@ -137,6 +137,29 @@ protected void CreateShield(byte number, byte slot, byte skill, byte width, byte shield.BasePowerUpAttributes.Add(isShieldEquipped); } + protected ItemDefinition CreateGloves(byte number, string name, byte dropLevel, int defense, int attackSpeed, byte durability, int strengthRequirement, int agilityRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel) + { + var gloves = this.CreateArmor(number, 5, 2, 2, name, dropLevel, defense, durability, strengthRequirement, agilityRequirement, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel); + if (attackSpeed > 0) + { + gloves.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.AttackSpeed, attackSpeed, AggregateType.AddRaw)); + gloves.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.MagicSpeed, attackSpeed, AggregateType.AddRaw)); + } + + return gloves; + } + + protected ItemDefinition CreateBoots(byte number, byte slot, byte width, byte height, string name, byte dropLevel, int defense, int walkSpeed, byte durability, int strengthRequirement, int agilityRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel) + { + var boots = this.CreateArmor(number, 6, 2, 2, name, dropLevel, defense, durability, strengthRequirement, agilityRequirement, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel); + if (walkSpeed > 0) + { + boots.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.WalkSpeed, walkSpeed, AggregateType.AddRaw)); + } + + return boots; + } + protected ItemDefinition CreateArmor(byte number, byte slot, byte width, byte height, string name, byte dropLevel, int defense, byte durability, int strengthRequirement, int agilityRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel) { var magicGladiatorClassLevel = 0; @@ -150,6 +173,29 @@ protected ItemDefinition CreateArmor(byte number, byte slot, byte width, byte he return this.CreateArmor(number, slot, width, height, name, dropLevel, defense, durability, 0, strengthRequirement, agilityRequirement, 0, 0, 0, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel, magicGladiatorClassLevel, 0, 0, 0); } + protected ItemDefinition CreateGloves(byte number, string name, byte dropLevel, int defense, int attackSpeed, byte durability, int levelRequirement, int strengthRequirement, int agilityRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel, int magicGladiatorClassLevel, int darkLordClassLevel, int summonerClassLevel) + { + var gloves = this.CreateArmor(number, 5, 2, 2, name, dropLevel, defense, durability, levelRequirement, strengthRequirement, agilityRequirement, 0, 0, 0, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel, magicGladiatorClassLevel, darkLordClassLevel, summonerClassLevel, 0); + if (attackSpeed > 0) + { + gloves.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.AttackSpeed, attackSpeed, AggregateType.AddRaw)); + gloves.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.MagicSpeed, attackSpeed, AggregateType.AddRaw)); + } + + return gloves; + } + + protected ItemDefinition CreateBoots(byte number, string name, byte dropLevel, int defense, int walkSpeed, byte durability, int levelRequirement, int strengthRequirement, int agilityRequirement, int energyRequirement, int vitalityRequirement, int leadershipRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel, int magicGladiatorClassLevel, int darkLordClassLevel, int summonerClassLevel, int ragefighterClassLevel) + { + var boots = this.CreateArmor(number, 6, 2, 2, name, dropLevel, defense, durability, levelRequirement, strengthRequirement, agilityRequirement, energyRequirement, vitalityRequirement, leadershipRequirement, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel, magicGladiatorClassLevel, darkLordClassLevel, summonerClassLevel, ragefighterClassLevel); + if (walkSpeed > 0) + { + boots.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.WalkSpeed, walkSpeed, AggregateType.AddRaw)); + } + + return boots; + } + protected ItemDefinition CreateArmor(byte number, byte slot, byte width, byte height, string name, byte dropLevel, int defense, byte durability, int levelRequirement, int strengthRequirement, int agilityRequirement, int energyRequirement, int vitalityRequirement, int leadershipRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel, int magicGladiatorClassLevel, int darkLordClassLevel, int summonerClassLevel, int ragefighterClassLevel) { var armor = this.Context.CreateNew(); diff --git a/src/Persistence/Initialization/Version075/Items/Armors.cs b/src/Persistence/Initialization/Version075/Items/Armors.cs index 951f50aee..44d1a8678 100644 --- a/src/Persistence/Initialization/Version075/Items/Armors.cs +++ b/src/Persistence/Initialization/Version075/Items/Armors.cs @@ -101,38 +101,38 @@ public override void Initialize() this.CreateArmor(14, 4, 2, 2, "Guardian Pants", 54, 25, 45, 40, 80, 0, 0, 1); // Gloves: - this.CreateArmor(0, 5, 2, 2, "Bronze Gloves", 13, 4, 34, 80, 20, 0, 1, 0); - this.CreateArmor(1, 5, 2, 2, "Dragon Gloves", 52, 14, 68, 120, 30, 0, 1, 0); - this.CreateArmor(2, 5, 2, 2, "Pad Gloves", 3, 2, 28, 20, 0, 1, 0, 0); - this.CreateArmor(3, 5, 2, 2, "Legendary Gloves", 44, 11, 42, 20, 0, 1, 0, 0); - this.CreateArmor(4, 5, 2, 2, "Bone Gloves", 14, 5, 30, 20, 0, 1, 0, 0); - this.CreateArmor(5, 5, 2, 2, "Leather Gloves", 4, 2, 30, 80, 0, 0, 1, 0); - this.CreateArmor(6, 5, 2, 2, "Scale Gloves", 22, 7, 40, 110, 0, 0, 1, 0); - this.CreateArmor(7, 5, 2, 2, "Sphinx Gloves", 28, 8, 36, 20, 0, 1, 0, 0); - this.CreateArmor(8, 5, 2, 2, "Brass Gloves", 32, 9, 44, 100, 30, 0, 1, 0); - this.CreateArmor(9, 5, 2, 2, "Plate Gloves", 42, 12, 50, 130, 0, 0, 1, 0); - this.CreateArmor(10, 5, 2, 2, "Vine Gloves", 4, 2, 22, 30, 60, 0, 0, 1); - this.CreateArmor(11, 5, 2, 2, "Silk Gloves", 14, 4, 26, 30, 70, 0, 0, 1); - this.CreateArmor(12, 5, 2, 2, "Wind Gloves", 26, 6, 32, 30, 80, 0, 0, 1); - this.CreateArmor(13, 5, 2, 2, "Spirit Gloves", 38, 9, 38, 40, 80, 0, 0, 1); - this.CreateArmor(14, 5, 2, 2, "Guardian Gloves", 50, 15, 45, 40, 80, 0, 0, 1); + this.CreateGloves(0, "Bronze Gloves", 13, 4, 4, 34, 80, 20, 0, 1, 0); + this.CreateGloves(1, "Dragon Gloves", 52, 14, 6, 68, 120, 30, 0, 1, 0); + this.CreateGloves(2, "Pad Gloves", 3, 2, 0, 28, 20, 0, 1, 0, 0); + this.CreateGloves(3, "Legendary Gloves", 44, 11, 0, 42, 20, 0, 1, 0, 0); + this.CreateGloves(4, "Bone Gloves", 14, 5, 0, 30, 20, 0, 1, 0, 0); + this.CreateGloves(5, "Leather Gloves", 4, 2, 8, 30, 80, 0, 0, 1, 0); + this.CreateGloves(6, "Scale Gloves", 22, 7, 10, 40, 110, 0, 0, 1, 0); + this.CreateGloves(7, "Sphinx Gloves", 28, 8, 0, 36, 20, 0, 1, 0, 0); + this.CreateGloves(8, "Brass Gloves", 32, 9, 8, 44, 100, 30, 0, 1, 0); + this.CreateGloves(9, "Plate Gloves", 42, 12, 4, 50, 130, 0, 0, 1, 0); + this.CreateGloves(10, "Vine Gloves", 4, 2, 4, 22, 30, 60, 0, 0, 1); + this.CreateGloves(11, "Silk Gloves", 14, 4, 8, 26, 30, 70, 0, 0, 1); + this.CreateGloves(12, "Wind Gloves", 26, 6, 10, 32, 30, 80, 0, 0, 1); + this.CreateGloves(13, "Spirit Gloves", 38, 9, 4, 38, 40, 80, 0, 0, 1); + this.CreateGloves(14, "Guardian Gloves", 50, 15, 6, 45, 40, 80, 0, 0, 1); // Boots: - this.CreateArmor(0, 6, 2, 2, "Bronze Boots", 12, 4, 34, 80, 20, 0, 1, 0); - this.CreateArmor(1, 6, 2, 2, "Dragon Boots", 54, 15, 68, 120, 30, 0, 1, 0); - this.CreateArmor(2, 6, 2, 2, "Pad Boots", 4, 3, 28, 20, 0, 1, 0, 0); - this.CreateArmor(3, 6, 2, 2, "Legendary Boots", 46, 12, 42, 30, 0, 1, 0, 0); - this.CreateArmor(4, 6, 2, 2, "Bone Boots", 16, 6, 30, 30, 0, 1, 0, 0); - this.CreateArmor(5, 6, 2, 2, "Leather Boots", 5, 2, 30, 80, 0, 0, 1, 0); - this.CreateArmor(6, 6, 2, 2, "Scale Boots", 22, 8, 40, 110, 0, 0, 1, 0); - this.CreateArmor(7, 6, 2, 2, "Sphinx Boots", 30, 9, 36, 30, 0, 1, 0, 0); - this.CreateArmor(8, 6, 2, 2, "Brass Boots", 32, 10, 44, 100, 30, 0, 1, 0); - this.CreateArmor(9, 6, 2, 2, "Plate Boots", 42, 12, 50, 130, 0, 0, 1, 0); - this.CreateArmor(10, 6, 2, 2, "Vine Boots", 5, 2, 22, 30, 60, 0, 0, 1); - this.CreateArmor(11, 6, 2, 2, "Silk Boots", 15, 4, 26, 30, 70, 0, 0, 1); - this.CreateArmor(12, 6, 2, 2, "Wind Boots", 27, 7, 32, 30, 80, 0, 0, 1); - this.CreateArmor(13, 6, 2, 2, "Spirit Boots", 40, 10, 38, 40, 80, 0, 0, 1); - this.CreateArmor(14, 6, 2, 2, "Guardian Boots", 52, 16, 45, 40, 80, 0, 0, 1); + this.CreateBoots(0, 6, 2, 2, "Bronze Boots", 12, 4, 10, 34, 80, 20, 0, 1, 0); + this.CreateBoots(1, 6, 2, 2, "Dragon Boots", 54, 15, 2, 68, 120, 30, 0, 1, 0); + this.CreateBoots(2, 6, 2, 2, "Pad Boots", 4, 3, 10, 28, 20, 0, 1, 0, 0); + this.CreateBoots(3, 6, 2, 2, "Legendary Boots", 46, 12, 0, 42, 30, 0, 1, 0, 0); + this.CreateBoots(4, 6, 2, 2, "Bone Boots", 16, 6, 6, 30, 30, 0, 1, 0, 0); + this.CreateBoots(5, 6, 2, 2, "Leather Boots", 5, 2, 12, 30, 80, 0, 0, 1, 0); + this.CreateBoots(6, 6, 2, 2, "Scale Boots", 22, 8, 8, 40, 110, 0, 0, 1, 0); + this.CreateBoots(7, 6, 2, 2, "Sphinx Boots", 30, 9, 8, 36, 30, 0, 1, 0, 0); + this.CreateBoots(8, 6, 2, 2, "Brass Boots", 32, 10, 6, 44, 100, 30, 0, 1, 0); + this.CreateBoots(9, 6, 2, 2, "Plate Boots", 42, 12, 4, 50, 130, 0, 0, 1, 0); + this.CreateBoots(10, 6, 2, 2, "Vine Boots", 5, 2, 0, 22, 30, 60, 0, 0, 1); + this.CreateBoots(11, 6, 2, 2, "Silk Boots", 15, 4, 0, 26, 30, 70, 0, 0, 1); + this.CreateBoots(12, 6, 2, 2, "Wind Boots", 27, 7, 0, 32, 30, 80, 0, 0, 1); + this.CreateBoots(13, 6, 2, 2, "Spirit Boots", 40, 10, 0, 38, 40, 80, 0, 0, 1); + this.CreateBoots(14, 6, 2, 2, "Guardian Boots", 52, 16, 0, 45, 40, 80, 0, 0, 1); this.BuildSets(); } diff --git a/src/Persistence/Initialization/Version095d/Items/Armors.cs b/src/Persistence/Initialization/Version095d/Items/Armors.cs index f47264b19..59038b1a9 100644 --- a/src/Persistence/Initialization/Version095d/Items/Armors.cs +++ b/src/Persistence/Initialization/Version095d/Items/Armors.cs @@ -101,38 +101,38 @@ public override void Initialize() this.CreateArmor(14, 4, 2, 2, "Guardian Pants", 54, 25, 45, 40, 80, 0, 0, 1); // Gloves: - this.CreateArmor(0, 5, 2, 2, "Bronze Gloves", 13, 4, 34, 80, 20, 0, 1, 0); - this.CreateArmor(1, 5, 2, 2, "Dragon Gloves", 52, 14, 68, 120, 30, 0, 1, 0); - this.CreateArmor(2, 5, 2, 2, "Pad Gloves", 3, 2, 28, 20, 0, 1, 0, 0); - this.CreateArmor(3, 5, 2, 2, "Legendary Gloves", 44, 11, 42, 20, 0, 1, 0, 0); - this.CreateArmor(4, 5, 2, 2, "Bone Gloves", 14, 5, 30, 20, 0, 1, 0, 0); - this.CreateArmor(5, 5, 2, 2, "Leather Gloves", 4, 2, 30, 80, 0, 0, 1, 0); - this.CreateArmor(6, 5, 2, 2, "Scale Gloves", 22, 7, 40, 110, 0, 0, 1, 0); - this.CreateArmor(7, 5, 2, 2, "Sphinx Gloves", 28, 8, 36, 20, 0, 1, 0, 0); - this.CreateArmor(8, 5, 2, 2, "Brass Gloves", 32, 9, 44, 100, 30, 0, 1, 0); - this.CreateArmor(9, 5, 2, 2, "Plate Gloves", 42, 12, 50, 130, 0, 0, 1, 0); - this.CreateArmor(10, 5, 2, 2, "Vine Gloves", 4, 2, 22, 30, 60, 0, 0, 1); - this.CreateArmor(11, 5, 2, 2, "Silk Gloves", 14, 4, 26, 30, 70, 0, 0, 1); - this.CreateArmor(12, 5, 2, 2, "Wind Gloves", 26, 6, 32, 30, 80, 0, 0, 1); - this.CreateArmor(13, 5, 2, 2, "Spirit Gloves", 38, 9, 38, 40, 80, 0, 0, 1); - this.CreateArmor(14, 5, 2, 2, "Guardian Gloves", 50, 15, 45, 40, 80, 0, 0, 1); + this.CreateGloves(0, "Bronze Gloves", 13, 4, 4, 34, 80, 20, 0, 1, 0); + this.CreateGloves(1, "Dragon Gloves", 52, 14, 6, 68, 120, 30, 0, 1, 0); + this.CreateGloves(2, "Pad Gloves", 3, 2, 0, 28, 20, 0, 1, 0, 0); + this.CreateGloves(3, "Legendary Gloves", 44, 11, 0, 42, 20, 0, 1, 0, 0); + this.CreateGloves(4, "Bone Gloves", 14, 5, 0, 30, 20, 0, 1, 0, 0); + this.CreateGloves(5, "Leather Gloves", 4, 2, 8, 30, 80, 0, 0, 1, 0); + this.CreateGloves(6, "Scale Gloves", 22, 7, 10, 40, 110, 0, 0, 1, 0); + this.CreateGloves(7, "Sphinx Gloves", 28, 8, 0, 36, 20, 0, 1, 0, 0); + this.CreateGloves(8, "Brass Gloves", 32, 9, 8, 44, 100, 30, 0, 1, 0); + this.CreateGloves(9, "Plate Gloves", 42, 12, 4, 50, 130, 0, 0, 1, 0); + this.CreateGloves(10, "Vine Gloves", 4, 2, 4, 22, 30, 60, 0, 0, 1); + this.CreateGloves(11, "Silk Gloves", 14, 4, 8, 26, 30, 70, 0, 0, 1); + this.CreateGloves(12, "Wind Gloves", 26, 6, 10, 32, 30, 80, 0, 0, 1); + this.CreateGloves(13, "Spirit Gloves", 38, 9, 4, 38, 40, 80, 0, 0, 1); + this.CreateGloves(14, "Guardian Gloves", 50, 15, 6, 45, 40, 80, 0, 0, 1); // Boots: - this.CreateArmor(0, 6, 2, 2, "Bronze Boots", 12, 4, 34, 80, 20, 0, 1, 0); - this.CreateArmor(1, 6, 2, 2, "Dragon Boots", 54, 15, 68, 120, 30, 0, 1, 0); - this.CreateArmor(2, 6, 2, 2, "Pad Boots", 4, 3, 28, 20, 0, 1, 0, 0); - this.CreateArmor(3, 6, 2, 2, "Legendary Boots", 46, 12, 42, 30, 0, 1, 0, 0); - this.CreateArmor(4, 6, 2, 2, "Bone Boots", 16, 6, 30, 30, 0, 1, 0, 0); - this.CreateArmor(5, 6, 2, 2, "Leather Boots", 5, 2, 30, 80, 0, 0, 1, 0); - this.CreateArmor(6, 6, 2, 2, "Scale Boots", 22, 8, 40, 110, 0, 0, 1, 0); - this.CreateArmor(7, 6, 2, 2, "Sphinx Boots", 30, 9, 36, 30, 0, 1, 0, 0); - this.CreateArmor(8, 6, 2, 2, "Brass Boots", 32, 10, 44, 100, 30, 0, 1, 0); - this.CreateArmor(9, 6, 2, 2, "Plate Boots", 42, 12, 50, 130, 0, 0, 1, 0); - this.CreateArmor(10, 6, 2, 2, "Vine Boots", 5, 2, 22, 30, 60, 0, 0, 1); - this.CreateArmor(11, 6, 2, 2, "Silk Boots", 15, 4, 26, 30, 70, 0, 0, 1); - this.CreateArmor(12, 6, 2, 2, "Wind Boots", 27, 7, 32, 30, 80, 0, 0, 1); - this.CreateArmor(13, 6, 2, 2, "Spirit Boots", 40, 10, 38, 40, 80, 0, 0, 1); - this.CreateArmor(14, 6, 2, 2, "Guardian Boots", 52, 16, 45, 40, 80, 0, 0, 1); + this.CreateBoots(0, 6, 2, 2, "Bronze Boots", 12, 4, 10, 34, 80, 20, 0, 1, 0); + this.CreateBoots(1, 6, 2, 2, "Dragon Boots", 54, 15, 2, 68, 120, 30, 0, 1, 0); + this.CreateBoots(2, 6, 2, 2, "Pad Boots", 4, 3, 10, 28, 20, 0, 1, 0, 0); + this.CreateBoots(3, 6, 2, 2, "Legendary Boots", 46, 12, 0, 42, 30, 0, 1, 0, 0); + this.CreateBoots(4, 6, 2, 2, "Bone Boots", 16, 6, 6, 30, 30, 0, 1, 0, 0); + this.CreateBoots(5, 6, 2, 2, "Leather Boots", 5, 2, 12, 30, 80, 0, 0, 1, 0); + this.CreateBoots(6, 6, 2, 2, "Scale Boots", 22, 8, 8, 40, 110, 0, 0, 1, 0); + this.CreateBoots(7, 6, 2, 2, "Sphinx Boots", 30, 9, 8, 36, 30, 0, 1, 0, 0); + this.CreateBoots(8, 6, 2, 2, "Brass Boots", 32, 10, 6, 44, 100, 30, 0, 1, 0); + this.CreateBoots(9, 6, 2, 2, "Plate Boots", 42, 12, 4, 50, 130, 0, 0, 1, 0); + this.CreateBoots(10, 6, 2, 2, "Vine Boots", 5, 2, 0, 22, 30, 60, 0, 0, 1); + this.CreateBoots(11, 6, 2, 2, "Silk Boots", 15, 4, 0, 26, 30, 70, 0, 0, 1); + this.CreateBoots(12, 6, 2, 2, "Wind Boots", 27, 7, 0, 32, 30, 80, 0, 0, 1); + this.CreateBoots(13, 6, 2, 2, "Spirit Boots", 40, 10, 0, 38, 40, 80, 0, 0, 1); + this.CreateBoots(14, 6, 2, 2, "Guardian Boots", 52, 16, 0, 45, 40, 80, 0, 0, 1); this.BuildSets(); } diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Armors.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Armors.cs index 3870cd285..6abdca791 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Armors.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Armors.cs @@ -232,118 +232,118 @@ public override void Initialize() this.CreateArmor(73, 4, 2, 2, "Phoenix Soul Pants", 134, 68, 88, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); // Gloves: - this.CreateArmor(0, 5, 2, 2, "Bronze Gloves", 13, 4, 34, 0, 80, 20, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0); - this.CreateArmor(1, 5, 2, 2, "Dragon Gloves", 52, 14, 68, 0, 120, 30, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0); - this.CreateArmor(2, 5, 2, 2, "Pad Gloves", 3, 2, 28, 0, 20, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); - this.CreateArmor(3, 5, 2, 2, "Legendary Gloves", 44, 11, 42, 0, 20, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); - this.CreateArmor(4, 5, 2, 2, "Bone Gloves", 14, 5, 30, 0, 20, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); - this.CreateArmor(5, 5, 2, 2, "Leather Gloves", 4, 2, 30, 0, 80, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0); - this.CreateArmor(6, 5, 2, 2, "Scale Gloves", 22, 7, 40, 0, 110, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0); - this.CreateArmor(7, 5, 2, 2, "Sphinx Gloves", 28, 8, 36, 0, 20, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); - this.CreateArmor(8, 5, 2, 2, "Brass Gloves", 32, 9, 44, 0, 100, 30, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0); - this.CreateArmor(9, 5, 2, 2, "Plate Gloves", 42, 12, 50, 0, 130, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0); - this.CreateArmor(10, 5, 2, 2, "Vine Gloves", 4, 2, 22, 0, 30, 60, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(11, 5, 2, 2, "Silk Gloves", 14, 4, 26, 0, 30, 70, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(12, 5, 2, 2, "Wind Gloves", 26, 6, 32, 0, 30, 80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(13, 5, 2, 2, "Spirit Gloves", 38, 9, 38, 0, 40, 80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(14, 5, 2, 2, "Guardian Gloves", 50, 15, 45, 0, 40, 80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(15, 5, 2, 2, "Storm Crow Gloves", 70, 20, 80, 0, 150, 70, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(16, 5, 2, 2, "Black Dragon Gloves", 76, 22, 74, 0, 170, 60, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); - this.CreateArmor(17, 5, 2, 2, "Dark Phoenix Gloves", 86, 37, 80, 0, 205, 63, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0); - this.CreateArmor(18, 5, 2, 2, "Grand Soul Gloves", 70, 20, 67, 0, 49, 10, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0); - this.CreateArmor(19, 5, 2, 2, "Divine Gloves", 72, 29, 74, 0, 50, 110, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0); - this.CreateArmor(20, 5, 2, 2, "Thunder Hawk Gloves", 88, 34, 82, 0, 150, 70, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(21, 5, 2, 2, "Great Dragon Gloves", 94, 48, 86, 0, 200, 58, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0); - this.CreateArmor(22, 5, 2, 2, "Dark Soul Gloves", 87, 30, 75, 0, 55, 18, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0); - this.CreateArmor(23, 5, 2, 2, "Hurricane Gloves", 102, 45, 90, 0, 162, 66, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(24, 5, 2, 2, "Red Spirit Gloves", 84, 38, 80, 0, 52, 115, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0); - this.CreateArmor(25, 5, 2, 2, "Light Plate Gloves", 42, 12, 42, 0, 70, 20, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(26, 5, 2, 2, "Adamantine Gloves", 57, 18, 56, 0, 77, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(27, 5, 2, 2, "Dark Steel Gloves", 75, 21, 70, 0, 84, 22, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(28, 5, 2, 2, "Dark Master Gloves", 89, 29, 78, 0, 80, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(29, 5, 2, 2, "Dragon Knight Gloves", 114, 60, 90, 380, 170, 60, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0); - this.CreateArmor(30, 5, 2, 2, "Venom Mist Gloves", 111, 44, 86, 380, 44, 15, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0); - this.CreateArmor(31, 5, 2, 2, "Sylphid Ray Gloves", 111, 50, 86, 380, 38, 80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0); - this.CreateArmor(32, 5, 2, 2, "Volcano Gloves", 127, 55, 95, 380, 145, 60, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(33, 5, 2, 2, "Sunlight Gloves", 110, 40, 82, 380, 62, 16, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(34, 5, 2, 2, "Ashcrow Gloves", 61, 18, 72, 0, 160, 50, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); - this.CreateArmor(35, 5, 2, 2, "Eclipse Gloves", 61, 15, 54, 0, 53, 12, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); - this.CreateArmor(36, 5, 2, 2, "Iris Gloves", 61, 22, 59, 0, 50, 70, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(37, 5, 2, 2, "Valiant Gloves", 91, 27, 81, 0, 155, 50, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(38, 5, 2, 2, "Glorious Gloves", 91, 25, 74, 0, 80, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(39, 5, 2, 2, "Mistery Gloves", 24, 9, 36, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); - this.CreateArmor(40, 5, 2, 2, "Red Wing Gloves", 44, 13, 42, 0, 18, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); - this.CreateArmor(41, 5, 2, 2, "Ancient Gloves", 61, 19, 54, 0, 52, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); - this.CreateArmor(42, 5, 2, 2, "Black Rose Gloves", 70, 26, 67, 0, 50, 10, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); - this.CreateArmor(43, 5, 2, 2, "Aura Gloves", 87, 34, 75, 0, 56, 20, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); - this.CreateArmor(44, 5, 2, 2, "Lilium Gloves", 82, 45, 80, 0, 75, 20, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); - this.CreateArmor(45, 5, 2, 2, "Titan Gloves", 100, 56, 86, 0, 222, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); - this.CreateArmor(46, 5, 2, 2, "Brave Gloves", 97, 42, 86, 0, 74, 162, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); - this.CreateArmor(47, 5, 2, 2, "Destory Gloves", 101, 49, 86, 0, 212, 57, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(48, 5, 2, 2, "Phantom Gloves", 99, 40, 86, 0, 62, 19, 165, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(49, 5, 2, 2, "Seraphim Gloves", 100, 43, 86, 0, 55, 197, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(50, 5, 2, 2, "Faith Gloves", 95, 36, 86, 0, 32, 29, 138, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(51, 5, 2, 2, "Paewang Gloves", 101, 34, 86, 0, 105, 38, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(52, 5, 2, 2, "Hades Gloves", 100, 31, 86, 0, 60, 15, 181, 0, 0, 1, 0, 0, 0, 0, 0, 0); + this.CreateGloves(0, "Bronze Gloves", 13, 4, 4, 34, 0, 80, 20, 0, 1, 0, 1, 1, 0); + this.CreateGloves(1, "Dragon Gloves", 52, 14, 6, 68, 0, 120, 30, 0, 1, 0, 1, 0, 0); + this.CreateGloves(2, "Pad Gloves", 3, 2, 0, 28, 0, 20, 0, 1, 0, 0, 1, 0, 0); + this.CreateGloves(3, "Legendary Gloves", 44, 11, 0, 42, 0, 20, 0, 1, 0, 0, 1, 0, 0); + this.CreateGloves(4, "Bone Gloves", 14, 5, 0, 30, 0, 20, 0, 1, 0, 0, 1, 0, 0); + this.CreateGloves(5, "Leather Gloves", 4, 2, 8, 30, 0, 80, 0, 0, 1, 0, 1, 1, 0); + this.CreateGloves(6, "Scale Gloves", 22, 7, 10, 40, 0, 110, 0, 0, 1, 0, 1, 1, 0); + this.CreateGloves(7, "Sphinx Gloves", 28, 8, 0, 36, 0, 20, 0, 1, 0, 0, 1, 0, 0); + this.CreateGloves(8, "Brass Gloves", 32, 9, 8, 44, 0, 100, 30, 0, 1, 0, 1, 0, 0); + this.CreateGloves(9, "Plate Gloves", 42, 12, 4, 50, 0, 130, 0, 0, 1, 0, 1, 0, 0); + this.CreateGloves(10, "Vine Gloves", 4, 2, 4, 22, 0, 30, 60, 0, 0, 1, 0, 0, 0); + this.CreateGloves(11, "Silk Gloves", 14, 4, 8, 26, 0, 30, 70, 0, 0, 1, 0, 0, 0); + this.CreateGloves(12, "Wind Gloves", 26, 6, 10, 32, 0, 30, 80, 0, 0, 1, 0, 0, 0); + this.CreateGloves(13, "Spirit Gloves", 38, 9, 4, 38, 0, 40, 80, 0, 0, 1, 0, 0, 0); + this.CreateGloves(14, "Guardian Gloves", 50, 15, 6, 45, 0, 40, 80, 0, 0, 1, 0, 0, 0); + this.CreateGloves(15, "Storm Crow Gloves", 70, 20, 6, 80, 0, 150, 70, 0, 0, 0, 1, 0, 0); + this.CreateGloves(16, "Black Dragon Gloves", 76, 22, 6, 74, 0, 170, 60, 0, 1, 0, 0, 0, 0); + this.CreateGloves(17, "Dark Phoenix Gloves", 86, 37, 6, 80, 0, 205, 63, 0, 2, 0, 0, 0, 0); + this.CreateGloves(18, "Grand Soul Gloves", 70, 20, 5, 67, 0, 49, 10, 2, 0, 0, 0, 0, 0); + this.CreateGloves(19, "Divine Gloves", 72, 29, 6, 74, 0, 50, 110, 0, 0, 2, 0, 0, 0); + this.CreateGloves(20, "Thunder Hawk Gloves", 88, 34, 7, 82, 0, 150, 70, 0, 0, 0, 1, 0, 0); + this.CreateGloves(21, "Great Dragon Gloves", 94, 48, 6, 86, 0, 200, 58, 0, 2, 0, 0, 0, 0); + this.CreateGloves(22, "Dark Soul Gloves", 87, 30, 6, 75, 0, 55, 18, 2, 0, 0, 0, 0, 0); + this.CreateGloves(23, "Hurricane Gloves", 102, 45, 7, 90, 0, 162, 66, 0, 0, 0, 1, 0, 0); + this.CreateGloves(24, "Red Spirit Gloves", 84, 38, 6, 80, 0, 52, 115, 0, 0, 2, 0, 0, 0); + this.CreateGloves(25, "Light Plate Gloves", 42, 12, 7, 42, 0, 70, 20, 0, 0, 0, 0, 1, 0); + this.CreateGloves(26, "Adamantine Gloves", 57, 18, 6, 56, 0, 77, 21, 0, 0, 0, 0, 1, 0); + this.CreateGloves(27, "Dark Steel Gloves", 75, 21, 5, 70, 0, 84, 22, 0, 0, 0, 0, 1, 0); + this.CreateGloves(28, "Dark Master Gloves", 89, 29, 4, 78, 0, 80, 21, 0, 0, 0, 0, 1, 0); + this.CreateGloves(29, "Dragon Knight Gloves", 114, 60, 7, 90, 380, 170, 60, 0, 2, 0, 0, 0, 0); + this.CreateGloves(30, "Venom Mist Gloves", 111, 44, 7, 86, 380, 44, 15, 2, 0, 0, 0, 0, 0); + this.CreateGloves(31, "Sylphid Ray Gloves", 111, 50, 7, 86, 380, 38, 80, 0, 0, 2, 0, 0, 0); + this.CreateGloves(32, "Volcano Gloves", 127, 55, 7, 95, 380, 145, 60, 0, 0, 0, 1, 0, 0); + this.CreateGloves(33, "Sunlight Gloves", 110, 40, 5, 82, 380, 62, 16, 0, 0, 0, 0, 1, 0); + this.CreateGloves(34, "Ashcrow Gloves", 61, 18, 6, 72, 0, 160, 50, 0, 1, 0, 0, 0, 0); + this.CreateGloves(35, "Eclipse Gloves", 61, 15, 6, 54, 0, 53, 12, 1, 0, 0, 0, 0, 0); + this.CreateGloves(36, "Iris Gloves", 61, 22, 6, 59, 0, 50, 70, 0, 0, 1, 0, 0, 0); + this.CreateGloves(37, "Valiant Gloves", 91, 27, 7, 81, 0, 155, 50, 0, 0, 0, 1, 0, 0); + this.CreateGloves(38, "Glorious Gloves", 91, 25, 5, 74, 0, 80, 21, 0, 0, 0, 0, 1, 0); + this.CreateGloves(39, "Mistery Gloves", 24, 9, 6, 36, 0, 22, 0, 0, 0, 0, 0, 0, 1); + this.CreateGloves(40, "Red Wing Gloves", 44, 13, 8, 42, 0, 18, 4, 0, 0, 0, 0, 0, 1); + this.CreateGloves(41, "Ancient Gloves", 61, 19, 7, 54, 0, 52, 16, 0, 0, 0, 0, 0, 1); + this.CreateGloves(42, "Black Rose Gloves", 70, 26, 6, 67, 0, 50, 10, 0, 0, 0, 0, 0, 2); + this.CreateGloves(43, "Aura Gloves", 87, 34, 6, 75, 0, 56, 20, 0, 0, 0, 0, 0, 2); + this.CreateGloves(44, "Lilium Gloves", 82, 45, 6, 80, 0, 75, 20, 0, 0, 0, 0, 0, 2); + this.CreateGloves(45, "Titan Gloves", 100, 56, 7, 86, 0, 222, 32, 0, 1, 0, 0, 0, 0); + this.CreateGloves(46, "Brave Gloves", 97, 42, 7, 86, 0, 74, 162, 0, 1, 0, 0, 0, 0); + this.CreateGloves(47, "Destory Gloves", 101, 49, 7, 86, 0, 212, 57, 0, 0, 0, 1, 0, 0); + this.CreateGloves(48, "Phantom Gloves", 99, 40, 7, 86, 0, 62, 19, 0, 0, 0, 1, 0, 0); + this.CreateGloves(49, "Seraphim Gloves", 100, 43, 7, 86, 0, 55, 197, 0, 0, 1, 0, 0, 0); + this.CreateGloves(50, "Faith Gloves", 95, 36, 7, 86, 0, 32, 29, 0, 0, 1, 0, 0, 0); + this.CreateGloves(51, "Paewang Gloves", 101, 34, 7, 86, 0, 105, 38, 0, 0, 0, 0, 1, 0); + this.CreateGloves(52, "Hades Gloves", 100, 31, 7, 86, 0, 60, 15, 1, 0, 0, 0, 0, 0); // Boots: - this.CreateArmor(0, 6, 2, 2, "Bronze Boots", 12, 4, 34, 0, 80, 20, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0); - this.CreateArmor(1, 6, 2, 2, "Dragon Boots", 54, 15, 68, 0, 120, 30, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0); - this.CreateArmor(2, 6, 2, 2, "Pad Boots", 4, 3, 28, 0, 20, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); - this.CreateArmor(3, 6, 2, 2, "Legendary Boots", 46, 12, 42, 0, 30, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); - this.CreateArmor(4, 6, 2, 2, "Bone Boots", 16, 6, 30, 0, 30, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); - this.CreateArmor(5, 6, 2, 2, "Leather Boots", 5, 2, 30, 0, 80, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1); - this.CreateArmor(6, 6, 2, 2, "Scale Boots", 22, 8, 40, 0, 110, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1); - this.CreateArmor(7, 6, 2, 2, "Sphinx Boots", 30, 9, 36, 0, 30, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); - this.CreateArmor(8, 6, 2, 2, "Brass Boots", 32, 10, 44, 0, 100, 30, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); - this.CreateArmor(9, 6, 2, 2, "Plate Boots", 42, 12, 50, 0, 130, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); - this.CreateArmor(10, 6, 2, 2, "Vine Boots", 5, 2, 22, 0, 30, 60, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(11, 6, 2, 2, "Silk Boots", 15, 4, 26, 0, 30, 70, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(12, 6, 2, 2, "Wind Boots", 27, 7, 32, 0, 30, 80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(13, 6, 2, 2, "Spirit Boots", 40, 10, 38, 0, 40, 80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(14, 6, 2, 2, "Guardian Boots", 52, 16, 45, 0, 40, 80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(15, 6, 2, 2, "Storm Crow Boots", 72, 22, 80, 0, 150, 70, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(16, 6, 2, 2, "Black Dragon Boots", 78, 24, 74, 0, 170, 60, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); - this.CreateArmor(17, 6, 2, 2, "Dark Phoenix Boots", 93, 40, 80, 0, 198, 60, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0); - this.CreateArmor(18, 6, 2, 2, "Grand Soul Boots", 76, 22, 67, 0, 59, 10, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0); - this.CreateArmor(19, 6, 2, 2, "Divine Boots", 81, 30, 74, 0, 50, 110, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0); - this.CreateArmor(20, 6, 2, 2, "Thunder Hawk Boots", 92, 37, 82, 0, 150, 70, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(21, 6, 2, 2, "Great Dragon Boots", 98, 50, 86, 0, 200, 58, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0); - this.CreateArmor(22, 6, 2, 2, "Dark Soul Boots", 95, 31, 75, 0, 55, 18, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0); - this.CreateArmor(23, 6, 2, 2, "Hurricane Boots", 110, 50, 90, 0, 162, 66, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(24, 6, 2, 2, "Red Spirit Boots", 87, 40, 80, 0, 52, 115, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0); - this.CreateArmor(25, 6, 2, 2, "Light Plate Boots", 45, 13, 42, 0, 70, 20, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(26, 6, 2, 2, "Adamantine Boots", 60, 20, 56, 0, 77, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(27, 6, 2, 2, "Dark Steel Boots", 83, 25, 70, 0, 84, 22, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(28, 6, 2, 2, "Dark Master Boots", 95, 33, 78, 0, 80, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(29, 6, 2, 2, "Dragon Knight Boots", 119, 63, 90, 380, 170, 60, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0); - this.CreateArmor(30, 6, 2, 2, "Venom Mist Boots", 119, 47, 86, 380, 44, 15, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0); - this.CreateArmor(31, 6, 2, 2, "Sylphid Ray Boots", 119, 53, 86, 380, 38, 80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0); - this.CreateArmor(32, 6, 2, 2, "Volcano Boots", 131, 61, 95, 380, 145, 60, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(33, 6, 2, 2, "Sunlight Boots", 121, 44, 82, 380, 62, 16, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(34, 6, 2, 2, "Ashcrow Boots", 68, 19, 72, 0, 160, 50, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); - this.CreateArmor(35, 6, 2, 2, "Eclipse Boots", 68, 17, 54, 0, 53, 12, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); - this.CreateArmor(36, 6, 2, 2, "Iris Boots", 68, 23, 59, 0, 50, 70, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(37, 6, 2, 2, "Valiant Boots", 98, 29, 81, 0, 155, 50, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(38, 6, 2, 2, "Glorious Boots", 98, 29, 74, 0, 80, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(39, 6, 2, 2, "Mistery Boots", 26, 11, 36, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); - this.CreateArmor(40, 6, 2, 2, "Red Wing Boots", 46, 15, 42, 0, 25, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); - this.CreateArmor(41, 6, 2, 2, "Ancient Boots", 65, 21, 54, 0, 53, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); - this.CreateArmor(42, 6, 2, 2, "Black Rose Boots", 76, 28, 67, 0, 60, 10, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); - this.CreateArmor(43, 6, 2, 2, "Aura Boots", 95, 38, 75, 0, 57, 20, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); - this.CreateArmor(44, 6, 2, 2, "Lilium Boots", 90, 50, 85, 0, 150, 30, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); - this.CreateArmor(45, 6, 2, 2, "Titan Boots", 96, 57, 86, 0, 222, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); - this.CreateArmor(46, 6, 2, 2, "Brave Boots", 93, 45, 86, 0, 74, 162, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); - this.CreateArmor(47, 6, 2, 2, "Destory Boots", 97, 54, 86, 0, 212, 57, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(48, 6, 2, 2, "Phantom Boots", 94, 44, 86, 0, 62, 19, 165, 0, 0, 0, 0, 0, 1, 0, 0, 0); - this.CreateArmor(49, 6, 2, 2, "Seraphim Boots", 97, 42, 86, 0, 55, 197, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(50, 6, 2, 2, "Faith Boots", 92, 35, 86, 0, 32, 29, 138, 0, 0, 0, 0, 1, 0, 0, 0, 0); - this.CreateArmor(51, 6, 2, 2, "Phaewang Boots", 98, 38, 86, 0, 105, 38, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateArmor(52, 6, 2, 2, "Hades Boots", 94, 34, 86, 0, 60, 15, 181, 0, 0, 1, 0, 0, 0, 0, 0, 0); - this.CreateArmor(59, 6, 2, 2, "Sacred Boots", 50, 20, 52, 1, 85, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 1); - this.CreateArmor(60, 6, 2, 2, "Storm Hard Boots", 62, 28, 68, 1, 100, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 1); - this.CreateArmor(61, 6, 2, 2, "Piercing Boots", 82, 36, 82, 1, 115, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1); - this.CreateArmor(73, 6, 2, 2, "Phoenix Soul Boots", 119, 57, 88, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + this.CreateBoots(0, "Bronze Boots", 12, 4, 10, 34, 0, 80, 20, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0); + this.CreateBoots(1, "Dragon Boots", 54, 15, 2, 68, 0, 120, 30, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0); + this.CreateBoots(2, "Pad Boots", 4, 3, 10, 28, 0, 20, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); + this.CreateBoots(3, "Legendary Boots", 46, 12, 0, 42, 0, 30, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); + this.CreateBoots(4, "Bone Boots", 16, 6, 6, 30, 0, 30, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); + this.CreateBoots(5, "Leather Boots", 5, 2, 12, 30, 0, 80, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1); + this.CreateBoots(6, "Scale Boots", 22, 8, 8, 40, 0, 110, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1); + this.CreateBoots(7, "Sphinx Boots", 30, 9, 8, 36, 0, 30, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0); + this.CreateBoots(8, "Brass Boots", 32, 10, 6, 44, 0, 100, 30, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); + this.CreateBoots(9, "Plate Boots", 42, 12, 4, 50, 0, 130, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); + this.CreateBoots(10, "Vine Boots", 5, 2, 0, 22, 0, 30, 60, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); + this.CreateBoots(11, "Silk Boots", 15, 4, 0, 26, 0, 30, 70, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); + this.CreateBoots(12, "Wind Boots", 27, 7, 0, 32, 0, 30, 80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); + this.CreateBoots(13, "Spirit Boots", 40, 10, 0, 38, 0, 40, 80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); + this.CreateBoots(14, "Guardian Boots", 52, 16, 0, 45, 0, 40, 80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); + this.CreateBoots(15, "Storm Crow Boots", 72, 22, 2, 80, 0, 150, 70, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); + this.CreateBoots(16, "Black Dragon Boots", 78, 24, 2, 74, 0, 170, 60, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); + this.CreateBoots(17, "Dark Phoenix Boots", 93, 40, 2, 80, 0, 198, 60, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0); + this.CreateBoots(18, "Grand Soul Boots", 76, 22, 0, 67, 0, 59, 10, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0); + this.CreateBoots(19, "Divine Boots", 81, 30, 0, 74, 0, 50, 110, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0); + this.CreateBoots(20, "Thunder Hawk Boots", 92, 37, 2, 82, 0, 150, 70, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); + this.CreateBoots(21, "Great Dragon Boots", 98, 50, 0, 86, 0, 200, 58, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0); + this.CreateBoots(22, "Dark Soul Boots", 95, 31, 0, 75, 0, 55, 18, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0); + this.CreateBoots(23, "Hurricane Boots", 110, 50, 0, 90, 0, 162, 66, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); + this.CreateBoots(24, "Red Spirit Boots", 87, 40, 0, 80, 0, 52, 115, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0); + this.CreateBoots(25, "Light Plate Boots", 45, 13, 0, 42, 0, 70, 20, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); + this.CreateBoots(26, "Adamantine Boots", 60, 20, 0, 56, 0, 77, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); + this.CreateBoots(27, "Dark Steel Boots", 83, 25, 0, 70, 0, 84, 22, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); + this.CreateBoots(28, "Dark Master Boots", 95, 33, 0, 78, 0, 80, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); + this.CreateBoots(29, "Dragon Knight Boots", 119, 63, 0, 90, 380, 170, 60, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0); + this.CreateBoots(30, "Venom Mist Boots", 119, 47, 0, 86, 380, 44, 15, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0); + this.CreateBoots(31, "Sylphid Ray Boots", 119, 53, 0, 86, 380, 38, 80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0); + this.CreateBoots(32, "Volcano Boots", 131, 61, 0, 95, 380, 145, 60, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); + this.CreateBoots(33, "Sunlight Boots", 121, 44, 0, 82, 380, 62, 16, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); + this.CreateBoots(34, "Ashcrow Boots", 68, 19, 0, 72, 0, 160, 50, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); + this.CreateBoots(35, "Eclipse Boots", 68, 17, 0, 54, 0, 53, 12, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0); + this.CreateBoots(36, "Iris Boots", 68, 23, 0, 59, 0, 50, 70, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); + this.CreateBoots(37, "Valiant Boots", 98, 29, 0, 81, 0, 155, 50, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); + this.CreateBoots(38, "Glorious Boots", 98, 29, 0, 74, 0, 80, 21, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); + this.CreateBoots(39, "Mistery Boots", 26, 11, 0, 36, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); + this.CreateBoots(40, "Red Wing Boots", 46, 15, 0, 42, 0, 25, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); + this.CreateBoots(41, "Ancient Boots", 65, 21, 0, 54, 0, 53, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); + this.CreateBoots(42, "Black Rose Boots", 76, 28, 0, 67, 0, 60, 10, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); + this.CreateBoots(43, "Aura Boots", 95, 38, 0, 75, 0, 57, 20, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); + this.CreateBoots(44, "Lilium Boots", 90, 50, 0, 85, 0, 150, 30, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); + this.CreateBoots(45, "Titan Boots", 96, 57, 0, 86, 0, 222, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); + this.CreateBoots(46, "Brave Boots", 93, 45, 0, 86, 0, 74, 162, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); + this.CreateBoots(47, "Destory Boots", 97, 54, 0, 86, 0, 212, 57, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0); + this.CreateBoots(48, "Phantom Boots", 94, 44, 0, 86, 0, 62, 19, 165, 0, 0, 0, 0, 0, 1, 0, 0, 0); + this.CreateBoots(49, "Seraphim Boots", 97, 42, 0, 86, 0, 55, 197, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); + this.CreateBoots(50, "Faith Boots", 92, 35, 0, 86, 0, 32, 29, 138, 0, 0, 0, 0, 1, 0, 0, 0, 0); + this.CreateBoots(51, "Phaewang Boots", 98, 38, 0, 86, 0, 105, 38, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0); + this.CreateBoots(52, "Hades Boots", 94, 34, 0, 86, 0, 60, 15, 181, 0, 0, 1, 0, 0, 0, 0, 0, 0); + this.CreateBoots(59, "Sacred Boots", 50, 20, 0, 52, 1, 85, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 1); + this.CreateBoots(60, "Storm Hard Boots", 62, 28, 0, 68, 1, 100, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 1); + this.CreateBoots(61, "Piercing Boots", 82, 36, 0, 82, 1, 115, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1); + this.CreateBoots(73, "Phoenix Soul Boots", 119, 57, 0, 88, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); this.BuildSets(); this.AddGuardianOptionsToSets(); diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs index 3e599e81b..b1e768fa6 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs @@ -167,7 +167,7 @@ public override void Initialize() this.CreateWeapon(2, 10, 0, 66, 1, 4, true, "Great Scepter", 82, 74, 85, 45, 65, 35, 0, 100, 21, 0, 0, 0, 0, 0, 0, 1, 0, 0); this.CreateWeapon(2, 11, 0, 66, 1, 4, true, "Lord Scepter", 98, 91, 102, 40, 72, 52, 0, 105, 23, 0, 0, 0, 0, 0, 0, 1, 0, 0); this.CreateWeapon(2, 12, 0, 66, 1, 4, true, "Great Lord Scepter", 140, 108, 120, 40, 84, 67, 0, 90, 20, 0, 0, 0, 0, 0, 0, 1, 0, 0); - this.CreateWeapon(2, 13, 0, 66, 1, 4, false, "Divine Scepter of Archangel", 150, 120, 143, 40, 90, 78, 0, 75, 16, 0, 0, 0, 0, 0, 0, 1, 0, 0); + this.CreateWeapon(2, 13, 0, 66, 1, 4, false, "Divine Scepter of Archangel", 150, 120, 143, 45, 90, 78, 0, 75, 16, 0, 0, 0, 0, 0, 0, 1, 0, 0); this.CreateWeapon(2, 14, 0, 66, 1, 4, true, "Soleil Scepter", 146, 130, 153, 40, 95, 84, 380, 80, 15, 0, 0, 0, 0, 0, 0, 1, 0, 0); this.CreateWeapon(2, 15, 0, 66, 1, 4, true, "Shining Scepter", 110, 99, 111, 40, 78, 60, 0, 108, 22, 0, 0, 0, 0, 0, 0, 1, 0, 0); this.CreateWeapon(2, 16, 0, 0, 1, 3, true, "Frost mace", 121, 106, 146, 50, 80, 0, 0, 27, 19, 0, 0, 0, 0, 2, 0, 0, 0, 0); From 7fb2294d9f26d15688d097274853dc3f4d7b36fb Mon Sep 17 00:00:00 2001 From: sven-n Date: Thu, 17 Oct 2024 21:47:44 +0200 Subject: [PATCH 02/11] Refactored stats updates and consolidated extended messages --- ...1-26-FE-MaximumStatsExtended_by-server.md} | 12 +- ...urrentHealthAndShieldExtended_by-server.md | 20 - ...C1-26-FF-CurrentStatsExtended_by-server.md | 24 ++ ...MaximumManaAndAbilityExtended_by-server.md | 20 - ...CurrentManaAndAbilityExtended_by-server.md | 20 - docs/Packets/ServerToClient.md | 6 +- src/GameLogic/AttackableExtensions.cs | 11 +- src/GameLogic/Player.cs | 38 +- .../AlcoholConsumeHandlerPlugIn.cs | 1 + .../HealthPotionConsumeHandlerPlugIn.cs | 2 +- .../ManaPotionConsumehandler.cs | 2 +- .../Skills/DrainLifeSkillPlugIn.cs | 2 +- .../Character/IUpdateCurrentHealthPlugIn.cs | 16 - .../Character/IUpdateCurrentManaPlugIn.cs | 16 - .../Character/IUpdateMaximumHealthPlugIn.cs | 16 - .../Character/IUpdateMaximumManaPlugIn.cs | 16 - .../Views/Character/IUpdateStatsPlugIn.cs | 53 +++ .../UpdateCurrentHealthExtendedPlugIn.cs | 42 --- .../Character/UpdateCurrentHealthPlugIn.cs | 40 -- .../UpdateCurrentManaExtendedPlugIn.cs | 42 --- .../Character/UpdateCurrentManaPlugIn.cs | 40 -- .../UpdateMaximumHealthExtendedPlugIn.cs | 43 --- .../Character/UpdateMaximumHealthPlugIn.cs | 41 --- .../UpdateMaximumManaExtendedPlugIn.cs | 43 --- .../Character/UpdateMaximumManaPlugIn.cs | 41 --- .../Character/UpdateStatsExtendedPlugIn.cs | 63 ++++ .../RemoteView/Character/UpdateStatsPlugIn.cs | 75 ++++ .../ServerToClient/ConnectionExtensions.cs | 106 ++---- .../ServerToClient/ServerToClientPackets.cs | 342 ++++++------------ .../ServerToClient/ServerToClientPackets.xml | 112 +++--- .../ServerToClientPacketsRef.cs | 342 ++++++------------ 31 files changed, 544 insertions(+), 1103 deletions(-) rename docs/Packets/{C1-26-FE-MaximumHealthAndShieldExtended_by-server.md => C1-26-FE-MaximumStatsExtended_by-server.md} (50%) delete mode 100644 docs/Packets/C1-26-FF-CurrentHealthAndShieldExtended_by-server.md create mode 100644 docs/Packets/C1-26-FF-CurrentStatsExtended_by-server.md delete mode 100644 docs/Packets/C1-27-FE-MaximumManaAndAbilityExtended_by-server.md delete mode 100644 docs/Packets/C1-27-FF-CurrentManaAndAbilityExtended_by-server.md delete mode 100644 src/GameLogic/Views/Character/IUpdateCurrentHealthPlugIn.cs delete mode 100644 src/GameLogic/Views/Character/IUpdateCurrentManaPlugIn.cs delete mode 100644 src/GameLogic/Views/Character/IUpdateMaximumHealthPlugIn.cs delete mode 100644 src/GameLogic/Views/Character/IUpdateMaximumManaPlugIn.cs create mode 100644 src/GameLogic/Views/Character/IUpdateStatsPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateCurrentHealthExtendedPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateCurrentHealthPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateCurrentManaExtendedPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateCurrentManaPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateMaximumHealthExtendedPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateMaximumHealthPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateMaximumManaExtendedPlugIn.cs delete mode 100644 src/GameServer/RemoteView/Character/UpdateMaximumManaPlugIn.cs create mode 100644 src/GameServer/RemoteView/Character/UpdateStatsExtendedPlugIn.cs create mode 100644 src/GameServer/RemoteView/Character/UpdateStatsPlugIn.cs diff --git a/docs/Packets/C1-26-FE-MaximumHealthAndShieldExtended_by-server.md b/docs/Packets/C1-26-FE-MaximumStatsExtended_by-server.md similarity index 50% rename from docs/Packets/C1-26-FE-MaximumHealthAndShieldExtended_by-server.md rename to docs/Packets/C1-26-FE-MaximumStatsExtended_by-server.md index 9ea3b588d..789acc585 100644 --- a/docs/Packets/C1-26-FE-MaximumHealthAndShieldExtended_by-server.md +++ b/docs/Packets/C1-26-FE-MaximumStatsExtended_by-server.md @@ -1,20 +1,22 @@ -# C1 26 FE - MaximumHealthAndShieldExtended (by server) +# C1 26 FE - MaximumStatsExtended (by server) ## Is sent when -When the maximum health changed, e.g. by adding stat points or changed items. +When the maximum stats, like health, shield, mana or attack speed changed on the server side, e.g. by adding stat points or changed items. ## Causes the following actions on the client side -The health and shield bar is updated on the game client user interface. +The values are updated on the game client user interface. ## Structure | Index | Length | Data Type | Value | Description | |-------|--------|-----------|-------|-------------| | 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) | -| 1 | 1 | Byte | 12 | Packet header - length of the packet | +| 1 | 1 | Byte | 20 | Packet header - length of the packet | | 2 | 1 | Byte | 0x26 | Packet header - packet type identifier | | 3 | 1 | Byte | 0xFE | Packet header - sub packet type identifier | | 4 | 4 | IntegerLittleEndian | | Health | -| 8 | 4 | IntegerLittleEndian | | Shield | \ No newline at end of file +| 8 | 4 | IntegerLittleEndian | | Shield | +| 12 | 4 | IntegerLittleEndian | | Mana | +| 16 | 4 | IntegerLittleEndian | | Ability | \ No newline at end of file diff --git a/docs/Packets/C1-26-FF-CurrentHealthAndShieldExtended_by-server.md b/docs/Packets/C1-26-FF-CurrentHealthAndShieldExtended_by-server.md deleted file mode 100644 index 72edaaf40..000000000 --- a/docs/Packets/C1-26-FF-CurrentHealthAndShieldExtended_by-server.md +++ /dev/null @@ -1,20 +0,0 @@ -# C1 26 FF - CurrentHealthAndShieldExtended (by server) - -## Is sent when - -Periodically, or if the current health or shield changed on the server side, e.g. by hits. - -## Causes the following actions on the client side - -The health and shield bar is updated on the game client user interface. - -## Structure - -| Index | Length | Data Type | Value | Description | -|-------|--------|-----------|-------|-------------| -| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) | -| 1 | 1 | Byte | 12 | Packet header - length of the packet | -| 2 | 1 | Byte | 0x26 | Packet header - packet type identifier | -| 3 | 1 | Byte | 0xFF | Packet header - sub packet type identifier | -| 4 | 4 | IntegerLittleEndian | | Health | -| 8 | 4 | IntegerLittleEndian | | Shield | \ No newline at end of file diff --git a/docs/Packets/C1-26-FF-CurrentStatsExtended_by-server.md b/docs/Packets/C1-26-FF-CurrentStatsExtended_by-server.md new file mode 100644 index 000000000..a979a7139 --- /dev/null +++ b/docs/Packets/C1-26-FF-CurrentStatsExtended_by-server.md @@ -0,0 +1,24 @@ +# C1 26 FF - CurrentStatsExtended (by server) + +## Is sent when + +Periodically, or if the current stats, like health, shield, mana or attack speed changed on the server side, e.g. by hits. + +## Causes the following actions on the client side + +The values are updated on the game client user interface. + +## Structure + +| Index | Length | Data Type | Value | Description | +|-------|--------|-----------|-------|-------------| +| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) | +| 1 | 1 | Byte | 24 | Packet header - length of the packet | +| 2 | 1 | Byte | 0x26 | Packet header - packet type identifier | +| 3 | 1 | Byte | 0xFF | Packet header - sub packet type identifier | +| 4 | 4 | IntegerLittleEndian | | Health | +| 8 | 4 | IntegerLittleEndian | | Shield | +| 12 | 4 | IntegerLittleEndian | | Mana | +| 16 | 4 | IntegerLittleEndian | | Ability | +| 20 | 2 | ShortLittleEndian | | AttackSpeed | +| 22 | 2 | ShortLittleEndian | | MagicSpeed | \ No newline at end of file diff --git a/docs/Packets/C1-27-FE-MaximumManaAndAbilityExtended_by-server.md b/docs/Packets/C1-27-FE-MaximumManaAndAbilityExtended_by-server.md deleted file mode 100644 index 360ea9520..000000000 --- a/docs/Packets/C1-27-FE-MaximumManaAndAbilityExtended_by-server.md +++ /dev/null @@ -1,20 +0,0 @@ -# C1 27 FE - MaximumManaAndAbilityExtended (by server) - -## Is sent when - -The maximum available mana or ability has changed, e.g. by adding stat points. - -## Causes the following actions on the client side - -The mana and ability bar is updated on the game client user interface. - -## Structure - -| Index | Length | Data Type | Value | Description | -|-------|--------|-----------|-------|-------------| -| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) | -| 1 | 1 | Byte | 12 | Packet header - length of the packet | -| 2 | 1 | Byte | 0x27 | Packet header - packet type identifier | -| 3 | 1 | Byte | 0xFE | Packet header - sub packet type identifier | -| 4 | 4 | IntegerLittleEndian | | Mana | -| 8 | 4 | IntegerLittleEndian | | Ability | \ No newline at end of file diff --git a/docs/Packets/C1-27-FF-CurrentManaAndAbilityExtended_by-server.md b/docs/Packets/C1-27-FF-CurrentManaAndAbilityExtended_by-server.md deleted file mode 100644 index cafa844ab..000000000 --- a/docs/Packets/C1-27-FF-CurrentManaAndAbilityExtended_by-server.md +++ /dev/null @@ -1,20 +0,0 @@ -# C1 27 FF - CurrentManaAndAbilityExtended (by server) - -## Is sent when - -The currently available mana or ability has changed, e.g. by using a skill. - -## Causes the following actions on the client side - -The mana and ability bar is updated on the game client user interface. - -## Structure - -| Index | Length | Data Type | Value | Description | -|-------|--------|-----------|-------|-------------| -| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) | -| 1 | 1 | Byte | 12 | Packet header - length of the packet | -| 2 | 1 | Byte | 0x27 | Packet header - packet type identifier | -| 3 | 1 | Byte | 0xFF | Packet header - sub packet type identifier | -| 4 | 4 | IntegerLittleEndian | | Mana | -| 8 | 4 | IntegerLittleEndian | | Ability | \ No newline at end of file diff --git a/docs/Packets/ServerToClient.md b/docs/Packets/ServerToClient.md index f840be18d..5d975f20f 100644 --- a/docs/Packets/ServerToClient.md +++ b/docs/Packets/ServerToClient.md @@ -50,13 +50,11 @@ * [C1 26 FD - ItemConsumptionFailed (by server)](C1-26-FD-ItemConsumptionFailed_by-server.md) * [C1 26 FD - ItemConsumptionFailedExtended (by server)](C1-26-FD-ItemConsumptionFailedExtended_by-server.md) * [C1 26 FE - MaximumHealthAndShield (by server)](C1-26-FE-MaximumHealthAndShield_by-server.md) - * [C1 26 FE - MaximumHealthAndShieldExtended (by server)](C1-26-FE-MaximumHealthAndShieldExtended_by-server.md) + * [C1 26 FE - MaximumStatsExtended (by server)](C1-26-FE-MaximumStatsExtended_by-server.md) * [C1 26 FF - CurrentHealthAndShield (by server)](C1-26-FF-CurrentHealthAndShield_by-server.md) - * [C1 26 FF - CurrentHealthAndShieldExtended (by server)](C1-26-FF-CurrentHealthAndShieldExtended_by-server.md) + * [C1 26 FF - CurrentStatsExtended (by server)](C1-26-FF-CurrentStatsExtended_by-server.md) * [C1 27 FE - MaximumManaAndAbility (by server)](C1-27-FE-MaximumManaAndAbility_by-server.md) - * [C1 27 FE - MaximumManaAndAbilityExtended (by server)](C1-27-FE-MaximumManaAndAbilityExtended_by-server.md) * [C1 27 FF - CurrentManaAndAbility (by server)](C1-27-FF-CurrentManaAndAbility_by-server.md) - * [C1 27 FF - CurrentManaAndAbilityExtended (by server)](C1-27-FF-CurrentManaAndAbilityExtended_by-server.md) * [C1 28 - ItemRemoved (by server)](C1-28-ItemRemoved_by-server.md) * [C3 29 - ConsumeItemWithEffect (by server)](C3-29-ConsumeItemWithEffect_by-server.md) * [C1 2A - ItemDurabilityChanged (by server)](C1-2A-ItemDurabilityChanged_by-server.md) diff --git a/src/GameLogic/AttackableExtensions.cs b/src/GameLogic/AttackableExtensions.cs index 04942f473..9dddcb103 100644 --- a/src/GameLogic/AttackableExtensions.cs +++ b/src/GameLogic/AttackableExtensions.cs @@ -199,14 +199,13 @@ public static async ValueTask ApplyRegenerationAsync(this IAttackable target, Pl if (target is IWorldObserver observer) { - if (isHealthUpdated) - { - await observer.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); - } + var updatedStats = + (isHealthUpdated ? IUpdateStatsPlugIn.UpdatedStats.Health : IUpdateStatsPlugIn.UpdatedStats.Undefined) + | (isManaUpdated ? IUpdateStatsPlugIn.UpdatedStats.Mana : IUpdateStatsPlugIn.UpdatedStats.Undefined); - if (isManaUpdated) + if (updatedStats != IUpdateStatsPlugIn.UpdatedStats.Undefined) { - await observer.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await observer.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(updatedStats)).ConfigureAwait(false); } } } diff --git a/src/GameLogic/Player.cs b/src/GameLogic/Player.cs index 6d0ae48e4..8c5851f48 100644 --- a/src/GameLogic/Player.cs +++ b/src/GameLogic/Player.cs @@ -4,6 +4,7 @@ namespace MUnique.OpenMU.GameLogic; +using System; using System.Threading; using MUnique.OpenMU.AttributeSystem; using MUnique.OpenMU.DataModel.Attributes; @@ -28,6 +29,7 @@ namespace MUnique.OpenMU.GameLogic; using MUnique.OpenMU.Persistence; using MUnique.OpenMU.PlugIns; using Nito.AsyncEx; +using static MUnique.OpenMU.GameLogic.Views.Character.IUpdateStatsPlugIn; /// /// The base implementation of a player. @@ -622,13 +624,13 @@ public bool IsAnySelfDefenseActive() if (Rand.NextRandomBool(this.Attributes[Stats.FullyRecoverHealthAfterHitChance])) { this.Attributes[Stats.CurrentHealth] = this.Attributes[Stats.MaximumHealth]; - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Health)).ConfigureAwait(false); } if (Rand.NextRandomBool(this.Attributes[Stats.FullyRecoverManaAfterHitChance])) { this.Attributes[Stats.CurrentMana] = this.Attributes[Stats.MaximumMana]; - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false); } await this.HitAsync(hitInfo, attacker, skill?.Skill).ConfigureAwait(false); @@ -731,8 +733,7 @@ public async ValueTask AfterKilledMonsterAsync() this.Attributes[recoverAfterMonsterKill.CurrentAttribute] = (uint)Math.Min(this.Attributes[recoverAfterMonsterKill.MaximumAttribute], this.Attributes[recoverAfterMonsterKill.CurrentAttribute] + additionalValue); } - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync()).ConfigureAwait(false); } /// @@ -1224,8 +1225,7 @@ public async Task RegenerateAsync() attributes[r.MaximumAttribute]); } - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync()).ConfigureAwait(false); await this.RegenerateHeroStateAsync().ConfigureAwait(false); } @@ -1334,7 +1334,8 @@ public async ValueTask TryConsumeForSkillAsync(Skill skill) this.Attributes![requirement.Attribute] -= this.GetRequiredValue(requirement); } - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false); + return true; } @@ -2082,6 +2083,7 @@ private async ValueTask OnPlayerEnteredWorldAsync() this.Attributes.GetOrCreateAttribute(Stats.MaximumHealth).ValueChanged += this.OnMaximumHealthOrShieldChanged; this.Attributes.GetOrCreateAttribute(Stats.MaximumShield).ValueChanged += this.OnMaximumHealthOrShieldChanged; this.Attributes.GetOrCreateAttribute(Stats.TransformationSkin).ValueChanged += this.OnTransformationSkinChanged; + this.Attributes.GetOrCreateAttribute(Stats.AttackSpeed).ValueChanged += this.OnAttackSpeedChanged; var ammoAttribute = this.Attributes.GetOrCreateAttribute(Stats.AmmunitionAmount); this.Attributes[Stats.AmmunitionAmount] = (float)(this.Inventory?.EquippedAmmunitionItem?.Durability ?? 0); @@ -2176,8 +2178,9 @@ private async void OnMaximumHealthOrShieldChanged(object? sender, EventArgs args { this.Attributes![Stats.CurrentHealth] = Math.Min(this.Attributes[Stats.CurrentHealth], this.Attributes[Stats.MaximumHealth]); this.Attributes[Stats.CurrentShield] = Math.Min(this.Attributes[Stats.CurrentShield], this.Attributes[Stats.MaximumShield]); - await this.InvokeViewPlugInAsync(p => p.UpdateMaximumHealthAsync()).ConfigureAwait(false); - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); + + await this.InvokeViewPlugInAsync(p => p.UpdateMaximumStatsAsync(UpdatedStats.Health)).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Health)).ConfigureAwait(false); } catch (Exception ex) { @@ -2218,8 +2221,21 @@ private async void OnMaximumManaOrAbilityChanged(object? sender, EventArgs args) { this.Attributes![Stats.CurrentMana] = Math.Min(this.Attributes[Stats.CurrentMana], this.Attributes[Stats.MaximumMana]); this.Attributes[Stats.CurrentAbility] = Math.Min(this.Attributes[Stats.CurrentAbility], this.Attributes[Stats.MaximumAbility]); - await this.InvokeViewPlugInAsync(p => p.UpdateMaximumManaAsync()).ConfigureAwait(false); - await this.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateMaximumStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false); + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Mana)).ConfigureAwait(false); + } + catch (Exception ex) + { + this.Logger.LogError(ex, nameof(this.OnMaximumManaOrAbilityChanged)); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "Catching all Exceptions.")] + private async void OnAttackSpeedChanged(object? sender, EventArgs args) + { + try + { + await this.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(UpdatedStats.Speed)).ConfigureAwait(false); } catch (Exception ex) { diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs index 3bc03506d..7c75a7663 100644 --- a/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs @@ -26,6 +26,7 @@ public override async ValueTask ConsumeItemAsync(Player player, Item item, if (await base.ConsumeItemAsync(player, item, targetItem, fruitUsage).ConfigureAwait(false)) { await player.InvokeViewPlugInAsync(p => p.DrinkAlcoholAsync()).ConfigureAwait(false); + // todo: add magic effect to update stat return true; } diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/HealthPotionConsumeHandlerPlugIn.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/HealthPotionConsumeHandlerPlugIn.cs index aa91b1a62..dd230f5c9 100644 --- a/src/GameLogic/PlayerActions/ItemConsumeActions/HealthPotionConsumeHandlerPlugIn.cs +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/HealthPotionConsumeHandlerPlugIn.cs @@ -25,6 +25,6 @@ public abstract class HealthPotionConsumeHandlerPlugIn : RecoverConsumeHandlerPl protected override async ValueTask OnAfterRecoverAsync(Player player) { // maybe instead of calling UpdateCurrentHealth etc. provide a more general method where we pass this.CurrentAttribute. The view can then decide what to do with it. - await player.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); + await player.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats.Health)).ConfigureAwait(false); } } \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/ManaPotionConsumehandler.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/ManaPotionConsumehandler.cs index d27931806..30efe2401 100644 --- a/src/GameLogic/PlayerActions/ItemConsumeActions/ManaPotionConsumehandler.cs +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/ManaPotionConsumehandler.cs @@ -24,6 +24,6 @@ public abstract class ManaPotionConsumeHandler : RecoverConsumeHandlerPlugIn.Man /// protected override async ValueTask OnAfterRecoverAsync(Player player) { - await player.InvokeViewPlugInAsync(p => p.UpdateCurrentManaAsync()).ConfigureAwait(false); + await player.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats.Mana)).ConfigureAwait(false); } } \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs b/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs index 05dc28838..5cf55d416 100644 --- a/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs +++ b/src/GameLogic/PlayerActions/Skills/DrainLifeSkillPlugIn.cs @@ -31,7 +31,7 @@ public async ValueTask AfterTargetGotAttackedAsync(IAttacker attacker, IAttackab if (playerAttributes != null) { playerAttributes[Stats.CurrentHealth] = (uint)Math.Min(playerAttributes[Stats.MaximumHealth], playerAttributes[Stats.CurrentHealth] + hitInfo.Value.HealthDamage); - await attackerPlayer.InvokeViewPlugInAsync(p => p.UpdateCurrentHealthAsync()).ConfigureAwait(false); + await attackerPlayer.InvokeViewPlugInAsync(p => p.UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats.Health)).ConfigureAwait(false); } } } diff --git a/src/GameLogic/Views/Character/IUpdateCurrentHealthPlugIn.cs b/src/GameLogic/Views/Character/IUpdateCurrentHealthPlugIn.cs deleted file mode 100644 index da9d4a4c6..000000000 --- a/src/GameLogic/Views/Character/IUpdateCurrentHealthPlugIn.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameLogic.Views.Character; - -/// -/// Interface of a view whose implementation informs about an updated current health. -/// -public interface IUpdateCurrentHealthPlugIn : IViewPlugIn -{ - /// - /// Updates the current health. - /// - ValueTask UpdateCurrentHealthAsync(); -} \ No newline at end of file diff --git a/src/GameLogic/Views/Character/IUpdateCurrentManaPlugIn.cs b/src/GameLogic/Views/Character/IUpdateCurrentManaPlugIn.cs deleted file mode 100644 index f259fa355..000000000 --- a/src/GameLogic/Views/Character/IUpdateCurrentManaPlugIn.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameLogic.Views.Character; - -/// -/// Interface of a view whose implementation informs about an updated current mana. -/// -public interface IUpdateCurrentManaPlugIn : IViewPlugIn -{ - /// - /// Updates the current mana. - /// - ValueTask UpdateCurrentManaAsync(); -} \ No newline at end of file diff --git a/src/GameLogic/Views/Character/IUpdateMaximumHealthPlugIn.cs b/src/GameLogic/Views/Character/IUpdateMaximumHealthPlugIn.cs deleted file mode 100644 index 967c3b766..000000000 --- a/src/GameLogic/Views/Character/IUpdateMaximumHealthPlugIn.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameLogic.Views.Character; - -/// -/// Interface of a view whose implementation informs about an updated maximum health. -/// -public interface IUpdateMaximumHealthPlugIn : IViewPlugIn -{ - /// - /// Updates the maximum health. - /// - ValueTask UpdateMaximumHealthAsync(); -} \ No newline at end of file diff --git a/src/GameLogic/Views/Character/IUpdateMaximumManaPlugIn.cs b/src/GameLogic/Views/Character/IUpdateMaximumManaPlugIn.cs deleted file mode 100644 index 34a096165..000000000 --- a/src/GameLogic/Views/Character/IUpdateMaximumManaPlugIn.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameLogic.Views.Character; - -/// -/// Interface of a view whose implementation informs about an updated maximum mana. -/// -public interface IUpdateMaximumManaPlugIn : IViewPlugIn -{ - /// - /// Updates the maximum mana. - /// - ValueTask UpdateMaximumManaAsync(); -} \ No newline at end of file diff --git a/src/GameLogic/Views/Character/IUpdateStatsPlugIn.cs b/src/GameLogic/Views/Character/IUpdateStatsPlugIn.cs new file mode 100644 index 000000000..6e6d81f42 --- /dev/null +++ b/src/GameLogic/Views/Character/IUpdateStatsPlugIn.cs @@ -0,0 +1,53 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.Views.Character; + +using MUnique.OpenMU.AttributeSystem; + +/// +/// Interface of a view whose implementation informs about updated stats. +/// +public interface IUpdateStatsPlugIn : IViewPlugIn +{ + /// + /// Updates the maximum stats. + /// + /// The updated stats. + ValueTask UpdateMaximumStatsAsync(UpdatedStats updatedStats = UpdatedStats.Health | UpdatedStats.Mana | UpdatedStats.Speed); + + /// + /// Updates the current stats. + /// + /// The updated stats. + ValueTask UpdateCurrentStatsAsync(UpdatedStats updatedStats = UpdatedStats.Health | UpdatedStats.Mana | UpdatedStats.Speed); + + /// + /// The updated stat. + /// This might be replaced by the actual in the future. + /// + [Flags] + public enum UpdatedStats + { + /// + /// Undefined. + /// + Undefined, + + /// + /// The health or shield changed. + /// + Health = 0x01, + + /// + /// The mana or ability changed. + /// + Mana = 0x02, + + /// + /// The attack speed changed. + /// + Speed = 0x04, + } +} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateCurrentHealthExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateCurrentHealthExtendedPlugIn.cs deleted file mode 100644 index daf062c2c..000000000 --- a/src/GameServer/RemoteView/Character/UpdateCurrentHealthExtendedPlugIn.cs +++ /dev/null @@ -1,42 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.Network.PlugIns; -using MUnique.OpenMU.PlugIns; - -/// -/// The extended implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn(nameof(UpdateCurrentHealthExtendedPlugIn), "The extended implementation of the IUpdateCurrentHealthPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("C609BC7E-170B-4C79-94E5-D97AB9A3CB4B")] -[MinimumClient(106, 3, ClientLanguage.Invariant)] -public class UpdateCurrentHealthExtendedPlugIn : IUpdateCurrentHealthPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateCurrentHealthExtendedPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateCurrentHealthAsync() - { - if (this._player.Attributes is null) - { - return; - } - - await this._player.Connection.SendCurrentHealthAndShieldExtendedAsync( - (uint)Math.Max(this._player.Attributes[Stats.CurrentHealth], 0f), - (uint)Math.Max(this._player.Attributes[Stats.CurrentShield], 0f)).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateCurrentHealthPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateCurrentHealthPlugIn.cs deleted file mode 100644 index 71847fab1..000000000 --- a/src/GameServer/RemoteView/Character/UpdateCurrentHealthPlugIn.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.PlugIns; - -/// -/// The default implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn("UpdateCurrentHealthPlugIn", "The default implementation of the IUpdateCurrentHealthPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("0c832ed3-fea7-4239-8208-b46897b44c84")] -public class UpdateCurrentHealthPlugIn : IUpdateCurrentHealthPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateCurrentHealthPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateCurrentHealthAsync() - { - if (this._player.Attributes is null) - { - return; - } - - await this._player.Connection.SendCurrentHealthAndShieldAsync( - (ushort)Math.Max(this._player.Attributes[Stats.CurrentHealth], 0f), - (ushort)Math.Max(this._player.Attributes[Stats.CurrentShield], 0f)).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateCurrentManaExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateCurrentManaExtendedPlugIn.cs deleted file mode 100644 index eb58815d1..000000000 --- a/src/GameServer/RemoteView/Character/UpdateCurrentManaExtendedPlugIn.cs +++ /dev/null @@ -1,42 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.Network.PlugIns; -using MUnique.OpenMU.PlugIns; - -/// -/// The extended implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn(nameof(UpdateCurrentManaExtendedPlugIn), "The extended implementation of the IUpdateCurrentManaPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("1F99BFB4-35FC-489B-AB3C-E0738314DF37")] -[MinimumClient(106, 3, ClientLanguage.Invariant)] -public class UpdateCurrentManaExtendedPlugIn : IUpdateCurrentManaPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateCurrentManaExtendedPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateCurrentManaAsync() - { - if (this._player.Attributes is null) - { - return; - } - - await this._player.Connection.SendCurrentManaAndAbilityExtendedAsync( - (uint)this._player.Attributes[Stats.CurrentMana], - (uint)this._player.Attributes[Stats.CurrentAbility]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateCurrentManaPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateCurrentManaPlugIn.cs deleted file mode 100644 index b661c3625..000000000 --- a/src/GameServer/RemoteView/Character/UpdateCurrentManaPlugIn.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.PlugIns; - -/// -/// The default implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn("UpdateCurrentManaPlugIn", "The default implementation of the IUpdateCurrentManaPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("814fcc24-022a-47c8-b7d2-b1d1ca0208cb")] -public class UpdateCurrentManaPlugIn : IUpdateCurrentManaPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateCurrentManaPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateCurrentManaAsync() - { - if (this._player.Attributes is null) - { - return; - } - - await this._player.Connection.SendCurrentManaAndAbilityAsync( - (ushort)this._player.Attributes[Stats.CurrentMana], - (ushort)this._player.Attributes[Stats.CurrentAbility]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateMaximumHealthExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateMaximumHealthExtendedPlugIn.cs deleted file mode 100644 index 5dd404843..000000000 --- a/src/GameServer/RemoteView/Character/UpdateMaximumHealthExtendedPlugIn.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.Network.PlugIns; -using MUnique.OpenMU.PlugIns; - -/// -/// The extended implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn(nameof(UpdateMaximumHealthExtendedPlugIn), "The extended implementation of the IUpdateMaximumHealthPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("7A287D6D-5C32-4FA9-9A0D-A4E0DEB053D1")] -[MinimumClient(106, 3, ClientLanguage.Invariant)] -public class UpdateMaximumHealthExtendedPlugIn : IUpdateMaximumHealthPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateMaximumHealthExtendedPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateMaximumHealthAsync() - { - if (this._player.Attributes is null - || !(this._player.Connection?.Connected ?? false)) - { - return; - } - - await this._player.Connection.SendMaximumHealthAndShieldExtendedAsync( - (uint)this._player.Attributes[Stats.MaximumHealth], - (uint)this._player.Attributes[Stats.MaximumShield]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateMaximumHealthPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateMaximumHealthPlugIn.cs deleted file mode 100644 index e683b6f7b..000000000 --- a/src/GameServer/RemoteView/Character/UpdateMaximumHealthPlugIn.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.PlugIns; - -/// -/// The default implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn("UpdateMaximumHealthPlugIn", "The default implementation of the IUpdateMaximumHealthPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("6f8e7d9a-7d15-4e76-a650-8bfa70c7298e")] -public class UpdateMaximumHealthPlugIn : IUpdateMaximumHealthPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateMaximumHealthPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateMaximumHealthAsync() - { - if (this._player.Attributes is null - || !(this._player.Connection?.Connected ?? false)) - { - return; - } - - await this._player.Connection.SendMaximumHealthAndShieldAsync( - (ushort)this._player.Attributes[Stats.MaximumHealth], - (ushort)this._player.Attributes[Stats.MaximumShield]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateMaximumManaExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateMaximumManaExtendedPlugIn.cs deleted file mode 100644 index 899f989c9..000000000 --- a/src/GameServer/RemoteView/Character/UpdateMaximumManaExtendedPlugIn.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.Network.PlugIns; -using MUnique.OpenMU.PlugIns; - -/// -/// The extended implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn(nameof(UpdateMaximumManaExtendedPlugIn), "The extended implementation of the IUpdateMaximumManaPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("25AF11D5-FA10-4634-AF5A-CBF6F5E8BDFE")] -[MinimumClient(106, 3, ClientLanguage.Invariant)] -public class UpdateMaximumManaExtendedPlugIn : IUpdateMaximumManaPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateMaximumManaExtendedPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateMaximumManaAsync() - { - if (this._player.Attributes is null - || !(this._player.Connection?.Connected ?? false)) - { - return; - } - - await this._player.Connection.SendMaximumManaAndAbilityExtendedAsync( - (uint)this._player.Attributes[Stats.MaximumMana], - (uint)this._player.Attributes[Stats.MaximumAbility]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateMaximumManaPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateMaximumManaPlugIn.cs deleted file mode 100644 index eff798d68..000000000 --- a/src/GameServer/RemoteView/Character/UpdateMaximumManaPlugIn.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView.Character; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Attributes; -using MUnique.OpenMU.GameLogic.Views.Character; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.PlugIns; - -/// -/// The default implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn("UpdateMaximumManaPlugIn", "The default implementation of the IUpdateMaximumManaPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("dc84be82-7ab0-4348-aa34-4a3dc8c1ee7a")] -public class UpdateMaximumManaPlugIn : IUpdateMaximumManaPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public UpdateMaximumManaPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask UpdateMaximumManaAsync() - { - if (this._player.Attributes is null - || !(this._player.Connection?.Connected ?? false)) - { - return; - } - - await this._player.Connection.SendMaximumManaAndAbilityAsync( - (ushort)this._player.Attributes[Stats.MaximumMana], - (ushort)this._player.Attributes[Stats.MaximumAbility]).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateStatsExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateStatsExtendedPlugIn.cs new file mode 100644 index 000000000..1e70249c4 --- /dev/null +++ b/src/GameServer/RemoteView/Character/UpdateStatsExtendedPlugIn.cs @@ -0,0 +1,63 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameServer.RemoteView.Character; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.GameLogic.Attributes; +using MUnique.OpenMU.GameLogic.Views.Character; +using MUnique.OpenMU.Network.Packets.ServerToClient; +using MUnique.OpenMU.Network.PlugIns; +using MUnique.OpenMU.PlugIns; + +/// +/// The extended implementation of the which is forwarding everything to the game client with specific data packets. +/// +[PlugIn(nameof(UpdateStatsExtendedPlugIn), "The extended implementation of the IUpdateStatsPlugIn which is forwarding everything to the game client with specific data packets.")] +[Guid("E9A1CCBE-416F-41BA-8E74-74CBEB7042DD")] +[MinimumClient(106, 3, ClientLanguage.Invariant)] +public class UpdateStatsExtendedPlugIn : IUpdateStatsPlugIn +{ + private readonly RemotePlayer _player; + + /// + /// Initializes a new instance of the class. + /// + /// The player. + public UpdateStatsExtendedPlugIn(RemotePlayer player) => this._player = player; + + /// + public async ValueTask UpdateMaximumStatsAsync(IUpdateStatsPlugIn.UpdatedStats updatedStats = IUpdateStatsPlugIn.UpdatedStats.Undefined) + { + if (this._player.Attributes is null + || !(this._player.Connection?.Connected ?? false)) + { + return; + } + + await this._player.Connection.SendMaximumStatsExtendedAsync( + (uint)this._player.Attributes[Stats.MaximumHealth], + (uint)this._player.Attributes[Stats.MaximumShield], + (uint)this._player.Attributes[Stats.MaximumMana], + (uint)this._player.Attributes[Stats.MaximumAbility]).ConfigureAwait(false); + } + + /// + public async ValueTask UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats updatedStats = IUpdateStatsPlugIn.UpdatedStats.Undefined) + { + if (this._player.Attributes is null + || !(this._player.Connection?.Connected ?? false)) + { + return; + } + + await this._player.Connection.SendCurrentStatsExtendedAsync( + (uint)this._player.Attributes[Stats.CurrentHealth], + (uint)this._player.Attributes[Stats.CurrentShield], + (uint)this._player.Attributes[Stats.CurrentMana], + (uint)this._player.Attributes[Stats.CurrentAbility], + (ushort)this._player.Attributes[Stats.AttackSpeed], + (ushort)this._player.Attributes[Stats.MagicSpeed]).ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/src/GameServer/RemoteView/Character/UpdateStatsPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateStatsPlugIn.cs new file mode 100644 index 000000000..bbffdd33a --- /dev/null +++ b/src/GameServer/RemoteView/Character/UpdateStatsPlugIn.cs @@ -0,0 +1,75 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameServer.RemoteView.Character; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.GameLogic.Attributes; +using MUnique.OpenMU.GameLogic.Views.Character; +using MUnique.OpenMU.Network.Packets.ServerToClient; +using MUnique.OpenMU.PlugIns; + +/// +/// The default implementation of the which is forwarding everything to the game client with specific data packets. +/// +[PlugIn(nameof(UpdateStatsPlugIn), "The default implementation of the IUpdateStatsPlugIn which is forwarding everything to the game client with specific data packets.")] +[Guid("2A8BFB0C-2AFF-4A52-B390-5A68D5C5F26A")] +public class UpdateStatsPlugIn : IUpdateStatsPlugIn +{ + private readonly RemotePlayer _player; + + /// + /// Initializes a new instance of the class. + /// + /// The player. + public UpdateStatsPlugIn(RemotePlayer player) => this._player = player; + + /// + public async ValueTask UpdateMaximumStatsAsync(IUpdateStatsPlugIn.UpdatedStats updatedStats = IUpdateStatsPlugIn.UpdatedStats.Undefined | IUpdateStatsPlugIn.UpdatedStats.Health | IUpdateStatsPlugIn.UpdatedStats.Mana | IUpdateStatsPlugIn.UpdatedStats.Speed) + { + if (this._player.Attributes is null + || !(this._player.Connection?.Connected ?? false)) + { + return; + } + + if (updatedStats.HasFlag(IUpdateStatsPlugIn.UpdatedStats.Health)) + { + await this._player.Connection.SendMaximumHealthAndShieldAsync( + (ushort)Math.Max(this._player.Attributes[Stats.MaximumHealth], 0f), + (ushort)Math.Max(this._player.Attributes[Stats.MaximumShield], 0f)).ConfigureAwait(false); + } + + if (updatedStats.HasFlag(IUpdateStatsPlugIn.UpdatedStats.Mana)) + { + await this._player.Connection.SendMaximumManaAndAbilityAsync( + (ushort)Math.Max(this._player.Attributes[Stats.MaximumMana], 0f), + (ushort)Math.Max(this._player.Attributes[Stats.MaximumAbility], 0f)).ConfigureAwait(false); + } + } + + /// + public async ValueTask UpdateCurrentStatsAsync(IUpdateStatsPlugIn.UpdatedStats updatedStats = IUpdateStatsPlugIn.UpdatedStats.Undefined | IUpdateStatsPlugIn.UpdatedStats.Health | IUpdateStatsPlugIn.UpdatedStats.Mana | IUpdateStatsPlugIn.UpdatedStats.Speed) + { + if (this._player.Attributes is null + || !(this._player.Connection?.Connected ?? false)) + { + return; + } + + if (updatedStats.HasFlag(IUpdateStatsPlugIn.UpdatedStats.Health)) + { + await this._player.Connection.SendCurrentHealthAndShieldAsync( + (ushort)Math.Max(this._player.Attributes[Stats.CurrentHealth], 0f), + (ushort)Math.Max(this._player.Attributes[Stats.CurrentShield], 0f)).ConfigureAwait(false); + } + + if (updatedStats.HasFlag(IUpdateStatsPlugIn.UpdatedStats.Mana)) + { + await this._player.Connection.SendCurrentHealthAndShieldAsync( + (ushort)Math.Max(this._player.Attributes[Stats.CurrentMana], 0f), + (ushort)Math.Max(this._player.Attributes[Stats.CurrentAbility], 0f)).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/Network/Packets/ServerToClient/ConnectionExtensions.cs b/src/Network/Packets/ServerToClient/ConnectionExtensions.cs index ec13a7a62..d7d1e18d2 100644 --- a/src/Network/Packets/ServerToClient/ConnectionExtensions.cs +++ b/src/Network/Packets/ServerToClient/ConnectionExtensions.cs @@ -1726,16 +1726,16 @@ int WritePacket() } /// - /// Sends a to this connection. + /// Sends a to this connection. /// /// The connection. /// The health. /// The shield. /// - /// Is sent by the server when: Periodically, or if the current health or shield changed on the server side, e.g. by hits. + /// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. /// Causes reaction on client side: The health and shield bar is updated on the game client user interface. /// - public static async ValueTask SendCurrentHealthAndShieldExtendedAsync(this IConnection? connection, uint @health, uint @shield) + public static async ValueTask SendMaximumHealthAndShieldAsync(this IConnection? connection, ushort @health, ushort @shield) { if (connection is null) { @@ -1744,8 +1744,8 @@ public static async ValueTask SendCurrentHealthAndShieldExtendedAsync(this IConn int WritePacket() { - var length = CurrentHealthAndShieldExtendedRef.Length; - var packet = new CurrentHealthAndShieldExtendedRef(connection.Output.GetSpan(length)[..length]); + var length = MaximumHealthAndShieldRef.Length; + var packet = new MaximumHealthAndShieldRef(connection.Output.GetSpan(length)[..length]); packet.Health = @health; packet.Shield = @shield; @@ -1756,16 +1756,20 @@ int WritePacket() } /// - /// Sends a to this connection. + /// Sends a to this connection. /// /// The connection. /// The health. /// The shield. + /// The mana. + /// The ability. + /// The attack speed. + /// The magic speed. /// - /// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. - /// Causes reaction on client side: The health and shield bar is updated on the game client user interface. + /// Is sent by the server when: Periodically, or if the current stats, like health, shield, mana or attack speed changed on the server side, e.g. by hits. + /// Causes reaction on client side: The values are updated on the game client user interface. /// - public static async ValueTask SendMaximumHealthAndShieldAsync(this IConnection? connection, ushort @health, ushort @shield) + public static async ValueTask SendCurrentStatsExtendedAsync(this IConnection? connection, uint @health, uint @shield, uint @mana, uint @ability, ushort @attackSpeed, ushort @magicSpeed) { if (connection is null) { @@ -1774,10 +1778,14 @@ public static async ValueTask SendMaximumHealthAndShieldAsync(this IConnection? int WritePacket() { - var length = MaximumHealthAndShieldRef.Length; - var packet = new MaximumHealthAndShieldRef(connection.Output.GetSpan(length)[..length]); + var length = CurrentStatsExtendedRef.Length; + var packet = new CurrentStatsExtendedRef(connection.Output.GetSpan(length)[..length]); packet.Health = @health; packet.Shield = @shield; + packet.Mana = @mana; + packet.Ability = @ability; + packet.AttackSpeed = @attackSpeed; + packet.MagicSpeed = @magicSpeed; return packet.Header.Length; } @@ -1786,16 +1794,18 @@ int WritePacket() } /// - /// Sends a to this connection. + /// Sends a to this connection. /// /// The connection. /// The health. /// The shield. + /// The mana. + /// The ability. /// - /// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. - /// Causes reaction on client side: The health and shield bar is updated on the game client user interface. + /// Is sent by the server when: When the maximum stats, like health, shield, mana or attack speed changed on the server side, e.g. by adding stat points or changed items. + /// Causes reaction on client side: The values are updated on the game client user interface. /// - public static async ValueTask SendMaximumHealthAndShieldExtendedAsync(this IConnection? connection, uint @health, uint @shield) + public static async ValueTask SendMaximumStatsExtendedAsync(this IConnection? connection, uint @health, uint @shield, uint @mana, uint @ability) { if (connection is null) { @@ -1804,10 +1814,12 @@ public static async ValueTask SendMaximumHealthAndShieldExtendedAsync(this IConn int WritePacket() { - var length = MaximumHealthAndShieldExtendedRef.Length; - var packet = new MaximumHealthAndShieldExtendedRef(connection.Output.GetSpan(length)[..length]); + var length = MaximumStatsExtendedRef.Length; + var packet = new MaximumStatsExtendedRef(connection.Output.GetSpan(length)[..length]); packet.Health = @health; packet.Shield = @shield; + packet.Mana = @mana; + packet.Ability = @ability; return packet.Header.Length; } @@ -1905,36 +1917,6 @@ int WritePacket() await connection.SendAsync(WritePacket).ConfigureAwait(false); } - /// - /// Sends a to this connection. - /// - /// The connection. - /// The mana. - /// The ability. - /// - /// Is sent by the server when: The currently available mana or ability has changed, e.g. by using a skill. - /// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. - /// - public static async ValueTask SendCurrentManaAndAbilityExtendedAsync(this IConnection? connection, uint @mana, uint @ability) - { - if (connection is null) - { - return; - } - - int WritePacket() - { - var length = CurrentManaAndAbilityExtendedRef.Length; - var packet = new CurrentManaAndAbilityExtendedRef(connection.Output.GetSpan(length)[..length]); - packet.Mana = @mana; - packet.Ability = @ability; - - return packet.Header.Length; - } - - await connection.SendAsync(WritePacket).ConfigureAwait(false); - } - /// /// Sends a to this connection. /// @@ -1965,36 +1947,6 @@ int WritePacket() await connection.SendAsync(WritePacket).ConfigureAwait(false); } - /// - /// Sends a to this connection. - /// - /// The connection. - /// The mana. - /// The ability. - /// - /// Is sent by the server when: The maximum available mana or ability has changed, e.g. by adding stat points. - /// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. - /// - public static async ValueTask SendMaximumManaAndAbilityExtendedAsync(this IConnection? connection, uint @mana, uint @ability) - { - if (connection is null) - { - return; - } - - int WritePacket() - { - var length = MaximumManaAndAbilityExtendedRef.Length; - var packet = new MaximumManaAndAbilityExtendedRef(connection.Output.GetSpan(length)[..length]); - packet.Mana = @mana; - packet.Ability = @ability; - - return packet.Header.Length; - } - - await connection.SendAsync(WritePacket).ConfigureAwait(false); - } - /// /// Sends a to this connection. /// diff --git a/src/Network/Packets/ServerToClient/ServerToClientPackets.cs b/src/Network/Packets/ServerToClient/ServerToClientPackets.cs index 2cd7d3da8..28a34366d 100644 --- a/src/Network/Packets/ServerToClient/ServerToClientPackets.cs +++ b/src/Network/Packets/ServerToClient/ServerToClientPackets.cs @@ -8874,28 +8874,28 @@ public ushort Shield /// -/// Is sent by the server when: Periodically, or if the current health or shield changed on the server side, e.g. by hits. +/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. /// Causes reaction on client side: The health and shield bar is updated on the game client user interface. /// -public readonly struct CurrentHealthAndShieldExtended +public readonly struct MaximumHealthAndShield { private readonly Memory _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public CurrentHealthAndShieldExtended(Memory data) + public MaximumHealthAndShield(Memory data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private CurrentHealthAndShieldExtended(Memory data, bool initialize) + private MaximumHealthAndShield(Memory data, bool initialize) { this._data = data; if (initialize) @@ -8922,12 +8922,12 @@ private CurrentHealthAndShieldExtended(Memory data, bool initialize) /// Gets the operation sub-code of this data packet. /// The is used as a grouping key. /// - public static byte SubCode => 0xFF; + public static byte SubCode => 0xFE; /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 12; + public static int Length => 9; /// /// Gets the header of this packet. @@ -8937,60 +8937,60 @@ private CurrentHealthAndShieldExtended(Memory data, bool initialize) /// /// Gets or sets the health. /// - public uint Health + public ushort Health { - get => ReadUInt32LittleEndian(this._data.Span[4..]); - set => WriteUInt32LittleEndian(this._data.Span[4..], value); + get => ReadUInt16BigEndian(this._data.Span[4..]); + set => WriteUInt16BigEndian(this._data.Span[4..], value); } /// /// Gets or sets the shield. /// - public uint Shield + public ushort Shield { - get => ReadUInt32LittleEndian(this._data.Span[8..]); - set => WriteUInt32LittleEndian(this._data.Span[8..], value); + get => ReadUInt16BigEndian(this._data.Span[7..]); + set => WriteUInt16BigEndian(this._data.Span[7..], value); } /// - /// Performs an implicit conversion from a Memory of bytes to a . + /// Performs an implicit conversion from a Memory of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator CurrentHealthAndShieldExtended(Memory packet) => new (packet, false); + public static implicit operator MaximumHealthAndShield(Memory packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Memory of bytes. + /// Performs an implicit conversion from to a Memory of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Memory(CurrentHealthAndShieldExtended packet) => packet._data; + public static implicit operator Memory(MaximumHealthAndShield packet) => packet._data; } /// -/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. -/// Causes reaction on client side: The health and shield bar is updated on the game client user interface. +/// Is sent by the server when: Periodically, or if the current stats, like health, shield, mana or attack speed changed on the server side, e.g. by hits. +/// Causes reaction on client side: The values are updated on the game client user interface. /// -public readonly struct MaximumHealthAndShield +public readonly struct CurrentStatsExtended { private readonly Memory _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public MaximumHealthAndShield(Memory data) + public CurrentStatsExtended(Memory data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumHealthAndShield(Memory data, bool initialize) + private CurrentStatsExtended(Memory data, bool initialize) { this._data = data; if (initialize) @@ -9017,12 +9017,12 @@ private MaximumHealthAndShield(Memory data, bool initialize) /// Gets the operation sub-code of this data packet. /// The is used as a grouping key. /// - public static byte SubCode => 0xFE; + public static byte SubCode => 0xFF; /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 9; + public static int Length => 24; /// /// Gets the header of this packet. @@ -9032,60 +9032,96 @@ private MaximumHealthAndShield(Memory data, bool initialize) /// /// Gets or sets the health. /// - public ushort Health + public uint Health { - get => ReadUInt16BigEndian(this._data.Span[4..]); - set => WriteUInt16BigEndian(this._data.Span[4..], value); + get => ReadUInt32LittleEndian(this._data.Span[4..]); + set => WriteUInt32LittleEndian(this._data.Span[4..], value); } /// /// Gets or sets the shield. /// - public ushort Shield + public uint Shield { - get => ReadUInt16BigEndian(this._data.Span[7..]); - set => WriteUInt16BigEndian(this._data.Span[7..], value); + get => ReadUInt32LittleEndian(this._data.Span[8..]); + set => WriteUInt32LittleEndian(this._data.Span[8..], value); } /// - /// Performs an implicit conversion from a Memory of bytes to a . + /// Gets or sets the mana. + /// + public uint Mana + { + get => ReadUInt32LittleEndian(this._data.Span[12..]); + set => WriteUInt32LittleEndian(this._data.Span[12..], value); + } + + /// + /// Gets or sets the ability. + /// + public uint Ability + { + get => ReadUInt32LittleEndian(this._data.Span[16..]); + set => WriteUInt32LittleEndian(this._data.Span[16..], value); + } + + /// + /// Gets or sets the attack speed. + /// + public ushort AttackSpeed + { + get => ReadUInt16LittleEndian(this._data.Span[20..]); + set => WriteUInt16LittleEndian(this._data.Span[20..], value); + } + + /// + /// Gets or sets the magic speed. + /// + public ushort MagicSpeed + { + get => ReadUInt16LittleEndian(this._data.Span[22..]); + set => WriteUInt16LittleEndian(this._data.Span[22..], value); + } + + /// + /// Performs an implicit conversion from a Memory of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator MaximumHealthAndShield(Memory packet) => new (packet, false); + public static implicit operator CurrentStatsExtended(Memory packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Memory of bytes. + /// Performs an implicit conversion from to a Memory of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Memory(MaximumHealthAndShield packet) => packet._data; + public static implicit operator Memory(CurrentStatsExtended packet) => packet._data; } /// -/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. -/// Causes reaction on client side: The health and shield bar is updated on the game client user interface. +/// Is sent by the server when: When the maximum stats, like health, shield, mana or attack speed changed on the server side, e.g. by adding stat points or changed items. +/// Causes reaction on client side: The values are updated on the game client user interface. /// -public readonly struct MaximumHealthAndShieldExtended +public readonly struct MaximumStatsExtended { private readonly Memory _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public MaximumHealthAndShieldExtended(Memory data) + public MaximumStatsExtended(Memory data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumHealthAndShieldExtended(Memory data, bool initialize) + private MaximumStatsExtended(Memory data, bool initialize) { this._data = data; if (initialize) @@ -9117,7 +9153,7 @@ private MaximumHealthAndShieldExtended(Memory data, bool initialize) /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 12; + public static int Length => 20; /// /// Gets the header of this packet. @@ -9143,18 +9179,36 @@ public uint Shield } /// - /// Performs an implicit conversion from a Memory of bytes to a . + /// Gets or sets the mana. + /// + public uint Mana + { + get => ReadUInt32LittleEndian(this._data.Span[12..]); + set => WriteUInt32LittleEndian(this._data.Span[12..], value); + } + + /// + /// Gets or sets the ability. + /// + public uint Ability + { + get => ReadUInt32LittleEndian(this._data.Span[16..]); + set => WriteUInt32LittleEndian(this._data.Span[16..], value); + } + + /// + /// Performs an implicit conversion from a Memory of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator MaximumHealthAndShieldExtended(Memory packet) => new (packet, false); + public static implicit operator MaximumStatsExtended(Memory packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Memory of bytes. + /// Performs an implicit conversion from to a Memory of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Memory(MaximumHealthAndShieldExtended packet) => packet._data; + public static implicit operator Memory(MaximumStatsExtended packet) => packet._data; } @@ -9443,101 +9497,6 @@ public ushort Ability } -/// -/// Is sent by the server when: The currently available mana or ability has changed, e.g. by using a skill. -/// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. -/// -public readonly struct CurrentManaAndAbilityExtended -{ - private readonly Memory _data; - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - public CurrentManaAndAbilityExtended(Memory data) - : this(data, true) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - /// If set to true, the header data is automatically initialized and written to the underlying span. - private CurrentManaAndAbilityExtended(Memory data, bool initialize) - { - this._data = data; - if (initialize) - { - var header = this.Header; - header.Type = HeaderType; - header.Code = Code; - header.Length = (byte)Math.Min(data.Length, Length); - header.SubCode = SubCode; - } - } - - /// - /// Gets the header type of this data packet. - /// - public static byte HeaderType => 0xC1; - - /// - /// Gets the operation code of this data packet. - /// - public static byte Code => 0x27; - - /// - /// Gets the operation sub-code of this data packet. - /// The is used as a grouping key. - /// - public static byte SubCode => 0xFF; - - /// - /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. - /// - public static int Length => 12; - - /// - /// Gets the header of this packet. - /// - public C1HeaderWithSubCode Header => new (this._data); - - /// - /// Gets or sets the mana. - /// - public uint Mana - { - get => ReadUInt32LittleEndian(this._data.Span[4..]); - set => WriteUInt32LittleEndian(this._data.Span[4..], value); - } - - /// - /// Gets or sets the ability. - /// - public uint Ability - { - get => ReadUInt32LittleEndian(this._data.Span[8..]); - set => WriteUInt32LittleEndian(this._data.Span[8..], value); - } - - /// - /// Performs an implicit conversion from a Memory of bytes to a . - /// - /// The packet as span. - /// The packet as struct. - public static implicit operator CurrentManaAndAbilityExtended(Memory packet) => new (packet, false); - - /// - /// Performs an implicit conversion from to a Memory of bytes. - /// - /// The packet as struct. - /// The packet as byte span. - public static implicit operator Memory(CurrentManaAndAbilityExtended packet) => packet._data; -} - - /// /// Is sent by the server when: The maximum available mana or ability has changed, e.g. by adding stat points. /// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. @@ -9633,101 +9592,6 @@ public ushort Ability } -/// -/// Is sent by the server when: The maximum available mana or ability has changed, e.g. by adding stat points. -/// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. -/// -public readonly struct MaximumManaAndAbilityExtended -{ - private readonly Memory _data; - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - public MaximumManaAndAbilityExtended(Memory data) - : this(data, true) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumManaAndAbilityExtended(Memory data, bool initialize) - { - this._data = data; - if (initialize) - { - var header = this.Header; - header.Type = HeaderType; - header.Code = Code; - header.Length = (byte)Math.Min(data.Length, Length); - header.SubCode = SubCode; - } - } - - /// - /// Gets the header type of this data packet. - /// - public static byte HeaderType => 0xC1; - - /// - /// Gets the operation code of this data packet. - /// - public static byte Code => 0x27; - - /// - /// Gets the operation sub-code of this data packet. - /// The is used as a grouping key. - /// - public static byte SubCode => 0xFE; - - /// - /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. - /// - public static int Length => 12; - - /// - /// Gets the header of this packet. - /// - public C1HeaderWithSubCode Header => new (this._data); - - /// - /// Gets or sets the mana. - /// - public uint Mana - { - get => ReadUInt32LittleEndian(this._data.Span[4..]); - set => WriteUInt32LittleEndian(this._data.Span[4..], value); - } - - /// - /// Gets or sets the ability. - /// - public uint Ability - { - get => ReadUInt32LittleEndian(this._data.Span[8..]); - set => WriteUInt32LittleEndian(this._data.Span[8..], value); - } - - /// - /// Performs an implicit conversion from a Memory of bytes to a . - /// - /// The packet as span. - /// The packet as struct. - public static implicit operator MaximumManaAndAbilityExtended(Memory packet) => new (packet, false); - - /// - /// Performs an implicit conversion from to a Memory of bytes. - /// - /// The packet as struct. - /// The packet as byte span. - public static implicit operator Memory(MaximumManaAndAbilityExtended packet) => packet._data; -} - - /// /// Is sent by the server when: The item has been removed from the inventory of the player. /// Causes reaction on client side: The client removes the item in the inventory user interface. diff --git a/src/Network/Packets/ServerToClient/ServerToClientPackets.xml b/src/Network/Packets/ServerToClient/ServerToClientPackets.xml index 3a93efe10..207bedd9a 100644 --- a/src/Network/Packets/ServerToClient/ServerToClientPackets.xml +++ b/src/Network/Packets/ServerToClient/ServerToClientPackets.xml @@ -3168,21 +3168,21 @@ C1HeaderWithSubCode 26 - FF - CurrentHealthAndShieldExtended - 12 + FE + MaximumHealthAndShield + 9 ServerToClient - Periodically, or if the current health or shield changed on the server side, e.g. by hits. + When the maximum health changed, e.g. by adding stat points or changed items. The health and shield bar is updated on the game client user interface. 4 - IntegerLittleEndian + ShortBigEndian Health - 8 - IntegerLittleEndian + 7 + ShortBigEndian Shield @@ -3190,34 +3190,54 @@ C1HeaderWithSubCode 26 - FE - MaximumHealthAndShield - 9 + FF + CurrentStatsExtended + 24 ServerToClient - When the maximum health changed, e.g. by adding stat points or changed items. - The health and shield bar is updated on the game client user interface. + Periodically, or if the current stats, like health, shield, mana or attack speed changed on the server side, e.g. by hits. + The values are updated on the game client user interface. 4 - ShortBigEndian + IntegerLittleEndian Health - 7 - ShortBigEndian + 8 + IntegerLittleEndian Shield + + 12 + IntegerLittleEndian + Mana + + + 16 + IntegerLittleEndian + Ability + + + 20 + ShortLittleEndian + AttackSpeed + + + 22 + ShortLittleEndian + MagicSpeed + C1HeaderWithSubCode 26 FE - MaximumHealthAndShieldExtended - 12 + MaximumStatsExtended + 20 ServerToClient - When the maximum health changed, e.g. by adding stat points or changed items. - The health and shield bar is updated on the game client user interface. + When the maximum stats, like health, shield, mana or attack speed changed on the server side, e.g. by adding stat points or changed items. + The values are updated on the game client user interface. 4 @@ -3229,6 +3249,16 @@ IntegerLittleEndian Shield + + 12 + IntegerLittleEndian + Mana + + + 16 + IntegerLittleEndian + Ability + @@ -3297,28 +3327,6 @@ - - C1HeaderWithSubCode - 27 - FF - CurrentManaAndAbilityExtended - 12 - ServerToClient - The currently available mana or ability has changed, e.g. by using a skill. - The mana and ability bar is updated on the game client user interface. - - - 4 - IntegerLittleEndian - Mana - - - 8 - IntegerLittleEndian - Ability - - - C1HeaderWithSubCode 27 @@ -3341,28 +3349,6 @@ - - C1HeaderWithSubCode - 27 - FE - MaximumManaAndAbilityExtended - 12 - ServerToClient - The maximum available mana or ability has changed, e.g. by adding stat points. - The mana and ability bar is updated on the game client user interface. - - - 4 - IntegerLittleEndian - Mana - - - 8 - IntegerLittleEndian - Ability - - - C1Header 28 diff --git a/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs b/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs index 8f55d24bb..10192f384 100644 --- a/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs +++ b/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs @@ -8668,28 +8668,28 @@ public ushort Shield /// -/// Is sent by the server when: Periodically, or if the current health or shield changed on the server side, e.g. by hits. +/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. /// Causes reaction on client side: The health and shield bar is updated on the game client user interface. /// -public readonly ref struct CurrentHealthAndShieldExtendedRef +public readonly ref struct MaximumHealthAndShieldRef { private readonly Span _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public CurrentHealthAndShieldExtendedRef(Span data) + public MaximumHealthAndShieldRef(Span data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private CurrentHealthAndShieldExtendedRef(Span data, bool initialize) + private MaximumHealthAndShieldRef(Span data, bool initialize) { this._data = data; if (initialize) @@ -8716,12 +8716,12 @@ private CurrentHealthAndShieldExtendedRef(Span data, bool initialize) /// Gets the operation sub-code of this data packet. /// The is used as a grouping key. /// - public static byte SubCode => 0xFF; + public static byte SubCode => 0xFE; /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 12; + public static int Length => 9; /// /// Gets the header of this packet. @@ -8731,60 +8731,60 @@ private CurrentHealthAndShieldExtendedRef(Span data, bool initialize) /// /// Gets or sets the health. /// - public uint Health + public ushort Health { - get => ReadUInt32LittleEndian(this._data[4..]); - set => WriteUInt32LittleEndian(this._data[4..], value); + get => ReadUInt16BigEndian(this._data[4..]); + set => WriteUInt16BigEndian(this._data[4..], value); } /// /// Gets or sets the shield. /// - public uint Shield + public ushort Shield { - get => ReadUInt32LittleEndian(this._data[8..]); - set => WriteUInt32LittleEndian(this._data[8..], value); + get => ReadUInt16BigEndian(this._data[7..]); + set => WriteUInt16BigEndian(this._data[7..], value); } /// - /// Performs an implicit conversion from a Span of bytes to a . + /// Performs an implicit conversion from a Span of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator CurrentHealthAndShieldExtendedRef(Span packet) => new (packet, false); + public static implicit operator MaximumHealthAndShieldRef(Span packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Span of bytes. + /// Performs an implicit conversion from to a Span of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Span(CurrentHealthAndShieldExtendedRef packet) => packet._data; + public static implicit operator Span(MaximumHealthAndShieldRef packet) => packet._data; } /// -/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. -/// Causes reaction on client side: The health and shield bar is updated on the game client user interface. +/// Is sent by the server when: Periodically, or if the current stats, like health, shield, mana or attack speed changed on the server side, e.g. by hits. +/// Causes reaction on client side: The values are updated on the game client user interface. /// -public readonly ref struct MaximumHealthAndShieldRef +public readonly ref struct CurrentStatsExtendedRef { private readonly Span _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public MaximumHealthAndShieldRef(Span data) + public CurrentStatsExtendedRef(Span data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumHealthAndShieldRef(Span data, bool initialize) + private CurrentStatsExtendedRef(Span data, bool initialize) { this._data = data; if (initialize) @@ -8811,12 +8811,12 @@ private MaximumHealthAndShieldRef(Span data, bool initialize) /// Gets the operation sub-code of this data packet. /// The is used as a grouping key. /// - public static byte SubCode => 0xFE; + public static byte SubCode => 0xFF; /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 9; + public static int Length => 24; /// /// Gets the header of this packet. @@ -8826,60 +8826,96 @@ private MaximumHealthAndShieldRef(Span data, bool initialize) /// /// Gets or sets the health. /// - public ushort Health + public uint Health { - get => ReadUInt16BigEndian(this._data[4..]); - set => WriteUInt16BigEndian(this._data[4..], value); + get => ReadUInt32LittleEndian(this._data[4..]); + set => WriteUInt32LittleEndian(this._data[4..], value); } /// /// Gets or sets the shield. /// - public ushort Shield + public uint Shield { - get => ReadUInt16BigEndian(this._data[7..]); - set => WriteUInt16BigEndian(this._data[7..], value); + get => ReadUInt32LittleEndian(this._data[8..]); + set => WriteUInt32LittleEndian(this._data[8..], value); } /// - /// Performs an implicit conversion from a Span of bytes to a . + /// Gets or sets the mana. + /// + public uint Mana + { + get => ReadUInt32LittleEndian(this._data[12..]); + set => WriteUInt32LittleEndian(this._data[12..], value); + } + + /// + /// Gets or sets the ability. + /// + public uint Ability + { + get => ReadUInt32LittleEndian(this._data[16..]); + set => WriteUInt32LittleEndian(this._data[16..], value); + } + + /// + /// Gets or sets the attack speed. + /// + public ushort AttackSpeed + { + get => ReadUInt16LittleEndian(this._data[20..]); + set => WriteUInt16LittleEndian(this._data[20..], value); + } + + /// + /// Gets or sets the magic speed. + /// + public ushort MagicSpeed + { + get => ReadUInt16LittleEndian(this._data[22..]); + set => WriteUInt16LittleEndian(this._data[22..], value); + } + + /// + /// Performs an implicit conversion from a Span of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator MaximumHealthAndShieldRef(Span packet) => new (packet, false); + public static implicit operator CurrentStatsExtendedRef(Span packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Span of bytes. + /// Performs an implicit conversion from to a Span of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Span(MaximumHealthAndShieldRef packet) => packet._data; + public static implicit operator Span(CurrentStatsExtendedRef packet) => packet._data; } /// -/// Is sent by the server when: When the maximum health changed, e.g. by adding stat points or changed items. -/// Causes reaction on client side: The health and shield bar is updated on the game client user interface. +/// Is sent by the server when: When the maximum stats, like health, shield, mana or attack speed changed on the server side, e.g. by adding stat points or changed items. +/// Causes reaction on client side: The values are updated on the game client user interface. /// -public readonly ref struct MaximumHealthAndShieldExtendedRef +public readonly ref struct MaximumStatsExtendedRef { private readonly Span _data; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. - public MaximumHealthAndShieldExtendedRef(Span data) + public MaximumStatsExtendedRef(Span data) : this(data, true) { } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The underlying data. /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumHealthAndShieldExtendedRef(Span data, bool initialize) + private MaximumStatsExtendedRef(Span data, bool initialize) { this._data = data; if (initialize) @@ -8911,7 +8947,7 @@ private MaximumHealthAndShieldExtendedRef(Span data, bool initialize) /// /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. /// - public static int Length => 12; + public static int Length => 20; /// /// Gets the header of this packet. @@ -8937,18 +8973,36 @@ public uint Shield } /// - /// Performs an implicit conversion from a Span of bytes to a . + /// Gets or sets the mana. + /// + public uint Mana + { + get => ReadUInt32LittleEndian(this._data[12..]); + set => WriteUInt32LittleEndian(this._data[12..], value); + } + + /// + /// Gets or sets the ability. + /// + public uint Ability + { + get => ReadUInt32LittleEndian(this._data[16..]); + set => WriteUInt32LittleEndian(this._data[16..], value); + } + + /// + /// Performs an implicit conversion from a Span of bytes to a . /// /// The packet as span. /// The packet as struct. - public static implicit operator MaximumHealthAndShieldExtendedRef(Span packet) => new (packet, false); + public static implicit operator MaximumStatsExtendedRef(Span packet) => new (packet, false); /// - /// Performs an implicit conversion from to a Span of bytes. + /// Performs an implicit conversion from to a Span of bytes. /// /// The packet as struct. /// The packet as byte span. - public static implicit operator Span(MaximumHealthAndShieldExtendedRef packet) => packet._data; + public static implicit operator Span(MaximumStatsExtendedRef packet) => packet._data; } @@ -9237,101 +9291,6 @@ public ushort Ability } -/// -/// Is sent by the server when: The currently available mana or ability has changed, e.g. by using a skill. -/// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. -/// -public readonly ref struct CurrentManaAndAbilityExtendedRef -{ - private readonly Span _data; - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - public CurrentManaAndAbilityExtendedRef(Span data) - : this(data, true) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - /// If set to true, the header data is automatically initialized and written to the underlying span. - private CurrentManaAndAbilityExtendedRef(Span data, bool initialize) - { - this._data = data; - if (initialize) - { - var header = this.Header; - header.Type = HeaderType; - header.Code = Code; - header.Length = (byte)Math.Min(data.Length, Length); - header.SubCode = SubCode; - } - } - - /// - /// Gets the header type of this data packet. - /// - public static byte HeaderType => 0xC1; - - /// - /// Gets the operation code of this data packet. - /// - public static byte Code => 0x27; - - /// - /// Gets the operation sub-code of this data packet. - /// The is used as a grouping key. - /// - public static byte SubCode => 0xFF; - - /// - /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. - /// - public static int Length => 12; - - /// - /// Gets the header of this packet. - /// - public C1HeaderWithSubCodeRef Header => new (this._data); - - /// - /// Gets or sets the mana. - /// - public uint Mana - { - get => ReadUInt32LittleEndian(this._data[4..]); - set => WriteUInt32LittleEndian(this._data[4..], value); - } - - /// - /// Gets or sets the ability. - /// - public uint Ability - { - get => ReadUInt32LittleEndian(this._data[8..]); - set => WriteUInt32LittleEndian(this._data[8..], value); - } - - /// - /// Performs an implicit conversion from a Span of bytes to a . - /// - /// The packet as span. - /// The packet as struct. - public static implicit operator CurrentManaAndAbilityExtendedRef(Span packet) => new (packet, false); - - /// - /// Performs an implicit conversion from to a Span of bytes. - /// - /// The packet as struct. - /// The packet as byte span. - public static implicit operator Span(CurrentManaAndAbilityExtendedRef packet) => packet._data; -} - - /// /// Is sent by the server when: The maximum available mana or ability has changed, e.g. by adding stat points. /// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. @@ -9427,101 +9386,6 @@ public ushort Ability } -/// -/// Is sent by the server when: The maximum available mana or ability has changed, e.g. by adding stat points. -/// Causes reaction on client side: The mana and ability bar is updated on the game client user interface. -/// -public readonly ref struct MaximumManaAndAbilityExtendedRef -{ - private readonly Span _data; - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - public MaximumManaAndAbilityExtendedRef(Span data) - : this(data, true) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The underlying data. - /// If set to true, the header data is automatically initialized and written to the underlying span. - private MaximumManaAndAbilityExtendedRef(Span data, bool initialize) - { - this._data = data; - if (initialize) - { - var header = this.Header; - header.Type = HeaderType; - header.Code = Code; - header.Length = (byte)Math.Min(data.Length, Length); - header.SubCode = SubCode; - } - } - - /// - /// Gets the header type of this data packet. - /// - public static byte HeaderType => 0xC1; - - /// - /// Gets the operation code of this data packet. - /// - public static byte Code => 0x27; - - /// - /// Gets the operation sub-code of this data packet. - /// The is used as a grouping key. - /// - public static byte SubCode => 0xFE; - - /// - /// Gets the initial length of this data packet. When the size is dynamic, this value may be bigger than actually needed. - /// - public static int Length => 12; - - /// - /// Gets the header of this packet. - /// - public C1HeaderWithSubCodeRef Header => new (this._data); - - /// - /// Gets or sets the mana. - /// - public uint Mana - { - get => ReadUInt32LittleEndian(this._data[4..]); - set => WriteUInt32LittleEndian(this._data[4..], value); - } - - /// - /// Gets or sets the ability. - /// - public uint Ability - { - get => ReadUInt32LittleEndian(this._data[8..]); - set => WriteUInt32LittleEndian(this._data[8..], value); - } - - /// - /// Performs an implicit conversion from a Span of bytes to a . - /// - /// The packet as span. - /// The packet as struct. - public static implicit operator MaximumManaAndAbilityExtendedRef(Span packet) => new (packet, false); - - /// - /// Performs an implicit conversion from to a Span of bytes. - /// - /// The packet as struct. - /// The packet as byte span. - public static implicit operator Span(MaximumManaAndAbilityExtendedRef packet) => packet._data; -} - - /// /// Is sent by the server when: The item has been removed from the inventory of the player. /// Causes reaction on client side: The client removes the item in the inventory user interface. From 4761521711bc029f3691979b46ab3ff0c3672e2b Mon Sep 17 00:00:00 2001 From: sven-n Date: Fri, 18 Oct 2024 20:27:51 +0200 Subject: [PATCH 03/11] fixed endianness of effect time --- docs/Packets/C3-29-ConsumeItemWithEffect_by-server.md | 2 +- src/Network/Packets/ServerToClient/ServerToClientPackets.cs | 4 ++-- src/Network/Packets/ServerToClient/ServerToClientPackets.xml | 2 +- .../Packets/ServerToClient/ServerToClientPacketsRef.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/Packets/C3-29-ConsumeItemWithEffect_by-server.md b/docs/Packets/C3-29-ConsumeItemWithEffect_by-server.md index 9c34e9d60..d87d15caa 100644 --- a/docs/Packets/C3-29-ConsumeItemWithEffect_by-server.md +++ b/docs/Packets/C3-29-ConsumeItemWithEffect_by-server.md @@ -16,7 +16,7 @@ The player is shown in a red color and has increased attack speed. | 1 | 1 | Byte | 6 | Packet header - length of the packet | | 2 | 1 | Byte | 0x29 | Packet header - packet type identifier | | 3 | 1 | ConsumedItemType | | ItemType | -| 4 | 2 | ShortBigEndian | | EffectTimeInSeconds | +| 4 | 2 | ShortLittleEndian | | EffectTimeInSeconds | ### ConsumedItemType Enum diff --git a/src/Network/Packets/ServerToClient/ServerToClientPackets.cs b/src/Network/Packets/ServerToClient/ServerToClientPackets.cs index 28a34366d..b3410ae5c 100644 --- a/src/Network/Packets/ServerToClient/ServerToClientPackets.cs +++ b/src/Network/Packets/ServerToClient/ServerToClientPackets.cs @@ -9770,8 +9770,8 @@ public ConsumeItemWithEffect.ConsumedItemType ItemType /// public ushort EffectTimeInSeconds { - get => ReadUInt16BigEndian(this._data.Span[4..]); - set => WriteUInt16BigEndian(this._data.Span[4..], value); + get => ReadUInt16LittleEndian(this._data.Span[4..]); + set => WriteUInt16LittleEndian(this._data.Span[4..], value); } /// diff --git a/src/Network/Packets/ServerToClient/ServerToClientPackets.xml b/src/Network/Packets/ServerToClient/ServerToClientPackets.xml index 207bedd9a..4aa40c1aa 100644 --- a/src/Network/Packets/ServerToClient/ServerToClientPackets.xml +++ b/src/Network/Packets/ServerToClient/ServerToClientPackets.xml @@ -3389,7 +3389,7 @@ 4 - ShortBigEndian + ShortLittleEndian EffectTimeInSeconds diff --git a/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs b/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs index 10192f384..c272830c2 100644 --- a/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs +++ b/src/Network/Packets/ServerToClient/ServerToClientPacketsRef.cs @@ -9543,8 +9543,8 @@ public ConsumeItemWithEffect.ConsumedItemType ItemType /// public ushort EffectTimeInSeconds { - get => ReadUInt16BigEndian(this._data[4..]); - set => WriteUInt16BigEndian(this._data[4..], value); + get => ReadUInt16LittleEndian(this._data[4..]); + set => WriteUInt16LittleEndian(this._data[4..], value); } /// From 0bd52d55a04567c7d0ee039ccfa9b78f2f4dbf67 Mon Sep 17 00:00:00 2001 From: sven-n Date: Fri, 18 Oct 2024 20:31:56 +0200 Subject: [PATCH 04/11] Added possibility to define a maximum value for an attribute --- src/AttributeSystem/AttributeDefinition.cs | 11 +- src/AttributeSystem/AttributeSystem.cs | 5 + src/AttributeSystem/ComposableAttribute.cs | 8 +- src/AttributeSystem/StatAttribute.cs | 10 +- .../Character/IncreaseStatsAction.cs | 12 + ...1018200704_AddAttributeMaximum.Designer.cs | 5008 +++++++++++++++++ .../20241018200704_AddAttributeMaximum.cs | 30 + .../EntityDataContextModelSnapshot.cs | 3 + .../GameConfigurationInitializerBase.cs | 1 + 9 files changed, 5080 insertions(+), 8 deletions(-) create mode 100644 src/Persistence/EntityFramework/Migrations/20241018200704_AddAttributeMaximum.Designer.cs create mode 100644 src/Persistence/EntityFramework/Migrations/20241018200704_AddAttributeMaximum.cs diff --git a/src/AttributeSystem/AttributeDefinition.cs b/src/AttributeSystem/AttributeDefinition.cs index 5c0487a19..7f7c32039 100644 --- a/src/AttributeSystem/AttributeDefinition.cs +++ b/src/AttributeSystem/AttributeDefinition.cs @@ -38,19 +38,18 @@ public AttributeDefinition(Guid id, string designation, string description) /// /// Gets or sets the designation. /// - /// - /// The designation. - /// public string? Designation { get; set; } /// /// Gets or sets the description. /// - /// - /// The description. - /// public string? Description { get; set; } + /// + /// Gets or sets the maximum value of this attribute, if the value should be capped. + /// + public float? MaximumValue { get; set; } + /// /// Implements the operator ==. /// diff --git a/src/AttributeSystem/AttributeSystem.cs b/src/AttributeSystem/AttributeSystem.cs index d3af091e6..432e1b768 100644 --- a/src/AttributeSystem/AttributeSystem.cs +++ b/src/AttributeSystem/AttributeSystem.cs @@ -111,6 +111,11 @@ public float GetValueOfAttribute(AttributeDefinition? attributeDefinition) var element = this.GetAttribute(attributeDefinition); if (element != null) { + if (attributeDefinition?.MaximumValue is { } maximumValue && element.Value > maximumValue) + { + return maximumValue; + } + return element.Value; } diff --git a/src/AttributeSystem/ComposableAttribute.cs b/src/AttributeSystem/ComposableAttribute.cs index 4423689e1..df4dd8782 100644 --- a/src/AttributeSystem/ComposableAttribute.cs +++ b/src/AttributeSystem/ComposableAttribute.cs @@ -75,7 +75,13 @@ private float GetAndCacheValue() // nothing to do } - this._cachedValue = (rawValues * multiValues + finalValues); + var newValue = (rawValues * multiValues + finalValues); + if (this.Definition.MaximumValue.HasValue) + { + newValue = Math.Min(this.Definition.MaximumValue.Value, newValue); + } + + this._cachedValue = newValue; return this._cachedValue.Value; } diff --git a/src/AttributeSystem/StatAttribute.cs b/src/AttributeSystem/StatAttribute.cs index 3d5bd168d..4d53cdbff 100644 --- a/src/AttributeSystem/StatAttribute.cs +++ b/src/AttributeSystem/StatAttribute.cs @@ -38,7 +38,15 @@ public StatAttribute(AttributeDefinition definition, float baseValue) /// public new virtual float Value { - get => this._statValue; + get + { + if (this.Definition.MaximumValue.HasValue) + { + return Math.Min(this.Definition.MaximumValue.Value, this._statValue); + } + + return this._statValue; + } set { diff --git a/src/GameLogic/PlayerActions/Character/IncreaseStatsAction.cs b/src/GameLogic/PlayerActions/Character/IncreaseStatsAction.cs index cedfcf2dd..ecd813452 100644 --- a/src/GameLogic/PlayerActions/Character/IncreaseStatsAction.cs +++ b/src/GameLogic/PlayerActions/Character/IncreaseStatsAction.cs @@ -41,6 +41,18 @@ public async ValueTask IncreaseStatsAsync(Player player, AttributeDefinition tar var attributeDef = selectedCharacter.CharacterClass?.GetStatAttribute(targetAttribute); if (attributeDef is { IncreasableByPlayer: true }) { + if (attributeDef.Attribute?.MaximumValue is { } maximumValue + && player.Attributes![attributeDef.Attribute] is { } current + && current + amount > maximumValue) + { + amount = (ushort)(maximumValue - current); + if (amount == 0) + { + await player.InvokeViewPlugInAsync(p => p.ShowMessageAsync($"Maximum of {attributeDef.Attribute?.MaximumValue} {attributeDef.Attribute?.Designation} has been reached.", MessageType.BlueNormal)).ConfigureAwait(false); + return; + } + } + player.Attributes![attributeDef.Attribute] += amount; selectedCharacter.LevelUpPoints -= Math.Min(selectedCharacter.LevelUpPoints, amount); diff --git a/src/Persistence/EntityFramework/Migrations/20241018200704_AddAttributeMaximum.Designer.cs b/src/Persistence/EntityFramework/Migrations/20241018200704_AddAttributeMaximum.Designer.cs new file mode 100644 index 000000000..12e4a0705 --- /dev/null +++ b/src/Persistence/EntityFramework/Migrations/20241018200704_AddAttributeMaximum.Designer.cs @@ -0,0 +1,5008 @@ +// +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("20241018200704_AddAttributeMaximum")] + partial class AddAttributeMaximum + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.6") + .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("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.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("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("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.HasIndex("InputAttributeId"); + + b.HasIndex("OperandAttributeId"); + + b.HasIndex("PowerUpDefinitionValueId"); + + 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") + .IsRequired() + .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("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("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("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("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("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.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("CharacterId") + .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("DurationId") + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("InformObservers") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SendDuration") + .HasColumnType("boolean"); + + b.Property("StopByDeath") + .HasColumnType("boolean"); + + b.Property("SubType") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("DurationId") + .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("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("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BoostId") + .IsUnique(); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("MagicEffectDefinitionId"); + + 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("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("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("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("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("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.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", "RawDuration") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "DurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMagicEffects") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawDuration"); + }); + + 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.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.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("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"); + }); + + 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("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/20241018200704_AddAttributeMaximum.cs b/src/Persistence/EntityFramework/Migrations/20241018200704_AddAttributeMaximum.cs new file mode 100644 index 000000000..aaf1d78c5 --- /dev/null +++ b/src/Persistence/EntityFramework/Migrations/20241018200704_AddAttributeMaximum.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MUnique.OpenMU.Persistence.EntityFramework.Migrations +{ + /// + public partial class AddAttributeMaximum : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "MaximumValue", + schema: "config", + table: "AttributeDefinition", + type: "real", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "MaximumValue", + schema: "config", + table: "AttributeDefinition"); + } + } +} diff --git a/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs b/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs index 29f5050dd..5bbdebef3 100644 --- a/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs +++ b/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs @@ -130,6 +130,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("GameConfigurationId") .HasColumnType("uuid"); + b.Property("MaximumValue") + .HasColumnType("real"); + b.HasKey("Id"); b.HasIndex("GameConfigurationId"); diff --git a/src/Persistence/Initialization/GameConfigurationInitializerBase.cs b/src/Persistence/Initialization/GameConfigurationInitializerBase.cs index 8933a68d5..df3c961e4 100644 --- a/src/Persistence/Initialization/GameConfigurationInitializerBase.cs +++ b/src/Persistence/Initialization/GameConfigurationInitializerBase.cs @@ -220,6 +220,7 @@ private void CreateStatAttributes() foreach (var attribute in attributes) { var persistentAttribute = this.Context.CreateNew(attribute.Id, attribute.Designation, attribute.Description); + persistentAttribute.MaximumValue = attribute.MaximumValue; this.GameConfiguration.Attributes.Add(persistentAttribute); } } From 1ad59375c6711ed8f452ff29f05c516057567407 Mon Sep 17 00:00:00 2001 From: sven-n Date: Fri, 18 Oct 2024 20:34:49 +0200 Subject: [PATCH 05/11] Fixed attack speed when equipping two weapons --- src/GameLogic/Attributes/Stats.cs | 23 ++++++++++++++++++- .../CharacterClassInitialization.cs | 12 ++++++++++ .../VersionSeasonSix/Items/Weapons.cs | 7 +++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/GameLogic/Attributes/Stats.cs b/src/GameLogic/Attributes/Stats.cs index d37a7bd08..e9a867261 100644 --- a/src/GameLogic/Attributes/Stats.cs +++ b/src/GameLogic/Attributes/Stats.cs @@ -284,7 +284,28 @@ public class Stats /// /// Gets the attack speed attribute definition. /// - public static AttributeDefinition AttackSpeed { get; } = new (new Guid("BACC1115-1E8B-4E62-B952-8F8DDB58A949"), "Attack Speed", string.Empty); + public static AttributeDefinition AttackSpeed { get; } = new(new Guid("BACC1115-1E8B-4E62-B952-8F8DDB58A949"), "Attack Speed", string.Empty) + { + MaximumValue = 200, + }; + + /// + /// Gets the attack speed by weapon attribute definition. + /// + public static AttributeDefinition AttackSpeedByWeapon { get; } = new(new Guid("45EEEDEE-C76B-40E6-A0BC-2B493E10B140"), "Attack Speed by Weapons", string.Empty); + + /// + /// Gets the attribute which says, if two weapons are equipped. + /// + public static AttributeDefinition AreTwoWeaponsEquipped { get; } = new(new Guid("56DA895D-BAFD-4A5C-9864-B17AB8369998"), "Are two weapons equipped", string.Empty) + { + MaximumValue = 1, + }; + + /// + /// Gets the attribute which counts the equipped weapons. + /// + public static AttributeDefinition EquippedWeaponCount { get; } = new(new Guid("15D6493F-549D-455F-9FFF-A0D589FD7DA2"), "Equipped Weapon Count", string.Empty); /// /// Gets the magic speed attribute definition which is used for some skills. diff --git a/src/Persistence/Initialization/CharacterClasses/CharacterClassInitialization.cs b/src/Persistence/Initialization/CharacterClasses/CharacterClassInitialization.cs index 4498203aa..1e22b81a6 100644 --- a/src/Persistence/Initialization/CharacterClasses/CharacterClassInitialization.cs +++ b/src/Persistence/Initialization/CharacterClasses/CharacterClassInitialization.cs @@ -107,6 +107,17 @@ private void AddCommonAttributeRelationships(ICollection attributeRelationships.Add(this.CreateAttributeRelationship(Stats.DefensePvm, 1, Stats.DefenseBase)); attributeRelationships.Add(this.CreateAttributeRelationship(Stats.DefensePvp, 1, Stats.DefenseBase)); + attributeRelationships.Add(this.CreateAttributeRelationship(Stats.AttackSpeed, 1, Stats.AttackSpeedByWeapon)); + attributeRelationships.Add(this.CreateAttributeRelationship(Stats.MagicSpeed, 1, Stats.AttackSpeedByWeapon)); + + // If two weapons are equipped we subtract the half of the sum of the speeds again from the attack speed + attributeRelationships.Add(this.CreateAttributeRelationship(Stats.AreTwoWeaponsEquipped, 1, Stats.EquippedWeaponCount)); + var tempSpeed = this.Context.CreateNew(Guid.NewGuid(), "Temp Half weapon attack speed", string.Empty); + this.GameConfiguration.Attributes.Add(tempSpeed); + attributeRelationships.Add(this.CreateAttributeRelationship(tempSpeed, -0.5f, Stats.AttackSpeedByWeapon)); + attributeRelationships.Add(this.CreateConditionalRelationship(Stats.AttackSpeed, Stats.AreTwoWeaponsEquipped, tempSpeed)); + attributeRelationships.Add(this.CreateConditionalRelationship(Stats.MagicSpeed, Stats.AreTwoWeaponsEquipped, tempSpeed)); + attributeRelationships.Add(this.CreateConditionalRelationship(Stats.DefenseBase, Stats.IsShieldEquipped, Stats.BonusDefenseWithShield)); var tempDefense = this.Context.CreateNew(Guid.NewGuid(), "Temp Defense Bonus multiplier with Shield", string.Empty); @@ -140,6 +151,7 @@ private void AddCommonBaseAttributeValues(ICollection baseA baseAttributeValues.Add(this.CreateConstValueAttribute(0.03f, Stats.PoisonDamageMultiplier)); baseAttributeValues.Add(this.CreateConstValueAttribute(1, Stats.ItemDurationIncrease)); baseAttributeValues.Add(this.CreateConstValueAttribute(2, Stats.AbilityRecoveryAbsolute)); + baseAttributeValues.Add(this.CreateConstValueAttribute(-1, Stats.AreTwoWeaponsEquipped)); if (isMaster) { diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs index b1e768fa6..e8213df07 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs @@ -321,7 +321,7 @@ protected void CreateWeapon(byte @group, byte number, byte slot, int skillNumber maxDamagePowerUp.BonusPerLevelTable = this._weaponDamageIncreaseTable; item.BasePowerUpAttributes.Add(maxDamagePowerUp); - var speedPowerUp = this.CreateItemBasePowerUpDefinition(Stats.AttackSpeed, attackSpeed, AggregateType.AddRaw); + var speedPowerUp = this.CreateItemBasePowerUpDefinition(Stats.AttackSpeedByWeapon, attackSpeed, AggregateType.AddRaw); item.BasePowerUpAttributes.Add(speedPowerUp); this.CreateItemRequirementIfNeeded(item, Stats.Level, levelRequirement); @@ -368,6 +368,11 @@ protected void CreateWeapon(byte @group, byte number, byte slot, int skillNumber } } + if (height > 1) // exclude bolts and arrows + { + item.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.EquippedWeaponCount, 1, AggregateType.AddRaw)); + } + if (group == (int)ItemGroups.Bows && height > 1) { item.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.AmmunitionConsumptionRate, 1, AggregateType.AddRaw)); From 02f3e114d38b4d2a6787ae16ba4795afa9e167ee Mon Sep 17 00:00:00 2001 From: sven-n Date: Fri, 18 Oct 2024 20:37:51 +0200 Subject: [PATCH 06/11] Transmit max attack speed --- .../RemoteView/Character/UpdateCharacterStatsExtendedPlugIn.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/GameServer/RemoteView/Character/UpdateCharacterStatsExtendedPlugIn.cs b/src/GameServer/RemoteView/Character/UpdateCharacterStatsExtendedPlugIn.cs index cffd101c9..80124d500 100644 --- a/src/GameServer/RemoteView/Character/UpdateCharacterStatsExtendedPlugIn.cs +++ b/src/GameServer/RemoteView/Character/UpdateCharacterStatsExtendedPlugIn.cs @@ -37,6 +37,7 @@ public async ValueTask UpdateCharacterStatsAsync() return; } + var maxAttackSpeed = this._player.GameContext.Configuration.Attributes.FirstOrDefault(a => a == Stats.AttackSpeed)?.MaximumValue ?? 200; await connection.SendCharacterInformationExtendedAsync( this._player.Position.X, this._player.Position.Y, @@ -66,7 +67,7 @@ await connection.SendCharacterInformationExtendedAsync( this._player.SelectedCharacter.GetMaximumFruitPoints(), (ushort)this._player.Attributes[Stats.AttackSpeed], (ushort)this._player.Attributes[Stats.MagicSpeed], - 200, // todo: This is the maximum attack speed, make configurable. + (ushort)maxAttackSpeed, (byte)this._player.SelectedCharacter.InventoryExtensions) .ConfigureAwait(false); From 440e00da5aa65e206c65a45eb97ac4355d946a5e Mon Sep 17 00:00:00 2001 From: sven-n Date: Sat, 19 Oct 2024 16:29:10 +0200 Subject: [PATCH 07/11] Fixed speed after ale consumption. It needs to be applied as magic effect on server side. --- src/GameLogic/ItemConstants.cs | 2 +- .../AlcoholConsumeHandlerPlugIn.cs | 6 +-- .../ApplyMagicEffectConsumeHandlerPlugIn.cs | 28 ++++++++-- ...PlugIn.cs => IConsumeSpecialItemPlugIn.cs} | 9 ++-- .../RemoteView/ConsumeSpecialItemPlugIn.cs | 47 +++++++++++++++++ .../RemoteView/DrinkAlcoholPlugIn.cs | 32 ------------ .../Skills/AlcoholEffectInitializer.cs | 52 +++++++++++++++++++ .../Skills/MagicEffectNumber.cs | 5 ++ .../Version075/Items/Potions.cs | 2 + .../Version075/SkillsInitializer.cs | 1 + .../Version095d/SkillsInitializer.cs | 1 + .../VersionSeasonSix/Items/Potions.cs | 1 + .../VersionSeasonSix/SkillsInitializer.cs | 1 + .../ItemConsumptionTest.cs | 37 +++++++++---- 14 files changed, 173 insertions(+), 51 deletions(-) rename src/GameLogic/Views/{IDrinkAlcoholPlugIn.cs => IConsumeSpecialItemPlugIn.cs} (58%) create mode 100644 src/GameServer/RemoteView/ConsumeSpecialItemPlugIn.cs delete mode 100644 src/GameServer/RemoteView/DrinkAlcoholPlugIn.cs create mode 100644 src/Persistence/Initialization/Skills/AlcoholEffectInitializer.cs diff --git a/src/GameLogic/ItemConstants.cs b/src/GameLogic/ItemConstants.cs index e3201cb88..7fe87facb 100644 --- a/src/GameLogic/ItemConstants.cs +++ b/src/GameLogic/ItemConstants.cs @@ -7,7 +7,7 @@ namespace MUnique.OpenMU.GameLogic; /// /// A central place to keep item identifiers, so we can keep track of them. /// -internal class ItemConstants +public class ItemConstants { /// /// Gets the identifier for the summon orb. diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs index 7c75a7663..d30d97575 100644 --- a/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/AlcoholConsumeHandlerPlugIn.cs @@ -15,7 +15,7 @@ namespace MUnique.OpenMU.GameLogic.PlayerActions.ItemConsumeActions; /// [Guid("7FC2FE02-9215-4AD3-958F-D2279CD84266")] [PlugIn(nameof(AlcoholConsumeHandlerPlugIn), "Plugin which handles the alcohol consumption.")] -public class AlcoholConsumeHandlerPlugIn : BaseConsumeHandlerPlugIn +public class AlcoholConsumeHandlerPlugIn : ApplyMagicEffectConsumeHandlerPlugIn { /// public override ItemIdentifier Key => ItemConstants.Alcohol; @@ -25,8 +25,8 @@ public override async ValueTask ConsumeItemAsync(Player player, Item item, { if (await base.ConsumeItemAsync(player, item, targetItem, fruitUsage).ConfigureAwait(false)) { - await player.InvokeViewPlugInAsync(p => p.DrinkAlcoholAsync()).ConfigureAwait(false); - // todo: add magic effect to update stat + var effectDefinition = item.Definition?.ConsumeEffect; + await player.InvokeViewPlugInAsync(p => p.ConsumeSpecialItemAsync(item, (ushort)(effectDefinition?.Duration?.ConstantValue.Value ?? 0))).ConfigureAwait(false); return true; } diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/ApplyMagicEffectConsumeHandlerPlugIn.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/ApplyMagicEffectConsumeHandlerPlugIn.cs index 65fe91381..007c9cb66 100644 --- a/src/GameLogic/PlayerActions/ItemConsumeActions/ApplyMagicEffectConsumeHandlerPlugIn.cs +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/ApplyMagicEffectConsumeHandlerPlugIn.cs @@ -18,13 +18,30 @@ public class ApplyMagicEffectConsumeHandlerPlugIn : BaseConsumeHandlerPlugIn /// public override async ValueTask ConsumeItemAsync(Player player, Item item, Item? targetItem, FruitUsage fruitUsage) { - if (!await base.ConsumeItemAsync(player, item, targetItem, fruitUsage).ConfigureAwait(false)) + if (item.Definition?.ConsumeEffect is not { } effectDefinition) { return false; } - if (item.Definition?.ConsumeEffect is not { } effectDefinition - || !effectDefinition.PowerUpDefinitions.Any() + return await this.ConsumeItemAsyncCore(player, item, targetItem, fruitUsage, effectDefinition).ConfigureAwait(false); + } + + /// + /// Consumes the item at the specified slot with the specified effect and reduces its durability by one. + /// If the durability has reached 0, the item is getting destroyed. + /// If a target slot is specified, the consumption targets the item on this slot (e.g. upgrade of an item by a jewel). + /// + /// The player which is consuming. + /// The item which gets consumed. + /// The item which is the target of the consumption (e.g. upgrade target of a jewel). + /// In case the item is a fruit, this parameter defines how the fruit should be used. + /// The effect definition. + /// + /// The success of the consumption. + /// + protected async ValueTask ConsumeItemAsyncCore(Player player, Item item, Item? targetItem, FruitUsage fruitUsage, MagicEffectDefinition effectDefinition) + { + if (!effectDefinition.PowerUpDefinitions.Any() || effectDefinition.Duration?.ConstantValue.Value is not { } durationInSeconds) { return false; @@ -44,6 +61,11 @@ public override async ValueTask ConsumeItemAsync(Player player, Item item, return false; } + if (!await base.ConsumeItemAsync(player, item, targetItem, fruitUsage).ConfigureAwait(false)) + { + return false; + } + var effect = new MagicEffect(TimeSpan.FromSeconds(durationInSeconds), effectDefinition, boosts!); await player.MagicEffectList.AddEffectAsync(effect).ConfigureAwait(false); return true; diff --git a/src/GameLogic/Views/IDrinkAlcoholPlugIn.cs b/src/GameLogic/Views/IConsumeSpecialItemPlugIn.cs similarity index 58% rename from src/GameLogic/Views/IDrinkAlcoholPlugIn.cs rename to src/GameLogic/Views/IConsumeSpecialItemPlugIn.cs index 49088cdcd..e211bdffb 100644 --- a/src/GameLogic/Views/IDrinkAlcoholPlugIn.cs +++ b/src/GameLogic/Views/IConsumeSpecialItemPlugIn.cs @@ -7,10 +7,13 @@ namespace MUnique.OpenMU.GameLogic.Views; /// /// Interface of a view whose implementation informs about the alcohol consumption of the own character. The character appears to be red (drunken). /// -public interface IDrinkAlcoholPlugIn : IViewPlugIn +public interface IConsumeSpecialItemPlugIn : IViewPlugIn { /// - /// Shows the effects of drinking alcohol. + /// Consumes the special item. /// - ValueTask DrinkAlcoholAsync(); + /// The item. + /// The effect time in seconds. + /// + ValueTask ConsumeSpecialItemAsync(Item item, ushort effectTimeInSeconds); } \ No newline at end of file diff --git a/src/GameServer/RemoteView/ConsumeSpecialItemPlugIn.cs b/src/GameServer/RemoteView/ConsumeSpecialItemPlugIn.cs new file mode 100644 index 000000000..2767d4b63 --- /dev/null +++ b/src/GameServer/RemoteView/ConsumeSpecialItemPlugIn.cs @@ -0,0 +1,47 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameServer.RemoteView; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.DataModel.Entities; +using MUnique.OpenMU.GameLogic; +using MUnique.OpenMU.GameLogic.Views; +using MUnique.OpenMU.Network.Packets.ServerToClient; +using MUnique.OpenMU.PlugIns; + +/// +/// The default implementation of the which is forwarding everything to the game client with specific data packets. +/// +[PlugIn(nameof(ConsumeSpecialItemPlugIn), "The default implementation of the IConsumeSpecialItemPlugIn which is forwarding everything to the game client with specific data packets.")] +[Guid("a31546d8-bf79-43dd-872c-52f24ea9bca9")] +public class ConsumeSpecialItemPlugIn : IConsumeSpecialItemPlugIn +{ + private readonly RemotePlayer _player; + + /// + /// Initializes a new instance of the class. + /// + /// The player. + public ConsumeSpecialItemPlugIn(RemotePlayer player) => this._player = player; + + /// + public async ValueTask ConsumeSpecialItemAsync(Item item, ushort effectTimeInSeconds) + { + if (item.Definition is null) + { + return; + } + + var itemIdentifier = new ItemIdentifier(item.Definition.Number, item.Definition.Group); + if (itemIdentifier == ItemConstants.Alcohol) + { + await this._player.Connection.SendConsumeItemWithEffectAsync(ConsumeItemWithEffect.ConsumedItemType.Ale, effectTimeInSeconds).ConfigureAwait(false); + } + else if (itemIdentifier == ItemConstants.SiegePotion && item.Level == 1) + { + await this._player.Connection.SendConsumeItemWithEffectAsync(ConsumeItemWithEffect.ConsumedItemType.PotionOfSoul, effectTimeInSeconds).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/GameServer/RemoteView/DrinkAlcoholPlugIn.cs b/src/GameServer/RemoteView/DrinkAlcoholPlugIn.cs deleted file mode 100644 index b661b2abd..000000000 --- a/src/GameServer/RemoteView/DrinkAlcoholPlugIn.cs +++ /dev/null @@ -1,32 +0,0 @@ -// -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace MUnique.OpenMU.GameServer.RemoteView; - -using System.Runtime.InteropServices; -using MUnique.OpenMU.GameLogic.Views; -using MUnique.OpenMU.Network.Packets.ServerToClient; -using MUnique.OpenMU.PlugIns; - -/// -/// The default implementation of the which is forwarding everything to the game client with specific data packets. -/// -[PlugIn("DrinkAlcoholPlugIn", "The default implementation of the IDrinkAlcoholPlugIn which is forwarding everything to the game client with specific data packets.")] -[Guid("a31546d8-bf79-43dd-872c-52f24ea9bca9")] -public class DrinkAlcoholPlugIn : IDrinkAlcoholPlugIn -{ - private readonly RemotePlayer _player; - - /// - /// Initializes a new instance of the class. - /// - /// The player. - public DrinkAlcoholPlugIn(RemotePlayer player) => this._player = player; - - /// - public async ValueTask DrinkAlcoholAsync() - { - await this._player.Connection.SendConsumeItemWithEffectAsync(ConsumeItemWithEffect.ConsumedItemType.Ale, 80).ConfigureAwait(false); - } -} \ No newline at end of file diff --git a/src/Persistence/Initialization/Skills/AlcoholEffectInitializer.cs b/src/Persistence/Initialization/Skills/AlcoholEffectInitializer.cs new file mode 100644 index 000000000..f8b1a91fe --- /dev/null +++ b/src/Persistence/Initialization/Skills/AlcoholEffectInitializer.cs @@ -0,0 +1,52 @@ +// +// 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.DataModel.Attributes; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.GameLogic.Attributes; + +/// +/// Initializer which initializes the alcohol effect. +/// +public class AlcoholEffectInitializer : InitializerBase +{ + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public AlcoholEffectInitializer(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + public override void Initialize() + { + var magicEffect = this.Context.CreateNew(); + this.GameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (byte)MagicEffectNumber.Alcohol; + magicEffect.SubType = 54; + magicEffect.Name = "Alcohol Effect"; + magicEffect.InformObservers = false; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = false; + magicEffect.Duration = this.Context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 80f; + + var attackSpeedPowerUp = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(attackSpeedPowerUp); + attackSpeedPowerUp.TargetAttribute = Stats.AttackSpeed.GetPersistent(this.GameConfiguration); + attackSpeedPowerUp.Boost = this.Context.CreateNew(); + attackSpeedPowerUp.Boost.ConstantValue.Value = 20f; + + var magicSpeedPowerUp = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(magicSpeedPowerUp); + magicSpeedPowerUp.TargetAttribute = Stats.MagicSpeed.GetPersistent(this.GameConfiguration); + magicSpeedPowerUp.Boost = this.Context.CreateNew(); + magicSpeedPowerUp.Boost.ConstantValue.Value = 20f; + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Skills/MagicEffectNumber.cs b/src/Persistence/Initialization/Skills/MagicEffectNumber.cs index 75eb87744..1bc738568 100644 --- a/src/Persistence/Initialization/Skills/MagicEffectNumber.cs +++ b/src/Persistence/Initialization/Skills/MagicEffectNumber.cs @@ -290,6 +290,11 @@ internal enum MagicEffectNumber : short /// ShieldSkill = 200, + /// + /// The alcohol effect number. + /// + Alcohol = 201, + #endregion } \ No newline at end of file diff --git a/src/Persistence/Initialization/Version075/Items/Potions.cs b/src/Persistence/Initialization/Version075/Items/Potions.cs index 491d7504e..fb5f0e090 100644 --- a/src/Persistence/Initialization/Version075/Items/Potions.cs +++ b/src/Persistence/Initialization/Version075/Items/Potions.cs @@ -6,6 +6,7 @@ namespace MUnique.OpenMU.Persistence.Initialization.Version075.Items; using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.Persistence.Initialization.Skills; /// /// Class which contains item definitions for jewels. @@ -52,6 +53,7 @@ private ItemDefinition CreateAlcohol() alcohol.Width = 1; alcohol.Height = 2; alcohol.SetGuid(alcohol.Group, alcohol.Number); + alcohol.ConsumeEffect = this.GameConfiguration.MagicEffects.First(effect => effect.Number == (short)MagicEffectNumber.Alcohol); return alcohol; } diff --git a/src/Persistence/Initialization/Version075/SkillsInitializer.cs b/src/Persistence/Initialization/Version075/SkillsInitializer.cs index d21b984c7..78a5619f9 100644 --- a/src/Persistence/Initialization/Version075/SkillsInitializer.cs +++ b/src/Persistence/Initialization/Version075/SkillsInitializer.cs @@ -125,6 +125,7 @@ private void InitializeEffects() new GreaterDamageEffectInitializer(this.Context, this.GameConfiguration).Initialize(); new GreaterDefenseEffectInitializer(this.Context, this.GameConfiguration).Initialize(); new HealEffectInitializer(this.Context, this.GameConfiguration).Initialize(); + new AlcoholEffectInitializer(this.Context, this.GameConfiguration).Initialize(); } private void MapSkillsToEffects() diff --git a/src/Persistence/Initialization/Version095d/SkillsInitializer.cs b/src/Persistence/Initialization/Version095d/SkillsInitializer.cs index c11487a98..8baaae6d2 100644 --- a/src/Persistence/Initialization/Version095d/SkillsInitializer.cs +++ b/src/Persistence/Initialization/Version095d/SkillsInitializer.cs @@ -130,6 +130,7 @@ private void InitializeEffects() new GreaterDamageEffectInitializer(this.Context, this.GameConfiguration).Initialize(); new GreaterDefenseEffectInitializer(this.Context, this.GameConfiguration).Initialize(); new HealEffectInitializer(this.Context, this.GameConfiguration).Initialize(); + new AlcoholEffectInitializer(this.Context, this.GameConfiguration).Initialize(); } private void MapSkillsToEffects() diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs index 833d24091..cd4e4e689 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs @@ -74,6 +74,7 @@ private ItemDefinition CreateAlcohol() alcohol.Width = 1; alcohol.Height = 2; alcohol.SetGuid(alcohol.Group, alcohol.Number); + alcohol.ConsumeEffect = this.GameConfiguration.MagicEffects.First(effect => effect.Number == (short)MagicEffectNumber.Alcohol); return alcohol; } diff --git a/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs b/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs index 142cc96a9..6d60dbe41 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs @@ -572,6 +572,7 @@ private void InitializeEffects() new IncreaseHealthEffectInitializer(this.Context, this.GameConfiguration).Initialize(); new IncreaseBlockEffectInitializer(this.Context, this.GameConfiguration).Initialize(); new WizardryEnhanceEffectInitializer(this.Context, this.GameConfiguration).Initialize(); + new AlcoholEffectInitializer(this.Context, this.GameConfiguration).Initialize(); } private void MapSkillsToEffects() diff --git a/tests/MUnique.OpenMU.Tests/ItemConsumptionTest.cs b/tests/MUnique.OpenMU.Tests/ItemConsumptionTest.cs index 5007842f6..1cdfe6792 100644 --- a/tests/MUnique.OpenMU.Tests/ItemConsumptionTest.cs +++ b/tests/MUnique.OpenMU.Tests/ItemConsumptionTest.cs @@ -251,7 +251,7 @@ public async ValueTask ShieldPotionAsync() } /// - /// Tests if the consume fails because of the player state. + /// Tests if the consumption fails because of the player state. /// [Test] public async ValueTask FailByWrongPlayerStateAsync() @@ -266,12 +266,12 @@ public async ValueTask FailByWrongPlayerStateAsync() } /// - /// Tests if the consume of the item decreases its durability by one. + /// Tests if the consumption of the item decreases its durability by one. /// [Test] public async ValueTask ItemDurabilityDecreaseAsync() { - var consumeHandler = new AlcoholConsumeHandlerPlugIn(); + var consumeHandler = new LargeShieldPotionConsumeHandlerPlugIn(); var player = await this.GetPlayerAsync().ConfigureAwait(false); var item = this.GetItem(); await player.Inventory!.AddItemAsync(ItemSlot, item).ConfigureAwait(false); @@ -283,13 +283,13 @@ public async ValueTask ItemDurabilityDecreaseAsync() } /// - /// Tests if the consume of the item not causes the removal of the item, when the durability reaches 0. + /// Tests if the consumption of the item not causes the removal of the item, when the durability reaches 0. /// The removal is handled in the . /// [Test] public async ValueTask ItemRemovalAsync() { - var consumeHandler = new AlcoholConsumeHandlerPlugIn(); + var consumeHandler = new LargeShieldPotionConsumeHandlerPlugIn(); var player = await this.GetPlayerAsync().ConfigureAwait(false); var item = this.GetItem(); await player.Inventory!.AddItemAsync(ItemSlot, item).ConfigureAwait(false); @@ -300,7 +300,7 @@ public async ValueTask ItemRemovalAsync() } /// - /// Tests if the consume of the alcohol fails when the item has no durability anymore. + /// Tests if the consumption of the alcohol fails when the item has no durability anymore. /// [Test] public async ValueTask DrinkAlcoholFailAsync() @@ -312,11 +312,11 @@ public async ValueTask DrinkAlcoholFailAsync() var success = await consumeHandler.ConsumeItemAsync(player, item, null, FruitUsage.Undefined).ConfigureAwait(false); Assert.That(success, Is.False); - Mock.Get(player.ViewPlugIns.GetPlugIn()).Verify(view => view!.DrinkAlcoholAsync(), Times.Never); + Mock.Get(player.ViewPlugIns.GetPlugIn()).Verify(view => view!.ConsumeSpecialItemAsync(item, 80), Times.Never); } /// - /// Tests if the consume of alcohol works and is forwarded to the player view. + /// Tests if the consumption of alcohol works and is forwarded to the player view. /// [Test] public async ValueTask DrinkAlcoholSuccessAsync() @@ -324,11 +324,30 @@ public async ValueTask DrinkAlcoholSuccessAsync() var consumeHandler = new AlcoholConsumeHandlerPlugIn(); var player = await this.GetPlayerAsync().ConfigureAwait(false); var item = this.GetItem(); + item.Definition!.ConsumeEffect = new Persistence.BasicModel.MagicEffectDefinition() + { + Duration = new Persistence.BasicModel.PowerUpDefinitionValue() + { + ConstantValue = { Value = 80 } + }, + PowerUpDefinitions = + { + new Persistence.BasicModel.PowerUpDefinition() + { + TargetAttribute = Stats.AttackSpeed, + Boost = new Persistence.BasicModel.PowerUpDefinitionValue() + { + ConstantValue = { Value = 20 } + } + } + } + }; + await player.Inventory!.AddItemAsync(ItemSlot, item).ConfigureAwait(false); var success = await consumeHandler.ConsumeItemAsync(player, item, null, FruitUsage.Undefined).ConfigureAwait(false); Assert.That(success, Is.True); - Mock.Get(player.ViewPlugIns.GetPlugIn()).Verify(view => view!.DrinkAlcoholAsync(), Times.Once); + Mock.Get(player.ViewPlugIns.GetPlugIn()).Verify(view => view!.ConsumeSpecialItemAsync(item, 80), Times.Once); } /// From 12539aa7b53d39f2e3d2fdf9d6ebd6d447ec5250 Mon Sep 17 00:00:00 2001 From: sven-n Date: Sat, 19 Oct 2024 16:30:57 +0200 Subject: [PATCH 08/11] Implemented potion of soul and partially bless. --- .../SiegePotionConsumeHandlerPlugIn.cs | 49 +++++++++++++ .../Skills/BlessPotionEffectInitializer.cs | 49 +++++++++++++ .../Skills/SoulPotionEffectInitializer.cs | 70 +++++++++++++++++++ .../VersionSeasonSix/ChaosMixes.cs | 6 +- .../VersionSeasonSix/Items/Potions.cs | 5 +- .../VersionSeasonSix/SkillsInitializer.cs | 2 + 6 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 src/GameLogic/PlayerActions/ItemConsumeActions/SiegePotionConsumeHandlerPlugIn.cs create mode 100644 src/Persistence/Initialization/Skills/BlessPotionEffectInitializer.cs create mode 100644 src/Persistence/Initialization/Skills/SoulPotionEffectInitializer.cs diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/SiegePotionConsumeHandlerPlugIn.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/SiegePotionConsumeHandlerPlugIn.cs new file mode 100644 index 000000000..1200991c7 --- /dev/null +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/SiegePotionConsumeHandlerPlugIn.cs @@ -0,0 +1,49 @@ +// ----------------------------------------------------------------------- +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// +// ----------------------------------------------------------------------- + +namespace MUnique.OpenMU.GameLogic.PlayerActions.ItemConsumeActions; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.GameLogic.PlugIns.ChatCommands; +using MUnique.OpenMU.GameLogic.Views; +using MUnique.OpenMU.PlugIns; + +/// +/// The alcohol consume handler. +/// +[Guid("9D50CE95-5354-43A7-8DD5-9D6953700DFA")] +[PlugIn(nameof(SiegePotionConsumeHandlerPlugIn), "Plugin which handles the siege potion consumption.")] +public class SiegePotionConsumeHandlerPlugIn : ApplyMagicEffectConsumeHandlerPlugIn +{ + /// + public override ItemIdentifier Key => ItemConstants.SiegePotion; + + /// + public override async ValueTask ConsumeItemAsync(Player player, Item item, Item? targetItem, FruitUsage fruitUsage) + { + if (item.Level == 0 + && player.GameContext.Configuration.MagicEffects.FirstOrDefault(e => e.Number == 10) is { } blessEffectDefinition) + { + return await base.ConsumeItemAsyncCore(player, item, targetItem, fruitUsage, blessEffectDefinition).ConfigureAwait(false); + } + + if (item.Level == 1 + && player.GameContext.Configuration.MagicEffects.FirstOrDefault(e => e.Number == 11) is { } effectDefinition) + { + if (await base.ConsumeItemAsyncCore(player, item, targetItem, fruitUsage, effectDefinition).ConfigureAwait(false)) + { + await player.InvokeViewPlugInAsync(p => p.ConsumeSpecialItemAsync(item, (ushort)(effectDefinition.Duration?.ConstantValue.Value ?? 0))).ConfigureAwait(false); + return true; + } + } + else + { + await player.ShowMessageAsync("Effect for item not found.").ConfigureAwait(false); + } + + return false; + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Skills/BlessPotionEffectInitializer.cs b/src/Persistence/Initialization/Skills/BlessPotionEffectInitializer.cs new file mode 100644 index 000000000..7c1a1a648 --- /dev/null +++ b/src/Persistence/Initialization/Skills/BlessPotionEffectInitializer.cs @@ -0,0 +1,49 @@ +// +// 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 which initializes the bless potion effect. +/// +public class BlessPotionEffectInitializer : InitializerBase +{ + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public BlessPotionEffectInitializer(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + public override void Initialize() + { + var magicEffect = this.Context.CreateNew(); + this.GameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (byte)MagicEffectNumber.PotionOfBless; + magicEffect.SubType = 255 - (byte)MagicEffectNumber.PotionOfBless; + magicEffect.Name = "Potion of Bless Effect"; + magicEffect.InformObservers = false; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = true; + magicEffect.Duration = this.Context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 120; + + // TODO: This should only apply to castle gates and statues! + var powerUp = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(powerUp); + powerUp.TargetAttribute = Stats.AttackDamageIncrease.GetPersistent(this.GameConfiguration); + powerUp.Boost = this.Context.CreateNew(); + powerUp.Boost.ConstantValue.Value = 1.2f; + powerUp.Boost.ConstantValue.AggregateType = AggregateType.Multiplicate; + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Skills/SoulPotionEffectInitializer.cs b/src/Persistence/Initialization/Skills/SoulPotionEffectInitializer.cs new file mode 100644 index 000000000..050647f7c --- /dev/null +++ b/src/Persistence/Initialization/Skills/SoulPotionEffectInitializer.cs @@ -0,0 +1,70 @@ +// +// 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.DataModel.Attributes; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.GameLogic.Attributes; + +/// +/// Initializer which initializes the soul potion effect. +/// +public class SoulPotionEffectInitializer : InitializerBase +{ + /// + /// Initializes a new instance of the class. + /// + /// The context. + /// The game configuration. + public SoulPotionEffectInitializer(IContext context, GameConfiguration gameConfiguration) + : base(context, gameConfiguration) + { + } + + /// + public override void Initialize() + { + var magicEffect = this.Context.CreateNew(); + this.GameConfiguration.MagicEffects.Add(magicEffect); + magicEffect.Number = (byte)MagicEffectNumber.PotionOfSoul; + magicEffect.SubType = 255 - (byte)MagicEffectNumber.PotionOfSoul; + magicEffect.Name = "Potion of Soul Effect"; + magicEffect.InformObservers = false; + magicEffect.SendDuration = false; + magicEffect.StopByDeath = true; + magicEffect.Duration = this.Context.CreateNew(); + magicEffect.Duration.ConstantValue.Value = 60; + + var attackSpeedPowerUp = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(attackSpeedPowerUp); + attackSpeedPowerUp.TargetAttribute = Stats.AttackSpeed.GetPersistent(this.GameConfiguration); + attackSpeedPowerUp.Boost = this.Context.CreateNew(); + attackSpeedPowerUp.Boost.ConstantValue.Value = 20f; + + var magicSpeedPowerUp = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(magicSpeedPowerUp); + magicSpeedPowerUp.TargetAttribute = Stats.MagicSpeed.GetPersistent(this.GameConfiguration); + magicSpeedPowerUp.Boost = this.Context.CreateNew(); + magicSpeedPowerUp.Boost.ConstantValue.Value = 20f; + + var abilityRecoveryIncrease = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(abilityRecoveryIncrease); + abilityRecoveryIncrease.TargetAttribute = Stats.AbilityRecoveryAbsolute.GetPersistent(this.GameConfiguration); + abilityRecoveryIncrease.Boost = this.Context.CreateNew(); + abilityRecoveryIncrease.Boost.ConstantValue.Value = 8f; + + var lightningResistance = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(lightningResistance); + lightningResistance.TargetAttribute = Stats.LightningResistance.GetPersistent(this.GameConfiguration); + lightningResistance.Boost = this.Context.CreateNew(); + lightningResistance.Boost.ConstantValue.Value = 0.5f; + + var iceResistance = this.Context.CreateNew(); + magicEffect.PowerUpDefinitions.Add(iceResistance); + iceResistance.TargetAttribute = Stats.IceResistance.GetPersistent(this.GameConfiguration); + iceResistance.Boost = this.Context.CreateNew(); + iceResistance.Boost.ConstantValue.Value = 0.5f; + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/VersionSeasonSix/ChaosMixes.cs b/src/Persistence/Initialization/VersionSeasonSix/ChaosMixes.cs index c489321a8..f3a8a9c36 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/ChaosMixes.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/ChaosMixes.cs @@ -7,6 +7,7 @@ namespace MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix; using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic; using MUnique.OpenMU.GameLogic.PlayerActions.Craftings; /// @@ -682,7 +683,8 @@ private ItemCrafting PotionOfBlessCrafting() // Result: var potion = this.Context.CreateNew(); - potion.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Siege Potion"); + + potion.ItemDefinition = this.GameConfiguration.Items.First(i => i.Number == ItemConstants.SiegePotion.Number && i.Group == ItemConstants.SiegePotion.Group); potion.Durability = 10; craftingSettings.ResultItems.Add(potion); @@ -712,7 +714,7 @@ private ItemCrafting PotionOfSoulCrafting() // Result: var potion = this.Context.CreateNew(); - potion.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Siege Potion"); + potion.ItemDefinition = this.GameConfiguration.Items.First(i => i.Number == ItemConstants.SiegePotion.Number && i.Group == ItemConstants.SiegePotion.Group); potion.Durability = 10; potion.RandomMinimumLevel = 1; potion.RandomMaximumLevel = 1; diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs index cd4e4e689..61c771b42 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs @@ -381,10 +381,11 @@ private ItemDefinition CreateTownPortalScroll() private ItemDefinition CreateSiegePotion() { var definition = this.Context.CreateNew(); - definition.Name = "Siege Potion"; + definition.Name = "Potion of Bless;Potion of Soul"; definition.Number = 7; definition.Group = 14; - definition.Durability = 1; + definition.Durability = 10; + definition.MaximumItemLevel = 1; definition.Value = 30; definition.Width = 1; definition.Height = 1; diff --git a/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs b/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs index 6d60dbe41..8123871d1 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/SkillsInitializer.cs @@ -573,6 +573,8 @@ private void InitializeEffects() new IncreaseBlockEffectInitializer(this.Context, this.GameConfiguration).Initialize(); new WizardryEnhanceEffectInitializer(this.Context, this.GameConfiguration).Initialize(); new AlcoholEffectInitializer(this.Context, this.GameConfiguration).Initialize(); + new SoulPotionEffectInitializer(this.Context, this.GameConfiguration).Initialize(); + new BlessPotionEffectInitializer(this.Context, this.GameConfiguration).Initialize(); } private void MapSkillsToEffects() From 312e6e5404b1b598b806e08c9fd1766300663f7b Mon Sep 17 00:00:00 2001 From: sven-n Date: Sun, 20 Oct 2024 17:48:15 +0200 Subject: [PATCH 09/11] Added magic speed to 'Jack O'Lantern Blessings' --- .../VersionSeasonSix/Items/Potions.cs | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs index 61c771b42..785b46fd7 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Potions.cs @@ -421,7 +421,7 @@ private ItemDefinition CreateJackOLanternBlessings() item.Width = 1; item.Height = 2; item.SetGuid(item.Group, item.Number); - this.CreateConsumeEffect(item, 16, MagicEffectNumber.JackOlanternBlessing, Stats.AttackSpeed, 10, TimeSpan.FromMinutes(32)); + this.CreateConsumeEffect(item, 16, MagicEffectNumber.JackOlanternBlessing, TimeSpan.FromMinutes(32), (Stats.AttackSpeed, 10), (Stats.MagicSpeed, 10)); return item; } @@ -435,7 +435,7 @@ private ItemDefinition CreateJackOLanternWrath() item.Width = 1; item.Height = 2; item.SetGuid(item.Group, item.Number); - this.CreateConsumeEffect(item, 16, MagicEffectNumber.JackOlanternWrath, Stats.BaseDamageBonus, 25, TimeSpan.FromMinutes(30)); + this.CreateConsumeEffect(item, 16, MagicEffectNumber.JackOlanternWrath, TimeSpan.FromMinutes(30), (Stats.BaseDamageBonus, 25)); return item; } @@ -449,7 +449,7 @@ private ItemDefinition CreateJackOLanternCry() item.Width = 1; item.Height = 2; item.SetGuid(item.Group, item.Number); - this.CreateConsumeEffect(item, 16, MagicEffectNumber.JackOlanternCry, Stats.DefenseBase, 100, TimeSpan.FromMinutes(30)); + this.CreateConsumeEffect(item, 16, MagicEffectNumber.JackOlanternCry, TimeSpan.FromMinutes(30), (Stats.DefenseBase, 100)); return item; } @@ -463,7 +463,7 @@ private ItemDefinition CreateJackOLanternFood() item.Width = 1; item.Height = 1; item.SetGuid(item.Group, item.Number); - this.CreateConsumeEffect(item, 16, MagicEffectNumber.JackOlanternFood, Stats.MaximumHealth, 500, TimeSpan.FromMinutes(30)); + this.CreateConsumeEffect(item, 16, MagicEffectNumber.JackOlanternFood, TimeSpan.FromMinutes(30), (Stats.MaximumHealth, 500)); return item; } @@ -477,7 +477,7 @@ private ItemDefinition CreateJackOLanternDrink() item.Width = 1; item.Height = 1; item.SetGuid(item.Group, item.Number); - this.CreateConsumeEffect(item, 16, MagicEffectNumber.JackOlanternDrink, Stats.MaximumMana, 500, TimeSpan.FromMinutes(30)); + this.CreateConsumeEffect(item, 16, MagicEffectNumber.JackOlanternDrink, TimeSpan.FromMinutes(30), (Stats.MaximumMana, 500)); return item; } @@ -491,7 +491,7 @@ private ItemDefinition CreateCherryBlossomWine() item.Width = 1; item.Height = 2; item.SetGuid(item.Group, item.Number); - this.CreateConsumeEffect(item, 16, MagicEffectNumber.CherryBlossomWine, Stats.MaximumMana, 700, TimeSpan.FromMinutes(30)); + this.CreateConsumeEffect(item, 16, MagicEffectNumber.CherryBlossomWine, TimeSpan.FromMinutes(30), (Stats.MaximumMana, 700)); return item; } @@ -505,7 +505,7 @@ private ItemDefinition CreateCherryBlossomRiceCake() item.Width = 1; item.Height = 1; item.SetGuid(item.Group, item.Number); - this.CreateConsumeEffect(item, 16, MagicEffectNumber.CherryBlossomRiceCake, Stats.MaximumHealth, 700, TimeSpan.FromMinutes(30)); + this.CreateConsumeEffect(item, 16, MagicEffectNumber.CherryBlossomRiceCake, TimeSpan.FromMinutes(30), (Stats.MaximumHealth, 700)); return item; } @@ -519,11 +519,11 @@ private ItemDefinition CreateCherryBlossomFlowerPetal() item.Width = 1; item.Height = 1; item.SetGuid(item.Group, item.Number); - this.CreateConsumeEffect(item, 16, MagicEffectNumber.CherryBlossomFlowerPetal, Stats.BaseDamageBonus, 40, TimeSpan.FromMinutes(30)); + this.CreateConsumeEffect(item, 16, MagicEffectNumber.CherryBlossomFlowerPetal, TimeSpan.FromMinutes(30), (Stats.BaseDamageBonus, 40)); return item; } - private MagicEffectDefinition CreateConsumeEffect(ItemDefinition item, byte subType, MagicEffectNumber effectNumber, AttributeDefinition targetAttribute, float boostValue, TimeSpan duration) + private MagicEffectDefinition CreateConsumeEffect(ItemDefinition item, byte subType, MagicEffectNumber effectNumber, TimeSpan duration, params (AttributeDefinition targetAttribute, float boostValue)[] boosts) { var effect = this.Context.CreateNew(); effect.SetGuid(item.Number, (short)effectNumber); @@ -538,11 +538,15 @@ private MagicEffectDefinition CreateConsumeEffect(ItemDefinition item, byte subT effect.Duration = this.Context.CreateNew(); effect.Duration.ConstantValue.Value = (float)duration.TotalSeconds; - var powerUpDefinition = this.Context.CreateNew(); - effect.PowerUpDefinitions.Add(powerUpDefinition); - powerUpDefinition.Boost = this.Context.CreateNew(); - powerUpDefinition.Boost.ConstantValue.Value = boostValue; - powerUpDefinition.TargetAttribute = targetAttribute.GetPersistent(this.GameConfiguration); + foreach (var (targetAttribute, boostValue) in boosts) + { + var powerUpDefinition = this.Context.CreateNew(); + effect.PowerUpDefinitions.Add(powerUpDefinition); + powerUpDefinition.Boost = this.Context.CreateNew(); + powerUpDefinition.Boost.ConstantValue.Value = boostValue; + powerUpDefinition.TargetAttribute = targetAttribute.GetPersistent(this.GameConfiguration); + } + return effect; } } \ No newline at end of file From f5b006a0b1215454e99a4f748672d56b38cbf1ab Mon Sep 17 00:00:00 2001 From: sven-n Date: Thu, 24 Oct 2024 21:58:46 +0200 Subject: [PATCH 10/11] Added config update plugin --- .../CharacterClasses/CharacterClassHelper.cs | 66 +++++ .../CharacterClassInitialization.cs | 16 +- .../FixAttackSpeedCalculationUpdate.cs | 248 ++++++++++++++++++ .../Updates/UpdatePlugInBase.cs | 14 + .../Initialization/Updates/UpdateVersion.cs | 4 + 5 files changed, 336 insertions(+), 12 deletions(-) create mode 100644 src/Persistence/Initialization/Updates/FixAttackSpeedCalculationUpdate.cs diff --git a/src/Persistence/Initialization/CharacterClasses/CharacterClassHelper.cs b/src/Persistence/Initialization/CharacterClasses/CharacterClassHelper.cs index 2d6bf37dd..34b0812e7 100644 --- a/src/Persistence/Initialization/CharacterClasses/CharacterClassHelper.cs +++ b/src/Persistence/Initialization/CharacterClasses/CharacterClassHelper.cs @@ -4,6 +4,7 @@ namespace MUnique.OpenMU.Persistence.Initialization.CharacterClasses; +using MUnique.OpenMU.AttributeSystem; using MUnique.OpenMU.DataModel.Configuration; /// @@ -128,4 +129,69 @@ public static IEnumerable DetermineCharacterClasses(this GameCon yield return characterClasses.First(c => c.Number == (int)CharacterClassNumber.FairyElf); } } + + /// + /// Creates the attribute relationship. + /// + /// The context. + /// The game configuration. + /// The target attribute. + /// The multiplier. + /// The source attribute. + /// The input operator. + /// The attribute relationship + public static AttributeRelationship CreateAttributeRelationship(IContext context, GameConfiguration gameConfiguration, AttributeDefinition targetAttribute, float multiplier, AttributeDefinition sourceAttribute, InputOperator inputOperator = InputOperator.Multiply) + { + return context.CreateNew(targetAttribute.GetPersistent(gameConfiguration) ?? targetAttribute, multiplier, sourceAttribute.GetPersistent(gameConfiguration) ?? sourceAttribute, inputOperator, default(AttributeDefinition?)); + } + + /// + /// Creates the attribute relationship. + /// + /// The context. + /// The game configuration. + /// The target attribute. + /// The multiplier attribute. + /// The source attribute. + /// The input operator. + /// The attribute relationship + public static AttributeRelationship CreateAttributeRelationship(IContext context, GameConfiguration gameConfiguration, AttributeDefinition targetAttribute, AttributeDefinition multiplierAttribute, AttributeDefinition sourceAttribute, InputOperator inputOperator = InputOperator.Multiply) + { + return context.CreateNew( + targetAttribute.GetPersistent(gameConfiguration) ?? targetAttribute, + 0f, + sourceAttribute.GetPersistent(gameConfiguration) ?? sourceAttribute, + inputOperator, + multiplierAttribute.GetPersistent(gameConfiguration) ?? multiplierAttribute); + } + + /// + /// Creates the conditional relationship between attributes. + /// + /// The context. + /// The game configuration. + /// The target attribute. + /// The conditional attribute. + /// The source attribute. + /// The attribute relationship + public static AttributeRelationship CreateConditionalRelationship(IContext context, GameConfiguration gameConfiguration, AttributeDefinition targetAttribute, AttributeDefinition conditionalAttribute, AttributeDefinition sourceAttribute) + { + return context.CreateNew( + targetAttribute.GetPersistent(gameConfiguration) ?? targetAttribute, + conditionalAttribute.GetPersistent(gameConfiguration) ?? conditionalAttribute, + sourceAttribute.GetPersistent(gameConfiguration) ?? sourceAttribute); + } + + /// + /// Creates the constant value attribute. + /// + /// The context. + /// The game configuration. + /// The value. + /// The attribute. + /// The constant value attribute. + public static ConstValueAttribute CreateConstValueAttribute(IContext context, GameConfiguration gameConfiguration, float value, AttributeDefinition attribute) + { + return context.CreateNew(value, attribute.GetPersistent(gameConfiguration)); + } } \ No newline at end of file diff --git a/src/Persistence/Initialization/CharacterClasses/CharacterClassInitialization.cs b/src/Persistence/Initialization/CharacterClasses/CharacterClassInitialization.cs index 1e22b81a6..2e2e92dda 100644 --- a/src/Persistence/Initialization/CharacterClasses/CharacterClassInitialization.cs +++ b/src/Persistence/Initialization/CharacterClasses/CharacterClassInitialization.cs @@ -71,30 +71,22 @@ private StatAttributeDefinition CreateStatAttributeDefinition(AttributeDefinitio private AttributeRelationship CreateAttributeRelationship(AttributeDefinition targetAttribute, float multiplier, AttributeDefinition sourceAttribute, InputOperator inputOperator = InputOperator.Multiply) { - return this.Context.CreateNew(targetAttribute.GetPersistent(this.GameConfiguration) ?? targetAttribute, multiplier, sourceAttribute.GetPersistent(this.GameConfiguration) ?? sourceAttribute, inputOperator, default(AttributeDefinition?)); + return CharacterClassHelper.CreateAttributeRelationship(this.Context, this.GameConfiguration, targetAttribute, multiplier, sourceAttribute, inputOperator); } private AttributeRelationship CreateAttributeRelationship(AttributeDefinition targetAttribute, AttributeDefinition multiplierAttribute, AttributeDefinition sourceAttribute, InputOperator inputOperator = InputOperator.Multiply) { - return this.Context.CreateNew( - targetAttribute.GetPersistent(this.GameConfiguration) ?? targetAttribute, - 0f, - sourceAttribute.GetPersistent(this.GameConfiguration) ?? sourceAttribute, - inputOperator, - multiplierAttribute.GetPersistent(this.GameConfiguration) ?? multiplierAttribute); + return CharacterClassHelper.CreateAttributeRelationship(this.Context, this.GameConfiguration, targetAttribute, multiplierAttribute, sourceAttribute, inputOperator); } private AttributeRelationship CreateConditionalRelationship(AttributeDefinition targetAttribute, AttributeDefinition conditionalAttribute, AttributeDefinition sourceAttribute) { - return this.Context.CreateNew( - targetAttribute.GetPersistent(this.GameConfiguration) ?? targetAttribute, - conditionalAttribute.GetPersistent(this.GameConfiguration) ?? conditionalAttribute, - sourceAttribute.GetPersistent(this.GameConfiguration) ?? sourceAttribute); + return CharacterClassHelper.CreateConditionalRelationship(this.Context, this.GameConfiguration, targetAttribute, conditionalAttribute, sourceAttribute); } private ConstValueAttribute CreateConstValueAttribute(float value, AttributeDefinition attribute) { - return this.Context.CreateNew(value, attribute.GetPersistent(this.GameConfiguration)); + return CharacterClassHelper.CreateConstValueAttribute(this.Context, this.GameConfiguration, value, attribute); } private void AddCommonAttributeRelationships(ICollection attributeRelationships) diff --git a/src/Persistence/Initialization/Updates/FixAttackSpeedCalculationUpdate.cs b/src/Persistence/Initialization/Updates/FixAttackSpeedCalculationUpdate.cs new file mode 100644 index 000000000..99a486c82 --- /dev/null +++ b/src/Persistence/Initialization/Updates/FixAttackSpeedCalculationUpdate.cs @@ -0,0 +1,248 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.Updates; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.AttributeSystem; +using MUnique.OpenMU.DataModel.Attributes; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic; +using MUnique.OpenMU.GameLogic.Attributes; +using MUnique.OpenMU.Network.Packets; +using MUnique.OpenMU.Persistence.Initialization.Items; +using MUnique.OpenMU.Persistence.Initialization.Skills; +using MUnique.OpenMU.PlugIns; +using static CharacterClasses.CharacterClassHelper; + +/// +/// This adds attributes and relations for attack speed. Adds effects for Ale and Potion of Soul +/// +[PlugIn(PlugInName, PlugInDescription)] +[Guid("F9977AA7-F52A-4F42-BD6C-98DE700B5980")] +public class FixAttackSpeedCalculationUpdate : UpdatePlugInBase +{ + /// + /// The plug in name. + /// + internal const string PlugInName = "Fix Attack Speed Calculation"; + + /// + /// The plug in description. + /// + internal const string PlugInDescription = "Adds attributes and relations for attack speed. Adds effects for Ale and Potion of Soul."; + + private static readonly Dictionary AttackSpeedByGloveNumber = new() + { + {0, 4}, // Bronze Gloves + {1, 6}, // Dragon Gloves + {5, 8}, // Leather Gloves + {6, 10}, // Scale Gloves + {8, 8}, // Brass Gloves + {9, 4}, // Plate Gloves + {10, 4}, // Vine Gloves + {11, 8}, // Silk Gloves + {12, 10}, // Wind Gloves + {13, 4}, // Spirit Gloves + {14, 6}, // Guardian Gloves + {15, 6}, // Storm Crow Gloves + {16, 6}, // Black Dragon Gloves + {17, 6}, // Dark Phoenix Gloves + {18, 5}, // Grand Soul Gloves + {19, 6}, // Divine Gloves + {20, 7}, // Thunder Hawk Gloves + {21, 6}, // Great Dragon Gloves + {22, 6}, // Dark Soul Gloves + {23, 7}, // Hurricane Gloves + {24, 6}, // Red Spirit Gloves + {25, 7}, // Light Plate Gloves + {26, 6}, // Adamantine Gloves + {27, 5}, // Dark Steel Gloves + {28, 4}, // Dark Master Gloves + {29, 7}, // Dragon Knight Gloves + {30, 7}, // Venom Mist Gloves + {31, 7}, // Sylphid Ray Gloves + {32, 7}, // Volcano Gloves + {33, 5}, // Sunlight Gloves + {34, 6}, // Ashcrow Gloves + {35, 6}, // Eclipse Gloves + {36, 6}, // Iris Gloves + {37, 7}, // Valiant Gloves + {38, 5}, // Glorious Gloves + {39, 6}, // Violent Wind Gloves + {40, 8}, // Red Wing Gloves + {41, 7}, // Ancient Gloves + {42, 6}, // Demonic Gloves + {43, 6}, // Storm Blitz Gloves + {45, 7}, // Titan Gloves + {46, 7}, // Brave Gloves + {47, 7}, // Phantom Gloves + {48, 7}, // Destroy Gloves + {49, 7}, // Seraphim Gloves + {50, 7}, // Divine Gloves + {51, 7}, // Royal Gloves + {52, 7}, // Hades Gloves + }; + + private static readonly Dictionary WalkSpeedByBootNumber = new() + { + { 0, 10 }, // Bronze Boots + { 1, 2 }, // Dragon Boots + { 2, 10 }, // Pad Boots + { 3, 0 }, // Legendary Boots + { 4, 6 }, // Bone Boots + { 5, 12 }, // Leather Boots + { 6, 8 }, // Scale Boots + { 7, 8 }, // Sphinx Boots + { 8, 6 }, // Brass Boots + { 9, 4 }, // Plate Boots + { 15, 2 }, // Storm Crow Boots + { 16, 2 }, // Black Dragon Boots + { 17, 2 }, // Dark Phoenix Boots + { 20, 2 }, // Thunder Hawk Boots + }; + + /// + public override UpdateVersion Version => UpdateVersion.FixAttackSpeedCalculation; + + /// + public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id; + + /// + public override string Name => PlugInName; + + /// + public override string Description => PlugInDescription; + + /// + public override bool IsMandatory => false; + + /// + public override DateTime CreatedAt => new(2024, 10, 19, 14, 0, 0, DateTimeKind.Utc); + + /// + protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) + { + if (gameConfiguration.Attributes.Contains(Stats.MagicSpeed)) + { + return; + } + + AddStatIfNotExists(context, gameConfiguration, Stats.MagicSpeed); + AddStatIfNotExists(context, gameConfiguration, Stats.AttackSpeedByWeapon); + AddStatIfNotExists(context, gameConfiguration, Stats.AreTwoWeaponsEquipped); + AddStatIfNotExists(context, gameConfiguration, Stats.EquippedWeaponCount); + AddStatIfNotExists(context, gameConfiguration, Stats.WalkSpeed); + + Stats.AttackSpeed.GetPersistent(gameConfiguration).MaximumValue = Stats.AttackSpeed.MaximumValue; + + foreach (var characterClass in gameConfiguration.CharacterClasses) + { + var attributeRelationships = characterClass.AttributeCombinations; + attributeRelationships.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.AttackSpeed, 1, Stats.AttackSpeedByWeapon)); + attributeRelationships.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.MagicSpeed, 1, Stats.AttackSpeedByWeapon)); + + // If two weapons are equipped we subtract the half of the sum of the speeds again from the attack speed + attributeRelationships.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.AreTwoWeaponsEquipped, 1, Stats.EquippedWeaponCount)); + var tempSpeed = context.CreateNew(Guid.NewGuid(), "Temp Half weapon attack speed", string.Empty); + gameConfiguration.Attributes.Add(tempSpeed); + attributeRelationships.Add(CreateAttributeRelationship(context, gameConfiguration, tempSpeed, -0.5f, Stats.AttackSpeedByWeapon)); + attributeRelationships.Add(CreateConditionalRelationship(context, gameConfiguration, Stats.AttackSpeed, Stats.AreTwoWeaponsEquipped, tempSpeed)); + attributeRelationships.Add(CreateConditionalRelationship(context, gameConfiguration, Stats.MagicSpeed, Stats.AreTwoWeaponsEquipped, tempSpeed)); + + characterClass.BaseAttributeValues.Add(CreateConstValueAttribute(context, gameConfiguration, -1, Stats.AreTwoWeaponsEquipped)); + } + + foreach (var darkKnight in gameConfiguration.CharacterClasses.Where(c => ((CharacterClassNumber)c.Number) is CharacterClassNumber.BladeKnight or CharacterClassNumber.BladeMaster or CharacterClassNumber.DarkKnight)) + { + darkKnight.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.MagicSpeed, 1.0f / 20, Stats.TotalAgility)); + } + + foreach (var darkLord in gameConfiguration.CharacterClasses.Where(c => ((CharacterClassNumber)c.Number) is CharacterClassNumber.DarkLord or CharacterClassNumber.LordEmperor)) + { + darkLord.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.AttackSpeed, 1.0f / 10, Stats.TotalAgility)); + darkLord.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.MagicSpeed, 1.0f / 10, Stats.TotalAgility)); + } + + foreach (var darkWizard in gameConfiguration.CharacterClasses.Where(c => ((CharacterClassNumber)c.Number) is CharacterClassNumber.DarkWizard or CharacterClassNumber.SoulMaster or CharacterClassNumber.GrandMaster)) + { + darkWizard.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.AttackSpeed, 1.0f / 20, Stats.TotalAgility)); + darkWizard.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.MagicSpeed, 1.0f / 10, Stats.TotalAgility)); + } + + foreach (var elf in gameConfiguration.CharacterClasses.Where(c => ((CharacterClassNumber)c.Number) is CharacterClassNumber.FairyElf or CharacterClassNumber.MuseElf or CharacterClassNumber.HighElf)) + { + elf.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.AttackSpeed, 1.0f / 50, Stats.TotalAgility)); + elf.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.MagicSpeed, 1.0f / 50, Stats.TotalAgility)); + } + + foreach (var magicGladiator in gameConfiguration.CharacterClasses.Where(c => ((CharacterClassNumber)c.Number) is CharacterClassNumber.MagicGladiator or CharacterClassNumber.DuelMaster)) + { + magicGladiator.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.MagicSpeed, 1.0f / 20, Stats.TotalAgility)); + } + + foreach (var rageFighter in gameConfiguration.CharacterClasses.Where(c => ((CharacterClassNumber)c.Number) is CharacterClassNumber.RageFighter or CharacterClassNumber.FistMaster)) + { + rageFighter.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.AttackSpeed, 1.0f / 9, Stats.TotalAgility)); + rageFighter.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.MagicSpeed, 1.0f / 9, Stats.TotalAgility)); + } + + foreach (var summoner in gameConfiguration.CharacterClasses.Where(c => ((CharacterClassNumber)c.Number) is CharacterClassNumber.Summoner or CharacterClassNumber.BloodySummoner or CharacterClassNumber.DimensionMaster)) + { + summoner.AttributeCombinations.Add(CreateAttributeRelationship(context, gameConfiguration, Stats.MagicSpeed, 1.0f / 20, Stats.TotalAgility)); + } + + // attack speed from gloves: + var glovesWithSpeed = gameConfiguration.Items.Where(item => item.Group == (byte)ItemGroups.Gloves) + .Select(item => (item, AttackSpeedByGloveNumber.GetValueOrDefault(item.Number))) + .Where(pair => pair.Item2 > 0); + foreach (var (gloves, attackSpeed) in glovesWithSpeed) + { + gloves.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(context, gameConfiguration, Stats.AttackSpeed, attackSpeed, AggregateType.AddRaw)); + gloves.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(context, gameConfiguration, Stats.MagicSpeed, attackSpeed, AggregateType.AddRaw)); + } + + // walk speed from boots: + var bootsWithSpeed = gameConfiguration.Items.Where(item => item.Group == (byte)ItemGroups.Boots) + .Select(item => (item, WalkSpeedByBootNumber.GetValueOrDefault(item.Number))) + .Where(pair => pair.Item2 > 0); + foreach (var (boots, walkSpeed) in bootsWithSpeed) + { + boots.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(context, gameConfiguration, Stats.WalkSpeed, walkSpeed, AggregateType.AddRaw)); + } + + new AlcoholEffectInitializer(context, gameConfiguration).Initialize(); + new BlessPotionEffectInitializer(context, gameConfiguration).Initialize(); + new SoulPotionEffectInitializer(context, gameConfiguration).Initialize(); + + SetItemEffect(gameConfiguration, ItemConstants.Alcohol, MagicEffectNumber.Alcohol); + var siegePotion = gameConfiguration.Items.First(item => item.Number == ItemConstants.SiegePotion.Number && item.Group == ItemConstants.SiegePotion.Group); + siegePotion.Name = "Potion of Bless;Potion of Soul"; + siegePotion.Durability = 10; + siegePotion.MaximumItemLevel = 1; + + var jackOlanternBlessingEffect = gameConfiguration.MagicEffects.First(item => item.Number == (int)MagicEffectNumber.JackOlanternBlessing); + var powerUpDefinition = context.CreateNew(); + jackOlanternBlessingEffect.PowerUpDefinitions.Add(powerUpDefinition); + powerUpDefinition.Boost = context.CreateNew(); + powerUpDefinition.Boost.ConstantValue.Value = 10; + powerUpDefinition.TargetAttribute = Stats.MagicSpeed.GetPersistent(gameConfiguration); + } + + private void SetItemEffect(GameConfiguration gameConfiguration, ItemIdentifier itemIdentifier, MagicEffectNumber effectNumber) + { + var item = gameConfiguration.Items.First(i => i.Number == itemIdentifier.Number && i.Group == itemIdentifier.Group); + item.ConsumeEffect = gameConfiguration.MagicEffects.First(effect => effect.Number == (int)effectNumber); + } + + private ItemBasePowerUpDefinition CreateItemBasePowerUpDefinition(IContext context, GameConfiguration gameConfiguration, AttributeDefinition attributeDefinition, float value, AggregateType aggregateType) + { + var powerUpDefinition = context.CreateNew(); + powerUpDefinition.TargetAttribute = attributeDefinition.GetPersistent(gameConfiguration); + powerUpDefinition.BaseValue = value; + powerUpDefinition.AggregateType = aggregateType; + return powerUpDefinition; + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Updates/UpdatePlugInBase.cs b/src/Persistence/Initialization/Updates/UpdatePlugInBase.cs index d4138309e..89c977a45 100644 --- a/src/Persistence/Initialization/Updates/UpdatePlugInBase.cs +++ b/src/Persistence/Initialization/Updates/UpdatePlugInBase.cs @@ -4,6 +4,7 @@ namespace MUnique.OpenMU.Persistence.Initialization.Updates; +using MUnique.OpenMU.AttributeSystem; using MUnique.OpenMU.DataModel.Configuration; /// @@ -50,6 +51,19 @@ public async ValueTask ApplyUpdateAsync(IContext context, GameConfiguration game /// protected abstract ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration); + protected bool AddStatIfNotExists(IContext context, GameConfiguration gameConfiguration, AttributeDefinition attribute) + { + if (gameConfiguration.Attributes.Contains(attribute)) + { + return false; + } + + var persistent = context.CreateNew(attribute.Id, attribute.Designation, attribute.Description); + persistent.MaximumValue = attribute.MaximumValue; + gameConfiguration.Attributes.Add(persistent); + return true; + } + private void AddUpdateEntry(IContext context) { var entry = context.CreateNew(); diff --git a/src/Persistence/Initialization/Updates/UpdateVersion.cs b/src/Persistence/Initialization/Updates/UpdateVersion.cs index 923421ea1..6fc26b99c 100644 --- a/src/Persistence/Initialization/Updates/UpdateVersion.cs +++ b/src/Persistence/Initialization/Updates/UpdateVersion.cs @@ -179,4 +179,8 @@ public enum UpdateVersion /// The version of the . /// FixWingsDmgRatesPlugInSeason6 = 34, + + /// The version of the . + /// + FixAttackSpeedCalculation = 35, } \ No newline at end of file From 64e0fe3726e8ff9686356451995101e529216478 Mon Sep 17 00:00:00 2001 From: sven-n Date: Tue, 29 Oct 2024 07:45:18 +0100 Subject: [PATCH 11/11] Fix code style --- .../RemoteView/ConsumeSpecialItemPlugIn.cs | 4 ++ .../Items/ArmorInitializerBase.cs | 46 +++++++++---------- .../ItemConsumptionTest.cs | 8 ++-- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/GameServer/RemoteView/ConsumeSpecialItemPlugIn.cs b/src/GameServer/RemoteView/ConsumeSpecialItemPlugIn.cs index 2767d4b63..2cacedbc7 100644 --- a/src/GameServer/RemoteView/ConsumeSpecialItemPlugIn.cs +++ b/src/GameServer/RemoteView/ConsumeSpecialItemPlugIn.cs @@ -43,5 +43,9 @@ public async ValueTask ConsumeSpecialItemAsync(Item item, ushort effectTimeInSec { await this._player.Connection.SendConsumeItemWithEffectAsync(ConsumeItemWithEffect.ConsumedItemType.PotionOfSoul, effectTimeInSeconds).ConfigureAwait(false); } + else + { + // do nothing + } } } \ No newline at end of file diff --git a/src/Persistence/Initialization/Items/ArmorInitializerBase.cs b/src/Persistence/Initialization/Items/ArmorInitializerBase.cs index dddd63281..faafd0e22 100644 --- a/src/Persistence/Initialization/Items/ArmorInitializerBase.cs +++ b/src/Persistence/Initialization/Items/ArmorInitializerBase.cs @@ -149,51 +149,51 @@ protected ItemDefinition CreateGloves(byte number, string name, byte dropLevel, return gloves; } - protected ItemDefinition CreateBoots(byte number, byte slot, byte width, byte height, string name, byte dropLevel, int defense, int walkSpeed, byte durability, int strengthRequirement, int agilityRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel) + protected ItemDefinition CreateGloves(byte number, string name, byte dropLevel, int defense, int attackSpeed, byte durability, int levelRequirement, int strengthRequirement, int agilityRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel, int magicGladiatorClassLevel, int darkLordClassLevel, int summonerClassLevel) { - var boots = this.CreateArmor(number, 6, 2, 2, name, dropLevel, defense, durability, strengthRequirement, agilityRequirement, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel); - if (walkSpeed > 0) + var gloves = this.CreateArmor(number, 5, 2, 2, name, dropLevel, defense, durability, levelRequirement, strengthRequirement, agilityRequirement, 0, 0, 0, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel, magicGladiatorClassLevel, darkLordClassLevel, summonerClassLevel, 0); + if (attackSpeed > 0) { - boots.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.WalkSpeed, walkSpeed, AggregateType.AddRaw)); + gloves.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.AttackSpeed, attackSpeed, AggregateType.AddRaw)); + gloves.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.MagicSpeed, attackSpeed, AggregateType.AddRaw)); } - return boots; + return gloves; } - protected ItemDefinition CreateArmor(byte number, byte slot, byte width, byte height, string name, byte dropLevel, int defense, byte durability, int strengthRequirement, int agilityRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel) + protected ItemDefinition CreateBoots(byte number, byte slot, byte width, byte height, string name, byte dropLevel, int defense, int walkSpeed, byte durability, int strengthRequirement, int agilityRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel) { - var magicGladiatorClassLevel = 0; - if ((slot + 5) != (int)ItemGroups.Helm - && (darkKnightClassLevel == 1 || darkWizardClassLevel == 1) - && this.GameConfiguration.CharacterClasses.Any(c => c.Number == (byte)CharacterClassNumber.MagicGladiator)) + var boots = this.CreateArmor(number, 6, 2, 2, name, dropLevel, defense, durability, strengthRequirement, agilityRequirement, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel); + if (walkSpeed > 0) { - magicGladiatorClassLevel = 1; + boots.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.WalkSpeed, walkSpeed, AggregateType.AddRaw)); } - return this.CreateArmor(number, slot, width, height, name, dropLevel, defense, durability, 0, strengthRequirement, agilityRequirement, 0, 0, 0, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel, magicGladiatorClassLevel, 0, 0, 0); + return boots; } - protected ItemDefinition CreateGloves(byte number, string name, byte dropLevel, int defense, int attackSpeed, byte durability, int levelRequirement, int strengthRequirement, int agilityRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel, int magicGladiatorClassLevel, int darkLordClassLevel, int summonerClassLevel) + protected ItemDefinition CreateBoots(byte number, string name, byte dropLevel, int defense, int walkSpeed, byte durability, int levelRequirement, int strengthRequirement, int agilityRequirement, int energyRequirement, int vitalityRequirement, int leadershipRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel, int magicGladiatorClassLevel, int darkLordClassLevel, int summonerClassLevel, int ragefighterClassLevel) { - var gloves = this.CreateArmor(number, 5, 2, 2, name, dropLevel, defense, durability, levelRequirement, strengthRequirement, agilityRequirement, 0, 0, 0, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel, magicGladiatorClassLevel, darkLordClassLevel, summonerClassLevel, 0); - if (attackSpeed > 0) + var boots = this.CreateArmor(number, 6, 2, 2, name, dropLevel, defense, durability, levelRequirement, strengthRequirement, agilityRequirement, energyRequirement, vitalityRequirement, leadershipRequirement, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel, magicGladiatorClassLevel, darkLordClassLevel, summonerClassLevel, ragefighterClassLevel); + if (walkSpeed > 0) { - gloves.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.AttackSpeed, attackSpeed, AggregateType.AddRaw)); - gloves.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.MagicSpeed, attackSpeed, AggregateType.AddRaw)); + boots.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.WalkSpeed, walkSpeed, AggregateType.AddRaw)); } - return gloves; + return boots; } - protected ItemDefinition CreateBoots(byte number, string name, byte dropLevel, int defense, int walkSpeed, byte durability, int levelRequirement, int strengthRequirement, int agilityRequirement, int energyRequirement, int vitalityRequirement, int leadershipRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel, int magicGladiatorClassLevel, int darkLordClassLevel, int summonerClassLevel, int ragefighterClassLevel) + protected ItemDefinition CreateArmor(byte number, byte slot, byte width, byte height, string name, byte dropLevel, int defense, byte durability, int strengthRequirement, int agilityRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel) { - var boots = this.CreateArmor(number, 6, 2, 2, name, dropLevel, defense, durability, levelRequirement, strengthRequirement, agilityRequirement, energyRequirement, vitalityRequirement, leadershipRequirement, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel, magicGladiatorClassLevel, darkLordClassLevel, summonerClassLevel, ragefighterClassLevel); - if (walkSpeed > 0) + var magicGladiatorClassLevel = 0; + if ((slot + 5) != (int)ItemGroups.Helm + && (darkKnightClassLevel == 1 || darkWizardClassLevel == 1) + && this.GameConfiguration.CharacterClasses.Any(c => c.Number == (byte)CharacterClassNumber.MagicGladiator)) { - boots.BasePowerUpAttributes.Add(this.CreateItemBasePowerUpDefinition(Stats.WalkSpeed, walkSpeed, AggregateType.AddRaw)); + magicGladiatorClassLevel = 1; } - return boots; + return this.CreateArmor(number, slot, width, height, name, dropLevel, defense, durability, 0, strengthRequirement, agilityRequirement, 0, 0, 0, darkWizardClassLevel, darkKnightClassLevel, elfClassLevel, magicGladiatorClassLevel, 0, 0, 0); } protected ItemDefinition CreateArmor(byte number, byte slot, byte width, byte height, string name, byte dropLevel, int defense, byte durability, int levelRequirement, int strengthRequirement, int agilityRequirement, int energyRequirement, int vitalityRequirement, int leadershipRequirement, int darkWizardClassLevel, int darkKnightClassLevel, int elfClassLevel, int magicGladiatorClassLevel, int darkLordClassLevel, int summonerClassLevel, int ragefighterClassLevel) diff --git a/tests/MUnique.OpenMU.Tests/ItemConsumptionTest.cs b/tests/MUnique.OpenMU.Tests/ItemConsumptionTest.cs index 1cdfe6792..a498a333d 100644 --- a/tests/MUnique.OpenMU.Tests/ItemConsumptionTest.cs +++ b/tests/MUnique.OpenMU.Tests/ItemConsumptionTest.cs @@ -324,18 +324,18 @@ public async ValueTask DrinkAlcoholSuccessAsync() var consumeHandler = new AlcoholConsumeHandlerPlugIn(); var player = await this.GetPlayerAsync().ConfigureAwait(false); var item = this.GetItem(); - item.Definition!.ConsumeEffect = new Persistence.BasicModel.MagicEffectDefinition() + item.Definition!.ConsumeEffect = new Persistence.BasicModel.MagicEffectDefinition { - Duration = new Persistence.BasicModel.PowerUpDefinitionValue() + Duration = new Persistence.BasicModel.PowerUpDefinitionValue { ConstantValue = { Value = 80 } }, PowerUpDefinitions = { - new Persistence.BasicModel.PowerUpDefinition() + new Persistence.BasicModel.PowerUpDefinition { TargetAttribute = Stats.AttackSpeed, - Boost = new Persistence.BasicModel.PowerUpDefinitionValue() + Boost = new Persistence.BasicModel.PowerUpDefinitionValue { ConstantValue = { Value = 20 } }