public MLQuestInstance(MLQuest quest, IQuestGiver quester, PlayerMobile player) { Quest = quest; m_Quester = quester; QuesterType = quester?.GetType(); Player = player; Accepted = DateTime.UtcNow; m_Flags = MLQuestInstanceFlags.None; Objectives = new BaseObjectiveInstance[quest.Objectives.Count]; BaseObjectiveInstance obj; var timed = false; for (var i = 0; i < quest.Objectives.Count; ++i) { Objectives[i] = obj = quest.Objectives[i].CreateInstance(this); if (obj.IsTimed) { timed = true; } } Register(); if (timed) { m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5), Slice); } }
public MLQuestInstance( MLQuest quest, IQuestGiver quester, PlayerMobile player ) { m_Quest = quest; m_Quester = quester; m_QuesterType = ( quester == null ) ? null : quester.GetType(); m_Player = player; m_Accepted = DateTime.UtcNow; m_Flags = MLQuestInstanceFlags.None; m_ObjectiveInstances = new BaseObjectiveInstance[quest.Objectives.Count]; BaseObjectiveInstance obj; bool timed = false; for ( int i = 0; i < quest.Objectives.Count; ++i ) { m_ObjectiveInstances[i] = obj = quest.Objectives[i].CreateInstance( this ); if ( obj.IsTimed ) timed = true; } Register(); if ( timed ) m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 5 ), Slice ); }
public static void TurnToFace(IQuestGiver quester, Mobile mob) { if (quester is Mobile m) { m.Direction = m.GetDirectionTo(mob); } }
public static MLQuestInstance Deserialize(GenericReader reader, int version, PlayerMobile pm) { MLQuest quest = MLQuestSystem.ReadQuestRef(reader); // TODO: Serialize quester TYPE too, the quest giver reference then becomes optional (only for escorts) IQuestGiver quester = World.FindEntity(reader.ReadInt()) as IQuestGiver; bool claimReward = reader.ReadBool(); int objectives = reader.ReadInt(); MLQuestInstance instance; if (quest != null && quester != null && pm != null) { instance = quest.CreateInstance(quester, pm); instance.ClaimReward = claimReward; } else { instance = null; } for (int i = 0; i < objectives; ++i) { BaseObjectiveInstance.Deserialize(reader, version, (instance != null && i < instance.Objectives.Length) ? instance.Objectives[i] : null); } if (instance != null) { instance.Slice(); } return(instance); }
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?.IsDoingQuest(quest) == true) { 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. */ fallback ??= quest; if (quest.CanOffer(quester, pm, context, false)) { m_EligiblePool.Add(quest); } } return(m_EligiblePool.Count == 0 ? fallback : m_EligiblePool[Utility.Random(m_EligiblePool.Count)]); }
protected virtual void Start() { _questGiver = GetComponent <IQuestGiver>(); foreach (var quest in _questGiver.quests) { quest.OnTaskProgressChanged += OnQuestTaskProgressChanged; quest.OnStatusChanged += OnQuestStatusChanged; OnQuestChanged(quest); // Invoke first time on start. } }
private static bool FindQuest( IQuestGiver quester, PlayerMobile pm, MLQuestContext context, out MLQuest quest, out MLQuestInstance entry ) { quest = null; entry = null; var quests = quester.MLQuests; var questerType = quester.GetType(); // 1. Check quests in progress with this NPC (overriding deliveries is intended) if (context != null) { foreach (var questEntry in quests) { var 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 (var 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 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); }
public override bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message ) { Skill skill = pm.Skills[m_Skill]; if ( ( UseReal ? skill.Fixed : skill.BaseFixedPoint ) >= m_ThresholdFixed ) { if ( message ) MLQuestSystem.Tell( quester, pm, 1077772 ); // I cannot teach you, for you know all I can teach! return false; } return true; }
public override bool CanOffer(IQuestGiver quester, PlayerMobile pm, bool message) { Skill skill = pm.Skills[m_Skill]; if ((UseReal ? skill.Fixed : skill.BaseFixedPoint) >= m_ThresholdFixed) { if (message) { MLQuestSystem.Tell(quester, pm, 1077772); // I cannot teach you, for you know all I can teach! } return(false); } return(true); }
public static void TellDef(IQuestGiver quester, PlayerMobile pm, TextDefinition def) { if (def == null) { return; } if (def.Number > 0) { Tell(quester, pm, def.Number); } else if (def.String != null) { Tell(quester, pm, def.String); } }
public override bool CanOffer(IQuestGiver quester, PlayerMobile pm, bool message) { if ((quester is BaseCreature && ((BaseCreature)quester).Controlled) || (quester is BaseEscortable && ((BaseEscortable)quester).IsBeingDeleted)) { return(false); } MLQuestContext context = MLQuestSystem.GetContext(pm); if (context != null) { foreach (MLQuestInstance instance in context.QuestInstances) { if (instance.Quest.IsEscort) { if (message) { MLQuestSystem.Tell(quester, pm, 500896); // I see you already have an escort. } return(false); } } } DateTime nextEscort = pm.LastEscortTime + BaseEscortable.EscortDelay; if (nextEscort > DateTime.UtcNow) { if (message) { int minutes = (int)Math.Ceiling((nextEscort - DateTime.UtcNow).TotalMinutes); if (minutes == 1) { MLQuestSystem.Tell(quester, pm, "You must rest 1 minute before we set out on this journey."); } else { MLQuestSystem.Tell(quester, pm, 1071195, minutes.ToString()); // You must rest ~1_minsleft~ minutes before we set out on this journey. } } return(false); } return(true); }
public static void Tell(IQuestGiver quester, PlayerMobile pm, string message) { TurnToFace(quester, pm); if (quester is Mobile mobile) { mobile.PrivateOverheadMessage(MessageType.Regular, SpeechColor, false, message, pm.NetState); } else if (quester is Item item) { MessageHelper.SendMessageTo(item, pm, message, SpeechColor); } else { pm.SendMessage(SpeechColor, message); } }
public static void HandleDeletion(IQuestGiver quester) { foreach (MLQuest quest in quester.MLQuests) { List <MLQuestInstance> instances = quest.Instances; for (int i = instances.Count - 1; i >= 0; --i) { MLQuestInstance instance = instances[i]; if (instance.Quester == quester) { instance.OnQuesterDeleted(); } } } }
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); } }
public static void Tell(IQuestGiver quester, PlayerMobile pm, int cliloc) { TurnToFace(quester, pm); if (quester is Mobile) { ((Mobile)quester).PrivateOverheadMessage(MessageType.Regular, SpeechColor, cliloc, pm.NetState); } else if (quester is Item) { MessageHelper.SendLocalizedMessageTo((Item)quester, pm, cliloc, SpeechColor); } else { pm.SendLocalizedMessage(cliloc, SpeechColor); } }
public static void Tell(IQuestGiver quester, PlayerMobile pm, int cliloc, string args) { TurnToFace(quester, pm); if (quester is Mobile mobile) { mobile.PrivateOverheadMessage(MessageType.Regular, SpeechColor, cliloc, args, pm.NetState); } else if (quester is Item item) { MessageHelper.SendLocalizedMessageTo(item, pm, cliloc, args, SpeechColor); } else { pm.SendLocalizedMessage(cliloc, args); } }
public virtual void OnAccept(IQuestGiver quester, PlayerMobile pm) { if (!CanOffer(quester, pm, true)) { return; } MLQuestInstance instance = CreateInstance(quester, pm); pm.SendLocalizedMessage(1049019); // You have accepted the Quest. pm.SendSound(0x2E7); // private sound OnAccepted(instance); foreach (BaseObjectiveInstance obj in instance.Objectives) { obj.OnQuestAccepted(); } }
public override bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message ) { if ( ( quester is BaseCreature && ( (BaseCreature)quester ).Controlled ) || ( quester is BaseEscortable && ( (BaseEscortable)quester ).IsBeingDeleted ) ) return false; MLQuestContext context = MLQuestSystem.GetContext( pm ); if ( context != null ) { foreach ( MLQuestInstance instance in context.QuestInstances ) { if ( instance.Quest.IsEscort ) { if ( message ) MLQuestSystem.Tell( quester, pm, 500896 ); // I see you already have an escort. return false; } } } DateTime nextEscort = pm.LastEscortTime + BaseEscortable.EscortDelay; if ( nextEscort > DateTime.UtcNow ) { if ( message ) { int minutes = (int)Math.Ceiling( ( nextEscort - DateTime.UtcNow ).TotalMinutes ); if ( minutes == 1 ) MLQuestSystem.Tell( quester, pm, "You must rest 1 minute before we set out on this journey." ); else MLQuestSystem.Tell( quester, pm, 1071195, minutes.ToString() ); // You must rest ~1_minsleft~ minutes before we set out on this journey. } return false; } return true; }
public MainHub( ILogService logService, IGameStateService gameStateService, IPlayerActionCollection playerActionQueue, IServerManager serverManager, ILoginService loginService, IAccountService accountService, ICharacterFactory characterFactory, IQuestGiver questGiver, IDisconnectService disconnectService, IHubService hubService) { this.logService = logService; this.gameStateService = gameStateService; this.playerActionQueue = playerActionQueue; this.serverManager = serverManager; this.loginService = loginService; this.accountService = accountService; this.characterFactory = characterFactory; this.questGiver = questGiver; this.disconnectService = disconnectService; this.hubService = hubService; }
public QuestOfferGump(MLQuest quest, IQuestGiver quester, PlayerMobile pm) : base(1049010) // Quest Offer { m_Quest = quest; m_Quester = quester; CloseOtherGumps(pm); pm.CloseGump(typeof(QuestOfferGump)); SetTitle(quest.Title); RegisterButton(ButtonPosition.Left, ButtonGraphic.Accept, 1); RegisterButton(ButtonPosition.Right, ButtonGraphic.Refuse, 2); SetPageCount(3); BuildPage(); AddDescription(quest); BuildPage(); AddObjectives(quest); BuildPage(); AddRewardsPage(quest); }
public QuestOfferGump( MLQuest quest, IQuestGiver quester, PlayerMobile pm ) : base( 1049010 ) // Quest Offer { m_Quest = quest; m_Quester = quester; CloseOtherGumps( pm ); pm.CloseGump( typeof( QuestOfferGump ) ); SetTitle( quest.Title ); RegisterButton( ButtonPosition.Left, ButtonGraphic.Accept, 1 ); RegisterButton( ButtonPosition.Right, ButtonGraphic.Refuse, 2 ); SetPageCount( 3 ); BuildPage(); AddDescription( quest ); BuildPage(); AddObjectives( quest ); BuildPage(); AddRewardsPage( quest ); }
public MLQuestInstance CreateInstance(IQuestGiver quester, PlayerMobile pm) { return(new MLQuestInstance(this, quester, pm)); }
public bool CanOffer(IQuestGiver quester, PlayerMobile pm, bool message) { return(CanOffer(quester, pm, MLQuestSystem.GetContext(pm), message)); }
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 virtual void SendOffer(IQuestGiver quester, PlayerMobile pm) { pm.SendGump(new QuestOfferGump(this, quester, pm)); }
public virtual bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message ) { return true; }
public virtual bool IsDestination( IQuestGiver quester, Type type ) { Type destType = m_Objective.Destination; return ( destType != null && destType.IsAssignableFrom( type ) ); }
public static void TurnToFace( IQuestGiver quester, Mobile mob ) { if ( quester is Mobile ) { Mobile m = (Mobile)quester; m.Direction = m.GetDirectionTo( mob ); } }
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 static void HandleDeletion( IQuestGiver quester ) { foreach ( MLQuest quest in quester.MLQuests ) { List<MLQuestInstance> instances = quest.Instances; for ( int i = instances.Count - 1; i >= 0; --i ) { MLQuestInstance instance = instances[i]; if ( instance.Quester == quester ) instance.OnQuesterDeleted(); } } }
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; }
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 ); } }
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 MLQuestInstance CreateInstance(IQuestGiver quester, PlayerMobile pm) => new MLQuestInstance(this, quester, pm);
public static void Tell( IQuestGiver quester, PlayerMobile pm, int cliloc, string args ) { TurnToFace( quester, pm ); if ( quester is Mobile ) ((Mobile)quester).PrivateOverheadMessage( MessageType.Regular, SpeechColor, cliloc, args, pm.NetState ); else if ( quester is Item ) MessageHelper.SendLocalizedMessageTo( (Item)quester, pm, cliloc, args, SpeechColor ); else pm.SendLocalizedMessage( cliloc, args, SpeechColor ); }
public virtual bool IsDestination(IQuestGiver quester, Type type) { Type destType = m_Objective.Destination; return(destType != null && destType.IsAssignableFrom(type)); }
public static void Tell( IQuestGiver quester, PlayerMobile pm, string message ) { TurnToFace( quester, pm ); if ( quester is Mobile ) ((Mobile)quester).PrivateOverheadMessage( MessageType.Regular, SpeechColor, false, message, pm.NetState ); else if ( quester is Item ) MessageHelper.SendMessageTo( (Item)quester, pm, message, SpeechColor ); else pm.SendMessage( SpeechColor, message ); }
public virtual bool CanOffer(IQuestGiver quester, PlayerMobile pm, bool message) { return(true); }
public static void TellDef( IQuestGiver quester, PlayerMobile pm, TextDefinition def ) { if ( def == null ) return; if ( def.Number > 0 ) Tell( quester, pm, def.Number ); else if ( def.String != null ) Tell( quester, pm, def.String ); }
public virtual bool CanOffer(IQuestGiver quester, PlayerMobile pm, bool message) => true;
public virtual void OnRefuse(IQuestGiver quester, PlayerMobile pm) { pm.SendGump(new QuestConversationGump(this, pm, RefusalMessage)); }