public static void HandleSkillGain(PlayerMobile pm, SkillName skill)
        {
            MLQuestContext context = GetContext(pm);

            if (context == null)
            {
                return;
            }

            List <MLQuestInstance> instances = context.QuestInstances;

            for (int i = instances.Count - 1; i >= 0; --i)
            {
                MLQuestInstance instance = instances[i];

                if (instance.ClaimReward)
                {
                    continue;
                }

                foreach (BaseObjectiveInstance objective in instance.Objectives)
                {
                    if (!objective.Expired && objective is GainSkillObjectiveInstance && ((GainSkillObjectiveInstance)objective).Handles(skill))
                    {
                        objective.CheckComplete();
                        break;
                    }
                }
            }
        }
        private static void OnMarkQuestItem(PlayerMobile pm, Item item, Type type)
        {
            MLQuestContext context = GetContext(pm);

            if (context == null)
            {
                return;
            }

            List <MLQuestInstance> instances = context.QuestInstances;

            // We don't foreach because CheckComplete() can potentially modify the MLQuests list
            for (int i = instances.Count - 1; i >= 0; --i)
            {
                MLQuestInstance instance = instances[i];

                if (instance.ClaimReward)
                {
                    continue;
                }

                foreach (BaseObjectiveInstance objective in instance.Objectives)
                {
                    if (!objective.Expired && objective.AllowsQuestItem(item, type))
                    {
                        objective.CheckComplete(); // yes, this can happen multiple times (for multiple quests)
                        break;
                    }
                }
            }
        }
        public static void HandleDeath(PlayerMobile pm)
        {
            MLQuestContext context = GetContext(pm);

            if (context != null)
            {
                context.HandleDeath();
            }
        }
        public static void HandleDeletion(PlayerMobile pm)
        {
            MLQuestContext context = GetContext(pm);

            if (context != null)
            {
                context.HandleDeletion();
                m_Contexts.Remove(pm);
            }
        }
        public static MLQuestContext GetOrCreateContext(PlayerMobile pm)
        {
            MLQuestContext context;

            if (!m_Contexts.TryGetValue(pm, out context))
            {
                m_Contexts[pm] = context = new MLQuestContext(pm);
            }

            return(context);
        }
        public static MLQuestInstance HandleDelivery(PlayerMobile pm, IQuestGiver quester, Type questerType)
        {
            MLQuestContext context = GetContext(pm);

            if (context == null)
            {
                return(null);
            }

            List <MLQuestInstance> instances       = context.QuestInstances;
            MLQuestInstance        deliverInstance = null;

            for (int i = instances.Count - 1; i >= 0; --i)
            {
                MLQuestInstance instance = instances[i];

                // Do NOT skip quests on ClaimReward, because the quester still needs the quest ref!
                //if ( instance.ClaimReward )
                //	continue;

                foreach (BaseObjectiveInstance objective in instance.Objectives)
                {
                    // Note: On OSI, expired deliveries can still be completed. Bug?
                    if (!objective.Expired && objective is DeliverObjectiveInstance)
                    {
                        DeliverObjectiveInstance deliver = (DeliverObjectiveInstance)objective;

                        if (deliver.IsDestination(quester, questerType))
                        {
                            if (!deliver.HasCompleted) // objective completes only once
                            {
                                deliver.HasCompleted = true;
                                deliver.CheckComplete();

                                // The quest is continued with this NPC (important for chains)
                                instance.Quester = quester;
                            }

                            if (deliverInstance == null)
                            {
                                deliverInstance = instance;
                            }

                            break; // don't return, we may have to complete more deliveries
                        }
                    }
                }
            }

            return(deliverInstance);
        }
        private static bool FindQuest(IQuestGiver quester, PlayerMobile pm, MLQuestContext context, out MLQuest quest, out MLQuestInstance entry)
        {
            quest = null;
            entry = null;

            List <MLQuest> quests      = quester.MLQuests;
            Type           questerType = quester.GetType();

            // 1. Check quests in progress with this NPC (overriding deliveries is intended)
            if (context != null)
            {
                foreach (MLQuest questEntry in quests)
                {
                    MLQuestInstance instance = context.FindInstance(questEntry);

                    if (instance != null && (instance.Quester == quester || (!questEntry.IsEscort && instance.QuesterType == questerType)))
                    {
                        entry = instance;
                        quest = questEntry;
                        return(true);
                    }
                }
            }

            // 2. Check deliveries (overriding chain offers is intended)
            if ((entry = HandleDelivery(pm, quester, questerType)) != null)
            {
                quest = entry.Quest;
                return(true);
            }

            // 3. Check chain quest offers
            if (context != null)
            {
                foreach (MLQuest questEntry in quests)
                {
                    if (questEntry.IsChainTriggered && context.ChainOffers.Contains(questEntry))
                    {
                        quest = questEntry;
                        return(true);
                    }
                }
            }

            // 4. Random quest
            quest = RandomStarterQuest(quester, pm, context);

            return(quest != null);
        }
        public static void HandleKill(PlayerMobile pm, Mobile mob)
        {
            MLQuestContext context = GetContext(pm);

            if (context == null)
            {
                return;
            }

            List <MLQuestInstance> instances = context.QuestInstances;

            Type type = null;

            for (int i = instances.Count - 1; i >= 0; --i)
            {
                MLQuestInstance instance = instances[i];

                if (instance.ClaimReward)
                {
                    continue;
                }

                /* A kill only counts for a single objective within a quest,
                 * but it can count for multiple quests. This is something not
                 * currently observable on OSI, so it is assumed behavior.
                 */
                foreach (BaseObjectiveInstance objective in instance.Objectives)
                {
                    if (!objective.Expired && objective is KillObjectiveInstance)
                    {
                        KillObjectiveInstance kill = (KillObjectiveInstance)objective;

                        if (type == null)
                        {
                            type = mob.GetType();
                        }

                        if (kill.AddKill(mob, type))
                        {
                            kill.CheckComplete();
                            break;
                        }
                    }
                }
            }
        }
        public static bool CanMarkQuestItem(PlayerMobile pm, Item item, Type type)
        {
            MLQuestContext context = GetContext(pm);

            if (context != null)
            {
                foreach (MLQuestInstance quest in context.QuestInstances)
                {
                    if (!quest.ClaimReward && quest.AllowsQuestItem(item, type))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        public static void OnDoubleClick(IQuestGiver quester, PlayerMobile pm)
        {
            if (quester.Deleted || !pm.Alive)
            {
                return;
            }

            MLQuestContext context = GetContext(pm);

            MLQuest         quest;
            MLQuestInstance entry;

            if (!FindQuest(quester, pm, context, out quest, out entry))
            {
                Tell(quester, pm, 1080107); // I'm sorry, I have nothing for you at this time.
                return;
            }

            if (entry != null)
            {
                TurnToFace(quester, pm);

                if (entry.Failed)
                {
                    return; // Note: OSI sends no gump at all for failed quests, they have to be cancelled in the quest overview
                }
                else if (entry.ClaimReward)
                {
                    entry.SendRewardOffer();
                }
                else if (entry.IsCompleted())
                {
                    entry.SendReportBackGump();
                }
                else
                {
                    entry.SendProgressGump();
                }
            }
            else if (quest.CanOffer(quester, pm, context, true))
            {
                TurnToFace(quester, pm);

                quest.SendOffer(quester, pm);
            }
        }
Example #11
0
        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            int version  = reader.ReadInt();
            int contexts = reader.ReadInt();

            for (int i = 0; i < contexts; ++i)
            {
                MLQuestContext context = new MLQuestContext(reader, version);

                if (context.Owner != null)
                {
                    MLQuestSystem.Contexts[context.Owner] = context;
                }
            }

            int quests = reader.ReadInt();

            for (int i = 0; i < quests; ++i)
            {
                MLQuest.Deserialize(reader, version);
            }
        }
Example #12
0
        public virtual bool CanOffer(IQuestGiver quester, PlayerMobile pm, MLQuestContext context, bool message)
        {
            if (!m_Activated || quester.Deleted)
            {
                return(false);
            }

            if (context != null)
            {
                if (context.IsFull)
                {
                    if (message)
                    {
                        MLQuestSystem.Tell(quester, pm, 1080107); // I'm sorry, I have nothing for you at this time.
                    }
                    return(false);
                }

                MLQuest checkQuest = this;

                while (checkQuest != null)
                {
                    DateTime nextAvailable;

                    if (context.HasDoneQuest(checkQuest, out nextAvailable))
                    {
                        if (checkQuest.OneTimeOnly)
                        {
                            if (message)
                            {
                                MLQuestSystem.Tell(quester, pm, 1075454); // I cannot offer you the quest again.
                            }
                            return(false);
                        }
                        else if (nextAvailable > DateTime.UtcNow)
                        {
                            if (message)
                            {
                                MLQuestSystem.Tell(quester, pm, 1075575); // I'm sorry, but I don't have anything else for you right now. Could you check back with me in a few minutes?
                            }
                            return(false);
                        }
                    }

                    if (checkQuest.NextQuest == null)
                    {
                        break;
                    }

                    checkQuest = MLQuestSystem.FindQuest(checkQuest.NextQuest);
                }
            }

            foreach (BaseObjective obj in m_Objectives)
            {
                if (!obj.CanOffer(quester, pm, message))
                {
                    return(false);
                }
            }

            return(true);
        }
        public static MLQuest RandomStarterQuest(IQuestGiver quester, PlayerMobile pm, MLQuestContext context)
        {
            List <MLQuest> quests = quester.MLQuests;

            if (quests.Count == 0)
            {
                return(null);
            }

            m_EligiblePool.Clear();
            MLQuest fallback = null;

            foreach (MLQuest quest in quests)
            {
                if (quest.IsChainTriggered || (context != null && context.IsDoingQuest(quest)))
                {
                    continue;
                }

                /*
                 * Save first quest that reaches the CanOffer call.
                 * If no quests are valid at all, return this quest for displaying the CanOffer error message.
                 */
                if (fallback == null)
                {
                    fallback = quest;
                }

                if (quest.CanOffer(quester, pm, context, false))
                {
                    m_EligiblePool.Add(quest);
                }
            }

            if (m_EligiblePool.Count == 0)
            {
                return(fallback);
            }

            return(m_EligiblePool[Utility.Random(m_EligiblePool.Count)]);
        }
        public void ClaimRewards()
        {
            if (m_Quest == null || m_Player == null || m_Player.Deleted || !ClaimReward || Removed)
            {
                return;
            }

            List <Item> rewards = new List <Item>();

            foreach (BaseReward reward in m_Quest.Rewards)
            {
                reward.AddRewardItems(m_Player, rewards);
            }

            if (rewards.Count != 0)
            {
                // On OSI a more naive method of checking is used.
                // For containers, only the actual container item counts.
                bool canFit = true;

                foreach (Item rewardItem in rewards)
                {
                    if (!m_Player.AddToBackpack(rewardItem))
                    {
                        canFit = false;
                        break;
                    }
                }

                if (!canFit)
                {
                    foreach (Item rewardItem in rewards)
                    {
                        rewardItem.Delete();
                    }

                    m_Player.SendLocalizedMessage(1078524); // Your backpack is full. You cannot complete the quest and receive your reward.
                    return;
                }

                foreach (Item rewardItem in rewards)
                {
                    string rewardName = (rewardItem.Name != null) ? rewardItem.Name : String.Concat("#", rewardItem.LabelNumber);

                    if (rewardItem.Stackable)
                    {
                        m_Player.SendLocalizedMessage(1115917, String.Concat(rewardItem.Amount, "\t", rewardName)); // You receive a reward: ~1_QUANTITY~ ~2_ITEM~
                    }
                    else
                    {
                        m_Player.SendLocalizedMessage(1074360, rewardName); // You receive a reward: ~1_REWARD~
                    }
                }
            }

            foreach (BaseObjectiveInstance objective in m_ObjectiveInstances)
            {
                objective.OnRewardClaimed();
            }

            m_Quest.OnRewardClaimed(this);

            MLQuestContext context = PlayerContext;

            if (m_Quest.RecordCompletion && !m_Quest.HasRestartDelay) // Quests with restart delays are logged earlier as per OSI
            {
                context.SetDoneQuest(m_Quest);
            }

            if (m_Quest.IsChainTriggered)
            {
                context.ChainOffers.Remove(m_Quest);
            }

            Type nextQuestType = m_Quest.NextQuest;

            if (nextQuestType != null)
            {
                MLQuest nextQuest = MLQuestSystem.FindQuest(nextQuestType);

                if (nextQuest != null && !context.ChainOffers.Contains(nextQuest))
                {
                    context.ChainOffers.Add(nextQuest);
                }
            }

            Remove();
        }