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,478 @@
namespace Server.Engines.Quests.Haven
{
public class AcceptConversation : QuestConversation
{
public override object Message => 1049092;
public override void OnRead()
{
System.AddObjective(new FindUzeraanBeginObjective());
}
}
public class UzeraanTitheConversation : QuestConversation
{
public override object Message => 1060209;
public override void OnRead()
{
System.AddObjective(new TitheGoldObjective());
}
}
public class UzeraanFirstTaskConversation : QuestConversation
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1023676, 0xE68) // glowing rune
};
public override object Message
{
get
{
if (System.From.Profession == 1) // warrior
return 1049088;
if (System.From.Profession == 2) // magician
return 1049386;
/* <I>Uzeraan nods at you with approval and begins to speak...</I><BR><BR>
*
* Now that you are ready, let me give you your first task.<BR><BR>
*
* As I mentioned earlier, we have been trying to fight back the wicked
* <I>Horde Minions</I> which have recently begun attacking our cities
* - but to no avail. Our need is great!<BR><BR>
*
* Your first task will be to assess the situation in the mountain pass,
* and help our troops defeat the Horde Minions there.<BR><BR>
*
* Take the road marked with glowing runes, that starts just outside of this mansion.
* Before you go into battle, it would be prudent to
* <a href="?ForceTopic27">review combat techniques</a> as well as
* <a href = "?ForceTopic29">information on healing yourself,
* using your Paladin ability 'Close Wounds'</a>.<BR><BR>
*
* To aid you in your fight, you may also wish to
* <a href = "?ForceTopic33">purchase equipment</a> from Frank the Blacksmith,
* who is standing just <a href = "?ForceTopic13">South</a> of here.<BR><BR>
*
* Good luck young Paladin!
*/
return 1060388;
}
}
public override QuestItemInfo[] Info => m_Info;
public override void OnRead()
{
System.AddObjective(new KillHordeMinionsObjective());
}
}
public class UzeraanReportConversation : QuestConversation
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1026153, 0x1822), // teleporter
new QuestItemInfo(1048032, 0xE76) // a bag
};
public override object Message
{
get
{
if (System.From.Profession == 2) // magician
return 1049387;
/* <I>You give your report to Uzeraan and after a while,
* he begins to speak...</I><BR><BR>
*
* Your report is grim, but all hope is not lost! It has become apparent
* that our swords and spells will not drive the evil from Haven.<BR><BR>
*
* The head of my order, the High Mage Schmendrick, arrived here shortly after
* you went into battle with the <I>Horde Minions</I>. He has brought with him a
* scroll of great power, that should aid us greatly in our battle.<BR><BR>
*
* Unfortunately, the entrance to one of our mining caves collapsed recently,
* trapping our miners inside.<BR><BR>
*
* Schmendrick went to install magical teleporters inside the mines so that
* the miners would have a way out. The miners have since returned, but Schmendrick has not.
* Those who have returned, all seem to have lost their minds to madness;
* mumbling strange things of "the souls of the dead seeking revenge".<BR><BR>
*
* No matter. We must find Schmendrick.<BR><BR>
*
* Step onto the teleporter, located against the wall, and seek Schmendrick in the mines.<BR><BR>
*
* I've given you a bag with some <a href="?ForceTopic75">Night Sight</a>
* and <a href="?ForceTopic76">Healing</a> <a href="?ForceTopic74">potions</a>
* to help you out along the way. Good luck.
*/
return 1049119;
}
}
public override QuestItemInfo[] Info => m_Info;
public override void OnRead()
{
System.AddObjective(new FindSchmendrickObjective());
}
}
public class SchmendrickConversation : QuestConversation
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1023637, 0xE34) // scroll
};
public override object Message
{
get
{
if (System.From.Profession == 5) // paladin
return 1060749;
/* <I>Schmendrick barely pays you any attention as you approach him. His
* mind seems to be occupied with something else. You explain to him that
* you came for the scroll of power and after a long while he begins to speak,
* but apparently still not giving you his full attention...</I><BR><BR>
*
* Hmmm.. peculiar indeed. Very strange activity here indeed... I wonder...<BR><BR>
*
* Hmmm. Oh yes! Scroll, you say? I don't have it, sorry. My apprentice was
* carrying it, and he ran off to somewhere in this cave. Find him and you will
* find the scroll.<BR><BR>Be sure to bring the scroll to Uzeraan once you
* have it. He's the only person aside from myself who can read the ancient
* markings on the scroll. I need to figure out what's going on down here before
* I can leave. Strange activity indeed...<BR><BR>
*
* <I>Schmendrick goes back to his work and you seem to completely fade from his
* awareness...
*/
return 1049322;
}
}
public override QuestItemInfo[] Info => m_Info;
public override void OnRead()
{
System.AddObjective(new FindApprenticeObjective());
}
}
public class UzeraanScrollOfPowerConversation : QuestConversation
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1048030, 0x14EB), // a Treasure Map
new QuestItemInfo(1023969, 0xF81), // Fertile Dirt
new QuestItemInfo(1049117, 0xFC4) // Horn of Retreat
};
public override object Message => 1049325;
public override QuestItemInfo[] Info => m_Info;
public override void OnRead()
{
System.AddObjective(new FindDryadObjective());
}
}
public class DryadConversation : QuestConversation
{
public override object Message => 1049326;
public override void OnRead()
{
System.AddObjective(new ReturnFertileDirtObjective());
}
}
public class UzeraanFertileDirtConversation : QuestConversation
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1023965, 0xF7D), // Daemon Blood
new QuestItemInfo(1022581, 0xA22) // lantern
};
public override object Message
{
get
{
if (System.From.Profession == 2) // magician
return 1049388;
/* <I>Uzeraan takes the dirt from you and smiles...<BR><BR></I>
*
* Wonderful! I knew I could count on you. As a token of my appreciation
* I've given you a bag with some bandages as well as some healing potions.
* They should help out a bit.<BR><BR>
*
* The next item I need is a <I>Vial of Blood</I>. I know it seems strange,
* but that's what the formula asks for. I have some locked away in a chest
* not far from here. It's only a short distance from the mansion. Let me give
* you directions...<BR><BR>
*
* Exit the front door to the East. Then follow the path to the North.
* You will pass by several pedestals with lanterns on them. Continue on this
* path until you run into a small hut. Walk up the stairs and through the door.
* Inside you will find a chest. Open it and bring me a <I>Vial of Blood</I>
* from inside the chest. It's very easy to find. Just follow the road and you
* can't miss it.<BR><BR>
*
* Good luck!
*/
return 1049329;
}
}
public override QuestItemInfo[] Info => m_Info;
public override void OnRead()
{
System.AddObjective(new GetDaemonBloodObjective());
}
}
public class UzeraanDaemonBloodConversation : QuestConversation
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1017412, 0xF80) // Daemon Bone
};
private static QuestItemInfo[] m_InfoPaladin =
{
new QuestItemInfo(1017412, 0xF80), // Daemon Bone
new QuestItemInfo(1060577, 0x1F14) // Recall Rune
};
public override object Message
{
get
{
if (System.From.Profession == 2) // magician
return "<I>You hand Uzeraan the Vial of Blood, which he hastily accepts...</I><BR>"
+ "<BR>"
+ "Excellent work! Only one reagent remains and the spell is complete! The final "
+ "requirement is a <I>Daemon Bone</I>, which will not be as easily acquired as the "
+ "previous two components.<BR>"
+ "<BR>"
+ "There is a haunted graveyard on this island, which is the home to many undead "
+ "creatures. Dispose of the undead as you see fit. Be sure to search their remains "
+ "after you have smitten them, to check for a <I>Daemon Bone</I>. I'm quite sure "
+ "that you will find what we seek, if you are thorough enough with your "
+ "extermination.<BR>"
+ "<BR>"
+ "Take these explosion spell scrolls and magical wizard's hat to aid you in your "
+ "battle. The scrolls should help you make short work of the undead.<BR>"
+ "<BR>"
+ "Return here when you have found a <I>Daemon Bone</I>.";
/* <I>You hand Uzeraan the Vial of Blood, which he hastily accepts...</I><BR><BR>
*
* Excellent work! Only one reagent remains and the spell is complete!
* The final requirement is a <I>Daemon Bone</I>, which will not be as easily
* acquired as the previous two components.<BR><BR>
*
* There is a haunted graveyard on this island, which is the home to many
* undead creatures. Dispose of the undead as you see fit. Be sure to search
* their remains after you have smitten them, to check for a <I>Daemon Bone</I>.
* I'm quite sure that you will find what we seek, if you are thorough enough
* with your extermination.<BR><BR>
*
* Take this magical silver sword to aid you in your battle. Silver weapons
* will damage the undead twice as much as your regular weapon.<BR><BR>
*
* Return here when you have found a <I>Daemon Bone</I>.
*/
return 1049333;
}
}
public override QuestItemInfo[] Info
{
get
{
if (System.From.Profession == 5) // paladin
return m_InfoPaladin;
return m_Info;
}
}
public override void OnRead()
{
System.AddObjective(new GetDaemonBoneObjective());
}
}
public class UzeraanDaemonBoneConversation : QuestConversation
{
public override object Message => 1049335;
public override void OnRead()
{
System.AddObjective(new CashBankCheckObjective());
}
}
public class BankerConversation : QuestConversation
{
public override object Message => 1060137;
public override void OnRead()
{
System.Complete();
}
}
public class RadarConversation : QuestConversation
{
public override object Message => 1049660;
public override bool Logged => false;
}
public class LostScrollOfPowerConversation : QuestConversation
{
private bool m_FromUzeraan;
public LostScrollOfPowerConversation(bool fromUzeraan)
{
m_FromUzeraan = fromUzeraan;
}
public LostScrollOfPowerConversation()
{
}
public override object Message
{
get
{
if (m_FromUzeraan) return 1049377;
/* You've lost the scroll? Argh! I will have to try and re-construct
* the scroll from memory. Bring me a blank scroll, which you can
* <a href = "?ForceTopic33">purchase from the mage shop</a> just
* <a href = "?ForceTopic13">East</a> of Uzeraan's mansion in Haven.<BR><BR>
*
* Return the scroll to me and I will try to make another scroll for you.<BR><BR>
*
* When you return, be sure to hand me the scroll (drag and drop).
*/
return 1049345;
}
}
public override bool Logged => false;
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_FromUzeraan = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_FromUzeraan);
}
}
public class LostFertileDirtConversation : QuestConversation
{
private bool m_FromUzeraan;
public LostFertileDirtConversation(bool fromUzeraan)
{
m_FromUzeraan = fromUzeraan;
}
public LostFertileDirtConversation()
{
}
public override object Message
{
get
{
if (m_FromUzeraan) return 1049374;
/* You've lost the dirt I gave you?<BR><BR>
*
* My, my, my... What ever shall we do now?<BR><BR>
*
* I can try to make you some more, but I will need something
* that I can transform. Bring me an <I>apple</I>, and I shall
* see what I can do.<BR><BR>
*
* You can <a href = "?ForceTopic33">buy</a> apples from the
* Provisioner's Shop, which is located a ways <a href = "?ForceTopic13">East</a>
* of Uzeraan's mansion.<BR><BR>
*
* Hand me the apple when you have it, and I shall see about transforming
* it for you.<BR><BR>
*
* Good luck.<BR><BR>
*/
return 1049359;
}
}
public override bool Logged => false;
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_FromUzeraan = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_FromUzeraan);
}
}
public class DryadAppleConversation : QuestConversation
{
public override object Message => 1049360;
public override bool Logged => false;
}
public class LostDaemonBloodConversation : QuestConversation
{
public override object Message => 1049375;
public override bool Logged => false;
}
public class LostDaemonBoneConversation : QuestConversation
{
public override object Message => 1049376;
public override bool Logged => false;
}
public class FewReagentsConversation : QuestConversation
{
public override object Message => 1049390;
public override bool Logged => false;
}
}

