internal void MonsterLife() { //Respawn if (!Alive && Respawn) { double timeDeath = (DateTime.Now - Death).TotalSeconds; if (timeDeath >= Monster.RespawnTime / 10) { DamageList = new Dictionary <long, long>(); Alive = true; Target = -1; CurrentHp = Monster.MaxHP; CurrentMp = Monster.MaxMP; MapX = firstX; MapY = firstY; Path = new List <MapCell>(); Map.Broadcast(GenerateIn3()); Map.Broadcast(GenerateEff(7)); } return; } else if (Target == -1) { //Normal Move Mode if (Alive == false) { return; } Random random = new Random((int)DateTime.Now.Ticks & 0x0000FFFF); double time = (DateTime.Now - LastMove).TotalSeconds; int MoveFrequent = 5 - (int)Math.Round((double)(Monster.Speed / 5)); if (MoveFrequent < 1) { MoveFrequent = 1; } if (IsMoving) { if (Path.Where(s => s != null).ToList().Count > 0) { if ((DateTime.Now - LastMove).TotalSeconds > 1.0 / Monster.Speed) { short mapX = Path.ElementAt(0).X; short mapY = Path.ElementAt(0).Y; Path.RemoveAt(0); LastMove = DateTime.Now; Map.Broadcast($"mv 3 {this.MapMonsterId} {this.MapX} {this.MapY} {Monster.Speed}"); Task.Factory.StartNew(async() => { await Task.Delay(400); this.MapX = mapX; this.MapY = mapY; }); return; } } else if (time > 0.5 * random.Next(1, 3) * (0.5 + random.NextDouble())) { byte point = (byte)random.Next(2, 4); byte fpoint = (byte)random.Next(0, 2); byte xpoint = (byte)random.Next(fpoint, point); byte ypoint = (byte)(point - xpoint); short mapX = firstX; short mapY = firstY; if (ServerManager.GetMap(MapId).GetFreePosition(ref mapX, ref mapY, xpoint, ypoint)) { Task.Factory.StartNew(async() => { await Task.Delay(400); this.MapX = mapX; this.MapY = mapY; }); LastMove = DateTime.Now; string movePacket = $"mv 3 {this.MapMonsterId} {mapX} {mapY} {Monster.Speed}"; Map.Broadcast(movePacket); } } } if (Monster.IsHostile) { Character character = ServerManager.Instance.Sessions.Where(s => s.Character != null && s.Character.Hp > 0).OrderBy(s => Map.GetDistance(new MapCell() { X = MapX, Y = MapY }, new MapCell() { X = s.Character.MapX, Y = s.Character.MapY })).FirstOrDefault(s => s.Character != null && !s.Character.Invisible && s.Character.MapId == MapId)?.Character; if (character != null) { if (Map.GetDistance(new MapCell() { X = character.MapX, Y = character.MapY }, new MapCell() { X = MapX, Y = MapY }) < 10) { Target = character.CharacterId; if (!Monster.NoAggresiveIcon) { character.Session.SendPacket(GenerateEff(5000)); } } } } } else { ClientSession targetSession = Map.Sessions.SingleOrDefault(s => s.Character.CharacterId == Target); if (targetSession == null || targetSession.Character.Invisible) { Target = -1; return; } Random random = new Random((int)DateTime.Now.Ticks & 0x0000FFFF); NpcMonsterSkill npcMonsterSkill = null; if (random.Next(10) > 8 || inWaiting) { inWaiting = false; if ((DateTime.Now - LastEffect).TotalMilliseconds < Monster.BasicCooldown * 200) { inWaiting = true; } npcMonsterSkill = Skills.Where(s => (DateTime.Now - s.LastUse).TotalMilliseconds >= 100 * s.Skill.Cooldown).OrderBy(rnd => random.Next()).FirstOrDefault(); } int damage = 100; if (targetSession != null && targetSession.Character.Hp > 0 && ((npcMonsterSkill != null && CurrentMp - npcMonsterSkill.Skill.MpCost >= 0 && Map.GetDistance(new MapCell() { X = this.MapX, Y = this.MapY }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY }) < npcMonsterSkill.Skill.Range) || (Map.GetDistance(new MapCell() { X = this.MapX, Y = this.MapY }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY }) <= Monster.BasicRange))) { if ((DateTime.Now - LastEffect).TotalMilliseconds >= Monster.BasicCooldown * 200 && !inWaiting) { if (npcMonsterSkill != null) { npcMonsterSkill.LastUse = DateTime.Now; CurrentMp -= npcMonsterSkill.Skill.MpCost; Map.Broadcast($"ct 3 {MapMonsterId} 1 {Target} {npcMonsterSkill.Skill.CastAnimation} {npcMonsterSkill.Skill.CastEffect} {npcMonsterSkill.Skill.SkillVNum}"); } LastMove = DateTime.Now; // deal 0 damage to GM with GodMode damage = targetSession.Character.HasGodMode ? 0 : 100; if (targetSession.Character.IsSitting) { targetSession.Character.IsSitting = false; Map.Broadcast(null, targetSession.Character.GenerateRest(), ReceiverType.OnlySomeone, "", targetSession.Character.CharacterId); } if (npcMonsterSkill != null && npcMonsterSkill.Skill.CastEffect != 0) { Map.Broadcast(GenerateEff(npcMonsterSkill.Skill.CastEffect)); Thread.Sleep(npcMonsterSkill.Skill.CastTime * 100); } Path = new List <MapCell>(); targetSession.Character.LastDefence = DateTime.Now; targetSession.Character.GetDamage(damage); Map.Broadcast(null, ServerManager.Instance.GetUserMethod <string>(Target, "GenerateStat"), ReceiverType.OnlySomeone, "", Target); if (npcMonsterSkill != null) { Map.Broadcast($"su 3 {MapMonsterId} 1 {Target} {npcMonsterSkill.SkillVNum} {npcMonsterSkill.Skill.Cooldown} {npcMonsterSkill.Skill.AttackAnimation} {npcMonsterSkill.Skill.Effect} {this.MapX} {this.MapY} {(targetSession.Character.Hp > 0 ? 1 : 0)} { (int)(targetSession.Character.Hp / targetSession.Character.HPLoad() * 100) } {damage} 0 0"); } else { Map.Broadcast($"su 3 {MapMonsterId} 1 {Target} 0 {Monster.BasicCooldown} 11 {Monster.BasicSkill} 0 0 {(targetSession.Character.Hp > 0 ? 1 : 0)} { (int)(targetSession.Character.Hp / targetSession.Character.HPLoad() * 100) } {damage} 0 0"); } LastEffect = DateTime.Now; if (targetSession.Character.Hp <= 0) { Thread.Sleep(1000); ServerManager.Instance.AskRevive(targetSession.Character.CharacterId); Target = -1; } if (npcMonsterSkill != null && (npcMonsterSkill.Skill.Range > 0 || npcMonsterSkill.Skill.TargetRange > 0)) { foreach (Character chara in ServerManager.GetMap(MapId).GetListPeopleInRange(npcMonsterSkill.Skill.TargetRange == 0 ? this.MapX : targetSession.Character.MapX, npcMonsterSkill.Skill.TargetRange == 0 ? this.MapY : targetSession.Character.MapY, (byte)(npcMonsterSkill.Skill.TargetRange + npcMonsterSkill.Skill.Range)).Where(s => s.CharacterId != Target && s.Hp > 0)) { if (chara.IsSitting) { chara.IsSitting = false; Map.Broadcast(null, chara.GenerateRest(), ReceiverType.OnlySomeone, "", chara.CharacterId); } damage = chara.HasGodMode ? 0 : 100; bool AlreadyDead2 = chara.Hp <= 0; chara.GetDamage(damage); chara.LastDefence = DateTime.Now; Map.Broadcast(null, chara.GenerateStat(), ReceiverType.OnlySomeone, "", chara.CharacterId); Map.Broadcast($"su 3 {MapMonsterId} 1 {chara.CharacterId} 0 {Monster.BasicCooldown} 11 {Monster.BasicSkill} 0 0 {(chara.Hp > 0 ? 1 : 0)} { (int)(chara.Hp / chara.HPLoad() * 100) } {damage} 0 0"); if (chara.Hp <= 0 && !AlreadyDead2) { Thread.Sleep(1000); ServerManager.Instance.AskRevive(chara.CharacterId); } } } } } else { if (IsMoving == true) { short maxDistance = 22; if (Path.Count() == 0 && targetSession != null && (Map.GetDistance(new MapCell() { X = this.MapX, Y = this.MapY }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY }) < maxDistance)) { Path = ServerManager.GetMap(MapId).StraightPath(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY, MapId = this.MapId }); if (!Path.Any()) { Path = ServerManager.GetMap(MapId).JPSPlus(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY, MapId = this.MapId }); } } if (Path.Count > 0 && Map.GetDistance(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY, MapId = this.MapId }) > 1) { this.MapX = Path.ElementAt(0).X; this.MapY = Path.ElementAt(0).Y; Path.RemoveAt(0); } if (targetSession == null || MapId != targetSession.Character.MapId || (Map.GetDistance(new MapCell() { X = this.MapX, Y = this.MapY }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY }) > maxDistance)) { Path = ServerManager.GetMap(MapId).StraightPath(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = firstX, Y = firstY, MapId = this.MapId }); if (!Path.Any()) { Path = ServerManager.GetMap(MapId).JPSPlus(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = firstX, Y = firstY, MapId = this.MapId }); } Target = -1; } else { if ((DateTime.Now - LastMove).TotalSeconds > 1.0 / Monster.Speed) { LastMove = DateTime.Now; Map.Broadcast($"mv 3 {this.MapMonsterId} {this.MapX} {this.MapY} {Monster.Speed}"); } } } } } }
/// <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); } } } }
internal void NpcLife() { double time = (DateTime.Now - LastEffect).TotalMilliseconds; if (Effect > 0 && time > EffectDelay) { Map.Broadcast(GenerateEff(), MapX, MapY); LastEffect = DateTime.Now; } time = (DateTime.Now - LastMove).TotalMilliseconds; if (IsMoving && Npc.Speed > 0 && time > _movetime) { _movetime = ServerManager.RandomNumber(500, 3000); byte point = (byte)ServerManager.RandomNumber(2, 4); byte fpoint = (byte)ServerManager.RandomNumber(0, 2); byte xpoint = (byte)ServerManager.RandomNumber(fpoint, point); byte ypoint = (byte)(point - xpoint); short mapX = FirstX; short mapY = FirstY; if (Map.GetFreePosition(ref mapX, ref mapY, xpoint, ypoint)) { Observable.Timer(TimeSpan.FromMilliseconds(1000 * (xpoint + ypoint) / (2 * Npc.Speed))) .Subscribe( x => { MapX = mapX; MapY = mapY; }); LastMove = DateTime.Now.AddSeconds((xpoint + ypoint) / (2 * Npc.Speed)); Map.Broadcast(new BroadcastPacket(null, GenerateMv2(), ReceiverType.AllInRange, xCoordinate: mapX, yCoordinate: mapY)); } } if (Target == -1) { if (Npc.IsHostile && Shop == null) { MapMonster monster = Map.Monsters.FirstOrDefault(s => MapId == s.MapId && Map.GetDistance(new MapCell() { X = MapX, Y = MapY }, new MapCell() { X = s.MapX, Y = s.MapY }) < (Npc.NoticeRange > 5 ? Npc.NoticeRange / 2 : Npc.NoticeRange)); ClientSession session = Map.Sessions.FirstOrDefault(s => MapId == s.Character.MapId && Map.GetDistance(new MapCell() { X = MapX, Y = MapY }, new MapCell() { X = s.Character.MapX, Y = s.Character.MapY }) < Npc.NoticeRange); if (monster != null && session != null) { Target = monster.MapMonsterId; } } } else if (Target != -1) { MapMonster monster = Map.Monsters.FirstOrDefault(s => s.MapMonsterId == Target); if (monster == null || monster.CurrentHp < 1) { Target = -1; return; } NpcMonsterSkill npcMonsterSkill = null; if (ServerManager.RandomNumber(0, 10) > 8) { npcMonsterSkill = Npc.Skills.Where(s => (DateTime.Now - s.LastSkillUse).TotalMilliseconds >= 100 * s.Skill.Cooldown).OrderBy(rnd => _random.Next()).FirstOrDefault(); } const short damage = 100; 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))) { if (((DateTime.Now - LastEffect).TotalMilliseconds >= 1000 + Npc.BasicCooldown * 200 && !Npc.Skills.Any()) || npcMonsterSkill != null) { if (npcMonsterSkill != null) { npcMonsterSkill.LastSkillUse = DateTime.Now; Map.Broadcast($"ct 2 {MapNpcId} 3 {Target} {npcMonsterSkill.Skill.CastAnimation} {npcMonsterSkill.Skill.CastEffect} {npcMonsterSkill.Skill.SkillVNum}"); } if (npcMonsterSkill != null && npcMonsterSkill.Skill.CastEffect != 0) { Map.Broadcast(GenerateEff()); } monster.CurrentHp -= damage; Map.Broadcast(npcMonsterSkill != null ? $"su 2 {MapNpcId} 3 {Target} {npcMonsterSkill.SkillVNum} {npcMonsterSkill.Skill.Cooldown} {npcMonsterSkill.Skill.AttackAnimation} {npcMonsterSkill.Skill.Effect} 0 0 {(monster.CurrentHp > 0 ? 1 : 0)} {(int)(monster.CurrentHp / monster.Monster.MaxHP * 100)} {damage} 0 0" : $"su 2 {MapNpcId} 3 {Target} 0 {Npc.BasicCooldown} 11 {Npc.BasicSkill} 0 0 {(monster.CurrentHp > 0 ? 1 : 0)} {(int)(monster.CurrentHp / monster.Monster.MaxHP * 100)} {damage} 0 0"); LastEffect = DateTime.Now; if (monster.CurrentHp < 1) { if (IsMoving) { Path = Map.StraightPath(new GridPos { x = MapX, y = MapY }, new GridPos { x = FirstX, y = FirstY }); if (!Path.Any()) { Path = Map.JPSPlus(JumpPointParameters, new GridPos { x = MapX, y = MapY }, new GridPos { x = FirstX, y = FirstY }); } } monster.IsAlive = false; monster.LastMove = DateTime.Now; monster.CurrentHp = 0; monster.CurrentMp = 0; monster.Death = DateTime.Now; Target = -1; } } } else { int maxdistance = Npc.NoticeRange > 5 ? Npc.NoticeRange / 2 : Npc.NoticeRange; if (IsMoving) { const short maxDistance = 5; if (!Path.Any() && distance > 1 && distance < maxDistance) { short xoffset = (short)ServerManager.RandomNumber(-1, 1); short yoffset = (short)ServerManager.RandomNumber(-1, 1); Path = Map.StraightPath(new GridPos { x = MapX, y = MapY }, new GridPos { x = (short)(monster.MapX + xoffset), y = (short)(monster.MapY + yoffset) }); if (!Path.Any()) { Path = Map.JPSPlus(JumpPointParameters, new GridPos { x = MapX, y = MapY }, new GridPos { x = (short)(monster.MapX + xoffset), y = (short)(monster.MapY + yoffset) }); } } if (DateTime.Now > LastMove && Npc.Speed > 0 && Path.Any()) { int maxindex = Path.Count > Npc.Speed / 2 && Npc.Speed > 1 ? Npc.Speed / 2 : Path.Count; short mapX = (short)Path.ElementAt(maxindex - 1).x; short mapY = (short)Path.ElementAt(maxindex - 1).y; double waitingtime = Map.GetDistance(new MapCell { X = mapX, Y = mapY, MapId = MapId }, new MapCell { X = MapX, Y = MapY, MapId = MapId }) / (double)Npc.Speed; Map.Broadcast(new BroadcastPacket(null, $"mv 2 {MapNpcId} {mapX} {mapY} {Npc.Speed}", ReceiverType.AllInRange, 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; }); for (int j = maxindex; j > 0; j--) { Path.RemoveAt(0); } } if (Path.Any() && (MapId != monster.MapId || distance > maxDistance)) { Path = Map.StraightPath(new GridPos { x = MapX, y = MapY }, new GridPos { x = FirstX, y = FirstY }); if (!Path.Any()) { Path = Map.JPSPlus(JumpPointParameters, new GridPos { x = MapX, y = MapY }, new GridPos { x = FirstX, y = FirstY }); } Target = -1; } } else { if (distance > maxdistance) { Target = -1; } } } } }
/// <summary> /// Hit the Target Character. /// </summary> /// <param name="targetSession"></param> /// <param name="npcMonsterSkill"></param> private void TargetHit(ClientSession targetSession, NpcMonsterSkill npcMonsterSkill) { if (((DateTime.Now - LastEffect).TotalMilliseconds >= 1000 + Monster.BasicCooldown * 200 && !Skills.Any()) || npcMonsterSkill != null) { int damage = 0; int hitmode = 0; if (npcMonsterSkill != null) { damage = GenerateDamage(targetSession.Character, npcMonsterSkill.Skill, ref hitmode); } else { damage = GenerateDamage(targetSession.Character, null, ref hitmode); } if (npcMonsterSkill != null) { npcMonsterSkill.LastSkillUse = DateTime.Now; CurrentMp -= npcMonsterSkill.Skill.MpCost; Map.Broadcast($"ct 3 {MapMonsterId} 1 {Target} {npcMonsterSkill.Skill.CastAnimation} {npcMonsterSkill.Skill.CastEffect} {npcMonsterSkill.Skill.SkillVNum}"); } LastMove = DateTime.Now; // deal 0 damage to GM with GodMode if (targetSession.Character.HasGodMode) { damage = 0; } if (targetSession.Character.IsSitting) { targetSession.Character.IsSitting = false; Map.Broadcast(targetSession.Character.GenerateRest()); Thread.Sleep(500); } if (npcMonsterSkill != null && npcMonsterSkill.Skill.CastEffect != 0) { Map.Broadcast(GenerateEff(npcMonsterSkill.Skill.CastEffect), MapX, MapY); Thread.Sleep(npcMonsterSkill.Skill.CastTime * 100); } Path = new List <GridPos>(); targetSession.Character.LastDefence = DateTime.Now; targetSession.Character.GetDamage(damage); Map.Broadcast(null, ServerManager.Instance.GetUserMethod <string>(Target, "GenerateStat"), ReceiverType.OnlySomeone, "", Target); if (npcMonsterSkill != null) { Map.Broadcast($"su 3 {MapMonsterId} 1 {Target} {npcMonsterSkill.SkillVNum} {npcMonsterSkill.Skill.Cooldown} {npcMonsterSkill.Skill.AttackAnimation} {npcMonsterSkill.Skill.Effect} {this.MapX} {this.MapY} {(targetSession.Character.Hp > 0 ? 1 : 0)} { (int)(targetSession.Character.Hp / targetSession.Character.HPLoad() * 100) } {damage} {hitmode} 0"); } else { Map.Broadcast($"su 3 {MapMonsterId} 1 {Target} 0 {Monster.BasicCooldown} 11 {Monster.BasicSkill} 0 0 {(targetSession.Character.Hp > 0 ? 1 : 0)} { (int)(targetSession.Character.Hp / targetSession.Character.HPLoad() * 100) } {damage} {hitmode} 0"); } LastEffect = DateTime.Now; if (targetSession.Character.Hp <= 0) { Thread.Sleep(1000); ServerManager.Instance.AskRevive(targetSession.Character.CharacterId); RemoveTarget(); } if (npcMonsterSkill != null && (npcMonsterSkill.Skill.Range > 0 || npcMonsterSkill.Skill.TargetRange > 0)) { foreach (Character characterInRange in Map.GetCharactersInRange(npcMonsterSkill.Skill.TargetRange == 0 ? this.MapX : targetSession.Character.MapX, npcMonsterSkill.Skill.TargetRange == 0 ? this.MapY : targetSession.Character.MapY, npcMonsterSkill.Skill.TargetRange).Where(s => s.CharacterId != Target && s.Hp > 0)) { if (characterInRange.IsSitting) { characterInRange.IsSitting = false; Map.Broadcast(characterInRange.GenerateRest()); Thread.Sleep(500); } if (characterInRange.HasGodMode) { damage = 0; hitmode = 1; } bool AlreadyDead2 = characterInRange.Hp <= 0; characterInRange.GetDamage(damage); characterInRange.LastDefence = DateTime.Now; Map.Broadcast(null, characterInRange.GenerateStat(), ReceiverType.OnlySomeone, "", characterInRange.CharacterId); Map.Broadcast($"su 3 {MapMonsterId} 1 {characterInRange.CharacterId} 0 {Monster.BasicCooldown} 11 {Monster.BasicSkill} 0 0 {(characterInRange.Hp > 0 ? 1 : 0)} { (int)(characterInRange.Hp / characterInRange.HPLoad() * 100) } {damage} {hitmode} 0"); if (characterInRange.Hp <= 0 && !AlreadyDead2) { damage = characterInRange.HasGodMode ? 0 : 100; } bool alreadyDead = characterInRange.Hp <= 0; characterInRange.GetDamage(damage); characterInRange.LastDefence = DateTime.Now; characterInRange.Session.SendPacket(characterInRange.GenerateStat()); Map.Broadcast($"su 3 {MapMonsterId} 1 {characterInRange.CharacterId} 0 {Monster.BasicCooldown} 11 {Monster.BasicSkill} 0 0 {(characterInRange.Hp > 0 ? 1 : 0)} { (int)(characterInRange.Hp / characterInRange.HPLoad() * 100) } {damage} {hitmode} 0"); if (characterInRange.Hp <= 0 && !alreadyDead) { Thread.Sleep(1000); ServerManager.Instance.AskRevive(characterInRange.CharacterId); } } } } }
private void Move() { // Normal Move Mode if (!IsAlive) { return; } if (IsMoving && Monster.Speed > 0) { double time = (DateTime.Now - LastMove).TotalMilliseconds; if (Path.Where(s => s != null).Any()) { int timetowalk = 1000 / (2 * Monster.Speed); if (time > timetowalk) { int mapX = Path.ElementAt(0).x; int mapY = Path.ElementAt(0).y; Path.RemoveAt(0); Task.Factory.StartNew(async() => { await Task.Delay(timetowalk); MapX = (short)mapX; MapY = (short)mapY; }); LastMove = DateTime.Now; Map.Broadcast(new BroadcastPacket(null, GenerateMv3(), ReceiverType.AllInRange, xCoordinate: mapX, yCoordinate: mapY)); return; } } else if (time > _movetime) { _movetime = _random.Next(600, 3000); byte point = (byte)_random.Next(2, 4); byte fpoint = (byte)_random.Next(0, 2); byte xpoint = (byte)_random.Next(fpoint, point); byte ypoint = (byte)(point - xpoint); short mapX = FirstX; short mapY = FirstY; if (Map?.GetFreePosition(ref mapX, ref mapY, xpoint, ypoint) ?? false) { Task.Factory.StartNew(async() => { await Task.Delay(1000 * (xpoint + ypoint) / (2 * Monster.Speed)); this.MapX = mapX; this.MapY = mapY; }); LastMove = DateTime.Now.AddSeconds((xpoint + ypoint) / (2 * Monster.Speed)); Map.Broadcast(new BroadcastPacket(null, GenerateMv3(), ReceiverType.AllInRange, xCoordinate: mapX, yCoordinate: mapY)); } } } if (Monster.IsHostile) { Character character = ServerManager.Instance.Sessions.FirstOrDefault(s => s != null && s.Character != null && s.Character.Hp > 0 && !s.Character.InvisibleGm && !s.Character.Invisible && s.Character.MapId == MapId && Map.GetDistance(new MapCell() { X = MapX, Y = MapY }, new MapCell() { X = s.Character.MapX, Y = s.Character.MapY }) < Monster.NoticeRange)?.Character; if (character != null) { Target = character.CharacterId; if (!Monster.NoAggresiveIcon) { character.Session.SendPacket(GenerateEff(5000)); } } } }
/// <summary> /// Follow the Monsters target to it's position. /// </summary> /// <param name="targetSession">The TargetSession to follow</param> private void FollowTarget(ClientSession targetSession) { int distance = 0; if (targetSession != null) { distance = Map.GetDistance(new MapCell() { X = this.MapX, Y = this.MapY }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY }); } if (IsMoving) { short maxDistance = 22; if (Path.Count() == 0 && targetSession != null && distance > 1 && distance < maxDistance) { short xoffset = (short)_random.Next(-1, 1); short yoffset = (short)_random.Next(-1, 1); Path = Map.StraightPath(new GridPos() { x = this.MapX, y = this.MapY }, new GridPos() { x = (short)(targetSession.Character.MapX + xoffset), y = (short)(targetSession.Character.MapY + yoffset) }); if (!Path.Any()) { Path = Map.JPSPlus(new GridPos() { x = this.MapX, y = this.MapY }, new GridPos() { x = (short)(targetSession.Character.MapX + xoffset), y = (short)(targetSession.Character.MapY + yoffset) }); } } if (DateTime.Now > LastMove && Monster.Speed > 0 && Path.Any()) { short mapX; short mapY; int maxindex = Path.Count > Monster.Speed / 2 ? Monster.Speed / 2 : Path.Count; mapX = (short)Path.ElementAt(maxindex - 1).x; mapY = (short)Path.ElementAt(maxindex - 1).y; double waitingtime = (double)(Map.GetDistance(new MapCell() { X = mapX, Y = mapY, MapId = MapId }, new MapCell() { X = MapX, Y = MapY, MapId = MapId })) / (double)(Monster.Speed); Map.Broadcast(new BroadcastPacket(null, $"mv 3 {this.MapMonsterId} {mapX} {mapY} {Monster.Speed}", ReceiverType.AllInRange, xCoordinate: mapX, yCoordinate: mapY)); LastMove = DateTime.Now.AddSeconds((waitingtime > 1 ? 1 : waitingtime)); Task.Factory.StartNew(async() => { await Task.Delay((int)((waitingtime > 1 ? 1 : waitingtime) * 1000)); this.MapX = mapX; this.MapY = mapY; }); for (int j = maxindex; j > 0; j--) { Path.RemoveAt(0); } } if (Path.Count() == 0 && (DateTime.Now - LastEffect).Seconds > 20 && (targetSession == null || MapId != targetSession.Character.MapId || distance > maxDistance)) { RemoveTarget(); } } }
internal void MonsterLife() { // Respawn if (!Alive && Respawn) { double timeDeath = (DateTime.Now - Death).TotalSeconds; if (timeDeath >= Monster.RespawnTime / 10) { DamageList = new Dictionary <long, long>(); Alive = true; Target = -1; CurrentHp = Monster.MaxHP; CurrentMp = Monster.MaxMP; MapX = FirstX; MapY = FirstY; Path = new List <MapCell>(); Map.Broadcast(GenerateIn3()); Map.Broadcast(GenerateEff(7), MapX, MapY, 10); } return; } else if (Target == -1) { // Normal Move Mode if (!Alive) { return; } if (IsMoving && Monster.Speed > 0) { double time = (DateTime.Now - LastMove).TotalMilliseconds; if (Path.Where(s => s != null).Any()) { int timetowalk = 1000 / (2 * Monster.Speed); if (time > timetowalk) { short mapX = Path.ElementAt(0).X; short mapY = Path.ElementAt(0).Y; Path.RemoveAt(0); LastMove = DateTime.Now; Map.Broadcast(new BroadcastPacket(null, $"mv 3 {this.MapMonsterId} {mapX} {mapY} {Monster.Speed}", ReceiverType.AllInRange, xCoordinate: mapX, yCoordinate: mapY)); Task.Factory.StartNew(async() => { await Task.Delay(timetowalk); MapX = mapX; MapY = mapY; }); return; } } else if (time > _movetime) { _movetime = _random.Next(400, 3200); byte point = (byte)_random.Next(2, 4); byte fpoint = (byte)_random.Next(0, 2); byte xpoint = (byte)_random.Next(fpoint, point); byte ypoint = (byte)(point - xpoint); short mapX = FirstX; short mapY = FirstY; if (Map.GetFreePosition(ref mapX, ref mapY, xpoint, ypoint)) { Task.Factory.StartNew(async() => { await Task.Delay(1000 * (xpoint + ypoint) / (2 * Monster.Speed)); this.MapX = mapX; this.MapY = mapY; }); LastMove = DateTime.Now.AddSeconds((xpoint + ypoint) / (2 * Monster.Speed)); Map.Broadcast(new BroadcastPacket(null, $"mv 3 {this.MapMonsterId} {mapX} {mapY} {Monster.Speed}", ReceiverType.AllInRange, xCoordinate: mapX, yCoordinate: mapY)); } } } if (Monster.IsHostile) { Character character = ServerManager.Instance.Sessions.FirstOrDefault(s => s != null && s.Character != null && s.Character.Hp > 0 && !s.Character.InvisibleGm && !s.Character.Invisible && s.Character.MapId == MapId && Map.GetDistance(new MapCell() { X = MapX, Y = MapY }, new MapCell() { X = s.Character.MapX, Y = s.Character.MapY }) < 10)?.Character; if (character != null) { Target = character.CharacterId; if (!Monster.NoAggresiveIcon) { character.Session.SendPacket(GenerateEff(5000)); } } } } else { ClientSession targetSession = Map.GetSessionByCharacterId(Target); if (targetSession == null || targetSession.Character.Invisible || targetSession.Character.Hp <= 0) { Target = -1; Path = Map.StraightPath(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = FirstX, Y = FirstY, MapId = this.MapId }); if (!Path.Any()) { Path = Map.JPSPlus(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = FirstX, Y = FirstY, MapId = this.MapId }); } } NpcMonsterSkill npcMonsterSkill = null; if (_random.Next(10) > 8) { npcMonsterSkill = Skills.Where(s => (DateTime.Now - s.LastUse).TotalMilliseconds >= 100 * s.Skill.Cooldown).OrderBy(rnd => _random.Next()).FirstOrDefault(); } int damage = 100; if (targetSession != null && !targetSession.Character.InvisibleGm && !targetSession.Character.Invisible && targetSession.Character.Hp > 0 && ((npcMonsterSkill != null && CurrentMp - npcMonsterSkill.Skill.MpCost >= 0 && Map.GetDistance(new MapCell() { X = this.MapX, Y = this.MapY }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY }) < npcMonsterSkill.Skill.Range) || (Map.GetDistance(new MapCell() { X = this.MapX, Y = this.MapY }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY }) <= Monster.BasicRange))) { if (((DateTime.Now - LastEffect).TotalMilliseconds >= 1000 + Monster.BasicCooldown * 200 && !Skills.Any()) || npcMonsterSkill != null) { if (npcMonsterSkill != null) { npcMonsterSkill.LastUse = DateTime.Now; CurrentMp -= npcMonsterSkill.Skill.MpCost; Map.Broadcast($"ct 3 {MapMonsterId} 1 {Target} {npcMonsterSkill.Skill.CastAnimation} {npcMonsterSkill.Skill.CastEffect} {npcMonsterSkill.Skill.SkillVNum}"); } LastMove = DateTime.Now; // deal 0 damage to GM with GodMode damage = targetSession.Character.HasGodMode ? 0 : 100; if (targetSession.Character.IsSitting) { targetSession.Character.IsSitting = false; Map.Broadcast(targetSession.Character.GenerateRest()); Thread.Sleep(500); } if (npcMonsterSkill != null && npcMonsterSkill.Skill.CastEffect != 0) { Map.Broadcast(GenerateEff(npcMonsterSkill.Skill.CastEffect), MapX, MapY, 10); Thread.Sleep(npcMonsterSkill.Skill.CastTime * 100); } Path = new List <MapCell>(); targetSession.Character.LastDefence = DateTime.Now; targetSession.Character.GetDamage(damage); Map.Broadcast(null, ServerManager.Instance.GetUserMethod <string>(Target, "GenerateStat"), ReceiverType.OnlySomeone, "", Target); if (npcMonsterSkill != null) { Map.Broadcast($"su 3 {MapMonsterId} 1 {Target} {npcMonsterSkill.SkillVNum} {npcMonsterSkill.Skill.Cooldown} {npcMonsterSkill.Skill.AttackAnimation} {npcMonsterSkill.Skill.Effect} {this.MapX} {this.MapY} {(targetSession.Character.Hp > 0 ? 1 : 0)} { (int)(targetSession.Character.Hp / targetSession.Character.HPLoad() * 100) } {damage} 0 0"); } else { Map.Broadcast($"su 3 {MapMonsterId} 1 {Target} 0 {Monster.BasicCooldown} 11 {Monster.BasicSkill} 0 0 {(targetSession.Character.Hp > 0 ? 1 : 0)} { (int)(targetSession.Character.Hp / targetSession.Character.HPLoad() * 100) } {damage} 0 0"); } LastEffect = DateTime.Now; if (targetSession.Character.Hp <= 0) { Thread.Sleep(1000); ServerManager.Instance.AskRevive(targetSession.Character.CharacterId); Path = Map.StraightPath(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = FirstX, Y = FirstY, MapId = this.MapId }); if (!Path.Any()) { Path = Map.JPSPlus(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = FirstX, Y = FirstY, MapId = this.MapId }); } Target = -1; } if (npcMonsterSkill != null && (npcMonsterSkill.Skill.Range > 0 || npcMonsterSkill.Skill.TargetRange > 0)) { foreach (Character chara in Map.GetListPeopleInRange(npcMonsterSkill.Skill.TargetRange == 0 ? this.MapX : targetSession.Character.MapX, npcMonsterSkill.Skill.TargetRange == 0 ? this.MapY : targetSession.Character.MapY, (byte)(npcMonsterSkill.Skill.TargetRange + npcMonsterSkill.Skill.Range)).Where(s => s.CharacterId != Target && s.Hp > 0)) { if (chara.IsSitting) { chara.IsSitting = false; Map.Broadcast(chara.GenerateRest()); Thread.Sleep(500); } damage = chara.HasGodMode ? 0 : 100; bool AlreadyDead2 = chara.Hp <= 0; chara.GetDamage(damage); chara.LastDefence = DateTime.Now; Map.Broadcast(null, chara.GenerateStat(), ReceiverType.OnlySomeone, "", chara.CharacterId); Map.Broadcast($"su 3 {MapMonsterId} 1 {chara.CharacterId} 0 {Monster.BasicCooldown} 11 {Monster.BasicSkill} 0 0 {(chara.Hp > 0 ? 1 : 0)} { (int)(chara.Hp / chara.HPLoad() * 100) } {damage} 0 0"); if (chara.Hp <= 0 && !AlreadyDead2) { Thread.Sleep(1000); ServerManager.Instance.AskRevive(chara.CharacterId); } } } } } else { int distance = 0; if (targetSession != null) { distance = Map.GetDistance(new MapCell() { X = this.MapX, Y = this.MapY }, new MapCell() { X = targetSession.Character.MapX, Y = targetSession.Character.MapY }); } if (IsMoving) { short maxDistance = 22; if (Path.Count() == 0 && targetSession != null && distance > 1 && distance < maxDistance) { short xoffset = (short)_random.Next(-1, 1); short yoffset = (short)_random.Next(-1, 1); Path = Map.StraightPath(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = (short)(targetSession.Character.MapX + xoffset), Y = (short)(targetSession.Character.MapY + yoffset), MapId = this.MapId }); if (!Path.Any()) { Path = Map.JPSPlus(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = (short)(targetSession.Character.MapX + xoffset), Y = (short)(targetSession.Character.MapY + yoffset), MapId = this.MapId }); } } if (DateTime.Now > LastMove && Monster.Speed > 0 && Path.Any()) { short mapX; short mapY; int maxindex = Path.Count > Monster.Speed / 2 ? Monster.Speed / 2 : Path.Count; mapX = Path.ElementAt(maxindex - 1).X; mapY = Path.ElementAt(maxindex - 1).Y; double waitingtime = (double)(Map.GetDistance(new MapCell() { X = mapX, Y = mapY, MapId = MapId }, new MapCell() { X = MapX, Y = MapY, MapId = MapId })) / (double)(Monster.Speed); Map.Broadcast(new BroadcastPacket(null, $"mv 3 {this.MapMonsterId} {mapX} {mapY} {Monster.Speed}", ReceiverType.AllInRange, xCoordinate: mapX, yCoordinate: mapY)); LastMove = DateTime.Now.AddSeconds((waitingtime > 1 ? 1 : waitingtime)); Task.Factory.StartNew(async() => { await Task.Delay((int)((waitingtime > 1 ? 1 : waitingtime) * 1000)); this.MapX = mapX; this.MapY = mapY; }); for (int j = maxindex; j > 0; j--) { Path.RemoveAt(0); } } if (Path.Count() == 0 && (targetSession == null || MapId != targetSession.Character.MapId || distance > maxDistance)) { Path = Map.StraightPath(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = FirstX, Y = FirstY, MapId = this.MapId }); if (!Path.Any()) { Path = Map.JPSPlus(new MapCell() { X = this.MapX, Y = this.MapY, MapId = this.MapId }, new MapCell() { X = FirstX, Y = FirstY, MapId = this.MapId }); } Target = -1; } } } } }