/// <summary> /// Track or hide an active <see cref="Quest.Quest"/>. /// </summary> public void QuestTrack(ushort questId, bool tracked) { if (GlobalQuestManager.GetQuestInfo(questId) == null) { throw new ArgumentException($"Invalid quest {questId}!"); } Quest.Quest quest = GetQuest(questId, GetQuestFlags.Active); if (quest == null) { throw new QuestException($"Player {player.CharacterId} tried to track quest {questId} which they don't have!"); } if (quest.State != QuestState.Accepted && quest.State != QuestState.Achieved) { throw new QuestException($"Player {player.CharacterId} tried to track quest {questId} with invalid state!"); } if (tracked) { quest.Flags |= QuestFlags.Tracked; } else { quest.Flags &= ~QuestFlags.Tracked; } log.Trace($"Updated tracked state of quest {questId} to {tracked}."); }
/// <summary> /// Share supplied <see cref="Quest.Quest"/> with another <see cref="Player"/>. /// </summary> public void QuestShare(ushort questId) { QuestInfo info = GlobalQuestManager.GetQuestInfo(questId); if (info == null) { throw new ArgumentException($"Invalid quest {questId}!"); } Quest.Quest quest = GetQuest(questId); if (quest == null) { throw new QuestException($"Player {player.CharacterId} tried to share quest {questId} which they don't have!"); } if (!quest.CanShare()) { throw new QuestException($"Player {player.CharacterId} tried to share quest {questId} which can't be shared!"); } Player recipient = player.GetVisible <Player>(player.TargetGuid); if (recipient == null) { throw new QuestException($"Player {player.CharacterId} tried to share quest {questId} to an invalid player!"); } // TODO log.Trace($"Shared quest {questId} with player {recipient.Name}."); }
/// <summary> /// Create a new <see cref="QuestManager"/> from existing <see cref="Character"/> database model. /// </summary> public QuestManager(Player owner, Character model) { player = owner; foreach (CharacterQuest questModel in model.CharacterQuest) { QuestInfo info = GlobalQuestManager.GetQuestInfo(questModel.QuestId); if (info == null) { log.Error($"Player {player.CharacterId} has an invalid quest {questModel.QuestId}!"); continue; } var quest = new Quest.Quest(player, info, questModel); switch (quest.State) { case QuestState.Completed: completedQuests.Add(quest.Id, quest); break; case QuestState.Botched: case QuestState.Ignored: inactiveQuests.Add(quest.Id, quest); break; case QuestState.Accepted: case QuestState.Achieved: activeQuests.Add(quest.Id, quest); break; } } }
/// <summary> /// Complete single <see cref="QuestObjective"/> for supplied active <see cref="Quest.Quest"/>. /// </summary> public void QuestAchieveObjective(ushort questId, byte index) { if (GlobalQuestManager.GetQuestInfo(questId) == null) { throw new ArgumentException($"Invalid quest {questId}!"); } Quest.Quest quest = GetQuest(questId); if (quest == null || quest.PendingDelete) { throw new QuestException(); } if (quest.State != QuestState.Accepted) { throw new QuestException(); } QuestObjective objective = quest.SingleOrDefault(o => o.Index == index); if (objective == null) { throw new QuestException(); } quest.ObjectiveUpdate((QuestObjectiveType)objective.Entry.Type, objective.Entry.Data, objective.Entry.Count); }
private void QuestAdd(QuestInfo info, Quest.Quest quest, Item item) { if (quest?.State == QuestState.Accepted || quest?.State == QuestState.Achieved) { throw new QuestException($"Player {player.CharacterId} tried to start quest {info.Entry.Id} which is already in progress!"); } // if quest has already been completed make sure it's repeatable and the reset period has elapsed if (quest?.State == QuestState.Completed) { if (info.Entry.QuestRepeatPeriodEnum == 0u) { throw new QuestException($"Player {player.CharacterId} tried to start quest {info.Entry.Id} which they have already completed!"); } DateTime?resetTime = GetQuest((ushort)info.Entry.Id, GetQuestFlags.Completed).Reset; if (DateTime.UtcNow < resetTime) { throw new QuestException($"Player {player.CharacterId} tried to start quest {info.Entry.Id} which hasn't reset yet!"); } } if (item != null) { if (info.Entry.Id != item.Entry.Quest2IdActivation) { throw new QuestException($"Player {player.CharacterId} tried to start quest {info.Entry.Id} from invalid item {item.Entry.Id}!"); } // TODO: consume charge } else { // make sure the player is in range of a quest giver or they are eligible for a communicator message that starts the quest if (!GlobalQuestManager.GetQuestGivers((ushort)info.Entry.Id) .Any(c => player.GetVisibleCreature <WorldEntity>(c).Any())) { if (!info.IsCommunicatorReceived()) { throw new QuestException($"Player {player.CharacterId} tried to start quest {info.Entry.Id} without quest giver!"); } if (!GlobalQuestManager.GetQuestCommunicatorMessages((ushort)info.Entry.Id) .Any(m => m.Meets(player))) { throw new QuestException($"Player {player.CharacterId} tried to start quest {info.Entry.Id} without communicator message!"); } } } // server doesn't send an error message for prerequisites since the client does the exact same checks // it's assumed that a player could never get here without cheating in some way if (!MeetsPrerequisites(info)) { throw new QuestException($"Player {player.CharacterId} tried to start quest {info.Entry.Id} without meeting the prerequisites!"); } QuestAdd(info); }
/// <summary> /// Ignore or acknowledge an inactive <see cref="Quest.Quest"/>. /// </summary> public void QuestIgnore(ushort questId, bool ignored) { if (GlobalQuestManager.GetQuestInfo(questId) == null) { throw new ArgumentException($"Invalid quest {questId}!"); } // TODO: }
/// <summary> /// Add a <see cref="Quest.Quest"/> from supplied id, optionally supplying <see cref="Item"/> which was used to start the quest. /// </summary> public void QuestAdd(ushort questId, Item item) { QuestInfo info = GlobalQuestManager.GetQuestInfo(questId); if (info == null) { throw new ArgumentException($"Invalid quest {questId}!"); } if (DisableManager.Instance.IsDisabled(DisableType.Quest, questId)) { player.SendSystemMessage($"Unable to add quest {questId} because it is disabled."); return; } Quest.Quest quest = GetQuest(questId); QuestAdd(info, quest, item); }
public async Task QuestAddCommandHandler(CommandContext context, string command, string[] parameters) { if (parameters.Length != 1 || !ushort.TryParse(parameters[0], out ushort questId)) { await SendHelpAsync(context); return; } QuestInfo info = GlobalQuestManager.GetQuestInfo(questId); if (info == null) { await context.SendMessageAsync($"Quest id {questId} is invalid!"); return; } context.Session.Player.QuestManager.QuestAdd(info); }
/// <summary> /// Abandon an active <see cref="Quest.Quest"/>. /// </summary> public void QuestAbandon(ushort questId) { if (GlobalQuestManager.GetQuestInfo(questId) == null) { throw new ArgumentException($"Invalid quest {questId}!"); } Quest.Quest quest = GetQuest(questId, GetQuestFlags.Active | GetQuestFlags.Inactive); if (quest == null || quest.PendingDelete) { throw new QuestException($"Player {player.CharacterId} tried to abandon quest {questId} which they don't have!"); } if (!quest.CanAbandon()) { throw new QuestException($"Player {player.CharacterId} tried to abandon quest {questId} which can't be abandoned!"); } if (!quest.PendingCreate) { quest.EnqueueDelete(true); } else { switch (quest.State) { case QuestState.Accepted: case QuestState.Achieved: activeQuests.Remove(questId); break; case QuestState.Botched: inactiveQuests.Remove(quest.Id); break; } } quest.State = QuestState.Abandoned; log.Trace($"Abandoned quest {questId}."); }
/// <summary> /// Retry an inactive <see cref="Quest.Quest"/> that was previously failed. /// </summary> public void QuestRetry(ushort questId) { QuestInfo info = GlobalQuestManager.GetQuestInfo(questId); if (info == null) { throw new ArgumentException($"Invalid quest {questId}!"); } Quest.Quest quest = GetQuest(questId, GetQuestFlags.Inactive); if (quest == null) { throw new QuestException($"Player {player.CharacterId} tried to restart quest {questId} which they don't have!"); } if (quest.State != QuestState.Botched) { throw new QuestException($"Player {player.CharacterId} tried to restart quest {questId} which hasn't been failed!"); } QuestAdd(info, quest, null); }
/// <summary> /// Complete all <see cref="QuestObjective"/>'s for supplied active <see cref="Quest.Quest"/>. /// </summary> public void QuestAchieve(ushort questId) { if (GlobalQuestManager.GetQuestInfo(questId) == null) { throw new ArgumentException($"Invalid quest {questId}!"); } Quest.Quest quest = GetQuest(questId); if (quest == null || quest.PendingDelete) { throw new QuestException($"Player {player.CharacterId} tried to achieve quest {questId} which they don't have!"); } if (quest.State != QuestState.Accepted) { throw new QuestException($"Player {player.CharacterId} tried to achieve quest {questId} with invalid state!"); } foreach (QuestObjectiveEntry entry in quest.Info.Objectives) { quest.ObjectiveUpdate((QuestObjectiveType)entry.Type, entry.Data, entry.Count); } }
private static void Main() { Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)); Console.Title = Title; log.Info("Initialising..."); ConfigurationManager <WorldServerConfiguration> .Initialise("WorldServer.json"); DatabaseManager.Initialise(ConfigurationManager <WorldServerConfiguration> .Config.Database); DisableManager.Instance.Initialise(); GameTableManager.Initialise(); MapManager.Initialise(); SearchManager.Initialise(); EntityManager.Initialise(); EntityCommandManager.Initialise(); GlobalMovementManager.Initialise(); AssetManager.Initialise(); PrerequisiteManager.Initialise(); GlobalSpellManager.Initialise(); GlobalQuestManager.Initialise(); ServerManager.Initialise(); ResidenceManager.Initialise(); GlobalStorefrontManager.Initialise(); // make sure the assigned realm id in the configuration file exists in the database RealmId = ConfigurationManager <WorldServerConfiguration> .Config.RealmId; if (ServerManager.Servers.All(s => s.Model.Id != RealmId)) { throw new ConfigurationException($"Realm id {RealmId} in configuration file doesn't exist in the database!"); } MessageManager.Initialise(); SocialManager.Initialise(); CommandManager.Initialise(); NetworkManager <WorldSession> .Initialise(ConfigurationManager <WorldServerConfiguration> .Config.Network); WorldManager.Initialise(lastTick => { NetworkManager <WorldSession> .Update(lastTick); MapManager.Update(lastTick); ResidenceManager.Update(lastTick); BuybackManager.Update(lastTick); GlobalQuestManager.Update(lastTick); }); using (WorldServerEmbeddedWebServer.Initialise()) { log.Info("Ready!"); while (true) { Console.Write(">> "); string line = Console.ReadLine(); if (!CommandManager.HandleCommand(new ConsoleCommandContext(), line, false)) { Console.WriteLine("Invalid command"); } } } }
/// <summary> /// Complete an achieved <see cref="Quest.Quest"/> supplying an optional reward and whether the quest was completed from the communicator. /// </summary> public void QuestComplete(ushort questId, ushort reward, bool communicator) { if (GlobalQuestManager.GetQuestInfo(questId) == null) { throw new ArgumentException($"Invalid quest {questId}!"); } if (DisableManager.Instance.IsDisabled(DisableType.Quest, questId)) { player.SendSystemMessage($"Unable to complete quest {questId} because it is disabled."); return; } Quest.Quest quest = GetQuest(questId, GetQuestFlags.Active); if (quest == null) { throw new QuestException($"Player {player.CharacterId} tried to complete quest {questId} which they don't have!"); } if (quest.State != QuestState.Achieved) { throw new QuestException($"Player {player.CharacterId} tried to complete quest {questId} which wasn't complete!"); } if (communicator) { if (!quest.Info.IsCommunicatorReceived()) { throw new QuestException($"Player {player.CharacterId} tried to complete quest {questId} without communicator message!"); } } else { if (!GlobalQuestManager.GetQuestReceivers(questId).Any(c => player.GetVisibleCreature <WorldEntity>(c).Any())) { throw new QuestException($"Player {player.CharacterId} tried to complete quest {questId} without any quest receiver!"); } } // reclaim any quest specific items for (int i = 0; i < quest.Info.Entry.PushedItemIds.Length; i++) { uint itemId = quest.Info.Entry.PushedItemIds[i]; if (itemId != 0u) { player.Inventory.ItemDelete(itemId, quest.Info.Entry.PushedItemCounts[i]); } } RewardQuest(quest.Info, reward); quest.State = QuestState.Completed; // mark repeatable quests for reset switch ((QuestRepeatPeriod)quest.Info.Entry.QuestRepeatPeriodEnum) { case QuestRepeatPeriod.Daily: quest.Reset = GlobalQuestManager.NextDailyReset; break; case QuestRepeatPeriod.Weekly: quest.Reset = GlobalQuestManager.NextWeeklyReset; break; } activeQuests.Remove(questId); completedQuests.Add(questId, quest); }