View file

@ -0,0 +1,186 @@
using Server.Items;
namespace Server.Engines.Quests.Haven
{
public enum CannonDirection
{
North,
East,
South,
West
}
public class Cannon : BaseAddon
{
[Constructible]
public Cannon(CannonDirection direction)
{
CannonDirection = direction;
switch (direction)
{
case CannonDirection.North:
{
AddComponent(new CannonComponent(0xE8D), 0, 0, 0);
AddComponent(new CannonComponent(0xE8C), 0, 1, 0);
AddComponent(new CannonComponent(0xE8B), 0, 2, 0);
break;
}
case CannonDirection.East:
{
AddComponent(new CannonComponent(0xE96), 0, 0, 0);
AddComponent(new CannonComponent(0xE95), -1, 0, 0);
AddComponent(new CannonComponent(0xE94), -2, 0, 0);
break;
}
case CannonDirection.South:
{
AddComponent(new CannonComponent(0xE91), 0, 0, 0);
AddComponent(new CannonComponent(0xE92), 0, -1, 0);
AddComponent(new CannonComponent(0xE93), 0, -2, 0);
break;
}
default:
{
AddComponent(new CannonComponent(0xE8E), 0, 0, 0);
AddComponent(new CannonComponent(0xE8F), 1, 0, 0);
AddComponent(new CannonComponent(0xE90), 2, 0, 0);
break;
}
}
}
public Cannon(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public CannonDirection CannonDirection{ get; private set; }
[CommandProperty(AccessLevel.GameMaster)]
public MilitiaCanoneer Canoneer{ get; set; }
public override bool HandlesOnMovement => Canoneer?.Deleted == false && Canoneer.Active;
public void DoFireEffect(IPoint3D target)
{
Point3D from;
switch (CannonDirection)
{
case CannonDirection.North:
from = new Point3D(X, Y - 1, Z);
break;
case CannonDirection.East:
from = new Point3D(X + 1, Y, Z);
break;
case CannonDirection.South:
from = new Point3D(X, Y + 1, Z);
break;
default:
from = new Point3D(X - 1, Y, Z);
break;
}
Effects.SendLocationEffect(from, Map, 0x36B0, 16, 1);
Effects.PlaySound(from, Map, 0x11D);
Effects.SendLocationEffect(target, Map, 0x36B0, 16, 1);
Effects.PlaySound(target, Map, 0x11D);
}
public void Fire(Mobile from, Mobile target)
{
DoFireEffect(target);
target.Damage(9999, from);
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (!(Canoneer?.Deleted == false && Canoneer.Active))
return;
bool canFire;
switch (CannonDirection)
{
case CannonDirection.North:
canFire = m.X >= X - 7 && m.X <= X + 7 && m.Y == Y - 7 && oldLocation.Y < Y - 7;
break;
case CannonDirection.East:
canFire = m.Y >= Y - 7 && m.Y <= Y + 7 && m.X == X + 7 && oldLocation.X > X + 7;
break;
case CannonDirection.South:
canFire = m.X >= X - 7 && m.X <= X + 7 && m.Y == Y + 7 && oldLocation.Y > Y + 7;
break;
default:
canFire = m.Y >= Y - 7 && m.Y <= Y + 7 && m.X == X - 7 && oldLocation.X < X - 7;
break;
}
if (canFire && Canoneer.WillFire(this, m))
Fire(Canoneer, m);
}
public override void Serialize(GenericWriter writer)
{
if (Canoneer?.Deleted == true)
Canoneer = null;
base.Serialize(writer);
writer.Write(0); // version
writer.WriteEncodedInt((int)CannonDirection);
writer.Write(Canoneer);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
CannonDirection = (CannonDirection)reader.ReadEncodedInt();
Canoneer = (MilitiaCanoneer)reader.ReadMobile();
}
}
public class CannonComponent : AddonComponent
{
public CannonComponent(int itemID) : base(itemID)
{
}
public CannonComponent(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public MilitiaCanoneer Canoneer
{
get => Addon is Cannon cannon ? cannon.Canoneer : null;
set
{
if (Addon is Cannon cannon) cannon.Canoneer = value;
}
}
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,69 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class DaemonBloodChest : MetalChest
{
[Constructible]
public DaemonBloodChest()
{
Movable = false;
}
public DaemonBloodChest(Serial serial) : base(serial)
{
}
public override void OnDoubleClick(Mobile from)
{
if (from is PlayerMobile player && player.InRange(GetWorldLocation(), 2))
{
QuestSystem qs = player.Quest;
if (qs is UzeraanTurmoilQuest)
{
QuestObjective obj = qs.FindObjective<GetDaemonBloodObjective>();
if (obj?.Completed == false || UzeraanTurmoilQuest.HasLostDaemonBlood(player))
{
Item vial = new QuestDaemonBlood();
if (player.PlaceInBackpack(vial))
{
player.SendLocalizedMessage(1049331, "",
0x22); // You take a vial of blood from the chest and put it in your pack.
if (obj?.Completed == false)
obj.Complete();
}
else
{
player.SendLocalizedMessage(1049338, "",
0x22); // You find a vial of blood, but can't pick it up because your pack is too full. Come back when you have more room in your pack.
vial.Delete();
}
return;
}
}
}
base.OnDoubleClick(from);
}
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,38 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class QuestDaemonBlood : QuestItem
{
[Constructible]
public QuestDaemonBlood() : base(0xF7D)
{
Weight = 1.0;
}
public QuestDaemonBlood(Serial serial) : base(serial)
{
}
public override bool CanDrop(PlayerMobile player)
{
return !(player.Quest is UzeraanTurmoilQuest);
/*return !qs.IsObjectiveInProgress( typeof( ReturnDaemonBloodObjective ) );*/
}
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,38 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class QuestDaemonBone : QuestItem
{
[Constructible]
public QuestDaemonBone() : base(0xF80)
{
Weight = 1.0;
}
public QuestDaemonBone(Serial serial) : base(serial)
{
}
public override bool CanDrop(PlayerMobile player)
{
return !(player.Quest is UzeraanTurmoilQuest);
//return !qs.IsObjectiveInProgress( typeof( ReturnDaemonBoneObjective ) );
}
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,38 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class QuestFertileDirt : QuestItem
{
[Constructible]
public QuestFertileDirt() : base(0xF81)
{
Weight = 1.0;
}
public QuestFertileDirt(Serial serial) : base(serial)
{
}
public override bool CanDrop(PlayerMobile player)
{
return !(player.Quest is UzeraanTurmoilQuest);
//return !qs.IsObjectiveInProgress( typeof( ReturnFertileDirtObjective ) );
}
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,175 @@
using System.Collections.Generic;
using Server.Items;
using Server.Misc;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Haven
{
public class SchmendrickApprenticeCorpse : Corpse
{
private static int m_HairHue;
private Lantern m_Lantern;
[Constructible]
public SchmendrickApprenticeCorpse() : base(GetOwner(), GetHair(), GetFacialHair(), GetEquipment())
{
Direction = Direction.West;
foreach (Item item in EquipItems)
DropItem(item);
m_Lantern = new Lantern { Movable = false, Protected = true };
m_Lantern.Ignite();
}
public SchmendrickApprenticeCorpse(Serial serial) : base(serial)
{
}
// TODO: What is this? Why are we creating and deleting a mobile?
private static Mobile GetOwner()
{
Mobile apprentice = new Mobile();
apprentice.Hue = Race.Human.RandomSkinHue();
apprentice.Female = false;
apprentice.Body = 0x190;
apprentice.Name = NameList.RandomName("male");
apprentice.Delete();
return apprentice;
}
private static List<Item> GetEquipment()
{
List<Item> list = new List<Item>();
list.Add(new Robe(QuestSystem.RandomBrightHue()));
list.Add(new WizardsHat(Utility.RandomNeutralHue()));
list.Add(new Shoes(Utility.RandomNeutralHue()));
list.Add(new Spellbook());
return list;
}
private static HairInfo GetHair()
{
m_HairHue = Race.Human.RandomHairHue();
return new HairInfo(Race.Human.RandomHair(false), m_HairHue);
}
private static FacialHairInfo GetFacialHair()
{
m_HairHue = Race.Human.RandomHairHue();
return new FacialHairInfo(Race.Human.RandomFacialHair(false), m_HairHue);
}
public override void AddNameProperty(ObjectPropertyList list)
{
if (ItemID == 0x2006) // Corpse form
{
list.Add("a human corpse");
list.Add(1049144, Name); // the remains of ~1_NAME~ the apprentice
}
else
{
list.Add(1049145); // the remains of a wizard's apprentice
}
}
public override void OnSingleClick(Mobile from)
{
int hue = Notoriety.GetHue(NotorietyHandlers.CorpseNotoriety(from, this));
if (ItemID == 0x2006) // Corpse form
from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1049144, "",
Name)); // the remains of ~1_NAME~ the apprentice
else
from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1049145, "",
"")); // the remains of a wizard's apprentice
}
public override void Open(Mobile from, bool checkSelfLoot)
{
if (!from.InRange(GetWorldLocation(), 2))
return;
if (from is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is UzeraanTurmoilQuest)
{
QuestObjective obj = qs.FindObjective<FindApprenticeObjective>();
if (obj?.Completed == false)
{
Item scroll = new SchmendrickScrollOfPower();
if (player.PlaceInBackpack(scroll))
{
player.SendLocalizedMessage(1049147, "", 0x22); // You find the scroll and put it in your pack.
obj.Complete();
}
else
{
player.SendLocalizedMessage(1049146, "",
0x22); // You find the scroll, but can't pick it up because your pack is too full. Come back when you have more room in your pack.
scroll.Delete();
}
return;
}
}
}
from.SendLocalizedMessage(1049143, "",
0x22); // This is the corpse of a wizard's apprentice. You can't bring yourself to search it without a good reason.
}
public override void OnLocationChange(Point3D oldLoc)
{
if (m_Lantern?.Deleted == false)
m_Lantern.Location = new Point3D(X, Y + 1, Z);
}
public override void OnMapChange()
{
if (m_Lantern?.Deleted == false)
m_Lantern.Map = Map;
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if (m_Lantern?.Deleted == false)
m_Lantern.Delete();
}
public override void Serialize(GenericWriter writer)
{
if (m_Lantern?.Deleted == true)
m_Lantern = null;
base.Serialize(writer);
writer.Write(0); // version
writer.Write(m_Lantern);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Lantern = (Lantern)reader.ReadItem();
}
}
}

View file

@ -0,0 +1,39 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class SchmendrickScrollOfPower : QuestItem
{
public SchmendrickScrollOfPower() : base(0xE34)
{
Weight = 1.0;
Hue = 0x34D;
}
public SchmendrickScrollOfPower(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1049118; // a scroll with ancient markings
public override bool CanDrop(PlayerMobile player)
{
return !(player.Quest is UzeraanTurmoilQuest qs &&
qs.IsObjectiveInProgress(typeof(ReturnScrollOfPowerObjective)));
}
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,37 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class UzeraanTurmoilHorn : HornOfRetreat
{
[Constructible]
public UzeraanTurmoilHorn()
{
DestLoc = new Point3D(3597, 2582, 0);
DestMap = Map.Trammel;
}
public UzeraanTurmoilHorn(Serial serial) : base(serial)
{
}
public override bool ValidateUse(Mobile from)
{
return from is PlayerMobile pm && pm.Quest is UzeraanTurmoilQuest;
}
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,73 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class UzeraanTurmoilTeleporter : DynamicTeleporter
{
[Constructible]
public UzeraanTurmoilTeleporter()
{
}
public UzeraanTurmoilTeleporter(Serial serial) : base(serial)
{
}
public override bool GetDestination(PlayerMobile player, ref Point3D loc, ref Map map)
{
QuestSystem qs = player.Quest;
if (qs is UzeraanTurmoilQuest)
{
if (qs.IsObjectiveInProgress(typeof(FindSchmendrickObjective))
|| qs.IsObjectiveInProgress(typeof(FindApprenticeObjective))
|| UzeraanTurmoilQuest.HasLostScrollOfPower(player))
{
loc = new Point3D(5222, 1858, 0);
map = Map.Trammel;
return true;
}
if (qs.IsObjectiveInProgress(typeof(FindDryadObjective))
|| UzeraanTurmoilQuest.HasLostFertileDirt(player))
{
loc = new Point3D(3557, 2690, 2);
map = Map.Trammel;
return true;
}
if (player.Profession != 5 // paladin
&& (qs.IsObjectiveInProgress(typeof(GetDaemonBoneObjective))
|| UzeraanTurmoilQuest.HasLostDaemonBone(player)))
{
loc = new Point3D(3422, 2653, 48);
map = Map.Trammel;
return true;
}
if (qs.IsObjectiveInProgress(typeof(CashBankCheckObjective)))
{
loc = new Point3D(3624, 2610, 0);
map = Map.Trammel;
return true;
}
}
return false;
}
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,185 @@
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class Dryad : BaseQuester
{
[Constructible]
public Dryad() : base("the Dryad")
{
SetSkill(SkillName.Peacemaking, 80.0, 100.0);
SetSkill(SkillName.Cooking, 80.0, 100.0);
SetSkill(SkillName.Provocation, 80.0, 100.0);
SetSkill(SkillName.Musicianship, 80.0, 100.0);
SetSkill(SkillName.Poisoning, 80.0, 100.0);
SetSkill(SkillName.Archery, 80.0, 100.0);
SetSkill(SkillName.Tailoring, 80.0, 100.0);
}
public Dryad(Serial serial) : base(serial)
{
}
public override bool IsActiveVendor => true;
public override bool DisallowAllMoves => false;
public override bool ClickTitle => true;
public override bool CanTeach => true;
public override string DefaultName => "Anwin Brenna";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x85A7;
Female = true;
Body = 0x191;
}
public override void InitOutfit()
{
AddItem(new Kilt(0x301));
AddItem(new FancyShirt(0x300));
HairItemID = 0x203D; // Pony Tail
HairHue = 0x22;
Bow bow = new Bow();
bow.Movable = false;
AddItem(bow);
}
public override void InitSBInfo()
{
m_SBInfos.Add(new SBDryad());
}
public override int GetAutoTalkRange(PlayerMobile pm)
{
return 4;
}
public override bool CanTalkTo(PlayerMobile to)
{
return to.Quest is UzeraanTurmoilQuest qs && qs.FindObjective<FindDryadObjective>() != null;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is UzeraanTurmoilQuest)
{
if (UzeraanTurmoilQuest.HasLostFertileDirt(player))
{
FocusTo(player);
qs.AddConversation(new LostFertileDirtConversation(false));
}
else
{
QuestObjective obj = qs.FindObjective<FindDryadObjective>();
if (obj?.Completed == false)
{
FocusTo(player);
Item fertileDirt = new QuestFertileDirt();
if (!player.PlaceInBackpack(fertileDirt))
{
fertileDirt.Delete();
player.SendLocalizedMessage(
1046260); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory.
}
else
{
obj.Complete();
}
}
else if (contextMenu)
{
FocusTo(player);
SayTo(player, 1049357); // I have nothing more for you at this time.
}
}
}
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
if (from is PlayerMobile player)
if (player.Quest is UzeraanTurmoilQuest qs && dropped is Apple &&
UzeraanTurmoilQuest.HasLostFertileDirt(from))
{
FocusTo(from);
Item fertileDirt = new QuestFertileDirt();
if (!player.PlaceInBackpack(fertileDirt))
{
fertileDirt.Delete();
player.SendLocalizedMessage(
1046260); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory.
return false;
}
dropped.Consume();
qs.AddConversation(new DryadAppleConversation());
return dropped.Deleted;
}
return base.OnDragDrop(from, dropped);
}
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();
}
}
public class SBDryad : SBInfo
{
public override IShopSellInfo SellInfo{ get; } = new InternalSellInfo();
public override List<GenericBuyInfo> BuyInfo{ get; } = new InternalBuyInfo();
public class InternalBuyInfo : List<GenericBuyInfo>
{
public InternalBuyInfo()
{
Add(new GenericBuyInfo(typeof(Bandage), 5, 20, 0xE21, 0));
Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0));
Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0));
Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0));
Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0));
Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0));
Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0));
}
}
public class InternalSellInfo : GenericSellInfo
{
public InternalSellInfo()
{
Add(typeof(Bandage), 2);
Add(typeof(Garlic), 2);
Add(typeof(Ginseng), 2);
Add(typeof(Bloodmoss), 3);
Add(typeof(Nightshade), 2);
Add(typeof(SpidersSilk), 2);
Add(typeof(MandrakeRoot), 2);
}
}
}
}

