Reorganizes Project (#41)

This commit is contained in:
Kamron Batman 2019-08-02 18:13:40 -07:00 committed by GitHub
parent 08bf44af9a
commit 3614a66aee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3499 changed files with 79 additions and 55 deletions

View file

@ -0,0 +1,121 @@
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests
{
public class TalkEntry : ContextMenuEntry
{
private BaseQuester m_Quester;
public TalkEntry(BaseQuester quester) : base(quester.TalkNumber)
{
m_Quester = quester;
}
public override void OnClick()
{
Mobile from = Owner.From;
if (from.CheckAlive() && from is PlayerMobile mobile && m_Quester.CanTalkTo(mobile))
m_Quester.OnTalk(mobile, true);
}
}
public abstract class BaseQuester : BaseVendor
{
protected List<SBInfo> m_SBInfos = new List<SBInfo>();
public BaseQuester(string title = null) : base(title)
{
}
public BaseQuester(Serial serial) : base(serial)
{
}
protected override List<SBInfo> SBInfos => m_SBInfos;
public override bool IsActiveVendor => false;
public override bool IsInvulnerable => true;
public override bool DisallowAllMoves => true;
public override bool ClickTitle => false;
public override bool CanTeach => false;
public virtual int TalkNumber // Talk
=> 6146;
public override void InitSBInfo()
{
}
public abstract void OnTalk(PlayerMobile player, bool contextMenu);
public virtual bool CanTalkTo(PlayerMobile to)
{
return true;
}
public virtual int GetAutoTalkRange(PlayerMobile m)
{
return -1;
}
public override bool CanBeDamaged()
{
return false;
}
protected Item SetHue(Item item, int hue)
{
item.Hue = hue;
return item;
}
public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
{
base.AddCustomContextEntries(from, list);
if (from.Alive && from is PlayerMobile mobile && TalkNumber > 0 && CanTalkTo(mobile))
list.Add(new TalkEntry(this));
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (m.Alive && m is PlayerMobile pm)
{
int range = GetAutoTalkRange(pm);
if (pm.Alive && range >= 0 && InRange(m, range) && !InRange(oldLocation, range) && CanTalkTo(pm))
OnTalk(pm, false);
}
}
public void FocusTo(Mobile to)
{
QuestSystem.FocusTo(this, to);
}
public static Container GetNewContainer()
{
Bag bag = new Bag();
bag.Hue = QuestSystem.RandomBrightHue();
return bag;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,61 @@
using Server.Mobiles;
namespace Server.Engines.Quests
{
public abstract class DynamicTeleporter : Item
{
public DynamicTeleporter(int itemID = 0x1822, int hue = 0x482) : base(itemID)
{
Movable = false;
Hue = hue;
}
public DynamicTeleporter(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1049382; // a magical teleporter
public virtual int NotWorkingMessage // Nothing Happens.
=> 500309;
public abstract bool GetDestination(PlayerMobile player, ref Point3D loc, ref Map map);
public override bool OnMoveOver(Mobile m)
{
if (m is PlayerMobile pm)
{
Point3D loc = Point3D.Zero;
Map map = null;
if (GetDestination(pm, ref loc, ref map))
{
BaseCreature.TeleportPets(pm, loc, map);
pm.PlaySound(0x1FE);
pm.MoveToWorld(loc, map);
return false;
}
pm.SendLocalizedMessage(NotWorkingMessage);
}
return base.OnMoveOver(m);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,189 @@
using Server.Network;
namespace Server.Items
{
public class EnchantedSextant : Item
{
private const double m_LongDistance = 300.0;
private const double m_ShortDistance = 5.0;
//TODO: Trammel/Haven
private static readonly Point2D[] m_TrammelBanks =
{
new Point2D(652, 820),
new Point2D(1813, 2825),
new Point2D(3734, 2149),
new Point2D(2503, 552),
new Point2D(3764, 1317),
new Point2D(587, 2146),
new Point2D(1655, 1606),
new Point2D(1425, 1690),
new Point2D(4471, 1156),
new Point2D(1317, 3773),
new Point2D(2881, 684),
new Point2D(2731, 2192),
new Point2D(3620, 2617),
new Point2D(2880, 3472),
new Point2D(1897, 2684),
new Point2D(5346, 74),
new Point2D(5275, 3977),
new Point2D(5669, 3131)
};
private static readonly Point2D[] m_FeluccaBanks =
{
new Point2D(652, 820),
new Point2D(1813, 2825),
new Point2D(3734, 2149),
new Point2D(2503, 552),
new Point2D(3764, 1317),
new Point2D(3695, 2511),
new Point2D(587, 2146),
new Point2D(1655, 1606),
new Point2D(1425, 1690),
new Point2D(4471, 1156),
new Point2D(1317, 3773),
new Point2D(2881, 684),
new Point2D(2731, 2192),
new Point2D(2880, 3472),
new Point2D(1897, 2684),
new Point2D(5346, 74),
new Point2D(5275, 3977),
new Point2D(5669, 3131)
};
private static readonly Point2D[] m_IlshenarBanks =
{
new Point2D(854, 680),
new Point2D(855, 603),
new Point2D(1226, 554),
new Point2D(1610, 556)
};
private static readonly Point2D[] m_MalasBanks =
{
new Point2D(996, 519),
new Point2D(2048, 1345)
};
[Constructible]
public EnchantedSextant() : base(0x1058)
{
Weight = 2.0;
}
public EnchantedSextant(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1046226; // an enchanted sextant
public override void OnDoubleClick(Mobile from)
{
if (!from.InRange(GetWorldLocation(), 2))
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
return;
}
Point2D[] banks;
PMList moongates;
if (from.Map == Map.Trammel)
{
banks = m_TrammelBanks;
moongates = PMList.Trammel;
}
else if (from.Map == Map.Felucca)
{
banks = m_FeluccaBanks;
moongates = PMList.Felucca;
}
else if (from.Map == Map.Ilshenar)
{
#if false
banks = m_IlshenarBanks;
moongates = PMList.Ilshenar;
#else
from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, 0x482, 3, 1061684, "",
"")); // The magic of the sextant fails...
return;
#endif
}
else if (from.Map == Map.Malas)
{
banks = m_MalasBanks;
moongates = PMList.Malas;
}
else
{
banks = null;
moongates = null;
}
Point3D closestMoongate = Point3D.Zero;
double moongateDistance = double.MaxValue;
if (moongates != null)
foreach (PMEntry entry in moongates.Entries)
{
double dist = from.GetDistanceToSqrt(entry.Location);
if (moongateDistance > dist)
{
closestMoongate = entry.Location;
moongateDistance = dist;
}
}
Point2D closestBank = Point2D.Zero;
double bankDistance = double.MaxValue;
if (banks != null)
foreach (Point2D p in banks)
{
double dist = from.GetDistanceToSqrt(p);
if (bankDistance > dist)
{
closestBank = p;
bankDistance = dist;
}
}
int moonMsg;
if (moongateDistance == double.MaxValue)
moonMsg = 1048021; // The sextant fails to find a Moongate nearby.
else if (moongateDistance > m_LongDistance)
moonMsg = 1046449 + (int)from.GetDirectionTo(closestMoongate); // A moongate is * from here
else if (moongateDistance > m_ShortDistance)
moonMsg = 1048010 + (int)from.GetDirectionTo(closestMoongate); // There is a Moongate * of here.
else
moonMsg = 1048018; // You are next to a Moongate at the moment.
from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, 0x482, 3, moonMsg, "", ""));
int bankMsg;
if (bankDistance == double.MaxValue)
bankMsg = 1048020; // The sextant fails to find a Bank nearby.
else if (bankDistance > m_LongDistance)
bankMsg = 1046462 + (int)from.GetDirectionTo(closestBank); // A town is * from here
else if (bankDistance > m_ShortDistance)
bankMsg = 1048002 + (int)from.GetDirectionTo(closestBank); // There is a city Bank * of here.
else
bankMsg = 1048019; // You are next to a Bank at the moment.
from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, 0x5AA, 3, bankMsg, "", ""));
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,195 @@
using System;
using Server.Items;
using Server.Regions;
namespace Server.Engines.Quests
{
public class HornOfRetreat : Item
{
private int m_Charges;
private Timer m_PlayTimer;
[Constructible]
public HornOfRetreat() : base(0xFC4)
{
Hue = 0x482;
Weight = 1.0;
Charges = 10;
}
public HornOfRetreat(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public Point3D DestLoc{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public Map DestMap{ get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int Charges
{
get => m_Charges;
set
{
m_Charges = value;
InvalidateProperties();
}
}
public override int LabelNumber => 1049117; // Horn of Retreat
public virtual bool ValidateUse(Mobile from)
{
return true;
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
list.Add(1060741, m_Charges.ToString()); // charges: ~1_val~
}
public override void OnDoubleClick(Mobile from)
{
if (IsChildOf(from.Backpack))
{
if (!ValidateUse(from))
{
SendLocalizedMessageTo(from, 500309); // Nothing Happens.
}
else if (Core.ML && from.Map != Map.Trammel && from.Map != Map.Malas)
{
from.SendLocalizedMessage(1076154); // You can only use this in Trammel and Malas.
}
else if (m_PlayTimer != null)
{
SendLocalizedMessageTo(from, 1042144); // This is currently in use.
}
else if (Charges > 0)
{
from.Animate(34, 7, 1, true, false, 0);
from.PlaySound(0xFF);
from.SendLocalizedMessage(1049115); // You play the horn and a sense of peace overcomes you...
--Charges;
m_PlayTimer = Timer.DelayCall(TimeSpan.FromSeconds(5.0), () => PlayTimer_Callback(from));
}
else
{
SendLocalizedMessageTo(from, 1042544); // This item is out of charges.
}
}
else
{
SendLocalizedMessageTo(from, 1042001); // That must be in your pack for you to use it.
}
}
public virtual void PlayTimer_Callback(Mobile from)
{
m_PlayTimer = null;
HornOfRetreatMoongate gate = new HornOfRetreatMoongate(DestLoc, DestMap, from, Hue);
gate.MoveToWorld(from.Location, from.Map);
from.PlaySound(0x20E);
gate.SendLocalizedMessageTo(from, 1049102, from.Name); // Quickly ~1_NAME~! Onward through the gate!
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(DestLoc);
writer.Write(DestMap);
writer.Write(m_Charges);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
DestLoc = reader.ReadPoint3D();
DestMap = reader.ReadMap();
m_Charges = reader.ReadInt();
break;
}
}
}
}
public class HornOfRetreatMoongate : Moongate
{
private Mobile m_Caster;
public HornOfRetreatMoongate(Point3D destLoc, Map destMap, Mobile caster, int hue)
{
m_Caster = caster;
Target = destLoc;
TargetMap = destMap;
Hue = hue;
Light = LightType.Circle300;
Dispellable = false;
Timer.DelayCall(TimeSpan.FromSeconds(10.0), Delete);
}
public HornOfRetreatMoongate(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1049114; // Sanctuary Gate
public override void BeginConfirmation(Mobile from)
{
EndConfirmation(from);
}
public override void UseGate(Mobile m)
{
if (m.Region.IsPartOf<Jail>())
{
m.SendLocalizedMessage(1114345); // You'll need a better jailbreak plan than that!
}
else if (m == m_Caster)
{
base.UseGate(m);
Delete();
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Delete();
}
}
}

View file

@ -0,0 +1,92 @@
using Server.Mobiles;
namespace Server.Engines.Quests
{
public abstract class QuestItem : Item
{
public QuestItem(int itemID) : base(itemID)
{
}
public QuestItem(Serial serial) : base(serial)
{
}
public virtual bool Accepted => Deleted;
public abstract bool CanDrop(PlayerMobile pm);
public override bool DropToWorld(Mobile from, Point3D p)
{
bool ret = base.DropToWorld(from, p);
if (ret && !Accepted && Parent != from.Backpack)
{
if (from.AccessLevel > AccessLevel.Player) return true;
if (!(from is PlayerMobile) || CanDrop((PlayerMobile)from)) return true;
from.SendLocalizedMessage(
1049343); // You can only drop quest items into the top-most level of your backpack while you still need them for your quest.
return false;
}
return ret;
}
public override bool DropToMobile(Mobile from, Mobile target, Point3D p)
{
bool ret = base.DropToMobile(from, target, p);
if (ret && !Accepted && Parent != from.Backpack)
{
if (from.AccessLevel > AccessLevel.Player) return true;
if (!(from is PlayerMobile) || CanDrop((PlayerMobile)from)) return true;
from.SendLocalizedMessage(
1049344); // You decide against trading the item. You still need it for your quest.
return false;
}
return ret;
}
public override bool DropToItem(Mobile from, Item target, Point3D p)
{
bool ret = base.DropToItem(from, target, p);
if (ret && !Accepted && Parent != from.Backpack)
{
if (from.AccessLevel > AccessLevel.Player) return true;
if (!(from is PlayerMobile) || CanDrop((PlayerMobile)from)) return true;
from.SendLocalizedMessage(
1049343); // You can only drop quest items into the top-most level of your backpack while you still need them for your quest.
return false;
}
return ret;
}
public override DeathMoveResult OnParentDeath(Mobile parent)
{
if (parent is PlayerMobile mobile && !CanDrop(mobile))
return DeathMoveResult.MoveToBackpack;
return base.OnParentDeath(parent);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,23 @@
using Server.ContextMenus;
namespace Server.Engines.Quests
{
public class QuestCallbackEntry : ContextMenuEntry
{
private QuestCallback m_Callback;
public QuestCallbackEntry(int number, QuestCallback callback) : this(number, -1, callback)
{
}
public QuestCallbackEntry(int number, int range, QuestCallback callback) : base(number, range)
{
m_Callback = callback;
}
public override void OnClick()
{
m_Callback?.Invoke();
}
}
}

View file

@ -0,0 +1,138 @@
using System.Collections.Generic;
using Server.Gumps;
using Server.Network;
namespace Server.Engines.Quests
{
public abstract class QuestConversation
{
public abstract object Message{ get; }
public virtual QuestItemInfo[] Info => null;
public virtual bool Logged => true;
public QuestSystem System{ get; set; }
public bool HasBeenRead{ get; set; }
public virtual void BaseDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
switch (version)
{
case 0:
{
HasBeenRead = reader.ReadBool();
break;
}
}
ChildDeserialize(reader);
}
public virtual void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
}
public virtual void BaseSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(HasBeenRead);
ChildSerialize(writer);
}
public virtual void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
}
public virtual void OnRead()
{
}
}
public class QuestConversationsGump : BaseQuestGump
{
private List<QuestConversation> m_Conversations;
public QuestConversationsGump(QuestConversation conv) : this(new List<QuestConversation>{ conv })
{
}
public QuestConversationsGump(List<QuestConversation> conversations) : base(30, 50)
{
m_Conversations = conversations;
Closable = false;
AddPage(0);
AddImage(349, 10, 9392);
AddImageTiled(349, 130, 100, 120, 9395);
AddImageTiled(149, 10, 200, 140, 9391);
AddImageTiled(149, 250, 200, 140, 9397);
AddImage(349, 250, 9398);
AddImage(35, 10, 9390);
AddImageTiled(35, 150, 120, 100, 9393);
AddImage(35, 250, 9396);
AddHtmlLocalized(110, 60, 200, 20, 1049069, White); // <STRONG>Conversation Event</STRONG>
AddImage(65, 14, 10102);
AddImageTiled(81, 14, 349, 17, 10101);
AddImage(426, 14, 10104);
AddImageTiled(55, 40, 388, 323, 2624);
AddAlphaRegion(55, 40, 388, 323);
AddImageTiled(75, 90, 200, 1, 9101);
AddImage(75, 58, 9781);
AddImage(380, 45, 223);
AddButton(220, 335, 2313, 2312, 1);
AddImage(0, 0, 10440);
AddPage(1);
for (int i = 0; i < conversations.Count; ++i)
{
QuestConversation conv = conversations[conversations.Count - 1 - i];
if (i > 0)
{
AddButton(65, 366, 9909, 9911, 0, GumpButtonType.Page, 1 + i);
AddHtmlLocalized(90, 367, 50, 20, 1043354, Black); // Previous
AddPage(1 + i);
}
AddHtmlObject(70, 110, 365, 220, conv.Message, LightGreen, false, true);
if (i > 0)
{
AddButton(420, 366, 9903, 9905, 0, GumpButtonType.Page, i);
AddHtmlLocalized(370, 367, 50, 20, 1043353, Black); // Next
}
}
}
public override void OnResponse(NetState sender, RelayInfo info)
{
for (int i = m_Conversations.Count - 1; i >= 0; --i)
{
QuestConversation qc = m_Conversations[i];
if (!qc.HasBeenRead)
{
qc.HasBeenRead = true;
qc.OnRead();
}
}
}
}
}

View file

@ -0,0 +1,57 @@
namespace Server.Engines.Quests
{
public class QuestItemInfo
{
public QuestItemInfo(object name, int itemID)
{
Name = name;
ItemID = itemID;
}
public object Name{ get; set; }
public int ItemID{ get; set; }
}
public class QuestItemInfoGump : BaseQuestGump
{
public QuestItemInfoGump(QuestItemInfo[] info) : base(485, 75)
{
int height = 100 + info.Length * 75;
AddPage(0);
AddBackground(5, 10, 145, height, 5054);
AddImageTiled(13, 20, 125, 10, 2624);
AddAlphaRegion(13, 20, 125, 10);
AddImageTiled(13, height - 10, 128, 10, 2624);
AddAlphaRegion(13, height - 10, 128, 10);
AddImageTiled(13, 20, 10, height - 30, 2624);
AddAlphaRegion(13, 20, 10, height - 30);
AddImageTiled(131, 20, 10, height - 30, 2624);
AddAlphaRegion(131, 20, 10, height - 30);
AddHtmlLocalized(67, 35, 120, 20, 1011233, White); // INFO
AddImage(62, 52, 9157);
AddImage(72, 52, 9157);
AddImage(82, 52, 9157);
AddButton(25, 31, 1209, 1210, 777);
AddPage(1);
for (int i = 0; i < info.Length; ++i)
{
QuestItemInfo cur = info[i];
AddHtmlObject(25, 65 + i * 75, 110, 20, cur.Name, 1153, false, false);
AddItem(45, 85 + i * 75, cur.ItemID);
}
}
}
}

View file

@ -0,0 +1,255 @@
using System.Collections.Generic;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests
{
public abstract class QuestObjective
{
private int m_CurProgress;
public abstract object Message{ get; }
public virtual int MaxProgress => 1;
public virtual QuestItemInfo[] Info => null;
public QuestSystem System{ get; set; }
public bool HasBeenRead{ get; set; }
public int CurProgress
{
get => m_CurProgress;
set
{
m_CurProgress = value;
CheckCompletionStatus();
}
}
public bool HasCompleted{ get; set; }
public virtual bool Completed => m_CurProgress >= MaxProgress;
public bool IsSingleObjective => MaxProgress == 1;
public virtual void BaseDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
switch (version)
{
case 1:
{
HasBeenRead = reader.ReadBool();
goto case 0;
}
case 0:
{
m_CurProgress = reader.ReadEncodedInt();
HasCompleted = reader.ReadBool();
break;
}
}
ChildDeserialize(reader);
}
public virtual void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
}
public virtual void BaseSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(1); // version
writer.Write(HasBeenRead);
writer.WriteEncodedInt(m_CurProgress);
writer.Write(HasCompleted);
ChildSerialize(writer);
}
public virtual void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
}
public virtual void Complete()
{
CurProgress = MaxProgress;
}
public virtual void RenderMessage(BaseQuestGump gump)
{
gump.AddHtmlObject(70, 130, 300, 100, Message, BaseQuestGump.Blue, false, false);
}
public virtual void RenderProgress(BaseQuestGump gump)
{
gump.AddHtmlObject(70, 260, 270, 100, Completed ? 1049077 : 1049078, BaseQuestGump.Blue, false, false);
}
public virtual void CheckCompletionStatus()
{
if (Completed && !HasCompleted)
{
HasCompleted = true;
OnComplete();
}
}
public virtual void OnRead()
{
}
public virtual bool GetTimerEvent()
{
return !Completed;
}
public virtual void CheckProgress()
{
}
public virtual void OnComplete()
{
}
public virtual bool GetKillEvent(BaseCreature creature, Container corpse)
{
return !Completed;
}
public virtual void OnKill(BaseCreature creature, Container corpse)
{
}
public virtual bool IgnoreYoungProtection(Mobile from)
{
return false;
}
}
public class QuestLogUpdatedGump : BaseQuestGump
{
private QuestSystem m_System;
public QuestLogUpdatedGump(QuestSystem system) : base(3, 30)
{
m_System = system;
AddPage(0);
AddImage(20, 5, 1417);
AddHtmlLocalized(0, 78, 120, 40, 1049079, White); // Quest Log Updated
AddImageTiled(0, 78, 120, 40, 2624);
AddAlphaRegion(0, 78, 120, 40);
AddButton(30, 15, 5575, 5576, 1);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (info.ButtonID == 1)
m_System.ShowQuestLog();
}
}
public class QuestObjectivesGump : BaseQuestGump
{
private List<QuestObjective> m_Objectives;
public QuestObjectivesGump(QuestObjective obj) : this(new List<QuestObjective>{ obj })
{
}
public QuestObjectivesGump(List<QuestObjective> objectives) : base(90, 50)
{
m_Objectives = objectives;
Closable = false;
AddPage(0);
AddImage(0, 0, 3600);
AddImageTiled(0, 14, 15, 375, 3603);
AddImageTiled(380, 14, 14, 375, 3605);
AddImage(0, 376, 3606);
AddImageTiled(15, 376, 370, 16, 3607);
AddImageTiled(15, 0, 370, 16, 3601);
AddImage(380, 0, 3602);
AddImage(380, 376, 3608);
AddImageTiled(15, 15, 365, 365, 2624);
AddAlphaRegion(15, 15, 365, 365);
AddImage(20, 87, 1231);
AddImage(75, 62, 9307);
AddHtmlLocalized(117, 35, 230, 20, 1046026, Blue); // Quest Log
AddImage(77, 33, 9781);
AddImage(65, 110, 2104);
AddHtmlLocalized(79, 106, 230, 20, 1049073, Blue); // Objective:
AddImageTiled(68, 125, 120, 1, 9101);
AddImage(65, 240, 2104);
AddHtmlLocalized(79, 237, 230, 20, 1049076, Blue); // Progress details:
AddImageTiled(68, 255, 120, 1, 9101);
AddButton(175, 355, 2313, 2312, 1);
AddImage(341, 15, 10450);
AddImage(341, 330, 10450);
AddImage(15, 330, 10450);
AddImage(15, 15, 10450);
AddPage(1);
for (int i = 0; i < objectives.Count; ++i)
{
QuestObjective obj = objectives[objectives.Count - 1 - i];
if (i > 0)
{
AddButton(55, 346, 9909, 9911, 0, GumpButtonType.Page, 1 + i);
AddHtmlLocalized(82, 347, 50, 20, 1043354, White); // Previous
AddPage(1 + i);
}
obj.RenderMessage(this);
obj.RenderProgress(this);
if (i > 0)
{
AddButton(317, 346, 9903, 9905, 0, GumpButtonType.Page, i);
AddHtmlLocalized(278, 347, 50, 20, 1043353, White); // Next
}
}
}
public override void OnResponse(NetState sender, RelayInfo info)
{
for (int i = m_Objectives.Count - 1; i >= 0; --i)
{
QuestObjective obj = m_Objectives[i];
if (!obj.HasBeenRead)
{
obj.HasBeenRead = true;
obj.OnRead();
}
}
}
}
}

View file

@ -0,0 +1,31 @@
using System;
namespace Server.Engines.Quests
{
public class QuestRestartInfo
{
public QuestRestartInfo(Type questType, TimeSpan restartDelay)
{
QuestType = questType;
Reset(restartDelay);
}
public QuestRestartInfo(Type questType, DateTime restartTime)
{
QuestType = questType;
RestartTime = restartTime;
}
public Type QuestType{ get; set; }
public DateTime RestartTime{ get; set; }
public void Reset(TimeSpan restartDelay)
{
if (restartDelay < TimeSpan.MaxValue)
RestartTime = DateTime.UtcNow + restartDelay;
else
RestartTime = DateTime.MaxValue;
}
}
}

View file

@ -0,0 +1,188 @@
using System;
namespace Server.Engines.Quests
{
public class QuestSerializer
{
public static object Construct(Type type)
{
try
{
return Activator.CreateInstance(type);
}
catch
{
return null;
}
}
public static void Write(Type type, Type[] referenceTable, GenericWriter writer)
{
if (type == null)
{
writer.WriteEncodedInt(0x00);
}
else
{
for (int i = 0; i < referenceTable.Length; ++i)
if (referenceTable[i] == type)
{
writer.WriteEncodedInt(0x01);
writer.WriteEncodedInt(i);
return;
}
writer.WriteEncodedInt(0x02);
writer.Write(type.FullName);
}
}
public static Type ReadType(Type[] referenceTable, GenericReader reader)
{
int encoding = reader.ReadEncodedInt();
switch (encoding)
{
default:
{
return null;
}
case 0x01: // indexed
{
int index = reader.ReadEncodedInt();
if (index >= 0 && index < referenceTable.Length)
return referenceTable[index];
return null;
}
case 0x02: // by name
{
string fullName = reader.ReadString();
if (fullName == null)
return null;
return ScriptCompiler.FindTypeByFullName(fullName, false);
}
}
}
public static QuestSystem DeserializeQuest(GenericReader reader)
{
int encoding = reader.ReadEncodedInt();
switch (encoding)
{
default:
{
return null;
}
case 0x01:
{
Type type = ReadType(QuestSystem.QuestTypes, reader);
QuestSystem qs = Construct(type) as QuestSystem;
qs?.BaseDeserialize(reader);
return qs;
}
}
}
public static void Serialize(QuestSystem qs, GenericWriter writer)
{
if (qs == null)
{
writer.WriteEncodedInt(0x00);
}
else
{
writer.WriteEncodedInt(0x01);
Write(qs.GetType(), QuestSystem.QuestTypes, writer);
qs.BaseSerialize(writer);
}
}
public static QuestObjective DeserializeObjective(Type[] referenceTable, GenericReader reader)
{
int encoding = reader.ReadEncodedInt();
switch (encoding)
{
default:
{
return null;
}
case 0x01:
{
Type type = ReadType(referenceTable, reader);
QuestObjective obj = Construct(type) as QuestObjective;
obj?.BaseDeserialize(reader);
return obj;
}
}
}
public static void Serialize(Type[] referenceTable, QuestObjective obj, GenericWriter writer)
{
if (obj == null)
{
writer.WriteEncodedInt(0x00);
}
else
{
writer.WriteEncodedInt(0x01);
Write(obj.GetType(), referenceTable, writer);
obj.BaseSerialize(writer);
}
}
public static QuestConversation DeserializeConversation(Type[] referenceTable, GenericReader reader)
{
int encoding = reader.ReadEncodedInt();
switch (encoding)
{
default:
{
return null;
}
case 0x01:
{
Type type = ReadType(referenceTable, reader);
QuestConversation conv = Construct(type) as QuestConversation;
conv?.BaseDeserialize(reader);
return conv;
}
}
}
public static void Serialize(Type[] referenceTable, QuestConversation conv, GenericWriter writer)
{
if (conv == null)
{
writer.WriteEncodedInt(0x00);
}
else
{
writer.WriteEncodedInt(0x01);
Write(conv.GetType(), referenceTable, writer);
conv.BaseSerialize(writer);
}
}
}
}

View file

@ -0,0 +1,667 @@
using System;
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Engines.Quests.Ambitious;
using Server.Engines.Quests.Collector;
using Server.Engines.Quests.Doom;
using Server.Engines.Quests.Hag;
using Server.Engines.Quests.Haven;
using Server.Engines.Quests.Matriarch;
using Server.Engines.Quests.Naturalist;
using Server.Engines.Quests.Necro;
using Server.Engines.Quests.Ninja;
using Server.Engines.Quests.Samurai;
using Server.Engines.Quests.Zento;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests
{
public delegate void QuestCallback();
public abstract class QuestSystem
{
public static readonly Type[] QuestTypes =
{
typeof(TheSummoningQuest),
typeof(DarkTidesQuest),
typeof(UzeraanTurmoilQuest),
typeof(CollectorQuest),
typeof(WitchApprenticeQuest),
typeof(StudyOfSolenQuest),
typeof(SolenMatriarchQuest),
typeof(AmbitiousQueenQuest),
typeof(EminosUndertakingQuest),
typeof(HaochisTrialsQuest),
typeof(TerribleHatchlingsQuest)
};
private Timer m_Timer;
public QuestSystem(PlayerMobile from)
{
From = from;
Objectives = new List<QuestObjective>();
Conversations = new List<QuestConversation>();
}
public QuestSystem()
{
}
public abstract object Name{ get; }
public abstract object OfferMessage{ get; }
public abstract int Picture{ get; }
public abstract bool IsTutorial{ get; }
public abstract TimeSpan RestartDelay{ get; }
public abstract Type[] TypeReferenceTable{ get; }
public PlayerMobile From{ get; set; }
public List<QuestObjective> Objectives{ get; set; }
public List<QuestConversation> Conversations{ get; set; }
public virtual void StartTimer()
{
if (m_Timer != null)
return;
m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), Slice);
}
public virtual void StopTimer()
{
m_Timer?.Stop();
m_Timer = null;
}
public virtual void Slice()
{
for (int i = Objectives.Count - 1; i >= 0; --i)
{
QuestObjective obj = Objectives[i];
if (obj.GetTimerEvent())
obj.CheckProgress();
}
}
public virtual void OnKill(BaseCreature creature, Container corpse)
{
for (int i = Objectives.Count - 1; i >= 0; --i)
{
QuestObjective obj = Objectives[i];
if (obj.GetKillEvent(creature, corpse))
obj.OnKill(creature, corpse);
}
}
public virtual bool IgnoreYoungProtection(Mobile from)
{
for (int i = Objectives.Count - 1; i >= 0; --i)
{
QuestObjective obj = Objectives[i];
if (obj.IgnoreYoungProtection(from))
return true;
}
return false;
}
public virtual void BaseDeserialize(GenericReader reader)
{
Type[] referenceTable = TypeReferenceTable;
int version = reader.ReadEncodedInt();
switch (version)
{
case 0:
{
int count = reader.ReadEncodedInt();
Objectives = new List<QuestObjective>(count);
for (int i = 0; i < count; ++i)
{
QuestObjective obj = QuestSerializer.DeserializeObjective(referenceTable, reader);
if (obj != null)
{
obj.System = this;
Objectives.Add(obj);
}
}
count = reader.ReadEncodedInt();
Conversations = new List<QuestConversation>(count);
for (int i = 0; i < count; ++i)
{
QuestConversation conv = QuestSerializer.DeserializeConversation(referenceTable, reader);
if (conv != null)
{
conv.System = this;
Conversations.Add(conv);
}
}
break;
}
}
ChildDeserialize(reader);
}
public virtual void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
}
public virtual void BaseSerialize(GenericWriter writer)
{
Type[] referenceTable = TypeReferenceTable;
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt(Objectives.Count);
for (int i = 0; i < Objectives.Count; ++i)
QuestSerializer.Serialize(referenceTable, Objectives[i], writer);
writer.WriteEncodedInt(Conversations.Count);
for (int i = 0; i < Conversations.Count; ++i)
QuestSerializer.Serialize(referenceTable, Conversations[i], writer);
ChildSerialize(writer);
}
public virtual void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
}
public bool IsObjectiveInProgress(Type type)
{
QuestObjective obj = FindObjective(type);
return obj?.Completed == false;
}
public T FindObjective<T>() where T : QuestObjective
{
for (int i = Objectives.Count - 1; i >= 0; --i)
{
QuestObjective obj = Objectives[i];
if (obj is T t)
return t;
}
return null;
}
public QuestObjective FindObjective(Type type)
{
for (int i = Objectives.Count - 1; i >= 0; --i)
{
QuestObjective obj = Objectives[i];
if (obj.GetType() == type)
return obj;
}
return null;
}
public virtual void SendOffer()
{
From.SendGump(new QuestOfferGump(this));
}
public virtual void GetContextMenuEntries(List<ContextMenuEntry> list)
{
if (Objectives.Count > 0)
list.Add(new QuestCallbackEntry(6154, ShowQuestLog)); // View Quest Log
if (Conversations.Count > 0)
list.Add(new QuestCallbackEntry(6156, ShowQuestConversation)); // Quest Conversation
list.Add(new QuestCallbackEntry(6155, BeginCancelQuest)); // Cancel Quest
}
public virtual void ShowQuestLogUpdated()
{
From.CloseGump<QuestLogUpdatedGump>();
From.SendGump(new QuestLogUpdatedGump(this));
}
public virtual void ShowQuestLog()
{
if (Objectives.Count > 0)
{
From.CloseGump<QuestItemInfoGump>();
From.CloseGump<QuestLogUpdatedGump>();
From.CloseGump<QuestObjectivesGump>();
From.CloseGump<QuestConversationsGump>();
From.SendGump(new QuestObjectivesGump(Objectives));
QuestObjective last = Objectives[Objectives.Count - 1];
if (last.Info != null)
From.SendGump(new QuestItemInfoGump(last.Info));
}
}
public virtual void ShowQuestConversation()
{
if (Conversations.Count > 0)
{
From.CloseGump<QuestItemInfoGump>();
From.CloseGump<QuestObjectivesGump>();
From.CloseGump<QuestConversationsGump>();
From.SendGump(new QuestConversationsGump(Conversations));
QuestConversation last = Conversations[Conversations.Count - 1];
if (last.Info != null)
From.SendGump(new QuestItemInfoGump(last.Info));
}
}
public virtual void BeginCancelQuest()
{
From.SendGump(new QuestCancelGump(this));
}
public virtual void EndCancelQuest(bool shouldCancel)
{
if (From.Quest != this)
return;
if (shouldCancel)
{
From.SendLocalizedMessage(1049015); // You have canceled your quest.
Cancel();
}
else
{
From.SendLocalizedMessage(1049014); // You have chosen not to cancel your quest.
}
}
public virtual void Cancel()
{
ClearQuest(false);
}
public virtual void Complete()
{
ClearQuest(true);
}
public virtual void ClearQuest(bool completed)
{
StopTimer();
if (From.Quest == this)
{
From.Quest = null;
TimeSpan restartDelay = RestartDelay;
if (completed && restartDelay > TimeSpan.Zero || !completed && restartDelay == TimeSpan.MaxValue)
{
List<QuestRestartInfo> doneQuests = From.DoneQuests;
if (doneQuests == null)
From.DoneQuests = doneQuests = new List<QuestRestartInfo>();
bool found = false;
Type ourQuestType = GetType();
for (int i = 0; i < doneQuests.Count; ++i)
{
QuestRestartInfo restartInfo = doneQuests[i];
if (restartInfo.QuestType == ourQuestType)
{
restartInfo.Reset(restartDelay);
found = true;
break;
}
}
if (!found)
doneQuests.Add(new QuestRestartInfo(ourQuestType, restartDelay));
}
}
}
public virtual void AddConversation(QuestConversation conv)
{
conv.System = this;
if (conv.Logged)
Conversations.Add(conv);
From.CloseGump<QuestItemInfoGump>();
From.CloseGump<QuestObjectivesGump>();
From.CloseGump<QuestConversationsGump>();
From.SendGump(conv.Logged ? new QuestConversationsGump(Conversations) : new QuestConversationsGump(conv));
if (conv.Info != null)
From.SendGump(new QuestItemInfoGump(conv.Info));
}
public virtual void AddObjective(QuestObjective obj)
{
obj.System = this;
Objectives.Add(obj);
ShowQuestLogUpdated();
}
public virtual void Accept()
{
if (From.Quest != null)
return;
From.Quest = this;
From.SendLocalizedMessage(1049019); // You have accepted the Quest.
StartTimer();
}
public virtual void Decline()
{
From.SendLocalizedMessage(1049018); // You have declined the Quest.
}
public static bool CanOfferQuest(Mobile check, Type questType)
{
return CanOfferQuest(check, questType, out _);
}
public static bool CanOfferQuest(Mobile check, Type questType, out bool inRestartPeriod)
{
inRestartPeriod = false;
if (!(check is PlayerMobile pm))
return false;
if (pm.HasGump<QuestOfferGump>())
return false;
if (questType == typeof(DarkTidesQuest) && pm.Profession != 4) // necromancer
return false;
if (questType == typeof(UzeraanTurmoilQuest) && pm.Profession != 1 && pm.Profession != 2 && pm.Profession != 5
) // warrior / magician / paladin
return false;
if (questType == typeof(HaochisTrialsQuest) && pm.Profession != 6) // samurai
return false;
if (questType == typeof(EminosUndertakingQuest) && pm.Profession != 7) // ninja
return false;
List<QuestRestartInfo> doneQuests = pm.DoneQuests;
if (doneQuests != null)
for (int i = 0; i < doneQuests.Count; ++i)
{
QuestRestartInfo restartInfo = doneQuests[i];
if (restartInfo.QuestType == questType)
{
DateTime endTime = restartInfo.RestartTime;
if (DateTime.UtcNow < endTime)
{
inRestartPeriod = true;
return false;
}
doneQuests.RemoveAt(i--);
return true;
}
}
return true;
}
public static void FocusTo(Mobile who, Mobile to)
{
if (Utility.RandomBool())
who.Animate(17, 7, 1, true, false, 0);
else
switch (Utility.Random(3))
{
case 0:
who.Animate(32, 7, 1, true, false, 0);
break;
case 1:
who.Animate(33, 7, 1, true, false, 0);
break;
case 2:
who.Animate(34, 7, 1, true, false, 0);
break;
}
who.Direction = who.GetDirectionTo(to);
}
public static int RandomBrightHue()
{
if (0.1 > Utility.RandomDouble())
return Utility.RandomList(0x62, 0x71);
return Utility.RandomList(0x03, 0x0D, 0x13, 0x1C, 0x21, 0x30, 0x37, 0x3A, 0x44, 0x59);
}
}
public class QuestCancelGump : BaseQuestGump
{
private QuestSystem m_System;
public QuestCancelGump(QuestSystem system) : base(120, 50)
{
m_System = system;
Closable = false;
AddPage(0);
AddImageTiled(0, 0, 348, 262, 2702);
AddAlphaRegion(0, 0, 348, 262);
AddImage(0, 15, 10152);
AddImageTiled(0, 30, 17, 200, 10151);
AddImage(0, 230, 10154);
AddImage(15, 0, 10252);
AddImageTiled(30, 0, 300, 17, 10250);
AddImage(315, 0, 10254);
AddImage(15, 244, 10252);
AddImageTiled(30, 244, 300, 17, 10250);
AddImage(315, 244, 10254);
AddImage(330, 15, 10152);
AddImageTiled(330, 30, 17, 200, 10151);
AddImage(330, 230, 10154);
AddImage(333, 2, 10006);
AddImage(333, 248, 10006);
AddImage(2, 248, 10006);
AddImage(2, 2, 10006);
AddHtmlLocalized(25, 22, 200, 20, 1049000, 32000); // Confirm Quest Cancellation
AddImage(25, 40, 3007);
if (system.IsTutorial)
{
AddHtmlLocalized(25, 55, 300, 120, 1060836, White); // 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?
}
else
{
AddHtmlLocalized(25, 60, 300, 20, 1049001, White); // You have chosen to abort your quest:
AddImage(25, 81, 0x25E7);
AddHtmlObject(48, 80, 280, 20, system.Name, DarkGreen, false, false);
AddHtmlLocalized(25, 120, 280, 20, 1049002, White); // Can this quest be restarted after quitting?
AddImage(25, 141, 0x25E7);
AddHtmlLocalized(48, 140, 280, 20, system.RestartDelay < TimeSpan.MaxValue ? 1049016 : 1049017, DarkGreen); // Yes/No
}
AddRadio(25, 175, 9720, 9723, true, 1);
AddHtmlLocalized(60, 180, 280, 20, 1049005, White); // Yes, I really want to quit!
AddRadio(25, 210, 9720, 9723, false, 0);
AddHtmlLocalized(60, 215, 280, 20, 1049006, White); // No, I don't want to quit.
AddButton(265, 220, 247, 248, 1);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (info.ButtonID == 1)
m_System.EndCancelQuest(info.IsSwitched(1));
}
}
public class QuestOfferGump : BaseQuestGump
{
private QuestSystem m_System;
public QuestOfferGump(QuestSystem system) : base(75, 25)
{
m_System = system;
Closable = false;
AddPage(0);
AddImageTiled(50, 20, 400, 400, 2624);
AddAlphaRegion(50, 20, 400, 400);
AddImage(90, 33, 9005);
AddHtmlLocalized(130, 45, 270, 20, 1049010, White); // Quest Offer
AddImageTiled(130, 65, 175, 1, 9101);
AddImage(140, 110, 1209);
AddHtmlObject(160, 108, 250, 20, system.Name, DarkGreen, false, false);
AddHtmlObject(98, 140, 312, 200, system.OfferMessage, LightGreen, false, true);
AddRadio(85, 350, 9720, 9723, true, 1);
AddHtmlLocalized(120, 356, 280, 20, 1049011, White); // I accept!
AddRadio(85, 385, 9720, 9723, false, 0);
AddHtmlLocalized(120, 391, 280, 20, 1049012, White); // No thanks, I decline.
AddButton(340, 390, 247, 248, 1);
AddImageTiled(50, 29, 30, 390, 10460);
AddImageTiled(34, 140, 17, 279, 9263);
AddImage(48, 135, 10411);
AddImage(-16, 285, 10402);
AddImage(0, 10, 10421);
AddImage(25, 0, 10420);
AddImageTiled(83, 15, 350, 15, 10250);
AddImage(34, 419, 10306);
AddImage(442, 419, 10304);
AddImageTiled(51, 419, 392, 17, 10101);
AddImageTiled(415, 29, 44, 390, 2605);
AddImageTiled(415, 29, 30, 390, 10460);
AddImage(425, 0, 10441);
AddImage(370, 50, 1417);
AddImage(379, 60, system.Picture);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (info.ButtonID == 1)
{
if (info.IsSwitched(1))
m_System.Accept();
else
m_System.Decline();
}
}
}
public abstract class BaseQuestGump : Gump
{
public const int Black = 0x0000;
public const int White = 0x7FFF;
public const int DarkGreen = 10000;
public const int LightGreen = 90000;
public const int Blue = 19777215;
public BaseQuestGump(int x, int y) : base(x, y)
{
}
public static int C16232(int c16)
{
c16 &= 0x7FFF;
int r = ((c16 >> 10) & 0x1F) << 3;
int g = ((c16 >> 05) & 0x1F) << 3;
int b = ((c16 >> 00) & 0x1F) << 3;
return (r << 16) | (g << 8) | (b << 0);
}
public static int C16216(int c16)
{
return c16 & 0x7FFF;
}
public static int C32216(int c32)
{
c32 &= 0xFFFFFF;
int r = ((c32 >> 16) & 0xFF) >> 3;
int g = ((c32 >> 08) & 0xFF) >> 3;
int b = ((c32 >> 00) & 0xFF) >> 3;
return (r << 10) | (g << 5) | (b << 0);
}
public static string Color(string text, int color)
{
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
}
public void AddHtmlObject(int x, int y, int width, int height, object message, int color, bool back, bool scroll)
{
if (message is int html)
AddHtmlLocalized(x, y, width, height, html, C16216(color), back, scroll);
else
AddHtml(x, y, width, height, Color(message.ToString(), C16232(color)), back, scroll);
}
}
}

