public static void HandleSummonAttack(Character chr, Packet packet)
        {
            if (!ParseAttackData(chr, packet, out AttackData ad, AttackTypes.Summon))
            {
                return;
            }

            var summonId = ad.SummonID;

            if (chr.Summons.GetSummon(summonId, out var summon))
            {
                //SendMagicAttack(chr, ad);
                SendSummonAttack(chr, summon, ad);
                var totalDamage = 0;
                foreach (var ai in ad.Attacks)
                {
                    try
                    {
                        var mob = chr.Field.GetMob(ai.MobMapId);

                        if (mob != null)
                        {
                            foreach (int amount in ai.Damages)
                            {
                                totalDamage += amount;
                                mob.GiveDamage(chr, amount);
                            }

                            var dead = mob.CheckDead(mob.Position, ai.HitDelay, chr.PrimaryStats.BuffMesoUP.N);

                            if (!dead)
                            {
                                switch (summon.SkillId)
                                {
                                case Constants.Ranger.Skills.SilverHawk:
                                case Constants.Sniper.Skills.GoldenEagle:
                                    var sld = CharacterSkills.GetSkillLevelData(summon.SkillId, summon.SkillLevel);
                                    if (!mob.IsBoss && totalDamage > 0 && Rand32.NextBetween(0, 100) < sld.Property)
                                    {
                                        int  stunTime   = ai.HitDelay + 4000;
                                        long expireTime = MasterThread.CurrentTime + stunTime;
                                        var  stat       = mob.Status.BuffStun.Set(summon.SkillId, -1, expireTime);
                                        MobPacket.SendMobStatsTempSet(mob, ai.HitDelay, stat);
                                    }
                                    break;
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Program.MainForm.LogAppend(ex.ToString());
                    }
                }
            }
        }
        public static void HandleMagicAttack(Character chr, Packet packet)
        {
            //Program.MainForm.LogAppend("Handling Magic");
            if (!ParseAttackData(chr, packet, out AttackData ad, AttackTypes.Magic))
            {
                return;
            }

            int    TotalDamage;
            double MaxSpellDamage;
            bool   died;
            Mob    mob;

            SendMagicAttack(chr, ad);


            if (ad.SkillID != 0)
            {
                chr.Skills.UseMeleeAttack(ad.SkillID, ad);
            }

            int StolenMP       = 0;
            int MpStealSkillID = chr.Skills.GetMpStealSkillData(2, out int MpStealProp, out int MpStealPercent, out byte MpStealLevel);

            foreach (var ai in ad.Attacks)
            {
                try
                {
                    TotalDamage = 0;
                    mob         = chr.Field.GetMob(ai.MobMapId);

                    if (mob == null)
                    {
                        continue;
                    }

                    foreach (int amount in ai.Damages)
                    {
                        mob.GiveDamage(chr, amount);
                        TotalDamage += amount;
                    }

                    if (MpStealPercent > 0)
                    {
                        StolenMP += mob.OnMobMPSteal(MpStealProp, MpStealPercent / ad.Targets);
                    }

                    if (TotalDamage == 0)
                    {
                        continue;
                    }

                    died = mob.CheckDead(ai.HitPosition, ai.HitDelay, chr.PrimaryStats.BuffMesoUP.N);

                    if (!died)
                    {
                        var  sld      = DataProvider.Skills[ad.SkillID].Levels[ad.SkillLevel];
                        long buffTime = sld.BuffTime * 1000;

                        //TODO refactor element code when we get the proper element loading with calcdamage branch
                        if ((sld.ElementFlags == SkillElement.Ice || ad.SkillID == Constants.ILMage.Skills.ElementComposition) && !mob.IsBoss)
                        {
                            var stat = mob.Status.BuffFreeze.Set(ad.SkillID, 1, MasterThread.CurrentTime + buffTime);
                            MobPacket.SendMobStatsTempSet(mob, ai.HitDelay, stat);
                        }

                        if (ad.SkillID == Constants.FPMage.Skills.ElementComposition && !mob.IsBoss)
                        {
                            if (Rand32.NextBetween(0, 100) < sld.Property)
                            {
                                mob.DoPoison(chr.ID, chr.Skills.GetSkillLevel(ad.SkillID), buffTime, ad.SkillID, sld.MagicAttack, ai.HitDelay);
                            }
                        }

                        if (ad.SkillID == Constants.FPWizard.Skills.PoisonBreath)
                        {
                            if (Rand32.NextBetween(0, 100) < sld.Property)
                            {
                                mob.DoPoison(chr.ID, chr.Skills.GetSkillLevel(ad.SkillID), buffTime, ad.SkillID, sld.MagicAttack, ai.HitDelay);
                            }
                        }

                        if (StolenMP > 0)
                        {
                            chr.ModifyMP((short)StolenMP);
                            MapPacket.SendPlayerSkillAnimSelf(chr, MpStealSkillID, MpStealLevel);
                            MapPacket.SendPlayerSkillAnim(chr, MpStealSkillID, MpStealLevel);
                        }
                    }

                    switch (ad.SkillID)
                    {
                    case Constants.Magician.Skills.MagicClaw:     // If the Spell is Magic Claw (since it registers two hits)
                        MaxSpellDamage = DamageFormula.MaximumSpellDamage(chr, mob, ad.SkillID) * 2;
                        break;

                    case Constants.Cleric.Skills.Heal:     // If the Spell is Heal (since it has a special snowflake calculation for it)
                        if (mob.Data.Undead == false)
                        {
                            chr.PermaBan("Heal damaging regular mobs exploit");
                            return;
                        }
                        MaxSpellDamage = DamageFormula.MaximumHealDamage(chr, mob, ad.Targets);
                        break;

                    default:
                        MaxSpellDamage = DamageFormula.MaximumSpellDamage(chr, mob, ad.SkillID);
                        break;
                    }

                    if (TotalDamage > MaxSpellDamage)
                    {
                        if (ReportDamagehack(chr, ad, TotalDamage, (int)MaxSpellDamage))
                        {
                            return;
                        }
                    }
                }

                catch (Exception ex)
                {
                    Program.MainForm.LogAppend(ex.ToString());
                }
            }
        }