public ushort GenerateDamage(IBattleEntity targetEntity, Skill skill, ref int hitmode, ref bool onyxEffect)
        {
            BattleEntity target = targetEntity?.BattleEntity;

            if (target == null)
            {
                return(0);
            }

            #region Definitions

            // Percent Damage
            if (target.Session is MapMonster monster && monster.IsPercentage && monster.TakesDamage > 0)
            {
                return((ushort)monster.TakesDamage);
            }

            AttackType attackType = Entity.GetAttackType(skill);

            int   morale     = Level + GetBuff(CardType.Morale, (byte)AdditionalTypes.Morale.MoraleIncreased)[0] - GetBuff(CardType.Morale, (byte)AdditionalTypes.Morale.MoraleDecreased)[0];
            short upgrade    = AttackUpgrade;
            int   critChance = Critical;
            int   critHit    = CriticalRate;
            int   minDmg     = MinDamage;
            int   maxDmg     = MaxDamage;
            int   hitRate    = HitRate;

            #endregion

            #region Get Weapon Stats

            if (Session is Character character)
            {
                if (skill == null)
                {
                    return(0);
                }
                if (skill.SkillVNum == 1085) // pas de bcard ...
                {
                    character.TeleportOnMap(targetEntity.GetPos().X, targetEntity.GetPos().Y);
                }
                if (character.Inventory.LoadBySlotAndType <WearableInstance>((byte)EquipmentType.Amulet, InventoryType.Equipment)?.Item?.Effect == 932)
                {
                    upgrade += 1;
                }
                DefenceUpgrade = character.Inventory?.Armor?.Upgrade ?? 0;

                if (CharacterHelper.Instance.GetClassAttackType(character.Class) == attackType)
                {
                    minDmg     += character.MinHit;
                    maxDmg     += character.MaxHit;
                    hitRate    += character.HitRate;
                    critChance += character.HitCriticalRate;
                    critHit    += character.HitCritical;
                    upgrade    += character.Inventory.PrimaryWeapon?.Upgrade ?? 0;
                }
                else
                {
                    minDmg     += character.MinDistance;
                    maxDmg     += character.MaxDistance;
                    hitRate    += character.DistanceRate;
                    critChance += character.DistanceCriticalRate;
                    critHit    += character.DistanceCritical;
                    upgrade    += character.Inventory.SecondaryWeapon?.Upgrade ?? 0;
                }
            }

            #endregion

            skill?.BCards?.ToList().ForEach(s => SkillBcards.Add(s));
            #region Switch skill.Type

            int targetDefence = target.GetBuff(CardType.Defence, (byte)AdditionalTypes.Defence.AllIncreased)[0]
                                - target.GetBuff(CardType.Defence, (byte)AdditionalTypes.Defence.AllDecreased)[0];

            byte targetDefenseUpgrade = (byte)(target.GetBuff(CardType.Defence, (byte)AdditionalTypes.Defence.DefenceLevelIncreased)[0]
                                               - target.GetBuff(CardType.Defence, (byte)AdditionalTypes.Defence.DefenceLevelDecreased)[0]);

            int targetDodge = target.GetBuff(CardType.DodgeAndDefencePercent, (byte)AdditionalTypes.DodgeAndDefencePercent.DodgeIncreased)[0]
                              - target.GetBuff(CardType.DodgeAndDefencePercent, (byte)AdditionalTypes.DodgeAndDefencePercent.DodgeDecreased)[0];

            int targetMorale = target.Level + target.GetBuff(CardType.Morale, (byte)AdditionalTypes.Morale.MoraleIncreased)[0]
                               - target.GetBuff(CardType.Morale, (byte)AdditionalTypes.Morale.MoraleDecreased)[0];

            int targetBoostpercentage = 0;

            int boost = GetBuff(CardType.AttackPower, (byte)AdditionalTypes.AttackPower.AllAttacksIncreased)[0]
                        - GetBuff(CardType.AttackPower, (byte)AdditionalTypes.AttackPower.AllAttacksDecreased)[0];

            int boostpercentage = GetBuff(CardType.Damage, (byte)AdditionalTypes.Damage.DamageIncreased)[0]
                                  - GetBuff(CardType.Damage, (byte)AdditionalTypes.Damage.DamageDecreased)[0];

            switch (attackType)
            {
            case AttackType.Close:
                targetDefence        += target.CloseDefence;
                targetDodge          += target.DefenceRate;
                targetBoostpercentage = target.GetBuff(CardType.Defence, (byte)AdditionalTypes.Defence.MeleeIncreased)[0]
                                        - target.GetBuff(CardType.Defence, (byte)AdditionalTypes.Defence.MeleeDecreased)[0];
                boost += GetBuff(CardType.AttackPower, (byte)AdditionalTypes.AttackPower.MeleeAttacksIncreased)[0]
                         - GetBuff(CardType.AttackPower, (byte)AdditionalTypes.AttackPower.MeleeAttacksDecreased)[0];
                boostpercentage += GetBuff(CardType.Damage, (byte)AdditionalTypes.Damage.MeleeIncreased)[0]
                                   - GetBuff(CardType.Damage, (byte)AdditionalTypes.Damage.MeleeDecreased)[0];
                break;

            case AttackType.Ranged:
                targetDefence        += target.RangedDefence;
                targetDodge          += target.DistanceDefenceRate;
                targetBoostpercentage = target.GetBuff(CardType.Defence, (byte)AdditionalTypes.Defence.RangedIncreased)[0]
                                        - target.GetBuff(CardType.Defence, (byte)AdditionalTypes.Defence.RangedDecreased)[0];
                boost += GetBuff(CardType.AttackPower, (byte)AdditionalTypes.AttackPower.RangedAttacksIncreased)[0]
                         - GetBuff(CardType.AttackPower, (byte)AdditionalTypes.AttackPower.RangedAttacksDecreased)[0];
                boostpercentage += GetBuff(CardType.Damage, (byte)AdditionalTypes.Damage.RangedIncreased)[0]
                                   - GetBuff(CardType.Damage, (byte)AdditionalTypes.Damage.RangedDecreased)[0];
                break;

            case AttackType.Magical:
                targetDefence        += target.MagicDefence;
                targetBoostpercentage = target.GetBuff(CardType.Defence, (byte)AdditionalTypes.Defence.MagicalIncreased)[0]
                                        - target.GetBuff(CardType.Defence, (byte)AdditionalTypes.Defence.MeleeDecreased)[0];
                boost += GetBuff(CardType.AttackPower, (byte)AdditionalTypes.AttackPower.MagicalAttacksIncreased)[0]
                         - GetBuff(CardType.AttackPower, (byte)AdditionalTypes.AttackPower.MagicalAttacksDecreased)[0];
                boostpercentage += GetBuff(CardType.Damage, (byte)AdditionalTypes.Damage.MagicalIncreased)[0]
                                   - GetBuff(CardType.Damage, (byte)AdditionalTypes.Damage.MagicalDecreased)[0];
                break;
            }
            targetDefence = (int)(targetDefence * (1 + targetBoostpercentage / 100D));
            minDmg       += boost;
            maxDmg       += boost;
            minDmg        = (int)(minDmg * (1 + boostpercentage / 100D));
            maxDmg        = (int)(maxDmg * (1 + boostpercentage / 100D));

            #endregion

            upgrade -= (short)(target.DefenceUpgrade + targetDefenseUpgrade);

            #region Detailed Calculation

            #region Dodge

            if (attackType != AttackType.Magical)
            {
                double multiplier = targetDodge / (hitRate + 1);
                if (multiplier > 5)
                {
                    multiplier = 5;
                }
                double chance = -0.25 * Math.Pow(multiplier, 3) - 0.57 * Math.Pow(multiplier, 2) + 25.3 * multiplier - 1.41;
                if (chance <= 1)
                {
                    chance = 1;
                }
                if (GetBuff(CardType.DodgeAndDefencePercent, (byte)AdditionalTypes.DodgeAndDefencePercent.DodgeIncreased)[0] != 0)
                {
                    chance = 10;
                }
                if (skill?.Type == 0 || skill?.Type == 1)
                {
                    if (ServerManager.Instance.RandomNumber() <= chance)
                    {
                        hitmode = 1;
                        SkillBcards.Clear();
                        return(0);
                    }
                }
            }

            #endregion

            #region Base Damage

            int baseDamage = ServerManager.Instance.RandomNumber(minDmg, maxDmg < minDmg ? minDmg + 1 : maxDmg) + morale - targetMorale;

            double upgradeBonus = 0;
            switch (Math.Abs(upgrade))
            {
            case 1:
                upgradeBonus = 0.1;
                break;

            case 2:
                upgradeBonus = 0.15;
                break;

            case 3:
                upgradeBonus = 0.22;
                break;

            case 4:
                upgradeBonus = 0.32;
                break;

            case 5:
                upgradeBonus = 0.43;
                break;

            case 6:
                upgradeBonus = 0.54;
                break;

            case 7:
                upgradeBonus = 0.65;
                break;

            case 8:
                upgradeBonus = 0.9;
                break;

            case 9:
                upgradeBonus = 1.2;
                break;

            case 10:
                upgradeBonus = 2;
                break;
            }
            if (upgrade < 0)
            {
                targetDefence += (int)(targetDefence * upgradeBonus);
            }
            else
            {
                baseDamage += (int)(baseDamage * upgradeBonus);
            }

            baseDamage -= target.HasBuff(CardType.SpecialDefence, (byte)AdditionalTypes.SpecialDefence.AllDefenceNullified) ? 0 : targetDefence;

            if (skill?.Type == 1 && Map.Map.GetDistance(Entity.GetPos(), targetEntity.GetPos()) < 4)
            {
                baseDamage = (int)(baseDamage * 0.85);
            }

            #endregion

            #region Elementary Damage

            #region Calculate Elemental Boost + Rate

            double elementalBoost   = 0;
            int    targetResistance = 0;
            int    elementalDamage  = GetBuff(CardType.Element, (byte)AdditionalTypes.Element.AllIncreased)[0] - GetBuff(CardType.Element, (byte)AdditionalTypes.Element.AllDecreased)[0];
            int    bonusrez         = target.GetBuff(CardType.ElementResistance, (byte)AdditionalTypes.ElementResistance.AllIncreased)[0] - target.GetBuff(CardType.ElementResistance, (byte)AdditionalTypes.ElementResistance.AllDecreased)[0];

            switch (Element)
            {
            case 1:
                bonusrez += target.GetBuff(CardType.ElementResistance, (byte)AdditionalTypes.ElementResistance.FireIncreased)[0]
                            - target.GetBuff(CardType.ElementResistance, (byte)AdditionalTypes.ElementResistance.FireDecreased)[0];
                elementalDamage += GetBuff(CardType.Element, (byte)AdditionalTypes.Element.FireIncreased)[0]
                                   - GetBuff(CardType.Element, (byte)AdditionalTypes.Element.FireDecreased)[0];
                targetResistance = target.FireResistance;
                switch (target.Element)
                {
                case 0:
                    elementalBoost = 1.3;         // Damage vs no element
                    break;

                case 1:
                    elementalBoost = 1;         // Damage vs fire
                    break;

                case 2:
                    elementalBoost = 2;         // Damage vs water
                    break;

                case 3:
                    elementalBoost = 1;         // Damage vs light
                    break;

                case 4:
                    elementalBoost = 1.5;         // Damage vs darkness
                    break;
                }
                break;

            case 2:
                bonusrez += target.GetBuff(CardType.ElementResistance, (byte)AdditionalTypes.ElementResistance.WaterIncreased)[0]
                            - target.GetBuff(CardType.ElementResistance, (byte)AdditionalTypes.ElementResistance.WaterDecreased)[0];
                elementalDamage += GetBuff(CardType.Element, (byte)AdditionalTypes.Element.WaterIncreased)[0]
                                   - GetBuff(CardType.Element, (byte)AdditionalTypes.Element.WaterDecreased)[0];
                targetResistance = target.WaterResistance;
                switch (target.Element)
                {
                case 0:
                    elementalBoost = 1.3;
                    break;

                case 1:
                    elementalBoost = 2;
                    break;

                case 2:
                    elementalBoost = 1;
                    break;

                case 3:
                    elementalBoost = 1.5;
                    break;

                case 4:
                    elementalBoost = 1;
                    break;
                }
                break;

            case 3:
                bonusrez += target.GetBuff(CardType.ElementResistance, (byte)AdditionalTypes.ElementResistance.LightIncreased)[0]
                            - target.GetBuff(CardType.ElementResistance, (byte)AdditionalTypes.ElementResistance.LightDecreased)[0];
                elementalDamage += GetBuff(CardType.Element, (byte)AdditionalTypes.Element.LightIncreased)[0]
                                   - GetBuff(CardType.Element, (byte)AdditionalTypes.Element.LightDecreased)[0];
                targetResistance = target.LightResistance;
                switch (target.Element)
                {
                case 0:
                    elementalBoost = 1.3;
                    break;

                case 1:
                    elementalBoost = 1.5;
                    break;

                case 2:
                    elementalBoost = 1;
                    break;

                case 3:
                    elementalBoost = 1;
                    break;

                case 4:
                    elementalBoost = 3;
                    break;
                }
                break;

            case 4:
                bonusrez += target.GetBuff(CardType.ElementResistance, (byte)AdditionalTypes.ElementResistance.DarkIncreased)[0]
                            - target.GetBuff(CardType.ElementResistance, (byte)AdditionalTypes.ElementResistance.DarkDecreased)[0];
                targetResistance = target.DarkResistance;
                elementalDamage += GetBuff(CardType.Element, (byte)AdditionalTypes.Element.DarkIncreased)[0]
                                   - GetBuff(CardType.Element, (byte)AdditionalTypes.Element.DarkDecreased)[0];
                switch (target.Element)
                {
                case 0:
                    elementalBoost = 1.3;
                    break;

                case 1:
                    elementalBoost = 1;
                    break;

                case 2:
                    elementalBoost = 1.5;
                    break;

                case 3:
                    elementalBoost = 3;
                    break;

                case 4:
                    elementalBoost = 1;
                    break;
                }
                break;
            }

            #endregion ;

            if (skill?.Element == 0)
            {
                switch (elementalBoost)
                {
                case 0.5:
                    elementalBoost = 0;
                    break;

                case 1:
                    elementalBoost = 0.05;
                    break;

                case 1.3:
                case 1.5:
                    elementalBoost = 0.15;
                    break;

                case 2:
                case 3:
                    elementalBoost = 0.2;
                    break;
                }
            }
            else if (skill?.Element != Element)
            {
                elementalBoost = 0;
            }
            int resistance = targetResistance + bonusrez;
            elementalDamage = (int)(elementalDamage + (baseDamage + 100) * ((ElementRate + ElementRateSp) / 100D));
            elementalDamage = (int)(elementalDamage / 100D * (100 - (resistance > 100 ? 100 : resistance)) * elementalBoost);

            #endregion

            #region Critical Damage

            critChance += GetBuff(CardType.Critical, (byte)AdditionalTypes.Critical.InflictingIncreased)[0]
                          - GetBuff(CardType.Critical, (byte)AdditionalTypes.Critical.InflictingReduced)[0];

            critHit += GetBuff(CardType.Critical, (byte)AdditionalTypes.Critical.DamageIncreased)[0]
                       - GetBuff(CardType.Critical, (byte)AdditionalTypes.Critical.DamageIncreasedInflictingReduced)[0];

            if (ServerManager.Instance.RandomNumber() <= critChance)
            {
                if (skill?.Type != 2 && attackType != AttackType.Magical)
                {
                    double multiplier = critHit / 100D;
                    multiplier  = multiplier > 3 ? 3 : multiplier;
                    baseDamage += (int)(baseDamage * multiplier);
                    hitmode     = 3;
                }
            }


            #endregion

            // OFFENSIVE POTION
            baseDamage += (int)(baseDamage * GetBuff(CardType.Item, (byte)AdditionalTypes.Item.AttackIncreased)[0] / 100D);

            if (Session is Character charact)
            {
                int[] weaponSoftDamage = charact.GetWeaponSoftDamage();
                if (ServerManager.Instance.RandomNumber() < weaponSoftDamage[0])
                {
                    charact.MapInstance.Broadcast(charact.GenerateEff(15));
                    baseDamage += (int)(baseDamage * (1 + (weaponSoftDamage[1] / 100D)));
                }

                if (charact.HasBuff(CardType.IncreaseDamage, (byte)AdditionalTypes.IncreaseDamage.IncreasingPropability, true))
                {
                    charact.MapInstance.Broadcast(charact.GenerateEff(15));
                    baseDamage += (int)(baseDamage * (1 + GetBuff(CardType.IncreaseDamage,
                                                                  (byte)AdditionalTypes.IncreaseDamage
                                                                  .IncreasingPropability)[0] / 100D));
                }

                if (charact.ChargeValue > 0)
                {
                    baseDamage         += charact.ChargeValue;
                    charact.ChargeValue = 0;
                    charact.RemoveBuff(0);
                }
                baseDamage += charact.Class == ClassType.Adventurer ? 20 : 0;
            }

            #region Total Damage

            int totalDamage = baseDamage + elementalDamage;
            totalDamage = totalDamage < 5 ? ServerManager.Instance.RandomNumber(1, 6) : totalDamage;

            #endregion

            if (Session is MapMonster)
            {
                if (Level < 45)
                {
                    //no minimum damage
                }
                else if (Level < 55)
                {
                    totalDamage += Level;
                }
                else if (Level < 60)
                {
                    totalDamage += Level * 2;
                }
                else if (Level < 65)
                {
                    totalDamage += Level * 3;
                }
                else if (Level < 70)
                {
                    totalDamage += Level * 4;
                }
                else
                {
                    totalDamage += Level * 5;
                }
            }

            if (targetEntity.GetSession() is Character chara && target.HasBuff(CardType.NoDefeatAndNoDamage, (byte)AdditionalTypes.NoDefeatAndNoDamage.TransferAttackPower))
            {
                chara.ChargeValue = totalDamage;
                chara.AddBuff(new Buff.Buff(0));
                totalDamage = 0;
                hitmode     = 1;
            }

            #endregion

            totalDamage = totalDamage > ushort.MaxValue ? ushort.MaxValue : totalDamage;

            #region Onyx Wings

            onyxEffect = GetBuff(CardType.StealBuff, (byte)AdditionalTypes.StealBuff.ChanceSummonOnyxDragon)[0] > ServerManager.Instance.RandomNumber();

            #endregion

            SkillBcards.Clear();
            totalDamage = totalDamage > ushort.MaxValue ? ushort.MaxValue : totalDamage;
            if (Session is Character charac && targetEntity is MapMonster cali && cali.MonsterVNum == 2305 && Caligor.IsRunning)
            {
                switch (charac.Faction)
                {
                case FactionType.Angel:
                    Caligor.AngelDamage += totalDamage + (onyxEffect ? totalDamage / 2 : 0);
                    break;

                case FactionType.Demon:
                    Caligor.DemonDamage += totalDamage + (onyxEffect ? totalDamage / 2 : 0);
                    break;
                }
            }
            return((ushort)totalDamage);
        }
