Overwrite

Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
Unstable Kitsune
2023-11-28 23:20:26 -05:00
parent 3cd54811de
commit b918192e4e
11608 changed files with 2644205 additions and 47 deletions

View File

@@ -0,0 +1,97 @@
using System;
using System.Collections;
using System.Xml;
using Server.Engines.Quests;
using Server.Mobiles;
namespace Server.Regions
{
public class ApprenticeRegion : BaseRegion
{
private readonly Hashtable m_Table = new Hashtable();
public ApprenticeRegion(XmlElement xml, Map map, Region parent)
: base(xml, map, parent)
{
}
public Hashtable Table
{
get
{
return this.m_Table;
}
}
public override void OnEnter(Mobile m)
{
base.OnEnter(m);
if (m is PlayerMobile)
{
PlayerMobile player = (PlayerMobile)m;
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 ApprenticeObjective && !objective.Completed)
{
ApprenticeObjective apprentice = (ApprenticeObjective)objective;
if (this.IsPartOf(apprentice.Region))
{
if (apprentice.Enter is int)
player.SendLocalizedMessage((int)apprentice.Enter);
else if (apprentice.Enter is string)
player.SendMessage((string)apprentice.Enter);
BuffInfo info = new BuffInfo(BuffIcon.ArcaneEmpowerment, 1078511, 1078512, apprentice.Skill.ToString()); // Accelerated Skillgain Skill: ~1_val~
BuffInfo.AddBuff(m, info);
this.m_Table[m] = info;
}
}
}
}
}
}
public override void OnExit(Mobile m)
{
base.OnExit(m);
if (m is PlayerMobile)
{
PlayerMobile player = (PlayerMobile)m;
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 ApprenticeObjective && !objective.Completed)
{
ApprenticeObjective apprentice = (ApprenticeObjective)objective;
if (this.IsPartOf(apprentice.Region))
{
if (apprentice.Leave is int)
player.SendLocalizedMessage((int)apprentice.Leave);
else if (apprentice.Leave is string)
player.SendMessage((string)apprentice.Leave);
if (this.m_Table[m] is BuffInfo)
BuffInfo.RemoveBuff(m, (BuffInfo)this.m_Table[m]);
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,417 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.ContextMenus;
using Server.Mobiles;
using Server.Services.Virtues;
namespace Server.Engines.Quests
{
public class BaseEscort : MondainQuester
{
private static readonly TimeSpan m_EscortDelay = TimeSpan.FromMinutes(5.0);
private static readonly Dictionary<Mobile, Mobile> m_EscortTable = new Dictionary<Mobile, Mobile>();
private Timer m_DeleteTimer;
private bool m_Checked;
public BaseQuest Quest { get; set; }
public DateTime LastSeenEscorter { get; set; }
public BaseEscort()
: base()
{
AI = AIType.AI_Melee;
FightMode = FightMode.Aggressor;
RangePerception = 22;
RangeFight = 1;
ActiveSpeed = 0.2;
PassiveSpeed = 1.0;
ControlSlots = 0;
}
public BaseEscort(Serial serial)
: base(serial)
{
}
public override bool InitialInnocent { get { return true; } }
public override bool IsInvulnerable { get { return false; } }
public override bool Commandable { get { return false; } }
public override Type[] Quests { get { return null; } }
public override bool CanAutoStable { get { return false; } }
public override bool CanDetectHidden { get { return false; } }
public override void OnTalk(PlayerMobile player)
{
if (AcceptEscorter(player))
base.OnTalk(player);
}
public override bool CanBeRenamedBy(Mobile from)
{
return (from.AccessLevel >= AccessLevel.GameMaster);
}
public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
{
if (from.Alive && from == ControlMaster)
list.Add(new AbandonEscortEntry(this));
base.AddCustomContextEntries(from, list);
}
public override void OnAfterDelete()
{
if (Quest != null)
{
Quest.RemoveQuest();
if (Quest.Owner != null)
m_EscortTable.Remove(Quest.Owner);
}
base.OnAfterDelete();
}
public override void OnThink()
{
base.OnThink();
CheckAtDestination();
}
public override bool CanBeDamaged()
{
return true;
}
public override void InitBody()
{
SetStr(90, 100);
SetDex(90, 100);
SetInt(15, 25);
Hue = Utility.RandomSkinHue();
Female = Utility.RandomBool();
Name = NameList.RandomName(Female ? "female" : "male");
Race = Race.Human;
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
writer.Write(m_DeleteTimer != null);
if (m_DeleteTimer != null)
writer.WriteDeltaTime(m_DeleteTimer.Next);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (reader.ReadBool())
{
DateTime deleteTime = reader.ReadDeltaTime();
m_DeleteTimer = Timer.DelayCall(deleteTime - DateTime.UtcNow, new TimerCallback(Delete));
}
}
public void AddHash(PlayerMobile player)
{
m_EscortTable[player] = this;
}
public virtual void StartFollow()
{
StartFollow(ControlMaster);
}
public virtual void StartFollow(Mobile escorter)
{
ActiveSpeed = 0.1;
PassiveSpeed = 0.2;
ControlOrder = OrderType.Follow;
ControlTarget = escorter;
CurrentSpeed = 0.1;
}
public virtual void StopFollow()
{
ActiveSpeed = 0.2;
PassiveSpeed = 1.0;
ControlOrder = OrderType.None;
ControlTarget = null;
CurrentSpeed = 1.0;
SetControlMaster(null);
}
public virtual void BeginDelete(Mobile m)
{
StopFollow();
if (m != null)
m_EscortTable.Remove(m);
m_DeleteTimer = Timer.DelayCall(TimeSpan.FromSeconds(45.0), new TimerCallback(Delete));
}
public virtual bool AcceptEscorter(Mobile m)
{
if (!m.Alive)
{
return false;
}
else if (m_DeleteTimer != null)
{
Say(500898); // I am sorry, but I do not wish to go anywhere.
return false;
}
else if (Controlled)
{
if (m == ControlMaster)
m.SendGump(new MondainQuestGump(Quest, MondainQuestGump.Section.InProgress, false));
else
Say(500897); // I am already being led!
return false;
}
else if (!m.InRange(Location, 5))
{
Say(500348); // I am too far away to do that.
return false;
}
else if (m_EscortTable.ContainsKey(m))
{
Say(500896); // I see you already have an escort.
return false;
}
else if (m is PlayerMobile && (((PlayerMobile)m).LastEscortTime + m_EscortDelay) >= DateTime.UtcNow)
{
int minutes = (int)Math.Ceiling(((((PlayerMobile)m).LastEscortTime + m_EscortDelay) - DateTime.UtcNow).TotalMinutes);
Say("You must rest {0} minute{1} before we set out on this journey.", minutes, minutes == 1 ? "" : "s");
return false;
}
return true;
}
public virtual EscortObjective GetObjective()
{
if (Quest != null)
{
for (int i = 0; i < Quest.Objectives.Count; i++)
{
EscortObjective escort = Quest.Objectives[i] as EscortObjective;
if (escort != null && !escort.Completed && !escort.Failed)
return escort;
}
}
return null;
}
public virtual Mobile GetEscorter()
{
Mobile master = ControlMaster;
if (master == null || !Controlled)
{
return master;
}
else if (master.Map != Map || !master.InRange(Location, 30) || !master.Alive)
{
TimeSpan lastSeenDelay = DateTime.UtcNow - LastSeenEscorter;
if (lastSeenDelay >= TimeSpan.FromMinutes(2.0))
{
EscortObjective escort = GetObjective();
if (escort != null)
{
master.SendLocalizedMessage(1071194); // You have failed your escort quest…
master.PlaySound(0x5B3);
escort.Fail();
}
master.SendLocalizedMessage(1042473); // You have lost the person you were escorting.
Say(1005653); // Hmmm. I seem to have lost my master.
StopFollow();
m_EscortTable.Remove(master);
m_DeleteTimer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), new TimerCallback(Delete));
return null;
}
else
{
ControlOrder = OrderType.Stay;
}
}
else
{
if (ControlOrder != OrderType.Follow)
StartFollow(master);
LastSeenEscorter = DateTime.UtcNow;
}
return master;
}
public virtual Region GetDestination()
{
return null;
}
public virtual bool CheckAtDestination()
{
if (Quest != null)
{
EscortObjective escort = GetObjective();
if (escort == null)
return false;
Mobile escorter = GetEscorter();
if (escorter == null)
return false;
if (escort.Region != null && escort.Region.Contains(Location))
{
Say(1042809, escorter.Name); // We have arrived! I thank thee, ~1_PLAYER_NAME~! I have no further need of thy services. Here is thy pay.
escort.Complete();
if (Quest.Completed)
{
escorter.SendLocalizedMessage(1046258, null, 0x23); // Your quest is complete.
if (QuestHelper.AnyRewards(Quest))
escorter.SendGump(new MondainQuestGump(Quest, MondainQuestGump.Section.Rewards, false, true));
else
Quest.GiveRewards();
escorter.PlaySound(Quest.CompleteSound);
StopFollow();
m_EscortTable.Remove(escorter);
m_DeleteTimer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), new TimerCallback(Delete));
// fame
Misc.Titles.AwardFame(escorter, escort.Fame, true);
// compassion
bool gainedPath = false;
PlayerMobile pm = escorter as PlayerMobile;
if (pm != null)
{
if (pm.CompassionGains > 0 && DateTime.UtcNow > pm.NextCompassionDay)
{
pm.NextCompassionDay = DateTime.MinValue;
pm.CompassionGains = 0;
}
if (pm.CompassionGains >= 5) // have already gained 5 times in one day, can gain no more
{
pm.SendLocalizedMessage(1053004); // You must wait about a day before you can gain in compassion again.
}
else if (VirtueHelper.Award(pm, VirtueName.Compassion, escort.Compassion, ref gainedPath))
{
pm.SendLocalizedMessage(1074949, null, 0x2A); // You have demonstrated your compassion! Your kind actions have been noted.
if (gainedPath)
pm.SendLocalizedMessage(1053005); // You have achieved a path in compassion!
else
pm.SendLocalizedMessage(1053002); // You have gained in compassion.
pm.NextCompassionDay = DateTime.UtcNow + TimeSpan.FromDays(1.0); // in one day CompassionGains gets reset to 0
++pm.CompassionGains;
}
else
{
pm.SendLocalizedMessage(1053003); // You have achieved the highest path of compassion and can no longer gain any further.
}
}
}
else
{
escorter.PlaySound(Quest.UpdateSound);
}
return true;
}
}
else if (!m_Checked)
{
Region region = GetDestination();
if (region != null && region.Contains(Location))
{
m_DeleteTimer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), new TimerCallback(Delete));
m_Checked = true;
}
}
return false;
}
private class AbandonEscortEntry : ContextMenuEntry
{
private readonly BaseEscort m_Mobile;
public AbandonEscortEntry(BaseEscort m)
: base(6102, 3)
{
m_Mobile = m;
}
public override void OnClick()
{
Owner.From.SendLocalizedMessage(1071194); // You have failed your escort quest…
Owner.From.PlaySound(0x5B3);
m_Mobile.Delete();
}
}
public static void DeleteEscort(Mobile owner)
{
PlayerMobile pm = owner as PlayerMobile;
foreach (var escortquest in pm.Quests.Where(x => x.Quester is BaseEscort))
{
BaseEscort escort = (BaseEscort)escortquest.Quester;
Timer.DelayCall(TimeSpan.FromSeconds(3), new TimerCallback(
delegate
{
escort.Say(500901); // Ack! My escort has come to haunt me!
owner.SendLocalizedMessage(1071194); // You have failed your escort quest…
owner.PlaySound(0x5B3);
escort.Delete();
}));
}
}
}
}

View File

@@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests
{
public abstract class BaseQuestItem : Item
{
private bool m_InDelivery;
private int m_Duration;
private BaseQuest m_Quest;
private Timer m_Timer;
public BaseQuestItem(int itemID)
: base(itemID)
{
this.LootType = LootType.Blessed;
if (this.Lifespan > 0)
this.StartTimer();
}
public BaseQuestItem(Serial serial)
: base(serial)
{
}
public virtual Type[] Quests
{
get
{
return null;
}
}
public virtual int Lifespan
{
get
{
return 0;
}
}
public int Duration
{
get
{
return this.m_Duration;
}
set
{
this.m_Duration = value;
this.InvalidateProperties();
}
}
public BaseQuest Quest
{
get
{
return this.m_Quest;
}
set
{
this.m_Quest = value;
}
}
public override void OnDoubleClick(Mobile from)
{
if (!this.IsChildOf(from.Backpack) && this.Movable)
{
from.SendLocalizedMessage(1060640); // The item must be in your backpack to use it.
return;
}
if (!(from is PlayerMobile))
return;
PlayerMobile player = (PlayerMobile)from;
if (QuestHelper.InProgress(player, this.Quests))
return;
if (QuestHelper.QuestLimitReached(player))
return;
// check if this quester can offer quest chain (already started)
foreach (KeyValuePair<QuestChain, BaseChain> pair in player.Chains)
{
BaseChain chain = pair.Value;
if (chain != null && chain.Quester != null && chain.Quester.IsAssignableFrom(this.GetType()))
{
BaseQuest quest = QuestHelper.RandomQuest(player, new Type[] { chain.CurrentQuest }, this);
if (quest != null)
{
player.CloseGump(typeof(MondainQuestGump));
player.SendGump(new MondainQuestGump(quest));
return;
}
}
}
BaseQuest questt = QuestHelper.RandomQuest(player, this.Quests, this);
if (questt != null)
{
player.CloseGump(typeof(MondainQuestGump));
player.SendGump(new MondainQuestGump(questt));
}
else
player.SendLocalizedMessage(1075141); // You are too busy with other tasks at this time.
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
if (this.m_Duration > 0)
list.Add(1072517, this.m_Duration.ToString()); // Lifespan: ~1_val~ seconds
if (!this.QuestItem)
list.Add(1072351); // Quest Item
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
writer.Write((int)this.m_Duration);
writer.Write((bool)this.m_InDelivery);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
this.m_Duration = reader.ReadInt();
this.m_InDelivery = reader.ReadBool();
if (this.m_Duration > 0)
this.StartTimer();
}
public virtual void StartTimer()
{
if (this.m_Timer != null)
return;
this.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10), new TimerCallback(Slice));
}
public virtual void StopTimer()
{
if (this.m_Timer != null)
this.m_Timer.Stop();
this.m_Timer = null;
}
public virtual void Slice()
{
if (this.m_Duration + 10 < this.Lifespan)
this.m_Duration += 10;
else
{
this.StopTimer();
if (this.Parent is Backpack)
{
Backpack pack = (Backpack)this.Parent;
if (pack.Parent is PlayerMobile)
QuestHelper.RemoveStatus((PlayerMobile)pack.Parent, this);
}
this.Delete();
}
}
}
}

