// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // namespace MUnique.OpenMU.GameLogic; using MUnique.OpenMU.DataModel.Configuration.Quests; using MUnique.OpenMU.GameLogic.Attributes; using Nito.Disposables.Internals; /// /// Extensions for . /// public static class CharacterExtensions { private const int MaxLevel = 400; private static readonly ushort[] FruitPointsPerLevel = GetFruitPoints(400).ToArray(); private static readonly ushort[] FruitPointsPerLevelMagicGladiator = GetFruitPoints(700).ToArray(); private static readonly ushort[] FruitPointsPerLevelDarkLord = GetFruitPoints(500).ToArray(); /// /// Gets the maximum fruit points of the character. /// /// The character. /// The maximum fruit points of the character. public static ushort GetMaximumFruitPoints(this Character character) { var index = (int)character.Attributes.First(a => a.Definition == Stats.Level).Value - 1; return character.CharacterClass?.FruitCalculation switch { FruitCalculationStrategy.DarkLord => FruitPointsPerLevelDarkLord[index], FruitCalculationStrategy.MagicGladiator => FruitPointsPerLevelMagicGladiator[index], _ => FruitPointsPerLevel[index], }; } /// /// Determines whether the character has a full ancient set equipped. /// /// The character. /// /// true if the character has a full ancient set equipped; otherwise, false. /// public static bool HasFullAncientSetEquipped(this Character character) { if (character?.Inventory is null) { return false; } var equippedAncientSetItems = character.Inventory.Items.Where(i => i.ItemSlot <= InventoryConstants.LastEquippableItemSlotIndex && i.ItemSlot >= InventoryConstants.FirstEquippableItemSlotIndex && i.ItemSetGroups.Any(group => group.AncientSetDiscriminator > 0)) .Select(i => new { Item = i.Definition, Set = i.ItemSetGroups.First(s => s.AncientSetDiscriminator > 0), }); var ancientSets = equippedAncientSetItems.Select(i => i.Set.ItemSetGroup).WhereNotNull().Distinct(); return ancientSets.Any(set => set.Items.All(setItem => equippedAncientSetItems.Any(i => object.Equals(i.Item, setItem.ItemDefinition) && object.Equals(i.Set.ItemSetGroup, set)))); } /// /// Determines whether the character is able to increase StatAttributes. /// /// The character. /// /// true if the character can increase StatAttributes; otherwise, false. /// public static bool CanIncreaseStats(this Character character) { return character.CharacterStatus == CharacterStatus.GameMaster || character.LevelUpPoints > 0; } /// /// Determines whether the character is able to increase StatAttributes. /// /// The character. /// The amount of points which should be added. /// /// true if the character can increase StatAttributes; otherwise, false. /// public static bool CanIncreaseStats(this Character character, ushort amount) { return character.CharacterStatus == CharacterStatus.GameMaster || character.LevelUpPoints >= amount; } /// /// Determines whether the character is a "special" character with reduced level requirements for maps and events. /// Special characters have a of 33. /// Usually, this includes the classes Magic Gladiator, Dark Lord, Rage Fighter and Summoner. /// /// The character. /// /// true if the character is a "special" character with reduced level requirements for maps and events; otherwise, false. /// public static bool IsSpecialCharacter(this Character character) { return character.CharacterClass?.LevelWarpRequirementReductionPercent > 30; } /// /// Gets the effective move level requirement by considering . /// /// The character. /// The level requirement. /// The effective move level requirement. public static int GetEffectiveMoveLevelRequirement(this Character character, int levelRequirement) { if (levelRequirement == 400) { return levelRequirement; } if (character.CharacterClass?.LevelWarpRequirementReductionPercent is { } reduction and > 0) { levelRequirement = levelRequirement * (100 - reduction) / 100; } return levelRequirement; } /// /// Gets the quest drop item groups of a character. /// /// The character. /// The quest drop item groups of a character. public static IEnumerable GetQuestDropItemGroups(this Character character) { return character.QuestStates? .SelectMany(q => q.ActiveQuest?.RequiredItems ?? Enumerable.Empty()) .Select(i => i.DropItemGroup) .WhereNotNull() ?? Enumerable.Empty(); } private static IEnumerable GetFruitPoints(int divisor) { var current = 2; for (int i = 0; i < MaxLevel; i++) { if (((i + 1) % 10) == 0) { current += (3 * (i + 11) / divisor) + 2; } yield return (ushort)current; } } }