using System.Collections.Generic; using System.Linq; using WingsAPI.Data.Families; using WingsEmu.Core.Extensions; using WingsEmu.DTOs.BCards; using WingsEmu.Game.Buffs; using WingsEmu.Game.Mates; using WingsEmu.Packets.Enums; using WingsEmu.Packets.Enums.Battle; namespace WingsEmu.Game.EntityStatistics; public class MateStatisticsComponent : IMateStatisticsComponent { private readonly Dictionary _stats = new(); private IMateEntity _mateEntity; public MateStatisticsComponent(IMateEntity mateEntity) => _mateEntity = mateEntity; public int MinDamage => _mateEntity?.DamagesMinimum + _stats.GetValueOrDefault(Statistics.MIN_DAMAGE) ?? 0; public int MaxDamage => _mateEntity?.DamagesMaximum + _stats.GetValueOrDefault(Statistics.MAX_DAMAGE) ?? 0; public int HitRate => _mateEntity?.HitRate + _stats.GetValueOrDefault(Statistics.MIN_DAMAGE) ?? 0; public int CriticalChance => _mateEntity?.HitCriticalChance + _stats.GetValueOrDefault(Statistics.CRITICAL_CHANCE) ?? 0; public int CriticalDamage => _mateEntity?.HitCriticalDamage + _stats.GetValueOrDefault(Statistics.CRITICAL_DAMAGE) ?? 0; public int MeleeDefense => _mateEntity?.CloseDefence + _stats.GetValueOrDefault(Statistics.MELEE_DEFENSE) ?? 0; public int RangeDefense => _mateEntity?.DistanceDefence + _stats.GetValueOrDefault(Statistics.RANGE_DEFENSE) ?? 0; public int MagicDefense => _mateEntity?.MagicDefence + _stats.GetValueOrDefault(Statistics.MAGIC_DEFENSE) ?? 0; public int MeleeDodge => _mateEntity?.DefenceDodge + _stats.GetValueOrDefault(Statistics.MELEE_DODGE) ?? 0; public int RangeDodge => _mateEntity?.DistanceDodge + _stats.GetValueOrDefault(Statistics.RANGE_DODGE) ?? 0; public int FireResistance => _mateEntity?.FireResistance + _stats.GetValueOrDefault(Statistics.FIRE_RESISTANCE) ?? 0; public int WaterResistance => _mateEntity?.WaterResistance + _stats.GetValueOrDefault(Statistics.WATER_RESISTANCE) ?? 0; public int LightResistance => _mateEntity?.LightResistance + _stats.GetValueOrDefault(Statistics.LIGHT_RESISTANCE) ?? 0; public int ShadowResistance => _mateEntity?.DarkResistance + _stats.GetValueOrDefault(Statistics.SHADOW_RESISTANCE) ?? 0; public void RefreshMateStatistics(IMateEntity mateEntity) { _mateEntity = mateEntity; if (_mateEntity.MateType == MateType.Pet) { return; } _stats.Clear(); int minDamage = 0; int maxDamage = 0; int hitRate = 0; int criticalChance = 0; int criticalDamage = 0; int meleeDefense = 0; int rangeDefense = 0; int magicDefense = 0; int meleeDodge = 0; int rangeDodge = 0; int fireResistance = 0; int waterResistance = 0; int lightResistance = 0; int shadowResistance = 0; AttackType attackType = _mateEntity.AttackType; byte playerLevel = _mateEntity.Level; IReadOnlyList bCards = _mateEntity.BCardComponent.GetAllBCards(); IEnumerable minMaxDamageBCards = bCards.Where(x => x.Type == (short)BCardType.AttackPower); IEnumerable hitRateBCards = bCards.Where(x => x.Type == (short)BCardType.Target); IEnumerable criticalBCards = bCards.Where(x => x.Type == (short)BCardType.Critical); IEnumerable defenseBCards = bCards.Where(x => x.Type == (short)BCardType.Defence); IEnumerable dodgeBCards = bCards.Where(x => x.Type == (short)BCardType.DodgeAndDefencePercent); IEnumerable resistanceBCards = bCards.Where(x => x.Type == (short)BCardType.ElementResistance); foreach (BCardDTO bCard in minMaxDamageBCards) { int firstData = bCard.FirstDataValue(playerLevel); switch ((AdditionalTypes.AttackPower)bCard.SubType) { case AdditionalTypes.AttackPower.AllAttacksIncreased: minDamage += firstData; maxDamage += firstData; break; case AdditionalTypes.AttackPower.AllAttacksDecreased: minDamage -= firstData; maxDamage -= firstData; break; case AdditionalTypes.AttackPower.MeleeAttacksIncreased: if (attackType != AttackType.Melee) { break; } minDamage += firstData; maxDamage += firstData; break; case AdditionalTypes.AttackPower.MeleeAttacksDecreased: if (attackType != AttackType.Melee) { break; } minDamage -= firstData; maxDamage -= firstData; break; case AdditionalTypes.AttackPower.RangedAttacksIncreased: if (attackType != AttackType.Ranged) { break; } minDamage += firstData; maxDamage += firstData; break; case AdditionalTypes.AttackPower.RangedAttacksDecreased: if (attackType != AttackType.Ranged) { break; } minDamage -= firstData; maxDamage -= firstData; break; case AdditionalTypes.AttackPower.MagicalAttacksIncreased: if (attackType != AttackType.Magical) { break; } minDamage += firstData; maxDamage += firstData; break; case AdditionalTypes.AttackPower.MagicalAttacksDecreased: if (attackType != AttackType.Magical) { break; } minDamage -= firstData; maxDamage -= firstData; break; } } foreach (BCardDTO bCard in hitRateBCards) { int firstData = bCard.FirstDataValue(playerLevel); switch ((AdditionalTypes.Target)bCard.SubType) { case AdditionalTypes.Target.AllHitRateIncreased: hitRate += firstData; break; case AdditionalTypes.Target.AllHitRateDecreased: hitRate -= firstData; break; case AdditionalTypes.Target.MeleeHitRateIncreased: if (attackType != AttackType.Melee) { break; } hitRate += firstData; break; case AdditionalTypes.Target.MeleeHitRateDecreased: if (attackType != AttackType.Melee) { break; } hitRate -= firstData; break; case AdditionalTypes.Target.RangedHitRateIncreased: if (attackType != AttackType.Ranged) { break; } hitRate += firstData; break; case AdditionalTypes.Target.RangedHitRateDecreased: if (attackType != AttackType.Ranged) { break; } hitRate -= firstData; break; case AdditionalTypes.Target.MagicalConcentrationIncreased: if (attackType != AttackType.Magical) { break; } hitRate += firstData; break; case AdditionalTypes.Target.MagicalConcentrationDecreased: if (attackType != AttackType.Magical) { break; } hitRate -= firstData; break; } } foreach (BCardDTO bCard in criticalBCards) { int firstData = bCard.FirstDataValue(playerLevel); switch ((AdditionalTypes.Critical)bCard.SubType) { case AdditionalTypes.Critical.InflictingIncreased: if (attackType == AttackType.Magical) { break; } criticalChance += firstData; break; case AdditionalTypes.Critical.InflictingReduced: if (attackType == AttackType.Magical) { break; } criticalChance -= firstData; break; case AdditionalTypes.Critical.DamageIncreased: if (attackType == AttackType.Magical) { break; } criticalDamage += firstData; break; case AdditionalTypes.Critical.DamageIncreasedInflictingReduced: if (attackType == AttackType.Magical) { break; } criticalDamage -= firstData; break; } } foreach (BCardDTO bCard in defenseBCards) { int firstData = bCard.FirstDataValue(playerLevel); switch ((AdditionalTypes.Defence)bCard.SubType) { case AdditionalTypes.Defence.AllIncreased: meleeDefense += firstData; rangeDefense += firstData; magicDefense += firstData; break; case AdditionalTypes.Defence.AllDecreased: meleeDefense -= firstData; rangeDefense -= firstData; magicDefense -= firstData; break; case AdditionalTypes.Defence.MeleeIncreased: meleeDefense += firstData; break; case AdditionalTypes.Defence.MeleeDecreased: meleeDefense -= firstData; break; case AdditionalTypes.Defence.RangedIncreased: rangeDefense += firstData; break; case AdditionalTypes.Defence.RangedDecreased: rangeDefense -= firstData; break; case AdditionalTypes.Defence.MagicalIncreased: magicDefense += firstData; break; case AdditionalTypes.Defence.MagicalDecreased: magicDefense -= firstData; break; } } foreach (BCardDTO bCard in dodgeBCards) { int firstData = bCard.FirstDataValue(playerLevel); switch ((AdditionalTypes.DodgeAndDefencePercent)bCard.SubType) { case AdditionalTypes.DodgeAndDefencePercent.DodgeIncreased: meleeDodge += firstData; rangeDodge += firstData; break; case AdditionalTypes.DodgeAndDefencePercent.DodgeDecreased: meleeDodge -= firstData; rangeDodge -= firstData; break; case AdditionalTypes.DodgeAndDefencePercent.DodgingMeleeIncreased: meleeDodge += firstData; break; case AdditionalTypes.DodgeAndDefencePercent.DodgingMeleeDecreased: meleeDodge -= firstData; break; case AdditionalTypes.DodgeAndDefencePercent.DodgingRangedIncreased: rangeDodge += firstData; break; case AdditionalTypes.DodgeAndDefencePercent.DodgingRangedDecreased: rangeDodge -= firstData; break; } } foreach (BCardDTO bCard in resistanceBCards) { int firstData = bCard.FirstDataValue(playerLevel); switch ((AdditionalTypes.ElementResistance)bCard.SubType) { case AdditionalTypes.ElementResistance.AllIncreased: fireResistance += firstData; waterResistance += firstData; lightResistance += firstData; shadowResistance += firstData; break; case AdditionalTypes.ElementResistance.AllDecreased: fireResistance -= firstData; waterResistance -= firstData; lightResistance -= firstData; shadowResistance -= firstData; break; case AdditionalTypes.ElementResistance.FireIncreased: fireResistance += firstData; break; case AdditionalTypes.ElementResistance.FireDecreased: fireResistance -= firstData; break; case AdditionalTypes.ElementResistance.WaterIncreased: waterResistance += firstData; break; case AdditionalTypes.ElementResistance.WaterDecreased: waterResistance -= firstData; break; case AdditionalTypes.ElementResistance.LightIncreased: lightResistance += firstData; break; case AdditionalTypes.ElementResistance.LightDecreased: lightResistance -= firstData; break; case AdditionalTypes.ElementResistance.DarkIncreased: shadowResistance += firstData; break; case AdditionalTypes.ElementResistance.DarkDecreased: shadowResistance -= firstData; break; } } fireResistance += _mateEntity.Owner?.Family?.UpgradeValues?.GetOrDefault(FamilyUpgradeType.FIRE_RESISTANCE) ?? 0; waterResistance += _mateEntity.Owner?.Family?.UpgradeValues?.GetOrDefault(FamilyUpgradeType.WATER_RESISTANCE) ?? 0; lightResistance += _mateEntity.Owner?.Family?.UpgradeValues?.GetOrDefault(FamilyUpgradeType.LIGHT_RESISTANCE) ?? 0; shadowResistance += _mateEntity.Owner?.Family?.UpgradeValues?.GetOrDefault(FamilyUpgradeType.DARK_RESISTANCE) ?? 0; _stats[Statistics.MIN_DAMAGE] = minDamage; _stats[Statistics.MAX_DAMAGE] = maxDamage; _stats[Statistics.HITRATE] = hitRate; _stats[Statistics.CRITICAL_CHANCE] = criticalChance; _stats[Statistics.CRITICAL_DAMAGE] = criticalDamage; _stats[Statistics.MELEE_DEFENSE] = meleeDefense; _stats[Statistics.RANGE_DEFENSE] = rangeDefense; _stats[Statistics.MAGIC_DEFENSE] = magicDefense; _stats[Statistics.MELEE_DODGE] = meleeDodge; _stats[Statistics.RANGE_DODGE] = rangeDodge; _stats[Statistics.FIRE_RESISTANCE] = fireResistance; _stats[Statistics.WATER_RESISTANCE] = waterResistance; _stats[Statistics.LIGHT_RESISTANCE] = lightResistance; _stats[Statistics.SHADOW_RESISTANCE] = shadowResistance; } }