private void ExecuteHandler(ClientSession session)
        {
            Mate mate = session.Character.Mates.Find(s => s.MateTransportId == PetId);

            if (mate != null)
            {
                session.CurrentMapInstance.Broadcast(StaticPacketHelper.Say(UserType.Npc, mate.MateTransportId, 2, Message));
            }
        }
Exemplo n.º 2
0
        private void npcLife()
        {
            // Respawn
            if (CurrentHp <= 0 && ShouldRespawn != null && !ShouldRespawn.Value)
            {
                MapInstance.RemoveNpc(this);
                MapInstance.Broadcast(GenerateOut());
            }

            if (!IsAlive && ShouldRespawn != null && ShouldRespawn.Value)
            {
                double timeDeath = (DateTime.Now - Death).TotalSeconds;
                if (timeDeath >= Npc.RespawnTime / 10d)
                {
                    Respawn();
                }
            }

            if (LastProtectedEffect.AddMilliseconds(6000) <= DateTime.Now)
            {
                LastProtectedEffect = DateTime.Now;
                if (IsMate || IsProtected)
                {
                    MapInstance.Broadcast(StaticPacketHelper.GenerateEff(UserType.Npc, MapNpcId, 825), MapX, MapY);
                }
            }

            double time = (DateTime.Now - LastEffect).TotalMilliseconds;

            if (EffectDelay > 0)
            {
                if (time > EffectDelay)
                {
                    if (Effect > 0 && EffectActivated)
                    {
                        MapInstance.Broadcast(StaticPacketHelper.GenerateEff(UserType.Npc, MapNpcId, Effect), MapX, MapY);
                    }

                    LastEffect = DateTime.Now;
                }
            }

            time = (DateTime.Now - LastSay).Seconds;
            if (Delay != 0)
            {
                if (time > Delay)
                {
                    if (Say != null)
                    {
                        MapInstance.Broadcast(StaticPacketHelper.Say(2, MapNpcId, 0, $"{Say}"));
                        LastSay = DateTime.Now;
                    }
                }
            }

            time = (DateTime.Now - LastMove).TotalMilliseconds;
            if (Target == -1 && IsMoving && Npc.Speed > 0 && time > _movetime && !HasBuff(CardType.Move, (byte)AdditionalTypes.Move.MovementImpossible))
            {
                _movetime = ServerManager.RandomNumber(500, 3000);
                int maxindex = Path.Count > Npc.Speed / 2 && Npc.Speed > 1 ? Npc.Speed / 2 : Path.Count;
                if (maxindex < 1)
                {
                    maxindex = 1;
                }
                if (Path.Count == 0 || Path.Count >= maxindex && maxindex > 0 && Path[maxindex - 1] == null)
                {
                    short xoffset = (short)ServerManager.RandomNumber(-1, 1);
                    short yoffset = (short)ServerManager.RandomNumber(-1, 1);

                    MapCell moveToPosition = new MapCell {
                        X = FirstX, Y = FirstY
                    };
                    if (RunToX != 0 || RunToY != 0)
                    {
                        moveToPosition = new MapCell {
                            X = RunToX, Y = RunToY
                        };
                        _movetime = ServerManager.RandomNumber(300, 1200);
                    }
                    Path = BestFirstSearch.FindPathJagged(new GridPos {
                        X = MapX, Y = MapY
                    }, new GridPos {
                        X = (short)ServerManager.RandomNumber(moveToPosition.X - 3, moveToPosition.X + 3), Y = (short)ServerManager.RandomNumber(moveToPosition.Y - 3, moveToPosition.Y + 3)
                    }, MapInstance.Map.JaggedGrid);
                    maxindex = Path.Count > Npc.Speed / 2 && Npc.Speed > 1 ? Npc.Speed / 2 : Path.Count;
                }
                if (DateTime.Now > LastMove && Npc.Speed > 0 && Path.Count > 0)
                {
                    byte speedIndex = (byte)(Npc.Speed / 2.5 < 1 ? 1 : Npc.Speed / 2.5);
                    maxindex = Path.Count > speedIndex ? speedIndex : Path.Count;
                    short mapX = (short)ServerManager.RandomNumber(Path[maxindex - 1].X - 1, Path[maxindex - 1].X + 1);
                    short mapY = (short)_random.Next(Path[maxindex - 1].Y - 1, Path[maxindex - 1].Y + 1);

                    //short mapX = Path[maxindex - 1].X;
                    //short mapY = Path[maxindex - 1].Y;
                    double waitingtime = Map.GetDistance(new MapCell {
                        X = mapX, Y = mapY
                    }, new MapCell {
                        X = MapX, Y = MapY
                    }) / (double)Npc.Speed;
                    MapInstance.Broadcast(new BroadcastPacket(null, PacketFactory.Serialize(StaticPacketHelper.Move(UserType.Npc, MapNpcId, mapX, mapY, Npc.Speed)), ReceiverType.All, xCoordinate: mapX, yCoordinate: mapY));
                    LastMove = DateTime.Now.AddSeconds(waitingtime > 1 ? 1 : waitingtime);

                    Observable.Timer(TimeSpan.FromMilliseconds((int)((waitingtime > 1 ? 1 : waitingtime) * 1000))).Subscribe(x =>
                    {
                        MapX = mapX;
                        MapY = mapY;
                    });

                    Path.RemoveRange(0, maxindex);
                }
            }
            if (Target == -1)
            {
                if (IsHostile && Shop == null)
                {
                    MapMonster    monster = MapInstance.GetMonsterInRangeList(MapX, MapY, (byte)(Npc.NoticeRange > 5 ? Npc.NoticeRange / 2 : Npc.NoticeRange)).Where(s => BattleEntity.CanAttackEntity(s.BattleEntity)).FirstOrDefault();
                    ClientSession session = MapInstance.Sessions.FirstOrDefault(s => BattleEntity.CanAttackEntity(s.Character.BattleEntity) && MapInstance == s.Character.MapInstance && Map.GetDistance(new MapCell {
                        X = MapX, Y = MapY
                    }, new MapCell {
                        X = s.Character.PositionX, Y = s.Character.PositionY
                    }) < Npc.NoticeRange);

                    if (monster != null)
                    {
                        Target = monster.MapMonsterId;
                    }
                    if (session?.Character != null)
                    {
                        Target = session.Character.CharacterId;
                    }
                }
            }
            else if (Target != -1)
            {
                MapMonster monster = MapInstance.Monsters.Find(s => s.MapMonsterId == Target);
                if (monster == null || monster.CurrentHp < 1)
                {
                    Target = -1;
                    return;
                }
                NpcMonsterSkill npcMonsterSkill = null;
                if (ServerManager.RandomNumber(0, 10) > 8)
                {
                    npcMonsterSkill = Skills.Where(s => (DateTime.Now - s.LastSkillUse).TotalMilliseconds >= 100 * s.Skill.Cooldown).OrderBy(rnd => _random.Next()).FirstOrDefault();
                }
                int  hitmode   = 0;
                bool onyxWings = false;
                int  damage    = DamageHelper.Instance.CalculateDamage(new BattleEntity(this), new BattleEntity(monster), npcMonsterSkill?.Skill, ref hitmode, ref onyxWings);
                if (monster.Monster.BCards.Find(s => s.Type == (byte)CardType.LightAndShadow && s.SubType == (byte)AdditionalTypes.LightAndShadow.InflictDamageToMP) is BCard card)
                {
                    int reduce = damage / 100 * card.FirstData;
                    if (monster.CurrentMp < reduce)
                    {
                        reduce            = (int)monster.CurrentMp;
                        monster.CurrentMp = 0;
                    }
                    else
                    {
                        monster.DecreaseMp(reduce);
                    }
                    damage -= reduce;
                }
                int distance = Map.GetDistance(new MapCell {
                    X = MapX, Y = MapY
                }, new MapCell {
                    X = monster.MapX, Y = monster.MapY
                });
                if (monster.CurrentHp > 0 && ((npcMonsterSkill != null && distance < npcMonsterSkill.Skill.Range) || distance <= Npc.BasicRange) && !HasBuff(CardType.SpecialAttack, (byte)AdditionalTypes.SpecialAttack.NoAttack))
                {
                    if (((DateTime.Now - LastSkill).TotalMilliseconds >= 1000 + (Npc.BasicCooldown * 200) /* && Skills.Count == 0*/) || npcMonsterSkill != null)
                    {
                        if (npcMonsterSkill != null)
                        {
                            npcMonsterSkill.LastSkillUse = DateTime.Now;
                            MapInstance.Broadcast(StaticPacketHelper.CastOnTarget(UserType.Npc, MapNpcId, UserType.Monster, Target, npcMonsterSkill.Skill.CastAnimation, npcMonsterSkill.Skill.CastEffect, npcMonsterSkill.Skill.SkillVNum));
                        }

                        if (npcMonsterSkill != null && npcMonsterSkill.Skill.CastEffect != 0)
                        {
                            MapInstance.Broadcast(StaticPacketHelper.GenerateEff(UserType.Npc, MapNpcId, Effect));
                        }
                        monster.BattleEntity.GetDamage(damage, BattleEntity);
                        lock (monster.DamageList)
                        {
                            if (!monster.DamageList.Any(s => s.Key.MapEntityId == MapNpcId))
                            {
                                monster.AddToAggroList(BattleEntity);
                            }
                        }
                        MapInstance.Broadcast(npcMonsterSkill != null
                            ? StaticPacketHelper.SkillUsed(UserType.Npc, MapNpcId, 3, Target, npcMonsterSkill.SkillVNum, npcMonsterSkill.Skill.Cooldown, npcMonsterSkill.Skill.AttackAnimation, npcMonsterSkill.Skill.Effect, 0, 0, monster.CurrentHp > 0, (int)((float)monster.CurrentHp / (float)monster.MaxHp * 100), damage, hitmode, 0)
                            : StaticPacketHelper.SkillUsed(UserType.Npc, MapNpcId, 3, Target, 0, Npc.BasicCooldown, 11, Npc.BasicSkill, 0, 0, monster.CurrentHp > 0, (int)((float)monster.CurrentHp / (float)monster.MaxHp * 100), damage, hitmode, 0));
                        LastSkill = DateTime.Now;

                        if (npcMonsterSkill?.Skill.TargetType == 1 && npcMonsterSkill?.Skill.HitType == 2)
                        {
                            IEnumerable <ClientSession> clientSessions =
                                MapInstance.Sessions?.Where(s =>
                                                            s.Character.IsInRange(MapX,
                                                                                  MapY, npcMonsterSkill.Skill.TargetRange));
                            IEnumerable <Mate> mates = MapInstance.GetListMateInRange(MapX, MapY, npcMonsterSkill.Skill.TargetRange);

                            foreach (BCard skillBcard in npcMonsterSkill.Skill.BCards)
                            {
                                if (skillBcard.Type == 25 && skillBcard.SubType == 1 && new Buff((short)skillBcard.SecondData, Npc.Level)?.Card?.BuffType == BuffType.Good)
                                {
                                    if (clientSessions != null)
                                    {
                                        foreach (ClientSession clientSession in clientSessions)
                                        {
                                            if (clientSession.Character != null)
                                            {
                                                if (!BattleEntity.CanAttackEntity(clientSession.Character.BattleEntity))
                                                {
                                                    skillBcard.ApplyBCards(clientSession.Character.BattleEntity, BattleEntity);
                                                }
                                            }
                                        }
                                    }
                                    if (mates != null)
                                    {
                                        foreach (Mate mate in mates)
                                        {
                                            if (!BattleEntity.CanAttackEntity(mate.BattleEntity))
                                            {
                                                skillBcard.ApplyBCards(mate.BattleEntity, BattleEntity);
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        if (monster.CurrentHp < 1 && monster.SetDeathStatement())
                        {
                            monster.RunDeathEvent();
                            RemoveTarget();
                        }
                    }
                }
                else
                {
                    int maxdistance = Npc.NoticeRange > 5 ? Npc.NoticeRange / 2 : Npc.NoticeRange;
                    if (IsMoving && !HasBuff(CardType.Move, (byte)AdditionalTypes.Move.MovementImpossible))
                    {
                        const short maxDistance = 5;
                        int         maxindex    = Path.Count > Npc.Speed / 2 && Npc.Speed > 1 ? Npc.Speed / 2 : Path.Count;
                        if (maxindex < 1)
                        {
                            maxindex = 1;
                        }
                        if ((Path.Count == 0 && distance >= 1 && distance < maxDistance) || (Path.Count >= maxindex && maxindex > 0 && Path[maxindex - 1] == null))
                        {
                            short xoffset = (short)ServerManager.RandomNumber(-1, 1);
                            short yoffset = (short)ServerManager.RandomNumber(-1, 1);

                            //go to monster
                            Path = BestFirstSearch.FindPathJagged(new GridPos {
                                X = MapX, Y = MapY
                            }, new GridPos {
                                X = (short)(monster.MapX + xoffset), Y = (short)(monster.MapY + yoffset)
                            }, MapInstance.Map.JaggedGrid);
                            maxindex = Path.Count > Npc.Speed / 2 && Npc.Speed > 1 ? Npc.Speed / 2 : Path.Count;
                        }
                        if (DateTime.Now > LastMove && Npc.Speed > 0 && Path.Count > 0)
                        {
                            byte speedIndex = (byte)(Npc.Speed / 2.5 < 1 ? 1 : Npc.Speed / 2.5);
                            maxindex = Path.Count > speedIndex ? speedIndex : Path.Count;
                            //short mapX = (short)ServerManager.RandomNumber(Path[maxindex - 1].X - 1, Path[maxindex - 1].X + 1);
                            //short mapY = (short)_random.Next(Path[maxindex - 1].Y - 1, Path[maxindex - 1].Y + 1);

                            short  mapX        = Path[maxindex - 1].X;
                            short  mapY        = Path[maxindex - 1].Y;
                            double waitingtime = Map.GetDistance(new MapCell {
                                X = mapX, Y = mapY
                            }, new MapCell {
                                X = MapX, Y = MapY
                            }) / (double)Npc.Speed;
                            MapInstance.Broadcast(new BroadcastPacket(null, PacketFactory.Serialize(StaticPacketHelper.Move(UserType.Npc, MapNpcId, mapX, mapY, Npc.Speed)), ReceiverType.All, xCoordinate: mapX, yCoordinate: mapY));
                            LastMove = DateTime.Now.AddSeconds(waitingtime > 1 ? 1 : waitingtime);

                            Observable.Timer(TimeSpan.FromMilliseconds((int)((waitingtime > 1 ? 1 : waitingtime) * 1000))).Subscribe(x =>
                            {
                                MapX = mapX;
                                MapY = mapY;
                            });

                            Path.RemoveRange(0, maxindex);
                        }
                        if (Target != -1 && (MapId != monster.MapId || distance > maxDistance))
                        {
                            RemoveTarget();
                        }
                    }
                }
            }
        }
Exemplo n.º 3
0
        public void ApplyBCards(object session, object sender = null, short buffLevel = 0)
        {
            Type type = session.GetType();

            // int counterBuff = 0;

            switch ((BCardType.CardType)Type)
            {
            case BCardType.CardType.Buff:
            {
                if (type == typeof(Character) && session is Character character)
                {
                    Buff buff = null;
                    if (sender != null)
                    {
                        Type sType = sender.GetType();
                        if (sType == typeof(Character) && sender is Character sendingCharacter)
                        {
                            buff = new Buff((short)((short)SecondData + buffLevel), sendingCharacter.Level);

                            //Todo: Get anti stats from BCard
                        }
                    }
                    else
                    {
                        buff = new Buff((short)((short)SecondData + buffLevel), character.Level);
                    }

                    int anti = 0;
                    if (buff?.Card.BuffType == BuffType.Bad)
                    {
                        anti += character.ShellEffectArmor?.FirstOrDefault(s =>
                                                                           s.Effect == (byte)ShellArmorEffectType.ReducedAllNegativeEffect)?.Value ??
                                0;
                        switch (SecondData)
                        {
                        case 1:
                            anti += character.ShellEffectArmor?.FirstOrDefault(s =>
                                                                               s.Effect == (byte)ShellArmorEffectType
                                                                               .ReducedBleedingAndMinorBleeding)
                                    ?.Value ?? 0;
                            anti += character.ShellEffectArmor?.FirstOrDefault(s =>
                                                                               s.Effect == (byte)ShellArmorEffectType.ReducedAllBleedingType)
                                    ?.Value ?? 0;
                            break;

                        case 7:
                            anti += character.ShellEffectArmor
                                    ?.FirstOrDefault(s =>
                                                     s.Effect == (byte)ShellArmorEffectType.ReducedStun)?.Value ?? 0;
                            anti += character.ShellEffectArmor?.FirstOrDefault(s =>
                                                                               s.Effect == (byte)ShellArmorEffectType.ReducedAllStun)?.Value ?? 0;
                            break;

                        case 21:
                            anti += character.ShellEffectArmor?.FirstOrDefault(s =>
                                                                               s.Effect == (byte)ShellArmorEffectType.ReducedMinorBleeding)?.Value ??
                                    0;
                            anti += character.ShellEffectArmor?.FirstOrDefault(s =>
                                                                               s.Effect == (byte)ShellArmorEffectType
                                                                               .ReducedBleedingAndMinorBleeding)
                                    ?.Value ?? 0;
                            anti += character.ShellEffectArmor?.FirstOrDefault(s =>
                                                                               s.Effect == (byte)ShellArmorEffectType.ReducedAllBleedingType)
                                    ?.Value ?? 0;
                            break;

                        case 27:
                            anti += character.ShellEffectArmor?.FirstOrDefault(s =>
                                                                               s.Effect == (byte)ShellArmorEffectType.ReducedFreeze)?.Value ?? 0;
                            break;

                        case 42:
                            anti += character.ShellEffectArmor?.FirstOrDefault(s =>
                                                                               s.Effect == (byte)ShellArmorEffectType.ReducedAllBleedingType)
                                    ?.Value ?? 0;
                            break;

                        case 66:
                            anti += character.ShellEffectArmor?.FirstOrDefault(s =>
                                                                               s.Effect == (byte)ShellArmorEffectType.ReducedAllStun)?.Value ?? 0;
                            break;
                        }
                    }

                    if (ServerManager.RandomNumber() < FirstData / 100D * (100 - anti))
                    {
                        character.AddBuff(buff);
                    }
                }
                else if (type == typeof(MapMonster))
                {
                    if (ServerManager.RandomNumber() < FirstData && session is MapMonster mapMonster)
                    {
                        mapMonster.AddBuff(new Buff((short)((short)SecondData + buffLevel), mapMonster.Monster.Level));
                    }
                }
                else if (type == typeof(MapNpc))
                {
                }
                else if (type == typeof(Mate))
                {
                }
            }
            break;

            case BCardType.CardType.Move:
            {
                if (type == typeof(Character) && session is Character character)
                {
                    character.LastSpeedChange = DateTime.UtcNow;
                    character.Session.SendPacket(character.GenerateCond());
                }
            }
            break;

            case BCardType.CardType.Summons:
            {
                if (type == typeof(Character))
                {
                    // jajamaru spawn
                    if (session is Character character && character.MapInstance != null)
                    {
                        List <MonsterToSummon> summonParameters = new List <MonsterToSummon>();
                        for (int i = 0; i < FirstData; i++)
                        {
                            short x, y;
                            byte  t = 0;
                            do
                            {
                                x = (short)(ServerManager.RandomNumber(-3, 3) + character.PositionX);
                                y = (short)(ServerManager.RandomNumber(-3, 3) + character.PositionY);
                                t++;
                            } while (!character.MapInstance.Map.IsBlockedZone(x, y) && t < byte.MaxValue);
                            summonParameters.Add(new MonsterToSummon((short)SecondData, new MapCell {
                                    X = x, Y = y
                                },
                                                                     -1, true));
                        }

                        if (ServerManager.RandomNumber() <= Math.Abs(ThirdData) || ThirdData == 0)
                        {
                            switch (SubType)
                            {
                            case 2:
                                EventHelper.Instance.RunEvent(new EventContainer(
                                                                  character.Session.CurrentMapInstance, EventActionType.SpawnMonsters,
                                                                  summonParameters));
                                break;
                            }
                        }
                    }
                }
                else if (type == typeof(MapMonster))
                {
                    if (session is MapMonster mapMonster && mapMonster.MapInstance != null)
                    {
                        List <MonsterToSummon> summonParameters = new List <MonsterToSummon>();
                        for (int i = 0; i < FirstData; i++)
                        {
                            short x, y;
                            byte  t = 0;
                            do
                            {
                                x = (short)(ServerManager.RandomNumber(-3, 3) + mapMonster.MapX);
                                y = (short)(ServerManager.RandomNumber(-3, 3) + mapMonster.MapY);
                                t++;
                            } while (!mapMonster.MapInstance.Map.IsBlockedZone(x, y) && t < byte.MaxValue);
                            summonParameters.Add(new MonsterToSummon((short)SecondData, new MapCell {
                                    X = x, Y = y
                                },
                                                                     -1, true));
                        }

                        if (ServerManager.RandomNumber() <= Math.Abs(ThirdData) || ThirdData == 0)
                        {
                            switch (SubType)
                            {
                            case 2:
                                EventHelper.Instance.RunEvent(new EventContainer(mapMonster.MapInstance,
                                                                                 EventActionType.SpawnMonsters, summonParameters));
                                break;

                            default:
                                if (mapMonster.OnDeathEvents.All(s =>
                                                                 s.EventActionType != EventActionType.SpawnMonsters))
                                {
                                    mapMonster.OnDeathEvents.Add(new EventContainer(mapMonster.MapInstance,
                                                                                    EventActionType.SpawnMonsters, summonParameters));
                                }

                                break;
                            }
                        }
                    }
                }
                else if (type == typeof(MapNpc))
                {
                }
                else if (type == typeof(Mate))
                {
                }
            }
            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:
            {
                if (type == typeof(Character))
                {
                    if (session is Character character && character.Hp > 0)
                    {
                        int bonus;
                        if (SubType == (byte)AdditionalTypes.HealingBurningAndCasting.RestoreHP / 10)
                        {
                            if (IsLevelScaled)
                            {
                                bonus = character.Level * FirstData;
                            }
                            else
                            {
                                bonus = FirstData;
                            }

                            if (character.Hp + bonus <= character.HPLoad())
                            {
                                character.Hp += bonus;
                            }
                            else
                            {
                                bonus        = (int)character.HPLoad() - character.Hp;
                                character.Hp = (int)character.HPLoad();
                            }

                            character.Session.CurrentMapInstance?.Broadcast(character.Session,
                                                                            character.GenerateRc(bonus));
                        }

                        if (SubType == (byte)AdditionalTypes.HealingBurningAndCasting.RestoreMP / 10)
                        {
                            if (IsLevelScaled)
                            {
                                bonus = character.Level * FirstData;
                            }
                            else
                            {
                                bonus = FirstData;
                            }

                            if (character.Mp + bonus <= character.MPLoad())
                            {
                                character.Mp += bonus;
                            }
                            else
                            {
                                character.Mp = (int)character.MPLoad();
                            }
                        }

                        character.Session.SendPacket(character.GenerateStat());
                    }
                }
                else if (type == typeof(MapMonster))
                {
                    if (ServerManager.RandomNumber() < FirstData && session is MapMonster mapMonster)
                    {
                        mapMonster.AddBuff(new Buff((short)SecondData, mapMonster.Monster.Level));
                    }
                }
                else if (type == typeof(MapNpc))
                {
                }
                else if (type == typeof(Mate))
                {
                }
            }
            break;

            case BCardType.CardType.Hpmp:
                if (type == typeof(Character))
                {
                    if (session is Character c)
                    {
                        switch (SubType)
                        {
                        case (byte)AdditionalTypes.Hpmp.RestoreDecreasedMP / 10:
                        {
                            int bonus = (int)(FirstData * c.MPLoad() / 100);

                            c.Mp = c.Mp + bonus > 1 ? c.Mp + bonus : c.Mp = 1;
                        }
                        break;
                        }
                    }
                }

                break;

            case BCardType.CardType.SpecialisationBuffResistance:
            {
                switch (SubType)
                {
                case (byte)AdditionalTypes.SpecialisationBuffResistance.RemoveBadEffects / 10:
                {
                    if (session is Character c &&              /*&& sender is ClientSession senderSession*/
                        ServerManager.RandomNumber() < Math.Abs(FirstData))
                    {
                        c.DisableBuffs(FirstData > 0 ? BuffType.Good : BuffType.Bad, SecondData);
                    }
                }
                break;
                }
            }
            break;

            case BCardType.CardType.SpecialEffects:
                break;

            case BCardType.CardType.Capture:
            {
                if (type == typeof(MapMonster) && session is MapMonster mapMonster &&
                    sender is ClientSession senderSession)
                {
                    NpcMonster mateNpc = ServerManager.GetNpcMonster(mapMonster.MonsterVNum);
                    if (mateNpc != null)
                    {
                        if (mapMonster.Monster.Catch)
                        {
                            if (mapMonster.IsAlive &&
                                mapMonster.CurrentHp <= (int)((double)mapMonster.MaxHp / 2))
                            {
                                if (mapMonster.Monster.Level < senderSession.Character.Level)
                                {
                                    // TODO: find a new algorithm
                                    int[] chance = { 100, 80, 60, 40, 20, 0 };
                                    if (ServerManager.RandomNumber() < chance[ServerManager.RandomNumber(0, 5)])
                                    {
                                        Mate mate = new Mate(senderSession.Character, mateNpc,
                                                             (byte)(mapMonster.Monster.Level - 15 > 0
                                                        ? mapMonster.Monster.Level - 15
                                                        : 1), MateType.Pet);
                                        if (senderSession.Character.CanAddMate(mate))
                                        {
                                            senderSession.Character.AddPetWithSkill(mate);
                                            senderSession.SendPacket(
                                                UserInterfaceHelper.GenerateMsg(
                                                    Language.Instance.GetMessageFromKey("CATCH_SUCCESS"), 0));
                                            senderSession.CurrentMapInstance?.Broadcast(
                                                StaticPacketHelper.GenerateEff(UserType.Player,
                                                                               senderSession.Character.CharacterId, 197));
                                            senderSession.CurrentMapInstance?.Broadcast(
                                                StaticPacketHelper.SkillUsed(UserType.Player,
                                                                             senderSession.Character.CharacterId, 3,
                                                                             mapMonster.MapMonsterId, -1, 0, 15, -1, -1, -1, true,
                                                                             (int)(mapMonster.CurrentHp / (float)mapMonster.MaxHp * 100
                                                                                   ), 0, -1, 0));
                                            mapMonster.SetDeathStatement();
                                            senderSession.CurrentMapInstance?.Broadcast(
                                                StaticPacketHelper.Out(UserType.Monster,
                                                                       mapMonster.MapMonsterId));
                                        }
                                        else
                                        {
                                            senderSession.SendPacket(
                                                senderSession.Character.GenerateSay(
                                                    Language.Instance.GetMessageFromKey("PET_SLOT_FULL"), 10));
                                            senderSession.SendPacket(
                                                StaticPacketHelper.Cancel(2, mapMonster.MapMonsterId));
                                        }
                                    }
                                    else
                                    {
                                        senderSession.SendPacket(
                                            UserInterfaceHelper.GenerateMsg(
                                                Language.Instance.GetMessageFromKey("CATCH_FAIL"), 0));
                                        senderSession.CurrentMapInstance?.Broadcast(
                                            StaticPacketHelper.SkillUsed(UserType.Player,
                                                                         senderSession.Character.CharacterId, 3, mapMonster.MapMonsterId,
                                                                         -1, 0, 15, -1, -1, -1, true,
                                                                         (int)(mapMonster.CurrentHp / (float)mapMonster.MaxHp * 100),
                                                                         0, -1, 0));
                                    }
                                }
                                else
                                {
                                    senderSession.SendPacket(UserInterfaceHelper.GenerateMsg(
                                                                 Language.Instance.GetMessageFromKey("LEVEL_LOWER_THAN_MONSTER"), 0));
                                    senderSession.SendPacket(
                                        StaticPacketHelper.Cancel(2, mapMonster.MapMonsterId));
                                }
                            }
                            else
                            {
                                senderSession.SendPacket(UserInterfaceHelper.GenerateMsg(
                                                             Language.Instance.GetMessageFromKey("CURRENT_HP_TOO_HIGH"), 0));
                                senderSession.SendPacket(StaticPacketHelper.Cancel(2, mapMonster.MapMonsterId));
                            }
                        }
                        else
                        {
                            senderSession.SendPacket(UserInterfaceHelper.GenerateMsg(
                                                         Language.Instance.GetMessageFromKey("MONSTER_CANT_BE_CAPTURED"), 0));
                            senderSession.SendPacket(StaticPacketHelper.Cancel(2, mapMonster.MapMonsterId));
                        }
                    }
                }
            }
            break;

            case BCardType.CardType.SpecialDamageAndExplosions:
                break;

            case BCardType.CardType.SpecialEffects2:
                if (type == typeof(Character))
                {
                    if (session is Character c)
                    {
                        short destinationX = c.PositionX;
                        short destinationY = c.PositionY;
                        switch (SubType)
                        {
                        case (byte)AdditionalTypes.SpecialEffects2.TeleportInRadius / 10:
                        {
                            switch (c.Direction)
                            {
                            case 0:
                                // -y
                                destinationY -= (short)FirstData;
                                break;

                            case 1:
                                // +x
                                destinationX += (short)FirstData;
                                break;

                            case 2:
                                // +y
                                destinationY += (short)FirstData;
                                break;

                            case 3:
                                // -x
                                destinationX -= (short)FirstData;
                                break;

                            case 4:
                                // -x -y
                                destinationX -= (short)FirstData;
                                destinationY -= (short)FirstData;
                                break;

                            case 5:
                                // +x +y
                                destinationX += (short)FirstData;
                                destinationY += (short)FirstData;
                                break;

                            case 6:
                                // +x -y
                                destinationX += (short)FirstData;
                                destinationY -= (short)FirstData;
                                break;

                            case 7:
                                // -x +y
                                destinationX -= (short)FirstData;
                                destinationY += (short)FirstData;
                                break;
                            }

                            ServerManager.Instance.TeleportForward(c.Session, c.MapInstanceId, destinationX,
                                                                   destinationY);
                        }
                        break;
                        }
                    }
                }

                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:
            {
                switch (SubType)
                {
                case (byte)AdditionalTypes.SpecialActions.RunAway / 10:
                    if (session is MapMonster m)
                    {
                        m.MapInstance.Broadcast(StaticPacketHelper.Say(UserType.Monster, m.MapMonsterId, 0, "!!!"));
                        m.RemoveTarget();
                        for (int i = 0; i < 10; i++)
                        {
                            Observable.Timer(TimeSpan.FromSeconds(i)).Subscribe(o =>
                                {
                                    m.MapX++;
                                    m.MapY++;
                                    m.IgnoreTargetsUntil = DateTime.UtcNow.AddSeconds(10);
                                    m.RemoveTarget();
                                });
                        }
                    }
                    break;
                }
            }
            break;

            case BCardType.CardType.Mode:
                break;

            case BCardType.CardType.NoCharacteristicValue:
                break;

            case BCardType.CardType.LightAndShadow:
            {
                switch (SubType)
                {
                case (byte)AdditionalTypes.LightAndShadow.RemoveBadEffects / 10:
                {
                    if (session is Character c /*&& sender is ClientSession senderSession*/)
                    {
                        c.DisableBuffs(BuffType.Bad, FirstData);
                    }
                }
                break;
                }
            }
            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 (type == typeof(Character) && session is Character character)
                {
                    if (SkillVNum.HasValue &&
                        SubType.Equals((byte)AdditionalTypes.MeditationSkill.CausingChance / 10) &&
                        ServerManager.RandomNumber() < FirstData)
                    {
                        Skill skill    = ServerManager.GetSkill(SkillVNum.Value);
                        Skill newSkill = ServerManager.GetSkill((short)SecondData);
                        Observable.Timer(TimeSpan.FromMilliseconds(100)).Subscribe(observer =>
                            {
                                foreach (QuicklistEntryDTO quicklistEntry in character.QuicklistEntries.Where(s =>
                                                                                                              s.Morph == character.Morph && s.Pos.Equals(skill.CastId)))
                                {
                                    character.Session.SendPacket(
                                        $"qset {quicklistEntry.Q1} {quicklistEntry.Q2} {quicklistEntry.Type}.{quicklistEntry.Slot}.{newSkill.CastId}.0");
                                }

                                character.Session.SendPacket($"mslot {newSkill.CastId} -1");
                            });
                        character.SkillComboCount++;
                        character.LastSkillComboUse = DateTime.UtcNow;
                        if (skill.CastId > 10)
                        {
                            // HACK this way
                            Observable.Timer(TimeSpan.FromMilliseconds((skill.Cooldown * 100) + 500))
                            .Subscribe(observer =>
                                       character.Session.SendPacket(StaticPacketHelper.SkillReset(skill.CastId)));
                        }
                    }

                    switch (SubType)
                    {
                    case 2:
                        character.MeditationDictionary[(short)SecondData] = DateTime.UtcNow.AddSeconds(4);
                        break;

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

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

            case BCardType.CardType.FalconSkill:
            {
                if (session is Character c)
                {
                    switch (SubType)
                    {
                    case (byte)AdditionalTypes.FalconSkill.Hide:
                        c.Invisible = true;
                        c.Mates.Where(s => s.IsTeamMember).ToList().ForEach(s =>
                                                                            c.Session.CurrentMapInstance?.Broadcast(s.GenerateOut()));
                        c.Session.CurrentMapInstance?.Broadcast(c.GenerateInvisible());
                        c.Session.SendPacket(c.GenerateEq());
                        break;
                    }
                }
            }
            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:
                if (type == typeof(Character))
                {
                    if (session is Character character)
                    {
                        switch (SubType)
                        {
                        case ((byte)AdditionalTypes.MeteoriteTeleport.TeleportYouAndGroupToSavedLocation / 10):
                            if (character.TeleportSet == false)
                            {
                                character.TeleportX   = character.PositionX;
                                character.TeleportY   = character.PositionY;
                                character.TeleportMap = character.MapId;
                                character.MapInstance.Broadcast(StaticPacketHelper.GenerateEff(UserType.Player, character.CharacterId, 4497));
                                character.TeleportSet = true;
                                Observable.Timer(TimeSpan.FromSeconds(40)).Subscribe(o => character.TeleportSet = false);
                            }
                            else
                            {
                                if (character.MapInstance.IsPvp)
                                {
                                    if (character.MapInstance.MapInstanceType != MapInstanceType.BaseMapInstance)
                                    {
                                        character.TeleportSet = false;
                                        return;
                                    }

                                    character.MapInstance.Broadcast($"tp 1 {character.CharacterId} {character.TeleportX} {character.TeleportY} 0");
                                    character.PositionX   = character.TeleportX;
                                    character.PositionY   = character.TeleportY;
                                    character.TeleportSet = false;
                                }
                                else
                                {
                                    if (character.MapId == character.TeleportMap)
                                    {
                                        if (character.MapInstance.MapInstanceType == MapInstanceType.CaligorInstance)
                                        {
                                            character.TeleportSet = false;
                                            return;
                                        }
                                        character.MapInstance.Broadcast($"tp 1 {character.CharacterId} {character.TeleportX} {character.TeleportY} 0");
                                        character.PositionX   = character.TeleportX;
                                        character.PositionY   = character.TeleportY;
                                        character.TeleportSet = false;
                                    }
                                    else
                                    {
                                        character.TeleportSet = false;
                                    }
                                }
                            }
                            break;

                        case (byte)AdditionalTypes.MeteoriteTeleport.CauseMeteoriteFall / 10:
                        {
                            int amount = 10 + (character.Level / FirstData);

                            for (int i = 0; i < amount; i++)
                            {
                                Observable.Timer(TimeSpan.FromMilliseconds(i * 500)).Subscribe(o => character.SpawnMeteorite());
                            }
                        }
                        break;
                        }
                    }
                }
                break;

            case BCardType.CardType.StealBuff:
                break;

            case BCardType.CardType.Unknown:
                break;

            case BCardType.CardType.EffectSummon:
                break;

            default:
                Logger.Warn($"Card Type {Type} not defined!");
                break;
            }
        }