View file

@ -0,0 +1,77 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class MansionGuard : BaseQuester
{
[Constructible]
public MansionGuard() : base("the Mansion Guard")
{
}
public MansionGuard(Serial serial) : base(serial)
{
}
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = Race.Human.RandomSkinHue();
Female = false;
Body = 0x190;
Name = NameList.RandomName("male");
}
public override void InitOutfit()
{
AddItem(new PlateChest());
AddItem(new PlateArms());
AddItem(new PlateGloves());
AddItem(new PlateLegs());
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this, HairHue);
Bardiche weapon = new Bardiche();
weapon.Movable = false;
AddItem(weapon);
}
public override int GetAutoTalkRange(PlayerMobile pm)
{
return 3;
}
public override bool CanTalkTo(PlayerMobile to)
{
return to.Quest == null && QuestSystem.CanOfferQuest(to, typeof(UzeraanTurmoilQuest));
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
if (player.Quest == null && QuestSystem.CanOfferQuest(player, typeof(UzeraanTurmoilQuest)))
{
Direction = GetDirectionTo(player);
new UzeraanTurmoilQuest(player).SendOffer();
}
}
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,102 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class MilitiaCanoneer : BaseQuester
{
[Constructible]
public MilitiaCanoneer() : base("the Militia Canoneer")
{
Active = true;
}
public MilitiaCanoneer(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public bool Active{ get; set; }
public override void InitBody()
{
InitStats(100, 125, 25);
Hue = Race.Human.RandomSkinHue();
Female = false;
Body = 0x190;
Name = NameList.RandomName("male");
}
public override void InitOutfit()
{
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this, HairHue);
AddItem(new PlateChest());
AddItem(new PlateArms());
AddItem(new PlateGloves());
AddItem(new PlateLegs());
Torch torch = new Torch();
torch.Movable = false;
AddItem(torch);
torch.Ignite();
}
public override bool CanTalkTo(PlayerMobile to)
{
return false;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
}
public override bool IsEnemy(Mobile m)
{
if (m.Player || m is BaseVendor)
return false;
if (m is BaseCreature bc)
{
Mobile master = bc.GetMaster();
if (master != null)
return IsEnemy(master);
}
return m.Karma < 0;
}
public bool WillFire(Cannon cannon, Mobile target)
{
if (Active && IsEnemy(target))
{
Direction = GetDirectionTo(target);
Say(Utility.RandomList(500651, 1049098, 1049320, 1043149));
return true;
}
return false;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(Active);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Active = reader.ReadBool();
}
}
}

