Files
Unstable Kitsune b918192e4e Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
2023-11-28 23:20:26 -05:00

967 lines
32 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Server.ContextMenus;
using Server.Mobiles;
using Server.Regions;
using Server.Targeting;
namespace Server.Engines.Quests
{
public class QuestHelper
{
public static void Initialize()
{
EventSink.OnKilledBy += OnKilledBy;
}
public static void RemoveAcceleratedSkillgain(PlayerMobile from)
{
Region region = from.Region;
while (region != null)
{
if (region is ApprenticeRegion && ((ApprenticeRegion)region).Table[from] is BuffInfo)
{
BuffInfo.RemoveBuff(from, (BuffInfo)((ApprenticeRegion)region).Table[from]);
((ApprenticeRegion)region).Table[from] = null;
}
region = region.Parent;
}
}
public static BaseQuest RandomQuest(PlayerMobile from, Type[] quests, object quester)
{
return RandomQuest(from, quests, quester, quests != null && quests.Length == 1);
}
public static BaseQuest RandomQuest(PlayerMobile from, Type[] quests, object quester, bool message)
{
if (quests == null)
return null;
BaseQuest quest = null;
if (quester is ITierQuester)
{
quest = TierQuestInfo.RandomQuest(from, (ITierQuester)quester);
}
else if (quests.Length > 0)
{
// give it 10 tries to generate quest
for (int i = 0; i < 10; i++)
{
quest = Construct(quests[Utility.Random(quests.Length)]) as BaseQuest;
}
}
if (quest != null)
{
quest.Owner = from;
quest.Quester = quester;
if (CanOffer(from, quest, quester, message))
{
return quest;
}
else if (quester is Mobile && message)
{
if (quester is MondainQuester)
{
((MondainQuester)quester).OnOfferFailed();
}
else if (quester is Mobile)
{
((Mobile)quester).Say(1080107); // I'm sorry, I have nothing for you at this time.
}
}
}
return null;
}
public static bool CanOffer(PlayerMobile from, BaseQuest quest, object quester, bool message)
{
if (!quest.CanOffer())
return false;
if (quest.ChainID != QuestChain.None)
{
// if a player wants to start quest chain (already started) again (not osi)
if (from.Chains.ContainsKey(quest.ChainID) && FirstChainQuest(quest, quest.Quester))
{
return false;
}
// if player already has an active quest from the chain
else if (InChainProgress(from, quest))
{
return false;
}
}
if (!Delayed(from, quest, quester, message))
return false;
for (int i = quest.Objectives.Count - 1; i >= 0; i --)
{
Type type = quest.Objectives[i].Type();
if (type == null)
continue;
for (int j = from.Quests.Count - 1; j >= 0; j --)
{
BaseQuest pQuest = from.Quests[j];
for (int k = pQuest.Objectives.Count - 1; k >= 0; k --)
{
BaseObjective obj = pQuest.Objectives[k];
if (type == obj.Type() && (quest.ChainID == QuestChain.None || quest.ChainID == pQuest.ChainID))
return false;
}
}
}
return true;
}
public static bool Delayed(PlayerMobile player, BaseQuest quest, object quester, bool message)
{
var restartInfo = GetRestartInfo(player, quest.GetType());
if (restartInfo != null)
{
if (quest.DoneOnce)
{
if (message && quester is Mobile)
{
((Mobile)quester).Say(1075454); // I can not offer you the quest again.
}
return false;
}
DateTime endTime = restartInfo.RestartTime;
if (DateTime.UtcNow < endTime)
{
if (message && quester is Mobile)
{
var ts = endTime - DateTime.UtcNow;
string str;
if (ts.TotalDays > 1)
str = String.Format("I cannot offer this quest again for about {0} more days.", ts.TotalDays);
else if (ts.TotalHours > 1)
str = String.Format("I cannot offer this quest again for about {0} more hours.", ts.TotalHours);
else if (ts.TotalMinutes > 1)
str = String.Format("I cannot offer this quest again for about {0} more minutes.", ts.TotalMinutes);
else
str = "I can offer this quest again very soon.";
((Mobile)quester).SayTo(player, false, str);
}
return false;
}
if (quest.RestartDelay > TimeSpan.Zero)
{
player.DoneQuests.Remove(restartInfo);
}
return true;
}
return true;
}
public static QuestRestartInfo GetRestartInfo(PlayerMobile pm, Type quest)
{
return pm.DoneQuests.FirstOrDefault(ri => ri.QuestType == quest);
}
public static bool CheckDoneOnce(PlayerMobile player, BaseQuest quest, Mobile quester, bool message)
{
return quest.DoneOnce && CheckDoneOnce(player, quest.GetType(), quester, message);
}
public static bool CheckDoneOnce(PlayerMobile player, Type questType, Mobile quester, bool message)
{
if (player.DoneQuests.Any(x => x.QuestType == questType))
{
if (message && quester != null)
{
quester.SayTo(player, 1075454, 0x3B2); // I can not offer you the quest again.
}
return true;
}
return false;
}
public static bool TryReceiveQuestItem(PlayerMobile player, Type type, TimeSpan delay)
{
if (type.IsSubclassOf(typeof(Item)))
{
var info = player.DoneQuests.FirstOrDefault(x => x.QuestType == type);
if (info != null)
{
DateTime endTime = info.RestartTime;
if (DateTime.UtcNow < endTime)
{
TimeSpan ts = endTime - DateTime.UtcNow;
if (ts.Days > 0)
{
player.SendLocalizedMessage(1158377, String.Format("{0}\t{1}", ts.Days.ToString(), "day[s]"));
}
else if (ts.Hours > 0)
{
player.SendLocalizedMessage(1158377, String.Format("{0}\t{1}", ts.Hours.ToString(), "hour[s]"));
}
else
{
player.SendLocalizedMessage(1158377, String.Format("{0}\t{1}", ts.Minutes.ToString(), "minute[s]"));
}
return false;
}
else
{
info.Reset(delay);
}
}
else
{
player.DoneQuests.Add(new QuestRestartInfo(type, delay));
}
return true;
}
return false;
}
public static void Delay(PlayerMobile player, Type type, TimeSpan delay)
{
var restartInfo = GetRestartInfo(player, type);
if (restartInfo != null)
{
restartInfo.Reset(delay);
return;
}
player.DoneQuests.Add(new QuestRestartInfo(type, delay));
}
/// <summary>
/// Called in BaseQuestItem.cs
/// </summary>
/// <param name="player"></param>
/// <param name="quests"></param>
/// <returns></returns>
public static bool InProgress(PlayerMobile player, Type[] quests)
{
if (quests == null)
return false;
var quest = player.Quests.FirstOrDefault(q => quests.Any(questerType => questerType == q.GetType()));
if (quest != null)
{
if (quest.Completed)
{
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.Complete, false, true));
}
else
{
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.InProgress, false));
quest.InProgress();
}
return true;
}
/*for (int i = 0; i < quests.Length; i ++)
{
for (int j = 0; j < player.Quests.Count; j ++)
{
BaseQuest quest = player.Quests[j];
if (quests[i].IsAssignableFrom(quest.GetType()))
{
if (quest.Completed)
{
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.Complete, false, true));
}
else
{
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.InProgress, false));
quest.InProgress();
}
return true;
}
}
}*/
return false;
}
/// <summary>
/// Called in MondainQuester.cs
/// </summary>
/// <param name="player"></param>
/// <param name="quester"></param>
/// <returns></returns>
public static bool InProgress(PlayerMobile player, Mobile quester)
{
var quest = player.Quests.FirstOrDefault(q => q.QuesterType == quester.GetType());
if (quest != null)
{
if (quest.Completed)
{
if (quest.Complete == null && !AnyRewards(quest))
quest.GiveRewards();
else
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.Complete, false, true));
}
else
{
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.InProgress, false));
quest.InProgress();
}
return true;
}
/*for (int i = 0; i < player.Quests.Count; i ++)
{
BaseQuest quest = player.Quests[i];
if (quest.Quester == null && quest.QuesterType == null)
continue;
if (quest.QuesterType == quester.GetType())
{
if (quest.Completed)
{
if (quest.Complete == null && !AnyRewards(quest))
quest.GiveRewards();
else
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.Complete, false, true));
}
else
{
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.InProgress, false));
quest.InProgress();
}
return true;
}
}*/
return false;
}
public static bool AnyRewards(BaseQuest quest)
{
for (int i = 0; i < quest.Rewards.Count; i ++)
{
BaseReward reward = quest.Rewards[i];
if (reward.Type != null)
return true;
}
return false;
}
public static bool DeliveryArrived(PlayerMobile player, BaseVendor vendor)
{
for (int i = 0; i < player.Quests.Count; i ++)
{
BaseQuest quest = player.Quests[i];
for (int j = 0; j < quest.Objectives.Count; j ++)
{
BaseObjective objective = quest.Objectives[j];
if (objective is DeliverObjective)
{
DeliverObjective deliver = (DeliverObjective)objective;
if (deliver.Update(vendor))
{
if (quest.Completed)
{
player.SendLocalizedMessage(1046258, null, 0x23); // Your quest is complete.
player.PlaySound(quest.CompleteSound);
quest.OnCompleted();
if (vendor is MondainQuester)
player.SendGump(new MondainQuestGump(player, quest, MondainQuestGump.Section.Complete, false, true, (MondainQuester)vendor));
else
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.Complete, false, true));
}
return true;
}
}
}
}
return false;
}
public static bool QuestLimitReached(PlayerMobile player)
{
if (player.Quests.Count >= 10)
{
player.SendLocalizedMessage(1075141); // You are too busy with other tasks at this time.
return true;
}
return false;
}
public static bool FirstChainQuest(BaseQuest quest, object quester)
{
return quest != null && BaseChain.Chains[(int)quest.ChainID] != null && BaseChain.Chains[(int)quest.ChainID].Length > 0 && BaseChain.Chains[(int)quest.ChainID][0] == quest.GetType();
}
public static Type FindFirstChainQuest(BaseQuest quest)
{
if (quest == null || quest.ChainID == QuestChain.None || BaseChain.Chains[(int)quest.ChainID] == null || BaseChain.Chains[(int)quest.ChainID].Length == 0)
return null;
return BaseChain.Chains[(int)quest.ChainID][0];
}
public static bool InChainProgress(PlayerMobile pm, BaseQuest quest)
{
return pm.Quests.Any(q => q.ChainID != QuestChain.None && q.ChainID == quest.ChainID && q.GetType() != quest.GetType());
}
public static Region FindRegion(string name)
{
if (name == null)
return null;
Region reg = null;
if (Map.Trammel.Regions.TryGetValue(name, out reg))
return reg;
if (Map.Felucca.Regions.TryGetValue(name, out reg))
return reg;
if (Map.Ilshenar.Regions.TryGetValue(name, out reg))
return reg;
if (Map.Malas.Regions.TryGetValue(name, out reg))
return reg;
if (Map.Tokuno.Regions.TryGetValue(name, out reg))
return reg;
if (Map.TerMur.Regions.TryGetValue(name, out reg))
return reg;
return reg;
}
public static void CompleteQuest(PlayerMobile from, BaseQuest quest)
{
if (quest == null)
return;
for (int i = 0; i < quest.Objectives.Count; i ++)
{
BaseObjective obj = quest.Objectives[i];
obj.Complete();
}
from.SendLocalizedMessage(1046258, null, 0x23); // Your quest is complete.
from.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.Complete, false, true));
from.PlaySound(quest.CompleteSound);
quest.OnCompleted();
}
public static void DeleteItems(PlayerMobile from, Type itemType, int amount, bool questItem)
{
if (from.Backpack == null || itemType == null || amount <= 0)
return;
Item[] items = from.Backpack.FindItemsByType(itemType);
int deleted = 0;
for (int i = items.Length - 1; i >= 0 && deleted < amount; i --)
{
Item item = items[i];
if (item.QuestItem || !questItem)
{
item.QuestItem = false;
if (deleted + item.Amount > amount)
{
item.Amount -= amount - deleted;
deleted += amount - deleted;
}
else
{
item.Delete();
deleted += item.Amount;
}
}
}
if (deleted < amount)
{
for (int i = from.Items.Count - 1; i >= 0 && deleted < amount; i --)
{
Item item = from.Items[i];
if (item.QuestItem || !questItem)
{
if (itemType.IsAssignableFrom(item.GetType()))
{
deleted += item.Amount;
item.Delete();
}
}
}
}
}
public static void DeleteItems(BaseQuest quest)
{
for (int i = 0; i < quest.Objectives.Count; i ++)
{
BaseObjective objective = quest.Objectives[i];
DeleteItems(quest.Owner, objective.Type(), objective.MaxProgress, true);
RemoveStatus(quest.Owner, objective.Type());
}
}
public static bool TryDeleteItems(BaseQuest quest)
{
if (quest == null)
return false;
bool complete = false;
for (int i = 0; i < quest.Objectives.Count && !complete; i ++)
{
if (quest.Objectives[i] is ObtainObjective)
{
ObtainObjective obtain = (ObtainObjective)quest.Objectives[i];
if (CountQuestItems(quest.Owner, obtain.Obtain) >= obtain.MaxProgress)
{
if (!quest.AllObjectives)
{
complete = true;
}
}
else
{
return false;
}
}
else if (quest.Objectives[i] is DeliverObjective)
{
DeliverObjective deliver = (DeliverObjective)quest.Objectives[i];
if (quest.StartingItem != null)
continue;
else if (deliver.MaxProgress > CountQuestItems(quest.Owner, deliver.Delivery))
{
quest.Owner.SendLocalizedMessage(1074813); // You have failed to complete your delivery.
deliver.Fail();
return false;
}
}
}
DeleteItems(quest);
return true;
}
public static int CountQuestItems(PlayerMobile from, Type type)
{
int count = 0;
if (from.Backpack == null)
return count;
Item[] items = from.Backpack.FindItemsByType(type);
for (int i = 0; i < items.Length; i ++)
{
Item item = items[i];
if (item.QuestItem)
count += item.Amount;
}
return count;
}
public static int RemoveStatus(PlayerMobile from, Type type)
{
if (type == null)
return 0;
Item[] items = from.Backpack.FindItemsByType(type);
int count = 0;
for (int i = 0; i < items.Length; i ++)
{
Item item = items[i];
if (item.QuestItem)
{
count += 1;
item.QuestItem = false;
}
}
return count;
}
public static void RemoveStatus(PlayerMobile from, Item item)
{
for (int i = from.Quests.Count - 1; i >= 0; i --)
{
BaseQuest quest = from.Quests[i];
for (int j = quest.Objectives.Count - 1; j >= 0; j --)
{
if (quest.Objectives[j] is ObtainObjective)
{
ObtainObjective obtain = (ObtainObjective)quest.Objectives[j];
if (obtain.Obtain != null && obtain.Obtain.IsAssignableFrom(item.GetType()))
{
obtain.CurProgress -= item.Amount;
item.QuestItem = false;
from.SendLocalizedMessage(1074769); // An item must be in your backpack (and not in a container within) to be toggled as a quest item.
return;
}
}
else if (quest.Objectives[j] is DeliverObjective)
{
DeliverObjective deliver = (DeliverObjective)quest.Objectives[j];
if (deliver.Delivery != null && deliver.Delivery.IsAssignableFrom(item.GetType()))
{
from.SendLocalizedMessage(1074813); // You have failed to complete your delivery.
DeleteItems(from, deliver.Delivery, deliver.MaxProgress, false);
deliver.Fail();
item.Delete();
return;
}
}
}
}
}
public static void OnKilledBy(OnKilledByEventArgs e)
{
if (e.KilledBy is PlayerMobile)
{
CheckCreature((PlayerMobile)e.KilledBy, e.Killed);
}
}
public static bool CheckCreature(PlayerMobile player, Mobile creature)
{
for (int i = player.Quests.Count - 1; i >= 0; i --)
{
BaseQuest quest = player.Quests[i];
for (int j = quest.Objectives.Count - 1; j >= 0; j --)
{
if (quest.Objectives[j] is SlayObjective)
{
SlayObjective slay = (SlayObjective)quest.Objectives[j];
if (slay.Update(creature))
{
if (quest.Completed)
quest.OnCompleted();
else if (slay.Completed)
player.PlaySound(quest.UpdateSound);
return true;
}
}
}
}
return false;
}
public static bool CheckItem(PlayerMobile player, Item item)
{
for (int i = player.Quests.Count - 1; i >= 0; i --)
{
BaseQuest quest = player.Quests[i];
for (int j = quest.Objectives.Count - 1; j >= 0; j --)
{
BaseObjective objective = quest.Objectives[j];
if (objective is ObtainObjective)
{
ObtainObjective obtain = (ObtainObjective)objective;
if (obtain.Update(item))
{
if (quest.Completed)
quest.OnCompleted();
else if (obtain.Completed)
player.PlaySound(quest.UpdateSound);
return true;
}
}
}
}
return false;
}
public static bool CheckRewardItem(PlayerMobile player, Item item)
{
foreach(var quest in player.Quests.Where(q => q.Objectives.Any(obj => obj is ObtainObjective)))
{
foreach (var obtain in quest.Objectives.OfType<ObtainObjective>())
{
if (obtain.IsObjective(item))
{
obtain.CurProgress += item.Amount;
quest.OnObjectiveUpdate(item);
return true;
}
}
}
return false;
}
public static bool CheckSkill(PlayerMobile player, Skill skill)
{
for (int i = player.Quests.Count - 1; i >= 0; i --)
{
BaseQuest quest = player.Quests[i];
for (int j = quest.Objectives.Count - 1; j >= 0; j --)
{
BaseObjective objective = quest.Objectives[j];
if (objective is ApprenticeObjective)
{
ApprenticeObjective apprentice = (ApprenticeObjective)objective;
if (apprentice.Update(skill))
{
if (quest.Completed)
quest.OnCompleted();
else if (apprentice.Completed)
player.PlaySound(quest.UpdateSound);
}
}
}
}
return false;
}
public static bool EnhancedSkill(PlayerMobile player, Skill skill)
{
if (player == null || player.Region == null || skill == null)
return false;
for (int i = player.Quests.Count - 1; i >= 0; i --)
{
BaseQuest quest = player.Quests[i];
for (int j = quest.Objectives.Count - 1; j >= 0; j --)
{
BaseObjective objective = quest.Objectives[j];
if (objective is ApprenticeObjective && !objective.Completed)
{
ApprenticeObjective apprentice = (ApprenticeObjective)objective;
if (apprentice.Region != null)
{
if (player.Region.IsPartOf(apprentice.Region) && skill.SkillName == apprentice.Skill)
return true;
}
}
}
}
return false;
}
public static object Construct(Type type)
{
if (type == null)
return null;
try
{
return Activator.CreateInstance(type);
}
catch
{
return null;
}
}
public static void StartTimer(PlayerMobile player)
{
if (player == null || player.Quests == null)
return;
for (int i = player.Quests.Count - 1; i >= 0; i --)
player.Quests[i].StartTimer();
}
public static void StopTimer(PlayerMobile player)
{
if (player == null || player.Quests == null)
return;
for (int i = player.Quests.Count - 1; i >= 0; i --)
player.Quests[i].StopTimer();
}
public static void GetContextMenuEntries(List<ContextMenuEntry> list)
{
if (list == null)
return;
list.Add(new SelectQuestItem());
}
public static bool FindCompletedQuest(PlayerMobile from, Type type, bool delete)
{
if (type == null)
return false;
for (int i = from.DoneQuests.Count - 1; i >= 0; i --)
{
QuestRestartInfo restartInfo = from.DoneQuests[i];
if (restartInfo.QuestType == type)
{
if (delete)
from.DoneQuests.RemoveAt(i);
return true;
}
}
return false;
}
public static bool HasQuest<T>( PlayerMobile from ) where T : BaseQuest
{
return GetQuest( from, typeof( T ) ) != null;
}
public static bool HasQuest(PlayerMobile from, Type t)
{
return GetQuest(from, t) != null;
}
public static BaseQuest GetQuest(PlayerMobile from, Type type)
{
if (type == null)
return null;
for (int i = from.Quests.Count - 1; i >= 0; i --)
{
BaseQuest quest = from.Quests[i];
if (quest.GetType() == type)
return quest;
}
return null;
}
public static T GetQuest<T>(PlayerMobile pm) where T : BaseQuest
{
return pm.Quests.FirstOrDefault(quest => quest.GetType() == typeof(T)) as T;
}
}
public class SelectQuestItem : ContextMenuEntry
{
public SelectQuestItem()
: base(6169)
{
}
public override void OnClick()
{
if (!Owner.From.Alive)
return;
Owner.From.SendLocalizedMessage(1072352); // Target the item you wish to toggle Quest Item status on <ESC> to cancel
Owner.From.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(ToggleQuestItem_Callback));
}
private void ToggleQuestItem_Callback(Mobile from, object obj)
{
if (from is PlayerMobile)
{
PlayerMobile player = (PlayerMobile)from;
if (obj is Item)
{
Item item = (Item)obj;
if (item.Parent != null && item.Parent == player.Backpack)
{
if (!QuestHelper.CheckItem(player, item))
player.SendLocalizedMessage(1072355, null, 0x23); // That item does not match any of your quest criteria
}
else
player.SendLocalizedMessage(1074769); // An item must be in your backpack (and not in a container within) to be toggled as a quest item.
}
else
player.SendLocalizedMessage(1074769); // An item must be in your backpack (and not in a container within) to be toggled as a quest item.
player.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(ToggleQuestItem_Callback));
}
}
}
}