View File

@@ -0,0 +1,345 @@
#region References
using System;
using Server.Engines.Craft;
using Server.Items;
#endregion
namespace Server.Engines.Quests
{
public class BaseReward
{
private static readonly int[] m_SatchelHues = new[]
{0x1C, 0x37, 0x71, 0x3A, 0x62, 0x44, 0x59, 0x13, 0x21, 0x3, 0xD, 0x3F,}; // TODO update
private static readonly int[] m_RewardBagHues = new[]
{
// from, to,
0x385, 0x3E9, 0x4B0, 0x4E6, 0x514, 0x54A, 0x578, 0x5AE, 0x5DC, 0x612, 0x640, 0x676, 0x6A5, 0x6DA, 0x708, 0x774
};
public BaseReward(object name)
: this(null, 1, name)
{ }
public BaseReward(Type type, object name)
: this(type, 1, name)
{ }
public BaseReward(Type type, int amount, object name)
{
Type = type;
Amount = amount;
Name = name;
}
public BaseQuest Quest { get; set; }
public Type Type { get; set; }
public int Amount { get; set; }
public object Name { get; set; }
public static int SatchelHue()
{
return m_SatchelHues[Utility.Random(m_SatchelHues.Length)];
}
public static int RewardBagHue()
{
if (Utility.RandomDouble() < 0.005)
{
return 0;
}
int row = Utility.Random(m_RewardBagHues.Length / 2) * 2;
return Utility.RandomMinMax(m_RewardBagHues[row], m_RewardBagHues[row + 1]);
}
public static int StrongboxHue()
{
return Utility.RandomMinMax(0x898, 0x8B0);
}
public static void ApplyMods(Item item)
{
if (item != null)
{
if (Core.SA && RandomItemGenerator.Enabled)
{
RunicReforging.GenerateRandomItem(item, 0, 10, 850);
}
else
{
int attributeCount = Utility.RandomMinMax(1, 5);
if(item is BaseJewel)
BaseRunicTool.ApplyAttributesTo((BaseJewel)item, false, 0, attributeCount, 10, 100);
else if (item is BaseWeapon)
BaseRunicTool.ApplyAttributesTo((BaseWeapon)item, false, 0, attributeCount, 10, 100);
else if (item is BaseRanged)
BaseRunicTool.ApplyAttributesTo((BaseRanged)item, false, 0, attributeCount, 10, 100);
else if (item is BaseArmor)
BaseRunicTool.ApplyAttributesTo((BaseArmor)item, false, 0, attributeCount, 10, 100);
}
}
}
public static Item Jewlery()
{
BaseJewel item = Loot.RandomJewelry();
ApplyMods(item);
return item;
}
public static Item FletcherRecipe()
{
return GetRecipe(Enum.GetValues(typeof(BowRecipes)));
}
public static Item FletcherRunic()
{
var ran = Utility.RandomDouble();
if (Core.HS)
{
if (ran <= 0.0001)
{
return new RunicFletcherTool(CraftResource.Heartwood, 15);
}
else if (ran <= 0.0005)
{
return new RunicFletcherTool(CraftResource.YewWood, 25);
}
else if (ran <= 0.0025)
{
return new RunicFletcherTool(CraftResource.AshWood, 35);
}
else if (ran <= 0.005)
{
return new RunicFletcherTool(CraftResource.OakWood, 45);
}
}
else if (ran <= 0.01)
{
switch (Utility.Random(4))
{
case 0:
return new RunicFletcherTool(CraftResource.OakWood, 45);
case 1:
return new RunicFletcherTool(CraftResource.AshWood, 35);
case 2:
return new RunicFletcherTool(CraftResource.YewWood, 25);
case 3:
return new RunicFletcherTool(CraftResource.Heartwood, 15);
}
}
return null;
}
public static Item RangedWeapon()
{
BaseWeapon item = Loot.RandomRangedWeapon(false, true);
ApplyMods(item);
return item;
}
public static Item TailorRecipe()
{
return GetRecipe(new int[] { 501, 502, 503, 504, 505, 550, 551, 552 });
}
public static Item Armor()
{
BaseArmor item = Loot.RandomArmor(false, true);
ApplyMods(item);
return item;
}
public static Item SmithRecipe()
{
return GetRecipe(new int[] { 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 350, 351, 352, 353, 354 });
}
public static Item Weapon()
{
BaseWeapon item = Loot.RandomWeapon(false, true);
ApplyMods(item);
return item;
}
public static Item TinkerRecipe()
{
RecipeScroll recipe = null;
if (0.01 > Utility.RandomDouble())
{
recipe = new RecipeScroll(Utility.RandomList(450, 451, 452, 453));
}
return recipe;
}
public static Item AlchemyRecipe()
{
RecipeScroll recipes;
if (Core.TOL)
{
recipes = GetRecipe(new int[] { 400, 401, 402 });
}
else
{
recipes = GetRecipe(new int[] { 400, 401, 402, 454 });
}
return recipes;
}
public static Item CarpentryRecipe()
{
int[] array = new int[24];
for (int i = 0; i <= 20; i++)
{
array[i] = 100 + i;
}
array[21] = 150;
array[22] = 151;
array[23] = 152;
return GetRecipe(array);
}
public static Item CarpenterRunic()
{
var ran = Utility.RandomDouble();
if (Core.HS)
{
if (ran <= 0.0001)
{
return new RunicDovetailSaw(CraftResource.Heartwood, 15);
}
else if (ran <= 0.0005)
{
return new RunicDovetailSaw(CraftResource.YewWood, 25);
}
else if (ran <= 0.0025)
{
return new RunicDovetailSaw(CraftResource.AshWood, 35);
}
else if (ran <= 0.005)
{
return new RunicDovetailSaw(CraftResource.OakWood, 45);
}
}
else if (ran <= 0.01)
{
switch (Utility.Random(4))
{
case 0:
return new RunicDovetailSaw(CraftResource.OakWood, 45);
case 1:
return new RunicDovetailSaw(CraftResource.AshWood, 35);
case 2:
return new RunicDovetailSaw(CraftResource.YewWood, 25);
case 3:
return new RunicDovetailSaw(CraftResource.Heartwood, 15);
}
}
return null;
}
public static Item RandomFurniture()
{
if (0.005 >= Utility.RandomDouble())
{
return Loot.Construct(ElvishFurniture);
}
return null;
}
public static Type[] ElvishFurniture =
{
typeof(WarriorStatueSouthDeed),
typeof(WarriorStatueEastDeed),
typeof(SquirrelStatueSouthDeed),
typeof(SquirrelStatueEastDeed),
typeof(ElvenDresserSouthDeed),
typeof(ElvenDresserEastDeed),
typeof(TallElvenBedSouthDeed),
typeof(TallElvenBedEastDeed),
typeof(StoneAnvilSouthDeed),
typeof(StoneAnvilEastDeed),
typeof(OrnateElvenChestEastDeed)
};
public static Item CookRecipe()
{
return GetRecipe(Enum.GetValues(typeof(CookRecipes)));
}
public static RecipeScroll GetRecipe(Array list)
{
var recipes = new int[list.Length];
int index = 0;
int mid = -1;
foreach (int i in list)
{
int val = i - (i / 100) * 100;
if (val >= 50 && mid == -1)
{
mid = index;
}
recipes[index] = i;
index += 1;
}
if (list.Length == 0) // empty list
{
return null;
}
var ran = Utility.RandomDouble();
if (mid == -1 && ran <= 0.33) // only lesser recipes in list
{
return new RecipeScroll(recipes[Utility.Random(list.Length)]);
}
else if (mid == 0 && ran <= 0.01) // only greater recipes in list
{
return new RecipeScroll(recipes[Utility.Random(list.Length)]);
}
else
{
if (ran <= 0.01)
{
return new RecipeScroll(recipes[Utility.RandomMinMax(mid, list.Length - 1)]);
}
else if (ran <= 0.33)
{
return new RecipeScroll(recipes[Utility.Random(mid)]);
}
}
return null;
}
public virtual void GiveReward()
{ }
}
}

View File

@@ -0,0 +1,73 @@
using System;
using Server.Gumps;
namespace Server.Engines.Quests
{
public class ConfirmHeritageGump : Gump
{
private readonly HeritageQuester m_Quester;
public ConfirmHeritageGump(HeritageQuester quester)
: base(50, 50)
{
m_Quester = quester;
Closable = true;
Disposable = true;
Dragable = true;
Resizable = false;
AddPage(0);
AddBackground(0, 0, 240, 135, 0x2422);
object message = m_Quester.ConfirmMessage;
if (message is int)
AddHtmlLocalized(15, 15, 210, 75, (int)message, 0x0, false, false);
else if (message is string)
AddHtml(15, 15, 210, 75, (string)message, false, false);
AddButton(160, 95, 0xF7, 0xF8, (int)Buttons.Okay, GumpButtonType.Reply, 0);
AddButton(90, 95, 0xF2, 0xF1, (int)Buttons.Close, GumpButtonType.Reply, 0);
}
private enum Buttons
{
Close,
Okay,
}
public override void OnResponse(Server.Network.NetState state, RelayInfo info)
{
if (m_Quester == null)
return;
if (info.ButtonID == (int)Buttons.Okay)
{
Mobile m = state.Mobile;
if (HeritageQuester.Check(m))
{
HeritageQuester.AddPending(m, m_Quester);
Timer.DelayCall(TimeSpan.FromMinutes(1), new TimerStateCallback(CloseHeritageGump), m);
state.Mobile.Send(new HeritagePacket(m.Female, (short)(m_Quester.Race.RaceID + 1)));
}
}
}
private void CloseHeritageGump(object args)
{
if (args is Mobile)
{
Mobile m = (Mobile)args;
if (HeritageQuester.IsPending(m))
{
m.Send(HeritagePacket.Close);
HeritageQuester.RemovePending(m);
}
}
}
}
}

View File