View file

@ -0,0 +1,162 @@
using System.Collections.Generic;
using Server.Items;
using Server.Misc;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Haven
{
public class MilitiaFighter : BaseCreature
{
[Constructible]
public MilitiaFighter() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
{
InitStats(40, 30, 5);
Title = "the Militia Fighter";
SpeechHue = Utility.RandomDyedHue();
Hue = Race.Human.RandomSkinHue();
Female = false;
Body = 0x190;
Name = NameList.RandomName("male");
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this, HairHue);
AddItem(new ThighBoots(0x1BB));
AddItem(new LeatherChest());
AddItem(new LeatherArms());
AddItem(new LeatherLegs());
AddItem(new LeatherCap());
AddItem(new LeatherGloves());
AddItem(new LeatherGorget());
Item weapon;
switch (Utility.Random(6))
{
case 0:
weapon = new Broadsword();
break;
case 1:
weapon = new Cutlass();
break;
case 2:
weapon = new Katana();
break;
case 3:
weapon = new Longsword();
break;
case 4:
weapon = new Scimitar();
break;
default:
weapon = new VikingSword();
break;
}
weapon.Movable = false;
AddItem(weapon);
Item shield = new BronzeShield();
shield.Movable = false;
AddItem(shield);
SetSkill(SkillName.Swords, 20.0);
}
public MilitiaFighter(Serial serial) : base(serial)
{
}
public override bool ClickTitle => false;
public override bool IsEnemy(Mobile m)
{
if (m.Player || m is BaseVendor)
return false;
if (m is BaseCreature bc)
{
Mobile master = bc.GetMaster();
if (master != null)
return IsEnemy(master);
}
return m.Karma < 0;
}
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();
}
}
public class MilitiaFighterCorpse : Corpse
{
public MilitiaFighterCorpse(Mobile owner, HairInfo hair, FacialHairInfo facialhair, List<Item> equipItems) : base(
owner, hair, facialhair, equipItems)
{
}
public MilitiaFighterCorpse(Serial serial) : base(serial)
{
}
public override void AddNameProperty(ObjectPropertyList list)
{
if (ItemID == 0x2006) // Corpse form
{
list.Add("a human corpse");
list.Add(1049318, Name); // the remains of ~1_NAME~ the militia fighter
}
else
{
list.Add(1049319); // the remains of a militia fighter
}
}
public override void OnSingleClick(Mobile from)
{
int hue = Notoriety.GetHue(NotorietyHandlers.CorpseNotoriety(from, this));
if (ItemID == 0x2006) // Corpse form
from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1049318, "",
Name)); // the remains of ~1_NAME~ the militia fighter
else
from.Send(new MessageLocalized(Serial, ItemID, MessageType.Label, hue, 3, 1049319, "",
"")); // the remains of a militia fighter
}
public override void Open(Mobile from, bool checkSelfLoot)
{
if (from.InRange(GetWorldLocation(), 2))
from.SendLocalizedMessage(1049661, "",
0x22); // Thinking about his sacrifice, you can't bring yourself to loot the body of this militia fighter.
}
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,152 @@
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class Schmendrick : BaseQuester
{
[Constructible]
public Schmendrick() : base("the High Mage")
{
}
public Schmendrick(Serial serial) : base(serial)
{
}
public override string DefaultName => "Schmendrick";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83F3;
Female = false;
Body = 0x190;
}
public override void InitOutfit()
{
AddItem(new Robe(0x4DD));
AddItem(new WizardsHat(0x482));
AddItem(new Shoes(0x482));
HairItemID = 0x203C;
HairHue = 0x455;
FacialHairItemID = 0x203E;
FacialHairHue = 0x455;
GlacialStaff staff = new GlacialStaff();
staff.Movable = false;
AddItem(staff);
Backpack pack = new Backpack();
pack.Movable = false;
AddItem(pack);
}
public override int GetAutoTalkRange(PlayerMobile pm)
{
return 7;
}
public override bool CanTalkTo(PlayerMobile to)
{
return to.Quest is UzeraanTurmoilQuest qs && qs.FindObjective<FindSchmendrickObjective>() != null;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is UzeraanTurmoilQuest)
{
if (UzeraanTurmoilQuest.HasLostScrollOfPower(player))
{
FocusTo(player);
qs.AddConversation(new LostScrollOfPowerConversation(false));
}
else
{
QuestObjective obj = qs.FindObjective<FindSchmendrickObjective>();
if (obj?.Completed == false)
{
FocusTo(player);
obj.Complete();
}
else if (contextMenu)
{
FocusTo(player);
SayTo(player, 1049357); // I have nothing more for you at this time.
}
}
}
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
if (dropped is BlankScroll && UzeraanTurmoilQuest.HasLostScrollOfPower(from))
{
FocusTo(from);
Item scroll = new SchmendrickScrollOfPower();
if (!from.PlaceInBackpack(scroll))
{
scroll.Delete();
from.SendLocalizedMessage(
1046260); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory.
return false;
}
dropped.Consume();
from.SendLocalizedMessage(
1049346); // Schmendrick scribbles on the scroll for a few moments and hands you the finished product.
return dropped.Deleted;
}
return base.OnDragDrop(from, dropped);
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
base.OnMovement(m, oldLocation);
if (m is PlayerMobile && !m.Frozen && !m.Alive && InRange(m, 4) && !InRange(oldLocation, 4) && InLOS(m))
{
if (m.Map == null || !m.Map.CanFit(m.Location, 16, false, false))
{
m.SendLocalizedMessage(502391); // Thou can not be resurrected there!
}
else
{
Direction = GetDirectionTo(m);
m.PlaySound(0x214);
m.FixedEffect(0x376A, 10, 16);
m.CloseGump<ResurrectGump>();
m.SendGump(new ResurrectGump(m, ResurrectMessage.Healer));
}
}
}
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,432 @@
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class Uzeraan : BaseQuester
{
[Constructible]
public Uzeraan() : base("the Conjurer")
{
}
public Uzeraan(Serial serial) : base(serial)
{
}
public override string DefaultName => "Uzeraan";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83F3;
Female = false;
Body = 0x190;
}
public override void InitOutfit()
{
AddItem(new Robe(0x4DD));
AddItem(new WizardsHat(0x8A5));
AddItem(new Shoes(0x8A5));
HairItemID = 0x203C;
HairHue = 0x455;
FacialHairItemID = 0x203E;
FacialHairHue = 0x455;
BlackStaff staff = new BlackStaff();
staff.Movable = false;
AddItem(staff);
}
public override int GetAutoTalkRange(PlayerMobile pm)
{
return 3;
}
public override bool CanTalkTo(PlayerMobile to)
{
return to.Quest is UzeraanTurmoilQuest;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is UzeraanTurmoilQuest)
{
if (UzeraanTurmoilQuest.HasLostScrollOfPower(player))
{
qs.AddConversation(new LostScrollOfPowerConversation(true));
}
else if (UzeraanTurmoilQuest.HasLostFertileDirt(player))
{
qs.AddConversation(new LostFertileDirtConversation(true));
}
else if (UzeraanTurmoilQuest.HasLostDaemonBlood(player))
{
qs.AddConversation(new LostDaemonBloodConversation());
}
else if (UzeraanTurmoilQuest.HasLostDaemonBone(player))
{
qs.AddConversation(new LostDaemonBoneConversation());
}
else
{
if (player.Profession == 2) // magician
{
Container backpack = player.Backpack;
if (backpack == null
|| backpack.GetAmount(typeof(BlackPearl)) < 30
|| backpack.GetAmount(typeof(Bloodmoss)) < 30
|| backpack.GetAmount(typeof(Garlic)) < 30
|| backpack.GetAmount(typeof(Ginseng)) < 30
|| backpack.GetAmount(typeof(MandrakeRoot)) < 30
|| backpack.GetAmount(typeof(Nightshade)) < 30
|| backpack.GetAmount(typeof(SulfurousAsh)) < 30
|| backpack.GetAmount(typeof(SpidersSilk)) < 30)
qs.AddConversation(new FewReagentsConversation());
}
QuestObjective obj = qs.FindObjective<FindUzeraanBeginObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else
{
obj = qs.FindObjective<FindUzeraanFirstTaskObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else
{
obj = qs.FindObjective<FindUzeraanAboutReportObjective>();
if (obj?.Completed == false)
{
Container cont = GetNewContainer();
if (player.Profession == 2) // magician
{
cont.DropItem(new MarkScroll(5));
cont.DropItem(new RecallScroll(5));
for (int i = 0; i < 5; i++) cont.DropItem(new RecallRune());
}
else
{
cont.DropItem(new Gold(300));
for (int i = 0; i < 6; i++)
{
cont.DropItem(new NightSightPotion());
cont.DropItem(new LesserHealPotion());
}
}
if (!player.PlaceInBackpack(cont))
{
cont.Delete();
player.SendLocalizedMessage(
1046260); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory.
}
else
{
obj.Complete();
}
}
else
{
obj = qs.FindObjective<ReturnScrollOfPowerObjective>();
if (obj?.Completed == false)
{
FocusTo(player);
SayTo(player, 1049378); // Hand me the scroll, if you have it.
}
else
{
obj = qs.FindObjective<ReturnFertileDirtObjective>();
if (obj?.Completed == false)
{
FocusTo(player);
SayTo(player, 1049381); // Hand me the Fertile Dirt, if you have it.
}
else
{
obj = qs.FindObjective<ReturnDaemonBloodObjective>();
if (obj?.Completed == false)
{
FocusTo(player);
SayTo(player, 1049379); // Hand me the Vial of Blood, if you have it.
}
else
{
obj = qs.FindObjective<ReturnDaemonBoneObjective>();
if (obj?.Completed == false)
{
FocusTo(player);
SayTo(player, 1049380); // Hand me the Daemon Bone, if you have it.
}
else
{
SayTo(player, 1049357); // I have nothing more for you at this time.
}
}
}
}
}
}
}
}
}
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
if (from is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is UzeraanTurmoilQuest)
{
if (dropped is UzeraanTurmoilHorn horn)
{
if (player.Young)
{
if (horn.Charges < 10)
{
SayTo(from, 1049384); // I have recharged the item for you.
horn.Charges = 10;
}
else
{
SayTo(from, 1049385); // That doesn't need recharging yet.
}
}
else
{
player.SendLocalizedMessage(1114333); //You must be young to have this item recharged.
}
return false;
}
if (dropped is SchmendrickScrollOfPower)
{
QuestObjective obj = qs.FindObjective<ReturnScrollOfPowerObjective>();
if (obj?.Completed == false)
{
Container cont = GetNewContainer();
cont.DropItem(new TreasureMap(player.Young ? 0 : 1, Map.Trammel));
cont.DropItem(new Shovel());
cont.DropItem(new UzeraanTurmoilHorn());
if (!player.PlaceInBackpack(cont))
{
cont.Delete();
player.SendLocalizedMessage(
1046260); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory.
return false;
}
dropped.Delete();
obj.Complete();
return true;
}
}
else if (dropped is QuestFertileDirt)
{
QuestObjective obj = qs.FindObjective<ReturnFertileDirtObjective>();
if (obj?.Completed == false)
{
Container cont = GetNewContainer();
if (player.Profession == 2) // magician
{
cont.DropItem(new BlackPearl(20));
cont.DropItem(new Bloodmoss(20));
cont.DropItem(new Garlic(20));
cont.DropItem(new Ginseng(20));
cont.DropItem(new MandrakeRoot(20));
cont.DropItem(new Nightshade(20));
cont.DropItem(new SulfurousAsh(20));
cont.DropItem(new SpidersSilk(20));
for (int i = 0; i < 3; i++)
cont.DropItem(Loot.RandomScroll(0, 23, SpellbookType.Regular));
}
else
{
cont.DropItem(new Gold(300));
cont.DropItem(new Bandage(25));
for (int i = 0; i < 5; i++)
cont.DropItem(new LesserHealPotion());
}
if (!player.PlaceInBackpack(cont))
{
cont.Delete();
player.SendLocalizedMessage(
1046260); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory.
return false;
}
dropped.Delete();
obj.Complete();
return true;
}
}
else if (dropped is QuestDaemonBlood)
{
QuestObjective obj = qs.FindObjective<ReturnDaemonBloodObjective>();
if (obj?.Completed == false)
{
Item reward;
if (player.Profession == 2) // magician
{
Container cont = GetNewContainer();
cont.DropItem(new ExplosionScroll(4));
cont.DropItem(new MagicWizardsHat());
reward = cont;
}
else
{
BaseWeapon weapon;
switch (Utility.Random(6))
{
case 0:
weapon = new Broadsword();
break;
case 1:
weapon = new Cutlass();
break;
case 2:
weapon = new Katana();
break;
case 3:
weapon = new Longsword();
break;
case 4:
weapon = new Scimitar();
break;
default:
weapon = new VikingSword();
break;
}
if (Core.AOS)
{
BaseRunicTool.ApplyAttributesTo(weapon, 3, 20, 40);
}
else
{
weapon.DamageLevel = (WeaponDamageLevel)RandomMinMaxScaled(2, 4);
weapon.AccuracyLevel = (WeaponAccuracyLevel)RandomMinMaxScaled(2, 4);
weapon.DurabilityLevel = (WeaponDurabilityLevel)RandomMinMaxScaled(2, 4);
}
weapon.Slayer = SlayerName.Silver;
reward = weapon;
}
if (!player.PlaceInBackpack(reward))
{
reward.Delete();
player.SendLocalizedMessage(
1046260); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory.
return false;
}
dropped.Delete();
obj.Complete();
return true;
}
}
else if (dropped is QuestDaemonBone)
{
QuestObjective obj = qs.FindObjective<ReturnDaemonBoneObjective>();
if (obj?.Completed == false)
{
Container cont = GetNewContainer();
cont.DropItem(new BankCheck(2000));
cont.DropItem(new EnchantedSextant());
if (!player.PlaceInBackpack(cont))
{
cont.Delete();
player.SendLocalizedMessage(
1046260); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory.
return false;
}
dropped.Delete();
obj.Complete();
return true;
}
}
}
}
return base.OnDragDrop(from, dropped);
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
base.OnMovement(m, oldLocation);
if (m is PlayerMobile && !m.Frozen && !m.Alive && InRange(m, 4) && !InRange(oldLocation, 4) && InLOS(m))
{
if (m.Map == null || !m.Map.CanFit(m.Location, 16, false, false))
{
m.SendLocalizedMessage(502391); // Thou can not be resurrected there!
}
else
{
Direction = GetDirectionTo(m);
m.PlaySound(0x214);
m.FixedEffect(0x376A, 10, 16);
m.CloseGump<ResurrectGump>();
m.SendGump(new ResurrectGump(m, ResurrectMessage.Healer));
}
}
}
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,435 @@
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Haven
{
public class FindUzeraanBeginObjective : QuestObjective
{
public override object Message => 1046039;
public override void OnComplete()
{
if (System.From.Profession == 5) // paladin
System.AddConversation(new UzeraanTitheConversation());
else
System.AddConversation(new UzeraanFirstTaskConversation());
}
}
public class TitheGoldObjective : QuestObjective
{
private int m_OldTithingPoints;
public TitheGoldObjective()
{
m_OldTithingPoints = -1;
}
public override object Message => 1060386;
public override void CheckProgress()
{
PlayerMobile pm = System.From;
int curTithingPoints = pm.TithingPoints;
if (curTithingPoints >= 500)
Complete();
else if (curTithingPoints > m_OldTithingPoints && m_OldTithingPoints >= 0)
pm.SendLocalizedMessage(1060240, "",
0x41); // You must have at least 500 tithing points before you can continue in your quest.
m_OldTithingPoints = curTithingPoints;
}
public override void OnComplete()
{
System.AddObjective(new FindUzeraanFirstTaskObjective());
}
}
public class FindUzeraanFirstTaskObjective : QuestObjective
{
public override object Message => 1060387;
public override void OnComplete()
{
System.AddConversation(new UzeraanFirstTaskConversation());
}
}
public enum KillHordeMinionsStep
{
First,
LearnKarma,
Others
}
public class KillHordeMinionsObjective : QuestObjective
{
public KillHordeMinionsObjective()
{
}
public KillHordeMinionsObjective(KillHordeMinionsStep step)
{
Step = step;
}
public KillHordeMinionsStep Step{ get; private set; }
public override object Message
{
get
{
switch (Step)
{
case KillHordeMinionsStep.First:
/* Find the mountain pass beyond the house which lies at the
* end of the runic road.<BR><BR>
*
* Assist the city Militia by slaying <I>Horde Minions</I>
*/
return 1049089;
case KillHordeMinionsStep.LearnKarma:
/* You have just gained some <a href="?ForceTopic45">Karma</a>
* for killing the horde minion. <a href="?ForceTopic134">Learn</a>
* how this affects your Paladin abilities.
*/
return 1060389;
default:
// Continue driving back the Horde Minions, as Uzeraan instructed you to do.
return 1060507;
}
}
}
public override int MaxProgress
{
get
{
if (System.From.Profession == 5) // paladin
switch (Step)
{
case KillHordeMinionsStep.First: return 1;
case KillHordeMinionsStep.LearnKarma: return 2;
default: return 5;
}
return 5;
}
}
public override bool Completed
{
get
{
if (Step == KillHordeMinionsStep.LearnKarma && HasBeenRead)
return true;
return base.Completed;
}
}
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
gump.AddHtmlObject(70, 260, 270, 100, 1049090, BaseQuestGump.Blue, false, false); // Horde Minions killed:
gump.AddLabel(70, 280, 0x64, CurProgress.ToString());
}
else
{
base.RenderProgress(gump);
}
}
public override void OnRead()
{
CheckCompletionStatus();
}
public override bool IgnoreYoungProtection(Mobile from)
{
// This restriction continues until the quest is ended
if (from is HordeMinion && from.Map == Map.Trammel && from.X >= 3314 && from.X <= 3814 && from.Y >= 2345 &&
from.Y <= 3095) // Haven island
return true;
return false;
}
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is HordeMinion && corpse.Map == Map.Trammel && corpse.X >= 3314 && corpse.X <= 3814 &&
corpse.Y >= 2345 && corpse.Y <= 3095) // Haven island
{
if (CurProgress == 0)
System.From.Send(new DisplayHelpTopic(29, false)); // HEALING
CurProgress++;
}
}
public override void OnComplete()
{
if (System.From.Profession == 5)
switch (Step)
{
case KillHordeMinionsStep.First:
{
QuestObjective obj = new KillHordeMinionsObjective(KillHordeMinionsStep.LearnKarma);
System.AddObjective(obj);
obj.CurProgress = CurProgress;
break;
}
case KillHordeMinionsStep.LearnKarma:
{
QuestObjective obj = new KillHordeMinionsObjective(KillHordeMinionsStep.Others);
System.AddObjective(obj);
obj.CurProgress = CurProgress;
break;
}
default:
{
System.AddObjective(new FindUzeraanAboutReportObjective());
break;
}
}
else
System.AddObjective(new FindUzeraanAboutReportObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
Step = (KillHordeMinionsStep)reader.ReadEncodedInt();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt((int)Step);
}
}
public class FindUzeraanAboutReportObjective : QuestObjective
{
public override object Message => 1049091;
public override void OnComplete()
{
System.AddConversation(new UzeraanReportConversation());
}
}
public class FindSchmendrickObjective : QuestObjective
{
public override object Message => 1049120;
public override bool IgnoreYoungProtection(Mobile from)
{
// This restriction begins when this objective is completed, and continues until the quest is ended
if (Completed && from is RestlessSoul && from.Map == Map.Trammel && from.X >= 5199 && from.X <= 5271 &&
from.Y >= 1812 && from.Y <= 1865) // Schmendrick's cave
return true;
return false;
}
public override void OnComplete()
{
System.AddConversation(new SchmendrickConversation());
}
}
public class FindApprenticeObjective : QuestObjective
{
public override object Message => 1049323;
public override void OnComplete()
{
System.AddObjective(new ReturnScrollOfPowerObjective());
}
}
public class ReturnScrollOfPowerObjective : QuestObjective
{
public override object Message => 1049324;
public override void OnComplete()
{
System.AddConversation(new UzeraanScrollOfPowerConversation());
}
}
public class FindDryadObjective : QuestObjective
{
public override object Message => 1049358;
public override void OnComplete()
{
System.AddConversation(new DryadConversation());
}
}
public class ReturnFertileDirtObjective : QuestObjective
{
public override object Message => 1049327;
public override void OnComplete()
{
System.AddConversation(new UzeraanFertileDirtConversation());
}
}
public class GetDaemonBloodObjective : QuestObjective
{
private bool m_Ambushed;
public override object Message => 1049361;
public override void CheckProgress()
{
PlayerMobile player = System.From;
if (!m_Ambushed && player.Map == Map.Trammel && player.InRange(new Point3D(3456, 2558, 50), 30))
{
int x = player.X - 1;
int y = player.Y - 2;
int z = Map.Trammel.GetAverageZ(x, y);
if (Map.Trammel.CanSpawnMobile(x, y, z))
{
m_Ambushed = true;
player.LocalOverheadMessage(MessageType.Regular, 0x3B2,
1049330); // You have been ambushed! Fight for your honor!!!
BaseCreature creature = new HordeMinion();
creature.MoveToWorld(new Point3D(x, y, z), Map.Trammel);
creature.Combatant = player;
}
}
}
public override void OnComplete()
{
System.AddObjective(new ReturnDaemonBloodObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_Ambushed = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_Ambushed);
}
}
public class ReturnDaemonBloodObjective : QuestObjective
{
public override object Message => 1049332;
public override void OnComplete()
{
System.AddConversation(new UzeraanDaemonBloodConversation());
}
}
public class GetDaemonBoneObjective : QuestObjective
{
public Container CorpseWithBone{ get; set; }
public override object Message
{
get
{
if (System.From.Profession == 5) return 1060755;
/* Use Uzeraan's teleporter to get to the Haunted graveyard.<BR><BR>
*
* Slay the undead until you find a <I>Daemon Bone</I>.
*/
return 1049362;
}
}
public override void OnComplete()
{
System.AddObjective(new ReturnDaemonBoneObjective());
}
public override bool IgnoreYoungProtection(Mobile from)
{
// This restriction continues until the end of the quest
if ((from is Zombie || from is Skeleton) && from.Map == Map.Trammel && from.X >= 3391 && from.X <= 3424 &&
from.Y >= 2639 && from.Y <= 2664) // Haven graveyard
return true;
return false;
}
public override bool GetKillEvent(BaseCreature creature, Container corpse)
{
if (base.GetKillEvent(creature, corpse))
return true;
return UzeraanTurmoilQuest.HasLostDaemonBone(System.From);
}
public override void OnKill(BaseCreature creature, Container corpse)
{
if ((creature is Zombie || creature is Skeleton) && corpse.Map == Map.Trammel && corpse.X >= 3391 &&
corpse.X <= 3424 && corpse.Y >= 2639 && corpse.Y <= 2664) // Haven graveyard
if (Utility.RandomDouble() < 0.25)
CorpseWithBone = corpse;
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
CorpseWithBone = (Container)reader.ReadItem();
}
public override void ChildSerialize(GenericWriter writer)
{
if (CorpseWithBone?.Deleted == true)
CorpseWithBone = null;
writer.WriteEncodedInt(0); // version
writer.Write(CorpseWithBone);
}
}
public class ReturnDaemonBoneObjective : QuestObjective
{
public override object Message => 1049334;
public override void OnComplete()
{
System.AddConversation(new UzeraanDaemonBoneConversation());
}
}
public class CashBankCheckObjective : QuestObjective
{
public override object Message => 1049336;
public override void OnComplete()
{
System.AddConversation(new BankerConversation());
}
}
}

