diff --git a/src/DataModel/Configuration/ItemCrafting/MixResult.cs b/src/DataModel/Configuration/ItemCrafting/MixResult.cs index 3cba8d892..8d61672b2 100644 --- a/src/DataModel/Configuration/ItemCrafting/MixResult.cs +++ b/src/DataModel/Configuration/ItemCrafting/MixResult.cs @@ -20,12 +20,12 @@ public enum MixResult StaysAsIs = 1, /// - /// The item will be downgraded to level 0. + /// The item will be downgraded to a random level, may lose its skill, and its item option may be reduced by 1 level. /// - DowngradedTo0 = 3, + ChaosWeaponAndFirstWingsDowngradedRandom = 2, /// - /// The item will be downgraded to a random level. + /// The item will be downgraded 2 or 3 levels and its item option will be removed. /// - DowngradedRandom = 4, + ThirdWingsDowngradedRandom = 3, } \ No newline at end of file diff --git a/src/DataModel/Configuration/ItemCrafting/SimpleCraftingSettings.cs b/src/DataModel/Configuration/ItemCrafting/SimpleCraftingSettings.cs index cf05037eb..b1c9ae921 100644 --- a/src/DataModel/Configuration/ItemCrafting/SimpleCraftingSettings.cs +++ b/src/DataModel/Configuration/ItemCrafting/SimpleCraftingSettings.cs @@ -22,6 +22,12 @@ public partial class SimpleCraftingSettings /// public int MoneyPerFinalSuccessPercentage { get; set; } + /// + /// Gets or sets the NPC price divisor for the sum of crafting items' prices. For each full division, the percentage gets increased by 1 percent, and the mix price rises. + /// + /// Used for Chaos Weapon and 1st Level Wing craftings. + public int NpcPriceDivisor { get; set; } + /// /// Gets or sets the success percent. /// @@ -69,6 +75,11 @@ public partial class SimpleCraftingSettings /// public int SuccessPercentageAdditionForAncientItem { get; set; } + /// + /// Gets or sets the success percentage addition for a "380 item" which gets modified. + /// + public int SuccessPercentageAdditionForGuardianItem { get; set; } + /// /// Gets or sets the success percentage addition for a socket item which gets modified. /// diff --git a/src/DataModel/Configuration/Items/IncreasableItemOption.cs b/src/DataModel/Configuration/Items/IncreasableItemOption.cs index 95f222570..9d846d6ed 100644 --- a/src/DataModel/Configuration/Items/IncreasableItemOption.cs +++ b/src/DataModel/Configuration/Items/IncreasableItemOption.cs @@ -23,7 +23,7 @@ public enum LevelType /// It's increased by the level of the item which has the option. /// /// - /// As far as I know, this is only required for wing options, e.g. 'Increase max HP +50~115'. That's why is the default, too. + /// As far as I know, this is only required for wing options, e.g. 'Increase max HP +50~125'. That's why is the default, too. /// ItemLevel, } diff --git a/src/GameLogic/ItemExtensions.cs b/src/GameLogic/ItemExtensions.cs index 34849077e..858acd630 100644 --- a/src/GameLogic/ItemExtensions.cs +++ b/src/GameLogic/ItemExtensions.cs @@ -102,6 +102,19 @@ public static bool IsExcellent(this Item item) return item.ItemOptions.Any(link => link.ItemOption?.OptionType == ItemOptionTypes.Excellent); } + /// + /// Determines whether this instance is a "380 item", that is, if it can be upgraded with Jewel of Guardian. + /// + /// The item. + /// + /// true if the specified item is a "380 item"; otherwise, false. + /// + public static bool IsGuardian(this Item item) + { + return item.Definition!.PossibleItemOptions.Any(pio => pio.PossibleOptions + .Any(po => po.OptionType == ItemOptionTypes.GuardianOption)); + } + /// /// Determines whether this item is a defensive item. /// diff --git a/src/GameLogic/ItemPowerUpFactory.cs b/src/GameLogic/ItemPowerUpFactory.cs index 227328b09..6f7c0664c 100644 --- a/src/GameLogic/ItemPowerUpFactory.cs +++ b/src/GameLogic/ItemPowerUpFactory.cs @@ -221,7 +221,7 @@ private IEnumerable GetPowerUpsOfItemOptions(Item item, Attribut var level = option.LevelType == LevelType.ItemLevel ? item.Level : optionLink.Level; var optionOfLevel = option.LevelDependentOptions?.FirstOrDefault(l => l.Level == level); - if (optionOfLevel is null && level > 1) + if (optionOfLevel is null && level > 1 && item.Definition!.Skill?.Number != 49) // Dinorant options are an exception { this._logger.LogWarning("Item {item} (id {itemId}) has IncreasableItemOption ({option}, id {optionId}) with level {level}, but no definition in LevelDependentOptions.", item, item.GetId(), option, option.GetId(), level); continue; diff --git a/src/GameLogic/ItemPriceCalculator.cs b/src/GameLogic/ItemPriceCalculator.cs index aca1a089b..5b9b58928 100644 --- a/src/GameLogic/ItemPriceCalculator.cs +++ b/src/GameLogic/ItemPriceCalculator.cs @@ -18,10 +18,15 @@ namespace MUnique.OpenMU.GameLogic; public class ItemPriceCalculator { private const short ForceWaveSkillId = 66; - private const long MaximumPrice = 3000000000; + private const short ExplosionSkillId = 223; + private const short RequiemSkillId = 224; + private const short PollutionSkillId = 225; + private const long MaximumPrice = 3_000_000_000; private const float DestroyedPetPenalty = 2.0f; private const float DestroyedItemPenalty = 1.4f; + private static readonly List WorthlessSkills = [ForceWaveSkillId, ExplosionSkillId, RequiemSkillId, PollutionSkillId]; + private static readonly Dictionary DropLevelIncreaseByLevel = new() { { 5, 4 }, @@ -37,21 +42,28 @@ public class ItemPriceCalculator { 15, 365 }, }; + private static readonly IDictionary SpecialItemOldValueDictionary = new Dictionary + { + { (int)SpecialItems.Bless, 100_000 }, + { (int)SpecialItems.Soul, 70_000 }, + { (int)SpecialItems.Chaos, 40_000 }, + { (int)SpecialItems.Life, 450_000 }, + { (int)SpecialItems.Creation, 450_000 }, + }; + private static readonly IDictionary> SpecialItemDictionary = new Dictionary> { { (int)SpecialItems.Arrow, item => { int gold = 0; - int baseprice = 70; - if (item.Level == 1) + int baseprice = item.Level switch { - baseprice = 1200; - } - else if (item.Level == 2) - { - baseprice = 2000; - } + 1 => 1200, + 2 => 2000, + 3 => 2800, + _ => 70, + }; if (item.Durability > 0) { @@ -65,15 +77,13 @@ public class ItemPriceCalculator (int)SpecialItems.Bolt, item => { int gold = 0; - int baseprice = 100; - if (item.Level == 1) + int baseprice = item.Level switch { - baseprice = 1400; - } - else if (item.Level == 2) - { - baseprice = 2200; - } + 1 => 1400, + 2 => 2200, + 3 => 3000, + _ => 100, + }; if (item.Durability > 0) { @@ -88,21 +98,25 @@ public class ItemPriceCalculator { (int)SpecialItems.Chaos, _ => 810000 }, { (int)SpecialItems.Life, _ => 45000000 }, { (int)SpecialItems.Creation, _ => 36000000 }, + { (int)SpecialItems.Guardian, _ => 60000000 }, + { (int)SpecialItems.Gemstone, _ => 18600 }, + { (int)SpecialItems.Harmony, _ => 18600 }, + { (int)SpecialItems.LowerRefineStone, _ => 18600 }, + { (int)SpecialItems.HigherRefineStone, _ => 18600 }, { (int)SpecialItems.PackedBless, item => (item.Level + 1) * 9000000 * 10 }, { (int)SpecialItems.PackedSoul, item => (item.Level + 1) * 6000000 * 10 }, + { (int)SpecialItems.PackedChaos, item => (item.Level + 1) * 810000 * 10 }, { (int)SpecialItems.PackedLife, item => (item.Level + 1) * 45000000 * 10 }, { (int)SpecialItems.PackedCreation, item => (item.Level + 1) * 36000000 * 10 }, { (int)SpecialItems.PackedGuardian, item => (item.Level + 1) * 60000000 * 10 }, - { (int)SpecialItems.PackedGemstone, item => (item.Level + 1) * 186000 * 10 }, - { (int)SpecialItems.PackedHarmony, item => (item.Level + 1) * 186000 * 10 }, - { (int)SpecialItems.PackedChaos, item => (item.Level + 1) * 810000 * 10 }, - { (int)SpecialItems.PackedLowerRefineStone, item => (item.Level + 1) * 186000 * 10 }, - { (int)SpecialItems.PackedHigherRefineStone, item => (item.Level + 1) * 186000 * 10 }, + { (int)SpecialItems.PackedGemstone, item => (item.Level + 1) * 18600 * 10 }, + { (int)SpecialItems.PackedHarmony, item => (item.Level + 1) * 18600 * 10 }, + { (int)SpecialItems.PackedLowerRefineStone, item => (item.Level + 1) * 18600 * 10 }, + { (int)SpecialItems.PackedHigherRefineStone, item => (item.Level + 1) * 18600 * 10 }, { (int)SpecialItems.Fruits, _ => 33000000 }, { (int)SpecialItems.LochFeather, item => item.Level == 1 ? 7500000 : 180000 }, - { (int)SpecialItems.JewelGuardian, _ => 60000000 }, { (int)SpecialItems.SiegePotion, item => item.Durability() * (item.Level == 0 ? 900000 : 450000) }, - { (int)SpecialItems.OrderGuardianLifeStone, item => item.Level == 1 ? 2400000 : 0 }, + { (int)SpecialItems.OrderGuardianLifeStone, item => item.Level == 1 ? 2400000 : 1000000 }, { (int)SpecialItems.ContractSummon, item => item.Level == 0 ? 1500000 : item.Level == 1 ? 1200000 : 0 }, { (int)SpecialItems.SplinterOfArmor, item => item.Durability() * 150 }, { (int)SpecialItems.BlessOfGuardian, item => item.Durability() * 300 }, @@ -121,55 +135,58 @@ public class ItemPriceCalculator { (int)SpecialItems.Dinorant, item => { - var gold = 960000; - var opt = item.ItemOptions.FirstOrDefault(o => o.ItemOption?.OptionType == ItemOptionTypes.Option); - var optionLevel = opt?.Level ?? 0; - gold += 300000 * optionLevel; - return gold; + var opts = item.ItemOptions.Where(o => o.ItemOption?.OptionType == ItemOptionTypes.Option).Count(); + return 960000 + (300000 * opts); } }, - { (int)SpecialItems.DevilEye, item => item.Level == 1 ? 15000 : item.Level == 2 ? 21000 : (item.Level - 1) * 15000 }, - { (int)SpecialItems.DevilKey, item => item.Level == 1 ? 15000 : item.Level == 2 ? 21000 : (item.Level - 1) * 15000 }, - { (int)SpecialItems.DevilInvitation, item => item.Level == 1 ? 60000 : item.Level == 2 ? 84000 : (item.Level - 1) * 60000 }, - { (int)SpecialItems.RedemyOfLove, _ => 900 }, - { (int)SpecialItems.Rena, item => item.Level == 3 ? item.Durability() * 3900 : 9000 }, - { (int)SpecialItems.Ale, _ => 1000 }, - { - (int)SpecialItems.InvisibleCloak, item => item.Level == 1 ? 150000 : - item.Level == 2 ? 660000 : - item.Level == 3 ? 720000 : - item.Level == 4 ? 780000 : - item.Level == 5 ? 840000 : - item.Level == 6 ? 900000 : - item.Level == 7 ? 960000 : - item.Level == 8 ? 1200000 : 60000 - }, { - (int)SpecialItems.BloodBone, item => item.Level == 1 ? 15000 : - item.Level == 2 ? 21000 : - item.Level == 3 ? 30000 : - item.Level == 4 ? 39000 : - item.Level == 5 ? 48000 : - item.Level == 6 ? 60000 : - item.Level == 7 ? 75000 : - item.Level == 8 ? 90000 : 15000 + (int)SpecialItems.DevilEye, item => item.Level == 1 ? 10000 : + item.Level == 2 ? 50000 : + item.Level == 3 ? 100000 : + item.Level == 4 ? 300000 : + item.Level == 5 ? 500000 : + item.Level == 6 ? 800000 : + item.Level == 7 ? 1000000 : 10000 }, { - (int)SpecialItems.ScrollOfArchangel, item => item.Level == 1 ? 15000 : - item.Level == 2 ? 21000 : - item.Level == 3 ? 30000 : - item.Level == 4 ? 39000 : - item.Level == 5 ? 48000 : - item.Level == 6 ? 60000 : - item.Level == 7 ? 75000 : - item.Level == 8 ? 90000 : 15000 + (int)SpecialItems.DevilKey, item => item.Level == 1 ? 15000 : + item.Level == 2 ? 75000 : + item.Level == 3 ? 150000 : + item.Level == 4 ? 450000 : + item.Level == 5 ? 750000 : + item.Level == 6 ? 1200000 : + item.Level == 7 ? 1500000 : 15000 }, + { (int)SpecialItems.DevilInvitation, item => item.Level is 1 ? 60000 : item.Level == 2 ? 84000 : (item.Level - 1) * 60000 }, // +7 sell price on S6E3 client is 60k (same as +4). Bug? + { (int)SpecialItems.RemedyOfLove, _ => 900 }, + { (int)SpecialItems.Rena, item => item.Level == 3 ? item.Durability() * 3900 : 9000 }, + { (int)SpecialItems.Ale, _ => 750 }, + { (int)SpecialItems.InvisibleCloak, item => item.Level == 1 ? 150000 : 600000 + ((item.Level - 1) * 60000) }, { - (int)SpecialItems.OldScroll, item => item.Level == 1 ? 500000 : (item.Level + 1) * 200000 + (int)SpecialItems.ScrollOfArchangel, item => item.Level == 1 ? 10000 : + item.Level == 2 ? 50000 : + item.Level == 3 ? 100000 : + item.Level == 4 ? 300000 : + item.Level == 5 ? 500000 : + item.Level == 6 ? 800000 : + item.Level == 7 ? 1000000 : + item.Level == 8 ? 1200000 : 10000 }, { - (int)SpecialItems.IllusionSorcererCovenant, item => item.Level == 1 ? 500000 : (item.Level + 1) * 200000 + (int)SpecialItems.BloodBone, item => item.Level == 1 ? 10000 : + item.Level == 2 ? 50000 : + item.Level == 3 ? 100000 : + item.Level == 4 ? 300000 : + item.Level == 5 ? 500000 : + item.Level == 6 ? 800000 : + item.Level == 7 ? 1000000 : + item.Level == 8 ? 1200000 : 10000 }, + { (int)SpecialItems.OldScroll, item => item.Level == 1 ? 500000 : (item.Level + 1) * 200000 }, + { (int)SpecialItems.IllusionSorcererCovenant, item => item.Level == 1 ? 500000 : (item.Level + 1) * 200000 }, + { (int)SpecialItems.ScrollOfBlood, item => item.Level == 1 ? 500000 : (item.Level + 1) * 200000 }, + { (int)SpecialItems.FlameOfCondor, _ => 3000000 }, + { (int)SpecialItems.FeatherOfCondor, _ => 3000000 }, { (int)SpecialItems.ArmorGuardman, _ => 5000 }, { (int)SpecialItems.WizardsRing, item => item.Level == 0 ? 30000 : 0 }, { (int)SpecialItems.SpiritPet, item => item.Level == 0 ? 30000000 : item.Level == 1 ? 15000000 : 0 }, @@ -182,6 +199,21 @@ public class ItemPriceCalculator { (int)SpecialItems.Halloween5, item => 150 * item.Durability() }, { (int)SpecialItems.Halloween6, item => 150 * item.Durability() }, { (int)SpecialItems.GemOfSecret, item => item.Level == 0 ? 60000 : 0 }, + { (int)SpecialItems.SuspiciousScrapOfPaper, item => 30000 * item.Durability() }, + { (int)SpecialItems.GaionsOrder, item => 30000 * item.Durability() }, + { (int)SpecialItems.FirstSecromiconFragment, item => 30000 * item.Durability() }, + { (int)SpecialItems.SecondSecromiconFragment, item => 30000 * item.Durability() }, + { (int)SpecialItems.ThirdSecromiconFragment, item => 30000 * item.Durability() }, + { (int)SpecialItems.FourthSecromiconFragment, item => 30000 * item.Durability() }, + { (int)SpecialItems.FifthSecromiconFragment, item => 30000 * item.Durability() }, + { (int)SpecialItems.SixthSecromiconFragment, item => 30000 * item.Durability() }, + { (int)SpecialItems.CompleteSecromicon, item => 30000 * item.Durability() }, + { (int)SpecialItems.ChristmasStar, _ => 200000 }, + { (int)SpecialItems.Firecracker, _ => 200000 }, + { (int)SpecialItems.CherryBlossomWine, item => 300 * item.Durability() }, + { (int)SpecialItems.CherryBlossomRiceCake, item => 300 * item.Durability() }, + { (int)SpecialItems.CherryBlossomFlowerPetal, item => 300 * item.Durability() }, + { (int)SpecialItems.GoldenCherryBlossomBranch, item => 300 * item.Durability() }, }; private enum SpecialItems @@ -193,19 +225,23 @@ private enum SpecialItems Chaos = 0xF0C, // getId(12,15), Life = 0x100E, // getId(14,16), Creation = 0x160E, // getId(14,22), + Guardian = 0x1F0E, // getId(14,31), + Gemstone = 0x290E, + Harmony = 0x2A0E, + LowerRefineStone = 0x2B0E, + HigherRefineStone = 0x2C0E, PackedBless = 0x1E0C, // getId(12,30), PackedSoul = 0x1F0C, // getId(12,31), + PackedChaos = 0x8D0C, PackedLife = 0x880C, PackedCreation = 0x890C, PackedGuardian = 0x8A0C, PackedGemstone = 0x8B0C, PackedHarmony = 0x8C0C, - PackedChaos = 0x8D0C, PackedLowerRefineStone = 0x8E0C, PackedHigherRefineStone = 0x8F0C, Fruits = 0xF0D, // getId(13,15), LochFeather = 0xE0D, // getId(13,14), - JewelGuardian = 0x1F0E, // getId(14,31), LargeHealPotion = 0x030E, LargeManaPotion = 0x060E, SiegePotion = 0x70E, // getId(14,7), @@ -220,14 +256,14 @@ private enum SpecialItems SmallSdPotion = 0x230E, // getId(14,35), SdPotion = 0x240E, // getId(14, 36), LargeSdPotion = 0x250E, // getId(14,37), - SmallComplexPotion = 0x280E, // getId(14,38), - ComplexPotion = 0x290E, // getId(14,39), - LargeComplexPotion = 0x2A0E, // getId(14,40), + SmallComplexPotion = 0x260E, // getId(14,38), + ComplexPotion = 0x270E, // getId(14,39), + LargeComplexPotion = 0x280E, // getId(14,40), Dinorant = 0x30D, // getId(13,3), DevilEye = 0x110E, // getId(14,17), DevilKey = 0x120E, // getId(14,18), DevilInvitation = 0x130E, // getId(14,19), - RedemyOfLove = 0x140E, // getId(14,20), + RemedyOfLove = 0x140E, // getId(14,20), Rena = 0x150E, // getId(14,21), Ale = 0x90E, // getId(14,9), InvisibleCloak = 0x120D, // getId(13,18), @@ -247,25 +283,62 @@ private enum SpecialItems GemOfSecret = 0x1A0C, // getId(12,26), OldScroll = 0x310D, IllusionSorcererCovenant = 0x320D, + ScrollOfBlood = 0x330D, + FlameOfCondor = 0x340D, + FeatherOfCondor = 0x350D, + SuspiciousScrapOfPaper = 0x650E, + GaionsOrder = 0x660E, + FirstSecromiconFragment = 0x670E, + SecondSecromiconFragment = 0x680E, + ThirdSecromiconFragment = 0x690E, + FourthSecromiconFragment = 0x6A0E, + FifthSecromiconFragment = 0x6B0E, + SixthSecromiconFragment = 0x6C0E, + CompleteSecromicon = 0x6D0E, + ChristmasStar = 0x330E, + Firecracker = 0x3F0E, + CherryBlossomWine = 0x550E, + CherryBlossomRiceCake = 0x560E, + CherryBlossomFlowerPetal = 0x570E, + GoldenCherryBlossomBranch = 0x5A0E, } + /// + /// Calculates the selling price of the item for its maximum durability. + /// + /// The item. + /// The selling price. + public long CalculateSellingPrice(Item item) => this.CalculateSellingPrice(item, item.GetMaximumDurabilityOfOnePiece()); + /// /// Calculates the selling price of the item, which the player gets if he is selling an item to a merchant. - /// It's usually a third of the buying price. + /// It's usually a third of the buying price, minus a durability factor. /// /// The item. + /// The current durability of the . /// The selling price. - public long CalculateSellingPrice(Item item) + public long CalculateSellingPrice(Item item, byte durability) { item.ThrowNotInitializedProperty(item.Definition is null, nameof(item.Definition)); - var sellingPrice = this.CalculateBuyingPrice(item) / 3; - if (item.Definition.Group == 14 && (item.Definition.Number <= 8)) + var sellingPrice = CalculateBuyingPrice(item) / 3; + if (item.Definition.Group == 14 && item.Definition.Number <= 8) { // Potions + Antidote return sellingPrice / 10 * 10; } + if (!item.IsTrainablePet()) + { + var maxDurability = item.GetMaximumDurabilityOfOnePiece(); + if (maxDurability > 1 && maxDurability > durability) + { + float multiplier = 1.0f - ((float)durability / maxDurability); + long loss = (long)(sellingPrice * 0.6 * multiplier); + sellingPrice -= loss; + } + } + return RoundPrice(sellingPrice); } @@ -282,10 +355,9 @@ public long CalculateRepairPrice(Item item, bool npcDiscount) return 0; } - const long maximumBasePrice = 400000000; + const long maximumBasePrice = 400_000_000; var isPet = item.IsTrainablePet(); - var maximumDurability = item.GetMaximumDurabilityOfOnePiece(); - var basePrice = Math.Min(isPet ? CalculateBuyingPrice(item, maximumDurability) : CalculateBuyingPrice(item, maximumDurability) / 3, maximumBasePrice); + var basePrice = Math.Min(this.CalculateFinalBuyingPrice(item) / (isPet ? 1 : 3), maximumBasePrice); basePrice = RoundPrice(basePrice); float squareRootOfBasePrice = (float)Math.Sqrt(basePrice); @@ -313,20 +385,74 @@ public long CalculateRepairPrice(Item item, bool npcDiscount) } /// - /// Calculates the buying price of the item, which the player has to pay if he wants to buy the item from a merchant. + /// Calculates the final buying price of the item, which the player has to pay if he wants to buy the item from a merchant. /// /// The item. /// The buying price. - public long CalculateBuyingPrice(Item item) => CalculateBuyingPrice(item, item.Durability()); + public long CalculateFinalBuyingPrice(Item item) => RoundPrice(CalculateBuyingPrice(item)); + + /// + /// Calculates the final "old" buying price of the item. + /// Supposedly in earlier versions jewel reference prices were different, and those were used since for Chaos Weapon and First Wings craftings rate calculations. + /// + /// The item. + /// The "old" buying price. + public long CalculateFinalOldBuyingPrice(Item item) + { + if (SpecialItemOldValueDictionary.TryGetValue(GetId(item.Definition!.Group, item.Definition.Number), out var oldValue)) + { + return RoundPrice(oldValue); + } + else + { + return this.CalculateFinalBuyingPrice(item); + } + } + + private static int GetId(byte group, int id) + { + return (id << 8) + group; + } + + private static long RoundPrice(long price) + { + var result = price; + if (result >= 1000) + { + result = result / 100 * 100; + } + else if (result >= 100) + { + result = result / 10 * 10; + } + else + { + // no rounding for smaller values. + } + + return result; + } - private static long CalculateBuyingPrice(Item item, byte durability) + private static long CalculateBuyingPrice(Item item) { item.ThrowNotInitializedProperty(item.Definition is null, nameof(item.Definition)); var definition = item.Definition!; if (definition.Value > 0 && (definition.Group == 15 || definition.Group == 12)) { - return RoundPrice(definition.Value); + return definition.Value; + } + + if (item.IsTrainablePet()) + { + if (item.IsDarkRaven()) + { + return item.Level * 1_000_000; + } + else + { + return item.Level * 2_000_000; + } } long price = 0; @@ -343,7 +469,7 @@ private static long CalculateBuyingPrice(Item item, byte durability) } else if (definition.Value > 0) { - price += (definition.Value * definition.Value * 10) / 12; + price += definition.Value * definition.Value * 10 / 12; if (item.Definition.Group == 14 && (item.Definition.Number <= 8)) { // Potions + Antidote @@ -357,9 +483,21 @@ private static long CalculateBuyingPrice(Item item, byte durability) return price; } } - else if ((item.Definition.Group == 12 && item.Definition.Number > 6) || item.Definition.Group == 13 || item.Definition.Group == 15) + else if ((item.Definition.Group == 12 + && ((item.Definition.Number > 6 && item.Definition.Number < 36) + || (item.Definition.Number > 43 && item.Definition.Number != 50))) + || item.Definition.Group == 13 + || item.Definition.Group == 15) { + // Cape of Lord and Cape of Fighter go here price = (dropLevel * dropLevel * dropLevel) + 100; + + if (item.ItemOptions.FirstOrDefault(o => o.ItemOption?.OptionType == ItemOptionTypes.Option) is { } opt + && opt.ItemOption?.PowerUpDefinition?.TargetAttribute == Stats.HealthRecoveryMultiplier) + { + // Rings, pendants, and capes. Capes with physical damage option have no extra value (possibly a source bug). + price += price * opt.Level; + } } else { @@ -379,14 +517,14 @@ private static long CalculateBuyingPrice(Item item, byte durability) price = ((dropLevel + 40) * dropLevel * dropLevel / 8) + 100; } - var isOneHandedWeapon = item.Definition.Group < 6 && definition.Width < 2 && definition.BasePowerUpAttributes.Any(o => o.TargetAttribute == Stats.MinimumPhysBaseDmg); + var isOneHandedWeapon = item.Definition.Group < 6 && definition.Width < 2; var isShield = item.Definition.Group == 6; if (isOneHandedWeapon || isShield) { price = price * 80 / 100; } - if (item.HasSkill && definition.Skill?.Number != ForceWaveSkillId) + if (item.HasSkill && !WorthlessSkills.Contains(definition.Skill?.Number ?? 0)) { price += (long)(price * 1.5); } @@ -438,38 +576,6 @@ private static long CalculateBuyingPrice(Item item, byte durability) price = MaximumPrice; } - var maxDurability = item.GetMaximumDurabilityOfOnePiece(); - if (maxDurability > 1 && maxDurability > durability) - { - float multiplier = 1.0f - ((float)durability / maxDurability); - long loss = (long)(price * 0.6 * multiplier); - price -= loss; - } - - return RoundPrice(price); - } - - private static int GetId(byte group, int id) - { - return (id << 8) + group; - } - - private static long RoundPrice(long price) - { - var result = price; - if (result >= 1000) - { - result = result / 100 * 100; - } - else if (result >= 100) - { - result = result / 10 * 10; - } - else - { - // no rounding for smaller values. - } - - return result; + return price; } } \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/Craftings/BaseEventTicketCrafting.cs b/src/GameLogic/PlayerActions/Craftings/BaseEventTicketCrafting.cs index 0c803bb2f..ba8e0e515 100644 --- a/src/GameLogic/PlayerActions/Craftings/BaseEventTicketCrafting.cs +++ b/src/GameLogic/PlayerActions/Craftings/BaseEventTicketCrafting.cs @@ -100,7 +100,7 @@ protected sealed override int GetPrice(byte successRate, IList - protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketIndex) + protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketIndex, byte successRate) { var item = player.PersistenceContext.CreateNew(); item.Definition = player.GameContext.Configuration.Items.First(i => i.Name == this._resultItemName); diff --git a/src/GameLogic/PlayerActions/Craftings/ChaosWeaponAndFirstWingsCrafting.cs b/src/GameLogic/PlayerActions/Craftings/ChaosWeaponAndFirstWingsCrafting.cs new file mode 100644 index 000000000..382865840 --- /dev/null +++ b/src/GameLogic/PlayerActions/Craftings/ChaosWeaponAndFirstWingsCrafting.cs @@ -0,0 +1,67 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlayerActions.Craftings; + +using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; +using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic.PlayerActions.Items; + +/// +/// Crafting for Chaos Weapon and First Wings. +/// +public class ChaosWeaponAndFirstWingsCrafting : SimpleItemCraftingHandler +{ + /// + /// Initializes a new instance of the class. + /// + /// The settings. + public ChaosWeaponAndFirstWingsCrafting(SimpleCraftingSettings settings) + : base(settings) + { + } + + /// + protected override void AddRandomItemOption(Item resultItem, Player player, byte successRate) + { + if (resultItem.Definition!.PossibleItemOptions.FirstOrDefault(o => + o.PossibleOptions.Any(p => p.OptionType == ItemOptionTypes.Option)) + is { } option) + { + int i = Rand.NextInt(0, 3); + if (Rand.NextRandomBool((successRate / 5) + (4 * (i + 1)))) + { + var link = player.PersistenceContext.CreateNew(); + link.ItemOption = option.PossibleOptions.First(); + link.Level = 3 - i; + resultItem.ItemOptions.Add(link); + } + } + } + + /// + protected override void AddRandomLuckOption(Item resultItem, Player player, byte successRate) + { + if (Rand.NextRandomBool((successRate / 5) + 4) + && resultItem.Definition!.PossibleItemOptions.FirstOrDefault(o => + o.PossibleOptions.Any(po => po.OptionType == ItemOptionTypes.Luck)) + is { } luck) + { + var luckOption = player.PersistenceContext.CreateNew(); + luckOption.ItemOption = luck.PossibleOptions.First(); + resultItem.ItemOptions.Add(luckOption); + } + } + + /// + protected override void AddRandomSkill(Item resultItem, byte successRate) + { + if (Rand.NextRandomBool((successRate / 5) + 6) + && !resultItem.HasSkill + && resultItem.Definition!.Skill is { }) + { + resultItem.HasSkill = true; + } + } +} \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/Craftings/DevilSquareTicketCrafting.cs b/src/GameLogic/PlayerActions/Craftings/DevilSquareTicketCrafting.cs index fc2899e5b..fe606a3ce 100644 --- a/src/GameLogic/PlayerActions/Craftings/DevilSquareTicketCrafting.cs +++ b/src/GameLogic/PlayerActions/Craftings/DevilSquareTicketCrafting.cs @@ -35,6 +35,6 @@ protected override int GetPrice(int eventLevel) /// protected override byte GetSuccessRate(int eventLevel) { - return (byte)(80 - (eventLevel * 5)); + return (byte)(eventLevel < 5 ? 80 : 70); // Future to-do: There is a +10% increase if Crywolf event is beaten } } \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/Craftings/DinorantCrafting.cs b/src/GameLogic/PlayerActions/Craftings/DinorantCrafting.cs new file mode 100644 index 000000000..eb2f29bbd --- /dev/null +++ b/src/GameLogic/PlayerActions/Craftings/DinorantCrafting.cs @@ -0,0 +1,86 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlayerActions.Craftings; + +using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; +using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic.Attributes; +using MUnique.OpenMU.GameLogic.PlayerActions.Items; +using MUnique.OpenMU.GameLogic.Views.NPC; + +/// +/// Crafting for Dinorant. +/// +public class DinorantCrafting : SimpleItemCraftingHandler +{ + /// + /// Initializes a new instance of the class. + /// + /// The settings. + public DinorantCrafting(SimpleCraftingSettings settings) + : base(settings) + { + } + + /// + protected override CraftingResult? TryGetRequiredItems(Player player, out IList items, out byte successRate) + { + var craftingResult = base.TryGetRequiredItems(player, out items, out successRate); + + var uniriaLink = items.Where(i => i.ItemRequirement.PossibleItems.Any(i => i.Name == "Horn of Uniria")); + foreach (var item in uniriaLink.First().Items) + { + if (item.Durability < 255) + { + return CraftingResult.IncorrectMixItems; + } + } + + return craftingResult; + } + + /// + protected override void AddRandomItemOption(Item resultItem, Player player, byte successRate) + { + if (Rand.NextRandomBool(30) + && resultItem.Definition!.PossibleItemOptions.FirstOrDefault(o => + o.PossibleOptions.Any(p => p.OptionType == ItemOptionTypes.Option)) + is { } option) + { + var link = player.PersistenceContext.CreateNew(); + link.ItemOption = option.PossibleOptions.SelectRandom(); + resultItem.ItemOptions.Add(link); + + // There is a second rollout for an additional bonus option to the first (but only if it doesn't coincide). + if (Rand.NextRandomBool(20)) + { + var bonusOpt = option.PossibleOptions.SelectRandom(); + if (bonusOpt != link.ItemOption) + { + var bonusLink = player.PersistenceContext.CreateNew(); + bonusLink.ItemOption = bonusOpt; + resultItem.ItemOptions.Add(bonusLink); + } + } + } + + // Dinorant options were originally coded within the normal item option; each has a different level. + foreach (var dinoOption in resultItem.ItemOptions) + { + if (dinoOption.ItemOption!.PowerUpDefinition!.TargetAttribute == Stats.DamageReceiveDecrement) + { + dinoOption.Level = 1; + } + else if (dinoOption.ItemOption!.PowerUpDefinition!.TargetAttribute == Stats.MaximumAbility) + { + dinoOption.Level = 2; + } + else + { + dinoOption.Level = 4; + } + } + } +} \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/Craftings/FenrirUpgradeCrafting.cs b/src/GameLogic/PlayerActions/Craftings/FenrirUpgradeCrafting.cs index 083902394..6e48e4c89 100644 --- a/src/GameLogic/PlayerActions/Craftings/FenrirUpgradeCrafting.cs +++ b/src/GameLogic/PlayerActions/Craftings/FenrirUpgradeCrafting.cs @@ -31,16 +31,15 @@ protected override int GetPrice(byte successRate, IList item.Level >= 4 - && item.ItemOptions.Any(o => o.ItemOption?.OptionType == ItemOptionTypes.Option)) + && item.ItemOptions.Any(o => o.ItemOption?.OptionType == ItemOptionTypes.Option)) .ToList(); var randomWeapons = itemsLevelAndOption4 .Where(item => item.IsWearable() - && item.Definition!.BasePowerUpAttributes.Any(a => - a.TargetAttribute == Stats.MaximumPhysBaseDmgByWeapon)) + && item.Definition!.BasePowerUpAttributes.Any(a => a.TargetAttribute == Stats.AttackSpeedByWeapon)) .ToList(); - var randomArmors = itemsLevelAndOption4 - .Where(item => item.IsWearable() && item.Definition!.BasePowerUpAttributes.Any(a => a.TargetAttribute == Stats.DefenseBase)) + .Where(item => item.IsWearable() + && item.Definition!.BasePowerUpAttributes.Any(a => a.TargetAttribute == Stats.DefenseBase)) .ToList(); if (randomArmors.Any() && randomWeapons.Any()) @@ -82,22 +81,22 @@ protected override int GetPrice(byte successRate, IList - protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketIndex) + protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketIndex, byte successRate) { var fenrir = requiredItems.First(i => i.ItemRequirement.Reference == 1).Items.First(); + fenrir.Durability = 255; IEnumerable fenrirOptions; if (requiredItems.Any(i => i.ItemRequirement.Reference == 2)) diff --git a/src/GameLogic/PlayerActions/Craftings/FenrirUpgradeCraftingGold.cs b/src/GameLogic/PlayerActions/Craftings/FenrirUpgradeCraftingGold.cs index b2ff1b36b..7b9aee1de 100644 --- a/src/GameLogic/PlayerActions/Craftings/FenrirUpgradeCraftingGold.cs +++ b/src/GameLogic/PlayerActions/Craftings/FenrirUpgradeCraftingGold.cs @@ -31,33 +31,36 @@ protected override int GetPrice(byte successRate, IList(4); var inputItems = player.TemporaryStorage!.Items.ToList(); var itemsLevelAndOption4gold = inputItems - .Where(item => item.Level >= 11 - && item.ItemOptions.Any(o => o.ItemOption?.OptionType == ItemOptionTypes.Option) - && item.ItemOptions.Any(e => e.ItemOption?.OptionType == ItemOptionTypes.Excellent)) - .ToList(); + .Where(item => item.Level >= 11 + && item.ItemOptions.Any(o => o.ItemOption?.OptionType == ItemOptionTypes.Option) + && item.IsExcellent()) + .ToList(); var itemsLevelAndOption4 = inputItems - .Where(item => (item.Level >= 11 && !item.ItemOptions.Any(e => e.ItemOption?.OptionType == ItemOptionTypes.Excellent) - && item.ItemOptions.Any(o => o.ItemOption?.OptionType == ItemOptionTypes.Option)) - || (item.Level >= 4 && item.Level <= 10 && item.ItemOptions.Any(o => o.ItemOption?.OptionType == ItemOptionTypes.Option))) - .ToList(); + .Where(item => (item.Level >= 11 + && item.ItemOptions.Any(o => o.ItemOption?.OptionType == ItemOptionTypes.Option) + && !item.IsExcellent()) + || (item.Level >= 4 + && item.Level <= 10 + && item.ItemOptions.Any(o => o.ItemOption?.OptionType == ItemOptionTypes.Option))) + .ToList(); var randomWeapons = itemsLevelAndOption4 .Where(item => item.IsWearable() - && item.Definition!.BasePowerUpAttributes.Any(a => - a.TargetAttribute == Stats.MaximumPhysBaseDmgByWeapon)) + && item.Definition!.BasePowerUpAttributes.Any(a => a.TargetAttribute == Stats.AttackSpeedByWeapon)) .ToList(); var randomArmors = itemsLevelAndOption4 - .Where(item => item.IsWearable() && item.Definition!.BasePowerUpAttributes.Any(a => a.TargetAttribute == Stats.DefenseBase)) + .Where(item => item.IsWearable() + && item.Definition!.BasePowerUpAttributes.Any(a => a.TargetAttribute == Stats.DefenseBase)) .ToList(); var randomWeaponsGold = itemsLevelAndOption4gold .Where(item => item.IsWearable() - && item.Definition!.BasePowerUpAttributes.Any(a => - a.TargetAttribute == Stats.MaximumPhysBaseDmgByWeapon)) + && item.Definition!.BasePowerUpAttributes.Any(a => a.TargetAttribute == Stats.AttackSpeedByWeapon)) .ToList(); var randomArmorsGold = itemsLevelAndOption4gold - .Where(item => item.IsWearable() && item.Definition!.BasePowerUpAttributes.Any(a => a.TargetAttribute == Stats.DefenseBase)) + .Where(item => item.IsWearable() + && item.Definition!.BasePowerUpAttributes.Any(a => a.TargetAttribute == Stats.DefenseBase)) .ToList(); if (randomArmors.Any() && randomWeapons.Any()) @@ -131,34 +134,35 @@ protected override int GetPrice(byte successRate, IList - protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketIndex) + protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketIndex, byte successRate) { var fenrir = requiredItems.First(i => i.ItemRequirement.Reference == 1).Items.First(); + fenrir.Durability = 255; IEnumerable fenrirOptions; if (requiredItems.Any(i => i.ItemRequirement.Reference == 2)) diff --git a/src/GameLogic/PlayerActions/Craftings/GuardianOptionCrafting.cs b/src/GameLogic/PlayerActions/Craftings/GuardianOptionCrafting.cs index 78db6da90..3decf0645 100644 --- a/src/GameLogic/PlayerActions/Craftings/GuardianOptionCrafting.cs +++ b/src/GameLogic/PlayerActions/Craftings/GuardianOptionCrafting.cs @@ -29,7 +29,7 @@ public GuardianOptionCrafting(SimpleCraftingSettings settings) public static byte ItemReference { get; } = 0x88; /// - protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot) + protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot, byte successRate) { var item = requiredItems.First(i => i.ItemRequirement.Reference == ItemReference && i.Items.Any()).Items.First(); foreach (var optionDefinition in item.Definition!.PossibleItemOptions.First(o => o.PossibleOptions.Any(p => p.OptionType == ItemOptionTypes.GuardianOption)).PossibleOptions) diff --git a/src/GameLogic/PlayerActions/Craftings/IllusionTempleTicketCrafting.cs b/src/GameLogic/PlayerActions/Craftings/IllusionTempleTicketCrafting.cs index 32c656e9d..0451c4f33 100644 --- a/src/GameLogic/PlayerActions/Craftings/IllusionTempleTicketCrafting.cs +++ b/src/GameLogic/PlayerActions/Craftings/IllusionTempleTicketCrafting.cs @@ -19,9 +19,6 @@ public IllusionTempleTicketCrafting() { } - /// - protected override CraftingResult IncorrectMixItemsResult => CraftingResult.IncorrectBloodCastleItems; - /// protected override int GetPrice(int eventLevel) { diff --git a/src/GameLogic/PlayerActions/Craftings/MountSeedSphereCrafting.cs b/src/GameLogic/PlayerActions/Craftings/MountSeedSphereCrafting.cs index 5c68b5658..e7a7842a9 100644 --- a/src/GameLogic/PlayerActions/Craftings/MountSeedSphereCrafting.cs +++ b/src/GameLogic/PlayerActions/Craftings/MountSeedSphereCrafting.cs @@ -34,7 +34,7 @@ public MountSeedSphereCrafting(SimpleCraftingSettings settings) public static byte SocketItemReference { get; } = 0x88; /// - protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot) + protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot, byte successRate) { var seedSphere = requiredItems.Single(i => i.ItemRequirement.Reference == SeedSphereReference).Items.Single(); var socketItem = requiredItems.Single(i => i.ItemRequirement.Reference == SocketItemReference).Items.Single(); diff --git a/src/GameLogic/PlayerActions/Craftings/RefineStoneCrafting.cs b/src/GameLogic/PlayerActions/Craftings/RefineStoneCrafting.cs index 7689fe174..7f870e24c 100644 --- a/src/GameLogic/PlayerActions/Craftings/RefineStoneCrafting.cs +++ b/src/GameLogic/PlayerActions/Craftings/RefineStoneCrafting.cs @@ -135,7 +135,7 @@ protected override bool RequiredItemMatches(Item item, ItemCraftingRequiredItem } /// - protected override async ValueTask> CreateOrModifyResultItemsAsync(IList referencedItems, Player player, byte socketSlot) + protected override async ValueTask> CreateOrModifyResultItemsAsync(IList referencedItems, Player player, byte socketSlot, byte successRate) { var higherRefineStoneItems = referencedItems .FirstOrDefault(r => r.ItemRequirement.Reference == HigherRefineStoneReference)?.Items.Count() ?? 0; diff --git a/src/GameLogic/PlayerActions/Craftings/RemoveSeedSphereCrafting.cs b/src/GameLogic/PlayerActions/Craftings/RemoveSeedSphereCrafting.cs index c640af903..2c722e8b5 100644 --- a/src/GameLogic/PlayerActions/Craftings/RemoveSeedSphereCrafting.cs +++ b/src/GameLogic/PlayerActions/Craftings/RemoveSeedSphereCrafting.cs @@ -28,7 +28,7 @@ public RemoveSeedSphereCrafting(SimpleCraftingSettings settings) public static byte SocketItemReference { get; } = 0x88; /// - protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot) + protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot, byte successRate) { var socketItem = requiredItems.Single(i => i.ItemRequirement.Reference == SocketItemReference).Items.Single(); diff --git a/src/GameLogic/PlayerActions/Craftings/RestoreItemCrafting.cs b/src/GameLogic/PlayerActions/Craftings/RestoreItemCrafting.cs index f82a46df8..636deffdf 100644 --- a/src/GameLogic/PlayerActions/Craftings/RestoreItemCrafting.cs +++ b/src/GameLogic/PlayerActions/Craftings/RestoreItemCrafting.cs @@ -34,7 +34,7 @@ protected override int GetPrice(byte successRate, IList - protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot) + protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot, byte successRate) { var item = requiredItems.First().Items.First(); var johOptionLink = item.ItemOptions.First(link => link.ItemOption?.OptionType == ItemOptionTypes.HarmonyOption); diff --git a/src/GameLogic/PlayerActions/Craftings/SecondWingsCrafting.cs b/src/GameLogic/PlayerActions/Craftings/SecondWingsCrafting.cs new file mode 100644 index 000000000..9035532c1 --- /dev/null +++ b/src/GameLogic/PlayerActions/Craftings/SecondWingsCrafting.cs @@ -0,0 +1,55 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlayerActions.Craftings; + +using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; +using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic.PlayerActions.Items; + +/// +/// Crafting for Second Wings (including first capes). +/// +public class SecondWingsCrafting : SimpleItemCraftingHandler +{ + /// + /// Initializes a new instance of the class. + /// + /// The settings. + public SecondWingsCrafting(SimpleCraftingSettings settings) + : base(settings) + { + } + + /// + protected override void AddRandomItemOption(Item resultItem, Player player, byte successRate) + { + if (resultItem.Definition!.PossibleItemOptions.Where(o => o.PossibleOptions.Any(p => p.OptionType == ItemOptionTypes.Option)) + is { } options && options.Any()) + { + (int chance, int level) = Rand.NextInt(0, 3) switch + { + 0 => (20, 1), + 1 => (10, 2), + _ => (4, 3), + }; // From 300 created wings about 20+10+4=34 (~11%) will have item option + + if (Rand.NextRandomBool(chance)) + { + var link = player.PersistenceContext.CreateNew(); + link.Level = level; + if (options.Count() > 1) + { + link.ItemOption = options.ElementAt(Rand.NextInt(0, 2)).PossibleOptions.First(); + } + else + { + link.ItemOption = options.ElementAt(0).PossibleOptions.First(); // Cape of Lord + } + + resultItem.ItemOptions.Add(link); + } + } + } +} \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/Craftings/SeedSphereCrafting.cs b/src/GameLogic/PlayerActions/Craftings/SeedSphereCrafting.cs index 32b69e64f..44fa69451 100644 --- a/src/GameLogic/PlayerActions/Craftings/SeedSphereCrafting.cs +++ b/src/GameLogic/PlayerActions/Craftings/SeedSphereCrafting.cs @@ -34,7 +34,7 @@ public SeedSphereCrafting(SimpleCraftingSettings settings) public static byte SeedReference { get; } = 0x77; /// - protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot) + protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot, byte successRate) { var seed = requiredItems.Single(i => i.ItemRequirement.Reference == SeedReference).Items.Single(); var sphere = requiredItems.Single(i => i.ItemRequirement.Reference == SphereReference).Items.Single(); diff --git a/src/GameLogic/PlayerActions/Craftings/ThirdWingsCrafting.cs b/src/GameLogic/PlayerActions/Craftings/ThirdWingsCrafting.cs new file mode 100644 index 000000000..b6615f432 --- /dev/null +++ b/src/GameLogic/PlayerActions/Craftings/ThirdWingsCrafting.cs @@ -0,0 +1,83 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlayerActions.Craftings; + +using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; +using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic.PlayerActions.Items; + +/// +/// Crafting for Third Wings. +/// +public class ThirdWingsCrafting : SimpleItemCraftingHandler +{ + /// + /// Initializes a new instance of the class. + /// + /// The settings. + public ThirdWingsCrafting(SimpleCraftingSettings settings) + : base(settings) + { + } + + /// + protected override void AddRandomItemOption(Item resultItem, Player player, byte successRate) + { + if (resultItem.Definition!.PossibleItemOptions.Where(o => o.PossibleOptions.Any(p => p.OptionType == ItemOptionTypes.Option)) + is { } options && options.Any()) + { + (int chance1, int level) = Rand.NextInt(0, 4) switch + { + 0 => (0, 0), + 1 => (12, 1), + 2 => (6, 2), + _ => (3, 3), + }; // From 400 created wings about 0+12+6+3=21 (~5%) will have item option + + if (Rand.NextRandomBool(chance1)) + { + var link = player.PersistenceContext.CreateNew(); + link.Level = level; + (int chance2, int type) = Rand.NextRandomBool() + ? (40, 1) + : (30, 2); + + if (Rand.NextRandomBool(chance2)) + { + link.ItemOption = options.ElementAt(type).PossibleOptions.First(); // Additional dmg (phys, wiz, curse) or defense + } + else + { + link.ItemOption = options.ElementAt(0).PossibleOptions.First(); // HP recovery % + } + + resultItem.ItemOptions.Add(link); + } + } + } + + /// + protected override void AddRandomExcellentOptions(Item resultItem, Player player) + { + if (resultItem.Definition!.PossibleItemOptions.FirstOrDefault(o => o.PossibleOptions.Any(p => p.OptionType == ItemOptionTypes.Wing)) + is { } wingOption) + { + (int chance, int type) = Rand.NextInt(0, 4) switch + { + 0 => (4, 0), // Ignore def + 1 => (2, 1), // 5% full reflect + 2 => (7, 2), // 5% HP restore + _ => (7, 3), // 5% mana restore + }; // From 400 created wings about 4+2+7+7=20 (5%) will have wing "exc" option + + if (Rand.NextRandomBool(chance)) + { + var link = player.PersistenceContext.CreateNew(); + link.ItemOption = wingOption.PossibleOptions.ElementAt(type); + resultItem.ItemOptions.Add(link); + } + } + } +} \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/Items/BaseItemCraftingHandler.cs b/src/GameLogic/PlayerActions/Items/BaseItemCraftingHandler.cs index 8e9933378..29d870623 100644 --- a/src/GameLogic/PlayerActions/Items/BaseItemCraftingHandler.cs +++ b/src/GameLogic/PlayerActions/Items/BaseItemCraftingHandler.cs @@ -5,6 +5,7 @@ namespace MUnique.OpenMU.GameLogic.PlayerActions.Items; using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; +using MUnique.OpenMU.DataModel.Configuration.Items; using MUnique.OpenMU.GameLogic.PlugIns; using MUnique.OpenMU.GameLogic.Views.Inventory; using MUnique.OpenMU.GameLogic.Views.NPC; @@ -42,7 +43,7 @@ public abstract class BaseItemCraftingHandler : IItemCraftingHandler if (success) { player.Logger.LogInformation("Crafting succeeded with success chance: {successRate} %", successRate); - if (await this.DoTheMixAsync(items, player, socketSlot).ConfigureAwait(false) is { } item) + if (await this.DoTheMixAsync(items, player, socketSlot, successRate).ConfigureAwait(false) is { } item) { player.Logger.LogInformation("Crafted item: {item}", item); player.BackupInventory = null; @@ -88,8 +89,9 @@ public abstract class BaseItemCraftingHandler : IItemCraftingHandler /// The required items. /// The player. /// The slot of the socket. + /// The success rate of the combination. /// The created or modified items. - protected abstract ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot); + protected abstract ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot, byte successRate); /// /// Performs the crafting with the specified items. @@ -97,17 +99,18 @@ public abstract class BaseItemCraftingHandler : IItemCraftingHandler /// The required items. /// The player. /// The slot of the socket. + /// The success rate of the combination. /// /// The created or modified item. If there are multiple, only the last one is returned. /// - private async ValueTask DoTheMixAsync(IList requiredItems, Player player, byte socketSlot) + private async ValueTask DoTheMixAsync(IList requiredItems, Player player, byte socketSlot, byte successRate) { foreach (var requiredItemLink in requiredItems) { await this.RequiredItemChangeAsync(player, requiredItemLink, true).ConfigureAwait(false); } - var resultItems = await this.CreateOrModifyResultItemsAsync(requiredItems, player, socketSlot).ConfigureAwait(false); + var resultItems = await this.CreateOrModifyResultItemsAsync(requiredItems, player, socketSlot, successRate).ConfigureAwait(false); return resultItems.LastOrDefault(); } @@ -134,20 +137,56 @@ private async ValueTask RequiredItemChangeAsync(Player player, CraftingRequiredI } break; - case MixResult.DowngradedRandom: + case MixResult.ChaosWeaponAndFirstWingsDowngradedRandom: itemLink.Items.ForEach(item => { var previousLevel = item.Level; - item.Level = (byte)Rand.NextInt(0, item.Level); - player.Logger.LogDebug("Item {0} was downgraded from {1} to {2}.", item, previousLevel, item.Level); + var hadSkill = item.HasSkill; + var optionLowered = false; + var previousMaxDurability = item.GetMaximumDurabilityOfOnePiece(); + + item.Level = (byte)Rand.NextInt(0, previousLevel); + if (item.HasSkill && !item.IsExcellent() && Rand.NextRandomBool()) + { + item.HasSkill = false; + } + + if (item.ItemOptions.FirstOrDefault(o => o.ItemOption?.OptionType == ItemOptionTypes.Option) is { } optionLink && Rand.NextRandomBool()) + { + optionLowered = true; + if (optionLink.Level > 1) + { + optionLink.Level--; + } + else + { + item.ItemOptions.Remove(optionLink); + } + } + + item.Durability = item.GetMaximumDurabilityOfOnePiece() * item.Durability / previousMaxDurability; + player.Logger.LogDebug( + "Item {0} was downgraded from level {1} to {2}. Skill removed: {3}. Item option lowered by 1 level: {4}.", + item, + previousLevel, + item.Level, + hadSkill && !item.HasSkill, + optionLowered); }); break; - case MixResult.DowngradedTo0: + case MixResult.ThirdWingsDowngradedRandom: itemLink.Items.ForEach(item => { - player.Logger.LogDebug("Item {0} is getting downgraded to level 0.", item); - item.Level = 0; + var previousLevel = item.Level; + item.Level -= (byte)(Rand.NextRandomBool() ? 2 : 3); + if (item.ItemOptions.FirstOrDefault(o => o.ItemOption?.OptionType == ItemOptionTypes.Option) is { } optionLink) + { + item.ItemOptions.Remove(optionLink); + } + + item.Durability = item.GetMaximumDurabilityOfOnePiece(); + player.Logger.LogDebug("Item {0} was downgraded from level {1} to {2}. Item option was removed.", item, previousLevel, item.Level); }); break; diff --git a/src/GameLogic/PlayerActions/Items/BuyNpcItemAction.cs b/src/GameLogic/PlayerActions/Items/BuyNpcItemAction.cs index 0d3c43d00..b7b90ad1b 100644 --- a/src/GameLogic/PlayerActions/Items/BuyNpcItemAction.cs +++ b/src/GameLogic/PlayerActions/Items/BuyNpcItemAction.cs @@ -94,7 +94,7 @@ public async ValueTask BuyItemAsync(Player player, byte slot) private bool CheckMoney(Player player, Item item) { - var price = this._priceCalculator.CalculateBuyingPrice(item); + var price = this._priceCalculator.CalculateFinalBuyingPrice(item); if (!player.TryRemoveMoney((int)price)) { return false; diff --git a/src/GameLogic/PlayerActions/Items/ItemRepairAction.cs b/src/GameLogic/PlayerActions/Items/ItemRepairAction.cs index 8d7f7c91d..b18f55fa4 100644 --- a/src/GameLogic/PlayerActions/Items/ItemRepairAction.cs +++ b/src/GameLogic/PlayerActions/Items/ItemRepairAction.cs @@ -56,7 +56,7 @@ public async ValueTask RepairItemAsync(Player player, byte slot) /// /// The player. /// - /// The client calculates a sum based on all items in the inventory, even these which are not equipped. + /// The client calculates a sum based on all items in the inventory, even those which are not equipped. /// However, it should really just repair the equipped ones. /// public async ValueTask RepairAllItemsAsync(Player player) diff --git a/src/GameLogic/PlayerActions/Items/SellItemToNpcAction.cs b/src/GameLogic/PlayerActions/Items/SellItemToNpcAction.cs index 782533213..85caf4636 100644 --- a/src/GameLogic/PlayerActions/Items/SellItemToNpcAction.cs +++ b/src/GameLogic/PlayerActions/Items/SellItemToNpcAction.cs @@ -57,7 +57,7 @@ public async ValueTask SellItemAsync(Player player, byte slot) private async ValueTask SellItemAsync(Player player, Item item) { - var sellingPrice = (int)this._itemPriceCalculator.CalculateSellingPrice(item); + var sellingPrice = (int)this._itemPriceCalculator.CalculateSellingPrice(item, item.Durability()); player.Logger.LogDebug("Calculated selling price {0} for item {1}", sellingPrice, item); if (player.TryAddMoney(sellingPrice)) { diff --git a/src/GameLogic/PlayerActions/Items/SimpleItemCraftingHandler.cs b/src/GameLogic/PlayerActions/Items/SimpleItemCraftingHandler.cs index ca78673a3..546bb4db8 100644 --- a/src/GameLogic/PlayerActions/Items/SimpleItemCraftingHandler.cs +++ b/src/GameLogic/PlayerActions/Items/SimpleItemCraftingHandler.cs @@ -53,6 +53,7 @@ protected virtual bool RequiredItemMatches(Item item, ItemCraftingRequiredItem r { successRate = 0; int rate = this._settings.SuccessPercent; + long totalCraftingPrice = 0; items = new List(this._settings.RequiredItems.Count); var storage = player.TemporaryStorage?.Items.ToList() ?? new List(); foreach (var requiredItem in this._settings.RequiredItems.OrderByDescending(i => i.MinimumAmount)) @@ -71,36 +72,49 @@ protected virtual bool RequiredItemMatches(Item item, ItemCraftingRequiredItem r return CraftingResult.TooManyItems; } - rate += (byte)(requiredItem.AddPercentage * (itemCount - requiredItem.MinimumAmount)); - if (requiredItem.NpcPriceDivisor > 0) + if (this._settings.NpcPriceDivisor > 0) { - rate += (byte)(foundItems.Sum(this._priceCalculator.CalculateBuyingPrice) / - requiredItem.NpcPriceDivisor); + totalCraftingPrice += foundItems.Sum(this._priceCalculator.CalculateFinalOldBuyingPrice); } - - foreach (var item in foundItems) + else { - if (this._settings.SuccessPercentageAdditionForLuck != default - && item.ItemOptions.Any(o => o.ItemOption?.OptionType == ItemOptionTypes.Luck)) - { - rate = (byte)(rate + this._settings.SuccessPercentageAdditionForLuck); - } - - if (this._settings.SuccessPercentageAdditionForExcellentItem != default - && item.IsExcellent()) + rate += (byte)(requiredItem.AddPercentage * (itemCount - requiredItem.MinimumAmount)); + if (requiredItem.NpcPriceDivisor > 0) { - rate = (byte)(rate + this._settings.SuccessPercentageAdditionForExcellentItem); + rate += (byte)(foundItems.Sum(this._priceCalculator.CalculateFinalBuyingPrice) + / requiredItem.NpcPriceDivisor); } - if (this._settings.SuccessPercentageAdditionForAncientItem != default - && item.IsAncient()) + foreach (var item in foundItems) { - rate = (byte)(rate + this._settings.SuccessPercentageAdditionForAncientItem); - } - - if (this._settings.SuccessPercentageAdditionForSocketItem != default && item.SocketCount > 0) - { - rate = (byte)(rate + this._settings.SuccessPercentageAdditionForSocketItem); + if (this._settings.SuccessPercentageAdditionForLuck != default + && item.ItemOptions.Any(o => o.ItemOption?.OptionType == ItemOptionTypes.Luck)) + { + rate = (byte)(rate + this._settings.SuccessPercentageAdditionForLuck); + } + + if (this._settings.SuccessPercentageAdditionForExcellentItem != default + && item.IsExcellent()) + { + rate = (byte)(rate + this._settings.SuccessPercentageAdditionForExcellentItem); + } + + if (this._settings.SuccessPercentageAdditionForAncientItem != default + && item.IsAncient()) + { + rate = (byte)(rate + this._settings.SuccessPercentageAdditionForAncientItem); + } + + if (this._settings.SuccessPercentageAdditionForGuardianItem != default + && item.IsGuardian()) + { + rate = (byte)(rate + this._settings.SuccessPercentageAdditionForGuardianItem); + } + + if (this._settings.SuccessPercentageAdditionForSocketItem != default && item.SocketCount > 0) + { + rate = (byte)(rate + this._settings.SuccessPercentageAdditionForSocketItem); + } } } @@ -114,6 +128,11 @@ protected virtual bool RequiredItemMatches(Item item, ItemCraftingRequiredItem r return CraftingResult.IncorrectMixItems; } + if (totalCraftingPrice > 0) + { + rate = (byte)(totalCraftingPrice / this._settings.NpcPriceDivisor); + } + if (this._settings.MaximumSuccessPercent > 0) { rate = Math.Min(this._settings.MaximumSuccessPercent, rate); @@ -125,7 +144,7 @@ protected virtual bool RequiredItemMatches(Item item, ItemCraftingRequiredItem r } /// - protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot) + protected override async ValueTask> CreateOrModifyResultItemsAsync(IList requiredItems, Player player, byte socketSlot, byte successRate) { var resultItems = this._settings.ResultItemSelect == ResultItemSelection.All ? this._settings.ResultItems @@ -139,7 +158,9 @@ protected override async ValueTask> CreateOrModifyResultItemsAsync(IL { foreach (var item in referencedItem.Items) { + var previousMaxDurability = item.GetMaximumDurabilityOfOnePiece(); item.Level += craftingResultItem.AddLevel; + item.Durability = item.GetMaximumDurabilityOfOnePiece() * item.Durability / previousMaxDurability; resultList.Add(item); } @@ -153,53 +174,62 @@ protected override async ValueTask> CreateOrModifyResultItemsAsync(IL continue; } - resultList.AddRange(await this.CreateResultItemsAsync(player, requiredItems, craftingResultItem).ConfigureAwait(false)); + resultList.AddRange(await this.CreateResultItemsAsync(player, requiredItems, craftingResultItem, successRate).ConfigureAwait(false)); } return resultList; } - private async ValueTask> CreateResultItemsAsync(Player player, IList referencedItems, ItemCraftingResultItem craftingResultItem) + /// + /// Randomly adds an excellent option to the . + /// + /// The result item. + /// The player. + protected virtual void AddRandomExcellentOptions(Item resultItem, Player player) { - int resultItemCount = this._settings.MultipleAllowed - ? referencedItems.FirstOrDefault(r => r.ItemRequirement.Reference > 0)?.Items.Count() ?? 1 - : 1; - - var resultList = new List(resultItemCount); - for (int i = 0; i < resultItemCount; i++) + if (this._settings.ResultItemExcellentOptionChance > 0 + && resultItem.Definition!.PossibleItemOptions.FirstOrDefault(o => + o.PossibleOptions.Any(p => p.OptionType == ItemOptionTypes.Excellent || p.OptionType == ItemOptionTypes.Wing)) + is { } optionDefinition) { - // Create new Item - var resultItem = player.PersistenceContext.CreateNew(); - resultItem.Definition = craftingResultItem.ItemDefinition ?? throw Error.NotInitializedProperty(craftingResultItem, nameof(craftingResultItem.ItemDefinition)); - resultItem.Level = (byte)Rand.NextInt( - craftingResultItem.RandomMinimumLevel, - craftingResultItem.RandomMaximumLevel + 1); - resultItem.Durability = - craftingResultItem.Durability ?? resultItem.GetMaximumDurabilityOfOnePiece(); - - this.AddRandomLuckOption(resultItem, player); - this.AddRandomExcellentOptions(resultItem, player); - if (!resultItem.HasSkill - && this._settings.ResultItemSkillChance > 0 - && Rand.NextRandomBool(this._settings.ResultItemSkillChance) - && resultItem.Definition!.Skill is { }) + for (int j = 0; + j < optionDefinition.MaximumOptionsPerItem && Rand.NextRandomBool(this._settings.ResultItemExcellentOptionChance); + j++) { - resultItem.HasSkill = true; + var link = player.PersistenceContext.CreateNew(); + link.ItemOption = optionDefinition.PossibleOptions + .Except(resultItem.ItemOptions.Select(io => io.ItemOption)).SelectRandom(); + resultItem.ItemOptions.Add(link); + if (resultItem.Definition.Skill != null) + { + // Excellent items always have skill. + resultItem.HasSkill = true; + } } - - await player.TemporaryStorage!.AddItemAsync(resultItem).ConfigureAwait(false); - resultList.Add(resultItem); } + } - return resultList; + /// + /// Randomly adds item option to the . + /// + /// The result item. + /// The player. + /// The crafting combination success rate. + protected virtual void AddRandomItemOption(Item resultItem, Player player, byte successRate) + { } - private void AddRandomLuckOption(Item resultItem, Player player) + /// + /// Randomly adds luck option to the . + /// + /// The result item. + /// The player. + /// The crafting combination success rate. + protected virtual void AddRandomLuckOption(Item resultItem, Player player, byte successRate) { - if (this._settings.ResultItemLuckOptionChance > 0 - && Rand.NextRandomBool(this._settings.ResultItemLuckOptionChance) - && resultItem.Definition!.PossibleItemOptions - .FirstOrDefault(o => o.PossibleOptions.Any(po => po.OptionType == ItemOptionTypes.Luck)) + if (this._settings.ResultItemLuckOptionChance > 0 && Rand.NextRandomBool(this._settings.ResultItemLuckOptionChance) + && resultItem.Definition!.PossibleItemOptions.FirstOrDefault(o => + o.PossibleOptions.Any(po => po.OptionType == ItemOptionTypes.Luck)) is { } luck) { var luckOption = player.PersistenceContext.CreateNew(); @@ -208,27 +238,47 @@ private void AddRandomLuckOption(Item resultItem, Player player) } } - private void AddRandomExcellentOptions(Item resultItem, Player player) + /// + /// Randomly adds skill to the . + /// + /// The result item. + /// The crafting combination success rate. + protected virtual void AddRandomSkill(Item resultItem, byte successRate) { - if (this._settings.ResultItemExcellentOptionChance > 0 - && resultItem.Definition!.PossibleItemOptions.FirstOrDefault(o => - o.PossibleOptions.Any(p => p.OptionType == ItemOptionTypes.Excellent || p.OptionType == ItemOptionTypes.Wing)) - is { } optionDefinition) + if (this._settings.ResultItemSkillChance > 0 && Rand.NextRandomBool(this._settings.ResultItemSkillChance) + && !resultItem.HasSkill + && resultItem.Definition!.Skill is { }) { - for (int j = 0; - j < optionDefinition.MaximumOptionsPerItem && Rand.NextRandomBool(this._settings.ResultItemExcellentOptionChance); - j++) - { - var link = player.PersistenceContext.CreateNew(); - link.ItemOption = optionDefinition.PossibleOptions - .Except(resultItem.ItemOptions.Select(io => io.ItemOption)).SelectRandom(); - resultItem.ItemOptions.Add(link); - if (resultItem.Definition.Skill != null) - { - // Excellent items always have skill. - resultItem.HasSkill = true; - } - } + resultItem.HasSkill = true; } } + + private async ValueTask> CreateResultItemsAsync(Player player, IList referencedItems, ItemCraftingResultItem craftingResultItem, byte successRate) + { + int resultItemCount = this._settings.MultipleAllowed + ? referencedItems.FirstOrDefault(r => r.ItemRequirement.Reference > 0)?.Items.Count() ?? 1 + : 1; + + var resultList = new List(resultItemCount); + for (int i = 0; i < resultItemCount; i++) + { + // Create new Item + var resultItem = player.PersistenceContext.CreateNew(); + resultItem.Definition = craftingResultItem.ItemDefinition ?? throw Error.NotInitializedProperty(craftingResultItem, nameof(craftingResultItem.ItemDefinition)); + resultItem.Level = resultItem.Definition.Group == ItemConstants.Fruits.Group && resultItem.Definition.Number == ItemConstants.Fruits.Number + ? (byte)new List { 0, 1, 2, 3, 4 }.SelectWeightedRandom([30, 25, 20, 20, 5]) + : (byte)Rand.NextInt(craftingResultItem.RandomMinimumLevel, craftingResultItem.RandomMaximumLevel + 1); + resultItem.Durability = craftingResultItem.Durability ?? resultItem.GetMaximumDurabilityOfOnePiece(); + + this.AddRandomLuckOption(resultItem, player, successRate); + this.AddRandomItemOption(resultItem, player, successRate); + this.AddRandomSkill(resultItem, successRate); + this.AddRandomExcellentOptions(resultItem, player); + + await player.TemporaryStorage!.AddItemAsync(resultItem).ConfigureAwait(false); + resultList.Add(resultItem); + } + + return resultList; + } } \ No newline at end of file diff --git a/src/GameLogic/PlugIns/ChatCommands/ItemChatCommandPlugIn.cs b/src/GameLogic/PlugIns/ChatCommands/ItemChatCommandPlugIn.cs index 2435da8d7..ead5d2cbd 100644 --- a/src/GameLogic/PlugIns/ChatCommands/ItemChatCommandPlugIn.cs +++ b/src/GameLogic/PlugIns/ChatCommands/ItemChatCommandPlugIn.cs @@ -6,6 +6,7 @@ namespace MUnique.OpenMU.GameLogic.PlugIns.ChatCommands; using System.Runtime.InteropServices; using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic.Attributes; using MUnique.OpenMU.GameLogic.PlugIns.ChatCommands.Arguments; using MUnique.OpenMU.PlugIns; @@ -77,13 +78,41 @@ private static void AddOption(TemporaryItem item, ItemChatCommandArgs arguments) { if (item.Definition != null && arguments.Opt > default(byte)) { - var itemOption = item.Definition.PossibleItemOptions + var allOptions = item.Definition.PossibleItemOptions .SelectMany(o => o.PossibleOptions) - .First(o => o.OptionType == ItemOptionTypes.Option); + .Where(o => o.OptionType == ItemOptionTypes.Option); + IncreasableItemOption itemOption; - var level = arguments.Opt; - var optionLink = new ItemOptionLink { ItemOption = itemOption, Level = level }; - item.ItemOptions.Add(optionLink); + if (item.Definition.Skill?.Number == 49) // Dinorant + { + if ((arguments.Opt & 1) > 0) + { + itemOption = allOptions.First(o => o.PowerUpDefinition!.TargetAttribute == Stats.DamageReceiveDecrement); + var dinoOptionLink = new ItemOptionLink { ItemOption = itemOption, Level = 1 }; + item.ItemOptions.Add(dinoOptionLink); + } + + if ((arguments.Opt & 2) > 0) + { + itemOption = allOptions.First(o => o.PowerUpDefinition!.TargetAttribute == Stats.MaximumAbility); + var dinoOptionLink = new ItemOptionLink { ItemOption = itemOption, Level = 2 }; + item.ItemOptions.Add(dinoOptionLink); + } + + if ((arguments.Opt & 4) > 0) + { + itemOption = allOptions.First(o => o.PowerUpDefinition!.TargetAttribute == Stats.AttackSpeed); + var dinoOptionLink = new ItemOptionLink { ItemOption = itemOption, Level = 4 }; + item.ItemOptions.Add(dinoOptionLink); + } + } + else + { + itemOption = allOptions.First(); + var level = arguments.Opt; + var optionLink = new ItemOptionLink { ItemOption = itemOption, Level = level }; + item.ItemOptions.Add(optionLink); + } } } diff --git a/src/GameLogic/Rand.cs b/src/GameLogic/Rand.cs index ec49d7ab6..33a297e00 100644 --- a/src/GameLogic/Rand.cs +++ b/src/GameLogic/Rand.cs @@ -31,7 +31,7 @@ public static IRandomizer GetRandomizer() /// Random boolean value. public static bool NextRandomBool() { - int a = RandomInstance.Next(0, 1); + int a = RandomInstance.Next(0, 2); return a == 1; } diff --git a/src/GameServer/RemoteView/ItemSerializer.cs b/src/GameServer/RemoteView/ItemSerializer.cs index 79e691f2f..0ea0f75ae 100644 --- a/src/GameServer/RemoteView/ItemSerializer.cs +++ b/src/GameServer/RemoteView/ItemSerializer.cs @@ -9,6 +9,7 @@ namespace MUnique.OpenMU.GameServer.RemoteView; using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.DataModel.Configuration.Items; using MUnique.OpenMU.DataModel.Entities; +using MUnique.OpenMU.GameLogic; using MUnique.OpenMU.Network.PlugIns; using MUnique.OpenMU.Persistence; using MUnique.OpenMU.PlugIns; @@ -52,9 +53,19 @@ public int SerializeItem(Span target, Item item) var itemOption = item.ItemOptions.FirstOrDefault(o => o.ItemOption?.OptionType == ItemOptionTypes.Option); if (itemOption != null) { + var optionLevel = itemOption.Level; + + // A dinorant can normally have up to 2 options, all being coded in the item option level. + // A one-option dino has level = 1, 2, or 4; a two-option has level = 3, 5, or 6. + if (item.Definition.Skill?.Number == 49) + { + item.ItemOptions.Where(o => o.ItemOption?.OptionType == ItemOptionTypes.Option && o != itemOption) + .ForEach(o => optionLevel |= o.Level); + } + // The item option level is splitted into 2 parts. Webzen... :-/ - target[1] += (byte)(itemOption.Level & 3); // setting the first 2 bits - target[3] = (byte)((itemOption.Level & 4) << 4); // The highest bit is placed into the 2nd bit of the exc byte (0x40). + target[1] += (byte)(optionLevel & 3); // setting the first 2 bits + target[3] = (byte)((optionLevel & 4) << 4); // The highest bit is placed into the 2nd bit of the exc byte (0x40). // Some items (wings) can have different options (3rd wings up to 3!) // Alternate options are set at array[startIndex + 3] |= 0x20 and 0x10 diff --git a/src/GameServer/RemoteView/ItemSerializer095.cs b/src/GameServer/RemoteView/ItemSerializer095.cs index 2c667372c..b72bd3569 100644 --- a/src/GameServer/RemoteView/ItemSerializer095.cs +++ b/src/GameServer/RemoteView/ItemSerializer095.cs @@ -9,6 +9,7 @@ namespace MUnique.OpenMU.GameServer.RemoteView; using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.DataModel.Configuration.Items; using MUnique.OpenMU.DataModel.Entities; +using MUnique.OpenMU.GameLogic; using MUnique.OpenMU.Network.PlugIns; using MUnique.OpenMU.Persistence; using MUnique.OpenMU.PlugIns; @@ -65,8 +66,18 @@ public int SerializeItem(Span target, Item item) var itemOption = item.ItemOptions.FirstOrDefault(o => o.ItemOption?.OptionType == ItemOptionTypes.Option); if (itemOption != null) { - target[1] |= (byte)(itemOption.Level & 3); - target[3] |= (byte)((itemOption.Level & 4) << 4); // The highest bit is placed into the 2nd bit of the exc byte (0x40). + var optionLevel = itemOption.Level; + + // A dinorant can normally have up to 2 options, all being coded in the item option level. + // A one-option dino has level = 1, 2, or 4; a two-option has level = 3, 5, or 6. + if (item.Definition.Skill?.Number == 49) + { + item.ItemOptions.Where(o => o.ItemOption?.OptionType == ItemOptionTypes.Option && o != itemOption) + .ForEach(o => optionLevel |= o.Level); + } + + target[1] |= (byte)(optionLevel & 3); + target[3] |= (byte)((optionLevel & 4) << 4); // The highest bit is placed into the 2nd bit of the exc byte (0x40). } target[3] |= GetExcellentByte(item); diff --git a/src/Persistence/EntityFramework/Migrations/20241204090233_UpdateSimpleCraftingSettings.Designer.cs b/src/Persistence/EntityFramework/Migrations/20241204090233_UpdateSimpleCraftingSettings.Designer.cs new file mode 100644 index 000000000..8acf6f9a9 --- /dev/null +++ b/src/Persistence/EntityFramework/Migrations/20241204090233_UpdateSimpleCraftingSettings.Designer.cs @@ -0,0 +1,5082 @@ +// +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("20241204090233_UpdateSimpleCraftingSettings")] + partial class UpdateSimpleCraftingSettings + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChatBanUntil") + .HasColumnType("timestamp with time zone"); + + b.Property("EMail") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsVaultExtended") + .HasColumnType("boolean"); + + b.Property("LoginName") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegistrationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("TimeZone") + .HasColumnType("smallint"); + + b.Property("VaultId") + .HasColumnType("uuid"); + + b.Property("VaultPassword") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("LoginName") + .IsUnique(); + + b.HasIndex("VaultId") + .IsUnique(); + + b.ToTable("Account", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AccountCharacterClass", b => + { + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("AccountId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("AccountCharacterClass", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("FullAncientSetEquipped") + .HasColumnType("boolean"); + + b.Property("Pose") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("AppearanceData", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AreaSkillSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DelayBetweenHits") + .HasColumnType("interval"); + + b.Property("DelayPerOneDistance") + .HasColumnType("interval"); + + b.Property("FrustumDistance") + .HasColumnType("real"); + + b.Property("FrustumEndWidth") + .HasColumnType("real"); + + b.Property("FrustumStartWidth") + .HasColumnType("real"); + + b.Property("HitChancePerDistanceMultiplier") + .HasColumnType("real"); + + b.Property("MaximumNumberOfHitsPerAttack") + .HasColumnType("integer"); + + b.Property("MaximumNumberOfHitsPerTarget") + .HasColumnType("integer"); + + b.Property("MinimumNumberOfHitsPerTarget") + .HasColumnType("integer"); + + b.Property("TargetAreaDiameter") + .HasColumnType("real"); + + b.Property("UseDeferredHits") + .HasColumnType("boolean"); + + b.Property("UseFrustumFilter") + .HasColumnType("boolean"); + + b.Property("UseTargetAreaFilter") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AreaSkillSettings", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Designation") + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MaximumValue") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("AttributeDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRelationship", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("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") + .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("MaximumItemOptionLevelDrop") + .HasColumnType("smallint"); + + b.Property("MaximumLetters") + .HasColumnType("integer"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MaximumMasterLevel") + .HasColumnType("smallint"); + + b.Property("MaximumPartySize") + .HasColumnType("smallint"); + + b.Property("MaximumPasswordLength") + .HasColumnType("integer"); + + b.Property("MaximumVaultMoney") + .HasColumnType("integer"); + + b.Property("MinimumMonsterLevelForMasterExperience") + .HasColumnType("smallint"); + + b.Property("RecoveryInterval") + .HasColumnType("integer"); + + b.Property("ShouldDropMoney") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("DuelConfigurationId") + .IsUnique(); + + b.ToTable("GameConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BattleZoneId") + .HasColumnType("uuid"); + + b.Property("Discriminator") + .HasColumnType("integer"); + + b.Property("ExpMultiplier") + .HasColumnType("double precision"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SafezoneMapId") + .HasColumnType("uuid"); + + b.Property("TerrainData") + .HasColumnType("bytea"); + + b.HasKey("Id"); + + b.HasIndex("BattleZoneId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("SafezoneMapId"); + + b.ToTable("GameMapDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinitionDropItemGroup", b => + { + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.HasKey("GameMapDefinitionId", "DropItemGroupId"); + + b.HasIndex("DropItemGroupId"); + + b.ToTable("GameMapDefinitionDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumPlayers") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("GameServerConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfigurationGameMapDefinition", b => + { + b.Property("GameServerConfigurationId") + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("GameServerConfigurationId", "GameMapDefinitionId"); + + b.HasIndex("GameMapDefinitionId"); + + b.ToTable("GameServerConfigurationGameMapDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExperienceRate") + .HasColumnType("real"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("PvpEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("ServerConfigurationId") + .HasColumnType("uuid"); + + b.Property("ServerID") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("ServerConfigurationId"); + + b.ToTable("GameServerDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerEndpoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AlternativePublishedPort") + .HasColumnType("integer"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("GameServerDefinitionId") + .HasColumnType("uuid"); + + b.Property("NetworkPort") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.HasIndex("GameServerDefinitionId"); + + b.ToTable("GameServerEndpoint", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllianceGuildId") + .HasColumnType("uuid"); + + b.Property("HostilityId") + .HasColumnType("uuid"); + + b.Property("Logo") + .HasColumnType("bytea"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.Property("Notice") + .HasColumnType("text"); + + b.Property("Score") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AllianceGuildId"); + + b.HasIndex("HostilityId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Guild", "guild"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GuildMember", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("GuildId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GuildId"); + + b.ToTable("GuildMember", "guild"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemOptionDefinitionId") + .HasColumnType("uuid"); + + b.Property("LevelType") + .HasColumnType("integer"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.Property("Weight") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ItemOptionDefinitionId"); + + b.HasIndex("OptionTypeId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("IncreasableItemOption", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Durability") + .HasColumnType("double precision"); + + b.Property("HasSkill") + .HasColumnType("boolean"); + + b.Property("ItemSlot") + .HasColumnType("smallint"); + + b.Property("ItemStorageId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("smallint"); + + b.Property("PetExperience") + .HasColumnType("integer"); + + b.Property("SocketCount") + .HasColumnType("integer"); + + b.Property("StorePrice") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DefinitionId"); + + b.HasIndex("ItemStorageId"); + + b.ToTable("Item", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AppearanceDataId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSlot") + .HasColumnType("smallint"); + + b.Property("Level") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AppearanceDataId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("ItemAppearance", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearanceItemOptionType", b => + { + b.Property("ItemAppearanceId") + .HasColumnType("uuid"); + + b.Property("ItemOptionTypeId") + .HasColumnType("uuid"); + + b.HasKey("ItemAppearanceId", "ItemOptionTypeId"); + + b.HasIndex("ItemOptionTypeId"); + + b.ToTable("ItemAppearanceItemOptionType", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemBasePowerUpDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AggregateType") + .HasColumnType("integer"); + + b.Property("BaseValue") + .HasColumnType("real"); + + b.Property("BonusPerLevelTableId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BonusPerLevelTableId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("ItemBasePowerUpDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCrafting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemCraftingHandlerClassName") + .IsRequired() + .HasColumnType("text"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MonsterDefinitionId"); + + b.HasIndex("SimpleCraftingSettingsId") + .IsUnique(); + + b.ToTable("ItemCrafting", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddPercentage") + .HasColumnType("smallint"); + + b.Property("FailResult") + .HasColumnType("integer"); + + b.Property("MaximumAmount") + .HasColumnType("smallint"); + + b.Property("MaximumItemLevel") + .HasColumnType("smallint"); + + b.Property("MinimumAmount") + .HasColumnType("smallint"); + + b.Property("MinimumItemLevel") + .HasColumnType("smallint"); + + b.Property("NpcPriceDivisor") + .HasColumnType("integer"); + + b.Property("Reference") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.Property("SuccessResult") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SimpleCraftingSettingsId"); + + b.ToTable("ItemCraftingRequiredItem", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemDefinition", b => + { + b.Property("ItemCraftingRequiredItemId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemCraftingRequiredItemId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("ItemCraftingRequiredItemItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemOptionType", b => + { + b.Property("ItemCraftingRequiredItemId") + .HasColumnType("uuid"); + + b.Property("ItemOptionTypeId") + .HasColumnType("uuid"); + + b.HasKey("ItemCraftingRequiredItemId", "ItemOptionTypeId"); + + b.HasIndex("ItemOptionTypeId"); + + b.ToTable("ItemCraftingRequiredItemItemOptionType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingResultItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddLevel") + .HasColumnType("smallint"); + + b.Property("Durability") + .HasColumnType("smallint"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("RandomMaximumLevel") + .HasColumnType("smallint"); + + b.Property("RandomMinimumLevel") + .HasColumnType("smallint"); + + b.Property("Reference") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("SimpleCraftingSettingsId"); + + b.ToTable("ItemCraftingResultItem", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConsumeEffectId") + .HasColumnType("uuid"); + + b.Property("DropLevel") + .HasColumnType("smallint"); + + b.Property("DropsFromMonsters") + .HasColumnType("boolean"); + + b.Property("Durability") + .HasColumnType("smallint"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Group") + .HasColumnType("smallint"); + + b.Property("Height") + .HasColumnType("smallint"); + + b.Property("IsAmmunition") + .HasColumnType("boolean"); + + b.Property("IsBoundToCharacter") + .HasColumnType("boolean"); + + b.Property("ItemSlotId") + .HasColumnType("uuid"); + + b.Property("MaximumItemLevel") + .HasColumnType("smallint"); + + b.Property("MaximumSockets") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("PetExperienceFormula") + .HasColumnType("text"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("StorageLimitPerCharacter") + .HasColumnType("integer"); + + b.Property("Value") + .HasColumnType("integer"); + + b.Property("Width") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ConsumeEffectId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("ItemSlotId"); + + b.HasIndex("SkillId"); + + b.ToTable("ItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionCharacterClass", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("ItemDefinitionCharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemOptionDefinition", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemOptionDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "ItemOptionDefinitionId"); + + b.HasIndex("ItemOptionDefinitionId"); + + b.ToTable("ItemDefinitionItemOptionDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemSetGroup", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSetGroupId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "ItemSetGroupId"); + + b.HasIndex("ItemSetGroupId"); + + b.ToTable("ItemDefinitionItemSetGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Chance") + .HasColumnType("double precision"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("DropEffect") + .HasColumnType("integer"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemLevel") + .HasColumnType("smallint"); + + b.Property("ItemType") + .HasColumnType("integer"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MaximumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MinimumLevel") + .HasColumnType("smallint"); + + b.Property("MinimumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MoneyAmount") + .HasColumnType("integer"); + + b.Property("MonsterId") + .HasColumnType("uuid"); + + b.Property("RequiredCharacterLevel") + .HasColumnType("smallint"); + + b.Property("SourceItemLevel") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("MonsterId"); + + b.ToTable("ItemDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroupItemDefinition", b => + { + b.Property("ItemDropItemGroupId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemDropItemGroupId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("ItemDropItemGroupItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemItemOfItemSet", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ItemOfItemSetId") + .HasColumnType("uuid"); + + b.HasKey("ItemId", "ItemOfItemSetId"); + + b.HasIndex("ItemOfItemSetId"); + + b.ToTable("ItemItemOfItemSet", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemLevelBonusTable", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOfItemSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AncientSetDiscriminator") + .HasColumnType("integer"); + + b.Property("BonusOptionId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSetGroupId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BonusOptionId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("ItemSetGroupId"); + + b.ToTable("ItemOfItemSet", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OptionTypeId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("ItemOption", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AppliesMultipleTimes") + .HasColumnType("boolean"); + + b.Property("BonusId") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("BonusId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionCombinationBonus", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddChance") + .HasColumnType("real"); + + b.Property("AddsRandomly") + .HasColumnType("boolean"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MaximumOptionsPerItem") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ItemOptionId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.HasIndex("ItemOptionId"); + + b.ToTable("ItemOptionLink", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionOfLevel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IncreasableItemOptionId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("RequiredItemLevel") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IncreasableItemOptionId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("ItemOptionOfLevel", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("IsVisible") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AlwaysApplies") + .HasColumnType("boolean"); + + b.Property("CountDistinct") + .HasColumnType("boolean"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MinimumItemCount") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OptionsId") + .HasColumnType("uuid"); + + b.Property("SetLevel") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("OptionsId"); + + b.ToTable("ItemSetGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("RawItemSlots") + .HasColumnType("text") + .HasColumnName("ItemSlots") + .HasAnnotation("Relational:JsonPropertyName", "itemSlots"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemSlotType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Money") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ItemStorage", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.JewelMix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MixedJewelId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SingleJewelId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MixedJewelId"); + + b.HasIndex("SingleJewelId"); + + b.ToTable("JewelMix", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterBody", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Animation") + .HasColumnType("smallint"); + + b.Property("HeaderId") + .HasColumnType("uuid"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("Rotation") + .HasColumnType("smallint"); + + b.Property("SenderAppearanceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("HeaderId"); + + b.HasIndex("SenderAppearanceId") + .IsUnique(); + + b.ToTable("LetterBody", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("LetterDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ReadFlag") + .HasColumnType("boolean"); + + b.Property("ReceiverId") + .HasColumnType("uuid"); + + b.Property("SenderName") + .HasColumnType("text"); + + b.Property("Subject") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ReceiverId"); + + b.ToTable("LetterHeader", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LevelBonus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdditionalValue") + .HasColumnType("real"); + + b.Property("ItemLevelBonusTableId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemLevelBonusTableId"); + + b.ToTable("LevelBonus", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("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("MinimumSuccessPercent") + .HasColumnType("smallint"); + + b.Property("Money") + .HasColumnType("integer"); + + b.Property("MoneyPerFinalSuccessPercentage") + .HasColumnType("integer"); + + b.Property("MultipleAllowed") + .HasColumnType("boolean"); + + b.Property("NpcPriceDivisor") + .HasColumnType("integer"); + + b.Property("ResultItemExcellentOptionChance") + .HasColumnType("smallint"); + + b.Property("ResultItemLuckOptionChance") + .HasColumnType("smallint"); + + b.Property("ResultItemMaxExcOptionCount") + .HasColumnType("smallint"); + + b.Property("ResultItemSelect") + .HasColumnType("integer"); + + b.Property("ResultItemSkillChance") + .HasColumnType("smallint"); + + b.Property("SuccessPercent") + .HasColumnType("smallint"); + + b.Property("SuccessPercentageAdditionForAncientItem") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForExcellentItem") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForGuardianItem") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForLuck") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForSocketItem") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("SimpleCraftingSettings", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AreaSkillSettingsId") + .HasColumnType("uuid"); + + b.Property("AttackDamage") + .HasColumnType("integer"); + + b.Property("DamageType") + .HasColumnType("integer"); + + b.Property("ElementalModifierTargetId") + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("ImplicitTargetRange") + .HasColumnType("smallint"); + + b.Property("MagicEffectDefId") + .HasColumnType("uuid"); + + b.Property("MasterDefinitionId") + .HasColumnType("uuid"); + + b.Property("MovesTarget") + .HasColumnType("boolean"); + + b.Property("MovesToTarget") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("Range") + .HasColumnType("smallint"); + + b.Property("SkillType") + .HasColumnType("integer"); + + b.Property("Target") + .HasColumnType("integer"); + + b.Property("TargetRestriction") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AreaSkillSettingsId") + .IsUnique(); + + b.HasIndex("ElementalModifierTargetId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MagicEffectDefId"); + + b.HasIndex("MasterDefinitionId") + .IsUnique(); + + b.ToTable("Skill", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillCharacterClass", b => + { + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("SkillId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("SkillCharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumCompletionTime") + .HasColumnType("interval"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("SkillComboDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsFinalStep") + .HasColumnType("boolean"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("SkillComboDefinitionId") + .HasColumnType("uuid"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SkillComboDefinitionId"); + + b.HasIndex("SkillId"); + + b.ToTable("SkillComboStep", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterId"); + + b.HasIndex("SkillId"); + + b.ToTable("SkillEntry", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttribute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CharacterId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("StatAttribute", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttributeDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeId") + .HasColumnType("uuid"); + + b.Property("BaseValue") + .HasColumnType("real"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("IncreasableByPlayer") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("AttributeId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("StatAttributeDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SystemConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AutoStart") + .HasColumnType("boolean"); + + b.Property("AutoUpdateSchema") + .HasColumnType("boolean"); + + b.Property("IpResolver") + .HasColumnType("integer"); + + b.Property("IpResolverParameter") + .HasColumnType("text"); + + b.Property("ReadConsoleInput") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("SystemConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.WarpInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Costs") + .HasColumnType("integer"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("GateId") + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("LevelRequirement") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("GateId"); + + b.ToTable("WarpInfo", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawVault") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", "VaultId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawVault"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AccountCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", "Account") + .WithMany("JoinedUnlockedCharacterClasses") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("CharacterClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawCharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId"); + + b.Navigation("RawCharacterClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawAttributes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRelationship", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", null) + .WithMany("RawAttributeCombinations") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawInputAttribute") + .WithMany() + .HasForeignKey("InputAttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawOperandAttribute") + .WithMany() + .HasForeignKey("OperandAttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", null) + .WithMany("RawRelatedValues") + .HasForeignKey("PowerUpDefinitionValueId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.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.AreaSkillSettings", "RawAreaSkillSettings") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "AreaSkillSettingsId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawElementalModifierTarget") + .WithMany() + .HasForeignKey("ElementalModifierTargetId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawSkills") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "RawMagicEffectDef") + .WithMany() + .HasForeignKey("MagicEffectDefId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", "RawMasterDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "MasterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAreaSkillSettings"); + + b.Navigation("RawElementalModifierTarget"); + + b.Navigation("RawMagicEffectDef"); + + b.Navigation("RawMasterDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "Skill") + .WithMany("JoinedQualifiedCharacters") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CharacterClass"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboStep", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", null) + .WithMany("RawSteps") + .HasForeignKey("SkillComboDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillEntry", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawLearnedSkills") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttribute", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", null) + .WithMany("RawAttributes") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawAttributes") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.Navigation("RawDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttributeDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttribute") + .WithMany() + .HasForeignKey("AttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", null) + .WithMany("RawStatAttributes") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.WarpInfo", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawWarpList") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawGate") + .WithMany() + .HasForeignKey("GateId"); + + b.Navigation("RawGate"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.Navigation("JoinedUnlockedCharacterClasses"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawCharacters"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.Navigation("RawEquippedItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawLearnedSkills"); + + b.Navigation("RawLetters"); + + b.Navigation("RawQuestStates"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", b => + { + b.Navigation("RawAttributeCombinations"); + + b.Navigation("RawBaseAttributeValues"); + + b.Navigation("RawStatAttributes"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", b => + { + b.Navigation("RawRequirementStates"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerDefinition", b => + { + b.Navigation("RawEndpoints"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", b => + { + b.Navigation("JoinedPossibleItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DuelConfiguration", b => + { + b.Navigation("RawDuelAreas"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", b => + { + b.Navigation("RawAttributes"); + + b.Navigation("RawCharacterClasses"); + + b.Navigation("RawDropItemGroups"); + + b.Navigation("RawItemLevelBonusTables"); + + b.Navigation("RawItemOptionCombinationBonuses"); + + b.Navigation("RawItemOptionTypes"); + + b.Navigation("RawItemOptions"); + + b.Navigation("RawItemSetGroups"); + + b.Navigation("RawItemSlotTypes"); + + b.Navigation("RawItems"); + + b.Navigation("RawJewelMixes"); + + b.Navigation("RawMagicEffects"); + + b.Navigation("RawMaps"); + + b.Navigation("RawMasterSkillRoots"); + + b.Navigation("RawMiniGameDefinitions"); + + b.Navigation("RawMonsters"); + + b.Navigation("RawPlugInConfigurations"); + + b.Navigation("RawSkills"); + + b.Navigation("RawWarpList"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawCharacterPowerUpDefinitions"); + + b.Navigation("RawEnterGates"); + + b.Navigation("RawExitGates"); + + b.Navigation("RawMapRequirements"); + + b.Navigation("RawMonsterSpawns"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", b => + { + b.Navigation("JoinedMaps"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.Navigation("RawEndpoints"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.Navigation("RawMembers"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.Navigation("RawLevelDependentOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.Navigation("JoinedItemSetGroups"); + + b.Navigation("RawItemOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.Navigation("JoinedVisibleOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.Navigation("JoinedPossibleItems"); + + b.Navigation("JoinedRequiredItemOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.Navigation("JoinedPossibleItemOptions"); + + b.Navigation("JoinedPossibleItemSetGroups"); + + b.Navigation("JoinedQualifiedCharacters"); + + b.Navigation("RawBasePowerUpAttributes"); + + b.Navigation("RawDropItems"); + + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.Navigation("JoinedPossibleItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.Navigation("RawBonusPerLevel"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.Navigation("RawPossibleOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.Navigation("RawItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", b => + { + b.Navigation("RawItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.Navigation("RawPowerUpDefinitions"); + }); + + 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/20241204090233_UpdateSimpleCraftingSettings.cs b/src/Persistence/EntityFramework/Migrations/20241204090233_UpdateSimpleCraftingSettings.cs new file mode 100644 index 000000000..e74ca5eba --- /dev/null +++ b/src/Persistence/EntityFramework/Migrations/20241204090233_UpdateSimpleCraftingSettings.cs @@ -0,0 +1,44 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MUnique.OpenMU.Persistence.EntityFramework.Migrations +{ + /// + public partial class UpdateSimpleCraftingSettings : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "NpcPriceDivisor", + schema: "config", + table: "SimpleCraftingSettings", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "SuccessPercentageAdditionForGuardianItem", + schema: "config", + table: "SimpleCraftingSettings", + type: "integer", + nullable: false, + defaultValue: 0); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "NpcPriceDivisor", + schema: "config", + table: "SimpleCraftingSettings"); + + migrationBuilder.DropColumn( + name: "SuccessPercentageAdditionForGuardianItem", + schema: "config", + table: "SimpleCraftingSettings"); + } + } +} diff --git a/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs b/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs index 388ba7f9b..13a9d4de2 100644 --- a/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs +++ b/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("ProductVersion", "9.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -324,8 +324,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("AccountId") .HasColumnType("uuid"); - b.Property("CharacterClassId") - .IsRequired() + b.Property("CharacterClassId") .HasColumnType("uuid"); b.Property("CharacterSlot") @@ -2142,9 +2141,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("uuid"); - b.Property("CharacterId") - .HasColumnType("uuid"); - b.Property("LetterDate") .HasColumnType("timestamp with time zone"); @@ -3021,6 +3017,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("MaximumSuccessPercent") .HasColumnType("smallint"); + b.Property("MinimumSuccessPercent") + .HasColumnType("smallint"); + b.Property("Money") .HasColumnType("integer"); @@ -3030,6 +3029,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("MultipleAllowed") .HasColumnType("boolean"); + b.Property("NpcPriceDivisor") + .HasColumnType("integer"); + b.Property("ResultItemExcellentOptionChance") .HasColumnType("smallint"); @@ -3054,6 +3056,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("SuccessPercentageAdditionForExcellentItem") .HasColumnType("integer"); + b.Property("SuccessPercentageAdditionForGuardianItem") + .HasColumnType("integer"); + b.Property("SuccessPercentageAdditionForLuck") .HasColumnType("integer"); diff --git a/src/Persistence/Initialization/Updates/FixChaosMixesPlugIn095D.cs b/src/Persistence/Initialization/Updates/FixChaosMixesPlugIn095D.cs new file mode 100644 index 000000000..6a68376fb --- /dev/null +++ b/src/Persistence/Initialization/Updates/FixChaosMixesPlugIn095D.cs @@ -0,0 +1,68 @@ +// +// 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.DataModel.Configuration; +using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; +using MUnique.OpenMU.PlugIns; + +/// +/// This update fixes the Chaos Weapon, First Wings, Dinorant, and Item Level Upgrade craftings' settings. +/// +[PlugIn(PlugInName, PlugInDescription)] +[Guid("68BC1F35-FC9A-468F-89FB-0940485AC107")] +public class FixChaosMixesPlugIn095D : FixChaosMixesPlugInBase +{ + /// + /// The plug in description. + /// + private new const string PlugInDescription = "This update fixes the Chaos Weapon, First Wings, Dinorant, and Item Level Upgrade crafting settings."; + + /// + public override string Description => PlugInDescription; + + /// + public override string DataInitializationKey => Version095d.DataInitialization.Id; + + /// + public override UpdateVersion Version => UpdateVersion.FixChaosMixes095d; + + /// + protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) + { + await base.ApplyAsync(context, gameConfiguration).ConfigureAwait(false); + + var craftings = gameConfiguration.Monsters.First(m => m.NpcWindow == NpcWindow.ChaosMachine).ItemCraftings; + this.ApplyFirstWingsCraftingUpdate(craftings); + this.ApplyDinorantCraftingUpdate(craftings); + this.ApplyDinorantOptionsUpdate(gameConfiguration); + + // Item Level Upgrade craftings + int[] itemLevelUpgradeCraftingNos = [3, 4]; + + for (int i = 0; i < itemLevelUpgradeCraftingNos.Length; i++) + { + if (craftings.Single(c => c.Number == itemLevelUpgradeCraftingNos[i])?.SimpleCraftingSettings is { } craftingSettings) + { + craftingSettings.Money = 2_000_000 * (10 + i - 9); + craftingSettings.SuccessPercent = (byte)(10 + i == 10 ? 50 : 45); + craftingSettings.SuccessPercentageAdditionForLuck = 25; + craftingSettings.SuccessPercentageAdditionForExcellentItem = 0; + craftingSettings.SuccessPercentageAdditionForAncientItem = 0; + craftingSettings.SuccessPercentageAdditionForSocketItem = 0; + + foreach (var item in craftingSettings.RequiredItems) + { + item.FailResult = MixResult.Disappear; + if (item.MaximumAmount == 0) + { + item.MaximumAmount = item.MinimumAmount; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Updates/FixChaosMixesPlugInBase.cs b/src/Persistence/Initialization/Updates/FixChaosMixesPlugInBase.cs new file mode 100644 index 000000000..2e9ad1768 --- /dev/null +++ b/src/Persistence/Initialization/Updates/FixChaosMixesPlugInBase.cs @@ -0,0 +1,159 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.Updates; + +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; +using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic.PlayerActions.Craftings; + +/// +/// This update fixes the Chaos Weapon crafting settings. +/// +public abstract class FixChaosMixesPlugInBase : UpdatePlugInBase +{ + /// + /// The plug in name. + /// + internal const string PlugInName = "Fix Chaos Mixes Settings"; + + /// + /// The plug in description. + /// + internal const string PlugInDescription = "This update fixes Chaos Weapon crafting settings."; + + /// + public override string Name => PlugInName; + + /// + public override string Description => PlugInDescription; + + /// + public override bool IsMandatory => true; + + /// + public override DateTime CreatedAt => new(2024, 12, 10, 16, 0, 0, DateTimeKind.Utc); + + /// + protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) + { + // Misc item fixes + Guid crystalSwordId = new("00000080-0002-0005-0000-000000000000"); + if (gameConfiguration.Items.FirstOrDefault(id => id.GetId() == crystalSwordId) is { } crystalSword) + { + crystalSword.Width = 2; + } + + Guid powerWaveScrollId = new("00000080-000f-000a-0000-000000000000"); + if (gameConfiguration.Items.FirstOrDefault(id => id.GetId() == powerWaveScrollId) is { } powerWaveScroll) + { + powerWaveScroll.Value = 1100; + } + + // Fix Chaos Weapon crafting + var craftings = gameConfiguration.Monsters.First(m => m.NpcWindow == NpcWindow.ChaosMachine).ItemCraftings; + + if (craftings.Single(c => c.Number == 1) is { } chaosWeaponCrafting) + { + chaosWeaponCrafting.ItemCraftingHandlerClassName = typeof(ChaosWeaponAndFirstWingsCrafting).FullName!; + + if (chaosWeaponCrafting.SimpleCraftingSettings is { } settings) + { + settings.SuccessPercent = 0; + settings.NpcPriceDivisor = 20_000; + + foreach (var requiredItem in settings.RequiredItems) + { + requiredItem.AddPercentage = 0; + if (requiredItem.FailResult != MixResult.Disappear) + { + requiredItem.NpcPriceDivisor = 0; + requiredItem.FailResult = MixResult.ChaosWeaponAndFirstWingsDowngradedRandom; + } + } + + settings.ResultItemLuckOptionChance = 0; + settings.ResultItemSkillChance = 0; + + foreach (var resultItem in settings.ResultItems) + { + resultItem.RandomMinimumLevel = 0; + resultItem.RandomMaximumLevel = 4; + } + } + } + } + + /// + /// Applies First Wings crafting settings update. + /// + /// The craftings collection. + protected void ApplyFirstWingsCraftingUpdate(ICollection craftings) + { + if (craftings.Single(c => c.Number == 11) is { } firstWingsCrafting) + { + firstWingsCrafting.ItemCraftingHandlerClassName = typeof(ChaosWeaponAndFirstWingsCrafting).FullName!; + + if (firstWingsCrafting.SimpleCraftingSettings is { } settings) + { + settings.SuccessPercent = 0; + settings.NpcPriceDivisor = 20_000; + + foreach (var requiredItem in settings.RequiredItems) + { + requiredItem.AddPercentage = 0; + requiredItem.NpcPriceDivisor = 0; + if (requiredItem.MaximumAmount == 1) + { + // Chaos weapon + requiredItem.FailResult = MixResult.ChaosWeaponAndFirstWingsDowngradedRandom; + } + else + { + requiredItem.FailResult = MixResult.Disappear; + } + } + + settings.ResultItemLuckOptionChance = 0; + } + } + } + + /// + /// Applies Dinorant crafting settings update. + /// + /// The craftings collection. + protected void ApplyDinorantCraftingUpdate(ICollection craftings) + { + if (craftings.Single(c => c.Number == 5) is { } dinorantCrafting) + { + dinorantCrafting.ItemCraftingHandlerClassName = typeof(DinorantCrafting).FullName!; + + if (dinorantCrafting.SimpleCraftingSettings is { } settings) + { + settings.ResultItemExcellentOptionChance = 0; + } + } + } + + /// + /// Applies Dinorant options update. + /// + /// The game configuration. + protected void ApplyDinorantOptionsUpdate(GameConfiguration gameConfiguration) + { + if (gameConfiguration.ItemOptions.Single(iod => iod.Name == "Dinorant Options") is { } dinoOpts + && gameConfiguration.ItemOptionTypes.Single(iot => iot == ItemOptionTypes.Option) is { } itemOption) + { + dinoOpts.AddChance = 0.3f; + + foreach (var opt in dinoOpts.PossibleOptions) + { + opt.OptionType = itemOption; + opt.Number = 4; + } + } + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Updates/FixChaosMixesPlugInSeason6.cs b/src/Persistence/Initialization/Updates/FixChaosMixesPlugInSeason6.cs new file mode 100644 index 000000000..94c332152 --- /dev/null +++ b/src/Persistence/Initialization/Updates/FixChaosMixesPlugInSeason6.cs @@ -0,0 +1,422 @@ +// +// 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.DataModel.Attributes; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; +using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic.Attributes; +using MUnique.OpenMU.GameLogic.PlayerActions.Craftings; +using MUnique.OpenMU.Network; +using MUnique.OpenMU.Persistence.Initialization.Items; +using MUnique.OpenMU.PlugIns; + +/// +/// This update fixes the Chaos Weapon, First Wings, Dinorant, Item Level Upgrade, Second Wings, Third Wings, Cape, SD Potions, Guardian Option, and Secromicon crafting settings; Blue Fenrir (Protect) damage decrease option value; Wizard's Ring wizardry option; lvl 380 item guardian options for Summoner and Rage Fighter. +/// +[PlugIn(PlugInName, PlugInDescription)] +[Guid("EFD7EA69-56AE-48A3-ACE2-1C3B5B87780A")] +public class FixChaosMixesPlugInSeason6 : FixChaosMixesPlugInBase +{ + /// + /// The plug in name. + /// + private new const string PlugInName = "Fix Chaos Mixes Settings And Several Options"; + + /// + /// The plug in description. + /// + private new const string PlugInDescription = "This update fixes the Chaos Weapon, First Wings, Dinorant, Item Level Upgrade, Second Wings, Third Wings, Cape, SD Potions, Guardian Option, and Secromicon crafting settings; Blue Fenrir (Protect) damage decrease option value; Wizard's Ring wizardry option; lvl 380 item guardian options for Summoner and Rage Fighter."; + + /// + public override string Name => PlugInName; + + /// + public override string Description => PlugInDescription; + + /// + public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id; + + /// + public override UpdateVersion Version => UpdateVersion.FixChaosMixesSeason6; + + /// + protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) + { + // Dark horse spirit and raven spirit drop item groups id fix (do this first because it persists changes to DB) + if (gameConfiguration.Items.Single(id => id.Name == "Spirit") is { } spirit) + { + spirit.MaximumItemLevel = 1; + var maps = gameConfiguration.Maps; + if (gameConfiguration.DropItemGroups.Single(dig => dig.Description == "Dark Horse Spirit") is { } oldHorseGroup + && gameConfiguration.DropItemGroups.Single(dig => dig.Description == "Dark Raven Spirit") is { } oldRavenGroup) + { + DeleteDropItemGroup(oldHorseGroup); + DeleteDropItemGroup(oldRavenGroup); + CreateDropItemGroup(0, "Dark Horse Spirit", 102); + CreateDropItemGroup(1, "Dark Raven Spirit", 96); + } + + void DeleteDropItemGroup(DropItemGroup group) + { + group.PossibleItems.Clear(); + foreach (var map in maps) + { + if (map.DropItemGroups.FirstOrDefault(dig => dig.GetId() == group.GetId()) is { } mapDropItemGroup) + { + map.DropItemGroups.Remove(mapDropItemGroup); + } + } + + gameConfiguration.DropItemGroups.Remove(group); + context.DeleteAsync(group); + } + + void CreateDropItemGroup(int itemLevel, string description, short minimumMonsterLevel) + { + var group = context.CreateNew(); + group.SetGuid(NumberConversionExtensions.MakeWord(13, 31).ToSigned(), (short)itemLevel, 1); + group.ItemLevel = (byte)itemLevel; + group.Chance = 0.001; + group.Description = description; + group.PossibleItems.Add(spirit); + group.MinimumMonsterLevel = (byte)minimumMonsterLevel; + + gameConfiguration.DropItemGroups.Add(group); + foreach (var map in maps) + { + map.DropItemGroups.Add(group); + } + } + } + + await base.ApplyAsync(context, gameConfiguration).ConfigureAwait(false); + + var goblinCraftings = gameConfiguration.Monsters.Single(m => m.NpcWindow == NpcWindow.ChaosMachine).ItemCraftings; + var petTrainercraftings = gameConfiguration.Monsters.Single(m => m.NpcWindow == NpcWindow.PetTrainer).ItemCraftings; + this.ApplyFirstWingsCraftingUpdate(goblinCraftings); + this.ApplyDinorantCraftingUpdate(goblinCraftings); + this.ApplyDinorantOptionsUpdate(gameConfiguration); + + // Fenrir dmg decrease fix + Guid fenrirOptionsId = new("00000083-0081-0000-0000-000000000000"); + if (gameConfiguration.ItemOptions.Single(iod => iod.GetId() == fenrirOptionsId) is { } fenrirOpts + && fenrirOpts.PossibleOptions.Single(iio => iio.PowerUpDefinition?.TargetAttribute == Stats.DamageReceiveDecrement) is { } dmgDecreaseOpt + && dmgDecreaseOpt.PowerUpDefinition?.Boost is { } boost) + { + boost.ConstantValue.Value = 0.90f; + } + + // Wizard's Ring wizardry option fix + Guid wizardsRingId = new("00000080-000d-0014-0000-000000000000"); + if (gameConfiguration.Items.Single(id => id.GetId() == wizardsRingId) is { } wizardsRing) + { + wizardsRing.Durability = 30; + + if (wizardsRing.PossibleItemOptions.FirstOrDefault() is { } wizardsRingOpts) + { + wizardsRingOpts.MaximumOptionsPerItem = 3; + + var increaseWizardryDamage = context.CreateNew(); + increaseWizardryDamage.SetGuid(ItemOptionDefinitionNumbers.WizardRing, 3); + increaseWizardryDamage.PowerUpDefinition = context.CreateNew(); + increaseWizardryDamage.PowerUpDefinition.TargetAttribute = Stats.WizardryAttackDamageIncrease.GetPersistent(gameConfiguration); + increaseWizardryDamage.PowerUpDefinition.Boost = context.CreateNew(); + increaseWizardryDamage.PowerUpDefinition.Boost.ConstantValue.Value = 0.1f; + wizardsRingOpts.PossibleOptions.Add(increaseWizardryDamage); + } + } + + // Remove Raven's lvl requirement + Guid darkRavenId = new("00000080-000d-0005-0000-000000000000"); + if (gameConfiguration.Items.Single(id => id.GetId() == darkRavenId) is { } darkRaven) + { + darkRaven.Requirements.Clear(); + } + + // Aura/Storm Blitz Set definitions fix + for (int i = 7; i <= 11; i++) + { + if (gameConfiguration.Items.FirstOrDefault(id => id.Group == i && id.Number == 43) is { } auraItem) + { + if (gameConfiguration.ItemOptions.FirstOrDefault(io => io.PossibleOptions.Any(po => po.OptionType == ItemOptionTypes.GuardianOption && po.Number == i)) is { } guardOpt) + { + auraItem.PossibleItemOptions.Add(guardOpt); + } + + if (auraItem.Requirements.FirstOrDefault(r => r.Attribute == Stats.Level) is { } auraLvlRequirement) + { + auraLvlRequirement.MinimumValue = 380; + } + } + } + + // Phoenix Soul Set definitions fix + for (int i = 7; i <= 11; i++) + { + if (gameConfiguration.Items.FirstOrDefault(id => id.Group == i && id.Number == 73) is { } phoenixSoulItem) + { + if (gameConfiguration.ItemOptions.FirstOrDefault(io => io.PossibleOptions.Any(po => po.OptionType == ItemOptionTypes.GuardianOption && po.Number == i)) is { } guardOpt) + { + phoenixSoulItem.PossibleItemOptions.Add(guardOpt); + } + + if (phoenixSoulItem.Requirements.FirstOrDefault(r => r.Attribute == Stats.Level) is { } psLvlRequirement) + { + psLvlRequirement.MinimumValue = 380; + } + } + } + + // Phoenix Soul Star definition fix + Guid phoenixSoulStarId = new("00000080-0000-0023-0000-000000000000"); + if (gameConfiguration.Items.FirstOrDefault(id => id.GetId() == phoenixSoulStarId) is { } phoenixSoulStar) + { + if (gameConfiguration.ItemOptions.FirstOrDefault(io => io.PossibleOptions.Any(po => po.OptionType == ItemOptionTypes.GuardianOption && po.Number == (int)ItemGroups.Weapon)) is { } weapGuardOpt) + { + phoenixSoulStar.PossibleItemOptions.Add(weapGuardOpt); + } + + if (phoenixSoulStar.Requirements.FirstOrDefault(r => r.Attribute == Stats.Level) is { } pssLvlRequirement) + { + pssLvlRequirement.MinimumValue = 380; + } + } + + // ---> Fix chaos mixes settings + // Item Level Upgrade craftings + int[] itemLevelUpgradeCraftingNos = [3, 4, 22, 23, 49, 50]; + for (int i = 0; i < itemLevelUpgradeCraftingNos.Length; i++) + { + if (goblinCraftings.Single(c => c.Number == itemLevelUpgradeCraftingNos[i])?.SimpleCraftingSettings is { } craftingSettings) + { + craftingSettings.Money = 2_000_000 * (10 + i - 9); + craftingSettings.SuccessPercentageAdditionForLuck = 25; + craftingSettings.SuccessPercentageAdditionForAncientItem = -10; + craftingSettings.SuccessPercentageAdditionForGuardianItem = -10; + + foreach (var item in craftingSettings.RequiredItems) + { + item.FailResult = MixResult.Disappear; + if (item.MaximumAmount == 0) + { + item.MaximumAmount = item.MinimumAmount; + } + } + } + } + + // Second Wings crafting + if (goblinCraftings.Single(c => c.Number == 7) is { } secondWingsCrafting) + { + secondWingsCrafting.ItemCraftingHandlerClassName = typeof(SecondWingsCrafting).FullName!; + + if (secondWingsCrafting.SimpleCraftingSettings is { } settings) + { + settings.MoneyPerFinalSuccessPercentage = 0; + + foreach (var requiredItem in settings.RequiredItems) + { + if (requiredItem.FailResult != MixResult.Disappear) + { + // 1st level wings or exc item + requiredItem.FailResult = MixResult.Disappear; + } + else + { + // chaos or feather + requiredItem.AddPercentage = 0; + requiredItem.MaximumAmount = 1; + } + } + + settings.ResultItemLuckOptionChance = 20; + } + } + + // Thirds Wings, Stage 1 crafting + if (goblinCraftings.Single(c => c.Number == 38) is { } thirdWingsS1Crafting) + { + if (thirdWingsS1Crafting.SimpleCraftingSettings is { } settings) + { + settings.SuccessPercent = 1; + + foreach (var requiredItem in settings.RequiredItems) + { + if (requiredItem.FailResult != MixResult.Disappear) + { + // 2nd level wings or anc item + requiredItem.FailResult = MixResult.ThirdWingsDowngradedRandom; + if (requiredItem.MinimumItemLevel == 9) + { + // 2nd lvl wings + requiredItem.NpcPriceDivisor = 0; + } + } + } + } + } + + // Thirds Wings, Stage 2 crafting + if (goblinCraftings.Single(c => c.Number == 39) is { } thirdWingsS2Crafting) + { + thirdWingsS2Crafting.ItemCraftingHandlerClassName = typeof(ThirdWingsCrafting).FullName!; + + if (thirdWingsS2Crafting.SimpleCraftingSettings is { } settings) + { + settings.Money = 0; + settings.MoneyPerFinalSuccessPercentage = 200_000; + settings.SuccessPercent = 1; + + foreach (var requiredItem in settings.RequiredItems) + { + if (requiredItem.FailResult != MixResult.Disappear) + { + // exc item + requiredItem.MinimumAmount = 1; + requiredItem.FailResult = MixResult.ThirdWingsDowngradedRandom; + } + else + { + requiredItem.MaximumAmount = 1; + } + } + + settings.ResultItemLuckOptionChance = 5; + settings.ResultItemExcellentOptionChance = 0; + settings.ResultItemMaxExcOptionCount = 0; + } + } + + // Cape crafting + if (goblinCraftings.Single(c => c.Number == 24) is { } capeCrafting) + { + capeCrafting.ItemCraftingHandlerClassName = typeof(SecondWingsCrafting).FullName!; + + if (capeCrafting.SimpleCraftingSettings is { } settings) + { + settings.MoneyPerFinalSuccessPercentage = 0; + + foreach (var requiredItem in settings.RequiredItems) + { + if (requiredItem.FailResult != MixResult.Disappear) + { + // 1st level wings or exc item + requiredItem.FailResult = MixResult.Disappear; + + if (requiredItem.NpcPriceDivisor == 4_000_000) + { + // 1st level wings + requiredItem.MinimumItemLevel = 0; + } + } + else + { + // chaos or crest + requiredItem.AddPercentage = 0; + requiredItem.MaximumAmount = 1; + } + } + + settings.ResultItemLuckOptionChance = 20; + settings.ResultItemExcellentOptionChance = 20; + settings.ResultItemMaxExcOptionCount = 1; + } + } + + // Fruit crafting + if (goblinCraftings.Single(c => c.Number == 6) is { } fruitCrafting) + { + fruitCrafting.ItemCraftingHandlerClassName = typeof(SecondWingsCrafting).FullName!; + + if (fruitCrafting.SimpleCraftingSettings is { } settings) + { + settings.MoneyPerFinalSuccessPercentage = 0; + + foreach (var resultItem in settings.ResultItems) + { + resultItem.RandomMaximumLevel = 0; + } + } + } + + // Small, Medium, and Large Shield Potion craftings + for (int i = 30; i <= 32; i++) + { + if (goblinCraftings.Single(c => c.Number == i) is { } smallShieldPotCrafting) + { + if (smallShieldPotCrafting.SimpleCraftingSettings is { } settings) + { + foreach (var resultItem in settings.ResultItems) + { + resultItem.Durability = 1; + } + } + } + } + + // Guardian Option crafting + if (goblinCraftings.Single(c => c.Number == 36) is { } guardianOptionCrafting) + { + if (guardianOptionCrafting.SimpleCraftingSettings is { } settings) + { + foreach (var requiredItem in settings.RequiredItems.OrderBy(i => i.MinimumItemLevel)) + { + if (requiredItem.MinimumItemLevel < 10) + { + continue; + } + else if (requiredItem.MinimumItemLevel == 10) + { + requiredItem.MaximumItemLevel = 15; + } + else + { + settings.RequiredItems.Remove(requiredItem); + break; + } + } + } + } + + // Secromicon crafting + if (goblinCraftings.Single(c => c.Number == 46) is { } secromiconCrafting) + { + if (secromiconCrafting.SimpleCraftingSettings is { } settings) + { + settings.Money = 1_000_000; + } + } + + // Dark Horse crafting + if (petTrainercraftings.Single(c => c.Number == 13) is { } darkHorseCrafting) + { + if (darkHorseCrafting.SimpleCraftingSettings is { } settings) + { + if (settings.ResultItems.First() is { } darkHorseResult) + { + darkHorseResult.RandomMinimumLevel = 1; + darkHorseResult.RandomMaximumLevel = 1; + } + } + } + + // Dark Raven crafting + if (petTrainercraftings.Single(c => c.Number == 14) is { } darkRavenCrafting) + { + if (darkRavenCrafting.SimpleCraftingSettings is { } settings) + { + settings.ResultItemSkillChance = 0; + if (settings.ResultItems.First() is { } darkRavenResult) + { + darkRavenResult.RandomMinimumLevel = 1; + darkRavenResult.RandomMaximumLevel = 1; + } + } + } + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Updates/FixChaosMixesUpdatePlugIn075.cs b/src/Persistence/Initialization/Updates/FixChaosMixesUpdatePlugIn075.cs new file mode 100644 index 000000000..635d03483 --- /dev/null +++ b/src/Persistence/Initialization/Updates/FixChaosMixesUpdatePlugIn075.cs @@ -0,0 +1,22 @@ +// +// 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.PlugIns; + +/// +/// This update fixes the Chaos Weapon crafting settings. +/// +[PlugIn(PlugInName, PlugInDescription)] +[Guid("04A5F236-117F-422A-8C38-28D09DE911D7")] +public class FixChaosMixesUpdatePlugIn075 : FixChaosMixesPlugInBase +{ + /// + public override string DataInitializationKey => Version075.DataInitialization.Id; + + /// + public override UpdateVersion Version => UpdateVersion.FixChaosMixes075; +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Updates/UpdateVersion.cs b/src/Persistence/Initialization/Updates/UpdateVersion.cs index 2f5465e1a..d2fde1411 100644 --- a/src/Persistence/Initialization/Updates/UpdateVersion.cs +++ b/src/Persistence/Initialization/Updates/UpdateVersion.cs @@ -219,4 +219,19 @@ public enum UpdateVersion /// The version of the . /// FixWeaponRisePercentageSeason6 = 42, + + /// + /// The version of the . + /// + FixChaosMixes075 = 43, + + /// + /// The version of the . + /// + FixChaosMixes095d = 44, + + /// + /// The version of the . + /// + FixChaosMixesSeason6 = 45, } \ No newline at end of file diff --git a/src/Persistence/Initialization/Version075/ChaosMixes.cs b/src/Persistence/Initialization/Version075/ChaosMixes.cs index 88e37ea36..d0da2fb66 100644 --- a/src/Persistence/Initialization/Version075/ChaosMixes.cs +++ b/src/Persistence/Initialization/Version075/ChaosMixes.cs @@ -7,6 +7,7 @@ namespace MUnique.OpenMU.Persistence.Initialization.Version075; using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic.PlayerActions.Craftings; using MUnique.OpenMU.Persistence.Initialization.Version075.Items; /// @@ -36,26 +37,24 @@ private ItemCrafting ChaosWeaponCrafting() var chaosWeapon = this.Context.CreateNew(); chaosWeapon.Name = "Chaos Weapon"; chaosWeapon.Number = 1; + chaosWeapon.ItemCraftingHandlerClassName = typeof(ChaosWeaponAndFirstWingsCrafting).FullName!; var chaosWeaponSettings = this.Context.CreateNew(); - chaosWeapon.SimpleCraftingSettings = chaosWeaponSettings; - chaosWeaponSettings.MoneyPerFinalSuccessPercentage = 10000; - chaosWeaponSettings.SuccessPercent = 1; + chaosWeaponSettings.MoneyPerFinalSuccessPercentage = 10_000; + chaosWeaponSettings.NpcPriceDivisor = 20_000; // Requirements: var randomItem = this.Context.CreateNew(); randomItem.MinimumAmount = 1; randomItem.MinimumItemLevel = 4; randomItem.MaximumItemLevel = Constants.MaximumItemLevel; - randomItem.NpcPriceDivisor = 15000; - randomItem.FailResult = MixResult.DowngradedRandom; + randomItem.FailResult = MixResult.ChaosWeaponAndFirstWingsDowngradedRandom; randomItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); randomItem.SuccessResult = MixResult.Disappear; chaosWeaponSettings.RequiredItems.Add(randomItem); var chaos = this.Context.CreateNew(); chaos.MinimumAmount = 1; - chaos.AddPercentage = 2; chaos.SuccessResult = MixResult.Disappear; chaos.FailResult = MixResult.Disappear; chaos.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Chaos")); @@ -63,7 +62,6 @@ private ItemCrafting ChaosWeaponCrafting() var bless = this.Context.CreateNew(); bless.MinimumAmount = 0; - bless.AddPercentage = 5; bless.SuccessResult = MixResult.Disappear; bless.FailResult = MixResult.Disappear; bless.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Bless")); @@ -71,7 +69,6 @@ private ItemCrafting ChaosWeaponCrafting() var soul = this.Context.CreateNew(); soul.MinimumAmount = 0; - soul.AddPercentage = 4; soul.SuccessResult = MixResult.Disappear; soul.FailResult = MixResult.Disappear; soul.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Soul")); @@ -79,19 +76,23 @@ private ItemCrafting ChaosWeaponCrafting() // Result: chaosWeaponSettings.ResultItemSelect = ResultItemSelection.Any; - chaosWeaponSettings.ResultItemLuckOptionChance = 10; - chaosWeaponSettings.ResultItemSkillChance = 30; var chaosDragonAxe = this.Context.CreateNew(); chaosDragonAxe.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Chaos Dragon Axe"); + chaosDragonAxe.RandomMinimumLevel = 0; + chaosDragonAxe.RandomMaximumLevel = 4; chaosWeaponSettings.ResultItems.Add(chaosDragonAxe); var chaosNatureBow = this.Context.CreateNew(); chaosNatureBow.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Chaos Nature Bow"); + chaosNatureBow.RandomMinimumLevel = 0; + chaosNatureBow.RandomMaximumLevel = 4; chaosWeaponSettings.ResultItems.Add(chaosNatureBow); var chaosLightningStaff = this.Context.CreateNew(); chaosLightningStaff.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Chaos Lightning Staff"); + chaosLightningStaff.RandomMinimumLevel = 0; + chaosLightningStaff.RandomMaximumLevel = 4; chaosWeaponSettings.ResultItems.Add(chaosLightningStaff); return chaosWeapon; diff --git a/src/Persistence/Initialization/Version075/Items/Scrolls.cs b/src/Persistence/Initialization/Version075/Items/Scrolls.cs index dbbcedc8b..290b78657 100644 --- a/src/Persistence/Initialization/Version075/Items/Scrolls.cs +++ b/src/Persistence/Initialization/Version075/Items/Scrolls.cs @@ -40,7 +40,7 @@ public override void Initialize() this.CreateScroll(7, 8, "Scroll of Twister", 40, 0, 180, 25000); this.CreateScroll(8, 9, "Scroll of Evil Spirit", 50, 0, 220, 35000); this.CreateScroll(9, 10, "Scroll of Hellfire", 60, 0, 260, 60000); - this.CreateScroll(10, 11, "Scroll of Power Wave", 9, 0, 56, 1150); + this.CreateScroll(10, 11, "Scroll of Power Wave", 9, 0, 56, 1100); this.CreateScroll(11, 12, "Scroll of Aqua Beam", 74, 0, 345, 100000); } diff --git a/src/Persistence/Initialization/Version075/Items/Weapons.cs b/src/Persistence/Initialization/Version075/Items/Weapons.cs index bd52cee0f..3c07ae359 100644 --- a/src/Persistence/Initialization/Version075/Items/Weapons.cs +++ b/src/Persistence/Initialization/Version075/Items/Weapons.cs @@ -118,7 +118,7 @@ public override void Initialize() this.CreateWeapon(2, 2, 0, 0, 1, 3, true, "Flail", 22, 22, 32, 15, 32, 0, 0, 80, 50, 0, 0, 0, 1, 0); this.CreateWeapon(2, 3, 0, 19, 2, 3, true, "Great Hammer", 38, 45, 56, 15, 50, 0, 0, 150, 0, 0, 0, 0, 1, 0); this.CreateWeapon(2, 4, 0, 19, 2, 3, true, "Crystal Morning Star", 66, 78, 107, 30, 72, 0, 0, 130, 0, 0, 0, 1, 1, 1); - this.CreateWeapon(2, 5, 0, 23, 1, 4, true, "Crystal Sword", 72, 89, 120, 40, 76, 0, 0, 130, 70, 0, 0, 1, 1, 1); + this.CreateWeapon(2, 5, 0, 23, 2, 4, true, "Crystal Sword", 72, 89, 120, 40, 76, 0, 0, 130, 70, 0, 0, 1, 1, 1); this.CreateWeapon(2, 6, 0, 23, 2, 4, false, "Chaos Dragon Axe", 75, 102, 130, 35, 80, 0, 0, 140, 50, 0, 0, 0, 1, 0); this.CreateWeapon(3, 0, 0, 22, 2, 4, true, "Light Spear", 42, 50, 63, 25, 56, 0, 0, 60, 70, 0, 0, 0, 1, 1); diff --git a/src/Persistence/Initialization/Version095d/ChaosMixes.cs b/src/Persistence/Initialization/Version095d/ChaosMixes.cs index 15a2f3d8f..5f59123d6 100644 --- a/src/Persistence/Initialization/Version095d/ChaosMixes.cs +++ b/src/Persistence/Initialization/Version095d/ChaosMixes.cs @@ -7,6 +7,8 @@ namespace MUnique.OpenMU.Persistence.Initialization.Version095d; using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.DataModel.Configuration.ItemCrafting; using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic.PlayerActions.Craftings; +using MUnique.OpenMU.Persistence.Initialization.Version095d.Items; /// /// Initializer for chaos mixes. @@ -36,14 +38,14 @@ public override void Initialize() chaosGoblin.ItemCraftings.Add(this.ChaosWeaponCrafting()); chaosGoblin.ItemCraftings.Add(this.DinorantCrafting()); - chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(3, 10, 1_000_000)); - chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(4, 11, 2_000_000)); + chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(3, 10)); + chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(4, 11)); chaosGoblin.ItemCraftings.Add(this.FirstWingsCrafting()); chaosGoblin.ItemCraftings.Add(this.DevilSquareTicketCrafting()); } - private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLevel, int money) + private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLevel) { var crafting = this.Context.CreateNew(); crafting.Name = $"+{targetLevel} Item Combination"; @@ -51,11 +53,9 @@ private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLe var craftingSettings = this.Context.CreateNew(); crafting.SimpleCraftingSettings = craftingSettings; - craftingSettings.Money = money; - craftingSettings.SuccessPercent = (byte)(60 - (((targetLevel - 10) / 2) * 5)); - craftingSettings.SuccessPercentageAdditionForExcellentItem = -10; - craftingSettings.SuccessPercentageAdditionForAncientItem = -15; - craftingSettings.SuccessPercentageAdditionForSocketItem = -20; + craftingSettings.Money = 2_000_000 * (targetLevel - 9); + craftingSettings.SuccessPercent = (byte)(targetLevel == 10 ? 50 : 45); + craftingSettings.SuccessPercentageAdditionForLuck = 25; // Requirements: var item = this.Context.CreateNew(); @@ -64,12 +64,13 @@ private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLe item.MaximumAmount = 1; item.MinimumItemLevel = (byte)(targetLevel - 1); item.MaximumItemLevel = item.MinimumItemLevel; - item.FailResult = MixResult.DowngradedTo0; + item.FailResult = MixResult.Disappear; item.SuccessResult = MixResult.StaysAsIs; craftingSettings.RequiredItems.Add(item); var chaos = this.Context.CreateNew(); chaos.MinimumAmount = 1; + chaos.MaximumAmount = 1; chaos.SuccessResult = MixResult.Disappear; chaos.FailResult = MixResult.Disappear; chaos.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Chaos")); @@ -77,6 +78,7 @@ private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLe var bless = this.Context.CreateNew(); bless.MinimumAmount = (byte)(targetLevel - 9); + bless.MaximumAmount = bless.MinimumAmount; bless.SuccessResult = MixResult.Disappear; bless.FailResult = MixResult.Disappear; bless.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Bless")); @@ -84,6 +86,7 @@ private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLe var soul = this.Context.CreateNew(); soul.MinimumAmount = (byte)(targetLevel - 9); + soul.MaximumAmount = soul.MinimumAmount; soul.SuccessResult = MixResult.Disappear; soul.FailResult = MixResult.Disappear; soul.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Soul")); @@ -102,26 +105,24 @@ private ItemCrafting ChaosWeaponCrafting() var chaosWeapon = this.Context.CreateNew(); chaosWeapon.Name = "Chaos Weapon"; chaosWeapon.Number = 1; + chaosWeapon.ItemCraftingHandlerClassName = typeof(ChaosWeaponAndFirstWingsCrafting).FullName!; var chaosWeaponSettings = this.Context.CreateNew(); - chaosWeapon.SimpleCraftingSettings = chaosWeaponSettings; - chaosWeaponSettings.MoneyPerFinalSuccessPercentage = 10000; - chaosWeaponSettings.SuccessPercent = 1; + chaosWeaponSettings.MoneyPerFinalSuccessPercentage = 10_000; + chaosWeaponSettings.NpcPriceDivisor = 20_000; // Requirements: var randomItem = this.Context.CreateNew(); randomItem.MinimumAmount = 1; randomItem.MinimumItemLevel = 4; - randomItem.MaximumItemLevel = 15; - randomItem.NpcPriceDivisor = 15000; - randomItem.FailResult = MixResult.DowngradedRandom; + randomItem.MaximumItemLevel = Constants.MaximumItemLevel; + randomItem.FailResult = MixResult.ChaosWeaponAndFirstWingsDowngradedRandom; randomItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); randomItem.SuccessResult = MixResult.Disappear; chaosWeaponSettings.RequiredItems.Add(randomItem); var chaos = this.Context.CreateNew(); chaos.MinimumAmount = 1; - chaos.AddPercentage = 2; chaos.SuccessResult = MixResult.Disappear; chaos.FailResult = MixResult.Disappear; chaos.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Chaos")); @@ -129,7 +130,6 @@ private ItemCrafting ChaosWeaponCrafting() var bless = this.Context.CreateNew(); bless.MinimumAmount = 0; - bless.AddPercentage = 5; bless.SuccessResult = MixResult.Disappear; bless.FailResult = MixResult.Disappear; bless.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Bless")); @@ -137,7 +137,6 @@ private ItemCrafting ChaosWeaponCrafting() var soul = this.Context.CreateNew(); soul.MinimumAmount = 0; - soul.AddPercentage = 4; soul.SuccessResult = MixResult.Disappear; soul.FailResult = MixResult.Disappear; soul.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Soul")); @@ -145,19 +144,23 @@ private ItemCrafting ChaosWeaponCrafting() // Result: chaosWeaponSettings.ResultItemSelect = ResultItemSelection.Any; - chaosWeaponSettings.ResultItemLuckOptionChance = 10; - chaosWeaponSettings.ResultItemSkillChance = 30; var chaosDragonAxe = this.Context.CreateNew(); chaosDragonAxe.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Chaos Dragon Axe"); + chaosDragonAxe.RandomMinimumLevel = 0; + chaosDragonAxe.RandomMaximumLevel = 4; chaosWeaponSettings.ResultItems.Add(chaosDragonAxe); var chaosNatureBow = this.Context.CreateNew(); chaosNatureBow.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Chaos Nature Bow"); + chaosNatureBow.RandomMinimumLevel = 0; + chaosNatureBow.RandomMaximumLevel = 4; chaosWeaponSettings.ResultItems.Add(chaosNatureBow); var chaosLightningStaff = this.Context.CreateNew(); chaosLightningStaff.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Chaos Lightning Staff"); + chaosLightningStaff.RandomMinimumLevel = 0; + chaosLightningStaff.RandomMaximumLevel = 4; chaosWeaponSettings.ResultItems.Add(chaosLightningStaff); return chaosWeapon; @@ -168,11 +171,11 @@ private ItemCrafting FirstWingsCrafting() var crafting = this.Context.CreateNew(); crafting.Name = "1st Level Wings"; crafting.Number = 11; + crafting.ItemCraftingHandlerClassName = typeof(ChaosWeaponAndFirstWingsCrafting).FullName!; var craftingSettings = this.Context.CreateNew(); - crafting.SimpleCraftingSettings = craftingSettings; - craftingSettings.MoneyPerFinalSuccessPercentage = 10000; - craftingSettings.SuccessPercent = 1; + craftingSettings.MoneyPerFinalSuccessPercentage = 10_000; + craftingSettings.NpcPriceDivisor = 20_000; // Requirements: var chaosWeapon = this.Context.CreateNew(); @@ -182,9 +185,8 @@ private ItemCrafting FirstWingsCrafting() chaosWeapon.MinimumAmount = 1; chaosWeapon.MaximumAmount = 1; chaosWeapon.MinimumItemLevel = 4; - chaosWeapon.MaximumItemLevel = 15; - chaosWeapon.NpcPriceDivisor = 15000; - chaosWeapon.FailResult = MixResult.DowngradedRandom; + chaosWeapon.MaximumItemLevel = Constants.MaximumItemLevel; + chaosWeapon.FailResult = MixResult.ChaosWeaponAndFirstWingsDowngradedRandom; chaosWeapon.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); chaosWeapon.SuccessResult = MixResult.Disappear; craftingSettings.RequiredItems.Add(chaosWeapon); @@ -192,16 +194,14 @@ private ItemCrafting FirstWingsCrafting() var randomItem = this.Context.CreateNew(); randomItem.MinimumAmount = 0; randomItem.MinimumItemLevel = 4; - randomItem.MaximumItemLevel = 15; - randomItem.NpcPriceDivisor = 15000; - randomItem.FailResult = MixResult.DowngradedRandom; + randomItem.MaximumItemLevel = Constants.MaximumItemLevel; + randomItem.FailResult = MixResult.Disappear; randomItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); randomItem.SuccessResult = MixResult.Disappear; craftingSettings.RequiredItems.Add(randomItem); var chaos = this.Context.CreateNew(); chaos.MinimumAmount = 1; - chaos.AddPercentage = 2; chaos.SuccessResult = MixResult.Disappear; chaos.FailResult = MixResult.Disappear; chaos.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Chaos")); @@ -209,7 +209,6 @@ private ItemCrafting FirstWingsCrafting() var bless = this.Context.CreateNew(); bless.MinimumAmount = 0; - bless.AddPercentage = 5; bless.SuccessResult = MixResult.Disappear; bless.FailResult = MixResult.Disappear; bless.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Bless")); @@ -217,7 +216,6 @@ private ItemCrafting FirstWingsCrafting() var soul = this.Context.CreateNew(); soul.MinimumAmount = 0; - soul.AddPercentage = 4; soul.SuccessResult = MixResult.Disappear; soul.FailResult = MixResult.Disappear; soul.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Soul")); @@ -225,7 +223,6 @@ private ItemCrafting FirstWingsCrafting() // Result: craftingSettings.ResultItemSelect = ResultItemSelection.Any; - craftingSettings.ResultItemLuckOptionChance = 10; var fairyWings = this.Context.CreateNew(); fairyWings.ItemDefinition = this.GameConfiguration.Items.First(i => i.Group == 12 && i.Number == 0); @@ -247,13 +244,11 @@ private ItemCrafting DinorantCrafting() var crafting = this.Context.CreateNew(); crafting.Name = "Dinorant"; crafting.Number = 5; + crafting.ItemCraftingHandlerClassName = typeof(DinorantCrafting).FullName!; var craftingSettings = this.Context.CreateNew(); - crafting.SimpleCraftingSettings = craftingSettings; craftingSettings.Money = 500_000; craftingSettings.SuccessPercent = 70; - craftingSettings.ResultItemExcellentOptionChance = 10; - craftingSettings.ResultItemSkillChance = 100; // Requirements: var chaos = this.Context.CreateNew(); @@ -273,6 +268,8 @@ private ItemCrafting DinorantCrafting() craftingSettings.RequiredItems.Add(horn); // Result: + craftingSettings.ResultItemSkillChance = 100; + var dinorant = this.Context.CreateNew(); dinorant.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Horn of Dinorant"); craftingSettings.ResultItems.Add(dinorant); diff --git a/src/Persistence/Initialization/Version095d/Items/Pets.cs b/src/Persistence/Initialization/Version095d/Items/Pets.cs index 965e272c1..fd7e7143c 100644 --- a/src/Persistence/Initialization/Version095d/Items/Pets.cs +++ b/src/Persistence/Initialization/Version095d/Items/Pets.cs @@ -82,13 +82,13 @@ private void AddDinorantOptions(ItemDefinition dinorant) this.GameConfiguration.ItemOptions.Add(dinoOptionDefinition); dinoOptionDefinition.Name = "Dinorant Options"; - dinoOptionDefinition.AddChance = 0.1f; + dinoOptionDefinition.AddChance = 0.3f; dinoOptionDefinition.AddsRandomly = true; - dinoOptionDefinition.MaximumOptionsPerItem = 1; + dinoOptionDefinition.MaximumOptionsPerItem = 1; // There is second rollout for an additional bonus option to the first - dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Excellent, 1, Stats.DamageReceiveDecrement, 0.95f, AggregateType.Multiplicate)); - dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Excellent, 2, Stats.MaximumAbility, 50f, AggregateType.AddFinal)); - dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Excellent, 4, Stats.AttackSpeed, 5f, AggregateType.AddFinal)); + dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Option, 4, Stats.DamageReceiveDecrement, 0.95f, AggregateType.Multiplicate)); + dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Option, 4, Stats.MaximumAbility, 50f, AggregateType.AddFinal)); + dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Option, 4, Stats.AttackSpeed, 5f, AggregateType.AddFinal)); dinorant.PossibleItemOptions.Add(dinoOptionDefinition); } diff --git a/src/Persistence/Initialization/Version095d/Items/Weapons.cs b/src/Persistence/Initialization/Version095d/Items/Weapons.cs index 27dbe137a..6d79c1376 100644 --- a/src/Persistence/Initialization/Version095d/Items/Weapons.cs +++ b/src/Persistence/Initialization/Version095d/Items/Weapons.cs @@ -121,7 +121,7 @@ public override void Initialize() this.CreateWeapon(2, 2, 0, 0, 1, 3, true, "Flail", 22, 22, 32, 15, 32, 0, 0, 80, 50, 0, 0, 0, 1, 0); this.CreateWeapon(2, 3, 0, 19, 2, 3, true, "Great Hammer", 38, 45, 56, 15, 50, 0, 0, 150, 0, 0, 0, 0, 1, 0); this.CreateWeapon(2, 4, 0, 19, 2, 3, true, "Crystal Morning Star", 66, 78, 107, 30, 72, 0, 0, 130, 0, 0, 0, 1, 1, 1); - this.CreateWeapon(2, 5, 0, 23, 1, 4, true, "Crystal Sword", 72, 89, 120, 40, 76, 0, 0, 130, 70, 0, 0, 1, 1, 1); + this.CreateWeapon(2, 5, 0, 23, 2, 4, true, "Crystal Sword", 72, 89, 120, 40, 76, 0, 0, 130, 70, 0, 0, 1, 1, 1); this.CreateWeapon(2, 6, 0, 23, 2, 4, false, "Chaos Dragon Axe", 75, 102, 130, 35, 80, 0, 0, 140, 50, 0, 0, 0, 1, 0); this.CreateWeapon(3, 0, 0, 22, 2, 4, true, "Light Spear", 42, 50, 63, 25, 56, 0, 0, 60, 70, 0, 0, 0, 1, 1); diff --git a/src/Persistence/Initialization/VersionSeasonSix/ChaosMixes.cs b/src/Persistence/Initialization/VersionSeasonSix/ChaosMixes.cs index acaff99be..0910394c2 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/ChaosMixes.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/ChaosMixes.cs @@ -40,12 +40,12 @@ public override void Initialize() chaosGoblin.ItemCraftings.Add(this.DinorantCrafting()); chaosGoblin.ItemCraftings.Add(this.PotionOfBlessCrafting()); chaosGoblin.ItemCraftings.Add(this.PotionOfSoulCrafting()); - chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(3, 10, 1_000_000)); - chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(4, 11, 2_000_000)); - chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(22, 12, 4_000_000)); - chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(23, 13, 8_000_000)); - chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(49, 14, 10_000_000)); - chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(50, 15, 12_000_000)); + chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(3, 10)); + chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(4, 11)); + chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(22, 12)); + chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(23, 13)); + chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(49, 14)); + chaosGoblin.ItemCraftings.Add(this.ItemLevelUpgradeCrafting(50, 15)); chaosGoblin.ItemCraftings.Add(this.BloodCastleTicketCrafting()); chaosGoblin.ItemCraftings.Add(this.DevilSquareTicketCrafting()); chaosGoblin.ItemCraftings.Add(this.IllusionTempleTicketCrafting()); @@ -82,7 +82,7 @@ public override void Initialize() cherryBlossomSpirit.ItemCraftings.Add(this.CherryBlossomEventCrafting()); } - private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLevel, int money) + private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLevel) { var crafting = this.Context.CreateNew(); crafting.Name = $"+{targetLevel} Item Combination"; @@ -90,10 +90,12 @@ private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLe var craftingSettings = this.Context.CreateNew(); crafting.SimpleCraftingSettings = craftingSettings; - craftingSettings.Money = money; + craftingSettings.Money = 2_000_000 * (targetLevel - 9); craftingSettings.SuccessPercent = (byte)(60 - ((targetLevel - 10) / 2 * 5)); + craftingSettings.SuccessPercentageAdditionForLuck = 25; craftingSettings.SuccessPercentageAdditionForExcellentItem = -10; - craftingSettings.SuccessPercentageAdditionForAncientItem = -15; + craftingSettings.SuccessPercentageAdditionForAncientItem = -10; + craftingSettings.SuccessPercentageAdditionForGuardianItem = -10; craftingSettings.SuccessPercentageAdditionForSocketItem = -20; // Requirements: @@ -103,12 +105,13 @@ private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLe item.MaximumAmount = 1; item.MinimumItemLevel = (byte)(targetLevel - 1); item.MaximumItemLevel = item.MinimumItemLevel; - item.FailResult = MixResult.DowngradedTo0; + item.FailResult = MixResult.Disappear; item.SuccessResult = MixResult.StaysAsIs; craftingSettings.RequiredItems.Add(item); var chaos = this.Context.CreateNew(); chaos.MinimumAmount = 1; + chaos.MaximumAmount = 1; chaos.SuccessResult = MixResult.Disappear; chaos.FailResult = MixResult.Disappear; chaos.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Chaos")); @@ -116,6 +119,7 @@ private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLe var bless = this.Context.CreateNew(); bless.MinimumAmount = (byte)(targetLevel - 9); + bless.MaximumAmount = bless.MinimumAmount; bless.SuccessResult = MixResult.Disappear; bless.FailResult = MixResult.Disappear; bless.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Bless")); @@ -123,6 +127,7 @@ private ItemCrafting ItemLevelUpgradeCrafting(byte craftingNumber, byte targetLe var soul = this.Context.CreateNew(); soul.MinimumAmount = (byte)(targetLevel - 9); + soul.MaximumAmount = soul.MinimumAmount; soul.SuccessResult = MixResult.Disappear; soul.FailResult = MixResult.Disappear; soul.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Soul")); @@ -141,26 +146,24 @@ private ItemCrafting ChaosWeaponCrafting() var chaosWeapon = this.Context.CreateNew(); chaosWeapon.Name = "Chaos Weapon"; chaosWeapon.Number = 1; + chaosWeapon.ItemCraftingHandlerClassName = typeof(ChaosWeaponAndFirstWingsCrafting).FullName!; var chaosWeaponSettings = this.Context.CreateNew(); - chaosWeapon.SimpleCraftingSettings = chaosWeaponSettings; - chaosWeaponSettings.MoneyPerFinalSuccessPercentage = 10000; - chaosWeaponSettings.SuccessPercent = 1; + chaosWeaponSettings.MoneyPerFinalSuccessPercentage = 10_000; + chaosWeaponSettings.NpcPriceDivisor = 20_000; // Requirements: var randomItem = this.Context.CreateNew(); randomItem.MinimumAmount = 1; randomItem.MinimumItemLevel = 4; randomItem.MaximumItemLevel = 15; - randomItem.NpcPriceDivisor = 15000; - randomItem.FailResult = MixResult.DowngradedRandom; + randomItem.FailResult = MixResult.ChaosWeaponAndFirstWingsDowngradedRandom; randomItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); randomItem.SuccessResult = MixResult.Disappear; chaosWeaponSettings.RequiredItems.Add(randomItem); var chaos = this.Context.CreateNew(); chaos.MinimumAmount = 1; - chaos.AddPercentage = 2; chaos.SuccessResult = MixResult.Disappear; chaos.FailResult = MixResult.Disappear; chaos.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Chaos")); @@ -168,7 +171,6 @@ private ItemCrafting ChaosWeaponCrafting() var bless = this.Context.CreateNew(); bless.MinimumAmount = 0; - bless.AddPercentage = 5; bless.SuccessResult = MixResult.Disappear; bless.FailResult = MixResult.Disappear; bless.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Bless")); @@ -176,7 +178,6 @@ private ItemCrafting ChaosWeaponCrafting() var soul = this.Context.CreateNew(); soul.MinimumAmount = 0; - soul.AddPercentage = 4; soul.SuccessResult = MixResult.Disappear; soul.FailResult = MixResult.Disappear; soul.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Soul")); @@ -184,19 +185,23 @@ private ItemCrafting ChaosWeaponCrafting() // Result: chaosWeaponSettings.ResultItemSelect = ResultItemSelection.Any; - chaosWeaponSettings.ResultItemLuckOptionChance = 10; - chaosWeaponSettings.ResultItemSkillChance = 30; var chaosDragonAxe = this.Context.CreateNew(); chaosDragonAxe.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Chaos Dragon Axe"); + chaosDragonAxe.RandomMinimumLevel = 0; + chaosDragonAxe.RandomMaximumLevel = 4; chaosWeaponSettings.ResultItems.Add(chaosDragonAxe); var chaosNatureBow = this.Context.CreateNew(); chaosNatureBow.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Chaos Nature Bow"); + chaosNatureBow.RandomMinimumLevel = 0; + chaosNatureBow.RandomMaximumLevel = 4; chaosWeaponSettings.ResultItems.Add(chaosNatureBow); var chaosLightningStaff = this.Context.CreateNew(); chaosLightningStaff.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Chaos Lightning Staff"); + chaosLightningStaff.RandomMinimumLevel = 0; + chaosLightningStaff.RandomMaximumLevel = 4; chaosWeaponSettings.ResultItems.Add(chaosLightningStaff); return chaosWeapon; @@ -207,11 +212,11 @@ private ItemCrafting FirstWingsCrafting() var crafting = this.Context.CreateNew(); crafting.Name = "1st Level Wings"; crafting.Number = 11; + crafting.ItemCraftingHandlerClassName = typeof(ChaosWeaponAndFirstWingsCrafting).FullName!; var craftingSettings = this.Context.CreateNew(); - crafting.SimpleCraftingSettings = craftingSettings; - craftingSettings.MoneyPerFinalSuccessPercentage = 10000; - craftingSettings.SuccessPercent = 1; + craftingSettings.MoneyPerFinalSuccessPercentage = 10_000; + craftingSettings.NpcPriceDivisor = 20_000; // Requirements: var chaosWeapon = this.Context.CreateNew(); @@ -222,8 +227,7 @@ private ItemCrafting FirstWingsCrafting() chaosWeapon.MaximumAmount = 1; chaosWeapon.MinimumItemLevel = 4; chaosWeapon.MaximumItemLevel = 15; - chaosWeapon.NpcPriceDivisor = 15000; - chaosWeapon.FailResult = MixResult.DowngradedRandom; + chaosWeapon.FailResult = MixResult.ChaosWeaponAndFirstWingsDowngradedRandom; chaosWeapon.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); chaosWeapon.SuccessResult = MixResult.Disappear; craftingSettings.RequiredItems.Add(chaosWeapon); @@ -232,15 +236,13 @@ private ItemCrafting FirstWingsCrafting() randomItem.MinimumAmount = 0; randomItem.MinimumItemLevel = 4; randomItem.MaximumItemLevel = 15; - randomItem.NpcPriceDivisor = 15000; - randomItem.FailResult = MixResult.DowngradedRandom; + randomItem.FailResult = MixResult.Disappear; randomItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); randomItem.SuccessResult = MixResult.Disappear; craftingSettings.RequiredItems.Add(randomItem); var chaos = this.Context.CreateNew(); chaos.MinimumAmount = 1; - chaos.AddPercentage = 2; chaos.SuccessResult = MixResult.Disappear; chaos.FailResult = MixResult.Disappear; chaos.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Chaos")); @@ -248,7 +250,6 @@ private ItemCrafting FirstWingsCrafting() var bless = this.Context.CreateNew(); bless.MinimumAmount = 0; - bless.AddPercentage = 5; bless.SuccessResult = MixResult.Disappear; bless.FailResult = MixResult.Disappear; bless.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Bless")); @@ -256,7 +257,6 @@ private ItemCrafting FirstWingsCrafting() var soul = this.Context.CreateNew(); soul.MinimumAmount = 0; - soul.AddPercentage = 4; soul.SuccessResult = MixResult.Disappear; soul.FailResult = MixResult.Disappear; soul.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Soul")); @@ -264,7 +264,6 @@ private ItemCrafting FirstWingsCrafting() // Result: craftingSettings.ResultItemSelect = ResultItemSelection.Any; - craftingSettings.ResultItemLuckOptionChance = 10; var fairyWings = this.Context.CreateNew(); fairyWings.ItemDefinition = this.GameConfiguration.Items.First(i => i.Group == 12 && i.Number == 0); @@ -290,12 +289,10 @@ private ItemCrafting SecondWingsCrafting() var crafting = this.Context.CreateNew(); crafting.Name = "2nd Level Wings"; crafting.Number = 7; + crafting.ItemCraftingHandlerClassName = typeof(SecondWingsCrafting).FullName!; var craftingSettings = this.Context.CreateNew(); - crafting.SimpleCraftingSettings = craftingSettings; craftingSettings.Money = 5_000_000; - craftingSettings.MoneyPerFinalSuccessPercentage = 10000; - craftingSettings.SuccessPercent = 0; craftingSettings.MaximumSuccessPercent = 90; // Requirements: @@ -309,7 +306,7 @@ private ItemCrafting SecondWingsCrafting() firstWing.MinimumItemLevel = 0; firstWing.MaximumItemLevel = 15; firstWing.NpcPriceDivisor = 4_000_000; - firstWing.FailResult = MixResult.DowngradedRandom; + firstWing.FailResult = MixResult.Disappear; firstWing.SuccessResult = MixResult.Disappear; craftingSettings.RequiredItems.Add(firstWing); @@ -318,14 +315,14 @@ private ItemCrafting SecondWingsCrafting() randomExcItem.MinimumItemLevel = 4; randomExcItem.MaximumItemLevel = 15; randomExcItem.NpcPriceDivisor = 40_000; - randomExcItem.FailResult = MixResult.DowngradedRandom; + randomExcItem.FailResult = MixResult.Disappear; randomExcItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Excellent)); randomExcItem.SuccessResult = MixResult.Disappear; craftingSettings.RequiredItems.Add(randomExcItem); var chaos = this.Context.CreateNew(); chaos.MinimumAmount = 1; - chaos.AddPercentage = 2; + chaos.MaximumAmount = 1; chaos.SuccessResult = MixResult.Disappear; chaos.FailResult = MixResult.Disappear; chaos.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Chaos")); @@ -333,6 +330,7 @@ private ItemCrafting SecondWingsCrafting() var feather = this.Context.CreateNew(); feather.MinimumAmount = 1; + feather.MaximumAmount = 1; feather.SuccessResult = MixResult.Disappear; feather.FailResult = MixResult.Disappear; feather.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Loch's Feather")); @@ -340,7 +338,7 @@ private ItemCrafting SecondWingsCrafting() // Result: craftingSettings.ResultItemSelect = ResultItemSelection.Any; - craftingSettings.ResultItemLuckOptionChance = 10; + craftingSettings.ResultItemLuckOptionChance = 20; craftingSettings.ResultItemExcellentOptionChance = 20; craftingSettings.ResultItemMaxExcOptionCount = 1; @@ -373,10 +371,9 @@ private ItemCrafting ThirdWingsStage1Crafting() crafting.Name = "3rd Level Wings, Stage 1"; crafting.Number = 38; var craftingSettings = this.Context.CreateNew(); - crafting.SimpleCraftingSettings = craftingSettings; - craftingSettings.MoneyPerFinalSuccessPercentage = 200000; - craftingSettings.SuccessPercent = 0; + craftingSettings.MoneyPerFinalSuccessPercentage = 200_000; + craftingSettings.SuccessPercent = 1; craftingSettings.MaximumSuccessPercent = 60; // Requirements: @@ -392,8 +389,7 @@ private ItemCrafting ThirdWingsStage1Crafting() secondWing.MaximumAmount = 1; secondWing.MinimumItemLevel = 9; secondWing.MaximumItemLevel = 15; - secondWing.NpcPriceDivisor = 4_000_000; - secondWing.FailResult = MixResult.DowngradedRandom; + secondWing.FailResult = MixResult.ThirdWingsDowngradedRandom; secondWing.SuccessResult = MixResult.Disappear; secondWing.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); craftingSettings.RequiredItems.Add(secondWing); @@ -403,7 +399,7 @@ private ItemCrafting ThirdWingsStage1Crafting() randomAncientItem.MinimumItemLevel = 7; randomAncientItem.MaximumItemLevel = 15; randomAncientItem.NpcPriceDivisor = 300_000; - randomAncientItem.FailResult = MixResult.DowngradedRandom; + randomAncientItem.FailResult = MixResult.ThirdWingsDowngradedRandom; randomAncientItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.AncientBonus)); randomAncientItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); randomAncientItem.SuccessResult = MixResult.Disappear; @@ -434,7 +430,6 @@ private ItemCrafting ThirdWingsStage1Crafting() craftingSettings.RequiredItems.Add(stackOf10Soul); // Result: - craftingSettings.ResultItemSelect = ResultItemSelection.Any; var featherOfCondor = this.Context.CreateNew(); featherOfCondor.ItemDefinition = this.GameConfiguration.Items.First(i => i.Group == 13 && i.Number == 53); craftingSettings.ResultItems.Add(featherOfCondor); @@ -447,21 +442,20 @@ private ItemCrafting ThirdWingsStage2Crafting() var crafting = this.Context.CreateNew(); crafting.Name = "3rd Level Wings, Stage 2"; crafting.Number = 39; + crafting.ItemCraftingHandlerClassName = typeof(ThirdWingsCrafting).FullName!; var craftingSettings = this.Context.CreateNew(); - crafting.SimpleCraftingSettings = craftingSettings; - craftingSettings.Money = 5_000_000; - craftingSettings.MoneyPerFinalSuccessPercentage = 10000; - craftingSettings.SuccessPercent = 0; + craftingSettings.MoneyPerFinalSuccessPercentage = 200_000; + craftingSettings.SuccessPercent = 1; craftingSettings.MaximumSuccessPercent = 40; // Requirements: var randomExcItem = this.Context.CreateNew(); - randomExcItem.MinimumAmount = 0; + randomExcItem.MinimumAmount = 1; randomExcItem.MinimumItemLevel = 9; randomExcItem.MaximumItemLevel = 15; randomExcItem.NpcPriceDivisor = 3_000_000; - randomExcItem.FailResult = MixResult.DowngradedRandom; + randomExcItem.FailResult = MixResult.ThirdWingsDowngradedRandom; randomExcItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Excellent)); randomExcItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); randomExcItem.SuccessResult = MixResult.Disappear; @@ -501,6 +495,7 @@ private ItemCrafting ThirdWingsStage2Crafting() var feather = this.Context.CreateNew(); feather.MinimumAmount = 1; + feather.MaximumAmount = 1; feather.SuccessResult = MixResult.Disappear; feather.FailResult = MixResult.Disappear; feather.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Feather of Condor")); @@ -508,6 +503,7 @@ private ItemCrafting ThirdWingsStage2Crafting() var flame = this.Context.CreateNew(); flame.MinimumAmount = 1; + flame.MaximumAmount = 1; flame.SuccessResult = MixResult.Disappear; flame.FailResult = MixResult.Disappear; flame.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Flame of Condor")); @@ -515,9 +511,7 @@ private ItemCrafting ThirdWingsStage2Crafting() // Result: craftingSettings.ResultItemSelect = ResultItemSelection.Any; - craftingSettings.ResultItemLuckOptionChance = 10; - craftingSettings.ResultItemExcellentOptionChance = 20; - craftingSettings.ResultItemMaxExcOptionCount = 1; + craftingSettings.ResultItemLuckOptionChance = 5; var wingsOfStorm = this.Context.CreateNew(); wingsOfStorm.ItemDefinition = this.GameConfiguration.Items.First(i => i.Group == 12 && i.Number == 36); @@ -555,12 +549,10 @@ private ItemCrafting CapeCrafting() var crafting = this.Context.CreateNew(); crafting.Name = "Cape of Lord/Fighter"; crafting.Number = 24; + crafting.ItemCraftingHandlerClassName = typeof(SecondWingsCrafting).FullName!; var craftingSettings = this.Context.CreateNew(); - crafting.SimpleCraftingSettings = craftingSettings; craftingSettings.Money = 5_000_000; - craftingSettings.MoneyPerFinalSuccessPercentage = 10000; - craftingSettings.SuccessPercent = 0; craftingSettings.MaximumSuccessPercent = 90; // Requirements: @@ -571,10 +563,10 @@ private ItemCrafting CapeCrafting() firstWing.PossibleItems.Add(this.GameConfiguration.Items.First(item => item.Group == 12 && item.Number == 41)); firstWing.MinimumAmount = 1; firstWing.MaximumAmount = 1; - firstWing.MinimumItemLevel = 4; + firstWing.MinimumItemLevel = 0; firstWing.MaximumItemLevel = 15; firstWing.NpcPriceDivisor = 4_000_000; - firstWing.FailResult = MixResult.DowngradedRandom; + firstWing.FailResult = MixResult.Disappear; firstWing.SuccessResult = MixResult.Disappear; craftingSettings.RequiredItems.Add(firstWing); @@ -583,14 +575,14 @@ private ItemCrafting CapeCrafting() randomExcItem.MinimumItemLevel = 4; randomExcItem.MaximumItemLevel = 15; randomExcItem.NpcPriceDivisor = 40_000; - randomExcItem.FailResult = MixResult.DowngradedRandom; + randomExcItem.FailResult = MixResult.Disappear; randomExcItem.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Excellent)); randomExcItem.SuccessResult = MixResult.Disappear; craftingSettings.RequiredItems.Add(randomExcItem); var chaos = this.Context.CreateNew(); chaos.MinimumAmount = 1; - chaos.AddPercentage = 2; + chaos.MaximumAmount = 1; chaos.SuccessResult = MixResult.Disappear; chaos.FailResult = MixResult.Disappear; chaos.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Chaos")); @@ -598,6 +590,7 @@ private ItemCrafting CapeCrafting() var crest = this.Context.CreateNew(); crest.MinimumAmount = 1; + crest.MaximumAmount = 1; crest.SuccessResult = MixResult.Disappear; crest.FailResult = MixResult.Disappear; @@ -609,7 +602,9 @@ private ItemCrafting CapeCrafting() // Result: craftingSettings.ResultItemSelect = ResultItemSelection.Any; - craftingSettings.ResultItemLuckOptionChance = 10; + craftingSettings.ResultItemLuckOptionChance = 20; + craftingSettings.ResultItemExcellentOptionChance = 20; + craftingSettings.ResultItemMaxExcOptionCount = 1; var capeOfLord = this.Context.CreateNew(); capeOfLord.ItemDefinition = this.GameConfiguration.Items.First(i => i.Group == 13 && i.Number == 30); @@ -628,7 +623,6 @@ private ItemCrafting FruitCrafting() fruitCrafting.Name = "Fruits"; fruitCrafting.Number = 6; var craftingSettings = this.Context.CreateNew(); - fruitCrafting.SimpleCraftingSettings = craftingSettings; craftingSettings.Money = 3_000_000; craftingSettings.SuccessPercent = 90; @@ -653,8 +647,6 @@ private ItemCrafting FruitCrafting() // Result: var fruit = this.Context.CreateNew(); fruit.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Fruits"); - fruit.RandomMinimumLevel = 0; - fruit.RandomMaximumLevel = 4; craftingSettings.ResultItems.Add(fruit); return fruitCrafting; @@ -666,7 +658,6 @@ private ItemCrafting PotionOfBlessCrafting() potionCrafting.Name = "Potion of Bless"; potionCrafting.Number = 15; var craftingSettings = this.Context.CreateNew(); - potionCrafting.SimpleCraftingSettings = craftingSettings; craftingSettings.Money = 100_000; craftingSettings.SuccessPercent = 100; @@ -683,7 +674,6 @@ private ItemCrafting PotionOfBlessCrafting() // Result: var potion = this.Context.CreateNew(); - potion.ItemDefinition = this.GameConfiguration.Items.First(i => i.Number == ItemConstants.SiegePotion.Number && i.Group == ItemConstants.SiegePotion.Group); potion.Durability = 10; craftingSettings.ResultItems.Add(potion); @@ -697,7 +687,6 @@ private ItemCrafting PotionOfSoulCrafting() potionCrafting.Name = "Potion of Soul"; potionCrafting.Number = 16; var craftingSettings = this.Context.CreateNew(); - potionCrafting.SimpleCraftingSettings = craftingSettings; craftingSettings.Money = 50_000; craftingSettings.SuccessPercent = 100; @@ -753,13 +742,11 @@ private ItemCrafting DinorantCrafting() var crafting = this.Context.CreateNew(); crafting.Name = "Dinorant"; crafting.Number = 5; + crafting.ItemCraftingHandlerClassName = typeof(DinorantCrafting).FullName!; var craftingSettings = this.Context.CreateNew(); - crafting.SimpleCraftingSettings = craftingSettings; craftingSettings.Money = 500_000; craftingSettings.SuccessPercent = 70; - craftingSettings.ResultItemExcellentOptionChance = 10; - craftingSettings.ResultItemSkillChance = 100; // Requirements: var chaos = this.Context.CreateNew(); @@ -779,6 +766,8 @@ private ItemCrafting DinorantCrafting() craftingSettings.RequiredItems.Add(horn); // Result: + craftingSettings.ResultItemSkillChance = 100; + var dinorant = this.Context.CreateNew(); dinorant.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Horn of Dinorant"); craftingSettings.ResultItems.Add(dinorant); @@ -791,7 +780,7 @@ private ItemCrafting BloodCastleTicketCrafting() var crafting = this.Context.CreateNew(); crafting.Name = "Blood Castle Ticket"; crafting.Number = 8; - crafting.ItemCraftingHandlerClassName = typeof(GameLogic.PlayerActions.Craftings.BloodCastleTicketCrafting).FullName!; + crafting.ItemCraftingHandlerClassName = typeof(BloodCastleTicketCrafting).FullName!; return crafting; } @@ -800,7 +789,7 @@ private ItemCrafting DevilSquareTicketCrafting() var crafting = this.Context.CreateNew(); crafting.Name = "Devil's Square Ticket"; crafting.Number = 2; - crafting.ItemCraftingHandlerClassName = typeof(GameLogic.PlayerActions.Craftings.DevilSquareTicketCrafting).FullName!; + crafting.ItemCraftingHandlerClassName = typeof(DevilSquareTicketCrafting).FullName!; return crafting; } @@ -809,7 +798,7 @@ private ItemCrafting IllusionTempleTicketCrafting() var crafting = this.Context.CreateNew(); crafting.Name = "Illusion Temple Ticket"; crafting.Number = 37; - crafting.ItemCraftingHandlerClassName = typeof(GameLogic.PlayerActions.Craftings.IllusionTempleTicketCrafting).FullName!; + crafting.ItemCraftingHandlerClassName = typeof(IllusionTempleTicketCrafting).FullName!; return crafting; } @@ -853,11 +842,15 @@ private ItemCrafting DarkHorseCrafting() creation.MaximumAmount = 1; craftingSettings.RequiredItems.Add(creation); + // Result: + craftingSettings.ResultItemSkillChance = 100; + var darkHorse = this.Context.CreateNew(); darkHorse.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Dark Horse"); darkHorse.Durability = 255; + darkHorse.RandomMinimumLevel = 1; + darkHorse.RandomMaximumLevel = 1; craftingSettings.ResultItems.Add(darkHorse); - craftingSettings.ResultItemSkillChance = 100; return crafting; } @@ -904,11 +897,13 @@ private ItemCrafting DarkRavenCrafting() creation.MaximumAmount = 1; craftingSettings.RequiredItems.Add(creation); + // Result: var darkRaven = this.Context.CreateNew(); darkRaven.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Dark Raven"); darkRaven.Durability = 255; + darkRaven.RandomMinimumLevel = 1; + darkRaven.RandomMaximumLevel = 1; craftingSettings.ResultItems.Add(darkRaven); - craftingSettings.ResultItemSkillChance = 100; return crafting; } @@ -930,9 +925,10 @@ private ItemCrafting SmallShieldPotionCrafting() healthPotion.MaximumItemLevel = 15; craftingSettings.RequiredItems.Add(healthPotion); + // Result: var shieldPotion = this.Context.CreateNew(); shieldPotion.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Small Shield Potion"); - shieldPotion.Durability = 3; + shieldPotion.Durability = 1; craftingSettings.ResultItems.Add(shieldPotion); return crafting; @@ -955,9 +951,10 @@ private ItemCrafting MediumShieldPotionCrafting() complexPotion.MaximumItemLevel = 1; craftingSettings.RequiredItems.Add(complexPotion); + // Result: var shieldPotion = this.Context.CreateNew(); shieldPotion.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Medium Shield Potion"); - shieldPotion.Durability = 3; + shieldPotion.Durability = 1; craftingSettings.ResultItems.Add(shieldPotion); return crafting; @@ -980,9 +977,10 @@ private ItemCrafting LargeShieldPotionCrafting() complexPotion.MaximumItemLevel = 1; craftingSettings.RequiredItems.Add(complexPotion); + // Result: var shieldPotion = this.Context.CreateNew(); shieldPotion.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Large Shield Potion"); - shieldPotion.Durability = 3; + shieldPotion.Durability = 1; craftingSettings.ResultItems.Add(shieldPotion); return crafting; @@ -1022,6 +1020,7 @@ private ItemCrafting LifeStoneCrafting() chaos.MaximumAmount = 1; craftingSettings.RequiredItems.Add(chaos); + // Result: var lifeStone = this.Context.CreateNew(); lifeStone.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Life Stone"); lifeStone.Durability = 1; @@ -1058,6 +1057,7 @@ private ItemCrafting FenrirStage1Crafting() splinter.MaximumAmount = 20; craftingSettings.RequiredItems.Add(splinter); + // Result: var fragmentOfHorn = this.Context.CreateNew(); fragmentOfHorn.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Fragment of Horn"); fragmentOfHorn.Durability = 1; @@ -1094,6 +1094,7 @@ private ItemCrafting FenrirStage2Crafting() clawOfBeast.MaximumAmount = 10; craftingSettings.RequiredItems.Add(clawOfBeast); + // Result: var brokenHorn = this.Context.CreateNew(); brokenHorn.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Broken Horn"); brokenHorn.Durability = 1; @@ -1130,10 +1131,12 @@ private ItemCrafting FenrirStage3Crafting() life.MaximumAmount = 3; craftingSettings.RequiredItems.Add(life); + // Result: + craftingSettings.ResultItemSkillChance = 100; + var fenrir = this.Context.CreateNew(); fenrir.ItemDefinition = this.GameConfiguration.Items.First(i => i.Name == "Horn of Fenrir"); fenrir.Durability = 255; - craftingSettings.ResultItemSkillChance = 100; craftingSettings.ResultItems.Add(fenrir); return crafting; @@ -1144,7 +1147,7 @@ private ItemCrafting FenrirUpgradeCrafting() var crafting = this.Context.CreateNew(); crafting.Name = "Fenrir Upgrade (Stage 4)"; crafting.Number = 28; - crafting.ItemCraftingHandlerClassName = typeof(GameLogic.PlayerActions.Craftings.FenrirUpgradeCrafting).FullName!; + crafting.ItemCraftingHandlerClassName = typeof(FenrirUpgradeCrafting).FullName!; return crafting; } @@ -1230,27 +1233,16 @@ private ItemCrafting Level380OptionCrafting() randomItem7To9.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); craftingSettings.RequiredItems.Add(randomItem7To9); - var randomItem10To13 = this.Context.CreateNew(); - randomItem10To13.MaximumAmount = 1; - randomItem10To13.MinimumItemLevel = 10; - randomItem10To13.MaximumItemLevel = 13; - randomItem10To13.AddPercentage = 70; - randomItem10To13.FailResult = MixResult.StaysAsIs; - randomItem10To13.SuccessResult = MixResult.StaysAsIs; - randomItem10To13.Reference = GuardianOptionCrafting.ItemReference; - randomItem10To13.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); - craftingSettings.RequiredItems.Add(randomItem10To13); - - var randomItem14To15 = this.Context.CreateNew(); - randomItem14To15.MaximumAmount = 1; - randomItem14To15.MinimumItemLevel = 14; - randomItem14To15.MaximumItemLevel = 15; - randomItem14To15.AddPercentage = 80; - randomItem14To15.FailResult = MixResult.StaysAsIs; - randomItem14To15.SuccessResult = MixResult.StaysAsIs; - randomItem14To15.Reference = GuardianOptionCrafting.ItemReference; - randomItem14To15.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); - craftingSettings.RequiredItems.Add(randomItem14To15); + var randomItem10To15 = this.Context.CreateNew(); + randomItem10To15.MaximumAmount = 1; + randomItem10To15.MinimumItemLevel = 10; + randomItem10To15.MaximumItemLevel = 15; + randomItem10To15.AddPercentage = 70; + randomItem10To15.FailResult = MixResult.StaysAsIs; + randomItem10To15.SuccessResult = MixResult.StaysAsIs; + randomItem10To15.Reference = GuardianOptionCrafting.ItemReference; + randomItem10To15.RequiredItemOptions.Add(this.GameConfiguration.ItemOptionTypes.First(o => o == ItemOptionTypes.Option)); + craftingSettings.RequiredItems.Add(randomItem10To15); var harmony = this.Context.CreateNew(); harmony.PossibleItems.Add(this.GameConfiguration.Items.First(i => i.Name == "Jewel of Harmony")); @@ -1309,6 +1301,7 @@ private ItemCrafting SecromiconCrafting() var craftingSettings = this.Context.CreateNew(); crafting.SimpleCraftingSettings = craftingSettings; craftingSettings.SuccessPercent = 100; + craftingSettings.Money = 1_000_000; for (int i = 0; i < 6; i++) { @@ -1319,6 +1312,7 @@ private ItemCrafting SecromiconCrafting() craftingSettings.RequiredItems.Add(fragment); } + // Result: var completeSecromicon = this.Context.CreateNew(); completeSecromicon.ItemDefinition = this.GameConfiguration.Items.First(item => item.Group == 14 && item.Number == 109); craftingSettings.ResultItems.Add(completeSecromicon); diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Armors.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Armors.cs index 179ee44c6..3562479e0 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Armors.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Armors.cs @@ -100,7 +100,7 @@ public override void Initialize() this.CreateArmor(40, 2, 2, 2, "Red Wing Helm", 50, 18, 42, 0, 26, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); this.CreateArmor(41, 2, 2, 2, "Ancient Helm", 68, 24, 54, 0, 52, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); this.CreateArmor(42, 2, 2, 2, "Black Rose Helm", 81, 32, 67, 0, 60, 20, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); - this.CreateArmor(43, 2, 2, 2, "Aura Helm", 110, 43, 75, 0, 56, 20, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); + this.CreateArmor(43, 2, 2, 2, "Aura Helm", 110, 43, 75, 380, 56, 20, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); this.CreateArmor(44, 2, 2, 2, "Lilium Helm", 110, 50, 80, 0, 80, 50, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); this.CreateArmor(45, 2, 2, 2, "Titan Helm", 111, 63, 86, 0, 222, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); this.CreateArmor(46, 2, 2, 2, "Brave Helm", 107, 51, 86, 0, 74, 162, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); @@ -111,7 +111,7 @@ public override void Initialize() this.CreateArmor(59, 2, 2, 2, "Sacred Helm", 54, 24, 52, 1, 85, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 1); this.CreateArmor(60, 2, 2, 2, "Storm Hard Helm", 70, 32, 68, 1, 100, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 1); this.CreateArmor(61, 2, 2, 2, "Piercing Helm", 90, 45, 82, 1, 115, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1); - this.CreateArmor(73, 2, 2, 2, "Phoenix Soul Helmet", 128, 60, 88, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + this.CreateArmor(73, 2, 2, 2, "Phoenix Soul Helmet", 128, 60, 88, 380, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); // Armors: this.CreateArmor(0, 3, 2, 2, "Bronze Armor", 18, 14, 34, 0, 80, 20, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0); @@ -157,7 +157,7 @@ public override void Initialize() this.CreateArmor(40, 3, 2, 2, "Red Wing Armor", 56, 28, 42, 0, 35, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); this.CreateArmor(41, 3, 2, 2, "Ancient Armor", 75, 35, 54, 0, 52, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); this.CreateArmor(42, 3, 2, 2, "Black Rose Armor", 91, 45, 67, 0, 60, 20, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); - this.CreateArmor(43, 3, 2, 2, "Aura Armor", 122, 56, 75, 0, 57, 19, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); + this.CreateArmor(43, 3, 2, 2, "Aura Armor", 122, 56, 75, 380, 57, 19, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); this.CreateArmor(44, 3, 2, 2, "Lilium Armor", 113, 71, 84, 0, 110, 50, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); this.CreateArmor(45, 3, 2, 3, "Titan Armor", 132, 81, 86, 0, 222, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); this.CreateArmor(46, 3, 2, 3, "Brave Armor", 128, 62, 86, 0, 74, 162, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); @@ -170,7 +170,7 @@ public override void Initialize() this.CreateArmor(59, 3, 2, 3, "Sacred Armor", 66, 43, 52, 1, 85, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 1); this.CreateArmor(60, 3, 2, 3, "Storm Hard Armor", 82, 51, 68, 1, 100, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 1); this.CreateArmor(61, 3, 2, 3, "Piercing Armor", 101, 59, 82, 1, 115, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1); - this.CreateArmor(73, 3, 2, 3, "Phoenix Soul Armor", 143, 78, 88, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + this.CreateArmor(73, 3, 2, 3, "Phoenix Soul Armor", 143, 78, 88, 380, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); // Pants: this.CreateArmor(0, 4, 2, 2, "Bronze Pants", 15, 10, 34, 0, 80, 20, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0); @@ -216,7 +216,7 @@ public override void Initialize() this.CreateArmor(40, 4, 2, 2, "Red Wing Pants", 53, 22, 42, 0, 35, 7, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); this.CreateArmor(41, 4, 2, 2, "Ancient Pants", 72, 28, 54, 0, 49, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); this.CreateArmor(42, 4, 2, 2, "Black Rose Pants", 86, 37, 67, 0, 60, 20, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); - this.CreateArmor(43, 4, 2, 2, "Aura Pants", 117, 49, 75, 0, 57, 19, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); + this.CreateArmor(43, 4, 2, 2, "Aura Pants", 117, 49, 75, 380, 57, 19, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); this.CreateArmor(44, 4, 2, 2, "Lilium Pants", 102, 52, 82, 0, 75, 30, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0); this.CreateArmor(45, 4, 2, 2, "Titan Pants", 116, 74, 86, 0, 222, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); this.CreateArmor(46, 4, 2, 2, "Brave Pants", 112, 58, 86, 0, 74, 162, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0); @@ -229,7 +229,7 @@ public override void Initialize() this.CreateArmor(59, 4, 2, 2, "Sacred Pants", 62, 33, 52, 1, 85, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 1); this.CreateArmor(60, 4, 2, 2, "Storm Hard Pants", 78, 41, 68, 1, 100, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 1); this.CreateArmor(61, 4, 2, 2, "Piercing Pants", 95, 49, 82, 1, 115, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1); - 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); + this.CreateArmor(73, 4, 2, 2, "Phoenix Soul Pants", 134, 68, 88, 380, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); // Gloves: this.CreateGloves(0, "Bronze Gloves", 13, 4, 4, 34, 0, 80, 20, 0, 1, 0, 1, 1, 0); @@ -275,7 +275,7 @@ public override void Initialize() 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(43, "Aura Gloves", 87, 34, 6, 75, 380, 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); @@ -330,7 +330,7 @@ public override void Initialize() 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(43, "Aura Boots", 95, 38, 0, 75, 380, 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); @@ -343,7 +343,7 @@ public override void Initialize() 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.CreateBoots(73, "Phoenix Soul Boots", 119, 57, 0, 88, 380, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); this.BuildSets(); this.AddGuardianOptionsToSets(); @@ -361,6 +361,18 @@ private void AddGuardianOptionsToSets() this.AddGuardianOptionForArmor(i, ItemGroups.Boots); this.AddGuardianOptionForArmor(i, ItemGroups.Gloves); } + + const int auraSetIndex = 43; + this.AddGuardianOptionForArmor(auraSetIndex, ItemGroups.Armor); + this.AddGuardianOptionForArmor(auraSetIndex, ItemGroups.Pants); + this.AddGuardianOptionForArmor(auraSetIndex, ItemGroups.Helm); + this.AddGuardianOptionForArmor(auraSetIndex, ItemGroups.Boots); + this.AddGuardianOptionForArmor(auraSetIndex, ItemGroups.Gloves); + const int phoenixSoulSetIndex = 73; + this.AddGuardianOptionForArmor(phoenixSoulSetIndex, ItemGroups.Armor); + this.AddGuardianOptionForArmor(phoenixSoulSetIndex, ItemGroups.Pants); + this.AddGuardianOptionForArmor(phoenixSoulSetIndex, ItemGroups.Helm); + this.AddGuardianOptionForArmor(phoenixSoulSetIndex, ItemGroups.Boots); } private void AddGuardianOptionForArmor(int setNumber, ItemGroups itemGroup) diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Jewelery.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Jewelery.cs index 181982c96..c4d8764eb 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Jewelery.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Jewelery.cs @@ -119,25 +119,27 @@ private IncreasableItemOption CreateItemOption(AttributeDefinition targetOption, } /// - /// Creates the wizard ring which is dropped by the white wizard (level 0). + /// Creates the wizard's ring which is dropped by the white wizard (level 0). /// Level 1 and 2 are Ring of Warriors which can be dropped at level 40 and 80, . /// These can be equipped but have no options, and are bound to the character. /// /// /// Options: - /// Increase Damage 10% - /// Increase Attacking(Wizardry) Speed+10. + /// Increase Damage +10% + /// Increase Wizardry Damage +10% + /// Increase Attacking (Wizardry) Speed +10. /// private void CreateWizardsRing() { - var ring = this.CreateJewelery(20, 10, false, "Wizards Ring", 0, 250, null, null, null); + var ring = this.CreateJewelery(20, 10, false, "Wizard's Ring", 0, 250, null, null, null); ring.MaximumItemLevel = 2; ring.IsBoundToCharacter = true; + ring.Durability = 30; var optionDefinition = this.Context.CreateNew(); optionDefinition.SetGuid(ItemOptionDefinitionNumbers.WizardRing); this.GameConfiguration.ItemOptions.Add(optionDefinition); ring.PossibleItemOptions.Add(optionDefinition); - optionDefinition.Name = "Wizard Ring Options"; + optionDefinition.Name = "Wizard's Ring Options"; var increaseDamage = this.Context.CreateNew(); increaseDamage.SetGuid(ItemOptionDefinitionNumbers.WizardRing, 1); @@ -155,10 +157,18 @@ private void CreateWizardsRing() increaseSpeed.PowerUpDefinition.Boost.ConstantValue.Value = 10f; optionDefinition.PossibleOptions.Add(increaseSpeed); - // Always add both options "randomly" when it drops ;) + var increaseWizardryDamage = this.Context.CreateNew(); + increaseWizardryDamage.SetGuid(ItemOptionDefinitionNumbers.WizardRing, 3); + increaseWizardryDamage.PowerUpDefinition = this.Context.CreateNew(); + increaseWizardryDamage.PowerUpDefinition.TargetAttribute = Stats.WizardryAttackDamageIncrease.GetPersistent(this.GameConfiguration); + increaseWizardryDamage.PowerUpDefinition.Boost = this.Context.CreateNew(); + increaseWizardryDamage.PowerUpDefinition.Boost.ConstantValue.Value = 0.1f; + optionDefinition.PossibleOptions.Add(increaseWizardryDamage); + + // Always add all options "randomly" when it drops ;) optionDefinition.AddChance = 1.0f; optionDefinition.AddsRandomly = true; - optionDefinition.MaximumOptionsPerItem = 2; + optionDefinition.MaximumOptionsPerItem = 3; } /// diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/PackedJewels.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/PackedJewels.cs index 3dce08b0e..81e0e58d1 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/PackedJewels.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/PackedJewels.cs @@ -56,9 +56,9 @@ private ItemDefinition CreateJewelOfBless() } /// - /// Creates an for the 'Packed Jewel of Bless'. + /// Creates an for the 'Packed Jewel of Soul'. /// - /// for the 'Packed Jewel of Bless'. + /// for the 'Packed Jewel of Soul'. private ItemDefinition CreateJewelOfSoul() { var itemDefinition = this.Context.CreateNew(); diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Pets.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Pets.cs index 906e39e2d..9cb279d93 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Pets.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Pets.cs @@ -17,6 +17,7 @@ namespace MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Items; /// /// Initializer for pets. /// +/// Pet system changed in Season 9. Reference: https://muonline.webzen.com/en/gameinfo/guide/detail/76 . public class Pets : InitializerBase { private const string PetExperienceFormula = "level * level * level * 100 * (level + 10)"; @@ -45,7 +46,7 @@ public override void Initialize() darkHorse.PetExperienceFormula = PetExperienceFormula; darkHorse.MaximumItemLevel = 50; - var darkRaven = this.CreatePet(5, 0, 1, 1, "Dark Raven", 218, false, false); + var darkRaven = this.CreatePet(5, 0, 1, 1, "Dark Raven", 0, false, false); darkRaven.ItemSlot = this.GameConfiguration.ItemSlotTypes.First(st => st.ItemSlots.Contains(1)); darkRaven.PetExperienceFormula = PetExperienceFormula; darkRaven.MaximumItemLevel = 50; @@ -146,11 +147,12 @@ private void CreateSpirit() spirit.Width = 1; spirit.Height = 1; spirit.Durability = 1; + spirit.MaximumItemLevel = 1; spirit.SetGuid(spirit.Group, spirit.Number); this.GameConfiguration.Items.Add(spirit); var horseDrop = this.Context.CreateNew(); - horseDrop.SetGuid(NumberConversionExtensions.MakeWord(13, 31).ToSigned(), 0); + horseDrop.SetGuid(NumberConversionExtensions.MakeWord(13, 31).ToSigned(), 0, 1); horseDrop.ItemLevel = 0; horseDrop.Chance = 0.001; horseDrop.Description = "Dark Horse Spirit"; @@ -160,7 +162,7 @@ private void CreateSpirit() BaseMapInitializer.RegisterDefaultDropItemGroup(horseDrop); var ravenDrop = this.Context.CreateNew(); - horseDrop.SetGuid(NumberConversionExtensions.MakeWord(13, 31).ToSigned(), 1); + ravenDrop.SetGuid(NumberConversionExtensions.MakeWord(13, 31).ToSigned(), 1, 1); ravenDrop.ItemLevel = 1; ravenDrop.Chance = 0.001; ravenDrop.Description = "Dark Raven Spirit"; @@ -218,13 +220,13 @@ private void AddDinorantOptions(ItemDefinition dinorant) this.GameConfiguration.ItemOptions.Add(dinoOptionDefinition); dinoOptionDefinition.Name = "Dinorant Options"; - dinoOptionDefinition.AddChance = 0.1f; + dinoOptionDefinition.AddChance = 0.3f; dinoOptionDefinition.AddsRandomly = true; - dinoOptionDefinition.MaximumOptionsPerItem = 1; + dinoOptionDefinition.MaximumOptionsPerItem = 1; // There is second rollout for an additional bonus option to the first - dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Excellent, 1, Stats.DamageReceiveDecrement, 0.95f, AggregateType.Multiplicate, ItemOptionDefinitionNumbers.Dino)); - dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Excellent, 2, Stats.MaximumAbility, 50f, AggregateType.AddFinal, ItemOptionDefinitionNumbers.Dino)); - dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Excellent, 4, Stats.AttackSpeed, 5f, AggregateType.AddFinal, ItemOptionDefinitionNumbers.Dino)); + dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Option, 4, Stats.DamageReceiveDecrement, 0.95f, AggregateType.Multiplicate, ItemOptionDefinitionNumbers.Dino)); // Level 1 + dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Option, 4, Stats.MaximumAbility, 50f, AggregateType.AddFinal, ItemOptionDefinitionNumbers.Dino)); // Level 2 + dinoOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.Option, 4, Stats.AttackSpeed, 5f, AggregateType.AddFinal, ItemOptionDefinitionNumbers.Dino)); // Level 4 dinorant.PossibleItemOptions.Add(dinoOptionDefinition); } @@ -245,7 +247,7 @@ private void AddFenrirOptions(ItemDefinition fenrir) fenrirOptionDefinition.Name = "Fenrir Options"; fenrirOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.BlackFenrir, 1, Stats.AttackDamageIncrease, 1.1f, AggregateType.Multiplicate, ItemOptionDefinitionNumbers.Fenrir)); - fenrirOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.BlueFenrir, 2, Stats.DamageReceiveDecrement, 0.95f, AggregateType.Multiplicate, ItemOptionDefinitionNumbers.Fenrir)); + fenrirOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.BlueFenrir, 2, Stats.DamageReceiveDecrement, 0.90f, AggregateType.Multiplicate, ItemOptionDefinitionNumbers.Fenrir)); fenrirOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.GoldFenrir, 4, Stats.MaximumHealth, 200f, AggregateType.AddFinal, ItemOptionDefinitionNumbers.Fenrir)); fenrirOptionDefinition.PossibleOptions.Add(this.CreateOption(ItemOptionTypes.GoldFenrir, 4, Stats.MaximumMana, 200f, AggregateType.AddFinal, ItemOptionDefinitionNumbers.Fenrir)); diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Scrolls.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Scrolls.cs index 32c85608b..ea75d9294 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Scrolls.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Scrolls.cs @@ -44,7 +44,7 @@ public override void Initialize() this.CreateScroll(7, 8, "Scroll of Twister", 40, 0, 180, 25000, 1, 0, 0, 1, 0, 0, 0); this.CreateScroll(8, 9, "Scroll of Evil Spirit", 50, 0, 220, 35000, 1, 0, 0, 1, 0, 0, 0); this.CreateScroll(9, 10, "Scroll of Hellfire", 60, 0, 260, 60000, 1, 0, 0, 1, 0, 0, 0); - this.CreateScroll(10, 11, "Scroll of Power Wave", 9, 0, 56, 1150, 1, 0, 0, 1, 0, 1, 0); + this.CreateScroll(10, 11, "Scroll of Power Wave", 9, 0, 56, 1100, 1, 0, 0, 1, 0, 1, 0); this.CreateScroll(11, 12, "Scroll of Aqua Beam", 74, 0, 345, 100000, 1, 0, 0, 1, 0, 0, 0); this.CreateScroll(12, 13, "Scroll of Cometfall", 80, 0, 436, 175000, 1, 0, 0, 1, 0, 0, 0); this.CreateScroll(13, 14, "Scroll of Inferno", 88, 0, 578, 265000, 1, 0, 0, 1, 0, 0, 0); diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs index 965ea95e5..a65b13dbe 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Weapons.cs @@ -148,7 +148,7 @@ public override void Initialize() this.CreateWeapon(0, 32, 0, 260, 1, 2, true, "Sacred Glove", 52, 52, 58, 25, 65, 0, 0, 85, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1); this.CreateWeapon(0, 33, 0, 261, 1, 2, true, "Storm Hard Glove", 82, 82, 88, 30, 77, 0, 0, 100, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1); this.CreateWeapon(0, 34, 0, 260, 1, 2, true, "Piercing Blade Glove", 105, 95, 101, 35, 86, 0, 0, 120, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1); - this.CreateWeapon(0, 35, 0, 270, 1, 2, false, "Phoenix Soul Star", 147, 122, 128, 40, 98, 0, 0, 101, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1); + this.CreateWeapon(0, 35, 0, 270, 1, 2, false, "Phoenix Soul Star", 147, 122, 128, 40, 98, 0, 380, 101, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1); this.CreateWeapon(1, 0, 0, 0, 1, 3, true, "Small Axe", 1, 1, 6, 20, 18, 0, 0, 50, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1); this.CreateWeapon(1, 1, 0, 0, 1, 3, true, "Hand Axe", 4, 4, 9, 30, 20, 0, 0, 70, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1); @@ -165,7 +165,7 @@ public override void Initialize() this.CreateWeapon(2, 2, 0, 0, 1, 3, true, "Flail", 22, 22, 32, 15, 32, 0, 0, 80, 50, 0, 0, 0, 1, 0, 1, 1, 0, 1); this.CreateWeapon(2, 3, 0, 19, 2, 3, true, "Great Hammer", 38, 45, 56, 15, 50, 0, 0, 150, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); this.CreateWeapon(2, 4, 0, 19, 2, 3, true, "Crystal Morning Star", 66, 78, 107, 30, 72, 0, 0, 130, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1); - this.CreateWeapon(2, 5, 0, 23, 1, 4, true, "Crystal Sword", 72, 89, 120, 40, 76, 0, 0, 130, 70, 0, 0, 1, 1, 1, 1, 0, 0, 0); + this.CreateWeapon(2, 5, 0, 23, 2, 4, true, "Crystal Sword", 72, 89, 120, 40, 76, 0, 0, 130, 70, 0, 0, 1, 1, 1, 1, 0, 0, 0); this.CreateWeapon(2, 6, 0, 23, 2, 4, false, "Chaos Dragon Axe", 75, 102, 130, 35, 80, 0, 0, 140, 50, 0, 0, 0, 1, 0, 1, 0, 0, 0); this.CreateWeapon(2, 7, 0, 0, 1, 3, true, "Elemental Mace", 90, 62, 80, 50, 50, 0, 0, 15, 42, 0, 0, 0, 0, 2, 0, 0, 0, 0); this.CreateWeapon(2, 8, 0, 66, 1, 3, true, "Battle Scepter", 54, 41, 52, 45, 40, 3, 0, 80, 17, 0, 0, 0, 0, 0, 0, 1, 0, 0); @@ -462,6 +462,7 @@ private void AddGuardianOptions() var boneBlade = this.GameConfiguration.Items.First(i => i.Number == 22 && i.Group == (int)ItemGroups.Swords); var explosionBlade = this.GameConfiguration.Items.First(i => i.Number == 23 && i.Group == (int)ItemGroups.Swords); + var phoenixSoulStar = this.GameConfiguration.Items.First(i => i.Number == 35 && i.Group == (int)ItemGroups.Swords); var soleilScepter = this.GameConfiguration.Items.First(i => i.Number == 14 && i.Group == (int)ItemGroups.Scepters); var sylphWindBow = this.GameConfiguration.Items.First(i => i.Number == 21 && i.Group == (int)ItemGroups.Bows); var viperStaff = this.GameConfiguration.Items.First(i => i.Number == 12 && i.Group == (int)ItemGroups.Staff); @@ -469,6 +470,7 @@ private void AddGuardianOptions() boneBlade.PossibleItemOptions.Add(weaponOption); explosionBlade.PossibleItemOptions.Add(weaponOption); + phoenixSoulStar.PossibleItemOptions.Add(weaponOption); soleilScepter.PossibleItemOptions.Add(weaponOption); sylphWindBow.PossibleItemOptions.Add(weaponOption); viperStaff.PossibleItemOptions.Add(weaponOption); diff --git a/src/Web/AdminPanel/Components/ItemEdit/ViewModel.cs b/src/Web/AdminPanel/Components/ItemEdit/ViewModel.cs index be2dc03b5..b99c74402 100644 --- a/src/Web/AdminPanel/Components/ItemEdit/ViewModel.cs +++ b/src/Web/AdminPanel/Components/ItemEdit/ViewModel.cs @@ -614,7 +614,7 @@ public IEnumerable PossibleSocketBonusOptions } /// - /// Gets the possible socket bonus options. + /// Gets the possible fenrir options. /// public IEnumerable PossibleFenrirOptions { diff --git a/tests/MUnique.OpenMU.Tests/ItemPriceCalculatorTest.cs b/tests/MUnique.OpenMU.Tests/ItemPriceCalculatorTest.cs index dad17020d..b41a39550 100644 --- a/tests/MUnique.OpenMU.Tests/ItemPriceCalculatorTest.cs +++ b/tests/MUnique.OpenMU.Tests/ItemPriceCalculatorTest.cs @@ -391,8 +391,8 @@ private void CheckPrice(byte id, byte dropLevel, byte maxDurability, byte height if (group < 6) { - // weapons should have a min dmg attribute - itemDefinition.BasePowerUpAttributes.Add(new ItemBasePowerUpDefinition { TargetAttribute = Stats.MinimumPhysBaseDmg }); + // weapons should have an attack speed attribute + itemDefinition.BasePowerUpAttributes.Add(new ItemBasePowerUpDefinition { TargetAttribute = Stats.AttackSpeedByWeapon }); } var itemMock = new Mock(); @@ -434,7 +434,7 @@ private void CheckPrice(byte id, byte dropLevel, byte maxDurability, byte height item.HasSkill = true; } - var buyingPrice = this._calculator.CalculateBuyingPrice(item); + var buyingPrice = this._calculator.CalculateFinalBuyingPrice(item); Assert.That(buyingPrice, Is.EqualTo(price)); } } \ No newline at end of file