public bool CanAcceptQuest(NWPlayer oPC, Quest quest, bool sendMessage) { PCQuestStatus status = _data.SingleOrDefault <PCQuestStatus>(x => x.PlayerID == oPC.GlobalID && x.QuestID == quest.ID); if (status != null) { if (status.CompletionDate != null) { if (sendMessage) { oPC.SendMessage("You have already completed this quest."); } return(false); } else { if (sendMessage) { oPC.SendMessage("You have already accepted this quest."); } return(false); } } if (!DoesPlayerMeetPrerequisites(oPC, quest.ID)) { if (sendMessage) { oPC.SendMessage("You do not meet the prerequisites necessary to accept this quest."); } return(false); } var questState = _data.Where <QuestState>(x => x.QuestID == quest.ID).First(); if (!DoesPlayerHaveRequiredKeyItems(oPC, questState.ID)) { if (sendMessage) { oPC.SendMessage("You do not have the required key items to accept this quest."); } return(false); } PCRegionalFame fame = _data.SingleOrDefault <PCRegionalFame>(x => x.PlayerID == oPC.GlobalID && x.FameRegionID == quest.FameRegionID); if (fame != null) { if (fame.Amount < quest.RequiredFameAmount) { if (sendMessage) { oPC.SendMessage("You do not have enough fame to accept this quest."); } return(false); } } return(true); }
public void AcceptQuest(NWPlayer player, NWObject questOwner, int questID) { if (!player.IsPlayer) { return; } Quest quest = _data.Single <Quest>(x => x.ID == questID); if (!CanAcceptQuest(player, quest, true)) { return; } var questState = _data.Single <QuestState>(x => x.QuestID == questID && x.Sequence == 1); var status = new PCQuestStatus { CurrentQuestStateID = questState.ID }; // Give temporary key item at start of quest. if (quest.StartKeyItemID != null) { _keyItem.GivePlayerKeyItem(player, (int)quest.StartKeyItemID); } if (!string.IsNullOrWhiteSpace(quest.MapNoteTag)) { _mapPin.AddWaypointMapPin(player, quest.MapNoteTag, quest.Name, "QST_MAP_NOTE_" + questID); } status.QuestID = quest.ID; status.PlayerID = player.GlobalID; _data.SubmitDataChange(status, DatabaseActionType.Insert); CreateExtendedQuestDataEntries(status); _.AddJournalQuestEntry(quest.JournalTag, 1, player.Object, FALSE); player.SendMessage("Quest '" + quest.Name + "' accepted. Refer to your journal for more information on this quest."); if (!string.IsNullOrWhiteSpace(quest.OnAcceptRule) && questOwner != null) { App.ResolveByInterface <IQuestRule>("QuestRule." + quest.OnAcceptRule, rule => { string[] args = null; if (!string.IsNullOrWhiteSpace(quest.OnAcceptArgs)) { args = quest.OnAcceptArgs.Split(','); } rule.Run(player, questOwner, questID, args); }); } }
public void AdvanceQuestState(NWPlayer player, NWObject questOwner, int questID) { if (!player.IsPlayer) { return; } PCQuestStatus questStatus = _data.SingleOrDefault <PCQuestStatus>(x => x.PlayerID == player.GlobalID && x.QuestID == questID); if (questStatus == null) { player.SendMessage("You have not accepted this quest yet."); return; } if (questStatus.CompletionDate != null) { return; } Quest quest = _data.Get <Quest>(questStatus.QuestID); QuestState currentState = _data.Get <QuestState>(questStatus.CurrentQuestStateID); QuestState nextState = _data.SingleOrDefault <QuestState>(x => x.QuestID == quest.ID && x.Sequence == currentState.Sequence + 1); // Either complete the quest or move to the new state. if (nextState == null) // We assume this is the last state in the quest, so it must be time to complete it. { RequestRewardSelectionFromPC(player, questOwner, questID); } else { _.AddJournalQuestEntry(quest.JournalTag, nextState.JournalStateID, player, FALSE); questStatus.CurrentQuestStateID = nextState.ID; player.SendMessage("Objective for quest '" + quest.Name + "' complete! Check your journal for information on the next objective."); CreateExtendedQuestDataEntries(questStatus); _data.SubmitDataChange(questStatus, DatabaseActionType.Update); if (!string.IsNullOrWhiteSpace(quest.OnAdvanceRule) && questOwner != null) { App.ResolveByInterface <IQuestRule>("QuestRule." + quest.OnAdvanceRule, rule => { string[] args = null; if (!string.IsNullOrWhiteSpace(quest.OnAdvanceArgs)) { args = quest.OnAdvanceArgs.Split(','); } rule.Run(player, questOwner, questID, args); }); } } }
private static void RequestRewardSelectionFromPC(NWPlayer oPC, NWObject questOwner, int questID) { if (!oPC.IsPlayer) { return; } Quest quest = DataService.Single <Quest>(x => x.ID == questID); if (quest.AllowRewardSelection) { oPC.SetLocalInt("QST_REWARD_SELECTION_QUEST_ID", questID); DialogService.StartConversation(oPC, oPC, "QuestRewardSelection"); } else { CompleteQuest(oPC, questOwner, questID, null); } }
public static void CompleteQuest(NWPlayer player, NWObject questOwner, int questID, ItemVO selectedItem) { if (!player.IsPlayer) { return; } Quest quest = DataService.Single <Quest>(x => x.ID == questID); PCQuestStatus pcState = DataService.Single <PCQuestStatus>(x => x.PlayerID == player.GlobalID && x.QuestID == questID); QuestState finalState = DataService.GetAll <QuestState>().Where(x => x.QuestID == questID).OrderBy(o => o.Sequence).Last(); if (finalState == null) { player.SendMessage("Could not find final state of quest. Please notify an admin this quest is bugged. (QuestID: " + questID + ")"); return; } pcState.CurrentQuestStateID = finalState.ID; pcState.CompletionDate = DateTime.UtcNow; if (selectedItem == null) { var rewardItems = DataService.Where <QuestRewardItem>(x => x.QuestID == questID); foreach (QuestRewardItem reward in rewardItems) { _.CreateItemOnObject(reward.Resref, player.Object, reward.Quantity); } } else { _.CreateItemOnObject(selectedItem.Resref, player.Object, selectedItem.Quantity); } if (quest.RewardGold > 0) { _.GiveGoldToCreature(player.Object, quest.RewardGold); } if (quest.RewardKeyItemID != null) { KeyItemService.GivePlayerKeyItem(player, (int)quest.RewardKeyItemID); } if (quest.RemoveStartKeyItemAfterCompletion && quest.StartKeyItemID != null) { KeyItemService.RemovePlayerKeyItem(player, (int)quest.StartKeyItemID); } if (!string.IsNullOrWhiteSpace(quest.MapNoteTag)) { MapPinService.DeleteMapPin(player, "QST_MAP_NOTE_" + questID); } if (quest.RewardFame > 0) { PCRegionalFame fame = DataService.SingleOrDefault <PCRegionalFame>(x => x.PlayerID == player.GlobalID && x.FameRegionID == quest.FameRegionID); DatabaseActionType action = DatabaseActionType.Update; if (fame == null) { fame = new PCRegionalFame { PlayerID = player.GlobalID, FameRegionID = quest.FameRegionID, Amount = 0 }; action = DatabaseActionType.Insert; } fame.Amount += quest.RewardFame; DataService.SubmitDataChange(fame, action); } player.SendMessage("Quest '" + quest.Name + "' complete!"); DataService.SubmitDataChange(pcState, DatabaseActionType.Update); _.RemoveJournalQuestEntry(quest.JournalTag, player, FALSE); if (!string.IsNullOrWhiteSpace(quest.OnCompleteRule) && questOwner != null) { var rule = GetQuestRule(quest.OnCompleteRule); string[] args = null; if (!string.IsNullOrWhiteSpace(quest.OnCompleteArgs)) { args = quest.OnCompleteArgs.Split(','); } rule.Run(player, questOwner, questID, args); } MessageHub.Instance.Publish(new QuestCompletedMessage(player, questID)); }
/// <summary> /// Progresses a player to the next state of a quest. /// If they're on the last state of the quest, it will be completed for them. /// </summary> /// <param name="player">The player to advance.</param> /// <param name="questOwner">The quest giver object.</param> /// <param name="questID">The ID number of the quest.</param> public static void AdvanceQuestState(NWPlayer player, NWObject questOwner, int questID) { if (!player.IsPlayer) { return; } // Retrieve the player's current quest state. PCQuestStatus questStatus = DataService.SingleOrDefault <PCQuestStatus>(x => x.PlayerID == player.GlobalID && x.QuestID == questID); // Can't find a state? Notify the player they haven't accepted the quest. if (questStatus == null) { player.SendMessage("You have not accepted this quest yet."); return; } // If this quest has already been completed, exit early. // This is used in case a module builder incorrectly configures a quest. // We don't want to risk giving duplicate rewards. if (questStatus.CompletionDate != null) { return; } // Retrieve the quest, the current state, and the next state of the quest from the cache. Quest quest = DataService.Get <Quest>(questStatus.QuestID); QuestState currentState = DataService.Get <QuestState>(questStatus.CurrentQuestStateID); QuestState nextState = DataService.SingleOrDefault <QuestState>(x => x.QuestID == quest.ID && x.Sequence == currentState.Sequence + 1); // If there's no state after this one, the assumption is that it's time to complete the quest. if (nextState == null) { // We'll request a reward selection from the player if the quest is configured that way. // Otherwise, this method will simply complete the quest outright. RequestRewardSelectionFromPC(player, questOwner, questID); } // We found another state to this quest. Let's advance their progress now. else { // Update the player's journal _.AddJournalQuestEntry(quest.JournalTag, nextState.JournalStateID, player, FALSE); // Progress player's quest status to the next state. questStatus.CurrentQuestStateID = nextState.ID; // Notify the player they've progressed. player.SendMessage("Objective for quest '" + quest.Name + "' complete! Check your journal for information on the next objective."); // Create any extended data entries for the next state of the quest. CreateExtendedQuestDataEntries(questStatus); // Submit all of these changes to the cache/DB. DataService.SubmitDataChange(questStatus, DatabaseActionType.Update); // If this quest has a custom rule configured, run that now. if (!string.IsNullOrWhiteSpace(quest.OnAdvanceRule) && questOwner != null) { var rule = GetQuestRule(quest.OnAdvanceRule); string[] args = null; if (!string.IsNullOrWhiteSpace(quest.OnAdvanceArgs)) { args = quest.OnAdvanceArgs.Split(','); } rule.Run(player, questOwner, questID, args); } // Notify subscribers we've advanced the player's quest status. MessageHub.Instance.Publish(new OnQuestAdvanced(player, questID, currentState.Sequence + 1)); } }
/// <summary> /// Accepts a quest for a player. This updates their journal entry and marks all necessary flags /// on the player. /// </summary> /// <param name="player">The player who is accepting the quest.</param> /// <param name="questOwner">The quest giver object.</param> /// <param name="questID">The ID number of the quest to accept.</param> public static void AcceptQuest(NWPlayer player, NWObject questOwner, int questID) { if (!player.IsPlayer) { return; } // Retrieve quest from the cache. Quest quest = DataService.Single <Quest>(x => x.ID == questID); // Check whether player can accept the quest. Send a message if they can't. if (!CanAcceptQuest(player, quest, true)) { return; } // By this point, it's assumed the player will accept the quest. // However, if this quest is repeatable we must first update the existing entry. var status = DataService.SingleOrDefault <PCQuestStatus>(x => x.QuestID == questID && x.PlayerID == player.GlobalID); bool foundExisting = status != null; // Didn't find an existing state so we'll create a new object. if (status == null) { status = new PCQuestStatus(); } else { status.CompletionDate = null; } // Retrieve the first quest state for this quest. var questState = DataService.Single <QuestState>(x => x.QuestID == questID && x.Sequence == 1); status.CurrentQuestStateID = questState.ID; // Give temporary key item at start of quest. if (quest.StartKeyItemID != null) { KeyItemService.GivePlayerKeyItem(player, (int)quest.StartKeyItemID); } // Add a map pin if specified by the quest. if (!string.IsNullOrWhiteSpace(quest.MapNoteTag)) { MapPinService.AddWaypointMapPin(player, quest.MapNoteTag, quest.Name, "QST_MAP_NOTE_" + questID); } status.QuestID = quest.ID; status.PlayerID = player.GlobalID; // Insert or update player's quest status. DataService.SubmitDataChange(status, foundExisting ? DatabaseActionType.Update : DatabaseActionType.Insert); // Create extended quest entries, if necessary. CreateExtendedQuestDataEntries(status); // Add the journal entry to the player. _.AddJournalQuestEntry(quest.JournalTag, 1, player.Object, FALSE); // Notify them that they've accepted a quest. player.SendMessage("Quest '" + quest.Name + "' accepted. Refer to your journal for more information on this quest."); // If this quest runs any custom rules, do those now. if (!string.IsNullOrWhiteSpace(quest.OnAcceptRule) && questOwner != null) { var rule = GetQuestRule(quest.OnAcceptRule); string[] args = null; if (!string.IsNullOrWhiteSpace(quest.OnAcceptArgs)) { args = quest.OnAcceptArgs.Split(','); } rule.Run(player, questOwner, questID, args); } // Notify to subscribers that a quest has just been accepted. MessageHub.Instance.Publish(new OnQuestAccepted(player, questID)); }
/// <summary> /// Returns true if player can accept a quest with the given ID. /// Returns false if player cannot accept the quest. /// </summary> /// <param name="oPC">The player to check</param> /// <param name="quest">The quest to check.</param> /// <param name="sendMessage">If true, a message will be sent to player about why they can't accept the quest.</param> /// <returns>true if player can accept quest. false otherwise.</returns> public static bool CanAcceptQuest(NWPlayer oPC, Quest quest, bool sendMessage) { // Retrieve the player's current quest status for this quest. // If they haven't accepted it yet, this will be null. PCQuestStatus status = DataService.SingleOrDefault <PCQuestStatus>(x => x.PlayerID == oPC.GlobalID && x.QuestID == quest.ID); // If the status is null, it's assumed that the player hasn't accepted it yet. if (status != null) { // If the quest isn't repeatable, prevent the player from accepting it after it's already been completed. if (status.CompletionDate != null) { // If it's repeatable, then we don't care if they've already completed it. if (!quest.IsRepeatable) { if (sendMessage) { oPC.SendMessage("You have already completed this quest."); } return(false); } } // If the player already accepted the quest, prevent them from accepting it again. else { if (sendMessage) { oPC.SendMessage("You have already accepted this quest."); } return(false); } } // Check whether the player meets all necessary prerequisites. if (!DoesPlayerMeetPrerequisites(oPC, quest.ID)) { if (sendMessage) { oPC.SendMessage("You do not meet the prerequisites necessary to accept this quest."); } return(false); } // Retrieve the first state of the quest. var questState = DataService.Where <QuestState>(x => x.QuestID == quest.ID).First(); // If this quest requires key items, ensure player has acquired them. if (!DoesPlayerHaveRequiredKeyItems(oPC, questState.ID)) { if (sendMessage) { oPC.SendMessage("You do not have the required key items to accept this quest."); } return(false); } // Retrieve the player's fame information. Treat a missing record as having 0 fame for this region. PCRegionalFame fame = DataService.SingleOrDefault <PCRegionalFame>(x => x.PlayerID == oPC.GlobalID && x.FameRegionID == quest.FameRegionID); int fameAmount = fame == null ? 0 : fame.Amount; // Ensure player has necessary fame for accepting this quest. if (fameAmount < quest.RequiredFameAmount) { if (sendMessage) { oPC.SendMessage("You do not have enough fame to accept this quest."); } return(false); } return(true); }