View file

@ -0,0 +1,167 @@
using System;
using Server.Mobiles;
namespace Server.Engines.Quests.Haven
{
public class UzeraanTurmoilQuest : QuestSystem
{
private static Type[] m_TypeReferenceTable =
{
typeof(AcceptConversation),
typeof(UzeraanTitheConversation),
typeof(UzeraanFirstTaskConversation),
typeof(UzeraanReportConversation),
typeof(SchmendrickConversation),
typeof(UzeraanScrollOfPowerConversation),
typeof(DryadConversation),
typeof(UzeraanFertileDirtConversation),
typeof(UzeraanDaemonBloodConversation),
typeof(UzeraanDaemonBoneConversation),
typeof(BankerConversation),
typeof(RadarConversation),
typeof(LostScrollOfPowerConversation),
typeof(LostFertileDirtConversation),
typeof(DryadAppleConversation),
typeof(LostDaemonBloodConversation),
typeof(LostDaemonBoneConversation),
typeof(FindUzeraanBeginObjective),
typeof(TitheGoldObjective),
typeof(FindUzeraanFirstTaskObjective),
typeof(KillHordeMinionsObjective),
typeof(FindUzeraanAboutReportObjective),
typeof(FindSchmendrickObjective),
typeof(FindApprenticeObjective),
typeof(ReturnScrollOfPowerObjective),
typeof(FindDryadObjective),
typeof(ReturnFertileDirtObjective),
typeof(GetDaemonBloodObjective),
typeof(ReturnDaemonBloodObjective),
typeof(GetDaemonBoneObjective),
typeof(ReturnDaemonBoneObjective),
typeof(CashBankCheckObjective),
typeof(FewReagentsConversation)
};
private bool m_HasLeftTheMansion;
public UzeraanTurmoilQuest(PlayerMobile from) : base(from)
{
}
// Serialization
public UzeraanTurmoilQuest()
{
}
public override Type[] TypeReferenceTable => m_TypeReferenceTable;
public override object Name => 1049007;
public override object OfferMessage => 1049008;
public override TimeSpan RestartDelay => TimeSpan.MaxValue;
public override bool IsTutorial => true;
public override int Picture
{
get
{
switch (From.Profession)
{
case 1: return 0x15C9; // warrior
case 2: return 0x15C1; // magician
default: return 0x15D3; // paladin
}
}
}
public override void Slice()
{
if (!m_HasLeftTheMansion &&
(From.Map != Map.Trammel || From.X < 3573 || From.X > 3611 || From.Y < 2568 || From.Y > 2606))
{
m_HasLeftTheMansion = true;
AddConversation(new RadarConversation());
}
base.Slice();
}
public override void Accept()
{
base.Accept();
AddConversation(new AcceptConversation());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_HasLeftTheMansion = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_HasLeftTheMansion);
}
public static bool HasLostScrollOfPower(Mobile from)
{
if (!(from is PlayerMobile pm))
return false;
QuestSystem qs = pm.Quest;
if (qs is UzeraanTurmoilQuest)
if (qs.IsObjectiveInProgress(typeof(ReturnScrollOfPowerObjective)))
return from.Backpack?.FindItemByType<SchmendrickScrollOfPower>() == null;
return false;
}
public static bool HasLostFertileDirt(Mobile from)
{
if (!(from is PlayerMobile pm))
return false;
QuestSystem qs = pm.Quest;
if (qs is UzeraanTurmoilQuest)
if (qs.IsObjectiveInProgress(typeof(ReturnFertileDirtObjective)))
return from.Backpack?.FindItemByType<QuestFertileDirt>() == null;
return false;
}
public static bool HasLostDaemonBlood(Mobile from)
{
if (!(from is PlayerMobile pm))
return false;
QuestSystem qs = pm.Quest;
if (qs is UzeraanTurmoilQuest)
if (qs.IsObjectiveInProgress(typeof(ReturnDaemonBloodObjective)))
return from.Backpack?.FindItemByType<QuestDaemonBlood>() == null;
return false;
}
public static bool HasLostDaemonBone(Mobile from)
{
if (!(from is PlayerMobile pm))
return false;
QuestSystem qs = pm.Quest;
if (qs is UzeraanTurmoilQuest)
if (qs.IsObjectiveInProgress(typeof(ReturnDaemonBoneObjective)))
return from.Backpack?.FindItemByType<QuestDaemonBone>() == null;
return false;
}
}
}