using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using PhoenixLib.Events; using WingsAPI.Scripting.Object.Timespace; using WingsEmu.DTOs.BCards; using WingsEmu.Game._enum; using WingsEmu.Game.Act4; using WingsEmu.Game.Battle; using WingsEmu.Game.Battle.Managers; using WingsEmu.Game.Buffs; using WingsEmu.Game.Characters; using WingsEmu.Game.Characters.Events; using WingsEmu.Game.Entities; using WingsEmu.Game.Extensions; using WingsEmu.Game.Maps; using WingsEmu.Game.Mates; using WingsEmu.Game.Monster.Event; using WingsEmu.Game.Networking; using WingsEmu.Game.Quests.Event; using WingsEmu.Game.TimeSpaces; using WingsEmu.Game.TimeSpaces.Events; using WingsEmu.Game.Triggers; using WingsEmu.Packets.Enums; namespace WingsEmu.Plugins.BasicImplementations.Event.Monster; public class MonsterDeathEventHandler : IAsyncEventProcessor { private readonly IAct4FlagManager _act4FlagManager; private readonly IAsyncEventPipeline _asyncEventPipeline; private readonly IBCardEffectHandlerContainer _bCardEffectHandlerContainer; private readonly IPhantomPositionManager _phantomPositionManager; private readonly ITimeSpaceManager _timeSpaceManager; public MonsterDeathEventHandler(IBCardEffectHandlerContainer bCardEffectHandlerContainer, IAsyncEventPipeline asyncEventPipeline, ITimeSpaceManager timeSpaceManager, IAct4FlagManager act4FlagManager, IPhantomPositionManager phantomPositionManager) { _bCardEffectHandlerContainer = bCardEffectHandlerContainer; _asyncEventPipeline = asyncEventPipeline; _timeSpaceManager = timeSpaceManager; _act4FlagManager = act4FlagManager; _phantomPositionManager = phantomPositionManager; } public async Task HandleAsync(MonsterDeathEvent e, CancellationToken cancellation) { IMonsterEntity monsterEntity = e.MonsterEntity; DateTime dateTimeNow = DateTime.UtcNow; monsterEntity.IsStillAlive = false; monsterEntity.Hp = 0; monsterEntity.Death = dateTimeNow; monsterEntity.Killer = e.Killer; if (monsterEntity.SummonerType is not VisualType.Player) { monsterEntity.MapInstance.IncreaseMonsterDeathsOnMap(); } monsterEntity.MapInstance.DeactivateMode(monsterEntity); if (monsterEntity.DeathEffect != 0) { monsterEntity.BroadcastEffectInRange(monsterEntity.DeathEffect); } if (monsterEntity.IsPhantom()) { _phantomPositionManager.AddPosition(monsterEntity.UniqueId, monsterEntity.Position); } await monsterEntity.TriggerEvents(BattleTriggers.OnDeath); if (!e.IsByCommand) { IEnumerable triggerBCard = monsterEntity.BCards.Where(b => b.TriggerType == BCardNpcMonsterTriggerType.ON_DEATH); foreach (BCardDTO bCard in triggerBCard) { _bCardEffectHandlerContainer.Execute(monsterEntity, monsterEntity, bCard, triggerType: BCardNpcMonsterTriggerType.ON_DEATH); } } if (monsterEntity.MapInstance.MapInstanceType == MapInstanceType.TimeSpaceInstance) { await CheckTargetMonstersInRoom(monsterEntity); await _asyncEventPipeline.ProcessEventAsync(new TimeSpaceCheckMonsterEvent(monsterEntity), cancellation); } monsterEntity.Mp = 0; switch (e.Killer) { case IPlayerEntity player: await player.Session.EmitEventAsync(new KillBonusEvent { MonsterEntity = monsterEntity }); if (player.IsInGroup()) { foreach (IPlayerEntity member in player.GetGroup().Members.ToArray()) { await member.Session.EmitEventAsync(new QuestMonsterDeathEvent { MonsterEntity = monsterEntity }); } } else { await player.Session.EmitEventAsync(new QuestMonsterDeathEvent { MonsterEntity = monsterEntity }); } player.HitsByMonsters.TryRemove(monsterEntity.Id, out _); break; case IMateEntity mate: await mate.Owner.Session.EmitEventAsync(new KillBonusEvent { MonsterEntity = monsterEntity }); if (mate.Owner.IsInGroup()) { foreach (IPlayerEntity member in mate.Owner.GetGroup().Members.ToArray()) { await member.Session.EmitEventAsync(new QuestMonsterDeathEvent { MonsterEntity = monsterEntity }); } } else { await mate.Owner.Session.EmitEventAsync(new QuestMonsterDeathEvent { MonsterEntity = monsterEntity }); } break; case IMonsterEntity mapMonster: if (!mapMonster.SummonerId.HasValue) { break; } if (mapMonster.IsMateTrainer) { break; } if (mapMonster.SummonerType != VisualType.Player) { break; } IClientSession summoner = mapMonster.MapInstance.GetCharacterById(mapMonster.SummonerId.Value)?.Session; if (summoner == null) { break; } if (monsterEntity.MonsterVNum == (short)MonsterVnum.BOMB) { summoner.PlayerEntity.SkillComponent.BombEntityId = null; } await summoner.EmitEventAsync(new KillBonusEvent { MonsterEntity = monsterEntity }); if (summoner.PlayerEntity.IsInGroup()) { foreach (IPlayerEntity member in summoner.PlayerEntity.GetGroup().Members.ToArray()) { await member.Session.EmitEventAsync(new QuestMonsterDeathEvent { MonsterEntity = monsterEntity }); } } else { await summoner.EmitEventAsync(new QuestMonsterDeathEvent { MonsterEntity = monsterEntity }); } break; } switch ((MonsterVnum)monsterEntity.MonsterVNum) { case MonsterVnum.DEMON_CAMP: _act4FlagManager.RemoveDemonFlag(); break; case MonsterVnum.ANGEL_CAMP: _act4FlagManager.RemoveAngelFlag(); break; } await monsterEntity.RemoveAllBuffsAsync(true); monsterEntity.MapInstance.ForgetAll(monsterEntity, dateTimeNow); } private async Task CheckTargetMonstersInRoom(IMonsterEntity monsterEntity) { if (!monsterEntity.IsTarget) { return; } Guid guid = monsterEntity.MapInstance.Id; TimeSpaceParty timeSpace = _timeSpaceManager.GetTimeSpaceByMapInstanceId(guid); if (timeSpace == null) { return; } if (timeSpace.Instance.TimeSpaceObjective.KillMonsterVnum.HasValue && monsterEntity.MonsterVNum == timeSpace.Instance.TimeSpaceObjective.KillMonsterVnum.Value) { timeSpace.Instance.TimeSpaceObjective.KilledMonsterAmount++; await _asyncEventPipeline.ProcessEventAsync(new TimeSpaceRefreshObjectiveProgressEvent { MapInstanceId = guid }); } if (monsterEntity.MapInstance.GetAliveMonsters(x => x.IsTarget).Any()) { return; } TimeSpaceSubInstance timeSpaceSubInstance = _timeSpaceManager.GetSubInstance(guid); if (timeSpaceSubInstance == null) { return; } await timeSpaceSubInstance.TriggerEvents(TimespaceConstEventKeys.OnAllTargetMobsDead); } }