using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using PhoenixLib.Events; using WingsAPI.Game.Extensions.ItemExtension.Inventory; using WingsAPI.Game.Extensions.Quests; using WingsEmu.DTOs.Quests; using WingsEmu.Game.Entities; using WingsEmu.Game.Extensions; using WingsEmu.Game.Helpers.Damages; using WingsEmu.Game.Items; using WingsEmu.Game.Managers; using WingsEmu.Game.Managers.StaticData; using WingsEmu.Game.Networking; using WingsEmu.Game.Quests; using WingsEmu.Game.Quests.Event; using WingsEmu.Packets.Enums; namespace Plugin.QuestImpl.Handlers { public class QuestNpcTalkEventHandler : IAsyncEventProcessor { private readonly IItemsManager _itemsManager; private readonly IQuestManager _questManager; private readonly IServerManager _serverManager; public QuestNpcTalkEventHandler(IItemsManager itemsManager, IServerManager serverManager, IQuestManager questManager) { _itemsManager = itemsManager; _serverManager = serverManager; _questManager = questManager; } public async Task HandleAsync(QuestNpcTalkEvent e, CancellationToken cancellation) { IClientSession session = e.Sender; CharacterQuest characterQuest = e.CharacterQuest; INpcEntity npcEntity = e.NpcEntity; bool isByBlueAlertNrun = e.IsByBlueAlertNrun; if (!session.PlayerEntity.IsInAoeZone(npcEntity, _serverManager.MaxNpcTalkRange)) { return; } switch (characterQuest.Quest.QuestType) { case QuestType.DIALOG: //12 case QuestType.DIALOG_2: //22 case QuestType.DELIVER_ITEM_TO_NPC: //4 case QuestType.GIVE_ITEM_TO_NPC: //14 (Same than before but without random values) case QuestType.GIVE_ITEM_TO_NPC_2: //24 case QuestType.GIVE_NPC_GOLD: //18 HandleDeliver(session, characterQuest, npcEntity, isByBlueAlertNrun); break; case QuestType.DIALOG_WHILE_WEARING: //15 HandleWearing(session, characterQuest, npcEntity); break; case QuestType.DIALOG_WHILE_HAVING_ITEM: //16 HandleHaving(session, characterQuest, npcEntity); break; case QuestType.WIN_RAID_AND_TALK_TO_NPC: //25 await HandleRaid(session, characterQuest, npcEntity); break; } } public void HandleDeliver(IClientSession session, CharacterQuest characterQuest, INpcEntity npcEntity, bool isByBlueAlertNrun) { IEnumerable objectives = characterQuest.Quest.Objectives; foreach (QuestObjectiveDto objective in objectives) { if (npcEntity.NpcVNum != (characterQuest.Quest.QuestType is QuestType.DELIVER_ITEM_TO_NPC ? objective.Data1 : objective.Data0)) { continue; } CharacterQuestObjectiveDto questObjectiveDto = characterQuest.ObjectiveAmount[objective.ObjectiveIndex]; switch (characterQuest.Quest.QuestType) { case QuestType.DELIVER_ITEM_TO_NPC: case QuestType.GIVE_ITEM_TO_NPC: int amountLeft = questObjectiveDto.RequiredAmount - questObjectiveDto.CurrentAmount; if (amountLeft == 0) { break; } int amountInPossession = session.PlayerEntity.CountItemWithVnum(characterQuest.Quest.QuestType is QuestType.DELIVER_ITEM_TO_NPC ? objective.Data0 : objective.Data1); if (amountInPossession == 0) { break; } int amountToRemove = Math.Min(amountLeft, amountInPossession); session.RemoveItemFromInventory(characterQuest.Quest.QuestType is QuestType.DELIVER_ITEM_TO_NPC ? objective.Data0 : objective.Data1, (short)amountToRemove); questObjectiveDto.CurrentAmount += amountToRemove; session.EmitEvent(new QuestObjectiveUpdatedEvent { CharacterQuest = characterQuest }); session.RefreshQuestProgress(_questManager, characterQuest.QuestId); if (session.PlayerEntity.IsQuestCompleted(characterQuest)) { session.EmitEvent(new QuestCompletedEvent(characterQuest)); } break; case QuestType.GIVE_NPC_GOLD: int totalGoldToGive = questObjectiveDto.RequiredAmount; // It is the way it's stored if (session.PlayerEntity.Gold < totalGoldToGive) { continue; } questObjectiveDto.CurrentAmount += totalGoldToGive; session.EmitEvent(new QuestObjectiveUpdatedEvent { CharacterQuest = characterQuest }); session.PlayerEntity.RemoveGold(totalGoldToGive); session.RefreshQuestProgress(_questManager, characterQuest.QuestId); session.EmitEvent(new QuestCompletedEvent(characterQuest)); break; case QuestType.DIALOG: case QuestType.DIALOG_2: // They have a special behavior if (_questManager.IsNpcBlueAlertQuest(characterQuest.QuestId) && !isByBlueAlertNrun) { continue; } questObjectiveDto.CurrentAmount++; session.EmitEvent(new QuestObjectiveUpdatedEvent { CharacterQuest = characterQuest }); bool giveNextQuest = !_questManager.IsNpcBlueAlertQuest(characterQuest.QuestId) || _questManager.IsNpcBlueAlertQuest(characterQuest.QuestId) && !session.PlayerEntity.HasCompletedQuest(characterQuest.Quest.NextQuestId); if (session.PlayerEntity.IsQuestCompleted(characterQuest)) { session.EmitEvent(new QuestCompletedEvent(characterQuest, true, giveNextQuest: giveNextQuest)); } break; case QuestType.GIVE_ITEM_TO_NPC_2: if (objective.Data0 != npcEntity.NpcVNum) { return; } amountLeft = questObjectiveDto.RequiredAmount - questObjectiveDto.CurrentAmount; if (amountLeft == 0) { break; } questObjectiveDto.CurrentAmount++; session.RefreshQuestProgress(_questManager, characterQuest.QuestId); session.EmitEvent(new QuestObjectiveUpdatedEvent { CharacterQuest = characterQuest }); if (session.PlayerEntity.IsQuestCompleted(characterQuest)) { session.EmitEvent(new QuestCompletedEvent(characterQuest, true, giveNextQuest: _questManager.IsNpcBlueAlertQuest(characterQuest.QuestId))); } break; } } } public async Task HandleRaid(IClientSession session, CharacterQuest characterQuest, INpcEntity npcEntity) { IEnumerable objectives = characterQuest.Quest.Objectives; foreach (QuestObjectiveDto objective in objectives) { if (npcEntity.NpcVNum != objective.Data2) { continue; } CharacterQuestObjectiveDto questObjectiveDto = characterQuest.ObjectiveAmount[objective.ObjectiveIndex]; int amountLeft = questObjectiveDto.RequiredAmount - questObjectiveDto.CurrentAmount; if (amountLeft != 0) { return; } await session.EmitEventAsync(new QuestCompletedEvent(characterQuest, true, ignoreNotCompletedQuest: true)); } } public void HandleWearing(IClientSession session, CharacterQuest characterQuest, INpcEntity npcEntity) { IEnumerable objectives = characterQuest.Quest.Objectives; foreach (QuestObjectiveDto objective in objectives) { if (npcEntity.NpcVNum != objective.Data0) { continue; } IGameItem gameItem = _itemsManager.GetItem(objective.Data1); if (gameItem == null) { continue; } GameItemInstance inv = session.PlayerEntity.GetItemInstanceFromEquipmentSlot(gameItem.EquipmentSlot); if (inv == null || inv.ItemVNum != objective.Data1) { continue; } CharacterQuestObjectiveDto questObjectiveDto = characterQuest.ObjectiveAmount[objective.ObjectiveIndex]; questObjectiveDto.CurrentAmount++; } // Checks that all the requirements have been met if (!session.PlayerEntity.IsQuestCompleted(characterQuest)) { characterQuest.ResetQuestProgress(); } else { session.EmitEventAsync(new QuestObjectiveUpdatedEvent { CharacterQuest = characterQuest }); session.EmitEvent(new QuestCompletedEvent(characterQuest)); } } public void HandleHaving(IClientSession session, CharacterQuest characterQuest, INpcEntity npcEntity) { IEnumerable objectives = characterQuest.Quest.Objectives; foreach (QuestObjectiveDto objective in objectives) { CharacterQuestObjectiveDto questObjectiveDto = characterQuest.ObjectiveAmount[objective.ObjectiveIndex]; if (npcEntity.NpcVNum != objective.Data0 || session.PlayerEntity.CountItemWithVnum(objective.Data1) < questObjectiveDto.RequiredAmount) { return; } } session.EmitEvent(new QuestCompletedEvent(characterQuest)); } } }