using System; using System.Collections.Generic; using System.Linq; using WingsAPI.Data.Families; using WingsAPI.Packets.Enums.Shells; using WingsEmu.DTOs.BCards; using WingsEmu.DTOs.Items; using WingsEmu.Game._enum; using WingsEmu.Game.Buffs; using WingsEmu.Game.Characters; using WingsEmu.Game.Helpers.Damages; using WingsEmu.Game.Items; using WingsEmu.Game.Maps; using WingsEmu.Game.Monster; using WingsEmu.Packets.Enums; using WingsEmu.Packets.Enums.Battle; using WingsEmu.Packets.Enums.Character; namespace WingsEmu.Game.Battle; public class PlayerBattleEntityDump : IBattleEntityDump { public PlayerBattleEntityDump(IPlayerEntity playerEntity, SkillInfo skill, bool isDefender, bool isMainTarget) { bool useSecondWeapon = false; GameItemInstance weapon = null; var bCardDictionary = new Dictionary<(BCardType type, byte subType), List>(); if (skill != null) // get all info from attacker calculation { if (isDefender) { if (skill.BCardsType.TryGetValue(SkillCastType.BEFORE_ATTACK_ALL_TARGETS, out HashSet hashSetBCards)) { foreach (BCardDTO bCard in hashSetBCards) { if (!bCardDictionary.TryGetValue(((BCardType)bCard.Type, bCard.SubType), out List list)) { list = new List(); bCardDictionary[((BCardType)bCard.Type, bCard.SubType)] = list; } list.Add(bCard); } } } else { if (skill.BCardsType.TryGetValue(SkillCastType.BEFORE_ATTACK_SELF, out HashSet hashSetBCards)) { foreach (BCardDTO bCard in hashSetBCards) { if (!bCardDictionary.TryGetValue(((BCardType)bCard.Type, bCard.SubType), out List list)) { list = new List(); bCardDictionary[((BCardType)bCard.Type, bCard.SubType)] = list; } list.Add(bCard); } } HashSet chargeBCardToRemove = new(); foreach (BCardDTO bCard in playerEntity.BCardComponent.GetChargeBCards()) { if (!bCardDictionary.TryGetValue(((BCardType)bCard.Type, bCard.SubType), out List list)) { list = new List(); bCardDictionary[((BCardType)bCard.Type, bCard.SubType)] = list; } list.Add(bCard); chargeBCardToRemove.Add(bCard); } foreach (BCardDTO bCard in chargeBCardToRemove) { playerEntity.BCardComponent.RemoveChargeBCard(bCard); } } if (isMainTarget) { if (skill.BCardsType.TryGetValue(SkillCastType.BEFORE_ATTACK_ON_MAIN_TARGET, out HashSet hashSetBCards)) { foreach (BCardDTO bCard in hashSetBCards) { if (!bCardDictionary.TryGetValue(((BCardType)bCard.Type, bCard.SubType), out List list)) { list = new List(); bCardDictionary[((BCardType)bCard.Type, bCard.SubType)] = list; } list.Add(bCard); } } } switch (skill.AttackType) { case AttackType.Melee: AttackType = AttackType.Melee; switch (playerEntity.Class) { case ClassType.Archer: DamageMinimum = playerEntity.SecondDamageMinimum; DamageMaximum = playerEntity.SecondDamageMaximum; HitRate = playerEntity.SecondHitRate; CriticalChance = playerEntity.SecondHitCriticalChance; CriticalDamage = playerEntity.SecondHitCriticalDamage; useSecondWeapon = true; { GameItemInstance inventoryItem = playerEntity.SecondaryWeapon; if (inventoryItem != null) { weapon = inventoryItem; } } break; default: { GameItemInstance inventoryItem = playerEntity.MainWeapon; if (inventoryItem != null) { weapon = inventoryItem; } } break; } break; case AttackType.Ranged: AttackType = AttackType.Ranged; switch (playerEntity.Class) { case ClassType.Adventurer: case ClassType.Swordman: case ClassType.Magician: case ClassType.Wrestler: DamageMinimum = playerEntity.SecondDamageMinimum; DamageMaximum = playerEntity.SecondDamageMaximum; HitRate = playerEntity.SecondHitRate; CriticalChance = playerEntity.SecondHitCriticalChance; CriticalDamage = playerEntity.SecondHitCriticalDamage; weapon = playerEntity.SecondaryWeapon; useSecondWeapon = true; break; case ClassType.Archer: weapon = playerEntity.MainWeapon; break; } break; case AttackType.Magical: AttackType = AttackType.Magical; weapon = playerEntity.MainWeapon; break; case AttackType.Other: weapon = playerEntity.MainWeapon; AttackType = playerEntity.Class switch { ClassType.Wrestler => AttackType.Melee, ClassType.Adventurer => AttackType.Melee, ClassType.Swordman => AttackType.Melee, ClassType.Archer => AttackType.Ranged, ClassType.Magician => AttackType.Magical }; break; case AttackType.Dash: AttackType = AttackType.Melee; weapon = playerEntity.Class switch { ClassType.Adventurer => playerEntity.MainWeapon, ClassType.Swordman => playerEntity.MainWeapon, ClassType.Archer => playerEntity.SecondaryWeapon, ClassType.Magician => playerEntity.MainWeapon, ClassType.Wrestler => playerEntity.MainWeapon }; if (playerEntity.Class == ClassType.Archer) { DamageMinimum = playerEntity.SecondDamageMinimum; DamageMaximum = playerEntity.SecondDamageMaximum; HitRate = playerEntity.SecondHitRate; CriticalChance = playerEntity.SecondHitCriticalChance; CriticalDamage = playerEntity.SecondHitCriticalDamage; useSecondWeapon = true; } break; } } else { weapon = playerEntity.SecondaryWeapon; useSecondWeapon = true; AttackType = playerEntity.Class switch { ClassType.Adventurer => AttackType.Melee, ClassType.Swordman => AttackType.Melee, ClassType.Wrestler => AttackType.Melee, ClassType.Archer => AttackType.Ranged, ClassType.Magician => AttackType.Magical }; } if (weapon != null) { AttackUpgrade = weapon.Upgrade; WeaponDamageMinimum = weapon.DamageMinimum + weapon.GameItem.DamageMinimum; WeaponDamageMaximum = weapon.DamageMaximum + weapon.GameItem.DamageMaximum; } GameItemInstance armor = playerEntity.Armor; if (armor != null) { DefenseUpgrade = armor.Upgrade; } IReadOnlyList bCards = playerEntity.BCardComponent.GetAllBCards(); foreach (BCardDTO bCard in bCards) { if (!bCardDictionary.TryGetValue(((BCardType)bCard.Type, bCard.SubType), out List list)) { list = new List(); bCardDictionary[((BCardType)bCard.Type, bCard.SubType)] = list; } list.Add(bCard); } ISet buffsById = playerEntity.BuffComponent.GetAllBuffsId().ToHashSet(); IReadOnlyList<(int casterLevel, BCardDTO bCard)> buffBCards = playerEntity.BCardComponent.GetBuffBCards(); var buffs = new Dictionary<(BCardType type, byte subType), List<(int casterLevel, BCardDTO bCard)>>(); foreach ((int casterLevel, BCardDTO bCard) in buffBCards) { (BCardType, byte SubType) key = ((BCardType)bCard.Type, bCard.SubType); if (!buffs.TryGetValue(key, out List<(int casterLevel, BCardDTO bCard)> list)) { list = new List<(int casterLevel, BCardDTO bCard)>(); buffs[key] = list; } list.Add((casterLevel, bCard)); } short element = playerEntity.Fairy?.GameItem.Element == (short)ElementType.All ? skill.Element : playerEntity.Element; BuffBCards = buffs; MaxHp = playerEntity.MaxHp; MaxMp = playerEntity.MaxMp; BuffsById = buffsById; Type = VisualType.Player; Id = playerEntity.Id; Morale = playerEntity.Level; Level = playerEntity.Level; Faction = playerEntity.Faction; DamageMinimum = !useSecondWeapon ? playerEntity.DamagesMinimum - WeaponDamageMinimum : DamageMinimum - WeaponDamageMinimum; DamageMaximum = !useSecondWeapon ? playerEntity.DamagesMaximum - WeaponDamageMaximum : DamageMaximum - WeaponDamageMaximum; CriticalChance = !useSecondWeapon ? playerEntity.HitCriticalChance : CriticalChance; CriticalDamage = !useSecondWeapon ? playerEntity.HitCriticalDamage : CriticalDamage; ShadowResistance = playerEntity.DarkResistance; LightResistance = playerEntity.LightResistance; WaterResistance = playerEntity.WaterResistance; FireResistance = playerEntity.FireResistance; HitRate = !useSecondWeapon ? playerEntity.HitRate : HitRate; MeleeDodge = playerEntity.MeleeDodge; RangeDodge = playerEntity.RangedDodge; Element = (ElementType)element; ElementRate = playerEntity.ElementRate + playerEntity.SpecialistElementRate; BCards = bCardDictionary; ShellOptionsWeapon = playerEntity.GetShellsValues(EquipmentOptionType.WEAPON_SHELL, !useSecondWeapon); ShellOptionArmor = playerEntity.GetShellsValues(EquipmentOptionType.ARMOR_SHELL, false); RingCellonValues = playerEntity.GetCellonValues(EquipmentType.Ring); NecklaceCellonValues = playerEntity.GetCellonValues(EquipmentType.Necklace); ; BraceletCellonValues = playerEntity.GetCellonValues(EquipmentType.Bracelet); Morale = playerEntity.Level; Position = new Position(playerEntity.PositionX, playerEntity.PositionY); MapInstance = playerEntity.MapInstance; MonsterRaceType = MonsterRaceType.People; MonsterRaceSubType = MonsterSubRace.People.Humanlike; MeleeDefense = playerEntity.MeleeDefence; RangeDefense = playerEntity.RangedDefence; MagicalDefense = playerEntity.MagicDefence; FamilyUpgrades = playerEntity.Family?.UpgradeValues ?? new Dictionary(); double decreaseMagicDamage = 1; double damageReduction = 1; if (playerEntity.Specialist != null && playerEntity.UseSp) { IncreaseJajamaruDamage = playerEntity.Specialist.ItemVNum == (short)ItemVnums.JAJAMARU_SP && playerEntity.MateComponent.GetTeamMember(x => x.MateType == MateType.Partner && x.MonsterVNum == (short)MonsterVnum.SAKURA) != null; int elementSl = playerEntity.SpecialistComponent.GetSlElement(); decreaseMagicDamage = elementSl switch { >= 20 and <= 49 => 0.95, >= 50 and <= 79 => 0.9, >= 80 and <= 99 => 0.85, >= 100 => 0.8, _ => decreaseMagicDamage }; int slDefense = playerEntity.SpecialistComponent.GetSlDefense(); damageReduction = slDefense switch { >= 10 and < 40 => 0.85, >= 40 and < 80 => 0.5, >= 80 and < 100 => 0.25, 100 => 0, _ => 1 }; } DecreaseMagicDamage = decreaseMagicDamage; MinimalDamageReduction = damageReduction; } public Dictionary ShellOptionArmor { get; } public Dictionary ShellOptionsWeapon { get; } public IReadOnlyDictionary RingCellonValues { get; } public IReadOnlyDictionary NecklaceCellonValues { get; } public IReadOnlyDictionary BraceletCellonValues { get; } public double MinimalDamageReduction { get; } public bool IncreaseJajamaruDamage { get; } public double DecreaseMagicDamage { get; } public IReadOnlyDictionary<(BCardType type, byte subType), List> BCards { get; } public IReadOnlyDictionary<(BCardType type, byte subType), List<(int casterLevel, BCardDTO bCard)>> BuffBCards { get; } public ISet BuffsById { get; } public IReadOnlyDictionary FamilyUpgrades { get; } public VisualType Type { get; } public long Id { get; } public IMapInstance MapInstance { get; } public MonsterRaceType MonsterRaceType { get; } public Enum MonsterRaceSubType { get; } public AttackType AttackType { get; } public ElementType Element { get; } public int ElementRate { get; } public int Morale { get; } public int Level { get; } public FactionType Faction { get; } public int DamageMinimum { get; } public int DamageMaximum { get; } public int AttackUpgrade { get; } public int DefenseUpgrade { get; } public int HitRate { get; } public int MaxHp { get; } public int MaxMp { get; } public int WeaponDamageMinimum { get; } public int WeaponDamageMaximum { get; } public int CriticalChance { get; } public int CriticalDamage { get; } public int FireResistance { get; } public int WaterResistance { get; } public int LightResistance { get; } public int ShadowResistance { get; } public int MeleeDefense { get; } public int MeleeDodge { get; } public int RangeDefense { get; } public int RangeDodge { get; } public int MagicalDefense { get; } public Position Position { get; } }