@@ -0,0 +1,719 @@
using System;
using Server.Gumps;
using Server.Mobiles;
namespace Server.Engines.Quests
{
public enum Buttons
{
Close,
CloseQuest,
RefuseQuest,
ResignQuest,
AcceptQuest,
AcceptReward,
PreviousPage,
NextPage,
Complete,
CompleteQuest,
RefuseReward
}
public class MondainQuestGump : BaseQuestGump
{
private const int ButtonOffset = 11;
private readonly object m_Quester;
private readonly PlayerMobile m_From;
private readonly BaseQuest m_Quest;
private readonly bool m_Offer;
private readonly bool m_Completed;
private Section m_Section;
public MondainQuestGump(PlayerMobile from)
: this(from, null, Section.Main, false, false)
{
}
public MondainQuestGump(BaseQuest quest)
: this(quest, Section.Description, true)
{
}
public MondainQuestGump(BaseQuest quest, Section section, bool offer)
: this(null, quest, section, offer, false)
{
}
public MondainQuestGump(BaseQuest quest, Section section, bool offer, bool completed)
: this(null, quest, section, offer, completed)
{
}
public MondainQuestGump(PlayerMobile owner, BaseQuest quest, Section section, bool offer, bool completed)
: this(owner, quest, section, offer, completed, null)
{
}
public MondainQuestGump(PlayerMobile owner, BaseQuest quest, Section section, bool offer, bool completed, object quester)
: base(75, 25)
{
m_Quester = quester;
m_Quest = quest;
m_Section = section;
m_Offer = offer;
m_Completed = completed;
if (quest != null)
m_From = quest.Owner;
else
m_From = owner;
Closable = false;
Disposable = true;
Dragable = true;
Resizable = false;
AddPage(0);
AddImageTiled(50, 20, 400, 460, 0x1404);
AddImageTiled(50, 29, 30, 450, 0x28DC);
AddImageTiled(34, 140, 17, 339, 0x242F);
AddImage(48, 135, 0x28AB);
AddImage(-16, 285, 0x28A2);
AddImage(0, 10, 0x28B5);
AddImage(25, 0, 0x28B4);
AddImageTiled(83, 15, 350, 15, 0x280A);
AddImage(34, 479, 0x2842);
AddImage(442, 479, 0x2840);
AddImageTiled(51, 479, 392, 17, 0x2775);
AddImageTiled(415, 29, 44, 450, 0xA2D);
AddImageTiled(415, 29, 30, 450, 0x28DC);
AddImage(370, 50, 0x589);
if ((int)m_From.AccessLevel > (int)AccessLevel.Counselor && quest != null)
{
AddButton(379, 60, 0x15A9, 0x15A9, (int)Buttons.CompleteQuest, GumpButtonType.Reply, 0);
}
else
{
if (m_Quest == null)
{
AddImage(379, 60, 0x15A9);
}
else
{
AddImage(379, 60, 0x1580);
}
}
AddImage(425, 0, 0x28C9);
AddImage(90, 33, 0x232D);
AddImageTiled(130, 65, 175, 1, 0x238D);
switch ( m_Section )
{
case Section.Main:
SecMain();
break;
case Section.Description:
SecDescription();
break;
case Section.Objectives:
SecObjectives();
break;
case Section.Rewards:
SecRewards();
break;
case Section.Refuse:
SecRefuse();
break;
case Section.Complete:
SecComplete();
break;
case Section.InProgress:
SecInProgress();
break;
case Section.Failed:
SecFailed();
break;
}
}
public enum Section
{
Main,
Description,
Objectives,
Rewards,
Refuse,
Complete,
InProgress,
Failed
}
public virtual void SecMain()
{
if (m_From == null)
return;
AddHtmlLocalized(130, 45, 270, 16, 1046026, 0xFFFFFF, false, false); // Quest Log
int offset = 140;
for (int i = m_From.Quests.Count - 1; i >= 0; i--)
{
BaseQuest quest = m_From.Quests[i];
AddHtmlObject(98, offset, 270, 21, quest.Title, quest.Failed ? 0x3C00 : White, false, false);
AddButton(368, offset, 0x26B0, 0x26B1, ButtonOffset + i, GumpButtonType.Reply, 0);
offset += 21;
}
AddButton(313, 455, 0x2EEC, 0x2EEE, (int)Buttons.Close, GumpButtonType.Reply, 0);
}
public virtual void SecDescription()
{
if (m_Quest == null)
return;
if (!m_Quest.RenderDescription(this, m_Offer))
{
if (m_Offer)
AddHtmlLocalized(130, 45, 270, 16, 1049010, 0xFFFFFF, false, false); // Quest Offer
else
AddHtmlLocalized(130, 45, 270, 16, 1046026, 0xFFFFFF, false, false); // Quest Log
if (m_Quest.Failed)
AddHtmlLocalized(160, 80, 200, 32, 500039, 0x3C00, false, false); // Failed!
AddHtmlObject(160, 70, 200, 40, m_Quest.Title, DarkGreen, false, false);
if (m_Quest.ChainID != QuestChain.None)
AddHtmlLocalized(98, 140, 312, 16, 1075024, 0x2710, false, false); // Description (quest chain)
else
AddHtmlLocalized(98, 140, 312, 16, 1072202, 0x2710, false, false); // Description
AddHtmlObject(98, 156, 312, 180, m_Quest.Description, LightGreen, false, true);
if (m_Offer)
{
AddButton(95, 455, 0x2EE0, 0x2EE2, (int)Buttons.AcceptQuest, GumpButtonType.Reply, 0);
AddButton(313, 455, 0x2EF2, 0x2EF4, (int)Buttons.RefuseQuest, GumpButtonType.Reply, 0);
}
else
{
AddButton(95, 455, 0x2EF5, 0x2EF7, (int)Buttons.ResignQuest, GumpButtonType.Reply, 0);
AddButton(313, 455, 0x2EEC, 0x2EEE, (int)Buttons.CloseQuest, GumpButtonType.Reply, 0);
}
if (m_Quest.ShowDescription)
AddButton(275, 430, 0x2EE9, 0x2EEB, (int)Buttons.NextPage, GumpButtonType.Reply, 0);
}
}
public virtual void SecObjectives()
{
if (m_Quest == null)
return;
if (m_Offer)
{
AddButton(95, 455, 0x2EE0, 0x2EE2, (int)Buttons.AcceptQuest, GumpButtonType.Reply, 0);
AddButton(313, 455, 0x2EF2, 0x2EF4, (int)Buttons.RefuseQuest, GumpButtonType.Reply, 0);
}
else
{
AddButton(95, 455, 0x2EF5, 0x2EF7, (int)Buttons.ResignQuest, GumpButtonType.Reply, 0);
AddButton(313, 455, 0x2EEC, 0x2EEE, (int)Buttons.CloseQuest, GumpButtonType.Reply, 0);
}
if (!m_Quest.RenderObjective(this, m_Offer))
{
if (m_Offer)
AddHtmlLocalized(130, 45, 270, 16, 1049010, 0xFFFFFF, false, false); // Quest Offer
else
AddHtmlLocalized(130, 45, 270, 16, 1046026, 0xFFFFFF, false, false); // Quest Log
AddHtmlObject(160, 70, 200, 40, m_Quest.Title, DarkGreen, false, false);
AddHtmlLocalized(98, 140, 312, 16, 1049073, 0x2710, false, false); // Objective:
if (m_Quest.AllObjectives)
AddHtmlLocalized(98, 156, 312, 16, 1072208, 0x2710, false, false); // All of the following
else
AddHtmlLocalized(98, 156, 312, 16, 1072209, 0x2710, false, false); // Only one of the following
int offset = 172;
for (int i = 0; i < m_Quest.Objectives.Count; i++)
{
BaseObjective objective = m_Quest.Objectives[i];
if (objective is SlayObjective)
{
SlayObjective slay = (SlayObjective)objective;
if (slay != null)
{
AddHtmlLocalized(98, offset, 30, 16, 1072204, 0x15F90, false, false); // Slay
AddLabel(133, offset, 0x481, slay.MaxProgress + " " + slay.Name); // %count% + %name%
offset += 16;
if (m_Offer)
{
if (slay.Timed)
{
AddHtmlLocalized(103, offset, 120, 16, 1062379, 0x15F90, false, false); // Est. time remaining:
AddLabel(223, offset, 0x481, FormatSeconds(slay.Seconds)); // %est. time remaining%
offset += 16;
}
continue;
}
if (slay.Region != null)
{
AddHtmlLocalized(103, offset, 312, 20, 1018327, 0x15F90, false, false); // Location
AddHtmlObject(223, offset, 312, 20, slay.Region.Name, White, false, false); // %location%
offset += 16;
}
AddHtmlLocalized(103, offset, 120, 16, 3000087, 0x15F90, false, false); // Total
AddLabel(223, offset, 0x481, slay.CurProgress.ToString()); // %current progress%
offset += 16;
if (ReturnTo() != null)
{
AddHtmlLocalized(103, offset, 120, 16, 1074782, 0x15F90, false, false); // Return to
AddLabel(223, offset, 0x481, ReturnTo()); // %return to%
offset += 16;
}
if (slay.Timed)
{
AddHtmlLocalized(103, offset, 120, 16, 1062379, 0x15F90, false, false); // Est. time remaining:
AddLabel(223, offset, 0x481, FormatSeconds(slay.Seconds)); // %est. time remaining%
offset += 16;
}
}
}
else if (objective is ObtainObjective)
{
ObtainObjective obtain = (ObtainObjective)objective;
if (obtain != null)
{
AddHtmlLocalized(98, offset, 40, 16, 1072205, 0x15F90, false, false); // Obtain
AddLabel(143, offset, 0x481, obtain.MaxProgress + " " + obtain.Name); // %count% + %name%
if (obtain.Image > 0)
AddItem(350, offset, obtain.Image, obtain.Hue); // Image
offset += 16;
if (m_Offer)
{
if (obtain.Timed)
{
AddHtmlLocalized(103, offset, 120, 16, 1062379, 0x15F90, false, false); // Est. time remaining:
AddLabel(223, offset, 0x481, FormatSeconds(obtain.Seconds)); // %est. time remaining%
offset += 16;
}
else if (obtain.Image > 0)
offset += 16;
continue;
}
AddHtmlLocalized(103, offset, 120, 16, 3000087, 0x15F90, false, false); // Total
AddLabel(223, offset, 0x481, obtain.CurProgress.ToString()); // %current progress%
offset += 16;
if (ReturnTo() != null)
{
AddHtmlLocalized(103, offset, 120, 16, 1074782, 0x15F90, false, false); // Return to
AddLabel(223, offset, 0x481, ReturnTo()); // %return to%
offset += 16;
}
if (obtain.Timed)
{
AddHtmlLocalized(103, offset, 120, 16, 1062379, 0x15F90, false, false); // Est. time remaining:
AddLabel(223, offset, 0x481, FormatSeconds(obtain.Seconds)); // %est. time remaining%
offset += 16;
}
}
}
else if (objective is DeliverObjective)
{
DeliverObjective deliver = (DeliverObjective)objective;
if (deliver != null)
{
AddHtmlLocalized(98, offset, 40, 16, 1072207, 0x15F90, false, false); // Deliver
AddLabel(143, offset, 0x481, deliver.MaxProgress + " " + deliver.DeliveryName); // %name%
offset += 16;
AddHtmlLocalized(103, offset, 120, 16, 1072379, 0x15F90, false, false); // Deliver to
AddLabel(223, offset, 0x481, deliver.DestName); // %deliver to%
offset += 16;
if (deliver.Timed)
{
AddHtmlLocalized(103, offset, 120, 16, 1062379, 0x15F90, false, false); // Est. time remaining:
AddLabel(223, offset, 0x481, FormatSeconds(deliver.Seconds)); // %est. time remaining%
offset += 16;
}
}
}
else if (objective is EscortObjective)
{
EscortObjective escort = (EscortObjective)objective;
if (escort != null)
{
AddHtmlLocalized(98, offset, 312, 16, 1072206, 0x15F90, false, false); // Escort to
if (escort.Label == 0)
{
AddHtmlObject(173, offset, 200, 16, escort.Region.Name, White, false, false);
}
else
{
AddHtmlLocalized(173, offset, 200, 16, escort.Label, 0xFFFFFF, false, false);
}
offset += 16;
if (escort.Timed)
{
AddHtmlLocalized(103, offset, 120, 16, 1062379, 0x15F90, false, false); // Est. time remaining:
AddLabel(223, offset, 0x481, FormatSeconds(escort.Seconds)); // %est. time remaining%
offset += 16;
}
}
}
else if (objective is ApprenticeObjective)
{
ApprenticeObjective apprentice = (ApprenticeObjective)objective;
if (apprentice != null)
{
AddHtmlLocalized(98, offset, 200, 16, 1077485, "#" + (1044060 + (int)apprentice.Skill) + "\t" + apprentice.MaxProgress, 0x15F90, false, false); // Increase ~1_SKILL~ to ~2_VALUE~
offset += 16;
}
}
else if (objective is SimpleObjective && ((SimpleObjective)objective).Descriptions != null)
{
SimpleObjective obj = (SimpleObjective)objective;
for (int j = 0; j < obj.Descriptions.Count; j++)
{
offset += 16;
AddLabel(98, offset, 0x481, obj.Descriptions[j]);
}
if (obj.Timed)
{
offset += 16;
AddHtmlLocalized(103, offset, 120, 16, 1062379, 0x15F90, false, false); // Est. time remaining:
AddLabel(223, offset, 0x481, FormatSeconds(obj.Seconds)); // %est. time remaining%
}
}
else if (objective.ObjectiveDescription != null)
{
if (objective.ObjectiveDescription is int)
{
AddHtmlLocalized(98, offset, 310, 300, (int)objective.ObjectiveDescription, 0x15F90, false, false);
}
else if (objective.ObjectiveDescription is string)
{
AddHtmlObject(98, offset, 310, 300, (string)objective.ObjectiveDescription, LightGreen, false, false);
}
}
}
AddButton(130, 430, 0x2EEF, 0x2EF1, (int)Buttons.PreviousPage, GumpButtonType.Reply, 0);
AddButton(275, 430, 0x2EE9, 0x2EEB, (int)Buttons.NextPage, GumpButtonType.Reply, 0);
}
}
public virtual void SecRewards()
{
if (m_Quest == null)
return;
if (m_Offer)
AddHtmlLocalized(130, 45, 270, 16, 1049010, 0xFFFFFF, false, false); // Quest Offer
else
AddHtmlLocalized(130, 45, 270, 16, 1046026, 0xFFFFFF, false, false); // Quest Log
AddHtmlObject(160, 70, 200, 40, m_Quest.Title, DarkGreen, false, false);
AddHtmlLocalized(98, 140, 312, 16, 1072201, 0x2710, false, false); // Reward
int offset = 163;
for (int i = 0; i < m_Quest.Rewards.Count; i++)
{
BaseReward reward = m_Quest.Rewards[i];
if (reward != null)
{
AddImage(105, offset, 0x4B9);
AddHtmlObject(133, offset, 280, m_Quest.Rewards.Count == 1 ? 100 : 16, reward.Name, LightGreen, false, false);
offset += 16;
}
}
if (m_Completed)
{
AddButton(95, 455, 0x2EE0, 0x2EE2, (int)Buttons.AcceptReward, GumpButtonType.Reply, 0);
if (m_Quest.CanRefuseReward)
AddButton(313, 430, 0x2EF2, 0x2EF4, (int)Buttons.RefuseReward, GumpButtonType.Reply, 0);
else
AddButton(313, 455, 0x2EE6, 0x2EE8, (int)Buttons.Close, GumpButtonType.Reply, 0);
}
else if (m_Offer)
{
AddButton(95, 455, 0x2EE0, 0x2EE2, (int)Buttons.AcceptQuest, GumpButtonType.Reply, 0);
AddButton(313, 455, 0x2EF2, 0x2EF4, (int)Buttons.RefuseQuest, GumpButtonType.Reply, 0);
AddButton(130, 430, 0x2EEF, 0x2EF1, (int)Buttons.PreviousPage, GumpButtonType.Reply, 0);
}
else
{
AddButton(95, 455, 0x2EF5, 0x2EF7, (int)Buttons.ResignQuest, GumpButtonType.Reply, 0);
AddButton(313, 455, 0x2EEC, 0x2EEE, (int)Buttons.CloseQuest, GumpButtonType.Reply, 0);
AddButton(130, 430, 0x2EEF, 0x2EF1, (int)Buttons.PreviousPage, GumpButtonType.Reply, 0);
}
}
public virtual void SecRefuse()
{
if (m_Quest == null)
return;
if (m_Offer)
{
AddHtmlLocalized(130, 45, 270, 16, 3006156, 0xFFFFFF, false, false); // Quest Conversation
AddImage(140, 110, 0x4B9);
AddHtmlObject(160, 70, 200, 40, m_Quest.Title, DarkGreen, false, false);
AddHtmlObject(98, 140, 312, 180, m_Quest.Refuse, LightGreen, false, true);
AddButton(313, 455, 0x2EE6, 0x2EE8, (int)Buttons.Close, GumpButtonType.Reply, 0);
}
}
public virtual void SecInProgress()
{
if (m_Quest == null)
return;
AddHtmlLocalized(130, 45, 270, 16, 3006156, 0xFFFFFF, false, false); // Quest Conversation
AddImage(140, 110, 0x4B9);
AddHtmlObject(160, 70, 200, 40, m_Quest.Title, DarkGreen, false, false);
AddHtmlObject(98, 140, 312, 180, m_Quest.Uncomplete, LightGreen, false, true);
AddButton(313, 455, 0x2EE6, 0x2EE8, (int)Buttons.Close, GumpButtonType.Reply, 0);
}
public virtual void SecComplete()
{
if (m_Quest == null)
return;
if (m_Quest.Complete == null)
{
if (QuestHelper.TryDeleteItems(m_Quest))
{
if (QuestHelper.AnyRewards(m_Quest))
{
m_Section = Section.Rewards;
SecRewards();
}
else
m_Quest.GiveRewards();
}
return;
}
AddHtmlLocalized(130, 45, 270, 16, 3006156, 0xFFFFFF, false, false); // Quest Conversation
AddImage(140, 110, 0x4B9);
AddHtmlObject(160, 70, 200, 40, m_Quest.Title, DarkGreen, false, false);
AddHtmlObject(98, 140, 312, 180, m_Quest.Complete, LightGreen, false, true);
AddButton(313, 455, 0x2EE6, 0x2EE8, (int)Buttons.Close, GumpButtonType.Reply, 0);
AddButton(95, 455, 0x2EE9, 0x2EEB, (int)Buttons.Complete, GumpButtonType.Reply, 0);
}
public virtual void SecFailed()
{
if (m_Quest == null)
return;
object fail = m_Quest.FailedMsg;
if (fail == null)
fail = "You have failed to meet the conditions of the quest.";
AddHtmlLocalized(130, 45, 270, 16, 3006156, 0xFFFFFF, false, false); // Quest Conversation
AddImage(140, 110, 0x4B9);
AddHtmlObject(160, 70, 200, 40, m_Quest.Title, DarkGreen, false, false);
AddHtmlObject(98, 140, 312, 240, fail, LightGreen, false, true);
AddButton(313, 455, 0x2EE6, 0x2EE8, (int)Buttons.Close, GumpButtonType.Reply, 0);
}
public virtual string FormatSeconds(int seconds)
{
int hours = seconds / 3600;
seconds -= hours * 3600;
int minutes = seconds / 60;
seconds -= minutes * 60;
if (hours > 0 && minutes > 0)
return hours + ":" + minutes + ":" + seconds;
else if (minutes > 0)
return minutes + ":" + seconds;
else
return seconds.ToString();
}
public virtual string ReturnTo()
{
if (m_Quest == null)
return null;
if (m_Quest.StartingMobile != null)
{
string returnTo = m_Quest.StartingMobile.Name;
if (m_Quest.StartingMobile.Region != null)
returnTo = String.Format("{0} ({1})", returnTo, m_Quest.StartingMobile.Region.Name);
else
returnTo = String.Format("{0}", returnTo);
return returnTo;
}
return null;
}
public override void OnResponse(Server.Network.NetState state, RelayInfo info)
{
if (m_From != null)
m_From.CloseGump(typeof(MondainQuestGump));
switch ( info.ButtonID )
{
// close quest list
case (int)Buttons.Close:
break;
// close quest
case (int)Buttons.CloseQuest:
m_From.SendGump(new MondainQuestGump(m_From));
break;
// accept quest
case (int)Buttons.AcceptQuest:
if (m_Offer)
m_Quest.OnAccept();
break;
// refuse quest
case (int)Buttons.RefuseQuest:
if (m_Offer)
{
m_Quest.OnRefuse();
m_From.SendGump(new MondainQuestGump(m_Quest, Section.Refuse, true));
}
break;
// resign quest
case (int)Buttons.ResignQuest:
if (!m_Offer)
m_From.SendGump(new MondainResignGump(m_Quest));
break;
// accept reward
case (int)Buttons.AcceptReward:
if (!m_Offer && m_Section == Section.Rewards && m_Completed)
m_Quest.GiveRewards();
break;
// refuse reward
case (int)Buttons.RefuseReward:
if (!m_Offer && m_Section == Section.Rewards && m_Completed)
m_Quest.RefuseRewards();
break;
// previous page
case (int)Buttons.PreviousPage:
if (m_Section == Section.Objectives || (m_Section == Section.Rewards && !m_Completed))
{
m_Section = (Section)((int)m_Section - 1);
m_From.SendGump(new MondainQuestGump(m_Quest, m_Section, m_Offer));
}
break;
// next page
case (int)Buttons.NextPage:
if (m_Section == Section.Description || m_Section == Section.Objectives)
{
m_Section = (Section)((int)m_Section + 1);
m_From.SendGump(new MondainQuestGump(m_Quest, m_Section, m_Offer));
}
break;
// player complete quest
case (int)Buttons.Complete:
if (!m_Offer && m_Section == Section.Complete)
{
if (!m_Quest.Completed)
m_From.SendLocalizedMessage(1074861); // You do not have everything you need!
else
{
if (QuestHelper.TryDeleteItems(m_Quest))
{
if (m_Quester != null)
m_Quest.Quester = m_Quester;
if (!QuestHelper.AnyRewards(m_Quest))
m_Quest.GiveRewards();
else
m_From.SendGump(new MondainQuestGump(m_Quest, Section.Rewards, false, true));
}
else
{
m_From.SendLocalizedMessage(1074861); // You do not have everything you need!
}
}
}
break;
// admin complete quest
case (int)Buttons.CompleteQuest:
if ((int)m_From.AccessLevel > (int)AccessLevel.Counselor && m_Quest != null)
QuestHelper.CompleteQuest(m_From, m_Quest);
break;
// show quest
default:
if (m_Section != Section.Main || info.ButtonID >= m_From.Quests.Count + ButtonOffset || info.ButtonID < ButtonOffset)
break;
m_From.SendGump(new MondainQuestGump(m_From.Quests[(int)info.ButtonID - ButtonOffset], Section.Description, false));
break;
}
}
}
}

