public void OnSFXDestroy(MeteorUnit unit, Collider co) { if (DamageList.ContainsKey(unit)) { DamageList[unit].Remove(co); } }
/// <summary> /// Handle any kind of Monster interaction /// </summary> private void monsterLife() { if (Monster == null) { return; } if ((DateTime.Now - LastEffect).TotalSeconds >= 5) { LastEffect = DateTime.Now; if (IsTarget) { MapInstance.Broadcast(StaticPacketHelper.GenerateEff(UserType.Monster, MapMonsterId, 824)); } if (IsBonus) { MapInstance.Broadcast(StaticPacketHelper.GenerateEff(UserType.Monster, MapMonsterId, 826)); } } if (IsBoss && IsAlive) { MapInstance.Broadcast(GenerateBoss()); } // handle hit queue while (HitQueue.TryDequeue(out HitRequest hitRequest)) { if (IsAlive && hitRequest.Session.Character.Hp > 0 && (ServerManager.Instance.ChannelId != 51 || MonsterVNum - (byte)hitRequest.Session.Character.Faction != 678)) { int hitmode = 0; bool isCaptureSkill = hitRequest.Skill.BCards.Any(s => s.Type.Equals((byte)CardType.Capture)); // calculate damage bool onyxWings = false; BattleEntity battleEntity = new BattleEntity(hitRequest.Session.Character, hitRequest.Skill); int damage = DamageHelper.Instance.CalculateDamage(battleEntity, new BattleEntity(this), hitRequest.Skill, ref hitmode, ref onyxWings); if (onyxWings) { short onyxX = (short)(hitRequest.Session.Character.PositionX + 2); short onyxY = (short)(hitRequest.Session.Character.PositionY + 2); int onyxId = MapInstance.GetNextMonsterId(); MapMonster onyx = new MapMonster() { MonsterVNum = 2371, MapX = onyxX, MapY = onyxY, MapMonsterId = onyxId, IsHostile = false, IsMoving = false, ShouldRespawn = false }; MapInstance.Broadcast(UserInterfaceHelper.Instance.GenerateGuri(31, 1, hitRequest.Session.Character.CharacterId, onyxX, onyxY)); onyx.Initialize(MapInstance); MapInstance.AddMonster(onyx); MapInstance.Broadcast(onyx.GenerateIn()); CurrentHp -= damage / 2; Observable.Timer(TimeSpan.FromMilliseconds(350)).Subscribe(o => { MapInstance.Broadcast(StaticPacketHelper.SkillUsed(UserType.Monster, onyxId, 3, MapMonsterId, -1, 0, -1, hitRequest.Skill.Effect, -1, -1, true, 92, damage / 2, 0, 0)); MapInstance.RemoveMonster(onyx); MapInstance.Broadcast(StaticPacketHelper.Out(UserType.Monster, onyx.MapMonsterId)); }); } if (hitmode != 1) { hitRequest.Skill.BCards.Where(s => s.Type.Equals((byte)CardType.Buff)).ToList().ForEach(s => s.ApplyBCards(this, hitRequest.Session)); hitRequest.Skill.BCards.Where(s => s.Type.Equals((byte)CardType.Capture)).ToList().ForEach(s => s.ApplyBCards(this, hitRequest.Session)); if (battleEntity?.ShellWeaponEffects != null) { foreach (ShellEffectDTO shell in battleEntity.ShellWeaponEffects) { switch (shell.Effect) { case (byte)ShellWeaponEffectType.Blackout: { Buff buff = new Buff(7, battleEntity.Level); if (ServerManager.Instance.RandomNumber() < shell.Value) { AddBuff(buff); } break; } case (byte)ShellWeaponEffectType.DeadlyBlackout: { Buff buff = new Buff(66, battleEntity.Level); if (ServerManager.Instance.RandomNumber() < shell.Value) { AddBuff(buff); } break; } case (byte)ShellWeaponEffectType.MinorBleeding: { Buff buff = new Buff(1, battleEntity.Level); if (ServerManager.Instance.RandomNumber() < shell.Value) { AddBuff(buff); } break; } case (byte)ShellWeaponEffectType.Bleeding: { Buff buff = new Buff(21, battleEntity.Level); if (ServerManager.Instance.RandomNumber() < shell.Value) { AddBuff(buff); } break; } case (byte)ShellWeaponEffectType.HeavyBleeding: { Buff buff = new Buff(42, battleEntity.Level); if (ServerManager.Instance.RandomNumber() < shell.Value) { AddBuff(buff); } break; } case (byte)ShellWeaponEffectType.Freeze: { Buff buff = new Buff(27, battleEntity.Level); if (ServerManager.Instance.RandomNumber() < shell.Value) { AddBuff(buff); } break; } } } } } if (DamageList.ContainsKey(hitRequest.Session.Character.CharacterId)) { DamageList[hitRequest.Session.Character.CharacterId] += damage; } else { DamageList.Add(hitRequest.Session.Character.CharacterId, damage); } if (isCaptureSkill) { damage = 0; } if (CurrentHp <= damage) { SetDeathStatement(); } else { CurrentHp -= damage; } // only set the hit delay if we become the monsters target with this hit if (Target == -1) { LastSkill = DateTime.Now; } int nearestDistance = 100; foreach (KeyValuePair <long, long> kvp in DamageList) { ClientSession session = MapInstance.GetSessionByCharacterId(kvp.Key); if (session != null) { int distance = Map.GetDistance(new MapCell { X = MapX, Y = MapY }, new MapCell { X = session.Character.PositionX, Y = session.Character.PositionY }); if (distance < nearestDistance) { nearestDistance = distance; Target = session.Character.CharacterId; } } } switch (hitRequest.TargetHitType) { case TargetHitType.SingleTargetHit: if (!isCaptureSkill) { MapInstance?.Broadcast(StaticPacketHelper.SkillUsed(UserType.Player, hitRequest.Session.Character.CharacterId, 3, MapMonsterId, hitRequest.Skill.SkillVNum, hitRequest.Skill.Cooldown, hitRequest.Skill.AttackAnimation, hitRequest.SkillEffect, hitRequest.Session.Character.PositionX, hitRequest.Session.Character.PositionY, IsAlive, (int)((float)CurrentHp / (float)MaxHp * 100), damage, hitmode, (byte)(hitRequest.Skill.SkillType - 1))); } break; case TargetHitType.SingleTargetHitCombo: MapInstance?.Broadcast(StaticPacketHelper.SkillUsed(UserType.Player, hitRequest.Session.Character.CharacterId, 3, MapMonsterId, hitRequest.Skill.SkillVNum, hitRequest.Skill.Cooldown, hitRequest.SkillCombo.Animation, hitRequest.SkillCombo.Effect, hitRequest.Session.Character.PositionX, hitRequest.Session.Character.PositionY, IsAlive, (int)((float)CurrentHp / (float)MaxHp * 100), damage, hitmode, (byte)(hitRequest.Skill.SkillType - 1))); break; case TargetHitType.SingleAOETargetHit: switch (hitmode) { case 1: hitmode = 4; break; case 3: hitmode = 6; break; default: hitmode = 5; break; } if (hitRequest.ShowTargetHitAnimation) { MapInstance?.Broadcast(StaticPacketHelper.SkillUsed(UserType.Player, hitRequest.Session.Character.CharacterId, 3, MapMonsterId, hitRequest.Skill.SkillVNum, hitRequest.Skill.Cooldown, hitRequest.Skill.AttackAnimation, hitRequest.SkillEffect, hitRequest.Session.Character.PositionX, hitRequest.Session.Character.PositionY, IsAlive, (int)((float)CurrentHp / (float)MaxHp * 100), damage, hitmode, (byte)(hitRequest.Skill.SkillType - 1))); } else { MapInstance?.Broadcast(StaticPacketHelper.SkillUsed(UserType.Player, hitRequest.Session.Character.CharacterId, 3, MapMonsterId, 0, 0, 0, 0, 0, 0, IsAlive, (int)((float)CurrentHp / (float)MaxHp * 100), damage, hitmode, (byte)(hitRequest.Skill.SkillType - 1))); } break; case TargetHitType.AOETargetHit: switch (hitmode) { case 1: hitmode = 4; break; case 3: hitmode = 6; break; default: hitmode = 5; break; } MapInstance?.Broadcast(StaticPacketHelper.SkillUsed(UserType.Player, hitRequest.Session.Character.CharacterId, 3, MapMonsterId, hitRequest.Skill.SkillVNum, hitRequest.Skill.Cooldown, hitRequest.Skill.AttackAnimation, hitRequest.SkillEffect, hitRequest.Session.Character.PositionX, hitRequest.Session.Character.PositionY, IsAlive, (int)((float)CurrentHp / (float)MaxHp * 100), damage, hitmode, (byte)(hitRequest.Skill.SkillType - 1))); break; case TargetHitType.ZoneHit: MapInstance?.Broadcast(StaticPacketHelper.SkillUsed(UserType.Player, hitRequest.Session.Character.CharacterId, 3, MapMonsterId, hitRequest.Skill.SkillVNum, hitRequest.Skill.Cooldown, hitRequest.Skill.AttackAnimation, hitRequest.SkillEffect, hitRequest.MapX, hitRequest.MapY, IsAlive, (int)((float)CurrentHp / (float)MaxHp * 100), damage, 5, (byte)(hitRequest.Skill.SkillType - 1))); break; case TargetHitType.SpecialZoneHit: MapInstance?.Broadcast(StaticPacketHelper.SkillUsed(UserType.Player, hitRequest.Session.Character.CharacterId, 3, MapMonsterId, hitRequest.Skill.SkillVNum, hitRequest.Skill.Cooldown, hitRequest.Skill.AttackAnimation, hitRequest.SkillEffect, hitRequest.Session.Character.PositionX, hitRequest.Session.Character.PositionY, IsAlive, (int)((float)CurrentHp / (float)MaxHp * 100), damage, hitmode, (byte)(hitRequest.Skill.SkillType - 1))); break; } if (CurrentHp <= 0 && !isCaptureSkill) { // generate the kill bonus hitRequest.Session.Character.GenerateKillBonus(this); } } else { // monster already has been killed, send cancel hitRequest.Session.SendPacket(StaticPacketHelper.Cancel(2, MapMonsterId)); } if (IsBoss) { MapInstance.Broadcast(GenerateBoss()); } } // Respawn if (!IsAlive && ShouldRespawn != null && !ShouldRespawn.Value) { MapInstance.RemoveMonster(this); } if (!IsAlive && ShouldRespawn != null && ShouldRespawn.Value) { double timeDeath = (DateTime.Now - Death).TotalSeconds; if (timeDeath >= Monster.RespawnTime / 10d) { respawn(); } } // normal movement else if (Target == -1) { move(); } // target following else if (MapInstance != null) { GetNearestOponent(); HostilityTarget(); ClientSession targetSession = MapInstance.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 (Skills != null && ServerManager.Instance.RandomNumber(0, 10) > 8) { npcMonsterSkill = Skills.Where(s => (DateTime.Now - s.LastSkillUse).TotalMilliseconds >= 100 * s.Skill?.Cooldown)?.OrderBy(rnd => _random.Next())?.FirstOrDefault(); } if (npcMonsterSkill?.Skill.TargetType == 1 && npcMonsterSkill?.Skill.HitType == 0) { targetHit(targetSession, npcMonsterSkill); } // check if target is in range if (!targetSession.Character.InvisibleGm && !targetSession.Character.Invisible && targetSession.Character.Hp > 0) { if (npcMonsterSkill != null && CurrentMp >= npcMonsterSkill.Skill.MpCost && Map.GetDistance(new MapCell { X = MapX, Y = MapY }, new MapCell { X = targetSession.Character.PositionX, Y = targetSession.Character.PositionY }) < npcMonsterSkill.Skill.Range) { targetHit(targetSession, npcMonsterSkill); } else if (Map.GetDistance(new MapCell { X = MapX, Y = MapY }, new MapCell { X = targetSession.Character.PositionX, Y = targetSession.Character.PositionY }) <= Monster.BasicRange) { targetHit(targetSession, npcMonsterSkill); } else { followTarget(targetSession); } } else { followTarget(targetSession); } } }