/// <summary>
        /// Handle any kind of Monster interaction
        /// </summary>
        internal void MonsterLife()
        {
            if (Monster == null)
            {
                return;
            }

            // handle hit queue
            HitRequest hitRequest;

            while (HitQueue.TryDequeue(out hitRequest))
            {
                if (IsAlive)
                {
                    int hitmode = 0;

                    // calculate damage
                    int damage = hitRequest.Session.Character.GenerateDamage(this, hitRequest.Skill, ref hitmode);

                    switch (hitRequest.TargetHitType)
                    {
                    case TargetHitType.SingleTargetHit:
                    {
                        // Target Hit
                        Map?.Broadcast($"su 1 {hitRequest.Session.Character.CharacterId} 3 {MapMonsterId} {hitRequest.Skill.SkillVNum} {hitRequest.Skill.Cooldown} {hitRequest.Skill.AttackAnimation} {hitRequest.SkillEffect} {hitRequest.Session.Character.MapX} {hitRequest.Session.Character.MapY} {(IsAlive ? 1 : 0)} {(int)((float)CurrentHp / (float)Monster.MaxHP * 100)} {damage} {hitmode} {hitRequest.Skill.SkillType - 1}");
                        break;
                    }

                    case TargetHitType.SingleTargetHitCombo:
                    {
                        // Taget Hit Combo
                        Map?.Broadcast($"su 1 {hitRequest.Session.Character.CharacterId} 3 {MapMonsterId} {hitRequest.Skill.SkillVNum} {hitRequest.Skill.Cooldown} {hitRequest.SkillCombo.Animation} {hitRequest.SkillCombo.Effect} {hitRequest.Session.Character.MapX} {hitRequest.Session.Character.MapY} {(IsAlive ? 1 : 0)} {(int)((float)CurrentHp / (float)Monster.MaxHP * 100)} {damage} {hitmode} {hitRequest.Skill.SkillType - 1}");
                        break;
                    }

                    case TargetHitType.SingleAOETargetHit:
                    {
                        // Target Hit Single AOE
                        switch (hitmode)
                        {
                        case 1:
                            hitmode = 4;
                            break;

                        case 3:
                            hitmode = 6;
                            break;

                        default:
                            hitmode = 5;
                            break;
                        }
                        if (hitRequest.ShowTargetHitAnimation)
                        {
                            Map?.Broadcast($"su 1 {hitRequest.Session.Character.CharacterId} 3 {MapMonsterId} {hitRequest.Skill.SkillVNum} {hitRequest.Skill.Cooldown} {hitRequest.Skill.AttackAnimation} {hitRequest.SkillEffect} 0 0 {(IsAlive ? 1 : 0)} {((int)((double)hitRequest.Session.Character.Hp / hitRequest.Session.Character.HPLoad()) * 100)} 0 0 {hitRequest.Skill.SkillType - 1}");
                        }
                        Map?.Broadcast($"su 1 {hitRequest.Session.Character.CharacterId} 3 {MapMonsterId} {hitRequest.Skill.SkillVNum} {hitRequest.Skill.Cooldown} {hitRequest.Skill.AttackAnimation} {hitRequest.SkillEffect} {hitRequest.Session.Character.MapX} {hitRequest.Session.Character.MapY} {(IsAlive ? 1 : 0)} {(int)((float)CurrentHp / (float)Monster.MaxHP * 100)} {damage} {hitmode} {hitRequest.Skill.SkillType - 1}");
                        break;
                    }

                    case TargetHitType.AOETargetHit:
                    {
                        // Target Hit AOE
                        switch (hitmode)
                        {
                        case 1:
                            hitmode = 4;
                            break;

                        case 3:
                            hitmode = 6;
                            break;

                        default:
                            hitmode = 5;
                            break;
                        }
                        Map?.Broadcast($"su 1 {hitRequest.Session.Character.CharacterId} 3 {MapMonsterId} {hitRequest.Skill.SkillVNum} {hitRequest.Skill.Cooldown} {hitRequest.Skill.AttackAnimation} {hitRequest.SkillEffect} {hitRequest.Session.Character.MapX} {hitRequest.Session.Character.MapY} {(IsAlive ? 1 : 0)} {(int)((float)CurrentHp / (float)Monster.MaxHP * 100)} {damage} {hitmode} {hitRequest.Skill.SkillType - 1}");
                        break;
                    }

                    case TargetHitType.ZoneHit:
                    {
                        // Zone HIT
                        Map?.Broadcast($"su 1 {hitRequest.Session.Character.CharacterId} 3 {MapMonsterId} {hitRequest.Skill.SkillVNum} {hitRequest.Skill.Cooldown} {hitRequest.Skill.AttackAnimation} {hitRequest.SkillEffect} {hitRequest.MapX} {hitRequest.MapY} {(IsAlive ? 1 : 0)} {(int)((float)CurrentHp / (float)Monster.MaxHP * 100)} {damage} 5 {hitRequest.Skill.SkillType - 1}");
                        break;
                    }

                    case TargetHitType.SpecialZoneHit:
                    {
                        // Special Zone hit
                        Map?.Broadcast($"su 1 {hitRequest.Session.Character.CharacterId} 3 {MapMonsterId} {hitRequest.Skill.SkillVNum} {hitRequest.Skill.Cooldown} {hitRequest.Skill.AttackAnimation} {hitRequest.SkillEffect} {hitRequest.Session.Character.MapX} {hitRequest.Session.Character.MapY} {(IsAlive ? 1 : 0)} {(int)((float)CurrentHp / (float)Monster.MaxHP * 100)} {damage} 0 {hitRequest.Skill.SkillType - 1}");
                        break;
                    }
                    }

                    // generate the kill bonus
                    hitRequest.Session.Character.GenerateKillBonus(this);
                }
                else
                {
                    // monster already has been killed, send cancel
                    hitRequest.Session.SendPacket($"cancel 2 {MapMonsterId}");
                }
            }

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

            // normal movement
            else if (Target == -1)
            {
                Move();
            }

            // target following
            else
            {
                if (Map != null)
                {
                    ClientSession targetSession = Map.GetSessionByCharacterId(Target);

                    // remove target in some situations
                    if (targetSession == null || targetSession.Character.Invisible || targetSession.Character.Hp <= 0 || CurrentHp <= 0)
                    {
                        RemoveTarget();
                        return;
                    }

                    NpcMonsterSkill npcMonsterSkill = null;
                    if (ServerManager.RandomNumber(0, 10) > 8 && Skills != null)
                    {
                        npcMonsterSkill = Skills.Where(s => (DateTime.Now - s.LastSkillUse).TotalMilliseconds >= 100 * s.Skill.Cooldown).OrderBy(rnd => _random.Next()).FirstOrDefault();
                    }

                    // check if target is in range
                    if (!targetSession.Character.InvisibleGm && !targetSession.Character.Invisible && targetSession.Character.Hp > 0 &&
                        ((npcMonsterSkill != null && CurrentMp >= npcMonsterSkill.Skill.MpCost &&
                          Map.GetDistance(new MapCell {
                        X = MapX, Y = MapY
                    },
                                          new MapCell {
                        X = targetSession.Character.MapX, Y = targetSession.Character.MapY
                    }) < npcMonsterSkill.Skill.Range) ||
                         (Map.GetDistance(new MapCell {
                        X = MapX, Y = MapY
                    },
                                          new MapCell {
                        X = targetSession.Character.MapX, Y = targetSession.Character.MapY
                    }) <= Monster.BasicRange)))
                    {
                        TargetHit(targetSession, npcMonsterSkill);
                    }
                    else
                    {
                        FollowTarget(targetSession);
                    }
                }
            }
        }
		/// <summary> A search implementation which executes each
		/// <see cref="Searchable"/> in its own thread and waits for each search to complete
		/// and merge the results back together.
		/// </summary>
		public override TopDocs Search(Weight weight, Filter filter, int nDocs)
		{
		    HitQueue hq = new HitQueue(nDocs, false);
            object lockObj = new object();

            Task<TopDocs>[] tasks = new Task<TopDocs>[searchables.Length];
            //search each searchable
            for (int i = 0; i < searchables.Length; i++)
            {
                int cur = i;
                tasks[i] =
                    Task.Factory.StartNew(() => MultiSearcherCallableNoSort(ThreadLock.MonitorLock, lockObj, searchables[cur], weight, filter,
                                                                            nDocs, hq, cur, starts));
            }

		    int totalHits = 0;
		    float maxScore = float.NegativeInfinity;
            

		    Task.WaitAll(tasks);
            foreach(TopDocs topDocs in tasks.Select(x => x.Result))
            {
                totalHits += topDocs.TotalHits;
                maxScore = Math.Max(maxScore, topDocs.MaxScore);
            }

            ScoreDoc[] scoreDocs = new ScoreDoc[hq.Size()];
            for (int i = hq.Size() - 1; i >= 0; i--) // put docs in array
                scoreDocs[i] = hq.Pop();

		    return new TopDocs(totalHits, scoreDocs, maxScore);
		}
Beispiel #3
0
	    public override TopDocs Search(Weight weight, Filter filter, int nDocs)
		{
			HitQueue hq = new HitQueue(nDocs, false);
			int totalHits = 0;

            var lockObj = new object();
			for (int i = 0; i < searchables.Length; i++)
			{
                // search each searcher
                // use NullLock, we don't care about synchronization for these
                TopDocs docs = MultiSearcherCallableNoSort(ThreadLock.NullLock, lockObj, searchables[i], weight, filter, nDocs, hq, i, starts);
				totalHits += docs.TotalHits; // update totalHits
			}
			
			ScoreDoc[] scoreDocs2 = new ScoreDoc[hq.Size()];
			for (int i = hq.Size() - 1; i >= 0; i--)
			// put docs in array
				scoreDocs2[i] = hq.Pop();
			
			float maxScore = (totalHits == 0)?System.Single.NegativeInfinity:scoreDocs2[0].Score;
			
			return new TopDocs(totalHits, scoreDocs2, maxScore);
		}