View File

@@ -0,0 +1,91 @@
using System;
using Server.Gumps;
namespace Server.Engines.Quests
{
public class MondainResignGump : Gump
{
private readonly BaseQuest m_Quest;
public MondainResignGump(BaseQuest quest)
: base(120, 50)
{
if (quest == null)
return;
this.m_Quest = quest;
this.Closable = false;
this.Disposable = true;
this.Dragable = true;
this.Resizable = false;
this.AddPage(0);
this.AddImageTiled(0, 0, 348, 262, 0xA8E);
this.AddAlphaRegion(0, 0, 348, 262);
this.AddImage(0, 15, 0x27A8);
this.AddImageTiled(0, 30, 17, 200, 0x27A7);
this.AddImage(0, 230, 0x27AA);
this.AddImage(15, 0, 0x280C);
this.AddImageTiled(30, 0, 300, 17, 0x280A);
this.AddImage(315, 0, 0x280E);
this.AddImage(15, 244, 0x280C);
this.AddImageTiled(30, 244, 300, 17, 0x280A);
this.AddImage(315, 244, 0x280E);
this.AddImage(330, 15, 0x27A8);
this.AddImageTiled(330, 30, 17, 200, 0x27A7);
this.AddImage(330, 230, 0x27AA);
this.AddImage(333, 2, 0x2716);
this.AddImage(333, 248, 0x2716);
this.AddImage(2, 248, 0x216);
this.AddImage(2, 2, 0x2716);
this.AddHtmlLocalized(25, 22, 200, 20, 1049000, 0x7D00, false, false); // Confirm Quest Cancellation
this.AddImage(25, 40, 0xBBF);
this.AddHtmlLocalized(25, 55, 300, 120, 1060836, 0xFFFFFF, false, false); // This quest will give you valuable information, skills and equipment that will help you advance in the game at a quicker pace.<BR><BR>Are you certain you wish to cancel at this time?
if (quest.ChainID != QuestChain.None)
{
this.AddRadio(25, 145, 0x25F8, 0x25FB, false, (int)Radios.Chain);
this.AddHtmlLocalized(60, 150, 280, 20, 1075023, 0xFFFFFF, false, false); // Yes, I want to quit this entire chain!
}
this.AddRadio(25, 180, 0x25F8, 0x25FB, true, (int)Radios.Quest);
this.AddHtmlLocalized(60, 185, 280, 20, 1049005, 0xFFFFFF, false, false); // Yes, I really want to quit this quest!
this.AddRadio(25, 215, 0x25F8, 0x25FB, false, (int)Radios.None);
this.AddHtmlLocalized(60, 220, 280, 20, 1049006, 0xFFFFFF, false, false); // No, I don't want to quit.
this.AddButton(265, 220, 0xF7, 0xF8, (int)Buttons.Okay, GumpButtonType.Reply, 0); // okay
}
private enum Buttons
{
Close,
Okay,
}
private enum Radios
{
Chain,
Quest,
None,
}
public override void OnResponse(Server.Network.NetState state, RelayInfo info)
{
if (info.ButtonID != (int)Buttons.Okay || this.m_Quest == null)
return;
if (this.m_Quest.ChainID != QuestChain.None && info.IsSwitched((int)Radios.Chain))
{
this.m_Quest.OnResign(true);
}
if (info.IsSwitched((int)Radios.Quest))
{
this.m_Quest.OnResign(false);
}
if (info.IsSwitched((int)Radios.None) && this.m_Quest.Owner != null)
this.m_Quest.Owner.SendGump(new MondainQuestGump(this.m_Quest.Owner));
}
}
}

View File

@@ -0,0 +1,93 @@
using System;
using Server.Commands;
using Server.Network;
using Server.Engines.Quests;
using System.Collections.Generic;
using Server.Items;
namespace Server.Gumps
{
public class QAndAGump : Gump
{
private const int FontColor = 0x000008;
private Mobile m_From;
private QuestionAndAnswerObjective m_Objective;
private BaseQuest m_Quest;
private int m_Index;
public QAndAGump(Mobile owner, BaseQuest quest) : base(0, 0)
{
m_From = owner;
m_Quest = quest;
Closable = false;
Disposable = false;
foreach (BaseObjective objective in quest.Objectives)
{
if (objective is QuestionAndAnswerObjective)
{
m_Objective = (QuestionAndAnswerObjective)objective;
break;
}
}
if (m_Objective == null)
return;
QuestionAndAnswerEntry entry = m_Objective.GetRandomQandA();
if (entry == null)
return;
AddPage(0);
AddImage(0, 0, 1228);
AddImage(40, 78, 95);
AddImageTiled(49, 87, 301, 3, 96);
AddImage(350, 78, 97);
object answer = entry.Answers[Utility.Random(entry.Answers.Length)];
List<object> selections = new List<object>(entry.WrongAnswers);
m_Index = Utility.Random(selections.Count); //Gets correct answer
selections.Insert(m_Index, answer);
AddHtmlLocalized(40, 40, 320, 40, entry.Question, FontColor, false, false); //question
for (int i = 0; i < selections.Count; i++)
{
object selection = selections[i];
AddButton(49, 104 + (i * 40), 2224, 2224, selection == answer ? 1 : 0, GumpButtonType.Reply, 0);
if (selection is int)
AddHtmlLocalized(80, 102 + (i * 40), 200, 18, (int)selection, 0x0, false, false);
else
AddHtml(80, 102 + (i * 40), 200, 18, String.Format( "<BASEFONT COLOR=#{0:X6}>{1}</BASEFONT>", FontColor, selection), false, false);
}
}
public override void OnResponse(NetState state, RelayInfo info)
{
if (info.ButtonID == 1) //correct answer
{
m_Objective.Update(null);
if (m_Quest.Completed)
{
m_Quest.OnCompleted();
m_From.SendGump(new MondainQuestGump(m_Quest, MondainQuestGump.Section.Complete, false, true));
}
else
{
m_From.SendGump(new QAndAGump(m_From, m_Quest));
}
}
else
{
m_From.SendGump(new MondainQuestGump(m_Quest, MondainQuestGump.Section.Failed, false, true));
m_Quest.OnResign(false);
}
}
}
}

View File