Example #2
0
        public void ApplyBCards(IBattleEntity session, IBattleEntity caster = null)
        {
            Mate mate;

            switch ((BCardType.CardType)Type)
            {
            case BCardType.CardType.Buff:
                if (ServerManager.Instance.RandomNumber() < FirstData)
                {
                    session?.BattleEntity.AddBuff(new Buff(SecondData, caster?.BattleEntity.Level ?? session.BattleEntity.Level));
                }
                break;

            case BCardType.CardType.Move:
                if (session.GetSession() is Character chara)
                {
                    chara.LastSpeedChange = DateTime.Now;
                    chara.LoadSpeed();
                    chara?.Session.SendPacket(chara.GenerateCond());
                }
                break;

            case BCardType.CardType.Summons:
                NpcMonster npcMonster = session.GetSession() is MapMonster mob ? mob.Monster : session.GetSession() is MapNpc npc ? npc.Npc : null;
                ConcurrentBag <ToSummon> summonParameters = new ConcurrentBag <ToSummon>();

                switch ((AdditionalTypes.Summons)SubType)
                {
                case AdditionalTypes.Summons.Summons:
                    for (int i = 0; i < FirstData; i++)
                    {
                        MapCell cell = session.GetPos();
                        cell.Y += (short)ServerManager.Instance.RandomNumber(-3, 3);
                        cell.X += (short)ServerManager.Instance.RandomNumber(-3, 3);
                        summonParameters.Add(new ToSummon((short)SecondData, cell, null, true, (byte)Math.Abs(ThirdData)));
                    }
                    EventHelper.Instance.RunEvent(new EventContainer(session.MapInstance, EventActionType.SPAWNMONSTERS, summonParameters));
                    break;

                case AdditionalTypes.Summons.SummonTrainingDummy:
                    if (npcMonster != null && session.BattleEntity.OnHitEvents.All(s => s?.EventActionType != EventActionType.SPAWNMONSTERS))
                    {
                        summonParameters.Add(new ToSummon((short)SecondData, session.GetPos(), null, true, (byte)Math.Abs(ThirdData)));
                        session.BattleEntity.OnHitEvents.Add(new EventContainer(session.MapInstance, EventActionType.SPAWNMONSTERS, summonParameters));
                    }
                    break;

                case AdditionalTypes.Summons.SummonUponDeathChance:
                case AdditionalTypes.Summons.SummonUponDeath:
                    if (npcMonster != null && session.BattleEntity.OnDeathEvents.All(s => s?.EventActionType != EventActionType.SPAWNMONSTERS))
                    {
                        for (int i = 0; i < FirstData; i++)
                        {
                            MapCell cell = session.GetPos();
                            cell.Y += (short)i;
                            summonParameters.Add(new ToSummon((short)SecondData, cell, null, true, (byte)Math.Abs(ThirdData)));
                        }
                        session.BattleEntity.OnDeathEvents.Add(new EventContainer(session.MapInstance, EventActionType.SPAWNMONSTERS, summonParameters));
                    }
                    break;

                default:
                    break;
                }
                break;

            case BCardType.CardType.SpecialAttack:
                break;

            case BCardType.CardType.SpecialDefence:
                break;

            case BCardType.CardType.AttackPower:
                break;

            case BCardType.CardType.Target:
                break;

            case BCardType.CardType.Critical:
                break;

            case BCardType.CardType.SpecialCritical:
                break;

            case BCardType.CardType.Element:
                break;

            case BCardType.CardType.IncreaseDamage:
                break;

            case BCardType.CardType.Defence:
                break;

            case BCardType.CardType.DodgeAndDefencePercent:
                break;

            case BCardType.CardType.Block:
                break;

            case BCardType.CardType.Absorption:
                break;

            case BCardType.CardType.ElementResistance:
                break;

            case BCardType.CardType.EnemyElementResistance:
                break;

            case BCardType.CardType.Damage:
                break;

            case BCardType.CardType.GuarantedDodgeRangedAttack:
                break;

            case BCardType.CardType.Morale:
                break;

            case BCardType.CardType.Casting:
                break;

            case BCardType.CardType.Reflection:
                break;

            case BCardType.CardType.DrainAndSteal:
                break;

            case BCardType.CardType.HealingBurningAndCasting:
                var       subtype = (AdditionalTypes.HealingBurningAndCasting)SubType;
                Character sess;
                switch (subtype)
                {
                case AdditionalTypes.HealingBurningAndCasting.RestoreHP:
                case AdditionalTypes.HealingBurningAndCasting.RestoreHPWhenCasting:
                    if (session.GetSession() is Character)
                    {
                        sess = (Character)session.GetSession();
                        int  heal   = FirstData;
                        bool change = false;
                        if (IsLevelScaled)
                        {
                            if (IsLevelDivided)
                            {
                                heal /= sess.Level;
                            }
                            else
                            {
                                heal *= sess.Level;
                            }
                        }
                        if (sess.Hp + heal < sess.HpLoad())
                        {
                            sess.Hp += heal;
                            sess.Session?.CurrentMapInstance?.Broadcast(sess.GenerateRc(heal));
                            change = true;
                        }
                        else
                        {
                            if (sess.Hp != (int)sess.HpLoad())
                            {
                                sess.Session?.CurrentMapInstance?.Broadcast(sess.GenerateRc((int)(sess.HpLoad() - sess.Hp)));
                                change = true;
                            }
                            sess.Hp = (int)sess.HpLoad();
                        }
                        if (change)
                        {
                            sess.Session?.SendPacket(sess.GenerateStat());
                        }
                    }

                    if (session.GetSession() is Mate)
                    {
                        mate = (Mate)session.GetSession();
                        int heal = FirstData;
                        if (IsLevelScaled)
                        {
                            if (IsLevelDivided)
                            {
                                heal /= mate.Level;
                            }
                            else
                            {
                                heal *= mate.Level;
                            }
                        }
                        if (mate.Hp + heal < mate.HpLoad())
                        {
                            mate.Hp += heal;
                        }
                        else
                        {
                            mate.Hp = mate.HpLoad();
                        }
                    }

                    break;

                case AdditionalTypes.HealingBurningAndCasting.RestoreMP:
                    if (session.GetSession() is Character)
                    {
                        sess = (Character)session.GetSession();
                        int  heal   = FirstData;
                        bool change = false;
                        if (IsLevelScaled)
                        {
                            if (IsLevelDivided)
                            {
                                heal /= sess.Level;
                            }
                            else
                            {
                                heal *= sess.Level;
                            }
                        }
                        if (sess.Mp + heal < sess.MpLoad())
                        {
                            sess.Mp += heal;
                            change   = true;
                        }
                        else
                        {
                            if (sess.Mp != (int)sess.MpLoad())
                            {
                                change = true;
                            }
                            sess.Mp = (int)sess.MpLoad();
                        }
                        if (change)
                        {
                            sess.Session?.SendPacket(sess.GenerateStat());
                        }
                    }

                    if (session.GetSession() is Mate)
                    {
                        mate = (Mate)session.GetSession();
                        int heal = FirstData;
                        if (IsLevelScaled)
                        {
                            if (IsLevelDivided)
                            {
                                heal /= mate.Level;
                            }
                            else
                            {
                                heal *= mate.Level;
                            }
                        }
                        if (mate.Mp + heal < mate.MpLoad())
                        {
                            mate.Mp += heal;
                        }
                        else
                        {
                            mate.Mp = mate.MpLoad();
                        }
                    }
                    break;
                }
                break;

            case BCardType.CardType.HPMP:
                break;

            case BCardType.CardType.SpecialisationBuffResistance:
                break;

            case BCardType.CardType.SpecialEffects:
                break;

            case BCardType.CardType.Capture:
                if (session is MapMonster monsterToCapture && caster is Character hunter)
                {
                    if (monsterToCapture.Monster.RaceType == 1 && (hunter.MapInstance.MapInstanceType == MapInstanceType.BaseMapInstance || hunter.MapInstance.MapInstanceType == MapInstanceType.TimeSpaceInstance))
                    {
                        if (monsterToCapture.Monster.Level < hunter.Level)
                        {
                            if (monsterToCapture.CurrentHp < (monsterToCapture.Monster.MaxHP / 2))
                            {
                                if (hunter.MaxMateCount > hunter.Mates.Count())
                                {
                                    // Algo
                                    int capturerate = 100 - (monsterToCapture.CurrentHp / monsterToCapture.Monster.MaxHP + 1) / 2;
                                    if (ServerManager.Instance.RandomNumber() <= capturerate)
                                    {
                                        if (hunter.Quests.Any(q => q.Quest.QuestType == (int)QuestType.Capture1 && q.Quest.QuestObjectives.Any(d => d.Data == monsterToCapture.MonsterVNum)))
                                        {
                                            hunter.IncrementQuests(QuestType.Capture1, monsterToCapture.MonsterVNum);
                                            return;
                                        }
                                        hunter.IncrementQuests(QuestType.Capture2, monsterToCapture.MonsterVNum);
                                        int  level       = monsterToCapture.Monster.Level - 15 < 1 ? 1 : monsterToCapture.Monster.Level - 15;
                                        Mate currentmate = hunter.Mates?.FirstOrDefault(m => m.IsTeamMember && m.MateType == MateType.Pet);
                                        if (currentmate != null)
                                        {
                                            currentmate.RemoveTeamMember();     // remove current pet
                                            hunter.MapInstance.Broadcast(currentmate.GenerateOut());
                                        }
                                        monsterToCapture.MapInstance.DespawnMonster(monsterToCapture);
                                        NpcMonster mateNpc = ServerManager.Instance.GetNpc(monsterToCapture.MonsterVNum);
                                        mate = new Mate(hunter, mateNpc, (byte)level, MateType.Pet);
                                        hunter.Mates?.Add(mate);
                                        mate.RefreshStats();
                                        hunter.Session.SendPacket($"ctl 2 {mate.PetId} 3");
                                        hunter.MapInstance.Broadcast(mate.GenerateIn());
                                        hunter.Session.SendPacket(hunter.GenerateSay(string.Format(Language.Instance.GetMessageFromKey("YOU_GET_PET"), mate.Name), 0));
                                        hunter.Session.SendPacket(UserInterfaceHelper.Instance.GeneratePClear());
                                        hunter.Session.SendPackets(hunter.GenerateScP());
                                        hunter.Session.SendPackets(hunter.GenerateScN());
                                        hunter.Session.SendPacket(hunter.GeneratePinit());
                                        hunter.Session.SendPackets(hunter.Mates.Where(s => s.IsTeamMember)
                                                                   .OrderBy(s => s.MateType)
                                                                   .Select(s => s.GeneratePst()));
                                    }
                                    else
                                    {
                                        hunter.Session.SendPacket(UserInterfaceHelper.Instance.GenerateMsg(Language.Instance.GetMessageFromKey("CAPTURE_FAILED"), 0));
                                    }
                                }
                                else
                                {
                                    hunter.Session.SendPacket(UserInterfaceHelper.Instance.GenerateMsg(Language.Instance.GetMessageFromKey("MAX_MATES_COUNT"), 0));
                                }
                            }
                            else
                            {
                                hunter.Session.SendPacket(UserInterfaceHelper.Instance.GenerateMsg(Language.Instance.GetMessageFromKey("monsterToCapture_MUST_BE_LOW_HP"), 0));
                            }
                        }
                        else
                        {
                            hunter.Session.SendPacket(UserInterfaceHelper.Instance.GenerateMsg(Language.Instance.GetMessageFromKey("monsterToCapture_LVL_MUST_BE_LESS"), 0));
                        }
                    }
                    else
                    {
                        hunter.Session.SendPacket(UserInterfaceHelper.Instance.GenerateMsg(Language.Instance.GetMessageFromKey("monsterToCapture_CANNOT_BE_CAPTURED"), 0));
                    }
                }
                break;

            case BCardType.CardType.SpecialDamageAndExplosions:
                break;

            case BCardType.CardType.SpecialEffects2:
                break;

            case BCardType.CardType.CalculatingLevel:
                break;

            case BCardType.CardType.Recovery:
                break;

            case BCardType.CardType.MaxHPMP:
                break;

            case BCardType.CardType.MultAttack:
                break;

            case BCardType.CardType.MultDefence:
                break;

            case BCardType.CardType.TimeCircleSkills:
                break;

            case BCardType.CardType.RecoveryAndDamagePercent:
                break;

            case BCardType.CardType.Count:
                break;

            case BCardType.CardType.NoDefeatAndNoDamage:
                break;

            case BCardType.CardType.SpecialActions:
                if (session.GetSession() is Character charact)
                {
                    if (SubType.Equals((byte)AdditionalTypes.SpecialActions.Hide))
                    {
                        charact.Invisible = true;
                        charact.Mates.Where(s => s.IsTeamMember).ToList().ForEach(s => charact.Session.CurrentMapInstance?.Broadcast(s.GenerateOut()));
                        charact.Session.CurrentMapInstance?.Broadcast(charact.GenerateInvisible());
                    }
                }
                break;

            case BCardType.CardType.Mode:
                break;

            case BCardType.CardType.NoCharacteristicValue:
                break;

            case BCardType.CardType.LightAndShadow:
                break;

            case BCardType.CardType.Item:
                break;

            case BCardType.CardType.DebuffResistance:
                break;

            case BCardType.CardType.SpecialBehaviour:
                break;

            case BCardType.CardType.Quest:
                break;

            case BCardType.CardType.SecondSPCard:
                break;

            case BCardType.CardType.SPCardUpgrade:
                break;

            case BCardType.CardType.HugeSnowman:
                break;

            case BCardType.CardType.Drain:
                break;

            case BCardType.CardType.BossMonstersSkill:
                break;

            case BCardType.CardType.LordHatus:
                break;

            case BCardType.CardType.LordCalvinas:
                break;

            case BCardType.CardType.SESpecialist:
                break;

            case BCardType.CardType.FourthGlacernonFamilyRaid:
                break;

            case BCardType.CardType.SummonedMonsterAttack:
                break;

            case BCardType.CardType.BearSpirit:
                break;

            case BCardType.CardType.SummonSkill:
                break;

            case BCardType.CardType.InflictSkill:
                break;

            case BCardType.CardType.HideBarrelSkill:
                break;

            case BCardType.CardType.FocusEnemyAttentionSkill:
                break;

            case BCardType.CardType.TauntSkill:
                break;

            case BCardType.CardType.FireCannoneerRangeBuff:
                break;

            case BCardType.CardType.VulcanoElementBuff:
                break;

            case BCardType.CardType.DamageConvertingSkill:
                break;

            case BCardType.CardType.MeditationSkill:
                if (session.GetSession().GetType() == typeof(Character))
                {
                    if (SubType.Equals((byte)AdditionalTypes.MeditationSkill.CausingChance))
                    {
                        if (ServerManager.Instance.RandomNumber() < FirstData)
                        {
                            if (!(session is Character character))
                            {
                                break;
                            }
                            if (SkillVNum.HasValue)
                            {
                                character.LastSkillCombo = DateTime.Now;
                                Skill skill    = ServerManager.Instance.GetSkill(SkillVNum.Value);
                                Skill newSkill = ServerManager.Instance.GetSkill((short)SecondData);
                                Observable.Timer(TimeSpan.FromMilliseconds(100)).Subscribe(observer =>
                                {
                                    foreach (QuicklistEntryDTO qe in character.QuicklistEntries.Where(s =>
                                                                                                      s.Pos.Equals(skill.CastId)))
                                    {
                                        character.Session.SendPacket(
                                            $"qset {qe.Q1} {qe.Q2} {qe.Type}.{qe.Slot}.{newSkill.CastId}.0");
                                    }
                                    character.Session.SendPacket($"mslot {newSkill.CastId} -1");
                                });

                                if (skill.CastId > 10)
                                {
                                    // HACK this way
                                    Observable.Timer(TimeSpan.FromMilliseconds(skill.Cooldown * 100 + 500))
                                    .Subscribe(observer =>
                                    {
                                        character.Session.SendPacket($"sr {skill.CastId}");
                                    });
                                }
                            }
                        }
                    }
                    else
                    {
                        if (!(session is Character character))
                        {
                            break;
                        }
                        switch (SubType)
                        {
                        case 21:
                            character.MeditationDictionary[(short)SecondData] = DateTime.Now.AddSeconds(4);
                            break;

                        case 31:
                            character.MeditationDictionary[(short)SecondData] = DateTime.Now.AddSeconds(8);
                            break;

                        case 41:
                            character.MeditationDictionary[(short)SecondData] = DateTime.Now.AddSeconds(12);
                            break;
                        }
                    }
                }
                break;

            case BCardType.CardType.FalconSkill:
                break;

            case BCardType.CardType.AbsorptionAndPowerSkill:
                break;

            case BCardType.CardType.LeonaPassiveSkill:
                break;

            case BCardType.CardType.FearSkill:
                break;

            case BCardType.CardType.SniperAttack:
                break;

            case BCardType.CardType.FrozenDebuff:
                break;

            case BCardType.CardType.JumpBackPush:
                break;

            case BCardType.CardType.FairyXPIncrease:
                break;

            case BCardType.CardType.SummonAndRecoverHP:
                break;

            case BCardType.CardType.TeamArenaBuff:
                break;

            case BCardType.CardType.ArenaCamera:
                break;

            case BCardType.CardType.DarkCloneSummon:
                break;

            case BCardType.CardType.AbsorbedSpirit:
                break;

            case BCardType.CardType.AngerSkill:
                break;

            case BCardType.CardType.MeteoriteTeleport:
                break;

            case BCardType.CardType.StealBuff:
                break;

            default:
                Logger.Error(new ArgumentOutOfRangeException($"Card Type {Type} not defined!"));
                //throw new ArgumentOutOfRangeException();
                break;
            }
        }