View file

@ -0,0 +1,41 @@
using System;
using System.Xml;
using Server.Mobiles;
using Server.Regions;
namespace Server.Engines.Quests
{
public class CancelQuestRegion : BaseRegion
{
private Type m_Quest;
public CancelQuestRegion(XmlElement xml, Map map, Region parent) : base(xml, map, parent)
{
ReadType(xml["quest"], "type", ref m_Quest);
}
public Type Quest => m_Quest;
public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation)
{
if (!base.OnMoveInto(m, d, newLocation, oldLocation))
return false;
if (m.AccessLevel > AccessLevel.Player)
return true;
if (m_Quest == null)
return true;
if (m is PlayerMobile player && player.Quest != null && player.Quest.GetType() == m_Quest)
{
if (!player.HasGump<QuestCancelGump>())
player.Quest.BeginCancelQuest();
return false;
}
return true;
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using System.Xml;
using Server.Mobiles;
using Server.Regions;
namespace Server.Engines.Quests
{
public class QuestCompleteObjectiveRegion : BaseRegion
{
private Type m_Objective;
private Type m_Quest;
public QuestCompleteObjectiveRegion(XmlElement xml, Map map, Region parent) : base(xml, map, parent)
{
XmlElement questEl = xml["quest"];
ReadType(questEl, "type", ref m_Quest);
ReadType(questEl, "complete", ref m_Objective);
}
public Type Quest => m_Quest;
public Type Objective => m_Objective;
public override void OnEnter(Mobile m)
{
base.OnEnter(m);
if (m_Quest != null && m_Objective != null)
if (m is PlayerMobile player && player.Quest != null && player.Quest.GetType() == m_Quest)
{
QuestObjective obj = player.Quest.FindObjective(m_Objective);
if (obj?.Completed == false)
obj.Complete();
}
}
}
}

View file

@ -0,0 +1,55 @@
using System;
using System.Xml;
using Server.Mobiles;
using Server.Regions;
namespace Server.Engines.Quests
{
public class QuestNoEntryRegion : BaseRegion
{
private Type m_MaxObjective;
private int m_Message;
private Type m_MinObjective;
private Type m_Quest;
public QuestNoEntryRegion(XmlElement xml, Map map, Region parent) : base(xml, map, parent)
{
XmlElement questEl = xml["quest"];
ReadType(questEl, "type", ref m_Quest);
ReadType(questEl, "min", ref m_MinObjective, false);
ReadType(questEl, "max", ref m_MaxObjective, false);
ReadInt32(questEl, "message", ref m_Message, false);
}
public Type Quest => m_Quest;
public Type MinObjective => m_MinObjective;
public Type MaxObjective => m_MaxObjective;
public int Message => m_Message;
public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation)
{
if (!base.OnMoveInto(m, d, newLocation, oldLocation))
return false;
if (m.AccessLevel > AccessLevel.Player)
return true;
if (m is BaseCreature bc && !bc.Controlled && !bc.Summoned)
return true;
if (m_Quest == null)
return true;
if (m is PlayerMobile player && player.Quest != null && player.Quest.GetType() == m_Quest
&& (m_MinObjective == null || player.Quest.FindObjective(m_MinObjective) != null)
&& (m_MaxObjective == null || player.Quest.FindObjective(m_MaxObjective) == null))
return true;
if (m_Message != 0)
m.SendLocalizedMessage(m_Message);
return false;
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using System.Xml;
using Server.Mobiles;
using Server.Regions;
namespace Server.Engines.Quests
{
public class QuestOfferRegion : BaseRegion
{
private Type m_Quest;
public QuestOfferRegion(XmlElement xml, Map map, Region parent) : base(xml, map, parent)
{
ReadType(xml["quest"], "type", ref m_Quest);
}
public Type Quest => m_Quest;
public override void OnEnter(Mobile m)
{
base.OnEnter(m);
if (m_Quest == null)
return;
if (m is PlayerMobile player && player.Quest == null && QuestSystem.CanOfferQuest(m, m_Quest))
try
{
QuestSystem qs = (QuestSystem)Activator.CreateInstance(m_Quest, player);
qs.SendOffer();
}
catch (Exception ex)
{
Console.WriteLine("Error creating quest {0}: {1}", m_Quest, ex);
}
}
}
}