@@ -0,0 +1,101 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Items;
namespace Server.Engines.Quests
{
public sealed class HeritagePacket : Packet
{
public static readonly Packet Close = Packet.SetStatic(new HeritagePacket(false, 0xFF));
public HeritagePacket(bool female, short type)
: base(0xBF)
{
this.EnsureCapacity(7);
this.m_Stream.Write((short)0x2A);
this.m_Stream.Write((byte)(female ? 1 : 0));
this.m_Stream.Write((byte)type);
}
}
public class PacketOverrides
{
public static void Initialize()
{
Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Override));
}
public static void Override()
{
PacketHandlers.RegisterEncoded(0x32, true, new OnEncodedPacketReceive(QuestButton));
PacketHandlers.RegisterExtended(0x2A, true, new OnPacketReceive(HeritageTransform));
}
public static void QuestButton(NetState state, IEntity e, EncodedReader reader)
{
if (state.Mobile is PlayerMobile)
{
PlayerMobile from = (PlayerMobile)state.Mobile;
from.CloseGump(typeof(MondainQuestGump));
from.SendGump(new MondainQuestGump(from));
}
}
public static void HeritageTransform(NetState state, PacketReader reader)
{
Mobile m = state.Mobile;
if (reader.Size == 5)
{
m.SendLocalizedMessage(1073645); // You may try this again later...
}
else if (reader.Size == 15 && HeritageQuester.Check(m))
{
bool proceed = false;
if (HeritageQuester.IsPending(m))
{
proceed = true;
HeritageQuester quester = HeritageQuester.Pending(m);
m.Race = quester.Race;
quester.CheckCompleted(m, true); // removes done quests
if (m.Race == Race.Elf)
m.SendLocalizedMessage(1073653); // You are now fully initiated into the Elven culture.
else if (m.Race == Race.Human)
m.SendLocalizedMessage(1073654); // You are now fully human.
}
else if (RaceChangeToken.IsPending(m))
{
var race = RaceChangeToken.GetPendingRace(m);
if (race != null)
{
m.Race = race;
proceed = true;
m.SendLocalizedMessage(1111914); // You have successfully changed your race.
RaceChangeToken.OnRaceChange(m);
}
}
if(proceed)
{
m.Hue = reader.ReadUInt16();
m.HairItemID = reader.ReadUInt16();
m.HairHue = reader.ReadUInt16();
m.FacialHairItemID = reader.ReadUInt16();
m.FacialHairHue = reader.ReadUInt16();
}
}
HeritageQuester.RemovePending(m);
RaceChangeToken.RemovePending(m);
}
}
}

View File

@@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.IO;
using Server;
using Server.Mobiles;
namespace Server.Engines.Quests
{
public static class MondainQuestData
{
public static string FilePath = Path.Combine("Saves/Quests", "MLQuests.bin");
public static Dictionary<PlayerMobile, List<BaseQuest>> QuestData { get; set; }
public static Dictionary<PlayerMobile, Dictionary<QuestChain, BaseChain>> ChainData { get; set; }
public static List<BaseQuest> GetQuests(PlayerMobile pm)
{
if (!QuestData.ContainsKey(pm))
{
QuestData[pm] = new List<BaseQuest>();
}
return QuestData[pm];
}
public static Dictionary<QuestChain, BaseChain> GetChains(PlayerMobile pm)
{
if (!ChainData.ContainsKey(pm))
{
ChainData[pm] = new Dictionary<QuestChain, BaseChain>();
}
return ChainData[pm];
}
public static void AddQuest(PlayerMobile pm, BaseQuest q)
{
if (!QuestData.ContainsKey(pm) || QuestData[pm] == null)
QuestData[pm] = new List<BaseQuest>();
QuestData[pm].Add(q);
}
public static void AddChain(PlayerMobile pm, QuestChain id, BaseChain chain)
{
if (pm == null)
return;
if (!ChainData.ContainsKey(pm) || ChainData[pm] == null)
ChainData[pm] = new Dictionary<QuestChain, BaseChain>();
ChainData[pm].Add(id, chain);
}
public static void RemoveQuest(PlayerMobile pm, BaseQuest quest)
{
if (QuestData.ContainsKey(pm) && QuestData[pm].Contains(quest))
{
QuestData[pm].Remove(quest);
if (QuestData[pm].Count == 0)
QuestData.Remove(pm);
}
}
public static void RemoveChain(PlayerMobile pm, QuestChain chain)
{
if (ChainData.ContainsKey(pm) && ChainData[pm].ContainsKey(chain))
{
ChainData[pm].Remove(chain);
if(ChainData[pm].Count == 0)
ChainData.Remove(pm);
}
}
public static void Configure()
{
EventSink.WorldSave += OnSave;
EventSink.WorldLoad += OnLoad;
QuestData = new Dictionary<PlayerMobile, List<BaseQuest>>();
ChainData = new Dictionary<PlayerMobile, Dictionary<QuestChain, BaseChain>>();
}
public static void OnSave(WorldSaveEventArgs e)
{
Persistence.Serialize(
FilePath,
writer =>
{
writer.Write(0);
writer.Write(QuestData.Count);
foreach (var kvp in QuestData)
{
writer.Write(kvp.Key);
QuestWriter.Quests(writer, kvp.Value);
}
writer.Write(ChainData.Count);
foreach (var kvp in ChainData)
{
writer.Write(kvp.Key);
QuestWriter.Chains(writer, kvp.Value);
}
TierQuestInfo.Save(writer);
});
}
public static void OnLoad()
{
Persistence.Deserialize(
FilePath,
reader =>
{
int version = reader.ReadInt();
int count = reader.ReadInt();
for (int i = 0; i < count; i++)
{
PlayerMobile pm = reader.ReadMobile() as PlayerMobile;
List<BaseQuest> quests = QuestReader.Quests(reader, pm);
if (pm != null)
QuestData[pm] = quests;
}
count = reader.ReadInt();
for (int i = 0; i < count; i++)
{
PlayerMobile pm = reader.ReadMobile() as PlayerMobile;
Dictionary<QuestChain, BaseChain> dic = QuestReader.Chains(reader);
if (pm != null)
ChainData[pm] = dic;
}
TierQuestInfo.Load(reader);
});
}
}
}

View File

@@ -0,0 +1,966 @@
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));
}
}
}
}

View File

@@ -0,0 +1,204 @@
#region References
using System;
using System.Collections.Generic;
using System.IO;
using Server.Mobiles;
#endregion
namespace Server.Engines.Quests
{
public class QuestReader
{
public static int Version(GenericReader reader)
{
if (reader == null)
{
return -1;
}
if (reader.PeekInt() == 0x7FFFFFFF)
{
reader.ReadInt(); // Preamble 0x7FFFFFFF
return reader.ReadInt();
}
return -1;
}
public static bool SubRead(GenericReader reader, Action<GenericReader> deserializer)
{
if (reader == null)
{
return false;
}
using (var s = new MemoryStream())
{
var length = reader.ReadLong();
while (s.Length < length)
{
s.WriteByte(reader.ReadByte());
}
if (deserializer != null)
{
s.Position = 0;
var r = new BinaryFileReader(new BinaryReader(s));
try
{
deserializer(r);
}
catch (Exception e)
{
Console.WriteLine("Quest Load Failure: {0}", Utility.FormatDelegate(deserializer));
Console.WriteLine(e);
return false;
}
finally
{
r.Close();
}
}
}
return true;
}
public static List<BaseQuest> Quests(GenericReader reader, PlayerMobile player)
{
var quests = new List<BaseQuest>();
if (reader == null)
{
return quests;
}
var version = Version(reader);
var count = reader.ReadInt();
for (var i = 0; i < count; i++)
{
var quest = Construct(reader) as BaseQuest;
if (quest == null)
{
if (version >= 0)
{
SubRead(reader, null);
}
continue;
}
quest.Owner = player;
if (version < 0)
{
quest.Deserialize(reader);
}
else if (!SubRead(reader, quest.Deserialize))
{
continue;
}
quests.Add(quest);
}
return quests;
}
public static Dictionary<QuestChain, BaseChain> Chains(GenericReader reader)
{
var chains = new Dictionary<QuestChain, BaseChain>();
if (reader == null)
{
return chains;
}
Version(reader);
var count = reader.ReadInt();
for (var i = 0; i < count; i++)
{
var chain = reader.ReadInt();
var quest = Type(reader);
var quester = Type(reader);
if (Enum.IsDefined(typeof(QuestChain), chain) && quest != null && quester != null)
{
chains[(QuestChain)chain] = new BaseChain(quest, quester);
}
}
return chains;
}
public static object Object(GenericReader reader)
{
if (reader == null)
{
return null;
}
Version(reader);
var type = reader.ReadByte();
switch (type)
{
case 0x0:
return null; // invalid
case 0x1:
return reader.ReadInt();
case 0x2:
return reader.ReadString();
case 0x3:
return reader.ReadItem();
case 0x4:
return reader.ReadMobile();
}
return null;
}
public static Type Type(GenericReader reader)
{
if (reader == null)
{
return null;
}
var type = reader.ReadString();
if (type != null)
{
return ScriptCompiler.FindTypeByFullName(type, false);
}
return null;
}
public static object Construct(GenericReader reader)
{
var type = Type(reader);
try
{
return Activator.CreateInstance(type);
}
catch
{
return null;
}
}
}
}

View File

@@ -0,0 +1,161 @@
#region References
using System;
using System.Collections.Generic;
using System.IO;
#endregion
namespace Server.Engines.Quests
{
public class QuestWriter
{
public static int Version(GenericWriter writer, int version)
{
if (writer == null)
{
return -1;
}
writer.Write(0x7FFFFFFF); // Preamble
writer.Write(version);
return version;
}
public static bool SubWrite(GenericWriter writer, Action<GenericWriter> serializer)
{
if (writer == null)
{
return false;
}
using (var s = new MemoryStream())
{
var w = new BinaryFileWriter(s, true);
try
{
serializer(w);
}
catch (Exception e)
{
Console.WriteLine("Quest Save Failure: {0}", Utility.FormatDelegate(serializer));
Console.WriteLine(e);
writer.Write(0L);
return false;
}
finally
{
w.Flush();
}
writer.Write(s.Length);
s.Position = 0;
while (s.Position < s.Length)
{
writer.Write((byte)s.ReadByte());
}
}
return true;
}
public static void Quests(GenericWriter writer, List<BaseQuest> quests)
{
if (writer == null)
{
return;
}
Version(writer, 0);
if (quests == null)
{
writer.Write(0);
return;
}
writer.Write(quests.Count);
foreach (var quest in quests)
{
Type(writer, quest.GetType());
SubWrite(writer, quest.Serialize);
}
}
public static void Chains(GenericWriter writer, Dictionary<QuestChain, BaseChain> chains)
{
if (writer == null)
{
return;
}
Version(writer, 0);
if (chains == null)
{
writer.Write(0);
return;
}
writer.Write(chains.Count);
foreach (var pair in chains)
{
writer.Write((int)pair.Key);
Type(writer, pair.Value.CurrentQuest);
Type(writer, pair.Value.Quester);
}
}
public static void Object(GenericWriter writer, object obj)
{
if (writer == null)
{
return;
}
Version(writer, 0);
if (obj is int)
{
writer.Write((byte)0x1);
writer.Write((int)obj);
}
else if (obj is String)
{
writer.Write((byte)0x2);
writer.Write((String)obj);
}
else if (obj is Item)
{
writer.Write((byte)0x3);
writer.Write((Item)obj);
}
else if (obj is Mobile)
{
writer.Write((byte)0x4);
writer.Write((Mobile)obj);
}
else
{
writer.Write((byte)0x0); // invalid
}
}
public static void Type(GenericWriter writer, Type type)
{
if (writer != null)
{
writer.Write(type == null ? null : type.FullName);
}
}
}
}

View File

