using System; using Server; using Server.Gumps; using Server.Network; using Server.Mobiles; using System.IO; using System.Collections.Generic; using Server.Targeting; using Server.Engines.PartySystem; using System.Data; using System.Xml; using Server.Engines.XmlSpawner2; /* ** XmlQuestToken class ** ** Version 1.10 ** updated 10/26/04 ** ArteGordon ** ** Version 1.10 ** updated 10/26/04 ** - modified RewardString to only support item rewards and added the new AttachmentString property for specifying attachment rewards. ** ** Version 1.09 ** updated 9/03/04 ** - added the autoreward and rewarditem properties that allow rewards to be automatically created and given upon quest completion ** ** Version 1.08 ** updated 7/31/04 ** - added the Description1-5 property to allow the quest objective descriptions to be explicitly specified. When this string is defined it will override the default ** description provided for the different types of quest objectives. ** ** Version 1.07 ** updated 7/28/04 ** - add support for an additional property test argument to the quest keywords ** - mobs no longer say "Thank you", or "I have no need for that." when given items for GIVE type quests. ** ** Version 1.06 ** updated 7/07/04 ** - Added the GIVE type quest objective. Using an objective string of the type "GIVE,mobname,item[,count]" or "GIVENAMED,mobname,itemname[,count]" will produce an objective ** that is satisfied when the specified item(s) are dragged and dropped onto the named mob. ** - Added the ESCORT type quest objective. Using an objective string of the type "ESCORT,mobname" will produce an objective ** that is satisfied when the specified TalkingBaseEscortable class mob is successfully escorted to its destination. ** Note, the destination is specified by setting the Destination property on the escort to a region name. ** - changed the rules for invalid XmlQuestTokens to eliminate hording or trading so that they can no longer be placed in containers and will automatically ** return to the player's pack if the player attempts to place them in any invalid location (such as another container, a bankbox, or another player). ** If they are placed on ground they will be automatically deleted. ** - added optimizations for KILL type quests in which only players that are flagged as carrying XmlQuestTokens are checked on kills. ** ** Version 1.05 ** updated 4/30/04 ** - Added the RewardString property ** ** Version 1.04 ** updated 3/25/04 ** - Added the LoadConfig and ConfigFile properties that allow XmlQuestTokens to read their configuration information from an XML file. ** - Moved the TitleString and NoteString properties from the QuestNote class to the XmlQuestToken class. ** ** Version 1.03 ** updated 3/25/04 ** - Added the PartyEnabled and PartyRange properties that allow party members to benefit from KILL and COLLECT keywords. ** ** Version 1.02 ** updated 3/20/04 ** - fixed the COLLECT and COLLECTNAMED keywords to remove non-stackable items after collecting. Thanks to nix4 for pointing this out. ** * Version 1.01 ** updated 2/26/04 ** - modified expiration time reporting format ** - added State properties to support more complex objective status information ** - added killtask support with special objective specification keywords KILL,mobtype,count and KILLNAMED,mobname,count ** - added collecttask support with special objective specification keywords COLLECT,itemtype,count and COLLECTNAMED,itemname,count ** ** Version 1.0 ** updated 1/07/04 */ namespace Server.Items { public class XmlQuestTokenPack : Container { public override bool OnDragDrop(Mobile from, Item dropped) { return false; } public override bool OnDragDropInto(Mobile from, Item item, Point3D p) { return false; } #if(NEWPARENT) public override void OnAdded(IEntity target) #else public override void OnAdded(object target) #endif { base.OnAdded(target); UpdateTotal(this, TotalType.Weight, 0); UpdateTotal(this, TotalType.Gold, 0); UpdateTotal(this, TotalType.Items, 0); } public sealed class ForcedContainerContent : Packet { public ForcedContainerContent(Mobile beholder, Item beheld) : base(0x3C) { List items = beheld.Items; int count = items.Count; this.EnsureCapacity(5 + (count * 19)); long pos = m_Stream.Position; int written = 0; m_Stream.Write((ushort)0); for (int i = 0; i < count; ++i) { Item child = items[i]; if (!child.Deleted ) { Point3D loc = child.Location; ushort cid = (ushort)child.ItemID; if (cid > 0x3FFF) cid = 0x9D7; m_Stream.Write((int)child.Serial); m_Stream.Write((ushort)cid); m_Stream.Write((byte)0); // signed, itemID offset m_Stream.Write((ushort)child.Amount); m_Stream.Write((short)loc.X); m_Stream.Write((short)loc.Y); m_Stream.Write((int)beheld.Serial); m_Stream.Write((ushort)child.Hue); ++written; } } m_Stream.Seek(pos, SeekOrigin.Begin); m_Stream.Write((ushort)written); } } public override void DisplayTo(Mobile to) { if (to == null) return; to.Send(new ContainerDisplay(this)); to.Send(new ForcedContainerContent(to, this)); if (ObjectPropertyList.Enabled) { List items = this.Items; for (int i = 0; i < items.Count; ++i) to.Send(((Item)items[i]).OPLPacket); } } public XmlQuestTokenPack() : base(0x9B2) { Weight = 0; } public XmlQuestTokenPack(Serial serial) : base(serial) { } public override void Serialize(GenericWriter writer) { base.Serialize(writer); writer.Write((int)0); } public override void Deserialize(GenericReader reader) { base.Deserialize(reader); int version = reader.ReadInt(); } } public abstract class XmlQuestToken : Item, IXmlQuest { //public const PlayerFlag CarriedXmlQuestFlag = (PlayerFlag)0x00100000; private bool m_wasMoved = false; private double m_ExpirationDuration; private DateTime m_TimeCreated; private string m_Objective1; private string m_Objective2; private string m_Objective3; private string m_Objective4; private string m_Objective5; private string m_Description1; private string m_Description2; private string m_Description3; private string m_Description4; private string m_Description5; private bool m_Completed1 = false; private bool m_Completed2 = false; private bool m_Completed3 = false; private bool m_Completed4 = false; private bool m_Completed5 = false; private string m_State1; private string m_State2; private string m_State3; private string m_State4; private string m_State5; private bool m_PartyEnabled = false; private int m_PartyRange = -1; private string m_ConfigFile; private string m_NoteString; private string m_TitleString; private string m_RewardString; private string m_AttachmentString; private PlayerMobile m_Owner; private string m_SkillTrigger = null; private bool m_Repeatable = true; private TimeSpan m_NextRepeatable; private Item m_RewardItem; private XmlAttachment m_RewardAttachment; private int m_RewardAttachmentSerialNumber; private bool m_AutoReward = false; private Container m_Pack; private bool m_CanSeeReward = false; private bool m_PlayerMade = false; private PlayerMobile m_Creator; private Container m_ReturnContainer; private string m_status_str; private int m_QuestDifficulty = 1; public XmlQuestToken(Serial serial) : base(serial) { } public XmlQuestToken() { //LootType = LootType.Blessed; TimeCreated = DateTime.UtcNow; } public XmlQuestToken(int itemID) { ItemID = itemID; //LootType = LootType.Blessed; TimeCreated = DateTime.UtcNow; } public override void Serialize(GenericWriter writer) { base.Serialize(writer); writer.Write((int)14); // version // version 14 if (m_Journal == null || m_Journal.Count == 0) { writer.Write((int)0); } else { writer.Write((int)m_Journal.Count); foreach (XmlQuest.JournalEntry e in m_Journal) { writer.Write(e.EntryID); writer.Write(e.EntryText); } } // version 13 writer.Write(m_Repeatable); // version 12 writer.Write(m_QuestDifficulty); // version 11 writer.Write(m_AttachmentString); // version 10 writer.Write(m_NextRepeatable); // version 9 if (m_RewardAttachment != null) writer.Write(m_RewardAttachment.Serial.Value); else writer.Write((int)0); // version 8 writer.Write(m_ReturnContainer); // version 7 writer.Write(m_Pack); writer.Write(m_RewardItem); writer.Write(m_AutoReward); writer.Write(m_CanSeeReward); writer.Write(m_PlayerMade); writer.Write(m_Creator); // version 6 writer.Write(m_Description1); writer.Write(m_Description2); writer.Write(m_Description3); writer.Write(m_Description4); writer.Write(m_Description5); // version 5 writer.Write(m_Owner); // version 4 writer.Write(m_RewardString); // version 3 writer.Write(m_ConfigFile); writer.Write(m_NoteString); // moved from the QuestNote class writer.Write(m_TitleString); // moved from the QuestNote class // version 2 writer.Write(m_PartyEnabled); writer.Write(m_PartyRange); // version 1 writer.Write(m_State1); writer.Write(m_State2); writer.Write(m_State3); writer.Write(m_State4); writer.Write(m_State5); // version 0 writer.Write(m_wasMoved); writer.Write(m_ExpirationDuration); writer.Write(m_TimeCreated); writer.Write(m_Objective1); writer.Write(m_Objective2); writer.Write(m_Objective3); writer.Write(m_Objective4); writer.Write(m_Objective5); writer.Write(m_Completed1); writer.Write(m_Completed2); writer.Write(m_Completed3); writer.Write(m_Completed4); writer.Write(m_Completed5); } public override void Deserialize(GenericReader reader) { base.Deserialize(reader); int version = reader.ReadInt(); switch (version) { case 14: { int nentries = reader.ReadInt(); if (nentries > 0) { m_Journal = new List(); for (int i = 0; i < nentries; i++) { string entryID = reader.ReadString(); string entryText = reader.ReadString(); m_Journal.Add(new XmlQuest.JournalEntry(entryID, entryText)); } } goto case 13; } case 13: { m_Repeatable = reader.ReadBool(); goto case 12; } case 12: { m_QuestDifficulty = reader.ReadInt(); goto case 11; } case 11: { m_AttachmentString = reader.ReadString(); goto case 10; } case 10: { m_NextRepeatable = reader.ReadTimeSpan(); goto case 9; } case 9: { m_RewardAttachmentSerialNumber = reader.ReadInt(); goto case 8; } case 8: { this.m_ReturnContainer = (Container)reader.ReadItem(); goto case 7; } case 7: { this.m_Pack = (Container)reader.ReadItem(); this.m_RewardItem = reader.ReadItem(); this.m_AutoReward = reader.ReadBool(); this.m_CanSeeReward = reader.ReadBool(); this.m_PlayerMade = reader.ReadBool(); this.m_Creator = reader.ReadMobile() as PlayerMobile; goto case 6; } case 6: { this.m_Description1 = reader.ReadString(); this.m_Description2 = reader.ReadString(); this.m_Description3 = reader.ReadString(); this.m_Description4 = reader.ReadString(); this.m_Description5 = reader.ReadString(); goto case 5; } case 5: { this.m_Owner = reader.ReadMobile() as PlayerMobile; goto case 4; } case 4: { this.m_RewardString = reader.ReadString(); goto case 3; } case 3: { this.m_ConfigFile = reader.ReadString(); this.m_NoteString = reader.ReadString(); this.m_TitleString = reader.ReadString(); goto case 2; } case 2: { this.m_PartyEnabled = reader.ReadBool(); this.m_PartyRange = reader.ReadInt(); goto case 1; } case 1: { this.m_State1 = reader.ReadString(); this.m_State2 = reader.ReadString(); this.m_State3 = reader.ReadString(); this.m_State4 = reader.ReadString(); this.m_State5 = reader.ReadString(); goto case 0; } case 0: { this.m_wasMoved = reader.ReadBool(); this.Expiration = reader.ReadDouble(); this.m_TimeCreated = reader.ReadDateTime(); this.m_Objective1 = reader.ReadString(); this.m_Objective2 = reader.ReadString(); this.m_Objective3 = reader.ReadString(); this.m_Objective4 = reader.ReadString(); this.m_Objective5 = reader.ReadString(); this.m_Completed1 = reader.ReadBool(); this.m_Completed2 = reader.ReadBool(); this.m_Completed3 = reader.ReadBool(); this.m_Completed4 = reader.ReadBool(); this.m_Completed5 = reader.ReadBool(); } break; } } public static void Initialize() { foreach (Item item in World.Items.Values) { if (item is XmlQuestToken) { XmlQuestToken t = item as XmlQuestToken; if (t.Pack != null && !t.Pack.Deleted) { t.UpdateWeight(); t.UpdateTotal(t.Pack, TotalType.Weight, 0); t.UpdateTotal(t.Pack, TotalType.Gold, 0); t.RestoreRewardAttachment(); } } } } public override void OnDoubleClick(Mobile from) { base.OnDoubleClick(from); if (!(from is PlayerMobile)) return; if (PlayerMade && (from == Creator) && (from == Owner)) { from.SendGump(new XmlPlayerQuestGump((PlayerMobile)from, this)); } } public override bool OnDroppedToWorld(Mobile from, Point3D point) { bool returnvalue = base.OnDroppedToWorld(from, point); from.SendGump(new XmlConfirmDeleteGump(from, this)); //m_wasMoved = true; //CheckOwnerFlag(); //Invalidate(); return false; //return returnvalue; } public override void OnDelete() { // remove any temporary quest attachments associated with this quest and quest owner XmlQuest.RemoveTemporaryQuestObjects(Owner, Name); base.OnDelete(); // remove any reward items that might be attached to this ReturnReward(); // and remove any pack if (Pack != null) { Pack.Delete(); } CheckOwnerFlag(); } public override void OnItemLifted(Mobile from, Item item) { base.OnItemLifted(from, item); if (from is PlayerMobile && PlayerMade && (Owner != null) && (Owner == Creator)) { LootType = LootType.Regular; } else if (from is PlayerMobile && Owner == null) { Owner = from as PlayerMobile; LootType = LootType.Blessed; // flag the owner as carrying a questtoken Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, true); } } #if(NEWPARENT) public override void OnAdded(IEntity target) #else public override void OnAdded(object target) #endif { base.OnAdded(target); if ((target != null) && target is Container) { // find the parent of the container // note, the only valid additions are to the player pack or a questbook. Anything else is invalid. This is to avoid exploits involving storage or transfer of questtokens // make an exception for playermade quests that can be put on playervendors object parentOfTarget = ((Container)target).Parent; // if this is a QuestBook then allow additions if it is in a players pack or it is a player quest if ((parentOfTarget != null) && parentOfTarget is Container && target is XmlQuestBook) { parentOfTarget = ((Container)parentOfTarget).Parent; } // check to see if it can be added. // allow playermade quests to be placed in playervendors or in xmlquestbooks that are in the world (supports the playerquestboards) if (PlayerMade && (((parentOfTarget != null) && parentOfTarget is PlayerVendor) || ((parentOfTarget == null) && target is XmlQuestBook))) { CheckOwnerFlag(); Owner = null; LootType = LootType.Regular; } else if ((parentOfTarget != null) && (parentOfTarget is PlayerMobile) && PlayerMade && (Owner != null) && ((Owner == Creator) || (Creator == null))) { // check the old owner CheckOwnerFlag(); Owner = parentOfTarget as PlayerMobile; // first owner will become creator by default if (Creator == null) Creator = Owner; LootType = LootType.Blessed; // flag the new owner as carrying a questtoken Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, true); } else if ((parentOfTarget != null) && (parentOfTarget is PlayerMobile)) { if (Owner == null) { Owner = parentOfTarget as PlayerMobile; LootType = LootType.Blessed; // flag the owner as carrying a questtoken Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, true); } else if ((parentOfTarget as PlayerMobile != Owner) || (target is BankBox)) { // tried to give it to another player or placed it in the players bankbox. try to return it to the owners pack Owner.AddToBackpack(this); /* // this has been added to a player who is not the owner so invalidate it WasMoved = true; CheckOwnerFlag(); Invalidate(); */ } } else { if (Owner != null) { // try to return it to the owners pack Owner.AddToBackpack(this); } // allow placement into npcs or drop on their corpses when owner is null else if (!(parentOfTarget is Mobile) && !(target is Corpse) && parentOfTarget != null) { // in principle this should never be reached // invalidate the token WasMoved = true; CheckOwnerFlag(); Invalidate(); } } } } private List m_Journal; public List Journal { get { return m_Journal; } set { m_Journal = value; } } private static char[] colondelim = new char[1] { ':' }; public string AddJournalEntry { set { if (value == null) return; // parse the value string[] args = value.Split(colondelim, 2); if (args == null) return; string entryID = null; string entryText = null; if (args.Length > 0) { entryID = args[0].Trim(); } if (entryID == null || entryID.Length == 0) return; if (args.Length > 1) { entryText = args[1].Trim(); } // allocate a new journal if none exists if (m_Journal == null) m_Journal = new List(); // go through the existing journal to find a matching ID XmlQuest.JournalEntry foundEntry = null; foreach (XmlQuest.JournalEntry e in m_Journal) { if (e.EntryID == entryID) { foundEntry = e; break; } } if (foundEntry != null) { if (entryText == null || entryText.Length == 0) { // delete the entry m_Journal.Remove(foundEntry); } else { // just replace the text foundEntry.EntryText = entryText; } } else { if (entryText != null && entryText.Length != 0) { // add the new entry m_Journal.Add(new XmlQuest.JournalEntry(entryID, entryText)); } } } } private void QuestCompletionAttachment() { bool complete = IsCompleted; // is this quest repeatable if ((!Repeatable || NextRepeatable > TimeSpan.Zero) && complete) { double expiresin = Repeatable ? NextRepeatable.TotalMinutes : 0; // then add an attachment indicating that it has already been done XmlAttach.AttachTo(Owner, new XmlQuestAttachment(this.Name, expiresin)); } // have quest points been enabled? if (XmlQuest.QuestPointsEnabled && complete && !PlayerMade) { XmlQuestPoints.GiveQuestPoints(Owner, this); } } private void PackItem(Item item) { if ((m_Pack == null || m_Pack.Deleted) && (Owner != null) /* && (this.RootParent is Mobile) */) { m_Pack = new XmlQuestTokenPack(); m_Pack.Layer = Layer.Invalid; //m_Pack.Parent = Owner; m_Pack.Parent = this; //m_Pack.Map = Owner.Map; m_Pack.Map = this.Map; m_Pack.Location = this.Location; } if ((m_Pack != null) && !m_Pack.Deleted) { m_Pack.DropItem(item); PackItemsMovable(m_Pack, false); UpdateTotal(m_Pack, TotalType.Weight, 0); UpdateTotal(m_Pack, TotalType.Gold, 0); } // make sure the weight and gold of the questtoken is updated to reflect the weight of added rewards in playermade quests to avoid // exploits where quests are used as zero weight containers UpdateWeight(); } private void CalculateWeight(Item target) { if (target is Container) { int gold = 0; int weight = 0; int nitems = 0; foreach (Item i in ((Container)target).FindItemsByType(typeof(Item), false)) { // make sure gold amount is consistent with totalgold if (i is Gold) { UpdateTotal(i, TotalType.Gold, i.Amount); } if (i is Container) { CalculateWeight(i); weight += i.TotalWeight + (int)i.Weight; gold += i.TotalGold; nitems += i.TotalItems + 1; } else { weight += (int)(i.Weight * i.Amount); gold += i.TotalGold; nitems += 1; } } UpdateTotal((Container)target, TotalType.Weight, weight); UpdateTotal((Container)target, TotalType.Gold, gold); UpdateTotal((Container)target, TotalType.Items, nitems); } } private void UpdateWeight() { // update the weight of the reward item itself CalculateWeight(m_RewardItem); // make sure the weight and gold of the questtoken is updated to reflect the weight of added rewards if (m_RewardItem != null && !m_RewardItem.Deleted && PlayerMade) { if (m_RewardItem is Container) { UpdateTotal(this, TotalType.Weight, m_RewardItem.TotalWeight + (int)m_RewardItem.Weight); UpdateTotal(this, TotalType.Gold, m_RewardItem.TotalGold); } else { UpdateTotal(this, TotalType.Weight, (int)(m_RewardItem.Weight * m_RewardItem.Amount)); UpdateTotal(this, TotalType.Gold, m_RewardItem.TotalGold); } } else { UpdateTotal(this, TotalType.Weight, 0); UpdateTotal(this, TotalType.Gold, 0); } } private void ReturnReward() { if (m_RewardItem != null) { CheckRewardItem(); // if this was player made, then return the item to the creator if (PlayerMade && (Creator != null) && !Creator.Deleted) { m_RewardItem.Movable = true; if (m_Pack != null && !m_Pack.Deleted) { // make sure all of the items in the pack are movable as well PackItemsMovable(m_Pack, true); } bool returned = false; //RefreshPackLocation(Creator, false); if ((ReturnContainer != null) && !ReturnContainer.Deleted) { returned = ReturnContainer.TryDropItem(Creator, m_RewardItem, false); //ReturnContainer.DropItem(m_RewardItem); } if (!returned) { returned = Creator.AddToBackpack(m_RewardItem); } if (returned) { Creator.SendMessage("Your reward {0} was returned from quest {1}", m_RewardItem.GetType().Name, Name); //AddMobileWeight(Creator, m_RewardItem); } else { Creator.SendMessage("Attempted to return reward {0} from quest {1} : containers full.", m_RewardItem.GetType().Name, Name); } } else { // just delete it m_RewardItem.Delete(); } m_RewardItem = null; UpdateWeight(); } if (m_RewardAttachment != null) { // delete any remaining attachments m_RewardAttachment.Delete(); } } [CommandProperty(AccessLevel.GameMaster)] public PlayerMobile Owner { get { return m_Owner; } set { m_Owner = value; } } [CommandProperty(AccessLevel.GameMaster)] public new string Name { get { if (PlayerMade) { return "PQ: " + base.Name; } else { return base.Name; } } set { base.Name = value; InvalidateProperties(); } } [CommandProperty(AccessLevel.GameMaster)] public PlayerMobile Creator { get { return m_Creator; } set { m_Creator = value; } } [CommandProperty(AccessLevel.GameMaster)] public int Difficulty { get { return m_QuestDifficulty; } set { m_QuestDifficulty = value; } } [CommandProperty(AccessLevel.GameMaster)] public string NoteString { get { return m_NoteString; } set { m_NoteString = value; } } [CommandProperty(AccessLevel.GameMaster)] public bool AutoReward { get { return m_AutoReward; } set { m_AutoReward = value; } } [CommandProperty(AccessLevel.GameMaster)] public bool CanSeeReward { // dont allow rewards to be seen on xmlquesttokens get { return false; } set { } } /* [CommandProperty( AccessLevel.GameMaster )] public bool CanSeeReward { get{ return m_CanSeeReward; } set { m_CanSeeReward = value; } } */ [CommandProperty(AccessLevel.GameMaster)] public bool PlayerMade { get { return m_PlayerMade; } set { m_PlayerMade = value; } } [CommandProperty(AccessLevel.GameMaster)] public Container ReturnContainer { get { return m_ReturnContainer; } set { m_ReturnContainer = value; } } public Container Pack { get { return m_Pack; } } private void PackItemsMovable(Container pack, bool canmove) { if (pack == null) return; Item[] itemlist = pack.FindItemsByType(typeof(Item), true); if (itemlist != null) { for (int i = 0; i < itemlist.Length; i++) { itemlist[i].Movable = canmove; } } } private void RestoreRewardAttachment() { m_RewardAttachment = XmlAttach.FindAttachmentBySerial(m_RewardAttachmentSerialNumber); } public XmlAttachment RewardAttachment { get { // if the reward item is not set, and the reward string is specified, then use the reward string to construct and assign the // reward item // dont allow player made quests to use the rewardstring creation feature if (m_RewardAttachment != null && m_RewardAttachment.Deleted) m_RewardAttachment = null; if ((m_RewardAttachment == null || m_RewardAttachment.Deleted) && (m_AttachmentString != null) && !PlayerMade) { object o = XmlQuest.CreateItem(this, m_AttachmentString, out m_status_str, typeof(XmlAttachment)); if (o is Item) { // should never get here ((Item)o).Delete(); } else if (o is XmlAttachment) { m_RewardAttachment = o as XmlAttachment; m_RewardAttachment.OwnedBy = this; } } return m_RewardAttachment; } set { // get rid of any existing attachment if (m_RewardAttachment != null && !m_RewardAttachment.Deleted) { m_RewardAttachment.Delete(); } m_RewardAttachment = value; } } [CommandProperty(AccessLevel.GameMaster)] public Item RewardItem { get { // if the reward item is not set, and the reward string is specified, then use the reward string to construct and assign the // reward item // dont allow player made quests to use the rewardstring creation feature if ((m_RewardItem == null || m_RewardItem.Deleted) && (m_RewardString != null) && !PlayerMade) { string status_str; object o = XmlQuest.CreateItem(this, m_RewardString, out status_str, typeof(Item)); if (o is Item) { m_RewardItem = o as Item; } else if (o is XmlAttachment) { // should never get here ((XmlAttachment)o).Delete(); } } // place it in the xmlquesttoken pack if it isnt already there if ((m_RewardItem != null && !m_RewardItem.Deleted) && ((Pack == null) || Pack.Deleted || (m_RewardItem.Parent != Pack))) { PackItem(m_RewardItem); } return m_RewardItem; } set { // get rid of any existing reward item if it has been assigned if (m_RewardItem != null && !m_RewardItem.Deleted) { ReturnReward(); } // and assign the new item m_RewardItem = value; // and put it in the xmlquesttoken pack if (m_RewardItem != null && !m_RewardItem.Deleted) { PackItem(m_RewardItem); } // is this currently carried by a mobile? if (m_RewardItem.RootParent != null && m_RewardItem.RootParent is Mobile) { // if so then remove it ((Mobile)(m_RewardItem.RootParent)).RemoveItem(m_RewardItem); } } } [CommandProperty(AccessLevel.GameMaster)] public string TitleString { get { return m_TitleString; } set { m_TitleString = value; InvalidateProperties(); } } [CommandProperty(AccessLevel.GameMaster)] public string RewardString { get { return m_RewardString; } set { m_RewardString = value; } } [CommandProperty(AccessLevel.GameMaster)] public string AttachmentString { get { return m_AttachmentString; } set { m_AttachmentString = value; } } [CommandProperty(AccessLevel.GameMaster)] public string ConfigFile { get { return m_ConfigFile; } set { m_ConfigFile = value; } } [CommandProperty(AccessLevel.GameMaster)] public bool LoadConfig { get { return false; } set { if (value == true) LoadXmlConfig(ConfigFile); } } [CommandProperty(AccessLevel.GameMaster)] public bool PartyEnabled { get { return m_PartyEnabled; } set { m_PartyEnabled = value; } } [CommandProperty(AccessLevel.GameMaster)] public int PartyRange { get { return m_PartyRange; } set { m_PartyRange = value; } } [CommandProperty(AccessLevel.GameMaster)] public string State1 { get { return m_State1; } set { m_State1 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string State2 { get { return m_State2; } set { m_State2 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string State3 { get { return m_State3; } set { m_State3 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string State4 { get { return m_State4; } set { m_State4 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string State5 { get { return m_State5; } set { m_State5 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string Description1 { get { return m_Description1; } set { m_Description1 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string Description2 { get { return m_Description2; } set { m_Description2 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string Description3 { get { return m_Description3; } set { m_Description3 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string Description4 { get { return m_Description4; } set { m_Description4 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string Description5 { get { return m_Description5; } set { m_Description5 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string Objective1 { get { return m_Objective1; } set { m_Objective1 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string Objective2 { get { return m_Objective2; } set { m_Objective2 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string Objective3 { get { return m_Objective3; } set { m_Objective3 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string Objective4 { get { return m_Objective4; } set { m_Objective4 = value; } } [CommandProperty(AccessLevel.GameMaster)] public string Objective5 { get { return m_Objective5; } set { m_Objective5 = value; } } [CommandProperty(AccessLevel.GameMaster)] public bool Completed1 { get { return m_Completed1; } set { m_Completed1 = value; CheckAutoReward(); } } [CommandProperty(AccessLevel.GameMaster)] public bool Completed2 { get { return m_Completed2; } set { m_Completed2 = value; CheckAutoReward(); } } [CommandProperty(AccessLevel.GameMaster)] public bool Completed3 { get { return m_Completed3; } set { m_Completed3 = value; CheckAutoReward(); } } [CommandProperty(AccessLevel.GameMaster)] public bool Completed4 { get { return m_Completed4; } set { m_Completed4 = value; CheckAutoReward(); } } [CommandProperty(AccessLevel.GameMaster)] public bool Completed5 { get { return m_Completed5; } set { m_Completed5 = value; CheckAutoReward(); } } [CommandProperty(AccessLevel.GameMaster)] public string Status { get { return m_status_str; } set { m_status_str = value; } } [CommandProperty(AccessLevel.GameMaster)] public virtual bool WasMoved { get { return m_wasMoved; } set { m_wasMoved = value; } } [CommandProperty(AccessLevel.GameMaster)] public DateTime TimeCreated { get { return m_TimeCreated; } set { m_TimeCreated = value; } } [CommandProperty(AccessLevel.GameMaster)] public double Expiration { get { return m_ExpirationDuration; } set { // cap the max value at 100 years if (value > 876000) { m_ExpirationDuration = 876000; } else { m_ExpirationDuration = value; } } } [CommandProperty(AccessLevel.GameMaster)] public TimeSpan ExpiresIn { get { if (m_ExpirationDuration > 0) { // if this is a player created quest, then refresh the expiration time until it is in someone elses possession /* if(PlayerMade && ((Owner == Creator) || (Owner == null))) { m_TimeCreated = DateTime.UtcNow; } */ return (m_TimeCreated + TimeSpan.FromHours(m_ExpirationDuration) - DateTime.UtcNow); } else { return TimeSpan.FromHours(0); } } } [CommandProperty(AccessLevel.GameMaster)] public virtual bool IsExpired { get { if (((m_ExpirationDuration > 0) && (ExpiresIn <= TimeSpan.FromHours(0)))) { return true; } else return false; } } [CommandProperty(AccessLevel.GameMaster)] public virtual bool Repeatable { get { return m_Repeatable; } set { m_Repeatable = value; } } [CommandProperty(AccessLevel.GameMaster)] public virtual TimeSpan NextRepeatable { get { return m_NextRepeatable; } set { m_NextRepeatable = value; } } [CommandProperty(AccessLevel.GameMaster)] public virtual bool AlreadyDone { get { // look for a quest attachment with the current quest name if (XmlAttach.FindAttachment(Owner, typeof(XmlQuestAttachment), Name) == null) return false; return true; } } public virtual string ExpirationString { get { if (AlreadyDone) { return "Already done"; } else if (m_ExpirationDuration <= 0) { return "Never expires"; } else if (IsExpired) { return "Expired"; } else { TimeSpan ts = ExpiresIn; int days = (int)ts.TotalDays; int hours = (int)(ts - TimeSpan.FromDays(days)).TotalHours; int minutes = (int)(ts - TimeSpan.FromHours(hours)).TotalMinutes; int seconds = (int)(ts - TimeSpan.FromMinutes(minutes)).TotalSeconds; if (days > 0) { return String.Format("Expires in {0} days {1} hrs", days, hours); } else if (hours > 0) { return String.Format("Expires in {0} hrs {1} mins", hours, minutes); } else { return String.Format("Expires in {0} mins {1} secs", minutes, seconds); } } } } [CommandProperty(AccessLevel.GameMaster)] public virtual bool IsValid { get { if (WasMoved || IsExpired) { // eliminate reward definitions RewardString = null; AttachmentString = null; // return any reward items ReturnReward(); // and get rid of the pack if (Pack != null) Pack.Delete(); return false; } else if (AlreadyDone) { return false; } else return true; } } [CommandProperty(AccessLevel.GameMaster)] public virtual bool IsCompleted { get { if (IsValid && (Completed1 || Objective1 == null || (Objective1.Length == 0)) && (Completed2 || Objective2 == null || (Objective2.Length == 0)) && (Completed3 || Objective3 == null || (Objective3.Length == 0)) && (Completed4 || Objective4 == null || (Objective4.Length == 0)) && (Completed5 || Objective5 == null || (Objective5.Length == 0)) ) return true; else return false; } } public bool HandlesOnSkillUse { get { return (IsValid && m_SkillTrigger != null && m_SkillTrigger.Length > 0); } } public void OnSkillUse(Mobile m, Skill skill, bool success) { } private void CheckOwnerFlag() { if (Owner != null && !Owner.Deleted) { // need to check to see if any other questtoken items are owned // search the Owners top level pack for an xmlquesttoken List list = XmlQuest.FindXmlQuest(Owner); if (list == null || list.Count == 0) { // if none remain then flag the ower as having none Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, false); } } } public virtual void Invalidate() { //Hue = 32; //LootType = LootType.Regular; if (Owner != null) { Owner.SendMessage(String.Format("Quest invalidated - '{0}' removed", Name)); } this.Delete(); } public void CheckRewardItem() { // go through all reward items and delete anything that is movable. This blocks any exploits where players might // try to add items themselves if (m_RewardItem != null && !m_RewardItem.Deleted && m_RewardItem is Container) { foreach (Item i in ((Container)m_RewardItem).FindItemsByType(typeof(Item), true)) { if (i.Movable) { i.Delete(); } } } } public void CheckAutoReward() { if (!this.Deleted && AutoReward && IsCompleted && Owner != null && ((RewardItem != null && !m_RewardItem.Deleted) || (RewardAttachment != null && !m_RewardAttachment.Deleted))) { if (RewardItem != null) { // make sure nothing has been added to the pack other than the original reward items CheckRewardItem(); m_RewardItem.Movable = true; if (m_Pack != null) { // make sure all of the items in the pack are movable as well PackItemsMovable(m_Pack, true); } //RefreshPackLocation(Owner, false); Owner.AddToBackpack(m_RewardItem); //AddMobileWeight(Owner,m_RewardItem); m_RewardItem = null; } if (RewardAttachment != null) { Timer.DelayCall(TimeSpan.Zero, new TimerStateCallback(AttachToCallback), new object[] { Owner, m_RewardAttachment }); m_RewardAttachment = null; } Owner.SendMessage(String.Format("{0} completed. You receive the quest reward!", Name)); this.Delete(); } } public void AttachToCallback(object state) { object[] args = (object[])state; XmlAttach.AttachTo(args[0], (XmlAttachment)args[1]); } private const string XmlTableName = "Properties"; private const string XmlDataSetName = "XmlQuestToken"; public void LoadXmlConfig(string filename) { if (filename == null || filename.Length <= 0) return; // Check if the file exists if (System.IO.File.Exists(filename) == true) { FileStream fs = null; try { fs = File.Open(filename, FileMode.Open, FileAccess.Read); } catch { } if (fs == null) { Status = String.Format("Unable to open {0} for loading", filename); return; } // Create the data set DataSet ds = new DataSet(XmlDataSetName); // Read in the file //ds.ReadXml( e.Arguments[0].ToString() ); bool fileerror = false; try { ds.ReadXml(fs); } catch { fileerror = true; } // close the file fs.Close(); if (fileerror) { Console.WriteLine("XmlQuestToken: Error in XML config file '{0}'", filename); return; } // Check that at least a single table was loaded if (ds.Tables != null && ds.Tables.Count > 0) { if (ds.Tables[XmlTableName] != null && ds.Tables[XmlTableName].Rows.Count > 0) { foreach (DataRow dr in ds.Tables[XmlTableName].Rows) { bool valid_entry; string strEntry = null; bool boolEntry = true; double doubleEntry = 0; int intEntry = 0; TimeSpan timespanEntry = TimeSpan.Zero; valid_entry = true; try { strEntry = (string)dr["Name"]; } catch { valid_entry = false; } if (valid_entry) { this.Name = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Title"]; } catch { valid_entry = false; } if (valid_entry) { this.TitleString = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Note"]; } catch { valid_entry = false; } if (valid_entry) { this.NoteString = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Reward"]; } catch { valid_entry = false; } if (valid_entry) { this.RewardString = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Attachment"]; } catch { valid_entry = false; } if (valid_entry) { this.AttachmentString = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Objective1"]; } catch { valid_entry = false; } if (valid_entry) { this.Objective1 = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Objective2"]; } catch { valid_entry = false; } if (valid_entry) { this.Objective2 = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Objective3"]; } catch { valid_entry = false; } if (valid_entry) { this.Objective3 = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Objective4"]; } catch { valid_entry = false; } if (valid_entry) { this.Objective4 = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Objective5"]; } catch { valid_entry = false; } if (valid_entry) { this.Objective5 = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Description1"]; } catch { valid_entry = false; } if (valid_entry) { this.Description1 = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Description2"]; } catch { valid_entry = false; } if (valid_entry) { this.Description2 = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Description3"]; } catch { valid_entry = false; } if (valid_entry) { this.Description3 = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Description4"]; } catch { valid_entry = false; } if (valid_entry) { this.Description4 = strEntry; } valid_entry = true; strEntry = null; try { strEntry = (string)dr["Description5"]; } catch { valid_entry = false; } if (valid_entry) { this.Description5 = strEntry; } valid_entry = true; boolEntry = false; try { boolEntry = bool.Parse((string)dr["PartyEnabled"]); } catch { valid_entry = false; } if (valid_entry) { this.PartyEnabled = boolEntry; } valid_entry = true; boolEntry = false; try { boolEntry = bool.Parse((string)dr["AutoReward"]); } catch { valid_entry = false; } if (valid_entry) { this.AutoReward = boolEntry; } valid_entry = true; boolEntry = true; try { boolEntry = bool.Parse((string)dr["CanSeeReward"]); } catch { valid_entry = false; } if (valid_entry) { this.CanSeeReward = boolEntry; } valid_entry = true; boolEntry = true; try { boolEntry = bool.Parse((string)dr["Repeatable"]); } catch { valid_entry = false; } if (valid_entry) { this.m_Repeatable = boolEntry; } valid_entry = true; timespanEntry = TimeSpan.Zero; try { timespanEntry = TimeSpan.Parse((string)dr["NextRepeatable"]); } catch { valid_entry = false; } if (valid_entry) { this.m_NextRepeatable = timespanEntry; } valid_entry = true; boolEntry = false; try { boolEntry = bool.Parse((string)dr["PlayerMade"]); } catch { valid_entry = false; } if (valid_entry) { this.PlayerMade = boolEntry; } valid_entry = true; intEntry = 0; try { intEntry = int.Parse((string)dr["PartyRange"]); } catch { valid_entry = false; } if (valid_entry) { this.PartyRange = intEntry; } valid_entry = true; doubleEntry = 0; try { doubleEntry = double.Parse((string)dr["Expiration"]); } catch { valid_entry = false; } if (valid_entry) { this.Expiration = doubleEntry; } } } } } } } }