using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Qmmands; using WingsAPI.Game.Extensions.Quests; using WingsEmu.Commands.Checks; using WingsEmu.Commands.Entities; using WingsEmu.DTOs.Account; using WingsEmu.DTOs.Quests; using WingsEmu.Game.Extensions; using WingsEmu.Game.Networking; using WingsEmu.Game.Quests; using WingsEmu.Game.Quests.Event; using WingsEmu.Packets.Enums.Chat; namespace Plugin.QuestImpl { [Name("Quests")] [Group("quests", "quest")] [Description("Module related to Quest commands.")] [RequireAuthority(AuthorityType.SuperGameMaster)] public class QuestModule : SaltyModuleBase { private readonly IQuestFactory _questFactory; private readonly IQuestManager _questManager; public QuestModule(IQuestManager questManager, IQuestFactory questFactory) { _questManager = questManager; _questFactory = questFactory; } [Command("add")] [Description("Add the quest linked to a given ID")] public async Task AddQuest(int questId, string questSlotTypeName) { if (!Enum.TryParse(questSlotTypeName, out QuestSlotType questSlotType)) { return new SaltyCommandResult(false, "Wrong quest slot type"); } QuestDto quest = _questManager.GetQuestById(questId); if (quest == null) { return new SaltyCommandResult(false, "Quest null"); } Context.Player.PlayerEntity.AddActiveQuest(_questFactory.NewQuest(Context.Player.PlayerEntity.Id, questId, questSlotType)); Context.Player.RefreshQuestList(_questManager, quest.Id); Context.Player.SendTargetQuest(quest.TargetMapX, quest.TargetMapY, quest.TargetMapId, quest.Id); return new SaltyCommandResult(true, "Quest added!"); } [Command("give")] [Description("Gives the quest to a character on a slot (general, main, secondary)")] public async Task AddQuest(IClientSession session, int questId, string questSlotTypeName) { if (!Enum.TryParse(questSlotTypeName, out QuestSlotType questSlotType)) { return new SaltyCommandResult(false, "Wrong quest slot type"); } QuestDto quest = _questManager.GetQuestById(questId); if (quest == null) { return new SaltyCommandResult(false, "Quest null"); } if (session == null) { return new SaltyCommandResult(false, "Player null"); } session.PlayerEntity.AddActiveQuest(_questFactory.NewQuest(session.PlayerEntity.Id, questId, questSlotType)); session.RefreshQuestList(_questManager, quest.Id); session.SendTargetQuest(quest.TargetMapX, quest.TargetMapY, quest.TargetMapId, quest.Id); return new SaltyCommandResult(true, "Quest added!"); } [Command("getscripts")] [Description("Get the scripts completed by the player")] public async Task GetPlayerCompletedScripts(IClientSession session) { if (session == null) { return new SaltyCommandResult(false, "Player null"); } foreach (CompletedScriptsDto completedScriptsDto in session.PlayerEntity.GetCompletedScripts()) { Context.Player.SendChatMessage($"script {completedScriptsDto.ScriptId} {completedScriptsDto.ScriptIndex}", ChatMessageColorType.Yellow); } return new SaltyCommandResult(true); } [Command("completescripts", "cs")] [Description("Forces the script completion, removing any MAIN quest running and any completed script after the specified, and sends the next one.")] public async Task ForceCompleteScripts(IClientSession session, int scriptId, int scriptIndex) { if (session == null) { return new SaltyCommandResult(false, "Player null"); } TutorialDto tutorialDto = _questManager.GetScriptTutorialByIndex(scriptId, scriptIndex); if (tutorialDto == null) { return new SaltyCommandResult(false, "Script null"); } IReadOnlyCollection scripts = _questManager.GetScriptsTutorialUntilIndex(scriptId, scriptIndex); IEnumerable playerCompletedScripts = session.PlayerEntity.GetCompletedScripts(); foreach (TutorialDto script in scripts) { session.PlayerEntity.SaveScript(script.ScriptId, script.ScriptIndex, script.Type, DateTime.UtcNow); if (script.Type == TutorialActionType.WAIT_FOR_QUEST_COMPLETION) { session.PlayerEntity.AddCompletedQuest(_questFactory.NewQuest(session.PlayerEntity.Id, script.Data, QuestSlotType.MAIN)); } } foreach (CompletedScriptsDto completedScript in playerCompletedScripts) { if (completedScript.ScriptId < scriptId || completedScript.ScriptId == scriptId && completedScript.ScriptIndex <= scriptIndex) { continue; } session.PlayerEntity.RemoveCompletedScript(completedScript.ScriptId, completedScript.ScriptIndex); TutorialDto script = _questManager.GetScriptTutorialByIndex(completedScript.ScriptId, completedScript.ScriptIndex); if (script.Type == TutorialActionType.WAIT_FOR_QUEST_COMPLETION) { session.PlayerEntity.RemoveCompletedQuest(script.Data); } } TutorialDto nextScript = _questManager.GetScriptTutorialById(scripts.Last().Id + 1); if (nextScript == null) { return new SaltyCommandResult(true, "That was the last script,"); } CharacterQuest characterQuest = session.GetQuestBySlot(5); if (characterQuest != null) // Remove a MAIN quest if there is any { session.DeleteQuestTarget(characterQuest); session.PlayerEntity.RemoveActiveQuest(characterQuest.QuestId); session.RefreshQuestList(_questManager, null); } if (nextScript.Type == TutorialActionType.WAIT_FOR_QUEST_COMPLETION && session.PlayerEntity.HasQuestWithId(nextScript.Data)) { QuestDto quest = _questManager.GetQuestById(nextScript.Data); session.PlayerEntity.AddActiveQuest(_questFactory.NewQuest(session.PlayerEntity.Id, nextScript.Data, QuestSlotType.MAIN)); session.RefreshQuestList(_questManager, quest.Id); session.SendTargetQuest(quest.TargetMapX, quest.TargetMapY, quest.TargetMapId, quest.Id); } session.SendScriptPacket(nextScript.ScriptId, nextScript.ScriptIndex); return new SaltyCommandResult(true, "Scripts completed"); } [Command("remove")] [Description("Remove the quest linked to a given ID")] public async Task RemoveQuest(int questId) { CharacterQuest quest = Context.Player.PlayerEntity.GetQuestById(questId); if (quest == null) { return new SaltyCommandResult(false, "Quest null"); } Context.Player.DeleteQuestTarget(quest); Context.Player.PlayerEntity.RemoveActiveQuest(quest.QuestId); Context.Player.RefreshQuestList(_questManager, null); return new SaltyCommandResult(true, "Quest removed!"); } [Command("remove")] [Description("Remove the quest linked to a given ID of a character")] public async Task RemoveQuest(IClientSession session, int questId) { if (session == null) { return new SaltyCommandResult(false, "Player null"); } CharacterQuest quest = session.PlayerEntity.GetQuestById(questId); if (quest == null) { return new SaltyCommandResult(false, "Quest null"); } session.DeleteQuestTarget(quest); session.PlayerEntity.RemoveActiveQuest(quest.QuestId); session.RefreshQuestList(_questManager, null); return new SaltyCommandResult(true, "Quest removed!"); } [Command("showinfo")] [Description("Show info related to a player quests")] public async Task ShowInfo(IClientSession session) { if (session == null) { return new SaltyCommandResult(false, "Player null"); } Context.Player.SendChatMessage($"== Active quests from {session.PlayerEntity.Name} ==", ChatMessageColorType.Yellow); foreach (CharacterQuest quest in session.PlayerEntity.GetCurrentQuests()) { Context.Player.SendChatMessage($"- Quest VNUM: {quest.QuestId}; Slot: {quest.SlotType}; Type: {quest.Quest.QuestType}", ChatMessageColorType.Yellow); foreach (QuestObjectiveDto objective in quest.Quest.Objectives) { CharacterQuestObjectiveDto questObjectiveDto = quest.ObjectiveAmount[objective.ObjectiveIndex]; Context.Player.SendChatMessage($"ObjectiveIndex: {objective.ObjectiveIndex}; CompletedAmount: {questObjectiveDto.CurrentAmount}", ChatMessageColorType.Yellow); } } return new SaltyCommandResult(true, "Scripts showed"); } [Command("showinfo")] [Description("Show info related to your quests")] public async Task ShowInfo() { Context.Player.SendChatMessage($"== Active quests from {Context.Player.PlayerEntity.Name} ==", ChatMessageColorType.Yellow); foreach (CharacterQuest quest in Context.Player.PlayerEntity.GetCurrentQuests()) { Context.Player.SendChatMessage($"- Quest VNUM: {quest.QuestId}; Slot: {quest.SlotType}; Type: {quest.Quest.QuestType}", ChatMessageColorType.Yellow); foreach (QuestObjectiveDto objective in quest.Quest.Objectives) { CharacterQuestObjectiveDto questObjectiveDto = quest.ObjectiveAmount[objective.ObjectiveIndex]; Context.Player.SendChatMessage($"ObjectiveIndex: {objective.ObjectiveIndex}; CompletedAmount: {questObjectiveDto.CurrentAmount}", ChatMessageColorType.Yellow); } } return new SaltyCommandResult(true); } [Command("clear")] [Description("Clear all quests")] public async Task ClearAllQuests() { foreach (CharacterQuest quest in Context.Player.PlayerEntity.GetCurrentQuests()) { Context.Player.PlayerEntity.RemoveActiveQuest(quest.QuestId); Context.Player.DeleteQuestTarget(quest); } Context.Player.RefreshQuestList(_questManager, null); return new SaltyCommandResult(true); } [Command("refresh-dq", "refreshdailyquests", "rdq")] [Description("Refresh your daily minigame points.")] public async Task RefreshDailyQuests([Description("Force refresh")] bool force = false) { Context.Player.EmitEvent(new QuestDailyRefreshEvent { Force = force }); return new SaltyCommandResult(true, "Daily quests refreshed!"); } [Command("set-soundflowers")] [Description("Gives the player X amount of unstarted soundflower quests")] public async Task GiveSoundFlowers(IClientSession session, int amount) { IReadOnlyCollection generalQuests = session.PlayerEntity.GetCurrentQuests().Where(s => s.SlotType == QuestSlotType.MAIN).ToList(); if (generalQuests.Count + amount > 5) { return new SaltyCommandResult(false, "You can't have more than 5 GENERAL quests active!"); } int currentSoundFlowers = session.PlayerEntity.GetPendingSoundFlowerQuests(); for (int i = 0; i < currentSoundFlowers; i++) { session.PlayerEntity.DecreasePendingSoundFlowerQuests(); } for (int i = 0; i < amount; i++) { session.PlayerEntity.IncreasePendingSoundFlowerQuests(); } session.RefreshQuestList(_questManager, null); return new SaltyCommandResult(true, "Sound flower quests added!"); } } }