@@ -0,0 +1,379 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Server.Mobiles;
using Server.Spells.Fifth;
namespace Server.Engines.Quests
{
public class HeritageQuestInfo
{
private readonly Type m_Quest;
private readonly object m_Title;
public Type Quest
{
get
{
return this.m_Quest;
}
}
public object Title
{
get
{
return this.m_Title;
}
}
public HeritageQuestInfo(Type quest, object title)
{
this.m_Quest = quest;
this.m_Title = title;
}
public bool Check(PlayerMobile player)
{
return this.Check(player, false);
}
public bool Check(PlayerMobile player, bool delete)
{
int j = 0;
while (j < player.DoneQuests.Count && player.DoneQuests[j].QuestType != this.m_Quest)
{
//if(player.Murderer && this.m_Quest == typeof(ResponsibilityQuest) && player.DoneQuests[j].QuestType.IsSubclassOf(typeof(
j += 1;
}
if (j == player.DoneQuests.Count)
return false;
else if (delete)
player.DoneQuests.RemoveAt(j);
return true;
}
}
public abstract class HeritageQuester : BaseVendor
{
#region Vendor stuff
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
protected override List<SBInfo> SBInfos
{
get
{
return this.m_SBInfos;
}
}
public override bool IsActiveVendor
{
get
{
return false;
}
}
public override void InitSBInfo()
{
}
#endregion
public virtual int AutoSpeakRange
{
get
{
return 7;
}
}
public virtual object ConfirmMessage
{
get
{
return 0;
}
}
public virtual object IncompleteMessage
{
get
{
return 0;
}
}
private List<HeritageQuestInfo> m_Quests;
private List<object> m_Objectives;
private List<object> m_Story;
private bool m_Busy;
private int m_Index;
public List<HeritageQuestInfo> Quests
{
get
{
return this.m_Quests;
}
}
public List<object> Objectives
{
get
{
return this.m_Objectives;
}
}
public List<object> Story
{
get
{
return this.m_Story;
}
}
public HeritageQuester()
: this(null)
{
}
public HeritageQuester(string name)
: this(name, null)
{
}
public HeritageQuester(string name, string title)
: base(title)
{
this.m_Quests = new List<HeritageQuestInfo>();
this.m_Objectives = new List<object>();
this.m_Story = new List<object>();
this.Initialize();
this.Name = name;
this.SpeechHue = 0x3B2;
}
public HeritageQuester(Serial serial)
: base(serial)
{
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (m.Alive && !m.Hidden && m is PlayerMobile)
{
int range = this.AutoSpeakRange;
if (range >= 0 && this.InRange(m, range) && !this.InRange(oldLocation, range))
this.OnTalk(m);
}
}
public override void OnDoubleClick(Mobile m)
{
Console.WriteLine(m.Items.Count);
if (m.Alive)
this.OnTalk(m);
}
public virtual void OnTalk(Mobile m)
{
if (m.Hidden || this.m_Busy || m.Race == this.Race)
{
m.SendLocalizedMessage(1074017); // He's too busy right now, so he ignores you.
return;
}
this.m_Busy = true;
this.m_Index = 0;
this.SpeechHue = Utility.RandomDyedHue();
this.Say(m.Name);
this.SpeechHue = 0x3B2;
if (this.CheckCompleted(m))
Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(10), this.Story.Count + 1, new TimerStateCallback(SayStory), m);
else
{
List<object> incomplete = this.FindIncompleted(m);
TimeSpan delay = TimeSpan.FromSeconds(2);
if (incomplete.Count == this.m_Quests.Count + 1)
{
incomplete = this.m_Objectives;
delay = TimeSpan.FromSeconds(10);
}
Timer.DelayCall(TimeSpan.Zero, delay, incomplete.Count, new TimerStateCallback(SayInstructions), incomplete);
}
}
public bool CheckCompleted(Mobile m)
{
return this.CheckCompleted(m, false);
}
public bool CheckCompleted(Mobile m, bool delete)
{
for (int i = 0; i < this.m_Quests.Count; i += 1)
{
HeritageQuestInfo info = this.m_Quests[i];
if (!info.Check((PlayerMobile)m, delete))
return false;
}
return true;
}
public List<object> FindIncompleted(Mobile m)
{
List<object> incomplete = new List<object>();
incomplete.Add(this.IncompleteMessage);
for (int i = 0; i < this.m_Quests.Count; i += 1)
{
HeritageQuestInfo info = this.m_Quests[i];
if (!info.Check((PlayerMobile)m))
incomplete.Add(info.Title);
}
return incomplete;
}
private void SayInstructions(object args)
{
if (args is List<object>)
this.SayInstructions((List<object>)args);
}
public void SayInstructions(List<object> incomplete)
{
Say(this, incomplete[this.m_Index]);
this.m_Index += 1;
if (this.m_Index == incomplete.Count)
this.m_Busy = false;
}
private void SayStory(object args)
{
if (args is Mobile)
this.SayStory((Mobile)args);
}
public void SayStory(Mobile m)
{
if (this.m_Index < this.m_Story.Count)
Say(this, this.m_Story[this.m_Index]);
else
{
this.m_Busy = false;
m.CloseGump(typeof(ConfirmHeritageGump));
m.SendGump(new ConfirmHeritageGump(this));
}
this.m_Index += 1;
}
#region Static
private static readonly Dictionary<Mobile, HeritageQuester> m_Pending = new Dictionary<Mobile, HeritageQuester>();
public static void AddPending(Mobile m, HeritageQuester quester)
{
m_Pending[m] = quester;
}
public static void RemovePending(Mobile m)
{
if (m_Pending.ContainsKey(m))
{
m_Pending.Remove(m);
}
}
public static bool IsPending(Mobile m)
{
return m_Pending.ContainsKey(m) && m_Pending[m] != null;
}
public static HeritageQuester Pending(Mobile m)
{
return m_Pending.ContainsKey(m) ? m_Pending[m] as HeritageQuester : null;
}
public static void Say(Mobile m, object message)
{
if (message is int)
m.Say((int)message);
else if (message is string)
m.Say((string)message);
}
public static bool Check(Mobile m)
{
if (!m.Alive)
m.SendLocalizedMessage(1073646); // Only the living may proceed...
else if (m.Mounted)
m.SendLocalizedMessage(1073647); // You may not continue while mounted...
else if (m.IsBodyMod || m.HueMod > 0 || !m.CanBeginAction(typeof(IncognitoSpell)))
m.SendLocalizedMessage(1073648); // You may only proceed while in your original state...
else if (m.Spell != null && m.Spell.IsCasting)
m.SendLocalizedMessage(1073649); // One may not proceed while embracing magic...
else if (IsUnburdened(m))
m.SendLocalizedMessage(1073650); // To proceed you must be unburdened by equipment...
else if (!m.NetState.SupportsExpansion(Expansion.ML))
m.SendLocalizedMessage(1073651); // You must have Mondain's Legacy before proceeding...
else if (m.Hits < m.HitsMax)
m.SendLocalizedMessage(1073652); // You must be healthy to proceed...
else
return true;
return false;
}
public static bool IsUnburdened(Mobile m)
{
int count = m.Items.Count - 1;
if (m.Backpack != null)
count -= 1;
return count > 0;
}
#endregion
public virtual void Initialize()
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
this.m_Quests = new List<HeritageQuestInfo>();
this.m_Objectives = new List<object>();
this.m_Story = new List<object>();
this.Initialize();
}
}
}

View File

@@ -0,0 +1,234 @@
using System;
using System.Collections.Generic;
using Server.Mobiles;
namespace Server.Engines.Quests
{
public abstract class MondainQuester : BaseVendor
{
protected readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
private DateTime m_Spoken;
public MondainQuester()
: base(null)
{
SpeechHue = 0x3B2;
}
public MondainQuester(string name)
: this(name, null)
{
}
public MondainQuester(string name, string title)
: base(title)
{
Name = name;
SpeechHue = 0x3B2;
}
public MondainQuester(Serial serial)
: base(serial)
{
}
public override void CheckMorph()
{
// Don't morph me!
}
public override bool IsActiveVendor
{
get
{
return false;
}
}
public override bool IsInvulnerable
{
get
{
return true;
}
}
public override bool DisallowAllMoves
{
get
{
return false;
}
}
public override bool ClickTitle
{
get
{
return false;
}
}
public override bool CanTeach
{
get
{
return true;
}
}
public virtual int AutoTalkRange
{
get
{
return -1;
}
}
public virtual int AutoSpeakRange
{
get
{
return 10;
}
}
public virtual TimeSpan SpeakDelay
{
get
{
return TimeSpan.FromMinutes(1);
}
}
public abstract Type[] Quests { get; }
protected override List<SBInfo> SBInfos
{
get
{
return m_SBInfos;
}
}
public override void InitSBInfo()
{
}
public virtual void OnTalk(PlayerMobile player)
{
if (QuestHelper.DeliveryArrived(player, this))
return;
if (QuestHelper.InProgress(player, this))
return;
if (QuestHelper.QuestLimitReached(player))
return;
// check if this quester can offer any quest chain (already started)
foreach (KeyValuePair<QuestChain, BaseChain> pair in player.Chains)
{
BaseChain chain = pair.Value;
if (chain != null && chain.Quester != null && chain.Quester == GetType())
{
BaseQuest quest = QuestHelper.RandomQuest(player, new Type[] { chain.CurrentQuest }, this);
if (quest != null)
{
player.CloseGump(typeof(MondainQuestGump));
player.SendGump(new MondainQuestGump(quest));
return;
}
}
}
BaseQuest questt = QuestHelper.RandomQuest(player, Quests, this);
if (questt != null)
{
player.CloseGump(typeof(MondainQuestGump));
player.SendGump(new MondainQuestGump(questt));
}
}
public virtual void OnOfferFailed()
{
Say(1080107); // I'm sorry, I have nothing for you at this time.
}
public virtual void Advertise()
{
Say(Utility.RandomMinMax(1074183, 1074223));
}
public override bool CanBeDamaged()
{
return false;
}
public override void InitBody()
{
if (Race != null)
{
HairItemID = Race.RandomHair(Female);
HairHue = Race.RandomHairHue();
FacialHairItemID = Race.RandomFacialHair(Female);
FacialHairHue = Race.RandomHairHue();
Hue = Race.RandomSkinHue();
}
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (m.Alive && !m.Hidden && m is PlayerMobile)
{
PlayerMobile pm = (PlayerMobile)m;
int range = AutoTalkRange;
if (range >= 0 && InRange(m, range) && !InRange(oldLocation, range))
OnTalk(pm);
range = AutoSpeakRange;
if (InLOS(m) && range >= 0 && InRange(m, range) && !InRange(oldLocation, range) && DateTime.UtcNow >= m_Spoken + SpeakDelay)
{
if (Utility.Random(100) < 50)
Advertise();
m_Spoken = DateTime.UtcNow;
}
}
}
public override void OnDoubleClick(Mobile m)
{
if (m.Alive && m is PlayerMobile)
OnTalk((PlayerMobile)m);
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
list.Add(1072269); // Quest Giver
}
public void FocusTo(Mobile to)
{
QuestSystem.FocusTo(this, to);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
if (CantWalk)
Frozen = true;
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Spoken = DateTime.UtcNow;
if (CantWalk)
Frozen = true;
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
namespace Server.Engines.Quests
{
public class QuestionAndAnswerEntry
{
private int m_Question;
private object[] m_Answers;
private object[] m_WrongAnswers;
public int Question { get { return m_Question; } }
public object[] Answers { get { return m_Answers; } }
public object[] WrongAnswers { get { return m_WrongAnswers; } }
public QuestionAndAnswerEntry(int question, object[] answerText, object[] wrongAnswers)
{
m_Question = question;
m_Answers = answerText;
m_WrongAnswers = wrongAnswers;
}
}
}

View File

@@ -0,0 +1,92 @@
#region References
using System;
#endregion
namespace Server.Engines.Quests
{
public enum QuestChain
{
None = 0,
Aemaeth = 1,
AncientWorld = 2,
BlightedGrove = 3,
CovetousGhost = 4,
GemkeeperWarriors = 5,
HonestBeggar = 6,
LibraryFriends = 7,
Marauders = 8,
MiniBoss = 9,
SummonFey = 10,
SummonFiend = 11,
TuitionReimbursement = 12,
Spellweaving = 13,
SpellweavingS = 14,
UnfadingMemories = 15,
Empty = 16,
KingVernixQuests = 17,
DoughtyWarriors = 18,
HonorOfDeBoors = 19,
LaifemTheWeaver = 20,
CloakOfHumility = 21,
ValleyOfOne = 22,
MyrmidexAlliance = 23,
EodonianAlliance = 24,
FlintTheQuartermaster = 25,
AnimalTraining = 26,
PaladinsOfTrinsic = 27,
RightingWrong = 28,
Ritual = 29
}
public class BaseChain
{
public static Type[][] Chains { get; set; }
static BaseChain()
{
Chains = new Type[30][];
Chains[(int)QuestChain.None] = new Type[] { };
Chains[(int)QuestChain.Aemaeth] = new Type[] { typeof(AemaethOneQuest), typeof(AemaethTwoQuest) };
Chains[(int)QuestChain.AncientWorld] = new Type[] { typeof(TheAncientWorldQuest), typeof(TheGoldenHornQuest), typeof(BullishQuest), typeof(LostCivilizationQuest) };
Chains[(int)QuestChain.BlightedGrove] = new Type[] { typeof(VilePoisonQuest), typeof(RockAndHardPlaceQuest), typeof(SympatheticMagicQuest), typeof(AlreadyDeadQuest), typeof(EurekaQuest), typeof(SubContractingQuest) };
Chains[(int)QuestChain.CovetousGhost] = new Type[] { typeof(GhostOfCovetousQuest), typeof(SaveHisDadQuest), typeof(FathersGratitudeQuest) };
Chains[(int)QuestChain.GemkeeperWarriors] = new Type[] { typeof(WarriorsOfTheGemkeeperQuest), typeof(CloseEnoughQuest), typeof(TakingTheBullByTheHornsQuest), typeof(EmissaryToTheMinotaurQuest) };
Chains[(int)QuestChain.HonestBeggar] = new Type[] { typeof(HonestBeggarQuest), typeof(ReginasThanksQuest) };
Chains[(int)QuestChain.LibraryFriends] = new Type[] { typeof(FriendsOfTheLibraryQuest), typeof(BureaucraticDelayQuest), typeof(TheSecretIngredientQuest), typeof(SpecialDeliveryQuest), typeof(AccessToTheStacksQuest) };
Chains[(int)QuestChain.Marauders] = new Type[] { typeof(MaraudersQuest), typeof(TheBrainsOfTheOperationQuest), typeof(TheBrawnQuest), typeof(TheBiggerTheyAreQuest) };
Chains[(int)QuestChain.MiniBoss] = new Type[] { typeof(MougGuurMustDieQuest), typeof(LeaderOfThePackQuest), typeof(SayonaraSzavetraQuest) };
Chains[(int)QuestChain.SummonFey] = new Type[] { typeof(FirendOfTheFeyQuest), typeof(TokenOfFriendshipQuest), typeof(AllianceQuest) };
Chains[(int)QuestChain.SummonFiend] = new Type[] { typeof(FiendishFriendsQuest), typeof(CrackingTheWhipQuest), typeof(IronWillQuest) };
Chains[(int)QuestChain.TuitionReimbursement] = new Type[] { typeof(MistakenIdentityQuest), typeof(YouScratchMyBackQuest), typeof(FoolingAernyaQuest), typeof(NotQuiteThatEasyQuest), typeof(ConvinceMeQuest), typeof(TuitionReimbursementQuest) };
Chains[(int)QuestChain.Spellweaving] = new Type[] { typeof(PatienceQuest), typeof(NeedsOfManyHeartwoodQuest), typeof(NeedsOfManyPartHeartwoodQuest), typeof(MakingContributionHeartwoodQuest), typeof(UnnaturalCreationsQuest) };
Chains[(int)QuestChain.SpellweavingS] = new Type[] { typeof(DisciplineQuest), typeof(NeedsOfTheManySanctuaryQuest), typeof(MakingContributionSanctuaryQuest), typeof(SuppliesForSanctuaryQuest), typeof(TheHumanBlightQuest) };
Chains[(int)QuestChain.UnfadingMemories] = new Type[] { typeof(UnfadingMemoriesOneQuest), typeof(UnfadingMemoriesTwoQuest), typeof(UnfadingMemoriesThreeQuest) };
Chains[(int)QuestChain.Empty] = new Type[] { };
Chains[(int)QuestChain.KingVernixQuests] = new Type[] { };
Chains[(int)QuestChain.DoughtyWarriors] = new Type[] { typeof(DoughtyWarriorsQuest), typeof(DoughtyWarriors2Quest), typeof(DoughtyWarriors3Quest) };
Chains[(int)QuestChain.HonorOfDeBoors] = new Type[] { typeof(HonorOfDeBoorsQuest), typeof(JackTheVillainQuest), typeof(SavedHonorQuest) };
Chains[(int)QuestChain.LaifemTheWeaver] = new Type[] { typeof(ShearingKnowledgeQuest), typeof(WeavingFriendshipsQuest), typeof(NewSpinQuest), };
Chains[(int)QuestChain.CloakOfHumility] = new Type[] { typeof(TheQuestionsQuest), typeof(CommunityServiceMuseumQuest), typeof(CommunityServiceZooQuest), typeof(CommunityServiceLibraryQuest), typeof(WhosMostHumbleQuest)};
Chains[(int)QuestChain.ValleyOfOne] = new Type[] { typeof(TimeIsOfTheEssenceQuest), typeof(UnitingTheTribesQuest) };
Chains[(int)QuestChain.MyrmidexAlliance] = new Type[] { typeof(TheZealotryOfZipactriotlQuest), typeof(DestructionOfZipactriotlQuest) };
Chains[(int)QuestChain.EodonianAlliance] = new Type[] { typeof(ExterminatingTheInfestationQuest), typeof(InsecticideAndRegicideQuest) };
Chains[(int)QuestChain.FlintTheQuartermaster] = new Type[] { typeof(ThievesBeAfootQuest), typeof(BibliophileQuest) };
Chains[(int)QuestChain.AnimalTraining] = new Type[] { typeof(TamingPetQuest), typeof(UsingAnimalLoreQuest), typeof(LeadingIntoBattleQuest), typeof(TeachingSomethingNewQuest) };
Chains[(int)QuestChain.PaladinsOfTrinsic] = new Type[] { typeof(PaladinsOfTrinsic), typeof(PaladinsOfTrinsic2) };
Chains[(int)QuestChain.RightingWrong] = new Type[] { typeof(RightingWrongQuest2), typeof(RightingWrongQuest3), typeof(RightingWrongQuest4) };
Chains[(int)QuestChain.Ritual] = new Type[] { typeof(Server.Engines.Quests.RitualQuest.ScalesOfADreamSerpentQuest), typeof(Server.Engines.Quests.RitualQuest.TearsOfASoulbinderQuest), typeof(Server.Engines.Quests.RitualQuest.PristineCrystalLotusQuest) };
}
public Type CurrentQuest { get; set; }
public Type Quester { get; set; }
public BaseChain(Type currentQuest, Type quester)
{
CurrentQuest = currentQuest;
Quester = quester;
}
}
}

View File

@@ -0,0 +1,132 @@
using System;
using Server;
using System.Collections.Generic;
using Server.Engines.Quests;
using Server.Mobiles;
namespace Server.Items
{
public class QuestHintItem : Item
{
private int m_Number;
private string m_String;
private int m_Range;
[CommandProperty(AccessLevel.GameMaster)]
public int Number { get { return m_Number; } set { m_Number = value; } }
[CommandProperty(AccessLevel.GameMaster)]
public string String { get { return m_String; } set { m_String = value; } }
[CommandProperty(AccessLevel.GameMaster)]
public int Range { get { return m_Range; } set { m_Range = value; } }
public virtual Type QuestType { get { return null; } }
public virtual Type QuestItemType { get { return null; } }
public virtual int DefaultRange { get { return 8; } }
[Constructable]
public QuestHintItem(int num)
: base(7108)
{
Visible = false;
Movable = false;
m_Number = num;
m_Range = DefaultRange;
Name = "Quest Hint Item";
}
[Constructable]
public QuestHintItem(string str)
: base(7108)
{
Visible = false;
Movable = false;
m_String = str;
m_Range = DefaultRange;
}
private Dictionary<Mobile, DateTime> m_Table = new Dictionary<Mobile, DateTime>();
public override bool HandlesOnMovement { get { return true; } }
public override void OnMovement(Mobile from, Point3D oldLocation)
{
if (!from.Player)
return;
if (m_Table.ContainsKey(from) && m_Table[from] < DateTime.Now)
m_Table.Remove(from);
if (!m_Table.ContainsKey(from) && from.InRange(this.Location, m_Range))
{
if (QuestItemType != null && !FindItem())
return;
if (QuestType != null && QuestHelper.GetQuest((PlayerMobile)from, QuestType) == null)
return;
m_Table[from] = DateTime.Now + TimeSpan.FromMinutes(3);
if (m_Number > 0)
from.SendLocalizedMessage(m_Number);
else if (m_String != null)
from.SendMessage(m_String);
}
}
private bool FindItem()
{
IPooledEnumerable eable = this.Map.GetItemsInRange(this.Location, m_Range * 2);
foreach(Item item in eable)
{
if(item.GetType() == QuestItemType)
{
eable.Free();
return true;
}
}
eable.Free();
return false;
}
public QuestHintItem(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)1); // version
writer.Write(m_Range);
writer.Write(m_Number);
writer.Write(m_String);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 1:
m_Range = reader.ReadInt();
goto case 0;
case 0:
m_Number = reader.ReadInt();
m_String = reader.ReadString();
break;
}
}
}
}

View File

@@ -0,0 +1,918 @@
using System;
using Server.Mobiles;
using Server.Regions;
using System.Collections.Generic;
using System.Linq;
namespace Server.Engines.Quests
{
public class BaseObjective
{
private BaseQuest m_Quest;
private int m_MaxProgress;
private int m_CurProgress;
private int m_Seconds;
private bool m_Timed;
public BaseObjective()
: this(1, 0)
{
}
public BaseObjective(int maxProgress)
: this(maxProgress, 0)
{
}
public BaseObjective(int maxProgress, int seconds)
{
m_MaxProgress = maxProgress;
m_Seconds = seconds;
if (seconds > 0)
Timed = true;
else
Timed = false;
}
public BaseQuest Quest
{
get
{
return m_Quest;
}
set
{
m_Quest = value;
}
}
public int MaxProgress
{
get
{
return m_MaxProgress;
}
set
{
m_MaxProgress = value;
}
}
public int CurProgress
{
get
{
return m_CurProgress;
}
set
{
m_CurProgress = value;
if (Completed)
OnCompleted();
if (m_CurProgress == -1)
OnFailed();
if (m_CurProgress < -1)
m_CurProgress = -1;
}
}
public int Seconds
{
get
{
return m_Seconds;
}
set
{
m_Seconds = value;
if (m_Seconds < 0)
m_Seconds = 0;
}
}
public bool Timed
{
get
{
return m_Timed;
}
set
{
m_Timed = value;
}
}
public bool Completed
{
get
{
return CurProgress >= MaxProgress;
}
}
public bool Failed
{
get
{
return CurProgress == -1;
}
}
public virtual object ObjectiveDescription
{
get { return null; }
}
public virtual void Complete()
{
CurProgress = MaxProgress;
}
public virtual void Fail()
{
CurProgress = -1;
}
public virtual void OnAccept()
{
}
public virtual void OnCompleted()
{
}
public virtual void OnFailed()
{
}
public virtual Type Type()
{
return null;
}
public virtual bool Update(object obj)
{
return false;
}
public virtual void UpdateTime()
{
if (!Timed || Failed)
return;
if (Seconds > 0)
{
Seconds -= 1;
}
else if (!Completed)
{
m_Quest.Owner.SendLocalizedMessage(1072258); // You failed to complete an objective in time!
Fail();
}
}
public virtual void Serialize(GenericWriter writer)
{
writer.WriteEncodedInt((int)0); // version
writer.Write((int)m_CurProgress);
writer.Write((int)m_Seconds);
}
public virtual void Deserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_CurProgress = reader.ReadInt();
m_Seconds = reader.ReadInt();
}
}
public class SlayObjective : BaseObjective
{
private Type[] m_Creatures;
private string m_Name;
private Region m_Region;
public SlayObjective(Type creature, string name, int amount)
: this(new Type[] { creature }, name, amount, null, 0)
{
}
public SlayObjective(Type creature, string name, int amount, string region)
: this(new Type[] { creature }, name, amount, region, 0)
{
}
public SlayObjective(Type creature, string name, int amount, int seconds)
: this(new Type[] { creature }, name, amount, null, seconds)
{
}
public SlayObjective(string name, int amount, params Type[] creatures)
: this(creatures, name, amount, null, 0)
{
}
public SlayObjective(string name, int amount, string region, params Type[] creatures)
: this(creatures, name, amount, region, 0)
{
}
public SlayObjective(string name, int amount, int seconds, params Type[] creatures)
: this(creatures, name, amount, null, seconds)
{
}
public SlayObjective(Type[] creatures, string name, int amount, string region, int seconds)
: base(amount, seconds)
{
m_Creatures = creatures;
m_Name = name;
if (region != null)
{
m_Region = QuestHelper.FindRegion(region);
if (m_Region == null)
Console.WriteLine(String.Format("Invalid region name ('{0}') in '{1}' objective!", region, GetType()));
}
}
public Type[] Creatures
{
get
{
return m_Creatures;
}
set
{
m_Creatures = value;
}
}
public string Name
{
get
{
return m_Name;
}
set
{
m_Name = value;
}
}
public Region Region
{
get
{
return m_Region;
}
set
{
m_Region = value;
}
}
public virtual void OnKill(Mobile killed)
{
if (Completed)
Quest.Owner.SendLocalizedMessage(1075050); // You have killed all the required quest creatures of this type.
else
Quest.Owner.SendLocalizedMessage(1075051, (MaxProgress - CurProgress).ToString()); // You have killed a quest creature. ~1_val~ more left.
}
public virtual bool IsObjective(Mobile mob)
{
if (m_Creatures == null)
return false;
foreach (var type in m_Creatures)
{
if (type.IsAssignableFrom(mob.GetType()))
{
if (m_Region != null && !m_Region.Contains(mob.Location))
return false;
return true;
}
}
return false;
}
public override bool Update(object obj)
{
if (obj is Mobile)
{
Mobile mob = (Mobile)obj;
if (IsObjective(mob))
{
if (!Completed)
CurProgress += 1;
OnKill(mob);
return true;
}
}
return false;
}
public override Type Type()
{
return m_Creatures != null && m_Creatures.Length > 0 ? m_Creatures[0] : null;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class ObtainObjective : BaseObjective
{
private Type m_Obtain;
private string m_Name;
private int m_Image;
private int m_Hue;
public ObtainObjective(Type obtain, string name, int amount)
: this(obtain, name, amount, 0, 0)
{
}
public ObtainObjective(Type obtain, string name, int amount, int image)
: this(obtain, name, amount, image, 0)
{
}
public ObtainObjective(Type obtain, string name, int amount, int image, int seconds)
: this(obtain, name, amount, image, seconds, 0)
{
}
public ObtainObjective(Type obtain, string name, int amount, int image, int seconds, int hue)
: base(amount, seconds)
{
m_Obtain = obtain;
m_Name = name;
m_Image = image;
m_Hue = hue;
}
public Type Obtain
{
get
{
return m_Obtain;
}
set
{
m_Obtain = value;
}
}
public string Name
{
get
{
return m_Name;
}
set
{
m_Name = value;
}
}
public int Image
{
get
{
return m_Image;
}
set
{
m_Image = value;
}
}
public int Hue
{
get
{
return m_Hue;
}
set
{
m_Hue = value;
}
}
public override bool Update(object obj)
{
if (obj is Item)
{
Item obtained = (Item)obj;
if (IsObjective(obtained))
{
if (!obtained.QuestItem)
{
CurProgress += obtained.Amount;
obtained.QuestItem = true;
Quest.Owner.SendLocalizedMessage(1072353); // You set the item to Quest Item status
Quest.OnObjectiveUpdate(obtained);
}
else
{
CurProgress -= obtained.Amount;
obtained.QuestItem = false;
Quest.Owner.SendLocalizedMessage(1072354); // You remove Quest Item status from the item
}
return true;
}
}
return false;
}
public virtual bool IsObjective(Item item)
{
if (m_Obtain == null)
return false;
if (m_Obtain.IsAssignableFrom(item.GetType()))
return true;
return false;
}
public override Type Type()
{
return m_Obtain;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class DeliverObjective : BaseObjective
{
private Type m_Delivery;
private string m_DeliveryName;
private Type m_Destination;
private string m_DestName;
public DeliverObjective(Type delivery, string deliveryName, int amount, Type destination, string destName)
: this(delivery, deliveryName, amount, destination, destName, 0)
{
}
public DeliverObjective(Type delivery, string deliveryName, int amount, Type destination, string destName, int seconds)
: base(amount, seconds)
{
m_Delivery = delivery;
m_DeliveryName = deliveryName;
m_Destination = destination;
m_DestName = destName;
}
public Type Delivery
{
get
{
return m_Delivery;
}
set
{
m_Delivery = value;
}
}
public string DeliveryName
{
get
{
return m_DeliveryName;
}
set
{
m_DeliveryName = value;
}
}
public Type Destination
{
get
{
return m_Destination;
}
set
{
m_Destination = value;
}
}
public string DestName
{
get
{
return m_DestName;
}
set
{
m_DestName = value;
}
}
public override void OnAccept()
{
if (Quest.StartingItem != null)
{
Quest.StartingItem.QuestItem = true;
return;
}
int amount = MaxProgress;
while (amount > 0 && !Failed)
{
Item item = QuestHelper.Construct(m_Delivery) as Item;
if (item == null)
{
Fail();
break;
}
if (item.Stackable)
{
item.Amount = amount;
amount = 1;
}
if (!Quest.Owner.PlaceInBackpack(item))
{
Quest.Owner.SendLocalizedMessage(503200); // You do not have room in your backpack for
Quest.Owner.SendLocalizedMessage(1075574); // Could not create all the necessary items. Your quest has not advanced.
Fail();
break;
}
else
item.QuestItem = true;
amount -= 1;
}
if (Failed)
{
QuestHelper.DeleteItems(Quest.Owner, m_Delivery, MaxProgress - amount, false);
Quest.RemoveQuest();
}
}
public override bool Update(object obj)
{
if (m_Delivery == null || m_Destination == null)
return false;
if (Failed)
{
Quest.Owner.SendLocalizedMessage(1074813); // You have failed to complete your delivery.
return false;
}
if (obj is BaseVendor)
{
if (Quest.StartingItem != null)
{
Complete();
return true;
}
else if (m_Destination.IsAssignableFrom(obj.GetType()))
{
if (MaxProgress < QuestHelper.CountQuestItems(Quest.Owner, Delivery))
{
Quest.Owner.SendLocalizedMessage(1074813); // You have failed to complete your delivery.
Fail();
}
else
Complete();
return true;
}
}
return false;
}
public override Type Type()
{
return m_Delivery;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class EscortObjective : BaseObjective
{
public Region Region { get; set; }
public int Fame { get; set; }
public int Compassion { get; set; }
public int Label { get; set; }
public EscortObjective(string region)
: this(region, 10, 200, 0, 0)
{
}
public EscortObjective(int label, string region)
: this(region, 10, 200, 0, label)
{
}
public EscortObjective(string region, int fame)
: this(region, fame, 200)
{
}
public EscortObjective(string region, int fame, int compassion)
: this(region, fame, compassion, 0, 0)
{
}
public EscortObjective(string region, int fame, int compassion, int seconds, int label)
: base(1, seconds)
{
Region = QuestHelper.FindRegion(region);
Fame = fame;
Compassion = compassion;
Label = label;
if (Region == null)
Console.WriteLine(String.Format("Invalid region name ('{0}') in '{1}' objective!", region, GetType()));
}
public override void OnCompleted()
{
if (Quest != null && Quest.Owner != null && Quest.Owner.Murderer && Quest.Owner.DoneQuests.FirstOrDefault(info => info.QuestType == typeof(ResponsibilityQuest)) == null)
{
QuestHelper.Delay(Quest.Owner, typeof(ResponsibilityQuest), Quest.RestartDelay);
}
base.OnCompleted();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class ApprenticeObjective : BaseObjective
{
private SkillName m_Skill;
private Region m_Region;
private object m_Enter;
private object m_Leave;
public ApprenticeObjective(SkillName skill, int cap)
: this(skill, cap, null, null, null)
{
}
public ApprenticeObjective(SkillName skill, int cap, string region, object enterRegion, object leaveRegion)
: base(cap)
{
m_Skill = skill;
if (region != null)
{
m_Region = QuestHelper.FindRegion(region);
m_Enter = enterRegion;
m_Leave = leaveRegion;
if (m_Region == null)
Console.WriteLine(String.Format("Invalid region name ('{0}') in '{1}' objective!", region, GetType()));
}
}
public SkillName Skill
{
get
{
return m_Skill;
}
set
{
m_Skill = value;
}
}
public Region Region
{
get
{
return m_Region;
}
set
{
m_Region = value;
}
}
public object Enter
{
get
{
return m_Enter;
}
set
{
m_Enter = value;
}
}
public object Leave
{
get
{
return m_Leave;
}
set
{
m_Leave = value;
}
}
public override bool Update(object obj)
{
if (Completed)
return false;
if (obj is Skill)
{
Skill skill = (Skill)obj;
if (skill.SkillName != m_Skill)
return false;
if (Quest.Owner.Skills[m_Skill].Base >= MaxProgress)
{
Complete();
return true;
}
}
return false;
}
public override void OnAccept()
{
Region region = Quest.Owner.Region;
while (region != null)
{
if (region is ApprenticeRegion)
region.OnEnter(Quest.Owner);
region = region.Parent;
}
}
public override void OnCompleted()
{
QuestHelper.RemoveAcceleratedSkillgain(Quest.Owner);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt((int)1); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class QuestionAndAnswerObjective : BaseObjective
{
private int _CurrentIndex;
private List<int> m_Done = new List<int>();
private QuestionAndAnswerEntry[] m_EntryTable;
public virtual QuestionAndAnswerEntry[] EntryTable { get { return m_EntryTable; } }
public QuestionAndAnswerObjective(int count, QuestionAndAnswerEntry[] table)
: base(count)
{
m_EntryTable = table;
_CurrentIndex = -1;
}
public QuestionAndAnswerEntry GetRandomQandA()
{
if (m_EntryTable == null || m_EntryTable.Length == 0 || m_EntryTable.Length - m_Done.Count <= 0)
return null;
if (_CurrentIndex >= 0 && _CurrentIndex < m_EntryTable.Length)
{
return m_EntryTable[_CurrentIndex];
}
int ran;
do
{
ran = Utility.Random(m_EntryTable.Length);
}
while (m_Done.Contains(ran));
_CurrentIndex = ran;
return m_EntryTable[ran];
}
public override bool Update(object obj)
{
m_Done.Add(_CurrentIndex);
_CurrentIndex = -1;
if (!Completed)
CurProgress++;
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)1); // version
writer.Write(_CurrentIndex);
writer.Write(m_Done.Count);
for (int i = 0; i < m_Done.Count; i++)
writer.Write(m_Done[i]);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version > 0)
{
_CurrentIndex = reader.ReadInt();
}
int c = reader.ReadInt();
for (int i = 0; i < c; i++)
m_Done.Add(reader.ReadInt());
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
using Server;
using Server.Items;
using Server.Mobiles;
using System.Collections.Generic;
using Server.Targeting;
/*
* Called in MondainsQuestGump.cs to show simple string for simple quest objectives.
*/
namespace Server.Engines.Quests
{
public abstract class SimpleObjective : BaseObjective
{
public abstract List<string> Descriptions { get; }
public SimpleObjective(int amount, int seconds)
: base(amount, seconds)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,228 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Mobiles;
namespace Server.Engines.Quests
{
public interface ITierQuest
{
TierQuestInfo TierInfo { get; }
TimeSpan RestartDelay { get; }
}
public interface ITierQuester
{
TierQuestInfo TierInfo { get; }
}
public class TierQuestInfo
{
public Type Quester { get; set; }
public TierInfo[] Tiers { get; set; }
public TierQuestInfo(Type quester, params TierInfo[] tiers)
{
Quester = quester;
Tiers = tiers;
}
public static TierQuestInfo Percolem { get; set; }
public static TierQuestInfo Thepem { get; set; }
public static TierQuestInfo Zosilem { get; set; }
static TierQuestInfo()
{
Percolem = new TierQuestInfo(typeof(Percolem),
new TierInfo(0, TimeSpan.FromMinutes(30), typeof(BouraBouraQuest), typeof(RaptorliciousQuest), typeof(TheSlithWarsQuest)),
new TierInfo(5, TimeSpan.FromMinutes(120), typeof(AmbushingTheAmbushersQuest), typeof(BouraBouraAndMoreBouraQuest), typeof(RevengeOfTheSlithQuest), typeof(WeveGotAnAntProblemQuest)),
new TierInfo(10, TimeSpan.FromMinutes(1440), typeof(ItMakesMeSickQuest), typeof(ItsAMadMadWorldQuest), typeof(TheDreamersQuest)));
Thepem = new TierQuestInfo(typeof(Thepem),
new TierInfo(0, TimeSpan.FromMinutes(30), typeof(AllThatGlitters), typeof(TastyTreats)),
new TierInfo(5, TimeSpan.FromMinutes(120), typeof(MetalHead), typeof(PinkistheNewBlack)));
Zosilem = new TierQuestInfo(typeof(Zosilem),
new TierInfo(0, TimeSpan.FromMinutes(30), typeof(DabblingontheDarkSide), typeof(TheBrainyAlchemist)),
new TierInfo(5, TimeSpan.FromMinutes(120), typeof(ArmorUp), typeof(ToTurnBaseMetalIntoVerite)),
new TierInfo(10, TimeSpan.FromMinutes(1440), typeof(PureValorite), typeof(TheForbiddenFruit)));
}
public static TimeSpan GetCooldown(TierQuestInfo tierInfo, Type questType)
{
var info = tierInfo.Tiers.FirstOrDefault(i => i.Quests.Any(q => q == questType));
if (info != null)
{
return info.Cooldown;
}
return TimeSpan.Zero;
}
public static int GetCompleteReq(TierQuestInfo tierInfo, Type questType)
{
var info = tierInfo.Tiers.FirstOrDefault(i => i.Quests.Any(q => q == questType));
if (info != null)
{
return info.ToComplete;
}
return 0;
}
public static Dictionary<PlayerMobile, Dictionary<Type, int>> PlayerTierInfo { get; set; } = new Dictionary<PlayerMobile, Dictionary<Type, int>>();
public static void CompleteQuest(PlayerMobile pm, ITierQuest quest)
{
var type = quest.GetType();
if (!PlayerTierInfo.ContainsKey(pm))
{
PlayerTierInfo[pm] = new Dictionary<Type, int>();
}
if (PlayerTierInfo[pm].ContainsKey(type))
{
PlayerTierInfo[pm][type]++;
}
else
{
PlayerTierInfo[pm][type] = 1;
}
}
public static int HasCompleted(PlayerMobile pm, Type questType, TierQuestInfo info)
{
if (!PlayerTierInfo.ContainsKey(pm))
{
return 0;
}
int completed = 0;
foreach (var kvp in PlayerTierInfo[pm])
{
if (questType == kvp.Key)
{
completed += kvp.Value;
}
}
/*foreach (var tier in info.Tiers)
{
if (tier.Quests.Any(q => q == questType))
{
foreach (var q in tier.Quests)
{
foreach (var kvp in PlayerTierInfo[pm])
{
if (q == kvp.Key)
{
completed += kvp.Value;
}
}
}
}
}*/
return completed;
}
public static BaseQuest RandomQuest(PlayerMobile pm, ITierQuester quester)
{
var info = quester.TierInfo;
if (info != null)
{
var list = new List<Type>();
int lastTierComplete = 0;
for(int i = 0; i < info.Tiers.Length; i++)
{
var tier = info.Tiers[i];
if (lastTierComplete >= tier.ToComplete)
{
list.AddRange(tier.Quests);
}
lastTierComplete = 0;
foreach (var quest in tier.Quests)
{
lastTierComplete += HasCompleted(pm, quest, info);
}
}
if (list.Count > 0)
{
return QuestHelper.Construct(list[Utility.Random(list.Count)]) as BaseQuest;
}
}
return null;
}
public static void Save(GenericWriter writer)
{
writer.Write(0);
writer.Write(PlayerTierInfo.Count);
foreach (var kvp in PlayerTierInfo)
{
writer.WriteMobile(kvp.Key);
writer.Write(kvp.Value.Count);
foreach (var kvp2 in kvp.Value)
{
writer.Write(kvp2.Key.FullName);
writer.Write(kvp2.Value);
}
}
}
public static void Load(GenericReader reader)
{
reader.ReadInt();
var count = reader.ReadInt();
for (int i = 0; i < count; i++)
{
var pm = reader.ReadMobile<PlayerMobile>();
var c = reader.ReadInt();
var list = new Dictionary<Type, int>();
for (int j = 0; j < c; j++)
{
var type = ScriptCompiler.FindTypeByFullName(reader.ReadString());
var completed = reader.ReadInt();
list[type] = completed;
}
if (pm != null)
{
PlayerTierInfo[pm] = list;
}
}
}
}
public class TierInfo
{
public Type[] Quests { get; set; }
public TimeSpan Cooldown { get; set; }
public int ToComplete { get; set; }
public TierInfo(int toComplete, TimeSpan cooldown, params Type[] quests)
{
Quests = quests;
Cooldown = cooldown;
ToComplete = toComplete;
}
}
}