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,118 @@
using System;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Ambitious
{
public class AmbitiousQueenQuest : QuestSystem
{
private static Type[] m_TypeReferenceTable =
{
typeof(DontOfferConversation),
typeof(AcceptConversation),
typeof(DuringKillQueensConversation),
typeof(GatherFungiConversation),
typeof(DuringFungiGatheringConversation),
typeof(EndConversation),
typeof(FullBackpackConversation),
typeof(End2Conversation),
typeof(KillQueensObjective),
typeof(ReturnAfterKillsObjective),
typeof(GatherFungiObjective),
typeof(GetRewardObjective)
};
public AmbitiousQueenQuest(PlayerMobile from, bool redSolen) : base(from)
{
RedSolen = redSolen;
}
// Serialization
public AmbitiousQueenQuest()
{
}
public override Type[] TypeReferenceTable => m_TypeReferenceTable;
public override object Name => 1054146;
public override object OfferMessage => 1054060;
public override TimeSpan RestartDelay => TimeSpan.Zero;
public override bool IsTutorial => false;
public override int Picture => 0x15C9;
public bool RedSolen{ get; private set; }
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
RedSolen = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(RedSolen);
}
public override void Accept()
{
base.Accept();
AddConversation(new AcceptConversation());
}
public static void GiveRewardTo(PlayerMobile player, ref bool bagOfSending, ref bool powderOfTranslocation,
ref bool gold)
{
if (bagOfSending)
{
Item reward = new BagOfSending();
if (player.PlaceInBackpack(reward))
{
player.SendLocalizedMessage(1054074, "", 0x59); // You have been given a bag of sending.
bagOfSending = false;
}
else
{
reward.Delete();
}
}
if (powderOfTranslocation)
{
Item reward = new PowderOfTranslocation(Utility.RandomMinMax(10, 12));
if (player.PlaceInBackpack(reward))
{
player.SendLocalizedMessage(1054075, "", 0x59); // You have been given some powder of translocation.
powderOfTranslocation = false;
}
else
{
reward.Delete();
}
}
if (gold)
{
Item reward = new Gold(Utility.RandomMinMax(250, 350));
if (player.PlaceInBackpack(reward))
{
player.SendLocalizedMessage(1054076, "", 0x59); // You have been given some gold.
gold = false;
}
else
{
reward.Delete();
}
}
}
}
}

View file

@ -0,0 +1,123 @@
namespace Server.Engines.Quests.Ambitious
{
public class DontOfferConversation : QuestConversation
{
public override object Message => 1054059;
public override bool Logged => false;
}
public class AcceptConversation : QuestConversation
{
public override object Message => 1054061;
public override void OnRead()
{
System.AddObjective(new KillQueensObjective());
}
}
public class DuringKillQueensConversation : QuestConversation
{
public override object Message => 1054066;
public override bool Logged => false;
}
public class GatherFungiConversation : QuestConversation
{
public override object Message => 1054068;
public override void OnRead()
{
System.AddObjective(new GatherFungiObjective());
}
}
public class DuringFungiGatheringConversation : QuestConversation
{
public override object Message => 1054070;
public override bool Logged => false;
}
public class EndConversation : QuestConversation
{
public override object Message => 1054073;
public override void OnRead()
{
bool bagOfSending = true;
bool powderOfTranslocation = true;
bool gold = true;
AmbitiousQueenQuest.GiveRewardTo(System.From, ref bagOfSending, ref powderOfTranslocation, ref gold);
if (!bagOfSending && !powderOfTranslocation && !gold)
System.Complete();
else
System.AddConversation(new FullBackpackConversation(true, bagOfSending, powderOfTranslocation, gold));
}
}
public class FullBackpackConversation : QuestConversation
{
private bool m_BagOfSending;
private bool m_Gold;
private bool m_Logged;
private bool m_PowderOfTranslocation;
public FullBackpackConversation(bool logged, bool bagOfSending, bool powderOfTranslocation, bool gold)
{
m_Logged = logged;
m_BagOfSending = bagOfSending;
m_PowderOfTranslocation = powderOfTranslocation;
m_Gold = gold;
}
public FullBackpackConversation()
{
m_Logged = true;
}
public override object Message => 1054077;
public override bool Logged => m_Logged;
public override void OnRead()
{
if (m_Logged)
System.AddObjective(new GetRewardObjective(m_BagOfSending, m_PowderOfTranslocation, m_Gold));
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_BagOfSending = reader.ReadBool();
m_PowderOfTranslocation = reader.ReadBool();
m_Gold = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_BagOfSending);
writer.Write(m_PowderOfTranslocation);
writer.Write(m_Gold);
}
}
public class End2Conversation : QuestConversation
{
public override object Message => 1054078;
public override void OnRead()
{
System.Complete();
}
}
}

View file

@ -0,0 +1,199 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Ambitious
{
public abstract class BaseAmbitiousSolenQueen : BaseQuester
{
public BaseAmbitiousSolenQueen()
{
}
public BaseAmbitiousSolenQueen(Serial serial) : base(serial)
{
}
public abstract bool RedSolen{ get; }
public override string DefaultName => "an ambitious solen queen";
public override bool DisallowAllMoves => false;
public override void InitBody()
{
Body = 0x30F;
if (!RedSolen)
Hue = 0x453;
SpeechHue = 0;
}
public override int GetIdleSound()
{
return 0x10D;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
Direction = GetDirectionTo(player);
if (player.Quest is AmbitiousQueenQuest qs && qs.RedSolen == RedSolen)
{
if (qs.IsObjectiveInProgress(typeof(KillQueensObjective)))
{
qs.AddConversation(new DuringKillQueensConversation());
}
else
{
QuestObjective obj = qs.FindObjective<ReturnAfterKillsObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else if (qs.IsObjectiveInProgress(typeof(GatherFungiObjective)))
{
qs.AddConversation(new DuringFungiGatheringConversation());
}
else
{
GetRewardObjective lastObj = qs.FindObjective<GetRewardObjective>();
if (lastObj?.Completed == false)
{
bool bagOfSending = lastObj.BagOfSending;
bool powderOfTranslocation = lastObj.PowderOfTranslocation;
bool gold = lastObj.Gold;
AmbitiousQueenQuest.GiveRewardTo(player, ref bagOfSending, ref powderOfTranslocation, ref gold);
lastObj.BagOfSending = bagOfSending;
lastObj.PowderOfTranslocation = powderOfTranslocation;
lastObj.Gold = gold;
if (!bagOfSending && !powderOfTranslocation && !gold)
lastObj.Complete();
else
qs.AddConversation(new FullBackpackConversation(false, lastObj.BagOfSending,
lastObj.PowderOfTranslocation, lastObj.Gold));
}
}
}
}
else
{
QuestSystem newQuest = new AmbitiousQueenQuest(player, RedSolen);
if (player.Quest == null && QuestSystem.CanOfferQuest(player, typeof(AmbitiousQueenQuest)))
newQuest.SendOffer();
else
newQuest.AddConversation(new DontOfferConversation());
}
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
Direction = GetDirectionTo(from);
if (from is PlayerMobile player)
if (player.Quest is AmbitiousQueenQuest qs && qs.RedSolen == RedSolen)
{
QuestObjective obj = qs.FindObjective<GatherFungiObjective>();
if (obj?.Completed == false)
if (dropped is ZoogiFungus fungi)
{
if (fungi.Amount >= 50)
{
obj.Complete();
fungi.Amount -= 50;
if (fungi.Amount == 0)
{
fungi.Delete();
return true;
}
return false;
}
SayTo(player,
1054072); // Our arrangement was for 50 of the zoogi fungus. Please return to me when you have that amount.
return false;
}
}
return base.OnDragDrop(from, dropped);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class RedAmbitiousSolenQueen : BaseAmbitiousSolenQueen
{
[Constructible]
public RedAmbitiousSolenQueen()
{
}
public RedAmbitiousSolenQueen(Serial serial) : base(serial)
{
}
public override bool RedSolen => true;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class BlackAmbitiousSolenQueen : BaseAmbitiousSolenQueen
{
[Constructible]
public BlackAmbitiousSolenQueen()
{
}
public BlackAmbitiousSolenQueen(Serial serial) : base(serial)
{
}
public override bool RedSolen => false;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,127 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Ambitious
{
public class KillQueensObjective : QuestObjective
{
public override object Message => ((AmbitiousQueenQuest)System).RedSolen ? 1054062 : 1054063;
public override int MaxProgress => 5;
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
// Red/Black Solen Queens killed:
gump.AddHtmlLocalized(70, 260, 270, 100, ((AmbitiousQueenQuest)System).RedSolen ? 1054064 : 1054065,
BaseQuestGump.Blue);
gump.AddLabel(70, 280, 0x64, CurProgress.ToString());
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, MaxProgress.ToString());
}
else
{
base.RenderProgress(gump);
}
}
public override bool IgnoreYoungProtection(Mobile from)
{
if (Completed)
return false;
bool redSolen = ((AmbitiousQueenQuest)System).RedSolen;
if (redSolen)
return from is RedSolenQueen;
return from is BlackSolenQueen;
}
public override void OnKill(BaseCreature creature, Container corpse)
{
bool redSolen = ((AmbitiousQueenQuest)System).RedSolen;
if (redSolen)
{
if (creature is RedSolenQueen)
CurProgress++;
}
else
{
if (creature is BlackSolenQueen)
CurProgress++;
}
}
public override void OnComplete()
{
System.AddObjective(new ReturnAfterKillsObjective());
}
}
public class ReturnAfterKillsObjective : QuestObjective
{
public override object Message => 1054067;
public override void OnComplete()
{
System.AddConversation(new GatherFungiConversation());
}
}
public class GatherFungiObjective : QuestObjective
{
public override object Message => 1054069;
public override void OnComplete()
{
System.AddConversation(new EndConversation());
}
}
public class GetRewardObjective : QuestObjective
{
public GetRewardObjective(bool bagOfSending, bool powderOfTranslocation, bool gold)
{
BagOfSending = bagOfSending;
PowderOfTranslocation = powderOfTranslocation;
Gold = gold;
}
public GetRewardObjective()
{
}
public override object Message => 1054148;
public bool BagOfSending{ get; set; }
public bool PowderOfTranslocation{ get; set; }
public bool Gold{ get; set; }
public override void OnComplete()
{
System.AddConversation(new End2Conversation());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
BagOfSending = reader.ReadBool();
PowderOfTranslocation = reader.ReadBool();
Gold = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(BagOfSending);
writer.Write(PowderOfTranslocation);
writer.Write(Gold);
}
}
}

View file

@ -0,0 +1,89 @@
using System;
using Server.Mobiles;
namespace Server.Engines.Quests.Collector
{
public class CollectorQuest : QuestSystem
{
private static Type[] m_TypeReferenceTable =
{
typeof(DontOfferConversation),
typeof(DeclineConversation),
typeof(AcceptConversation),
typeof(ElwoodDuringFishConversation),
typeof(ReturnPearlsConversation),
typeof(AlbertaPaintingConversation),
typeof(AlbertaStoolConversation),
typeof(AlbertaEndPaintingConversation),
typeof(AlbertaAfterPaintingConversation),
typeof(ElwoodDuringPainting1Conversation),
typeof(ElwoodDuringPainting2Conversation),
typeof(ReturnPaintingConversation),
typeof(GabrielAutographConversation),
typeof(GabrielNoSheetMusicConversation),
typeof(NoSheetMusicConversation),
typeof(GetSheetMusicConversation),
typeof(GabrielSheetMusicConversation),
typeof(GabrielIgnoreConversation),
typeof(ElwoodDuringAutograph1Conversation),
typeof(ElwoodDuringAutograph2Conversation),
typeof(ElwoodDuringAutograph3Conversation),
typeof(ReturnAutographConversation),
typeof(TomasToysConversation),
typeof(TomasDuringCollectingConversation),
typeof(ReturnImagesConversation),
typeof(ElwoodDuringToys1Conversation),
typeof(ElwoodDuringToys2Conversation),
typeof(ElwoodDuringToys3Conversation),
typeof(FullEndConversation),
typeof(FishPearlsObjective),
typeof(ReturnPearlsObjective),
typeof(FindAlbertaObjective),
typeof(SitOnTheStoolObjective),
typeof(ReturnPaintingObjective),
typeof(FindGabrielObjective),
typeof(FindSheetMusicObjective),
typeof(ReturnSheetMusicObjective),
typeof(ReturnAutographObjective),
typeof(FindTomasObjective),
typeof(CaptureImagesObjective),
typeof(ReturnImagesObjective),
typeof(ReturnToysObjective),
typeof(MakeRoomObjective)
};
public CollectorQuest(PlayerMobile from) : base(from)
{
}
// Serialization
public CollectorQuest()
{
}
public override Type[] TypeReferenceTable => m_TypeReferenceTable;
public override object Name => "Collector's Quest";
public override object OfferMessage => 1055081;
public override TimeSpan RestartDelay => TimeSpan.Zero;
public override bool IsTutorial => false;
public override int Picture => 0x15A9;
public override void Accept()
{
base.Accept();
AddConversation(new AcceptConversation());
}
public override void Decline()
{
base.Decline();
AddConversation(new DeclineConversation());
}
}
}

View file

@ -0,0 +1,266 @@
namespace Server.Engines.Quests.Collector
{
public class DontOfferConversation : QuestConversation
{
public override object Message => 1055080;
public override bool Logged => false;
}
public class DeclineConversation : QuestConversation
{
public override object Message => 1055082;
public override bool Logged => false;
}
public class AcceptConversation : QuestConversation
{
public override object Message => 1055083;
public override void OnRead()
{
System.AddObjective(new FishPearlsObjective());
}
}
public class ElwoodDuringFishConversation : QuestConversation
{
public override object Message => 1055089;
public override bool Logged => false;
}
public class ReturnPearlsConversation : QuestConversation
{
public override object Message => 1055090;
public override void OnRead()
{
System.AddObjective(new FindAlbertaObjective());
}
}
public class AlbertaPaintingConversation : QuestConversation
{
public override object Message => 1055092;
public override void OnRead()
{
System.AddObjective(new SitOnTheStoolObjective());
}
}
public class AlbertaStoolConversation : QuestConversation
{
public override object Message => 1055096;
public override bool Logged => false;
}
public class AlbertaEndPaintingConversation : QuestConversation
{
public override object Message => 1055098;
public override void OnRead()
{
System.AddObjective(new ReturnPaintingObjective());
}
}
public class AlbertaAfterPaintingConversation : QuestConversation
{
public override object Message => 1055102;
public override bool Logged => false;
}
public class ElwoodDuringPainting1Conversation : QuestConversation
{
public override object Message => 1055094;
public override bool Logged => false;
}
public class ElwoodDuringPainting2Conversation : QuestConversation
{
public override object Message => 1055097;
public override bool Logged => false;
}
public class ReturnPaintingConversation : QuestConversation
{
public override object Message => 1055100;
public override void OnRead()
{
System.AddObjective(new FindGabrielObjective());
}
}
public class GabrielAutographConversation : QuestConversation
{
public override object Message => 1055103;
public override void OnRead()
{
System.AddObjective(new FindSheetMusicObjective(true));
}
}
public class GabrielNoSheetMusicConversation : QuestConversation
{
public override object Message => 1055111;
public override bool Logged => false;
}
public class NoSheetMusicConversation : QuestConversation
{
public override object Message => 1055106;
public override bool Logged => false;
}
public class GetSheetMusicConversation : QuestConversation
{
public override object Message => 1055109;
public override void OnRead()
{
System.AddObjective(new ReturnSheetMusicObjective());
}
}
public class GabrielSheetMusicConversation : QuestConversation
{
public override object Message => 1055113;
public override void OnRead()
{
System.AddObjective(new ReturnAutographObjective());
}
}
public class GabrielIgnoreConversation : QuestConversation
{
public override object Message => 1055118;
public override bool Logged => false;
}
public class ElwoodDuringAutograph1Conversation : QuestConversation
{
public override object Message => 1055105;
public override bool Logged => false;
}
public class ElwoodDuringAutograph2Conversation : QuestConversation
{
public override object Message => 1055112;
public override bool Logged => false;
}
public class ElwoodDuringAutograph3Conversation : QuestConversation
{
public override object Message => 1055115;
public override bool Logged => false;
}
public class ReturnAutographConversation : QuestConversation
{
public override object Message => 1055116;
public override void OnRead()
{
System.AddObjective(new FindTomasObjective());
}
}
public class TomasToysConversation : QuestConversation
{
public override object Message => 1055119;
public override void OnRead()
{
System.AddObjective(new CaptureImagesObjective(true));
}
}
public class TomasDuringCollectingConversation : QuestConversation
{
public override object Message => 1055129;
public override bool Logged => false;
}
public class ReturnImagesConversation : QuestConversation
{
public override object Message => 1055131;
public override void OnRead()
{
System.AddObjective(new ReturnToysObjective());
}
}
public class ElwoodDuringToys1Conversation : QuestConversation
{
public override object Message => 1055123;
public override bool Logged => false;
}
public class ElwoodDuringToys2Conversation : QuestConversation
{
public override object Message => 1055130;
public override bool Logged => false;
}
public class ElwoodDuringToys3Conversation : QuestConversation
{
public override object Message => 1055133;
public override bool Logged => false;
}
public class EndConversation : QuestConversation
{
public override object Message => 1055134;
public override void OnRead()
{
System.Complete();
}
}
public class FullEndConversation : QuestConversation
{
private bool m_Logged;
public FullEndConversation(bool logged)
{
m_Logged = logged;
}
public FullEndConversation()
{
m_Logged = true;
}
public override object Message => 1055135;
public override bool Logged => m_Logged;
public override void OnRead()
{
if (m_Logged)
System.AddObjective(new MakeRoomObjective());
}
}
}

View file

@ -0,0 +1,133 @@
using Server.Mobiles;
using Server.Targeting;
namespace Server.Engines.Quests.Collector
{
public class EnchantedPaints : QuestItem
{
[Constructible]
public EnchantedPaints() : base(0xFC1)
{
LootType = LootType.Blessed;
Weight = 1.0;
}
public EnchantedPaints(Serial serial) : base(serial)
{
}
public override bool CanDrop(PlayerMobile player)
{
return !(player.Quest is CollectorQuest);
/*return !( qs.IsObjectiveInProgress( typeof( CaptureImagesObjective ) )
|| qs.IsObjectiveInProgress( typeof( ReturnImagesObjective ) ) );*/
}
public override void OnDoubleClick(Mobile from)
{
if (from is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is CollectorQuest)
if (qs.IsObjectiveInProgress(typeof(CaptureImagesObjective)))
{
player.SendAsciiMessage(0x59, "Target the creature whose image you wish to create.");
player.Target = new InternalTarget(this);
return;
}
}
from.SendLocalizedMessage(1010085); // You cannot use this.
}
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();
}
private class InternalTarget : Target
{
private EnchantedPaints m_Paints;
public InternalTarget(EnchantedPaints paints) : base(-1, false, TargetFlags.None)
{
CheckLOS = false;
m_Paints = paints;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (m_Paints.Deleted || !m_Paints.IsChildOf(from.Backpack))
return;
if (from is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (!(qs is CollectorQuest))
return;
CaptureImagesObjective obj = qs.FindObjective<CaptureImagesObjective>();
if (obj?.Completed != false)
return;
if (targeted is Mobile)
{
CaptureResponse response = obj.CaptureImage(
targeted.GetType().Name == "GreaterMongbat"
? new Mongbat().GetType()
: targeted.GetType(), out ImageType image);
switch (response)
{
case CaptureResponse.Valid:
{
player.SendLocalizedMessage(
1055125); // The enchanted paints swirl for a moment then an image begins to take shape. *Click*
player.AddToBackpack(new PaintedImage(image));
break;
}
case CaptureResponse.AlreadyDone:
{
player.SendAsciiMessage(0x2C,
"You have already captured the image of this creature");
break;
}
case CaptureResponse.Invalid:
{
player.SendLocalizedMessage(
1055124); // You have no interest in capturing the image of this creature.
break;
}
}
}
else
{
player.SendAsciiMessage(0x35, "You have no interest in that.");
}
return;
}
from.SendLocalizedMessage(1010085); // You cannot use this.
}
}
}
}

View file

@ -0,0 +1,97 @@
using System;
using System.Linq;
using Server.Mobiles;
namespace Server.Engines.Quests.Collector
{
public enum ImageType
{
Betrayer,
Bogling,
BogThing,
Gazer,
Beetle,
GiantBlackWidow,
Scorpion,
JukaMage,
JukaWarrior,
Lich,
MeerMage,
MeerWarrior,
Mongbat,
Mummy,
Pixie,
PlagueBeast,
SandVortex,
StoneGargoyle,
SwampDragon,
Wisp,
Juggernaut
}
public class ImageTypeInfo
{
private static readonly ImageTypeInfo[] m_Table =
{
new ImageTypeInfo(9734, typeof(Betrayer), 75, 45),
new ImageTypeInfo(9735, typeof(Bogling), 75, 45),
new ImageTypeInfo(9736, typeof(BogThing), 60, 47),
new ImageTypeInfo(9615, typeof(Gazer), 75, 45),
new ImageTypeInfo(9743, typeof(Beetle), 60, 55),
new ImageTypeInfo(9667, typeof(GiantBlackWidow), 55, 52),
new ImageTypeInfo(9657, typeof(Scorpion), 65, 47),
new ImageTypeInfo(9758, typeof(JukaMage), 75, 45),
new ImageTypeInfo(9759, typeof(JukaWarrior), 75, 45),
new ImageTypeInfo(9636, typeof(Lich), 75, 45),
new ImageTypeInfo(9756, typeof(MeerMage), 75, 45),
new ImageTypeInfo(9757, typeof(MeerWarrior), 75, 45),
new ImageTypeInfo(9638, typeof(Mongbat), 70, 50),
new ImageTypeInfo(9639, typeof(Mummy), 75, 45),
new ImageTypeInfo(9654, typeof(Pixie), 75, 45),
new ImageTypeInfo(9747, typeof(PlagueBeast), 60, 45),
new ImageTypeInfo(9750, typeof(SandVortex), 60, 43),
new ImageTypeInfo(9614, typeof(StoneGargoyle), 75, 45),
new ImageTypeInfo(9753, typeof(SwampDragon), 50, 55),
new ImageTypeInfo(8448, typeof(Wisp), 75, 45),
new ImageTypeInfo(9746, typeof(Juggernaut), 55, 38)
};
private static ImageType[] m_ImageTypeList;
public ImageTypeInfo(int figurine, Type type, int x, int y)
{
Figurine = figurine;
Type = type;
X = x;
Y = y;
}
public int Figurine{ get; }
public Type Type{ get; }
public int Name => Figurine < 0x4000 ? 1020000 + Figurine : 1078872 + Figurine;
public int X{ get; }
public int Y{ get; }
public static ImageTypeInfo Get(ImageType image)
{
int index = (int)image;
return m_Table[index >= 0 && index < m_Table.Length ? index : 0];
}
public static ImageType[] RandomList(int count)
{
if (m_ImageTypeList == null)
{
m_ImageTypeList = new ImageType[m_Table.Length];
for (int i = 0; i < m_Table.Length; i++)
m_ImageTypeList[i] = (ImageType)i;
}
ImageType[] array = m_ImageTypeList.ToArray();
Utility.Shuffle(array);
return array.Take(count).ToArray();
}
}
}

View file

@ -0,0 +1,265 @@
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Network;
using Server.Targeting;
namespace Server.Engines.Quests.Collector
{
public class Obsidian : Item
{
private const int m_Partial = 2;
private const int m_Completed = 10;
private static readonly string[] m_Names =
{
null,
"an aggressive cavalier",
"a beguiling rogue",
"a benevolent physician",
"a brilliant artisan",
"a capricious adventurer",
"a clever beggar",
"a convincing charlatan",
"a creative inventor",
"a creative tinker",
"a cunning knave",
"a dauntless explorer",
"a despicable ruffian",
"an earnest malcontent",
"an exultant animal tamer",
"a famed adventurer",
"a fanatical crusader",
"a fastidious clerk",
"a fearless hunter",
"a festive harlequin",
"a fidgety assassin",
"a fierce soldier",
"a fierce warrior",
"a frugal magnate",
"a glib pundit",
"a gnomic shaman",
"a graceful noblewoman",
"a idiotic madman",
"a imaginative designer",
"an inept conjurer",
"an innovative architect",
"an inventive blacksmith",
"a judicious mayor",
"a masterful chef",
"a masterful woodworker",
"a melancholy clown",
"a melodic bard",
"a merciful guard",
"a mirthful jester",
"a nervous surgeon",
"a peaceful scholar",
"a prolific gardener",
"a quixotic knight",
"a regal aristocrat",
"a resourceful smith",
"a reticent alchemist",
"a sanctified priest",
"a scheming patrician",
"a shrewd mage",
"a singing minstrel",
"a skilled tailor",
"a squeamish assassin",
"a stoic swordsman",
"a studious scribe",
"a thought provoking writer",
"a treacherous scoundrel",
"a troubled poet",
"an unflappable wizard",
"a valiant warrior",
"a wayward fool"
};
private int m_Quantity;
private string m_StatueName;
[Constructible]
public Obsidian() : base(0x1EA7)
{
Hue = 0x497;
m_Quantity = 1;
m_StatueName = "";
}
public Obsidian(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public int Quantity
{
get => m_Quantity;
set
{
if (value <= 1)
m_Quantity = 1;
else if (value >= m_Completed)
m_Quantity = m_Completed;
else
m_Quantity = value;
if (m_Quantity < m_Partial)
ItemID = 0x1EA7;
else if (m_Quantity < m_Completed)
ItemID = 0x1F13;
else
ItemID = 0x12CB;
InvalidateProperties();
}
}
[CommandProperty(AccessLevel.GameMaster)]
public string StatueName
{
get => m_StatueName;
set
{
m_StatueName = value;
InvalidateProperties();
}
}
public override bool ForceShowProperties => ObjectPropertyList.Enabled;
public static string RandomName(Mobile from)
{
int index = Utility.Random(m_Names.Length);
if (m_Names[index] == null)
return from.Name;
return m_Names[index];
}
public override void AddNameProperty(ObjectPropertyList list)
{
if (m_Quantity < m_Partial)
list.Add(1055137); // a section of an obsidian statue
else if (m_Quantity < m_Completed)
list.Add(1055138); // a partially reconstructed obsidian statue
else
list.Add(1055139, m_StatueName); // an obsidian statue of ~1_STATUE_NAME~
}
public override void OnSingleClick(Mobile from)
{
if (m_Quantity < m_Partial)
LabelTo(from, 1055137); // a section of an obsidian statue
else if (m_Quantity < m_Completed)
LabelTo(from, 1055138); // a partially reconstructed obsidian statue
else
LabelTo(from, 1055139, m_StatueName); // an obsidian statue of ~1_STATUE_NAME~
}
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
{
base.GetContextMenuEntries(from, list);
if (from.Alive && m_Quantity >= m_Partial && m_Quantity < m_Completed && IsChildOf(from.Backpack))
list.Add(new DisassembleEntry(this));
}
public override void OnDoubleClick(Mobile from)
{
if (m_Quantity < m_Completed)
{
if (!IsChildOf(from.Backpack))
from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x2C, 3, 500309, "",
"")); // Nothing Happens.
else
from.Target = new InternalTarget(this);
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.WriteEncodedInt(m_Quantity);
writer.Write(m_StatueName);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Quantity = reader.ReadEncodedInt();
m_StatueName = Utility.Intern(reader.ReadString());
}
private class DisassembleEntry : ContextMenuEntry
{
private Obsidian m_Obsidian;
public DisassembleEntry(Obsidian obsidian) : base(6142)
{
m_Obsidian = obsidian;
}
public override void OnClick()
{
Mobile from = Owner.From;
if (!m_Obsidian.Deleted && m_Obsidian.Quantity >= m_Partial && m_Obsidian.Quantity < m_Completed &&
m_Obsidian.IsChildOf(from.Backpack) && from.CheckAlive())
{
for (int i = 0; i < m_Obsidian.Quantity - 1; i++)
from.AddToBackpack(new Obsidian());
m_Obsidian.Quantity = 1;
}
}
}
private class InternalTarget : Target
{
private Obsidian m_Obsidian;
public InternalTarget(Obsidian obsidian) : base(-1, false, TargetFlags.None)
{
m_Obsidian = obsidian;
}
protected override void OnTarget(Mobile from, object targeted)
{
if (m_Obsidian.Deleted || m_Obsidian.Quantity >= m_Completed || !(targeted is Item targ))
return;
if (m_Obsidian.IsChildOf(from.Backpack) && targ.IsChildOf(from.Backpack) && targ is Obsidian targObsidian &&
targ != m_Obsidian)
if (targObsidian.Quantity < m_Completed)
{
if (targObsidian.Quantity + m_Obsidian.Quantity <= m_Completed)
{
targObsidian.Quantity += m_Obsidian.Quantity;
m_Obsidian.Delete();
}
else
{
int delta = m_Completed - targObsidian.Quantity;
targObsidian.Quantity += delta;
m_Obsidian.Quantity -= delta;
}
if (targObsidian.Quantity >= m_Completed)
targObsidian.StatueName = RandomName(from);
from.Send(new AsciiMessage(targObsidian.Serial, targObsidian.ItemID, MessageType.Regular, 0x59, 3,
m_Obsidian.Name, "Something Happened."));
return;
}
from.Send(new MessageLocalized(m_Obsidian.Serial, m_Obsidian.ItemID, MessageType.Regular, 0x2C, 3, 500309,
m_Obsidian.Name, "")); // Nothing Happens.
}
}
}
}

View file

@ -0,0 +1,88 @@
using Server.Gumps;
using Server.Network;
namespace Server.Engines.Quests.Collector
{
public class PaintedImage : Item
{
private ImageType m_Image;
[Constructible]
public PaintedImage(ImageType image) : base(0xFF3)
{
Weight = 1.0;
Hue = 0x8FD;
m_Image = image;
}
public PaintedImage(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public ImageType Image
{
get => m_Image;
set
{
m_Image = value;
InvalidateProperties();
}
}
public override void AddNameProperty(ObjectPropertyList list)
{
ImageTypeInfo info = ImageTypeInfo.Get(m_Image);
list.Add(1060847, "#1055126\t#" + info.Name); // a painted image of:
}
public override void OnSingleClick(Mobile from)
{
ImageTypeInfo info = ImageTypeInfo.Get(m_Image);
LabelTo(from, 1060847, "#1055126\t#" + info.Name); // a painted image of:
}
public override void OnDoubleClick(Mobile from)
{
if (!from.InRange(GetWorldLocation(), 2))
{
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
return;
}
from.SendGump(new InternalGump(m_Image));
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.WriteEncodedInt((int)m_Image);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Image = (ImageType)reader.ReadEncodedInt();
}
private class InternalGump : Gump
{
public InternalGump(ImageType image) : base(75, 25)
{
ImageTypeInfo info = ImageTypeInfo.Get(image);
AddBackground(45, 20, 100, 100, 0xA3C);
AddBackground(52, 29, 86, 82, 0xBB8);
AddItem(info.X, info.Y, info.Figurine);
}
}
}
}

View file

@ -0,0 +1,86 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Collector
{
public class AlbertaGiacco : BaseQuester
{
[Constructible]
public AlbertaGiacco() : base("the respected painter")
{
}
public AlbertaGiacco(Serial serial) : base(serial)
{
}
public override string DefaultName => "Alberta Giacco";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83F2;
Female = true;
Body = 0x191;
}
public override void InitOutfit()
{
AddItem(new FancyShirt());
AddItem(new Skirt(0x59B));
AddItem(new Boots());
AddItem(new FeatheredHat(0x59B));
AddItem(new FullApron(0x59B));
HairItemID = 0x203D; // Pony Tail
HairHue = 0x457;
}
public override bool CanTalkTo(PlayerMobile to)
{
QuestSystem qs = to.Quest as CollectorQuest;
if (qs == null)
return false;
return qs.IsObjectiveInProgress(typeof(FindAlbertaObjective))
|| qs.IsObjectiveInProgress(typeof(SitOnTheStoolObjective))
|| qs.IsObjectiveInProgress(typeof(ReturnPaintingObjective));
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is CollectorQuest)
{
Direction = GetDirectionTo(player);
QuestObjective obj = qs.FindObjective<FindAlbertaObjective>();
if (obj?.Completed == false)
obj.Complete();
else if (qs.IsObjectiveInProgress(typeof(SitOnTheStoolObjective)))
qs.AddConversation(new AlbertaStoolConversation());
else if (qs.IsObjectiveInProgress(typeof(ReturnPaintingObjective)))
qs.AddConversation(new AlbertaAfterPaintingConversation());
}
}
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,228 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Collector
{
public class ElwoodMcCarrin : BaseQuester
{
[Constructible]
public ElwoodMcCarrin() : base("the well-known collector")
{
}
public ElwoodMcCarrin(Serial serial) : base(serial)
{
}
public override string DefaultName => "Elwood McCarrin";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83ED;
Female = false;
Body = 0x190;
}
public override void InitOutfit()
{
AddItem(new FancyShirt());
AddItem(new LongPants(0x544));
AddItem(new Shoes(0x454));
AddItem(new JesterHat(0x4D2));
AddItem(new FullApron(0x4D2));
HairItemID = 0x203D; // Pony Tail
HairHue = 0x47D;
FacialHairItemID = 0x2040; // Goatee
FacialHairHue = 0x47D;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
Direction = GetDirectionTo(player);
QuestSystem qs = player.Quest;
if (qs is CollectorQuest)
{
if (qs.IsObjectiveInProgress(typeof(FishPearlsObjective)))
{
qs.AddConversation(new ElwoodDuringFishConversation());
}
else
{
QuestObjective obj = qs.FindObjective<ReturnPearlsObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else if (qs.IsObjectiveInProgress(typeof(FindAlbertaObjective)))
{
qs.AddConversation(new ElwoodDuringPainting1Conversation());
}
else if (qs.IsObjectiveInProgress(typeof(SitOnTheStoolObjective)))
{
qs.AddConversation(new ElwoodDuringPainting2Conversation());
}
else
{
obj = qs.FindObjective<ReturnPaintingObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else if (qs.IsObjectiveInProgress(typeof(FindGabrielObjective)))
{
qs.AddConversation(new ElwoodDuringAutograph1Conversation());
}
else if (qs.IsObjectiveInProgress(typeof(FindSheetMusicObjective)))
{
qs.AddConversation(new ElwoodDuringAutograph2Conversation());
}
else if (qs.IsObjectiveInProgress(typeof(ReturnSheetMusicObjective)))
{
qs.AddConversation(new ElwoodDuringAutograph3Conversation());
}
else
{
obj = qs.FindObjective<ReturnAutographObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else if (qs.IsObjectiveInProgress(typeof(FindTomasObjective)))
{
qs.AddConversation(new ElwoodDuringToys1Conversation());
}
else if (qs.IsObjectiveInProgress(typeof(CaptureImagesObjective)))
{
qs.AddConversation(new ElwoodDuringToys2Conversation());
}
else if (qs.IsObjectiveInProgress(typeof(ReturnImagesObjective)))
{
qs.AddConversation(new ElwoodDuringToys3Conversation());
}
else
{
obj = qs.FindObjective<ReturnToysObjective>();
if (obj?.Completed == false)
{
obj.Complete();
if (GiveReward(player))
qs.AddConversation(new EndConversation());
else
qs.AddConversation(new FullEndConversation(true));
}
else
{
obj = qs.FindObjective<MakeRoomObjective>();
if (obj?.Completed == false)
{
if (GiveReward(player))
{
obj.Complete();
qs.AddConversation(new EndConversation());
}
else
{
qs.AddConversation(new FullEndConversation(false));
}
}
}
}
}
}
}
}
else
{
QuestSystem newQuest = new CollectorQuest(player);
if (qs == null && QuestSystem.CanOfferQuest(player, typeof(CollectorQuest)))
newQuest.SendOffer();
else
newQuest.AddConversation(new DontOfferConversation());
}
}
public bool GiveReward(Mobile to)
{
Bag bag = new Bag();
bag.DropItem(new Gold(Utility.RandomMinMax(500, 1000)));
if (Utility.RandomBool())
{
BaseWeapon weapon = Loot.RandomWeapon();
if (Core.AOS)
{
BaseRunicTool.ApplyAttributesTo(weapon, 2, 20, 30);
}
else
{
weapon.DamageLevel = (WeaponDamageLevel)RandomMinMaxScaled(2, 3);
weapon.AccuracyLevel = (WeaponAccuracyLevel)RandomMinMaxScaled(2, 3);
weapon.DurabilityLevel = (WeaponDurabilityLevel)RandomMinMaxScaled(2, 3);
}
bag.DropItem(weapon);
}
else
{
Item item;
if (Core.AOS)
{
item = Loot.RandomArmorOrShieldOrJewelry();
if (item is BaseArmor armor)
BaseRunicTool.ApplyAttributesTo(armor, 2, 20, 30);
else if (item is BaseJewel jewel)
BaseRunicTool.ApplyAttributesTo(jewel, 2, 20, 30);
}
else
{
BaseArmor armor = Loot.RandomArmorOrShield();
item = armor;
armor.ProtectionLevel = (ArmorProtectionLevel)RandomMinMaxScaled(2, 3);
armor.Durability = (ArmorDurabilityLevel)RandomMinMaxScaled(2, 3);
}
bag.DropItem(item);
}
bag.DropItem(new Obsidian());
if (to.PlaceInBackpack(bag)) return true;
bag.Delete();
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,99 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Collector
{
public class GabrielPiete : BaseQuester
{
[Constructible]
public GabrielPiete() : base("the renowned minstrel")
{
}
public GabrielPiete(Serial serial) : base(serial)
{
}
public override string DefaultName => "Gabriel Piete";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83EF;
Female = false;
Body = 0x190;
}
public override void InitOutfit()
{
AddItem(new FancyShirt());
AddItem(new LongPants(0x5F7));
AddItem(new Shoes(0x5F7));
HairItemID = 0x2049; // Pig Tails
HairHue = 0x460;
FacialHairItemID = 0x2041; // Mustache
FacialHairHue = 0x460;
}
public override bool CanTalkTo(PlayerMobile to)
{
QuestSystem qs = to.Quest as CollectorQuest;
if (qs == null)
return false;
return qs.IsObjectiveInProgress(typeof(FindGabrielObjective))
|| qs.IsObjectiveInProgress(typeof(FindSheetMusicObjective))
|| qs.IsObjectiveInProgress(typeof(ReturnSheetMusicObjective))
|| qs.IsObjectiveInProgress(typeof(ReturnAutographObjective));
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is CollectorQuest)
{
Direction = GetDirectionTo(player);
QuestObjective obj = qs.FindObjective<FindGabrielObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else if (qs.IsObjectiveInProgress(typeof(FindSheetMusicObjective)))
{
qs.AddConversation(new GabrielNoSheetMusicConversation());
}
else
{
obj = qs.FindObjective<ReturnSheetMusicObjective>();
if (obj?.Completed == false)
obj.Complete();
else if (qs.IsObjectiveInProgress(typeof(ReturnAutographObjective)))
qs.AddConversation(new GabrielIgnoreConversation());
}
}
}
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,163 @@
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Collector
{
public class Impresario : BaseQuester
{
[Constructible]
public Impresario() : base("the impresario")
{
}
public Impresario(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 FancyShirt(Utility.RandomDyedHue()));
AddItem(new LongPants(Utility.RandomNondyedHue()));
AddItem(new Shoes(Utility.RandomNeutralHue()));
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this);
}
public override bool CanTalkTo(PlayerMobile to)
{
QuestSystem qs = to.Quest as CollectorQuest;
if (qs == null)
return false;
return qs.IsObjectiveInProgress(typeof(FindSheetMusicObjective));
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (!(qs is CollectorQuest))
return;
FindSheetMusicObjective obj = qs.FindObjective<FindSheetMusicObjective>();
if (obj?.Completed == false)
{
Direction = GetDirectionTo(player);
if (obj.IsInRightTheater())
{
player.CloseGump<SheetMusicOfferGump>();
player.SendGump(new SheetMusicOfferGump());
}
else
{
qs.AddConversation(new NoSheetMusicConversation());
}
}
}
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 SheetMusicOfferGump : BaseQuestGump
{
public SheetMusicOfferGump() : base(75, 25)
{
Closable = false;
AddImage(349, 10, 0x24B0);
AddImageTiled(349, 130, 100, 120, 0x24B3);
AddImageTiled(149, 10, 200, 140, 0x24AF);
AddImageTiled(149, 300, 200, 140, 0x24B5);
AddImage(349, 300, 0x24B6);
AddImage(35, 10, 0x24AE);
AddImageTiled(35, 150, 120, 100, 0x24B1);
AddImage(35, 300, 0x24B4);
AddHtmlLocalized(110, 60, 200, 20, 1049069, White); // <STRONG>Conversation Event</STRONG>
AddImage(65, 14, 0x2776);
AddImageTiled(81, 14, 349, 17, 0x2775);
AddImage(426, 14, 0x2778);
AddImageTiled(50, 37, 400, 376, 0xA40);
AddAlphaRegion(50, 37, 400, 376);
AddImage(0, 0, 0x28C8);
AddImageTiled(75, 90, 200, 1, 0x238D);
AddImage(75, 58, 0x2635);
AddImage(380, 45, 0xDF);
AddHtmlLocalized(98, 140, 312, 200, 1055107, LightGreen, false,
true); // Sure, I have some sheet music for a Gabriel Piete song. I'd be happy to sell you a copy for 10 gold.
AddRadio(85, 350, 0x25F8, 0x25FB, true, 1);
AddHtmlLocalized(120, 356, 280, 20, 1014088, White); // I accept.
AddRadio(85, 385, 0x25F8, 0x25FB, false, 0);
AddHtmlLocalized(120, 391, 280, 20, 1049012, White); // No thanks, I decline.
AddButton(340, 390, 0xF7, 0xF8, 1);
}
public override void OnResponse(NetState sender, RelayInfo info)
{
if (info.ButtonID == 1 && info.IsSwitched(1))
if (sender.Mobile is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (!(qs is CollectorQuest))
return;
FindSheetMusicObjective obj = qs.FindObjective<FindSheetMusicObjective>();
if (obj?.Completed != false)
return;
if (player.Backpack?.ConsumeTotal(typeof(Gold), 10) == true)
{
obj.Complete();
}
else
{
if (player.FindBankNoCreate()?.ConsumeTotal(typeof(Gold), 10) == true)
obj.Complete();
else
player.SendLocalizedMessage(
1055108); // You don't have enough gold to buy the sheet music.
}
}
}
}
}

View file

@ -0,0 +1,109 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Collector
{
public class TomasONeerlan : BaseQuester
{
[Constructible]
public TomasONeerlan() : base("the famed toymaker")
{
}
public TomasONeerlan(Serial serial) : base(serial)
{
}
public override string DefaultName => "Tomas O'Neerlan";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83F8;
Female = false;
Body = 0x190;
}
public override void InitOutfit()
{
AddItem(new FancyShirt());
AddItem(new LongPants(0x546));
AddItem(new Boots(0x452));
AddItem(new FullApron(0x455));
HairItemID = 0x203B; //ShortHair
HairHue = 0x455;
}
public override bool CanTalkTo(PlayerMobile to)
{
QuestSystem qs = to.Quest as CollectorQuest;
if (qs == null)
return false;
return qs.IsObjectiveInProgress(typeof(FindTomasObjective))
|| qs.IsObjectiveInProgress(typeof(CaptureImagesObjective))
|| qs.IsObjectiveInProgress(typeof(ReturnImagesObjective));
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is CollectorQuest)
{
Direction = GetDirectionTo(player);
QuestObjective obj = qs.FindObjective<FindTomasObjective>();
if (obj?.Completed == false)
{
Item paints = new EnchantedPaints();
if (!player.PlaceInBackpack(paints))
{
paints.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 (qs.IsObjectiveInProgress(typeof(CaptureImagesObjective)))
{
qs.AddConversation(new TomasDuringCollectingConversation());
}
else
{
obj = qs.FindObjective<ReturnImagesObjective>();
if (obj?.Completed == false)
{
player.Backpack?.ConsumeUpTo(typeof(EnchantedPaints), 1);
obj.Complete();
}
}
}
}
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,372 @@
using System;
using Server.Mobiles;
namespace Server.Engines.Quests.Collector
{
public class FishPearlsObjective : QuestObjective
{
public override object Message => 1055084;
public override int MaxProgress => 6;
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
// Rainbow pearls collected:
gump.AddHtmlObject(70, 260, 270, 100, 1055085, BaseQuestGump.Blue, false, false);
gump.AddLabel(70, 280, 0x64, CurProgress.ToString());
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, MaxProgress.ToString());
}
else
{
base.RenderProgress(gump);
}
}
public override void OnComplete()
{
System.AddObjective(new ReturnPearlsObjective());
}
}
public class ReturnPearlsObjective : QuestObjective
{
public override object Message => 1055088;
public override void OnComplete()
{
System.AddConversation(new ReturnPearlsConversation());
}
}
public class FindAlbertaObjective : QuestObjective
{
public override object Message => 1055091;
public override void OnComplete()
{
System.AddConversation(new AlbertaPaintingConversation());
}
}
public class SitOnTheStoolObjective : QuestObjective
{
private static readonly Point3D m_StoolLocation = new Point3D(2899, 706, 0);
private static readonly Map m_StoolMap = Map.Trammel;
private DateTime m_Begin;
public SitOnTheStoolObjective()
{
m_Begin = DateTime.MaxValue;
}
public override object Message => 1055093;
public override void CheckProgress()
{
PlayerMobile pm = System.From;
if (pm.Map == m_StoolMap && pm.Location == m_StoolLocation)
{
if (m_Begin == DateTime.MaxValue)
m_Begin = DateTime.UtcNow;
else if (DateTime.UtcNow - m_Begin > TimeSpan.FromSeconds(30.0)) Complete();
}
else if (m_Begin != DateTime.MaxValue)
{
m_Begin = DateTime.MaxValue;
pm.SendLocalizedMessage(1055095, "",
0x26); // You must remain seated on the stool until the portrait is complete. Alberta will now have to start again with a fresh canvas.
}
}
public override void OnComplete()
{
System.AddConversation(new AlbertaEndPaintingConversation());
}
}
public class ReturnPaintingObjective : QuestObjective
{
public override object Message => 1055099;
public override void OnComplete()
{
System.AddConversation(new ReturnPaintingConversation());
}
}
public class FindGabrielObjective : QuestObjective
{
public override object Message => 1055101;
public override void OnComplete()
{
System.AddConversation(new GabrielAutographConversation());
}
}
public enum Theater
{
Britain,
Nujelm,
Jhelom
}
public class FindSheetMusicObjective : QuestObjective
{
private Theater m_Theater;
public FindSheetMusicObjective(bool init)
{
if (init)
InitTheater();
}
public FindSheetMusicObjective()
{
}
public override object Message => 1055104;
public void InitTheater()
{
switch (Utility.Random(3))
{
case 1:
m_Theater = Theater.Britain;
break;
case 2:
m_Theater = Theater.Nujelm;
break;
default:
m_Theater = Theater.Jhelom;
break;
}
}
public bool IsInRightTheater()
{
PlayerMobile player = System.From;
Region region = Region.Find(player.Location, player.Map);
if (region == null)
return false;
switch (m_Theater)
{
case Theater.Britain: return region.IsPartOf("Britain");
case Theater.Nujelm: return region.IsPartOf("Nujel'm");
case Theater.Jhelom: return region.IsPartOf("Jhelom");
default: return false;
}
}
public override void OnComplete()
{
System.AddConversation(new GetSheetMusicConversation());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_Theater = (Theater)reader.ReadEncodedInt();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt((int)m_Theater);
}
}
public class ReturnSheetMusicObjective : QuestObjective
{
public override object Message => 1055110;
public override void OnComplete()
{
System.AddConversation(new GabrielSheetMusicConversation());
}
}
public class ReturnAutographObjective : QuestObjective
{
public override object Message => 1055114;
public override void OnComplete()
{
System.AddConversation(new ReturnAutographConversation());
}
}
public class FindTomasObjective : QuestObjective
{
public override object Message => 1055117;
public override void OnComplete()
{
System.AddConversation(new TomasToysConversation());
}
}
public enum CaptureResponse
{
Valid,
AlreadyDone,
Invalid
}
public class CaptureImagesObjective : QuestObjective
{
private bool[] m_Done;
private ImageType[] m_Images;
public CaptureImagesObjective(bool init)
{
if (init)
{
m_Images = ImageTypeInfo.RandomList(4);
m_Done = new bool[4];
}
}
public CaptureImagesObjective()
{
}
public override object Message => 1055120;
public override bool Completed
{
get
{
for (int i = 0; i < m_Done.Length; i++)
if (!m_Done[i])
return false;
return true;
}
}
public override bool IgnoreYoungProtection(Mobile from)
{
if (Completed)
return false;
Type fromType = from.GetType();
for (int i = 0; i < m_Images.Length; i++)
{
ImageTypeInfo info = ImageTypeInfo.Get(m_Images[i]);
if (info.Type == fromType)
return true;
}
return false;
}
public CaptureResponse CaptureImage(Type type, out ImageType image)
{
for (int i = 0; i < m_Images.Length; i++)
{
ImageTypeInfo info = ImageTypeInfo.Get(m_Images[i]);
if (info.Type == type)
{
image = m_Images[i];
if (m_Done[i]) return CaptureResponse.AlreadyDone;
m_Done[i] = true;
CheckCompletionStatus();
return CaptureResponse.Valid;
}
}
image = 0;
return CaptureResponse.Invalid;
}
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
for (int i = 0; i < m_Images.Length; i++)
{
ImageTypeInfo info = ImageTypeInfo.Get(m_Images[i]);
gump.AddHtmlObject(70, 260 + 20 * i, 200, 100, info.Name, BaseQuestGump.Blue, false, false);
gump.AddLabel(200, 260 + 20 * i, 0x64, " : ");
gump.AddHtmlObject(220, 260 + 20 * i, 100, 100, m_Done[i] ? 1055121 : 1055122, BaseQuestGump.Blue, false,
false);
}
else
base.RenderProgress(gump);
}
public override void OnComplete()
{
System.AddObjective(new ReturnImagesObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
int count = reader.ReadEncodedInt();
m_Images = new ImageType[count];
m_Done = new bool[count];
for (int i = 0; i < count; i++)
{
m_Images[i] = (ImageType)reader.ReadEncodedInt();
m_Done[i] = reader.ReadBool();
}
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt(m_Images.Length);
for (int i = 0; i < m_Images.Length; i++)
{
writer.WriteEncodedInt((int)m_Images[i]);
writer.Write(m_Done[i]);
}
}
}
public class ReturnImagesObjective : QuestObjective
{
public override object Message => 1055128;
public override void OnComplete()
{
System.AddConversation(new ReturnImagesConversation());
}
}
public class ReturnToysObjective : QuestObjective
{
public override object Message => 1055132;
}
public class MakeRoomObjective : QuestObjective
{
public override object Message => 1055136;
}
}

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);
}
}
}
}

View file

@ -0,0 +1,207 @@
using Server.Items;
namespace Server.Engines.Quests.Necro
{
public class AcceptConversation : QuestConversation
{
public override object Message => 1049092;
public override void OnRead()
{
Container bag = BaseQuester.GetNewContainer();
bag.DropItem(new DarkTidesHorn());
System.From.AddToBackpack(bag);
System.AddConversation(new ReanimateMaabusConversation());
}
}
public class ReanimateMaabusConversation : QuestConversation
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1026153, 6178), // teleporter
new QuestItemInfo(1049117, 4036), // Horn of Retreat
new QuestItemInfo(1048032, 3702) // a bag
};
public override object Message => 1060099;
public override QuestItemInfo[] Info => m_Info;
public override void OnRead()
{
System.AddObjective(new FindMaabusTombObjective());
}
}
public class MaabasConversation : QuestConversation
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1026153, 6178) // teleporter
};
public override object Message => 1060103;
public override QuestItemInfo[] Info => m_Info;
public override void OnRead()
{
System.AddObjective(new FindCrystalCaveObjective());
}
}
public class HorusConversation : QuestConversation
{
public override object Message => 1060105;
public override void OnRead()
{
System.AddObjective(new FindMardothAboutVaultObjective());
}
}
public class MardothVaultConversation : QuestConversation
{
public override object Message => 1060107;
public override void OnRead()
{
System.AddObjective(new FindCityOfLightObjective());
}
}
public class VaultOfSecretsConversation : QuestConversation
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1023643, 8787) // spellbook
};
public override object Message => 1060110;
public override QuestItemInfo[] Info => m_Info;
public override void OnRead()
{
System.AddObjective(new FetchAbraxusScrollObjective());
}
}
public class ReadAbraxusScrollConversation : QuestConversation
{
public override object Message => 1060114;
public override void OnRead()
{
System.AddObjective(new ReadAbraxusScrollObjective());
}
}
public class SecondHorusConversation : QuestConversation
{
public override object Message => 1060118;
public override void OnRead()
{
System.AddObjective(new FindCallingScrollObjective());
}
}
public class HealConversation : QuestConversation
{
public override object Message => 1061610;
}
public class HorusRewardConversation : QuestConversation
{
public override object Message => 1060717;
public override bool Logged => false;
}
public class LostCallingScrollConversation : QuestConversation
{
private bool m_FromMardoth;
public LostCallingScrollConversation(bool fromMardoth)
{
m_FromMardoth = fromMardoth;
}
// Serialization
public LostCallingScrollConversation()
{
}
public override object Message
{
get
{
if (m_FromMardoth) return 1062058;
/* You have arrived at the well, but no longer have the scroll
* of calling. Use Mardoth's teleporter to return to the
* Crystal Cave and fetch another scroll from the box.
*/
return 1060129;
}
}
public override bool Logged => false;
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_FromMardoth = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_FromMardoth);
}
}
public class MardothKronusConversation : QuestConversation
{
public override object Message => 1060121;
public override void OnRead()
{
System.AddObjective(new FindWellOfTearsObjective());
}
}
public class MardothEndConversation : QuestConversation
{
public override object Message => 1060133;
public override void OnRead()
{
System.AddObjective(new FindBankObjective());
}
}
public class BankerConversation : QuestConversation
{
public override object Message => 1060137;
public override void OnRead()
{
System.Complete();
}
}
public class RadarConversation : QuestConversation
{
public override object Message => 1061692;
public override bool Logged => false;
}
}

View file

@ -0,0 +1,98 @@
using System;
using Server.Mobiles;
namespace Server.Engines.Quests.Necro
{
public class DarkTidesQuest : QuestSystem
{
private static Type[] m_TypeReferenceTable =
{
typeof(AcceptConversation),
typeof(AnimateMaabusCorpseObjective),
typeof(BankerConversation),
typeof(CashBankCheckObjective),
typeof(FetchAbraxusScrollObjective),
typeof(FindBankObjective),
typeof(FindCallingScrollObjective),
typeof(FindCityOfLightObjective),
typeof(FindCrystalCaveObjective),
typeof(FindMaabusCorpseObjective),
typeof(FindMaabusTombObjective),
typeof(FindMardothAboutKronusObjective),
typeof(FindMardothAboutVaultObjective),
typeof(FindMardothEndObjective),
typeof(FindVaultOfSecretsObjective),
typeof(FindWellOfTearsObjective),
typeof(HorusConversation),
typeof(LostCallingScrollConversation),
typeof(MaabasConversation),
typeof(MardothEndConversation),
typeof(MardothKronusConversation),
typeof(MardothVaultConversation),
typeof(RadarConversation),
typeof(ReadAbraxusScrollConversation),
typeof(ReadAbraxusScrollObjective),
typeof(ReanimateMaabusConversation),
typeof(RetrieveAbraxusScrollObjective),
typeof(ReturnToCrystalCaveObjective),
typeof(SecondHorusConversation),
typeof(SpeakCavePasswordObjective),
typeof(UseCallingScrollObjective),
typeof(VaultOfSecretsConversation),
typeof(FindHorusAboutRewardObjective),
typeof(HealConversation),
typeof(HorusRewardConversation)
};
public DarkTidesQuest(PlayerMobile from) : base(from)
{
}
// Serialization
public DarkTidesQuest()
{
}
public override Type[] TypeReferenceTable => m_TypeReferenceTable;
public override object Name => 1060095;
public override object OfferMessage => 1060094;
public override TimeSpan RestartDelay => TimeSpan.MaxValue;
public override bool IsTutorial => true;
public override int Picture => 0x15B5;
public override void Accept()
{
base.Accept();
AddConversation(new AcceptConversation());
}
public override bool IgnoreYoungProtection(Mobile from)
{
if (from is SummonedPaladin)
return true;
return base.IgnoreYoungProtection(from);
}
public static bool HasLostCallingScroll(Mobile from)
{
if (!(from is PlayerMobile pm))
return false;
QuestSystem qs = pm.Quest;
if (qs is DarkTidesQuest)
if (qs.IsObjectiveInProgress(typeof(FindMardothAboutKronusObjective)) ||
qs.IsObjectiveInProgress(typeof(FindWellOfTearsObjective)) ||
qs.IsObjectiveInProgress(typeof(UseCallingScrollObjective)))
return from.Backpack?.FindItemByType<KronusScroll>() == null;
return false;
}
}
}

View file

@ -0,0 +1,65 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Necro
{
public class CrystalCaveBarrier : Item
{
[Constructible]
public CrystalCaveBarrier() : base(0x3967)
{
Movable = false;
}
public CrystalCaveBarrier(Serial serial) : base(serial)
{
}
public override bool OnMoveOver(Mobile m)
{
if (m.AccessLevel > AccessLevel.Player)
return true;
Mobile mob = m;
if (m is BaseCreature creature)
mob = creature.ControlMaster;
if (!(mob is PlayerMobile pm))
return false;
QuestSystem qs = pm.Quest;
if (qs is DarkTidesQuest)
{
QuestObjective obj = qs.FindObjective<SpeakCavePasswordObjective>();
if (obj?.Completed == true)
{
m.SendLocalizedMessage(
1060648); // With Horus' permission, you are able to pass through the barrier.
return true;
}
}
m.SendLocalizedMessage(1060649, "",
0x66D); // Without the permission of the guardian Horus, the magic of the barrier prevents your passage.
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,37 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Necro
{
public class DarkTidesHorn : HornOfRetreat
{
[Constructible]
public DarkTidesHorn()
{
DestLoc = new Point3D(2103, 1319, -68);
DestMap = Map.Malas;
}
public DarkTidesHorn(Serial serial) : base(serial)
{
}
public override bool ValidateUse(Mobile from)
{
return from is PlayerMobile pm && pm.Quest is DarkTidesQuest;
}
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,76 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Necro
{
public class DarkTidesTeleporter : DynamicTeleporter
{
[Constructible]
public DarkTidesTeleporter()
{
}
public DarkTidesTeleporter(Serial serial) : base(serial)
{
}
public override bool GetDestination(PlayerMobile player, ref Point3D loc, ref Map map)
{
QuestSystem qs = player.Quest;
if (qs is DarkTidesQuest)
{
if (qs.IsObjectiveInProgress(typeof(FindMaabusTombObjective)))
{
loc = new Point3D(2038, 1263, -90);
map = Map.Malas;
qs.AddConversation(new RadarConversation());
return true;
}
if (qs.IsObjectiveInProgress(typeof(FindCrystalCaveObjective)))
{
loc = new Point3D(1194, 521, -90);
map = Map.Malas;
return true;
}
if (qs.IsObjectiveInProgress(typeof(FindCityOfLightObjective)))
{
loc = new Point3D(1091, 519, -90);
map = Map.Malas;
return true;
}
if (qs.IsObjectiveInProgress(typeof(ReturnToCrystalCaveObjective)))
{
loc = new Point3D(1194, 521, -90);
map = Map.Malas;
return true;
}
if (DarkTidesQuest.HasLostCallingScroll(player))
{
loc = new Point3D(1194, 521, -90);
map = Map.Malas;
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,166 @@
using System;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Necro
{
public class KronusScroll : QuestItem
{
private static readonly Rectangle2D m_WellOfTearsArea = new Rectangle2D(2080, 1346, 10, 10);
private static readonly Map m_WellOfTearsMap = Map.Malas;
[Constructible]
public KronusScroll() : base(0x227A)
{
Weight = 1.0;
Hue = 0x44E;
}
public KronusScroll(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1060149; // Calling of Kronus
public override bool CanDrop(PlayerMobile player)
{
return !(player.Quest is DarkTidesQuest);
/*return !( qs.IsObjectiveInProgress( typeof( FindCallingScrollObjective ) )
|| qs.IsObjectiveInProgress( typeof( FindMardothAboutKronusObjective ) )
|| qs.IsObjectiveInProgress( typeof( FindWellOfTearsObjective ) )
|| qs.IsObjectiveInProgress( typeof( UseCallingScrollObjective ) ) );*/
}
public override void OnDoubleClick(Mobile from)
{
if (!IsChildOf(from))
return;
if (from is PlayerMobile pm)
{
QuestSystem qs = pm.Quest;
if (qs is DarkTidesQuest)
{
if (qs.IsObjectiveInProgress(typeof(FindMardothAboutKronusObjective)))
{
pm.SendLocalizedMessage(1060151, "",
0x41); // You read the scroll, but decide against performing the calling until you are instructed to do so by Mardoth.
}
else if (qs.IsObjectiveInProgress(typeof(FindWellOfTearsObjective)))
{
pm.SendLocalizedMessage(1060152, "",
0x41); // You must be at the Well of Tears in the city of Necromancers to use this scroll.
}
else if (qs.IsObjectiveInProgress(typeof(UseCallingScrollObjective)))
{
if (pm.Map == m_WellOfTearsMap && m_WellOfTearsArea.Contains(pm))
{
QuestObjective obj = qs.FindObjective<UseCallingScrollObjective>();
if (obj?.Completed == false)
obj.Complete();
Delete();
new CallingTimer(pm).Start();
}
else
{
pm.SendLocalizedMessage(1060152, "",
0x41); // You must be at the Well of Tears in the city of Necromancers to use this scroll.
}
}
else
{
pm.SendLocalizedMessage(1060150, "",
0x41); // A strange terror grips your heart as you attempt to read the scroll. You decide it would be a bad idea to read it out loud.
}
}
}
}
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();
}
private class CallingTimer : Timer
{
private PlayerMobile m_Player;
private int m_Step;
public CallingTimer(PlayerMobile player) : base(TimeSpan.Zero, TimeSpan.FromSeconds(1.0), 6)
{
Priority = TimerPriority.TwentyFiveMS;
m_Player = player;
m_Step = 0;
}
protected override void OnTick()
{
if (m_Player.Deleted)
{
Stop();
return;
}
if (!m_Player.Mounted)
m_Player.Animate(Utility.RandomBool() ? 16 : 17, 7, 1, true, false, 0);
if (m_Step == 4)
{
int baseX = m_WellOfTearsArea.X;
int baseY = m_WellOfTearsArea.Y;
int width = m_WellOfTearsArea.Width;
int height = m_WellOfTearsArea.Height;
Map map = m_WellOfTearsMap;
Effects.SendLocationParticles(
EffectItem.Create(m_Player.Location, m_Player.Map, TimeSpan.FromSeconds(1.0)), 0, 0, 0, 0x13C4);
Effects.PlaySound(m_Player.Location, m_Player.Map, 0x243);
for (int i = 0; i < 15; i++)
{
int x = baseX + Utility.Random(width);
int y = baseY + Utility.Random(height);
int z = map.GetAverageZ(x, y);
Point3D from = new Point3D(x, y, z + Utility.RandomMinMax(5, 20));
Point3D to = new Point3D(x, y, z);
int hue = Utility.RandomList(0x481, 0x482, 0x489, 0x497, 0x66D);
Effects.SendPacket(from, map,
new HuedEffect(EffectType.Moving, Serial.Zero, Serial.Zero, 0x36D4, from, to, 0, 0, false, true,
hue, 0));
}
}
if (m_Step < 5)
{
m_Player.Frozen = true;
}
else // Cast completed
{
m_Player.Frozen = false;
SummonedPaladin.BeginSummon(m_Player);
}
m_Step++;
}
}
}
}

View file

@ -0,0 +1,74 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Necro
{
public class KronusScrollBox : MetalBox
{
[Constructible]
public KronusScrollBox()
{
ItemID = 0xE80;
Movable = false;
for (int i = 0; i < 40; i++)
{
Item scroll = Loot.RandomScroll(0, 15, SpellbookType.Necromancer);
scroll.Movable = false;
DropItem(scroll);
}
}
public KronusScrollBox(Serial serial) : base(serial)
{
}
public override void OnDoubleClick(Mobile from)
{
if (from is PlayerMobile pm && pm.InRange(GetWorldLocation(), 2))
{
QuestSystem qs = pm.Quest;
if (qs is DarkTidesQuest)
{
QuestObjective obj = qs.FindObjective<FindCallingScrollObjective>();
if (obj?.Completed == false || DarkTidesQuest.HasLostCallingScroll(from))
{
Item scroll = new KronusScroll();
if (pm.PlaceInBackpack(scroll))
{
pm.SendLocalizedMessage(1060120, "",
0x41); // You rummage through the scrolls until you find the Scroll of Calling. You quickly put it in your pack.
if (obj?.Completed == false)
obj.Complete();
}
else
{
pm.SendLocalizedMessage(1060148, "", 0x41); // You were unable to take the scroll.
scroll.Delete();
}
}
}
}
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,154 @@
using System;
using Server.Items;
namespace Server.Engines.Quests.Necro
{
public class MaabusCoffin : BaseAddon
{
[Constructible]
public MaabusCoffin()
{
AddComponent(new MaabusCoffinComponent(0x1C2B, 0x1C2B), -1, -1, 0);
AddComponent(new MaabusCoffinComponent(0x1D16, 0x1C2C), 0, -1, 0);
AddComponent(new MaabusCoffinComponent(0x1D17, 0x1C2D), 1, -1, 0);
AddComponent(new MaabusCoffinComponent(0x1D51, 0x1C2E), 2, -1, 0);
AddComponent(new MaabusCoffinComponent(0x1D4E, 0x1C2A), 0, 0, 0);
AddComponent(new MaabusCoffinComponent(0x1D4D, 0x1C29), 1, 0, 0);
AddComponent(new MaabusCoffinComponent(0x1D4C, 0x1C28), 2, 0, 0);
}
public MaabusCoffin(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public Maabus Maabus{ get; private set; }
[CommandProperty(AccessLevel.GameMaster)]
public Point3D SpawnLocation{ get; set; }
public void Awake(Mobile caller)
{
if (Maabus != null || SpawnLocation == Point3D.Zero)
return;
foreach (AddonComponent c in Components)
(c as MaabusCoffinComponent)?.TurnToEmpty();
Maabus = new Maabus { Location = SpawnLocation, Map = Map };
Maabus.Direction = Maabus.GetDirectionTo(caller);
Timer.DelayCall(TimeSpan.FromSeconds(7.5), BeginSleep);
}
public void BeginSleep()
{
if (Maabus == null)
return;
Effects.PlaySound(Maabus.Location, Maabus.Map, 0x48E);
Timer.DelayCall(TimeSpan.FromSeconds(2.5), Sleep);
}
public void Sleep()
{
if (Maabus == null)
return;
Effects.SendLocationParticles(EffectItem.Create(Maabus.Location, Maabus.Map, EffectItem.DefaultDuration), 0x3728,
10, 10, 0x7E7);
Effects.PlaySound(Maabus.Location, Maabus.Map, 0x1FE);
Maabus.Delete();
Maabus = null;
foreach (MaabusCoffinComponent c in Components)
c.TurnToFull();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(Maabus);
writer.Write(SpawnLocation);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Maabus = reader.ReadMobile() as Maabus;
SpawnLocation = reader.ReadPoint3D();
Sleep();
}
}
public class MaabusCoffinComponent : AddonComponent
{
private int m_EmptyItemID;
private int m_FullItemID;
public MaabusCoffinComponent(int itemID) : this(itemID, itemID)
{
}
public MaabusCoffinComponent(int fullItemID, int emptyItemID) : base(fullItemID)
{
m_FullItemID = fullItemID;
m_EmptyItemID = emptyItemID;
}
public MaabusCoffinComponent(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public Point3D SpawnLocation
{
get => Addon is MaabusCoffin coffin ? coffin.SpawnLocation : Point3D.Zero;
set
{
if (Addon is MaabusCoffin coffin) coffin.SpawnLocation = value;
}
}
public void TurnToEmpty()
{
ItemID = m_EmptyItemID;
}
public void TurnToFull()
{
ItemID = m_FullItemID;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(m_FullItemID);
writer.Write(m_EmptyItemID);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_FullItemID = reader.ReadInt();
m_EmptyItemID = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,133 @@
using Server.Gumps;
using Server.Mobiles;
namespace Server.Engines.Quests.Necro
{
public class ScrollOfAbraxus : QuestItem
{
[Constructible]
public ScrollOfAbraxus() : base(0x227B)
{
Weight = 1.0;
}
public ScrollOfAbraxus(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1028827; // Scroll of Abraxus
public override bool CanDrop(PlayerMobile player)
{
return !(player.Quest is DarkTidesQuest);
//return !( qs.IsObjectiveInProgress( typeof( RetrieveAbraxusScrollObjective ) ) || qs.IsObjectiveInProgress( typeof( ReadAbraxusScrollObjective ) ) );
}
public override void OnAdded(IEntity parent)
{
base.OnAdded(parent);
if (RootParent is PlayerMobile pm)
{
QuestSystem qs = pm.Quest;
if (qs is DarkTidesQuest)
{
QuestObjective obj = qs.FindObjective<RetrieveAbraxusScrollObjective>();
if (obj?.Completed == false)
obj.Complete();
}
}
}
public override void OnDoubleClick(Mobile from)
{
if (IsChildOf(from.Backpack))
{
from.SendGump(new ScrollOfAbraxusGump());
if (from is PlayerMobile pm)
{
QuestSystem qs = pm.Quest;
if (qs is DarkTidesQuest)
{
QuestObjective obj = qs.FindObjective<ReadAbraxusScrollObjective>();
if (obj?.Completed == false)
obj.Complete();
}
}
}
else
{
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
}
}
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 ScrollOfAbraxusGump : Gump
{
public ScrollOfAbraxusGump() : base(150, 50)
{
AddPage(0);
AddImage(0, 0, 1228);
AddImage(340, 255, 9005);
/* Security at the Crystal Cave<BR><BR>
*
* We have taken great measuresto ensure the safety of the
* Scroll of Calling, which we have so valiantly taken from
* the Necromancer Maabus during the battle of the wood
* nearly 200 years ago.<BR><BR>
*
* The scroll must never fall into the hands of the
* Necromancers again, lest they use it to summon the ancient
* daemon Kronus. The scroll of calling is a necessity in the
* series of dark rites the Necromancers must perform to once again
* re-awaken Kronus.<BR><BR>
*
* Should Kronus ever rise again, the days of the Paladins, and
* indeed humanity as we know it will be numbered.<BR><BR>
*
* For this reason, we have posted the honorable Horus, former
* General of the Northern Legions to guard the entrance of the
* Crystal Cave where we keep the Scroll of Calling. Horus was
* infused with magical life from the tree Urywen during his last
* battle. The power gave him eternal life, but it also,
* unfortunately, took his eye sight.<BR><BR>
*
* Since Horus cannot see those he admits to the Crystal Cave,
* he will only allow those that know the secret password to enter.
* Speak the following word to Horus and he shall grant you passage
* to the Crystal Cave:<BR><BR>
*
* <I>Urywen</I><BR><BR>
*
* Do not speak this password anywhere except when seeking passage
* into the Crystal Cave, as our adversaries are lurking in the
* shadows <EFBFBD> they are everywhere.<BR><BR>Go with the light, friend.<BR><BR>
*
* <I>- Frater Melkeer</I>
*/
AddHtmlLocalized(25, 36, 350, 210, 1060116, 1, false, true);
}
}
}

View file

@ -0,0 +1,46 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Necro
{
public class VaultOfSecretsBarrier : Item
{
[Constructible]
public VaultOfSecretsBarrier() : base(0x49E)
{
Movable = false;
Visible = false;
}
public VaultOfSecretsBarrier(Serial serial) : base(serial)
{
}
public override bool OnMoveOver(Mobile m)
{
if (m.AccessLevel > AccessLevel.Player)
return true;
if (m is PlayerMobile pm && pm.Profession == 4)
{
m.SendLocalizedMessage(1060188, "", 0x24); // The wicked may not enter!
return false;
}
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,191 @@
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Necro
{
public class Horus : BaseQuester
{
[Constructible]
public Horus() : base("the Guardian")
{
}
public Horus(Serial serial) : base(serial)
{
}
public override string DefaultName => "Horus";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83F3;
Body = 0x190;
}
public override void InitOutfit()
{
AddItem(SetHue(new PlateLegs(), 0x849));
AddItem(SetHue(new PlateChest(), 0x849));
AddItem(SetHue(new PlateArms(), 0x849));
AddItem(SetHue(new PlateGloves(), 0x849));
AddItem(SetHue(new PlateGorget(), 0x849));
AddItem(SetHue(new Bardiche(), 0x482));
AddItem(SetHue(new Boots(), 0x001));
AddItem(SetHue(new Cloak(), 0x482));
Utility.AssignRandomHair(this, false);
Utility.AssignRandomFacialHair(this, false);
}
public override int GetAutoTalkRange(PlayerMobile m)
{
return 3;
}
public override bool CanTalkTo(PlayerMobile to)
{
QuestSystem qs = to.Quest;
return qs is DarkTidesQuest && qs.IsObjectiveInProgress(typeof(FindCrystalCaveObjective));
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is DarkTidesQuest)
{
QuestObjective obj = qs.FindObjective<FindCrystalCaveObjective>();
if (obj?.Completed == false)
obj.Complete();
}
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
base.OnMovement(m, oldLocation);
if (InRange(m.Location, 2) && !InRange(oldLocation, 2) && m is PlayerMobile pm)
{
QuestSystem qs = pm.Quest;
if (qs is DarkTidesQuest)
{
QuestObjective obj = qs.FindObjective<ReturnToCrystalCaveObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else
{
obj = qs.FindObjective<FindHorusAboutRewardObjective>();
if (obj?.Completed == false)
{
Container cont = GetNewContainer();
cont.DropItem(new Gold(500));
BaseJewel jewel = new GoldBracelet();
if (Core.AOS)
BaseRunicTool.ApplyAttributesTo(jewel, 3, 20, 40);
cont.DropItem(jewel);
if (!pm.PlaceInBackpack(cont))
{
cont.Delete();
pm.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();
}
}
}
}
}
}
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
{
base.GetContextMenuEntries(from, list);
if (from.Alive)
if (from is PlayerMobile pm)
{
QuestSystem qs = pm.Quest;
if (qs is DarkTidesQuest)
{
QuestObjective obj = qs.FindObjective<SpeakCavePasswordObjective>();
bool enabled = obj?.Completed == false;
list.Add(new SpeakPasswordEntry(this, pm, enabled));
}
}
}
public virtual void OnPasswordSpoken(PlayerMobile from)
{
QuestSystem qs = from.Quest;
if (qs is DarkTidesQuest)
{
QuestObjective obj = qs.FindObjective<SpeakCavePasswordObjective>();
if (obj?.Completed == false)
{
obj.Complete();
return;
}
}
from.SendLocalizedMessage(1060185); // Horus ignores you.
}
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();
}
private class SpeakPasswordEntry : ContextMenuEntry
{
private PlayerMobile m_From;
private Horus m_Horus;
public SpeakPasswordEntry(Horus horus, PlayerMobile from, bool enabled) : base(6193, 3)
{
m_Horus = horus;
m_From = from;
if (!enabled)
Flags |= CMEFlags.Disabled;
}
public override void OnClick()
{
if (m_From.Alive)
m_Horus.OnPasswordSpoken(m_From);
}
}
}
}

View file

@ -0,0 +1,45 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Necro
{
public class Maabus : BaseQuester
{
public Maabus()
{
}
public Maabus(Serial serial) : base(serial)
{
}
public override string DefaultName => "Maabus";
public override void InitBody()
{
Body = 0x94;
}
public override bool CanTalkTo(PlayerMobile to)
{
return false;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
}
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,219 @@
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Necro
{
public class Mardoth : BaseQuester
{
[Constructible]
public Mardoth() : base("the Ancient Necromancer")
{
}
public Mardoth(Serial serial) : base(serial)
{
}
public override string DefaultName => "Mardoth";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x8849;
Body = 0x190;
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
if (from is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is DarkTidesQuest)
if (dropped is DarkTidesHorn 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;
}
}
return base.OnDragDrop(from, dropped);
}
public override void InitOutfit()
{
AddItem(new Sandals(0x1));
AddItem(new Robe(0x66D));
AddItem(new BlackStaff());
AddItem(new WizardsHat(0x1));
FacialHairItemID = 0x2041;
FacialHairHue = 0x482;
HairItemID = 0x203C;
HairHue = 0x482;
Item gloves = new BoneGloves();
gloves.Hue = 0x66D;
AddItem(gloves);
Item gorget = new PlateGorget();
gorget.Hue = 0x1;
AddItem(gorget);
}
public override int GetAutoTalkRange(PlayerMobile m)
{
return 3;
}
public override bool CanTalkTo(PlayerMobile to)
{
if (!(to.Quest is DarkTidesQuest qs))
return to.Quest == null && QuestSystem.CanOfferQuest(to, typeof(DarkTidesQuest));
return qs.FindObjective<FindMardothAboutVaultObjective>() != null;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is DarkTidesQuest)
{
if (DarkTidesQuest.HasLostCallingScroll(player))
{
qs.AddConversation(new LostCallingScrollConversation(true));
}
else
{
QuestObjective obj = qs.FindObjective<FindMardothAboutVaultObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else
{
obj = qs.FindObjective<FindMardothAboutKronusObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else
{
obj = qs.FindObjective<FindMardothEndObjective>();
if (obj?.Completed == false)
{
Container cont = GetNewContainer();
cont.DropItem(new PigIron(20));
cont.DropItem(new NoxCrystal(20));
cont.DropItem(new BatWing(25));
cont.DropItem(new DaemonBlood(20));
cont.DropItem(new GraveDust(20));
BaseWeapon weapon = new BoneHarvester();
weapon.Slayer = SlayerName.OrcSlaying;
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);
}
cont.DropItem(weapon);
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.
}
else
{
obj.Complete();
}
}
else if (contextMenu)
{
FocusTo(player);
player.SendLocalizedMessage(1061821); // Mardoth has nothing more for you at this time.
}
}
}
}
}
else if (qs == null && QuestSystem.CanOfferQuest(player, typeof(DarkTidesQuest)))
{
new DarkTidesQuest(player).SendOffer();
}
}
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,243 @@
using System;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Necro
{
public class SummonedPaladin : BaseCreature
{
private PlayerMobile m_Necromancer;
private bool m_ToDelete;
public SummonedPaladin(PlayerMobile necromancer) : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
{
m_Necromancer = necromancer;
InitStats(45, 30, 5);
Title = "the Paladin";
Hue = 0x83F3;
Female = false;
Body = 0x190;
Name = NameList.RandomName("male");
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this, false);
FacialHairHue = HairHue;
AddItem(new Boots(0x1));
AddItem(new ChainChest());
AddItem(new ChainLegs());
AddItem(new RingmailArms());
AddItem(new PlateHelm());
AddItem(new PlateGloves());
AddItem(new PlateGorget());
AddItem(new Cloak(0xCF));
AddItem(new ThinLongsword());
SetSkill(SkillName.Swords, 50.0);
SetSkill(SkillName.Tactics, 50.0);
PackGold(500);
}
public SummonedPaladin(Serial serial) : base(serial)
{
}
public override bool ClickTitle => false;
public override bool PlayerRangeSensitive => false;
public override bool IsHarmfulCriminal(Mobile target)
{
if (target == m_Necromancer)
return false;
return base.IsHarmfulCriminal(target);
}
public override void OnThink()
{
if (!m_ToDelete && !Frozen)
{
if (m_Necromancer?.Deleted != false || m_Necromancer.Map == Map.Internal)
{
Delete();
return;
}
if (Combatant != m_Necromancer)
Combatant = m_Necromancer;
if (!m_Necromancer.Alive)
{
QuestSystem qs = m_Necromancer.Quest;
if (qs is DarkTidesQuest && qs.FindObjective<FindMardothEndObjective>() == null)
qs.AddObjective(new FindMardothEndObjective(false));
Say(1060139, m_Necromancer.Name); // You have made my work easy for me, ~1_NAME~. My task here is done.
m_ToDelete = true;
Timer.DelayCall(TimeSpan.FromSeconds(5.0), Delete);
}
else if (m_Necromancer.Map != Map || GetDistanceToSqrt(m_Necromancer) > RangePerception + 1)
{
Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 10,
10, 2023);
Effects.SendLocationParticles(
EffectItem.Create(m_Necromancer.Location, m_Necromancer.Map, EffectItem.DefaultDuration), 0x3728, 10,
10, 5023);
Map = m_Necromancer.Map;
Location = m_Necromancer.Location;
PlaySound(0x1FE);
Say(1060140); // You cannot escape me, knave of evil!
}
}
base.OnThink();
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
QuestSystem qs = m_Necromancer.Quest;
if (qs is DarkTidesQuest && qs.FindObjective<FindMardothEndObjective>() == null)
qs.AddObjective(new FindMardothEndObjective(true));
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(m_Necromancer);
writer.Write(m_ToDelete);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Necromancer = reader.ReadMobile() as PlayerMobile;
m_ToDelete = reader.ReadBool();
if (m_ToDelete)
Delete();
}
public static void BeginSummon(PlayerMobile player)
{
new SummonTimer(player).Start();
}
private class SummonTimer : Timer
{
private SummonedPaladin m_Paladin;
private PlayerMobile m_Player;
private int m_Step;
public SummonTimer(PlayerMobile player) : base(TimeSpan.FromSeconds(4.0))
{
Priority = TimerPriority.FiftyMS;
m_Player = player;
}
protected override void OnTick()
{
if (m_Player.Deleted)
{
if (m_Step > 0)
m_Paladin.Delete();
return;
}
if (m_Step > 0 && m_Paladin.Deleted)
return;
if (m_Step == 0)
{
SummonedPaladinMoongate moongate = new SummonedPaladinMoongate();
moongate.MoveToWorld(new Point3D(2091, 1348, -90), Map.Malas);
Effects.PlaySound(moongate.Location, moongate.Map, 0x20E);
m_Paladin = new SummonedPaladin(m_Player);
m_Paladin.Frozen = true;
m_Paladin.Location = moongate.Location;
m_Paladin.Map = moongate.Map;
Delay = TimeSpan.FromSeconds(2.0);
Start();
}
else if (m_Step == 1)
{
m_Paladin.Direction = m_Paladin.GetDirectionTo(m_Player);
m_Paladin.Say(1060122); // STOP WICKED ONE!
Delay = TimeSpan.FromSeconds(3.0);
Start();
}
else
{
m_Paladin.Frozen = false;
m_Paladin.Say(1060123); // I will slay you before I allow you to complete your evil rites!
m_Paladin.Combatant = m_Player;
}
m_Step++;
}
}
}
public class SummonedPaladinMoongate : Item
{
public SummonedPaladinMoongate() : base(0xF6C)
{
Movable = false;
Hue = 0x482;
Light = LightType.Circle300;
Timer.DelayCall(TimeSpan.FromSeconds(10.0), Delete);
}
public SummonedPaladinMoongate(Serial serial) : base(serial)
{
}
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,379 @@
using Server.Items;
using Server.Mobiles;
using Server.Spells.Necromancy;
namespace Server.Engines.Quests.Necro
{
public class AnimateMaabusCorpseObjective : QuestObjective
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1023643, 8787) // spellbook
};
public override object Message => 1060102;
public override QuestItemInfo[] Info => m_Info;
public override void OnComplete()
{
System.AddConversation(new MaabasConversation());
}
}
public class FindCrystalCaveObjective : QuestObjective
{
public override object Message => 1060104;
public override void OnComplete()
{
System.AddConversation(new HorusConversation());
}
}
public class FindMardothAboutVaultObjective : QuestObjective
{
public override object Message => 1060106;
public override void OnComplete()
{
System.AddConversation(new MardothVaultConversation());
}
}
public class FindMaabusTombObjective : QuestObjective
{
public override object Message => 1060124;
public override void CheckProgress()
{
if (System.From.Map == Map.Malas && System.From.InRange(new Point3D(2024, 1240, -90), 3))
Complete();
}
public override void OnComplete()
{
System.AddObjective(new FindMaabusCorpseObjective());
}
}
public class FindMaabusCorpseObjective : QuestObjective
{
public override object Message => 1061142;
public override void CheckProgress()
{
if (System.From.Map == Map.Malas && System.From.InRange(new Point3D(2024, 1223, -90), 3))
Complete();
}
public override void OnComplete()
{
System.AddObjective(new AnimateMaabusCorpseObjective());
}
}
public class FindCityOfLightObjective : QuestObjective
{
public override object Message => 1060108;
public override void CheckProgress()
{
if (System.From.Map == Map.Malas && System.From.InRange(new Point3D(1076, 519, -90), 5))
Complete();
}
public override void OnComplete()
{
System.AddObjective(new FindVaultOfSecretsObjective());
}
}
public class FindVaultOfSecretsObjective : QuestObjective
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1023676, 3679) // glowing rune
};
public override object Message => 1060109;
public override QuestItemInfo[] Info => m_Info;
public override void CheckProgress()
{
if (System.From.Map == Map.Malas && System.From.InRange(new Point3D(1072, 455, -90), 1))
Complete();
}
public override void OnComplete()
{
System.AddConversation(new VaultOfSecretsConversation());
}
}
public class FetchAbraxusScrollObjective : QuestObjective
{
public override object Message => 1060196;
public override void CheckProgress()
{
if (System.From.Map != Map.Malas || !System.From.InRange(new Point3D(1076, 450, -84), 5) ||
!SummonFamiliarSpell.Table.TryGetValue(System.From, out BaseCreature bc) || !(bc is HordeMinionFamiliar hmf) ||
!hmf.InRange(System.From, 5) || hmf.TargetLocation != null)
return;
System.From.SendLocalizedMessage(
1060113); // You instinctively will your familiar to fetch the scroll for you.
hmf.TargetLocation = new Point2D(1076, 450);
}
public override void OnComplete()
{
System.AddObjective(new RetrieveAbraxusScrollObjective());
}
}
public class RetrieveAbraxusScrollObjective : QuestObjective
{
public override object Message => 1060199;
public override void OnComplete()
{
System.AddConversation(new ReadAbraxusScrollConversation());
}
}
public class ReadAbraxusScrollObjective : QuestObjective
{
public override object Message => 1060125;
public override void OnComplete()
{
System.AddObjective(new ReturnToCrystalCaveObjective());
}
}
public class ReturnToCrystalCaveObjective : QuestObjective
{
private static QuestItemInfo[] m_Info =
{
new QuestItemInfo(1026153, 6178) // teleporter
};
public override object Message => 1060115;
public override QuestItemInfo[] Info => m_Info;
public override void OnComplete()
{
System.AddObjective(new SpeakCavePasswordObjective());
}
}
public class SpeakCavePasswordObjective : QuestObjective
{
public override object Message => 1060117;
public override void OnComplete()
{
System.AddConversation(new SecondHorusConversation());
}
}
public class FindCallingScrollObjective : QuestObjective
{
private bool m_HealConversationShown;
private bool m_SkitteringHoppersDisposed;
private int m_SkitteringHoppersKilled;
public override object Message => 1060119;
public override bool IgnoreYoungProtection(Mobile from)
{
return !m_SkitteringHoppersDisposed && from is SkitteringHopper;
}
public override bool GetKillEvent(BaseCreature creature, Container corpse)
{
return !m_SkitteringHoppersDisposed;
}
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is SkitteringHopper)
{
if (!m_HealConversationShown)
{
m_HealConversationShown = true;
System.AddConversation(new HealConversation());
}
if (++m_SkitteringHoppersKilled >= 5)
{
m_SkitteringHoppersDisposed = true;
System.AddObjective(new FindHorusAboutRewardObjective());
}
}
}
public override void OnComplete()
{
System.AddObjective(new FindMardothAboutKronusObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_SkitteringHoppersKilled = reader.ReadEncodedInt();
m_HealConversationShown = reader.ReadBool();
m_SkitteringHoppersDisposed = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt(m_SkitteringHoppersKilled);
writer.Write(m_HealConversationShown);
writer.Write(m_SkitteringHoppersDisposed);
}
}
public class FindHorusAboutRewardObjective : QuestObjective
{
public override object Message => 1060126;
public override void OnComplete()
{
System.AddConversation(new HorusRewardConversation());
}
}
public class FindMardothAboutKronusObjective : QuestObjective
{
public override object Message => 1060127;
public override void OnComplete()
{
System.AddConversation(new MardothKronusConversation());
}
}
public class FindWellOfTearsObjective : QuestObjective
{
private static readonly Rectangle2D m_WellOfTearsArea = new Rectangle2D(2080, 1346, 10, 10);
private bool m_Inside;
public override object Message => 1060128;
public override void CheckProgress()
{
if (System.From.Map == Map.Malas && m_WellOfTearsArea.Contains(System.From.Location))
{
if (DarkTidesQuest.HasLostCallingScroll(System.From))
{
if (!m_Inside)
System.AddConversation(new LostCallingScrollConversation(false));
}
else
{
Complete();
}
m_Inside = true;
}
else
{
m_Inside = false;
}
}
public override void OnComplete()
{
System.AddObjective(new UseCallingScrollObjective());
}
}
public class UseCallingScrollObjective : QuestObjective
{
public override object Message => 1060130;
}
public class FindMardothEndObjective : QuestObjective
{
private bool m_Victory;
public FindMardothEndObjective(bool victory)
{
m_Victory = victory;
}
// Serialization
public FindMardothEndObjective()
{
}
public override object Message
{
get
{
if (m_Victory) return 1060131;
/* Although you were slain by the cowardly paladin,
* you managed to complete the rite of calling as
* instructed. Return to Mardoth.
*/
return 1060132;
}
}
public override void OnComplete()
{
System.AddConversation(new MardothEndConversation());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_Victory = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_Victory);
}
}
public class FindBankObjective : QuestObjective
{
public override object Message => 1060134;
public override void CheckProgress()
{
if (System.From.Map == Map.Malas && System.From.InRange(new Point3D(2048, 1345, -84), 5))
Complete();
}
public override void OnComplete()
{
System.AddObjective(new CashBankCheckObjective());
}
}
public class CashBankCheckObjective : QuestObjective
{
public override object Message => 1060644;
public override void OnComplete()
{
System.AddConversation(new BankerConversation());
}
}
}

View file

@ -0,0 +1,185 @@
namespace Server.Engines.Quests.Ninja
{
public class AcceptConversation : QuestConversation
{
public override object Message => 1049092;
public override void OnRead()
{
System.AddObjective(new FindEminoBeginObjective());
}
}
public class FindZoelConversation : QuestConversation
{
public override object Message => 1063175;
public override void OnRead()
{
System.AddObjective(new FindZoelObjective());
}
}
public class RadarConversation : QuestConversation
{
public override object Message => 1063033;
public override bool Logged => false;
}
public class EnterCaveConversation : QuestConversation
{
public override object Message => 1063177;
public override void OnRead()
{
System.AddObjective(new EnterCaveObjective());
}
}
public class SneakPastGuardiansConversation : QuestConversation
{
public override object Message => 1063180;
public override void OnRead()
{
System.AddObjective(new SneakPastGuardiansObjective());
}
}
public class NeedToHideConversation : QuestConversation
{
public override object Message => 1063181;
}
public class UseTeleporterConversation : QuestConversation
{
public override object Message => 1063182;
public override void OnRead()
{
System.AddObjective(new UseTeleporterObjective());
}
}
public class GiveZoelNoteConversation : QuestConversation
{
public override object Message => 1063184;
public override void OnRead()
{
System.AddObjective(new GiveZoelNoteObjective());
}
}
public class LostNoteConversation : QuestConversation
{
public override object Message => 1063187;
public override bool Logged => false;
}
public class GainInnInformationConversation : QuestConversation
{
public override object Message => 1063189;
public override void OnRead()
{
System.AddObjective(new GainInnInformationObjective());
}
}
public class ReturnFromInnConversation : QuestConversation
{
public override object Message => 1063196;
public override void OnRead()
{
System.AddObjective(new ReturnFromInnObjective());
}
}
public class SearchForSwordConversation : QuestConversation
{
public override object Message => 1063199;
public override void OnRead()
{
System.AddObjective(new SearchForSwordObjective());
}
}
public class HallwayWalkConversation : QuestConversation
{
public override object Message => 1063201;
public override void OnRead()
{
System.AddObjective(new HallwayWalkObjective());
}
}
public class ReturnSwordConversation : QuestConversation
{
public override object Message => 1063203;
public override void OnRead()
{
System.AddObjective(new ReturnSwordObjective());
}
}
public class SlayHenchmenConversation : QuestConversation
{
public override object Message => 1063205;
public override void OnRead()
{
System.AddObjective(new SlayHenchmenObjective());
}
}
public class ContinueSlayHenchmenConversation : QuestConversation
{
public override object Message => 1063208;
public override bool Logged => false;
}
public class GiveEminoSwordConversation : QuestConversation
{
public override object Message => 1063211;
public override void OnRead()
{
System.AddObjective(new GiveEminoSwordObjective());
}
}
public class LostSwordConversation : QuestConversation
{
public override object Message => 1063212;
public override bool Logged => false;
}
public class EarnGiftsConversation : QuestConversation
{
public override object Message => 1063216;
public override void OnRead()
{
System.Complete();
}
}
public class EarnLessGiftsConversation : QuestConversation
{
public override object Message => 1063217;
public override void OnRead()
{
System.Complete();
}
}
}

View file

@ -0,0 +1,128 @@
using System;
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class EminosUndertakingQuest : QuestSystem
{
private static Type[] m_TypeReferenceTable =
{
typeof(AcceptConversation),
typeof(FindZoelConversation),
typeof(RadarConversation),
typeof(EnterCaveConversation),
typeof(SneakPastGuardiansConversation),
typeof(NeedToHideConversation),
typeof(UseTeleporterConversation),
typeof(GiveZoelNoteConversation),
typeof(LostNoteConversation),
typeof(GainInnInformationConversation),
typeof(ReturnFromInnConversation),
typeof(SearchForSwordConversation),
typeof(HallwayWalkConversation),
typeof(ReturnSwordConversation),
typeof(SlayHenchmenConversation),
typeof(ContinueSlayHenchmenConversation),
typeof(GiveEminoSwordConversation),
typeof(LostSwordConversation),
typeof(EarnGiftsConversation),
typeof(EarnLessGiftsConversation),
typeof(FindEminoBeginObjective),
typeof(FindZoelObjective),
typeof(EnterCaveObjective),
typeof(SneakPastGuardiansObjective),
typeof(UseTeleporterObjective),
typeof(GiveZoelNoteObjective),
typeof(GainInnInformationObjective),
typeof(ReturnFromInnObjective),
typeof(SearchForSwordObjective),
typeof(HallwayWalkObjective),
typeof(ReturnSwordObjective),
typeof(SlayHenchmenObjective),
typeof(GiveEminoSwordObjective)
};
private bool m_SentRadarConversion;
public EminosUndertakingQuest(PlayerMobile from) : base(from)
{
}
// Serialization
public EminosUndertakingQuest()
{
}
public override Type[] TypeReferenceTable => m_TypeReferenceTable;
public override object Name => 1063173;
public override object OfferMessage => 1063174;
public override TimeSpan RestartDelay => TimeSpan.MaxValue;
public override bool IsTutorial => true;
public override int Picture => 0x15D5;
public override void Accept()
{
base.Accept();
AddConversation(new AcceptConversation());
}
public override void Slice()
{
if (!m_SentRadarConversion &&
(From.Map != Map.Malas || From.X < 407 || From.X > 431 || From.Y < 801 || From.Y > 830))
{
m_SentRadarConversion = true;
AddConversation(new RadarConversation());
}
base.Slice();
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_SentRadarConversion = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_SentRadarConversion);
}
public static bool HasLostNoteForZoel(Mobile from)
{
if (!(from is PlayerMobile pm))
return false;
QuestSystem qs = pm.Quest;
if (qs is EminosUndertakingQuest)
if (qs.IsObjectiveInProgress(typeof(GiveZoelNoteObjective)))
return from.Backpack?.FindItemByType<NoteForZoel>() == null;
return false;
}
public static bool HasLostEminosKatana(Mobile from)
{
if (!(from is PlayerMobile pm))
return false;
QuestSystem qs = pm.Quest;
if (qs is EminosUndertakingQuest)
if (qs.IsObjectiveInProgress(typeof(GiveEminoSwordObjective)))
return from.Backpack?.FindItemByType<EminosKatana>() == null;
return false;
}
}
}

View file

@ -0,0 +1,49 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class BlueNinjaQuestTeleporter : DynamicTeleporter
{
[Constructible]
public BlueNinjaQuestTeleporter() : base(0x51C, 0x2)
{
}
public BlueNinjaQuestTeleporter(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1026157; // teleporter
public override int NotWorkingMessage => 1063198; // You stand on the strange floor tile but nothing happens.
public override bool GetDestination(PlayerMobile player, ref Point3D loc, ref Map map)
{
QuestSystem qs = player.Quest;
if (qs is EminosUndertakingQuest && qs.FindObjective<GainInnInformationObjective>() != null)
{
loc = new Point3D(411, 1116, 0);
map = Map.Malas;
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,42 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class EminosKatana : QuestItem
{
[Constructible]
public EminosKatana() : base(0x13FF)
{
Weight = 1.0;
}
public EminosKatana(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1063214; // Daimyo Emino's Katana
public override bool CanDrop(PlayerMobile player)
{
return !(player.Quest is EminosUndertakingQuest);
/*return !qs.IsObjectiveInProgress( typeof( ReturnSwordObjective ) )
&& !qs.IsObjectiveInProgress( typeof( SlayHenchmenObjective ) )
&& !qs.IsObjectiveInProgress( typeof( GiveEminoSwordObjective ) );*/
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,142 @@
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Ninja
{
public class EminosKatanaChest : WoodenChest
{
[Constructible]
public EminosKatanaChest()
{
Movable = false;
ItemID = 0xE42;
GenerateTreasure();
}
public EminosKatanaChest(Serial serial) : base(serial)
{
}
public override bool IsDecoContainer => false;
private void GenerateTreasure()
{
for (int i = Items.Count - 1; i >= 0; i--)
Items[i].Delete();
for (int i = 0; i < 75; i++)
switch (Utility.Random(3))
{
case 0:
DropItem(new GoldBracelet());
break;
case 1:
DropItem(new GoldRing());
break;
case 2:
DropItem(Loot.RandomGem());
break;
}
}
public override void OnDoubleClick(Mobile from)
{
if (from is PlayerMobile player && player.InRange(GetWorldLocation(), 2))
{
QuestSystem qs = player.Quest;
if (qs is EminosUndertakingQuest)
{
if (EminosUndertakingQuest.HasLostEminosKatana(from))
{
Item katana = new EminosKatana();
if (!player.PlaceInBackpack(katana))
{
katana.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
{
QuestObjective obj = qs.FindObjective<HallwayWalkObjective>();
if (obj?.Completed == false)
{
Item katana = new EminosKatana();
if (player.PlaceInBackpack(katana))
{
GenerateTreasure();
obj.Complete();
}
else
{
katana.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.
}
}
}
}
}
base.OnDoubleClick(from);
}
public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight)
{
return false;
}
public override bool CheckItemUse(Mobile from, Item item)
{
return item == this;
}
public override bool CheckLift(Mobile from, Item item, ref LRReason reject)
{
if (from.AccessLevel >= AccessLevel.GameMaster)
return true;
if (from is PlayerMobile player && player.Quest is EminosUndertakingQuest)
{
HallwayWalkObjective obj = player.Quest.FindObjective<HallwayWalkObjective>();
if (obj?.StolenTreasure == true)
from.SendLocalizedMessage(
1063247); // The guard is watching you carefully! It would be unwise to remove another item from here.
else
return true;
}
return false;
}
public override void OnItemLifted(Mobile from, Item item)
{
if (from is PlayerMobile player && player.Quest is EminosUndertakingQuest)
{
HallwayWalkObjective obj = player.Quest.FindObjective<HallwayWalkObjective>();
if (obj != null)
obj.StolenTreasure = true;
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,49 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class GreenNinjaQuestTeleporter : DynamicTeleporter
{
[Constructible]
public GreenNinjaQuestTeleporter() : base(0x51C, 0x17E)
{
}
public GreenNinjaQuestTeleporter(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1026157; // teleporter
public override int NotWorkingMessage => 1063198; // You stand on the strange floor tile but nothing happens.
public override bool GetDestination(PlayerMobile player, ref Point3D loc, ref Map map)
{
QuestSystem qs = player.Quest;
if (qs is EminosUndertakingQuest && qs.FindObjective<UseTeleporterObjective>() != null)
{
loc = new Point3D(410, 1125, 0);
map = Map.Malas;
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,68 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class GuardianBarrier : Item
{
[Constructible]
public GuardianBarrier() : base(0x3967)
{
Movable = false;
Visible = false;
}
public GuardianBarrier(Serial serial) : base(serial)
{
}
public override bool OnMoveOver(Mobile m)
{
if (m.AccessLevel > AccessLevel.Player)
return true;
// If the mobile is to the north of the barrier, allow him to pass
if (Y >= m.Y)
return true;
if (m is BaseCreature creature)
{
Mobile master = creature.GetMaster();
// Allow creatures to cross from the south to the north only if their master is near to the north
return master != null && Y >= master.Y && master.InRange(this, 4);
}
if (m is PlayerMobile pm && pm.Quest is EminosUndertakingQuest qs)
{
SneakPastGuardiansObjective obj = qs.FindObjective<SneakPastGuardiansObjective>();
if (obj != null)
{
if (m.Hidden)
return true; // Hidden ninjas can pass
if (!obj.TaughtHowToUseSkills)
{
obj.TaughtHowToUseSkills = true;
qs.AddConversation(new NeedToHideConversation());
}
}
}
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,41 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class NoteForZoel : QuestItem
{
[Constructible]
public NoteForZoel() : base(0x14EF)
{
Weight = 1.0;
Hue = 0x6B9;
}
public NoteForZoel(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1063186; // A Note for Zoel
public override bool CanDrop(PlayerMobile player)
{
return !(player.Quest is EminosUndertakingQuest);
//return !qs.IsObjectiveInProgress( typeof( GiveZoelNoteObjective ) );
}
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,57 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class WhiteNinjaQuestTeleporter : DynamicTeleporter
{
[Constructible]
public WhiteNinjaQuestTeleporter() : base(0x51C, 0x47E)
{
}
public WhiteNinjaQuestTeleporter(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1026157; // teleporter
public override int NotWorkingMessage => 1063198; // You stand on the strange floor tile but nothing happens.
public override bool GetDestination(PlayerMobile player, ref Point3D loc, ref Map map)
{
QuestSystem qs = player.Quest;
if (qs is EminosUndertakingQuest)
{
QuestObjective obj = qs.FindObjective<SearchForSwordObjective>();
if (obj != null)
{
if (!obj.Completed)
obj.Complete();
loc = new Point3D(411, 1085, 0);
map = Map.Malas;
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,231 @@
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class Emino : BaseQuester
{
[Constructible]
public Emino() : base("the Notorious")
{
}
public Emino(Serial serial) : base(serial)
{
}
public override string DefaultName => "Daimyo Emino";
public override int TalkNumber => -1;
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83FE;
Female = false;
Body = 0x190;
}
public override void InitOutfit()
{
HairItemID = 0x203B;
HairHue = 0x901;
AddItem(new MaleKimono());
AddItem(new SamuraiTabi());
AddItem(new Bandana());
AddItem(new PlateHaidate());
AddItem(new PlateDo());
AddItem(new PlateHiroSode());
Nunchaku nunchaku = new Nunchaku();
nunchaku.Movable = false;
AddItem(nunchaku);
}
public override int GetAutoTalkRange(PlayerMobile pm)
{
return 2;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is EminosUndertakingQuest)
{
if (EminosUndertakingQuest.HasLostNoteForZoel(player))
{
Item note = new NoteForZoel();
if (player.PlaceInBackpack(note))
{
qs.AddConversation(new LostNoteConversation());
}
else
{
note.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 if (EminosUndertakingQuest.HasLostEminosKatana(player))
{
qs.AddConversation(new LostSwordConversation());
}
else
{
QuestObjective obj = qs.FindObjective<FindEminoBeginObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else
{
obj = qs.FindObjective<UseTeleporterObjective>();
if (obj?.Completed == false)
{
Item note = new NoteForZoel();
if (player.PlaceInBackpack(note))
{
obj.Complete();
player.AddToBackpack(new LeatherNinjaPants());
player.AddToBackpack(new LeatherNinjaMitts());
}
else
{
note.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 = qs.FindObjective<ReturnFromInnObjective>();
if (obj?.Completed == false)
{
Container cont = GetNewContainer();
for (int i = 0; i < 10; i++)
cont.DropItem(new LesserHealPotion());
cont.DropItem(new LeatherNinjaHood());
cont.DropItem(new LeatherNinjaJacket());
if (player.PlaceInBackpack(cont))
{
obj.Complete();
}
else
{
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
{
if (qs.IsObjectiveInProgress(typeof(SlayHenchmenObjective)))
{
qs.AddConversation(new ContinueSlayHenchmenConversation());
}
else
{
obj = qs.FindObjective<GiveEminoSwordObjective>();
if (obj?.Completed == false)
{
Item katana = null;
if (player.Backpack != null)
katana = player.Backpack.FindItemByType<EminosKatana>();
if (katana != null)
{
bool stolenTreasure = false;
HallwayWalkObjective walk = qs.FindObjective<HallwayWalkObjective>();
if (walk != null)
stolenTreasure = walk.StolenTreasure;
Kama kama = new Kama();
if (stolenTreasure)
BaseRunicTool.ApplyAttributesTo(kama, 1, 10, 20);
else
BaseRunicTool.ApplyAttributesTo(kama, 1, 10, 30);
if (player.PlaceInBackpack(kama))
{
katana.Delete();
obj.Complete();
if (stolenTreasure)
qs.AddConversation(new EarnLessGiftsConversation());
else
qs.AddConversation(new EarnGiftsConversation());
}
else
{
kama.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.
}
}
}
}
}
}
}
}
}
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
base.OnMovement(m, oldLocation);
if (!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,54 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class EnshroudedFigure : BaseQuester
{
[Constructible]
public EnshroudedFigure()
{
}
public EnshroudedFigure(Serial serial) : base(serial)
{
}
public override string DefaultName => "an enshrouded figure";
public override int TalkNumber => -1;
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x8401;
Female = false;
Body = 0x190;
}
public override void InitOutfit()
{
AddItem(new DeathShroud());
AddItem(new ThighBoots());
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,54 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class Henchman : BaseCreature
{
[Constructible]
public Henchman() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
{
InitStats(45, 30, 5);
Hue = Race.Human.RandomSkinHue();
Body = 0x190;
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this);
AddItem(new LeatherNinjaJacket());
AddItem(new LeatherNinjaPants());
AddItem(new NinjaTabi());
if (Utility.RandomBool())
AddItem(new Kama());
else
AddItem(new Tessen());
SetSkill(SkillName.Swords, 50.0);
SetSkill(SkillName.Tactics, 50.0);
}
public Henchman(Serial serial) : base(serial)
{
}
public override string DefaultName => "a henchman";
public override bool AlwaysMurderer => true;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,92 @@
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Ninja
{
public class HiddenFigure : BaseQuester
{
public static int[] Messages =
{
1063191, // They won<6F>t find me here.
1063192 // Ah, a quiet hideout.
};
[Constructible]
public HiddenFigure()
{
Message = Utility.RandomList(Messages);
}
public HiddenFigure(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public int Message{ get; set; }
public override int TalkNumber => -1;
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = Race.Human.RandomSkinHue();
Female = Utility.RandomBool();
if (Female)
{
Body = 0x191;
Name = NameList.RandomName("female");
}
else
{
Body = 0x190;
Name = NameList.RandomName("male");
}
}
public override void InitOutfit()
{
Utility.AssignRandomHair(this);
AddItem(new TattsukeHakama(GetRandomHue()));
AddItem(new Kasa());
AddItem(new HakamaShita(GetRandomHue()));
if (Utility.RandomBool())
AddItem(new Shoes(GetShoeHue()));
else
AddItem(new Sandals(GetShoeHue()));
}
public override int GetAutoTalkRange(PlayerMobile pm)
{
return 3;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
PrivateOverheadMessage(MessageType.Regular, 0x3B2, Message, player.NetState);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
writer.Write(Message);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
Message = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,58 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class JedahEntille : BaseQuester
{
[Constructible]
public JedahEntille() : base("the Silent")
{
}
public JedahEntille(Serial serial) : base(serial)
{
}
public override string DefaultName => "Jedah Entille";
public override int TalkNumber => -1;
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83FE;
Female = true;
Body = 0x191;
}
public override void InitOutfit()
{
HairItemID = 0x203C;
HairHue = 0x6BE;
AddItem(new PlainDress(0x528));
AddItem(new ThighBoots());
AddItem(new FloppyHat());
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,132 @@
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class Zoel : BaseQuester
{
[Constructible]
public Zoel() : base("the Masterful Tactician")
{
}
public Zoel(Serial serial) : base(serial)
{
}
public override string DefaultName => "Elite Ninja Zoel";
public override int TalkNumber => -1;
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83FE;
Female = false;
Body = 0x190;
}
public override void InitOutfit()
{
HairItemID = 0x203B;
HairHue = 0x901;
AddItem(new HakamaShita(0x1));
AddItem(new NinjaTabi());
AddItem(new TattsukeHakama());
AddItem(new Bandana());
AddItem(new LeatherNinjaBelt());
Tekagi tekagi = new Tekagi();
tekagi.Movable = false;
AddItem(tekagi);
}
public override int GetAutoTalkRange(PlayerMobile pm)
{
return 2;
}
public override bool CanTalkTo(PlayerMobile to)
{
return to.Quest is EminosUndertakingQuest;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is EminosUndertakingQuest)
{
QuestObjective obj = qs.FindObjective<FindZoelObjective>();
if (obj?.Completed == false)
obj.Complete();
}
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
if (from is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is EminosUndertakingQuest)
if (dropped is NoteForZoel)
{
QuestObjective obj = qs.FindObjective<GiveZoelNoteObjective>();
if (obj?.Completed == 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.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,218 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Ninja
{
public class FindEminoBeginObjective : QuestObjective
{
public override object Message => 1063174;
public override void OnComplete()
{
System.AddConversation(new FindZoelConversation());
}
}
public class FindZoelObjective : QuestObjective
{
public override object Message => 1063176;
public override void OnComplete()
{
System.AddConversation(new EnterCaveConversation());
}
}
public class EnterCaveObjective : QuestObjective
{
public override object Message => 1063179;
public override void CheckProgress()
{
if (System.From.Map == Map.Malas && System.From.InRange(new Point3D(406, 1141, 0), 2))
Complete();
}
public override void OnComplete()
{
System.AddConversation(new SneakPastGuardiansConversation());
}
}
public class SneakPastGuardiansObjective : QuestObjective
{
public bool TaughtHowToUseSkills{ get; set; }
public override object Message => 1063261;
public override void CheckProgress()
{
if (System.From.Map == Map.Malas && System.From.InRange(new Point3D(412, 1123, 0), 3))
Complete();
}
public override void OnComplete()
{
System.AddConversation(new UseTeleporterConversation());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
TaughtHowToUseSkills = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(TaughtHowToUseSkills);
}
}
public class UseTeleporterObjective : QuestObjective
{
public override object Message => 1063183;
public override void OnComplete()
{
System.AddConversation(new GiveZoelNoteConversation());
}
}
public class GiveZoelNoteObjective : QuestObjective
{
public override object Message => 1063185;
public override void OnComplete()
{
System.AddConversation(new GainInnInformationConversation());
}
}
public class GainInnInformationObjective : QuestObjective
{
public override object Message => 1063190;
public override void CheckProgress()
{
Mobile from = System.From;
if (from.Map == Map.Malas && from.X > 399 && from.X < 408 && from.Y > 1091 && from.Y < 1099)
Complete();
}
public override void OnComplete()
{
System.AddConversation(new ReturnFromInnConversation());
}
}
public class ReturnFromInnObjective : QuestObjective
{
public override object Message => 1063197;
public override void OnComplete()
{
System.AddConversation(new SearchForSwordConversation());
}
}
public class SearchForSwordObjective : QuestObjective
{
public override object Message => 1063200;
public override void OnComplete()
{
System.AddConversation(new HallwayWalkConversation());
}
}
public class HallwayWalkObjective : QuestObjective
{
public bool StolenTreasure{ get; set; }
public override object Message => 1063202;
public override void OnComplete()
{
System.AddConversation(new ReturnSwordConversation());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
StolenTreasure = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(StolenTreasure);
}
}
public class ReturnSwordObjective : QuestObjective
{
public override object Message => 1063204;
public override void CheckProgress()
{
Mobile from = System.From;
if (from.Map != Map.Malas || from.Y > 992)
Complete();
}
public override void OnComplete()
{
System.AddConversation(new SlayHenchmenConversation());
}
}
public class SlayHenchmenObjective : QuestObjective
{
public override object Message => 1063206;
public override int MaxProgress => 3;
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
// Henchmen killed:
gump.AddHtmlLocalized(70, 260, 270, 100, 1063207, BaseQuestGump.Blue);
gump.AddLabel(70, 280, 0x64, CurProgress.ToString());
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, MaxProgress.ToString());
}
else
{
base.RenderProgress(gump);
}
}
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is Henchman)
CurProgress++;
}
public override void OnComplete()
{
System.AddConversation(new GiveEminoSwordConversation());
}
}
public class GiveEminoSwordObjective : QuestObjective
{
public override object Message => 1063210;
public override void OnComplete()
{
}
}
}

View file

@ -0,0 +1,374 @@
namespace Server.Engines.Quests.Samurai
{
public class AcceptConversation : QuestConversation
{
public override object Message => 1049092;
public override void OnRead()
{
System.AddObjective(new FindHaochiObjective());
}
}
public class RadarConversation : QuestConversation
{
public override object Message => 1063033;
public override bool Logged => false;
}
public class FirstTrialIntroConversation : QuestConversation
{
public override object Message => 1063029;
public override void OnRead()
{
System.AddObjective(new FirstTrialIntroObjective());
}
}
public class FirstTrialKillConversation : QuestConversation
{
public override object Message => 1063031;
public override void OnRead()
{
System.AddObjective(new FirstTrialKillObjective());
}
}
public class GainKarmaConversation : QuestConversation
{
private bool m_CursedSoul;
public GainKarmaConversation(bool cursedSoul)
{
m_CursedSoul = cursedSoul;
}
public GainKarmaConversation()
{
}
public override object Message
{
get
{
if (m_CursedSoul) return 1063040;
// You have just gained some <a href="?ForceTopic45">Karma</a> for killing a Young Ronin.
return 1063041;
}
}
public override bool Logged => false;
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_CursedSoul = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_CursedSoul);
}
}
public class SecondTrialIntroConversation : QuestConversation
{
private bool m_CursedSoul;
public SecondTrialIntroConversation(bool cursedSoul)
{
m_CursedSoul = cursedSoul;
}
public SecondTrialIntroConversation()
{
}
public override object Message
{
get
{
if (m_CursedSoul) return 1063045;
/* It is good that you rid the land of those dishonorable Samurai.
* Perhaps they will learn a greater lesson in death.<BR><BR>
*
* I have placed a reward in your pack.<BR><BR>
*
* The second trial will test your courage. You only have to follow
* the yellow path to see what awaits you.
*/
return 1063046;
}
}
public override void OnRead()
{
System.AddObjective(new SecondTrialIntroObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_CursedSoul = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_CursedSoul);
}
}
public class SecondTrialAttackConversation : QuestConversation
{
public override object Message => 1063057;
public override void OnRead()
{
System.AddObjective(new SecondTrialAttackObjective());
}
}
public class ThirdTrialIntroConversation : QuestConversation
{
private bool m_Dragon;
public ThirdTrialIntroConversation(bool dragon)
{
m_Dragon = dragon;
}
public ThirdTrialIntroConversation()
{
}
public override object Message
{
get
{
if (m_Dragon) return 1063060;
/* Fear remains in your eyes but you have learned that not all is
* what it appears to be. <BR><BR>
*
* You must have known the dragon would slay you instantly.
* You elected the weaker opponent though the imp did not come
* here to destroy. You have much to learn. <BR><BR>
*
* In these lands, death is not forever. The shrines can make you whole
* again as can a helpful mage or healer. <BR><BR>
*
* Seek them out when you have been mortally wounded. <BR><BR>
*
* The next trial will test your benevolence. You only have to walk the blue path.
*/
return 1063059;
}
}
public override void OnRead()
{
System.AddObjective(new ThirdTrialIntroObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_Dragon = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_Dragon);
}
}
public class ThirdTrialKillConversation : QuestConversation
{
public override object Message => 1063062;
public override void OnRead()
{
System.AddObjective(new ThirdTrialKillObjective());
}
}
public class FourthTrialIntroConversation : QuestConversation
{
public override object Message => 1063065;
public override void OnRead()
{
System.AddObjective(new FourthTrialIntroObjective());
}
}
public class FourthTrialCatsConversation : QuestConversation
{
public override object Message => 1063067;
public override void OnRead()
{
System.AddObjective(new FourthTrialCatsObjective());
}
}
public class FifthTrialIntroConversation : QuestConversation
{
private bool m_KilledCat;
public FifthTrialIntroConversation(bool killedCat)
{
m_KilledCat = killedCat;
}
public FifthTrialIntroConversation()
{
}
public override object Message
{
get
{
if (m_KilledCat) return 1063071;
/* You showed respect by helping another out while allowing the gypsy
* what little dignity she has left. <BR><BR>
*
* Now she will be able to feed herself and gain enough energy to walk
* to her camp. <BR><BR>
*
* The cats are her family members<EFBFBD> cursed by an evil mage. <BR><BR>
*
* Once she has enough strength to walk back to the camp, she will be
* able to undo the spell. <BR><BR>
*
* You have been rewarded for completing your trial. And now you must
* prove yourself again. <BR><BR>Please retrieve my katana from the
* treasure room and return it to me.
*/
return 1063070;
}
}
public override void OnRead()
{
System.AddObjective(new FifthTrialIntroObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_KilledCat = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_KilledCat);
}
}
public class FifthTrialReturnConversation : QuestConversation
{
public override object Message => 1063248;
public override void OnRead()
{
System.AddObjective(new FifthTrialReturnObjective());
}
}
public class LostSwordConversation : QuestConversation
{
public override object Message => 1063074;
public override bool Logged => false;
}
public class SixthTrialIntroConversation : QuestConversation
{
private bool m_StolenTreasure;
public SixthTrialIntroConversation(bool stolenTreasure)
{
m_StolenTreasure = stolenTreasure;
}
public SixthTrialIntroConversation()
{
}
public override object Message
{
get
{
if (m_StolenTreasure) return 1063077;
/* Thank you for returning this sword to me and leaving the remaining
* treasure alone. <BR><BR>
*
* Your training is nearly complete. Before you have your final trial,
* you should pay homage to Samurai who came before you. <BR><BR>
*
* Go into the Altar Room and light a candle for them. Afterwards, return to me.
*/
return 1063076;
}
}
public override void OnRead()
{
System.AddObjective(new SixthTrialIntroObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_StolenTreasure = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_StolenTreasure);
}
}
public class SeventhTrialIntroConversation : QuestConversation
{
public override object Message => 1063079;
public override void OnRead()
{
System.AddObjective(new SeventhTrialIntroObjective());
}
}
public class EndConversation : QuestConversation
{
public override object Message => 1063125;
public override void OnRead()
{
System.Complete();
}
}
}

View file

@ -0,0 +1,117 @@
using System;
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class HaochisTrialsQuest : QuestSystem
{
private static Type[] m_TypeReferenceTable =
{
typeof(AcceptConversation),
typeof(RadarConversation),
typeof(FirstTrialIntroConversation),
typeof(FirstTrialKillConversation),
typeof(GainKarmaConversation),
typeof(SecondTrialIntroConversation),
typeof(SecondTrialAttackConversation),
typeof(ThirdTrialIntroConversation),
typeof(ThirdTrialKillConversation),
typeof(FourthTrialIntroConversation),
typeof(FourthTrialCatsConversation),
typeof(FifthTrialIntroConversation),
typeof(FifthTrialReturnConversation),
typeof(LostSwordConversation),
typeof(SixthTrialIntroConversation),
typeof(SeventhTrialIntroConversation),
typeof(EndConversation),
typeof(FindHaochiObjective),
typeof(FirstTrialIntroObjective),
typeof(FirstTrialKillObjective),
typeof(FirstTrialReturnObjective),
typeof(SecondTrialIntroObjective),
typeof(SecondTrialAttackObjective),
typeof(SecondTrialReturnObjective),
typeof(ThirdTrialIntroObjective),
typeof(ThirdTrialKillObjective),
typeof(ThirdTrialReturnObjective),
typeof(FourthTrialIntroObjective),
typeof(FourthTrialCatsObjective),
typeof(FourthTrialReturnObjective),
typeof(FifthTrialIntroObjective),
typeof(FifthTrialReturnObjective),
typeof(SixthTrialIntroObjective),
typeof(SixthTrialReturnObjective),
typeof(SeventhTrialIntroObjective),
typeof(SeventhTrialReturnObjective)
};
private bool m_SentRadarConversion;
public HaochisTrialsQuest(PlayerMobile from) : base(from)
{
}
// Serialization
public HaochisTrialsQuest()
{
}
public override Type[] TypeReferenceTable => m_TypeReferenceTable;
public override object Name => 1063022;
public override object OfferMessage => 1063023;
public override TimeSpan RestartDelay => TimeSpan.MaxValue;
public override bool IsTutorial => true;
public override int Picture => 0x15D7;
public override void Accept()
{
base.Accept();
AddConversation(new AcceptConversation());
}
public override void Slice()
{
if (!m_SentRadarConversion &&
(From.Map != Map.Malas || From.X < 360 || From.X > 400 || From.Y < 760 || From.Y > 780))
{
m_SentRadarConversion = true;
AddConversation(new RadarConversation());
}
base.Slice();
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_SentRadarConversion = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_SentRadarConversion);
}
public static bool HasLostHaochisKatana(Mobile from)
{
if (!(from is PlayerMobile pm))
return false;
QuestSystem qs = pm.Quest;
if (qs is HaochisTrialsQuest)
if (qs.IsObjectiveInProgress(typeof(FifthTrialReturnObjective)))
return from.Backpack?.FindItemByType<HaochisKatana>() == null;
return false;
}
}
}

View file

@ -0,0 +1,40 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class HaochisKatana : QuestItem
{
[Constructible]
public HaochisKatana() : base(0x13FF)
{
Weight = 1.0;
}
public HaochisKatana(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1063165; // Daimyo Haochi's Katana
public override bool CanDrop(PlayerMobile player)
{
return !(player.Quest is HaochisTrialsQuest);
//return !qs.IsObjectiveInProgress( typeof( FifthTrialReturnObjective ) );
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,79 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class HaochisKatanaGenerator : Item
{
[Constructible]
public HaochisKatanaGenerator() : base(0x1B7B)
{
Visible = false;
Movable = false;
}
public HaochisKatanaGenerator(Serial serial) : base(serial)
{
}
public override string DefaultName => "Haochi's katana generator";
public override bool OnMoveOver(Mobile m)
{
if (m is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is HaochisTrialsQuest)
{
if (HaochisTrialsQuest.HasLostHaochisKatana(player))
{
Item katana = new HaochisKatana();
if (!player.PlaceInBackpack(katana))
{
katana.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
{
QuestObjective obj = qs.FindObjective<FifthTrialIntroObjective>();
if (obj?.Completed == false)
{
Item katana = new HaochisKatana();
if (player.PlaceInBackpack(katana))
{
obj.Complete();
}
else
{
katana.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 base.OnMoveOver(m);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,100 @@
using System;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Samurai
{
public class HaochisTreasureChest : WoodenFootLocker
{
[Constructible]
public HaochisTreasureChest()
{
Movable = false;
GenerateTreasure();
}
public HaochisTreasureChest(Serial serial) : base(serial)
{
}
public override bool IsDecoContainer => false;
private void GenerateTreasure()
{
for (int i = Items.Count - 1; i >= 0; i--)
Items[i].Delete();
for (int i = 0; i < 75; i++)
switch (Utility.Random(3))
{
case 0:
DropItem(new GoldBracelet());
break;
case 1:
DropItem(new GoldRing());
break;
case 2:
DropItem(Loot.RandomGem());
break;
}
}
public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight)
{
return false;
}
public override bool CheckItemUse(Mobile from, Item item)
{
return item == this;
}
public override bool CheckLift(Mobile from, Item item, ref LRReason reject)
{
if (from.AccessLevel >= AccessLevel.GameMaster)
return true;
if (from is PlayerMobile player && player.Quest is HaochisTrialsQuest)
{
FifthTrialIntroObjective obj = player.Quest.FindObjective<FifthTrialIntroObjective>();
if (obj?.StolenTreasure == true)
from.SendLocalizedMessage(
1063247); // The guard is watching you carefully! It would be unwise to remove another item from here.
else
return true;
}
return false;
}
public override void OnItemLifted(Mobile from, Item item)
{
if (from is PlayerMobile player && player.Quest is HaochisTrialsQuest)
{
FifthTrialIntroObjective obj = player.Quest.FindObjective<FifthTrialIntroObjective>();
if (obj != null)
obj.StolenTreasure = true;
}
Timer.DelayCall(TimeSpan.FromMinutes(2.0), GenerateTreasure);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
Timer.DelayCall(TimeSpan.Zero, GenerateTreasure);
}
}
}

View file

@ -0,0 +1,76 @@
using System;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class HonorCandle : CandleLong
{
private static readonly TimeSpan LitDuration = TimeSpan.FromSeconds(20.0);
[Constructible]
public HonorCandle()
{
Movable = false;
Duration = LitDuration;
}
public HonorCandle(Serial serial) : base(serial)
{
}
public override int LitSound => 0;
public override int UnlitSound => 0;
public override void OnDoubleClick(Mobile from)
{
bool wasBurning = Burning;
base.OnDoubleClick(from);
if (!wasBurning && Burning)
{
if (!(from is PlayerMobile player))
return;
QuestSystem qs = player.Quest;
if (qs is HaochisTrialsQuest)
{
QuestObjective obj = qs.FindObjective<SixthTrialIntroObjective>();
if (obj?.Completed == false)
obj.Complete();
SendLocalizedMessageTo(from, 1063251); // You light a candle in honor.
}
}
}
public override void Burn()
{
Douse();
}
public override void Douse()
{
base.Douse();
Duration = LitDuration;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,90 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class CursedSoul : BaseCreature
{
[Constructible]
public CursedSoul() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
{
Body = 3;
BaseSoundID = 471;
SetStr(20, 40);
SetDex(40, 60);
SetInt(15, 25);
SetHits(10, 20);
SetDamage(3, 7);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 15, 20);
SetResistance(ResistanceType.Fire, 8, 12);
SetSkill(SkillName.Wrestling, 35.0, 39.0);
SetSkill(SkillName.Tactics, 5.0, 15.0);
SetSkill(SkillName.MagicResist, 10.0);
Fame = 200;
Karma = -200;
switch (Utility.Random(10))
{
case 0:
PackItem(new LeftArm());
break;
case 1:
PackItem(new RightArm());
break;
case 2:
PackItem(new Torso());
break;
case 3:
PackItem(new Bone());
break;
case 4:
PackItem(new RibCage());
break;
case 5:
PackItem(new RibCage());
break;
case 6:
PackItem(new BonePile());
break;
case 7:
PackItem(new BonePile());
break;
case 8:
PackItem(new BonePile());
break;
case 9:
PackItem(new BonePile());
break;
}
}
public CursedSoul(Serial serial) : base(serial)
{
}
public override string CorpseName => "a cursed soul corpse";
public override string DefaultName => "a cursed soul";
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,79 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class DeadlyImp : BaseCreature
{
[Constructible]
public DeadlyImp() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
{
Body = 74;
BaseSoundID = 422;
Hue = 0x66A;
SetStr(91, 115);
SetDex(61, 80);
SetInt(86, 105);
SetHits(1000);
SetDamage(50, 80);
SetDamageType(ResistanceType.Fire, 100);
SetResistance(ResistanceType.Physical, 95, 98);
SetResistance(ResistanceType.Fire, 95, 98);
SetResistance(ResistanceType.Cold, 95, 98);
SetResistance(ResistanceType.Poison, 95, 98);
SetResistance(ResistanceType.Energy, 95, 98);
SetSkill(SkillName.Magery, 120.0);
SetSkill(SkillName.Tactics, 120.0);
SetSkill(SkillName.Wrestling, 120.0);
Fame = 2500;
Karma = -2500;
CantWalk = true;
}
public DeadlyImp(Serial serial) : base(serial)
{
}
public override string DefaultName => "a deadly imp";
public override void AggressiveAction(Mobile aggressor, bool criminal)
{
base.AggressiveAction(aggressor, criminal);
if (aggressor is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is HaochisTrialsQuest)
{
QuestObjective obj = qs.FindObjective<SecondTrialAttackObjective>();
if (obj?.Completed == false)
{
obj.Complete();
qs.AddObjective(new SecondTrialReturnObjective(false));
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,56 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class DiseasedCat : BaseCreature
{
[Constructible]
public DiseasedCat() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4)
{
Body = 0xC9;
Hue = Utility.RandomAnimalHue();
BaseSoundID = 0x69;
SetStr(9);
SetDex(35);
SetInt(5);
SetHits(6);
SetMana(0);
SetDamage(1);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 5, 10);
SetSkill(SkillName.MagicResist, 5.0);
SetSkill(SkillName.Tactics, 4.0);
SetSkill(SkillName.Wrestling, 5.0);
VirtualArmor = 8;
}
public DiseasedCat(Serial serial) : base(serial)
{
}
public override string DefaultName => "a diseased cat";
public override bool AlwaysMurderer => true;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,101 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class FierceDragon : BaseCreature
{
[Constructible]
public FierceDragon() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
{
Body = 103;
BaseSoundID = 362;
SetStr(6000, 6020);
SetDex(0);
SetInt(850, 870);
SetDamage(50, 80);
SetDamageType(ResistanceType.Fire, 100);
SetResistance(ResistanceType.Physical, 95, 98);
SetResistance(ResistanceType.Fire, 95, 98);
SetResistance(ResistanceType.Cold, 95, 98);
SetResistance(ResistanceType.Poison, 95, 98);
SetResistance(ResistanceType.Energy, 95, 98);
SetSkill(SkillName.Tactics, 120.0);
SetSkill(SkillName.Wrestling, 120.0);
SetSkill(SkillName.Magery, 120.0);
Fame = 15000;
Karma = 15000;
CantWalk = true;
}
public FierceDragon(Serial serial) : base(serial)
{
}
public override string DefaultName => "a fierce dragon";
public override int GetIdleSound()
{
return 0x2C4;
}
public override int GetAttackSound()
{
return 0x2C0;
}
public override int GetDeathSound()
{
return 0x2C1;
}
public override int GetAngerSound()
{
return 0x2C4;
}
public override int GetHurtSound()
{
return 0x2C3;
}
public override void AggressiveAction(Mobile aggressor, bool criminal)
{
base.AggressiveAction(aggressor, criminal);
if (aggressor is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is HaochisTrialsQuest)
{
QuestObjective obj = qs.FindObjective<SecondTrialAttackObjective>();
if (obj?.Completed == false)
{
obj.Complete();
qs.AddObjective(new SecondTrialReturnObjective(true));
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,173 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class Haochi : BaseQuester
{
[Constructible]
public Haochi() : base("the Honorable Samurai Legend")
{
}
public Haochi(Serial serial) : base(serial)
{
}
public override string DefaultName => "Daimyo Haochi";
public override int TalkNumber => -1;
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x8403;
Female = false;
Body = 0x190;
}
public override void InitOutfit()
{
HairItemID = 0x204A;
HairHue = 0x901;
AddItem(new SamuraiTabi());
AddItem(new JinBaori());
AddItem(new PlateHaidate());
AddItem(new StandardPlateKabuto());
AddItem(new PlateMempo());
AddItem(new PlateDo());
AddItem(new PlateHiroSode());
}
public override int GetAutoTalkRange(PlayerMobile pm)
{
return 2;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is HaochisTrialsQuest)
{
if (HaochisTrialsQuest.HasLostHaochisKatana(player))
{
qs.AddConversation(new LostSwordConversation());
return;
}
QuestObjective obj = qs.FindObjective<FindHaochiObjective>();
if (obj?.Completed == false)
{
obj.Complete();
return;
}
obj = qs.FindObjective<FirstTrialReturnObjective>();
if (obj?.Completed == false)
{
player.AddToBackpack(new LeatherDo());
obj.Complete();
return;
}
obj = qs.FindObjective<SecondTrialReturnObjective>();
if (obj?.Completed == false)
{
if (((SecondTrialReturnObjective)obj).Dragon)
player.AddToBackpack(new LeatherSuneate());
obj.Complete();
return;
}
obj = qs.FindObjective<ThirdTrialReturnObjective>();
if (obj?.Completed == false)
{
player.AddToBackpack(new LeatherHiroSode());
obj.Complete();
return;
}
obj = qs.FindObjective<FourthTrialReturnObjective>();
if (obj?.Completed == false)
{
if (!((FourthTrialReturnObjective)obj).KilledCat)
{
Container cont = GetNewContainer();
cont.DropItem(new LeatherHiroSode());
cont.DropItem(new JinBaori());
player.AddToBackpack(cont);
}
obj.Complete();
return;
}
obj = qs.FindObjective<FifthTrialReturnObjective>();
if (obj?.Completed == false)
{
HaochisKatana katana = player.Backpack?.FindItemByType<HaochisKatana>();
if (katana == null)
return;
katana.Delete();
obj.Complete();
obj = qs.FindObjective<FifthTrialIntroObjective>();
if (obj != null && ((FifthTrialIntroObjective)obj).StolenTreasure)
qs.AddConversation(new SixthTrialIntroConversation(true));
else
qs.AddConversation(new SixthTrialIntroConversation(false));
}
obj = qs.FindObjective<SixthTrialReturnObjective>();
if (obj?.Completed == false)
{
obj.Complete();
return;
}
obj = qs.FindObjective<SeventhTrialReturnObjective>();
if (obj?.Completed == false)
{
BaseWeapon weapon = new Daisho();
BaseRunicTool.ApplyAttributesTo(weapon, Utility.Random(1, 3), 10, 30);
player.AddToBackpack(weapon);
BaseArmor armor = new LeatherDo();
BaseRunicTool.ApplyAttributesTo(armor, Utility.Random(1, 3), 10, 20);
player.AddToBackpack(armor);
obj.Complete();
}
}
}
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,103 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class HaochisGuardsman : BaseQuester
{
[Constructible]
public HaochisGuardsman() : base("the Guardsman of Daimyo Haochi")
{
}
public HaochisGuardsman(Serial serial) : base(serial)
{
}
public override int TalkNumber => -1;
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = Race.Human.RandomSkinHue();
Female = false;
Body = 0x190;
Name = NameList.RandomName("male");
}
public override void InitOutfit()
{
Utility.AssignRandomHair(this);
AddItem(new LeatherDo());
AddItem(new LeatherHiroSode());
AddItem(new SamuraiTabi(Utility.RandomNondyedHue()));
switch (Utility.Random(3))
{
case 0:
AddItem(new StuddedHaidate());
break;
case 1:
AddItem(new PlateSuneate());
break;
default:
AddItem(new LeatherSuneate());
break;
}
switch (Utility.Random(4))
{
case 0:
AddItem(new DecorativePlateKabuto());
break;
case 1:
AddItem(new ChainHatsuburi());
break;
case 2:
AddItem(new LightPlateJingasa());
break;
default:
AddItem(new LeatherJingasa());
break;
}
Item weapon;
switch (Utility.Random(3))
{
case 0:
weapon = new NoDachi();
break;
case 1:
weapon = new Lajatang();
break;
default:
weapon = new Wakizashi();
break;
}
weapon.Movable = false;
AddItem(weapon);
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,59 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class InjuredWolf : BaseCreature
{
[Constructible]
public InjuredWolf() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4)
{
Body = 0xE1;
BaseSoundID = 0xE5;
Hue = Utility.RandomAnimalHue();
SetStr(10, 20);
SetDex(45, 65);
SetInt(10, 15);
SetHits(1);
SetDamage(1, 3);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 15);
SetResistance(ResistanceType.Fire, 5, 10);
SetSkill(SkillName.MagicResist, 10.0);
SetSkill(SkillName.Tactics, 0.0, 5.0);
SetSkill(SkillName.Wrestling, 20.0, 30.0);
}
public InjuredWolf(Serial serial) : base(serial)
{
}
public override string CorpseName => "an injured wolf corpse";
public override string DefaultName => "an injured wolf";
public override int GetIdleSound()
{
return 0xE9;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,88 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class Relnia : BaseQuester
{
[Constructible]
public Relnia() : base("the Gypsy")
{
}
public Relnia(Serial serial) : base(serial)
{
}
public override string DefaultName => "Disheveled Relnia";
public override int TalkNumber => -1;
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83FF;
Female = true;
Body = 0x191;
}
public override void InitOutfit()
{
HairItemID = 0x203C;
HairHue = 0x654;
AddItem(new ThighBoots(0x901));
AddItem(new FancyShirt(0x5F3));
AddItem(new SkullCap(0x6A7));
AddItem(new Skirt(0x544));
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
if (from is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is HaochisTrialsQuest)
{
QuestObjective obj = qs.FindObjective<FourthTrialCatsObjective>();
if (obj?.Completed == false)
if (dropped is Gold gold)
{
obj.Complete();
qs.AddObjective(new FourthTrialReturnObjective(false));
SayTo(from, 1063241); // I thank thee. This gold will be a great help to me and mine!
gold.Consume(); // Intentional difference from OSI: don't take all the gold of poor newbies!
return gold.Deleted;
}
}
}
return base.OnDragDrop(from, dropped);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,67 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class YoungNinja : BaseCreature
{
[Constructible]
public YoungNinja() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
{
InitStats(45, 30, 5);
SetHits(20, 30);
Hue = Race.Human.RandomSkinHue();
Body = 0x190;
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this);
AddItem(new NinjaTabi());
AddItem(new LeatherNinjaPants());
AddItem(new LeatherNinjaJacket());
AddItem(new LeatherNinjaBelt());
AddItem(new Bandana(Utility.RandomNondyedHue()));
switch (Utility.Random(3))
{
case 0:
AddItem(new Tessen());
break;
case 1:
AddItem(new Kama());
break;
default:
AddItem(new Lajatang());
break;
}
SetSkill(SkillName.Swords, 50.0);
SetSkill(SkillName.Tactics, 50.0);
}
public YoungNinja(Serial serial) : base(serial)
{
}
public override string CorpseName => "a young ninja's corpse";
public override string DefaultName => "a young ninja";
public override bool AlwaysMurderer => true;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,79 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class YoungRonin : BaseCreature
{
[Constructible]
public YoungRonin() : base(AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
{
InitStats(45, 30, 5);
SetHits(10, 20);
Hue = Race.Human.RandomSkinHue();
Body = 0x190;
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this);
AddItem(new LeatherDo());
AddItem(new LeatherHiroSode());
AddItem(new SamuraiTabi());
switch (Utility.Random(3))
{
case 0:
AddItem(new StuddedHaidate());
break;
case 1:
AddItem(new PlateSuneate());
break;
default:
AddItem(new LeatherSuneate());
break;
}
AddItem(new Bandana(Utility.RandomNondyedHue()));
switch (Utility.Random(3))
{
case 0:
AddItem(new NoDachi());
break;
case 1:
AddItem(new Lajatang());
break;
default:
AddItem(new Wakizashi());
break;
}
SetSkill(SkillName.Swords, 50.0);
SetSkill(SkillName.Tactics, 50.0);
}
public YoungRonin(Serial serial) : base(serial)
{
}
public override string CorpseName => "a young ronin's corpse";
public override string DefaultName => "a young ronin";
public override bool AlwaysMurderer => true;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,342 @@
using System;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Samurai
{
public class FindHaochiObjective : QuestObjective
{
public override object Message => 1063026;
public override void OnComplete()
{
System.AddConversation(new FirstTrialIntroConversation());
}
}
public class FirstTrialIntroObjective : QuestObjective
{
public override object Message => 1063030;
public override void OnComplete()
{
System.AddConversation(new FirstTrialKillConversation());
}
}
public class FirstTrialKillObjective : QuestObjective
{
private int m_CursedSoulsKilled;
private int m_YoungRoninKilled;
public override object Message => 1063032;
public override int MaxProgress => 3;
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is CursedSoul)
{
if (m_CursedSoulsKilled == 0)
System.AddConversation(new GainKarmaConversation(true));
m_CursedSoulsKilled++;
// Cursed Souls killed: ~1_COUNT~
System.From.SendLocalizedMessage(1063038, m_CursedSoulsKilled.ToString());
}
else if (creature is YoungRonin)
{
if (m_YoungRoninKilled == 0)
System.AddConversation(new GainKarmaConversation(false));
m_YoungRoninKilled++;
// Young Ronin killed: ~1_COUNT~
System.From.SendLocalizedMessage(1063039, m_YoungRoninKilled.ToString());
}
CurProgress = Math.Max(m_CursedSoulsKilled, m_YoungRoninKilled);
}
public override void OnComplete()
{
System.AddObjective(new FirstTrialReturnObjective(m_CursedSoulsKilled > m_YoungRoninKilled));
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_CursedSoulsKilled = reader.ReadEncodedInt();
m_YoungRoninKilled = reader.ReadEncodedInt();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt(m_CursedSoulsKilled);
writer.WriteEncodedInt(m_YoungRoninKilled);
}
}
public class FirstTrialReturnObjective : QuestObjective
{
private bool m_CursedSoul;
public FirstTrialReturnObjective(bool cursedSoul)
{
m_CursedSoul = cursedSoul;
}
public FirstTrialReturnObjective()
{
}
public override object Message => 1063044;
public override void OnComplete()
{
System.AddConversation(new SecondTrialIntroConversation(m_CursedSoul));
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_CursedSoul = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_CursedSoul);
}
}
public class SecondTrialIntroObjective : QuestObjective
{
public override object Message => 1063047;
public override void OnComplete()
{
System.AddConversation(new SecondTrialAttackConversation());
}
}
public class SecondTrialAttackObjective : QuestObjective
{
public override object Message => 1063058;
}
public class SecondTrialReturnObjective : QuestObjective
{
public SecondTrialReturnObjective(bool dragon)
{
Dragon = dragon;
}
public SecondTrialReturnObjective()
{
}
public override object Message => 1063229;
public bool Dragon{ get; private set; }
public override void OnComplete()
{
System.AddConversation(new ThirdTrialIntroConversation(Dragon));
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
Dragon = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(Dragon);
}
}
public class ThirdTrialIntroObjective : QuestObjective
{
public override object Message => 1063061;
public override void OnComplete()
{
System.AddConversation(new ThirdTrialKillConversation());
}
}
public class ThirdTrialKillObjective : QuestObjective
{
public override object Message => 1063063;
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is InjuredWolf)
Complete();
}
public override void OnComplete()
{
System.AddObjective(new ThirdTrialReturnObjective());
}
}
public class ThirdTrialReturnObjective : QuestObjective
{
public override object Message => 1063064;
public override void OnComplete()
{
System.AddConversation(new FourthTrialIntroConversation());
}
}
public class FourthTrialIntroObjective : QuestObjective
{
public override object Message => 1063066;
public override void OnComplete()
{
System.AddConversation(new FourthTrialCatsConversation());
}
}
public class FourthTrialCatsObjective : QuestObjective
{
public override object Message => 1063068;
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is DiseasedCat)
{
Complete();
System.AddObjective(new FourthTrialReturnObjective(true));
}
}
}
public class FourthTrialReturnObjective : QuestObjective
{
public FourthTrialReturnObjective(bool killedCat)
{
KilledCat = killedCat;
}
public FourthTrialReturnObjective()
{
}
public override object Message => 1063242;
public bool KilledCat{ get; private set; }
public override void OnComplete()
{
System.AddConversation(new FifthTrialIntroConversation(KilledCat));
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
KilledCat = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(KilledCat);
}
}
public class FifthTrialIntroObjective : QuestObjective
{
public override object Message => 1063072;
public bool StolenTreasure{ get; set; }
public override void OnComplete()
{
System.AddConversation(new FifthTrialReturnConversation());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
StolenTreasure = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(StolenTreasure);
}
}
public class FifthTrialReturnObjective : QuestObjective
{
public override object Message => 1063073;
}
public class SixthTrialIntroObjective : QuestObjective
{
public override object Message => 1063078;
public override void OnComplete()
{
System.AddObjective(new SixthTrialReturnObjective());
}
}
public class SixthTrialReturnObjective : QuestObjective
{
public override object Message => 1063252;
public override void OnComplete()
{
System.AddConversation(new SeventhTrialIntroConversation());
}
}
public class SeventhTrialIntroObjective : QuestObjective
{
public override object Message => 1063080;
public override int MaxProgress => 3;
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is YoungNinja)
CurProgress++;
}
public override void OnComplete()
{
System.AddObjective(new SeventhTrialReturnObjective());
}
}
public class SeventhTrialReturnObjective : QuestObjective
{
public override object Message => 1063253;
public override void OnComplete()
{
System.AddConversation(new EndConversation());
}
}
}

View file

@ -0,0 +1,183 @@
namespace Server.Engines.Quests.Matriarch
{
public class DontOfferConversation : QuestConversation
{
private bool m_Friend;
public DontOfferConversation(bool friend)
{
m_Friend = friend;
}
public DontOfferConversation()
{
}
public override object Message
{
get
{
if (m_Friend) return 1054081;
/* <I>The Solen Matriarch smiles as she eats the seed you offered.</I><BR><BR>
*
* Thank you for that seed. It was quite delicious. <BR><BR>
*
* I would offer to make you a friend of my colony, but you seem to be busy with
* another task at the moment. Perhaps you should finish whatever is occupying
* your attention at the moment and return to me once you're done.
*/
return 1054079;
}
}
public override bool Logged => false;
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_Friend = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_Friend);
}
}
public class AcceptConversation : QuestConversation
{
public override object Message => 1054084;
public override void OnRead()
{
System.AddObjective(new KillInfiltratorsObjective());
}
}
public class DuringKillInfiltratorsConversation : QuestConversation
{
public override object Message => 1054089;
public override bool Logged => false;
}
public class GatherWaterConversation : QuestConversation
{
public override object Message => 1054091;
public override void OnRead()
{
System.AddObjective(new GatherWaterObjective());
}
}
public class DuringWaterGatheringConversation : QuestConversation
{
public override object Message => 1054094;
public override bool Logged => false;
}
public class ProcessFungiConversation : QuestConversation
{
private bool m_Friend;
public ProcessFungiConversation(bool friend)
{
m_Friend = friend;
}
public ProcessFungiConversation()
{
}
public override object Message
{
get
{
if (m_Friend) return 1054097;
/* <I>The Solen Matriarch listens as you report the completion of your
* tasks to her.</I><BR><BR>
*
* I give you my thanks for your help, and I will gladly make you a friend of my
* solen colony. My warriors, workers, and queens will not longer look at you
* as an intruder and attack you when you enter our lair.<BR><BR>
*
* I will also process some zoogi fungus into powder of translocation for you.
* Two of the zoogi fungi are required for each measure of the powder. I will
* process up to 200 zoogi fungi into 100 measures of powder of translocation.<BR><BR>
*
* I will also give you some gold for assisting me and my colony, but first let's
* take care of your zoogi fungus.
*/
return 1054096;
}
}
public override void OnRead()
{
System.AddObjective(new ProcessFungiObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_Friend = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_Friend);
}
}
public class DuringFungiProcessConversation : QuestConversation
{
public override object Message => 1054099;
public override bool Logged => false;
}
public class FullBackpackConversation : QuestConversation
{
private bool m_Logged;
public FullBackpackConversation(bool logged)
{
m_Logged = logged;
}
public FullBackpackConversation()
{
m_Logged = true;
}
public override object Message => 1054102;
public override bool Logged => m_Logged;
public override void OnRead()
{
if (m_Logged)
System.AddObjective(new GetRewardObjective());
}
}
public class EndConversation : QuestConversation
{
public override object Message => 1054101;
public override void OnRead()
{
System.Complete();
}
}
}

View file

@ -0,0 +1,299 @@
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Engines.Plants;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Engines.Quests.Matriarch
{
public abstract class BaseSolenMatriarch : BaseQuester
{
public BaseSolenMatriarch()
{
Body = 0x328;
if (!RedSolen)
Hue = 0x44E;
SpeechHue = 0;
}
public BaseSolenMatriarch(Serial serial) : base(serial)
{
}
public abstract bool RedSolen{ get; }
public override string DefaultName => "the solen matriarch";
public override bool DisallowAllMoves => false;
public override int GetIdleSound()
{
return 0x10D;
}
public override bool CanTalkTo(PlayerMobile to)
{
if (SolenMatriarchQuest.IsFriend(to, RedSolen))
return true;
return to.Quest is SolenMatriarchQuest qs && qs.RedSolen == RedSolen;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
Direction = GetDirectionTo(player);
if (player.Quest is SolenMatriarchQuest qs && qs.RedSolen == RedSolen)
{
if (qs.IsObjectiveInProgress(typeof(KillInfiltratorsObjective)))
{
qs.AddConversation(new DuringKillInfiltratorsConversation());
}
else
{
QuestObjective obj = qs.FindObjective<ReturnAfterKillsObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else if (qs.IsObjectiveInProgress(typeof(GatherWaterObjective)))
{
qs.AddConversation(new DuringWaterGatheringConversation());
}
else
{
obj = qs.FindObjective<ReturnAfterWaterObjective>();
if (obj?.Completed == false)
{
obj.Complete();
}
else if (qs.IsObjectiveInProgress(typeof(ProcessFungiObjective)))
{
qs.AddConversation(new DuringFungiProcessConversation());
}
else
{
obj = qs.FindObjective<GetRewardObjective>();
if (obj?.Completed == false)
{
if (SolenMatriarchQuest.GiveRewardTo(player))
obj.Complete();
else
qs.AddConversation(new FullBackpackConversation(false));
}
}
}
}
}
else if (SolenMatriarchQuest.IsFriend(player, RedSolen))
{
QuestSystem newQuest = new SolenMatriarchQuest(player, RedSolen);
if (player.Quest == null && QuestSystem.CanOfferQuest(player, typeof(SolenMatriarchQuest)))
newQuest.SendOffer();
else
newQuest.AddConversation(new DontOfferConversation(true));
}
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
if (from is PlayerMobile player)
{
if (dropped is Seed)
{
if (player.Quest is SolenMatriarchQuest qs && qs.RedSolen == RedSolen)
{
SayTo(player, 1054080); // Thank you for that plant seed. Those have such wonderful flavor.
}
else
{
QuestSystem newQuest = new SolenMatriarchQuest(player, RedSolen);
if (player.Quest == null && QuestSystem.CanOfferQuest(player, typeof(SolenMatriarchQuest)))
newQuest.SendOffer();
else
newQuest.AddConversation(
new DontOfferConversation(SolenMatriarchQuest.IsFriend(player, RedSolen)));
}
dropped.Delete();
return true;
}
if (dropped is ZoogiFungus fungus)
{
OnGivenFungi(player, fungus);
return fungus.Deleted;
}
}
return base.OnDragDrop(from, dropped);
}
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
{
base.GetContextMenuEntries(from, list);
if (from.Alive)
if (from is PlayerMobile pm)
if (pm.Quest is SolenMatriarchQuest qs && qs.RedSolen == RedSolen)
if (qs.IsObjectiveInProgress(typeof(ProcessFungiObjective)))
list.Add(new ProcessZoogiFungusEntry(this, pm));
}
public void OnGivenFungi(PlayerMobile player, ZoogiFungus fungi)
{
Direction = GetDirectionTo(player);
if (player.Quest is SolenMatriarchQuest qs && qs.RedSolen == RedSolen)
{
QuestObjective obj = qs.FindObjective<ProcessFungiObjective>();
if (obj?.Completed == false)
{
int amount = fungi.Amount / 2;
if (amount > 100)
amount = 100;
if (amount > 0)
{
if (amount * 2 >= fungi.Amount)
fungi.Delete();
else
fungi.Amount -= amount * 2;
PowderOfTranslocation powder = new PowderOfTranslocation(amount);
player.AddToBackpack(powder);
player.SendLocalizedMessage(1054100); // You receive some powder of translocation.
obj.Complete();
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
private class ProcessZoogiFungusEntry : ContextMenuEntry
{
private PlayerMobile m_From;
private BaseSolenMatriarch m_Matriarch;
public ProcessZoogiFungusEntry(BaseSolenMatriarch matriarch, PlayerMobile from) : base(6184)
{
m_Matriarch = matriarch;
m_From = from;
}
public override void OnClick()
{
if (m_From.Alive)
m_From.Target = new ProcessFungiTarget(m_Matriarch, m_From);
}
}
private class ProcessFungiTarget : Target
{
private PlayerMobile m_From;
private BaseSolenMatriarch m_Matriarch;
public ProcessFungiTarget(BaseSolenMatriarch matriarch, PlayerMobile from) : base(-1, false, TargetFlags.None)
{
m_Matriarch = matriarch;
m_From = from;
}
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
{
from.SendLocalizedMessage(1042021, "", 0x59); // Cancelled.
}
protected override void OnTarget(Mobile from, object targeted)
{
if (targeted is ZoogiFungus fungus)
{
if (fungus.IsChildOf(m_From.Backpack))
m_Matriarch.OnGivenFungi(m_From, fungus);
else
m_From.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
}
}
}
}
public class RedSolenMatriarch : BaseSolenMatriarch
{
[Constructible]
public RedSolenMatriarch()
{
}
public RedSolenMatriarch(Serial serial) : base(serial)
{
}
public override bool RedSolen => true;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
public class BlackSolenMatriarch : BaseSolenMatriarch
{
[Constructible]
public BlackSolenMatriarch()
{
}
public BlackSolenMatriarch(Serial serial) : base(serial)
{
}
public override bool RedSolen => false;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,142 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Matriarch
{
public class KillInfiltratorsObjective : QuestObjective
{
public override object Message => ((SolenMatriarchQuest)System).RedSolen ? 1054086 : 1054085;
public override int MaxProgress => 7;
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
// Black/Red Solen Infiltrators killed:
gump.AddHtmlLocalized(70, 260, 270, 100, ((SolenMatriarchQuest)System).RedSolen ? 1054088 : 1054087,
BaseQuestGump.Blue);
gump.AddLabel(70, 280, 0x64, CurProgress.ToString());
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, MaxProgress.ToString());
}
else
{
base.RenderProgress(gump);
}
}
public override bool IgnoreYoungProtection(Mobile from)
{
if (Completed)
return false;
bool redSolen = ((SolenMatriarchQuest)System).RedSolen;
if (redSolen)
return from is BlackSolenInfiltratorWarrior || from is BlackSolenInfiltratorQueen;
return from is RedSolenInfiltratorWarrior || from is RedSolenInfiltratorQueen;
}
public override void OnKill(BaseCreature creature, Container corpse)
{
bool redSolen = ((SolenMatriarchQuest)System).RedSolen;
if (redSolen)
{
if (creature is BlackSolenInfiltratorWarrior || creature is BlackSolenInfiltratorQueen)
CurProgress++;
}
else
{
if (creature is RedSolenInfiltratorWarrior || creature is RedSolenInfiltratorQueen)
CurProgress++;
}
}
public override void OnComplete()
{
System.AddObjective(new ReturnAfterKillsObjective());
}
}
public class ReturnAfterKillsObjective : QuestObjective
{
public override object Message => 1054090;
public override void OnComplete()
{
System.AddConversation(new GatherWaterConversation());
}
}
public class GatherWaterObjective : QuestObjective
{
public override object Message => 1054092;
public override int MaxProgress => 40;
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
gump.AddHtmlLocalized(70, 260, 270, 100, 1054093, BaseQuestGump.Blue); // Gallons of Water gathered:
gump.AddLabel(70, 280, 0x64, (CurProgress / 5).ToString());
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, (MaxProgress / 5).ToString());
}
else
{
base.RenderProgress(gump);
}
}
public override void OnComplete()
{
System.AddObjective(new ReturnAfterWaterObjective());
}
}
public class ReturnAfterWaterObjective : QuestObjective
{
public override object Message => 1054095;
public override void OnComplete()
{
PlayerMobile player = System.From;
bool redSolen = ((SolenMatriarchQuest)System).RedSolen;
bool friend = SolenMatriarchQuest.IsFriend(player, redSolen);
System.AddConversation(new ProcessFungiConversation(friend));
if (redSolen)
player.SolenFriendship = SolenFriendship.Red;
else
player.SolenFriendship = SolenFriendship.Black;
}
}
public class ProcessFungiObjective : QuestObjective
{
public override object Message => 1054098;
public override void OnComplete()
{
if (SolenMatriarchQuest.GiveRewardTo(System.From))
System.Complete();
else
System.AddConversation(new FullBackpackConversation(true));
}
}
public class GetRewardObjective : QuestObjective
{
public override object Message => 1054149;
public override void OnComplete()
{
System.AddConversation(new EndConversation());
}
}
}

View file

@ -0,0 +1,124 @@
using System;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Matriarch
{
public class SolenMatriarchQuest : QuestSystem
{
private static Type[] m_TypeReferenceTable =
{
typeof(DontOfferConversation),
typeof(AcceptConversation),
typeof(DuringKillInfiltratorsConversation),
typeof(GatherWaterConversation),
typeof(DuringWaterGatheringConversation),
typeof(ProcessFungiConversation),
typeof(DuringFungiProcessConversation),
typeof(FullBackpackConversation),
typeof(EndConversation),
typeof(KillInfiltratorsObjective),
typeof(ReturnAfterKillsObjective),
typeof(GatherWaterObjective),
typeof(ReturnAfterWaterObjective),
typeof(ProcessFungiObjective),
typeof(GetRewardObjective)
};
public SolenMatriarchQuest(PlayerMobile from, bool redSolen) : base(from)
{
RedSolen = redSolen;
}
// Serialization
public SolenMatriarchQuest()
{
}
public override Type[] TypeReferenceTable => m_TypeReferenceTable;
public override object Name => 1054147;
public override object OfferMessage
{
get
{
if (IsFriend(From, RedSolen)) return 1054083;
/* <I>The Solen Matriarch smiles happily as she eats the seed you offered.</I><BR><BR>
*
* I think you for that seed. I was quite delicious. So full of flavor.<BR><BR>
*
* Hmm... if you would like, I could make you a friend of my colony. This would stop
* the warriors, workers, and queens of my colony from thinking you are an intruder,
* thus they would not attack you. In addition, as a friend of my colony I will process
* zoogi fungus into powder of translocation for you.<BR><BR>
*
* To become a friend of my colony, I ask that you complete a couple tasks for me. These
* are the same tasks I will ask of you when you wish me to process zoogi fungus,
* by the way.<BR><BR>
*
* First, I would like for you to eliminate some infiltrators from the other solen colony.
* They are spying on my colony, and I fear for the safety of my people. They must
* be slain.<BR><BR>
*
* After that, I must ask that you gather some water for me. Our water supplies are
* inadequate, so we must try to supplement our reserve using water vats here in our
* lair.<BR><BR>
*
* Will you accept my offer?
*/
return 1054082;
}
}
public override TimeSpan RestartDelay => TimeSpan.Zero;
public override bool IsTutorial => false;
public override int Picture => 0x15C9;
public bool RedSolen{ get; private set; }
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
RedSolen = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(RedSolen);
}
public override void Accept()
{
base.Accept();
AddConversation(new AcceptConversation());
}
public static bool IsFriend(PlayerMobile player, bool redSolen)
{
if (redSolen)
return player.SolenFriendship == SolenFriendship.Red;
return player.SolenFriendship == SolenFriendship.Black;
}
public static bool GiveRewardTo(PlayerMobile player)
{
Gold gold = new Gold(Utility.RandomMinMax(250, 350));
if (player.PlaceInBackpack(gold))
{
player.SendLocalizedMessage(1054076); // You have been given some gold.
return true;
}
gold.Delete();
return false;
}
}
}

View file

@ -0,0 +1,53 @@
namespace Server.Engines.Quests.Naturalist
{
public class DontOfferConversation : QuestConversation
{
public override object Message => 1054052;
public override bool Logged => false;
}
public class AcceptConversation : QuestConversation
{
public override object Message => 1054043;
public override void OnRead()
{
System.AddObjective(new StudyNestsObjective());
}
}
public class NaturalistDuringStudyConversation : QuestConversation
{
public override object Message => 1054049;
public override bool Logged => false;
}
public class EndConversation : QuestConversation
{
public override object Message => 1054050;
public override void OnRead()
{
System.Complete();
}
}
public class SpecialEndConversation : QuestConversation
{
public override object Message => 1054051;
public override void OnRead()
{
System.Complete();
}
}
public class FullBackpackConversation : QuestConversation
{
public override object Message => 1054053;
public override bool Logged => false;
}
}

View file

@ -0,0 +1,191 @@
using Server.Engines.Plants;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Naturalist
{
public class Naturalist : BaseQuester
{
[Constructible]
public Naturalist() : base("the Naturalist")
{
}
public Naturalist(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 Tunic(0x598));
AddItem(new LongPants(0x59B));
AddItem(new Boots());
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this, HairHue);
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
if (player.Quest is StudyOfSolenQuest qs && qs.Naturalist == this)
{
StudyNestsObjective study = qs.FindObjective<StudyNestsObjective>();
if (study == null)
return;
if (!study.Completed)
{
PlaySound(0x41F);
qs.AddConversation(new NaturalistDuringStudyConversation());
return;
}
QuestObjective obj = qs.FindObjective<ReturnToNaturalistObjective>();
if (obj?.Completed == false)
{
Seed reward;
PlantType type;
switch (Utility.Random(17))
{
case 0:
type = PlantType.CampionFlowers;
break;
case 1:
type = PlantType.Poppies;
break;
case 2:
type = PlantType.Snowdrops;
break;
case 3:
type = PlantType.Bulrushes;
break;
case 4:
type = PlantType.Lilies;
break;
case 5:
type = PlantType.PampasGrass;
break;
case 6:
type = PlantType.Rushes;
break;
case 7:
type = PlantType.ElephantEarPlant;
break;
case 8:
type = PlantType.Fern;
break;
case 9:
type = PlantType.PonytailPalm;
break;
case 10:
type = PlantType.SmallPalm;
break;
case 11:
type = PlantType.CenturyPlant;
break;
case 12:
type = PlantType.WaterPlant;
break;
case 13:
type = PlantType.SnakePlant;
break;
case 14:
type = PlantType.PricklyPearCactus;
break;
case 15:
type = PlantType.BarrelCactus;
break;
default:
type = PlantType.TribarrelCactus;
break;
}
if (study.StudiedSpecialNest)
{
reward = new Seed(type, PlantHue.FireRed);
}
else
{
PlantHue hue;
switch (Utility.Random(3))
{
case 0:
hue = PlantHue.Pink;
break;
case 1:
hue = PlantHue.Magenta;
break;
default:
hue = PlantHue.Aqua;
break;
}
reward = new Seed(type, hue);
}
if (player.PlaceInBackpack(reward))
{
obj.Complete();
PlaySound(0x449);
PlaySound(0x41B);
if (study.StudiedSpecialNest)
qs.AddConversation(new SpecialEndConversation());
else
qs.AddConversation(new EndConversation());
}
else
{
reward.Delete();
qs.AddConversation(new FullBackpackConversation());
}
}
}
else
{
QuestSystem newQuest = new StudyOfSolenQuest(player, this);
if (player.Quest == null && QuestSystem.CanOfferQuest(player, typeof(StudyOfSolenQuest)))
{
PlaySound(0x42F);
newQuest.SendOffer();
}
else
{
PlaySound(0x448);
newQuest.AddConversation(new DontOfferConversation());
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View file

@ -0,0 +1,64 @@
using System.Linq;
namespace Server.Engines.Quests.Naturalist
{
public class NestArea
{
private static readonly NestArea[] m_Areas =
{
new NestArea(false, new Rectangle2D(5861, 1787, 26, 25)),
new NestArea(false, new Rectangle2D(5734, 1788, 14, 50),
new Rectangle2D(5748, 1800, 3, 34),
new Rectangle2D(5751, 1808, 2, 20)),
new NestArea(false, new Rectangle2D(5907, 1908, 19, 43)),
new NestArea(false, new Rectangle2D(5721, 1926, 24, 29),
new Rectangle2D(5745, 1935, 7, 22)),
new NestArea(true, new Rectangle2D(5651, 1853, 21, 32),
new Rectangle2D(5672, 1857, 6, 20))
};
private Rectangle2D[] m_Rects;
private NestArea(bool special, params Rectangle2D[] rects)
{
Special = special;
m_Rects = rects;
}
public static int NonSpecialCount => m_Areas.Count(area => !area.Special);
public bool Special{ get; }
public int ID
{
get
{
for (int i = 0; i < m_Areas.Length; i++)
if (m_Areas[i] == this)
return i;
return 0;
}
}
public static NestArea Find(IPoint2D p)
{
return m_Areas.FirstOrDefault(area => area.Contains(p));
}
public static NestArea GetByID(int id)
{
if (id >= 0 && id < m_Areas.Length)
return m_Areas[id];
return null;
}
public bool Contains(IPoint2D p)
{
return m_Rects.Any(rect => rect.Contains(p));
}
}
}

View file

@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using Server.Mobiles;
namespace Server.Engines.Quests.Naturalist
{
public class StudyNestsObjective : QuestObjective
{
private NestArea m_CurrentNest;
private List<NestArea> m_StudiedNests = new List<NestArea>();
private DateTime m_StudyBegin;
private StudyState m_StudyState;
public override object Message => 1054044;
public override int MaxProgress => NestArea.NonSpecialCount;
public bool StudiedSpecialNest{ get; private set; }
public override bool GetTimerEvent()
{
return true;
}
public override void CheckProgress()
{
PlayerMobile from = System.From;
if (m_CurrentNest != null)
{
NestArea nest = m_CurrentNest;
if ((from.Map == Map.Trammel || from.Map == Map.Felucca) && nest.Contains(from))
{
if (m_StudyState != StudyState.Inactive)
{
TimeSpan time = DateTime.UtcNow - m_StudyBegin;
if (time > TimeSpan.FromSeconds(30.0))
{
m_StudiedNests.Add(nest);
m_StudyState = StudyState.Inactive;
if (m_CurrentNest.Special)
{
from.SendLocalizedMessage(
1054057); // You complete your examination of this bizarre Egg Nest. The Naturalist will undoubtedly be quite interested in these notes!
StudiedSpecialNest = true;
}
else
{
from.SendLocalizedMessage(
1054054); // You have completed your study of this Solen Egg Nest. You put your notes away.
CurProgress++;
}
}
else if (m_StudyState == StudyState.FirstStep && time > TimeSpan.FromSeconds(15.0))
{
if (!nest.Special)
from.SendLocalizedMessage(
1054058); // You begin recording your completed notes on a bit of parchment.
m_StudyState = StudyState.SecondStep;
}
}
}
else
{
if (m_StudyState != StudyState.Inactive)
from.SendLocalizedMessage(
1054046); // You abandon your study of the Solen Egg Nest without gathering the needed information.
m_CurrentNest = null;
}
}
else if (from.Map == Map.Trammel || from.Map == Map.Felucca)
{
NestArea nest = NestArea.Find(from);
if (nest != null)
{
m_CurrentNest = nest;
m_StudyBegin = DateTime.UtcNow;
if (m_StudiedNests.Contains(nest))
{
m_StudyState = StudyState.Inactive;
from.SendLocalizedMessage(
1054047); // You glance at the Egg Nest, realizing you've already studied this one.
}
else
{
m_StudyState = StudyState.FirstStep;
if (nest.Special)
from.SendLocalizedMessage(
1054056); // You notice something very odd about this Solen Egg Nest. You begin taking notes.
else
from.SendLocalizedMessage(
1054045); // You begin studying the Solen Egg Nest to gather information.
if (from.Female)
from.PlaySound(0x30B);
else
from.PlaySound(0x419);
}
}
}
}
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
gump.AddHtmlLocalized(70, 260, 270, 100, 1054055, BaseQuestGump.Blue); // Solen Nests Studied :
gump.AddLabel(70, 280, 0x64, CurProgress.ToString());
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, MaxProgress.ToString());
}
else
{
base.RenderProgress(gump);
}
}
public override void OnComplete()
{
System.AddObjective(new ReturnToNaturalistObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
int count = reader.ReadEncodedInt();
for (int i = 0; i < count; i++)
{
NestArea nest = NestArea.GetByID(reader.ReadEncodedInt());
m_StudiedNests.Add(nest);
}
StudiedSpecialNest = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt(m_StudiedNests.Count);
foreach (NestArea nest in m_StudiedNests)
writer.WriteEncodedInt(nest.ID);
writer.Write(StudiedSpecialNest);
}
private enum StudyState
{
Inactive,
FirstStep,
SecondStep
}
}
public class ReturnToNaturalistObjective : QuestObjective
{
public override object Message => 1054048;
public override void RenderProgress(BaseQuestGump gump)
{
string count = NestArea.NonSpecialCount.ToString();
gump.AddHtmlLocalized(70, 260, 270, 100, 1054055, BaseQuestGump.Blue); // Solen Nests Studied :
gump.AddLabel(70, 280, 0x64, count);
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, count);
}
}
}

View file

@ -0,0 +1,66 @@
using System;
using Server.Mobiles;
namespace Server.Engines.Quests.Naturalist
{
public class StudyOfSolenQuest : QuestSystem
{
private static Type[] m_TypeReferenceTable =
{
typeof(StudyNestsObjective),
typeof(ReturnToNaturalistObjective),
typeof(DontOfferConversation),
typeof(AcceptConversation),
typeof(NaturalistDuringStudyConversation),
typeof(EndConversation),
typeof(SpecialEndConversation),
typeof(FullBackpackConversation)
};
public StudyOfSolenQuest(PlayerMobile from, Naturalist naturalist) : base(from)
{
Naturalist = naturalist;
}
// Serialization
public StudyOfSolenQuest()
{
}
public override Type[] TypeReferenceTable => m_TypeReferenceTable;
public override object Name => 1054041;
public override object OfferMessage => 1054042;
public override TimeSpan RestartDelay => TimeSpan.Zero;
public override bool IsTutorial => false;
public override int Picture => 0x15C7;
public Naturalist Naturalist{ get; private set; }
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
Naturalist = (Naturalist)reader.ReadMobile();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(Naturalist);
}
public override void Accept()
{
base.Accept();
Naturalist?.PlaySound(0x431);
AddConversation(new AcceptConversation());
}
}
}

View file

@ -0,0 +1,36 @@
namespace Server.Engines.Quests.Zento
{
public class AcceptConversation : QuestConversation
{
public override object Message => 1049092;
public override void OnRead()
{
System.AddObjective(new FirstKillObjective());
}
}
public class DirectionConversation : QuestConversation
{
public override object Message => 1063323;
public override bool Logged => false;
}
public class TakeCareConversation : QuestConversation
{
public override object Message => 1063324;
public override bool Logged => false;
}
public class EndConversation : QuestConversation
{
public override object Message => 1063321;
public override void OnRead()
{
System.Complete();
}
}
}

View file

@ -0,0 +1,142 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Zento
{
public class AnsellaGryen : BaseQuester
{
[Constructible]
public AnsellaGryen()
{
}
public AnsellaGryen(Serial serial) : base(serial)
{
}
public override string DefaultName => "Ansella Gryen";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83EA;
Female = true;
Body = 0x191;
}
public override void InitOutfit()
{
HairItemID = 0x203B;
HairHue = 0x1BB;
AddItem(new SamuraiTabi(0x8FD));
AddItem(new FemaleKimono(0x4B6));
AddItem(new Obi(0x526));
AddItem(new GoldBracelet());
}
public override int GetAutoTalkRange(PlayerMobile m)
{
if (m.Quest == null)
return 3;
return -1;
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
QuestSystem qs = player.Quest;
if (qs is TerribleHatchlingsQuest)
{
if (qs.IsObjectiveInProgress(typeof(FirstKillObjective)))
{
qs.AddConversation(new DirectionConversation());
}
else if (qs.IsObjectiveInProgress(typeof(SecondKillObjective))
|| qs.IsObjectiveInProgress(typeof(ThirdKillObjective)))
{
qs.AddConversation(new TakeCareConversation());
}
else
{
QuestObjective obj = qs.FindObjective<ReturnObjective>();
if (obj?.Completed == false)
{
Container cont = GetNewContainer();
cont.DropItem(new Gold(Utility.RandomMinMax(100, 200)));
if (Utility.RandomBool())
{
if (Loot.Construct(Loot.SEWeaponTypes) is BaseWeapon weapon)
{
BaseRunicTool.ApplyAttributesTo(weapon, 3, 10, 30);
cont.DropItem(weapon);
}
}
else
{
if (Loot.Construct(Loot.SEArmorTypes) is BaseArmor armor)
{
BaseRunicTool.ApplyAttributesTo(armor, 1, 10, 20);
cont.DropItem(armor);
}
}
if (player.PlaceInBackpack(cont))
{
obj.Complete();
}
else
{
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
{
TerribleHatchlingsQuest newQuest = new TerribleHatchlingsQuest(player);
if (qs != null)
{
if (contextMenu)
SayTo(player,
1063322); // Before you can help me with the Terrible Hatchlings, you'll need to finish the quest you've already taken!
}
else if (QuestSystem.CanOfferQuest(player, typeof(TerribleHatchlingsQuest), out bool inRestartPeriod))
{
newQuest.SendOffer();
}
else if (inRestartPeriod && contextMenu)
{
SayTo(player, 1049357); // I have nothing more for you at this time.
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
public override void TurnToTokuno()
{
}
}
}

View file

@ -0,0 +1,132 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Zento
{
public class FirstKillObjective : QuestObjective
{
public override object Message => 1063316;
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
// Deathwatch Beetle Hatchlings killed:
gump.AddHtmlLocalized(70, 260, 270, 100, 1063318, 0x12DC6BF);
gump.AddLabel(70, 280, 0x64, "0");
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, "10");
}
else
{
base.RenderProgress(gump);
}
}
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is DeathwatchBeetleHatchling)
Complete();
}
public override void OnComplete()
{
System.AddObjective(new SecondKillObjective());
}
}
public class SecondKillObjective : QuestObjective
{
public override object Message => 1063320;
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
// Deathwatch Beetle Hatchlings killed:
gump.AddHtmlLocalized(70, 260, 270, 100, 1063318, 0x12DC6BF);
gump.AddLabel(70, 280, 0x64, "1");
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, "10");
}
else
{
base.RenderProgress(gump);
}
}
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is DeathwatchBeetleHatchling)
{
Complete();
System.AddObjective(new ThirdKillObjective(2));
}
}
public override void OnRead()
{
if (!Completed)
{
Complete();
System.AddObjective(new ThirdKillObjective(1));
}
}
}
public class ThirdKillObjective : QuestObjective
{
public ThirdKillObjective(int startingProgress)
{
CurProgress = startingProgress;
}
public ThirdKillObjective()
{
}
public override object Message => 1063319;
public override int MaxProgress => 10;
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
// Deathwatch Beetle Hatchlings killed:
gump.AddHtmlLocalized(70, 260, 270, 100, 1063318, 0x12DC6BF);
gump.AddLabel(70, 280, 0x64, CurProgress.ToString());
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, "10");
}
else
{
base.RenderProgress(gump);
}
}
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is DeathwatchBeetleHatchling)
CurProgress++;
}
public override void OnComplete()
{
System.AddObjective(new ReturnObjective());
}
}
public class ReturnObjective : QuestObjective
{
public override object Message => 1063313;
public override void OnComplete()
{
System.AddConversation(new EndConversation());
}
}
}

View file

@ -0,0 +1,47 @@
using System;
using Server.Mobiles;
namespace Server.Engines.Quests.Zento
{
public class TerribleHatchlingsQuest : QuestSystem
{
private static Type[] m_TypeReferenceTable =
{
typeof(AcceptConversation),
typeof(DirectionConversation),
typeof(TakeCareConversation),
typeof(EndConversation),
typeof(FirstKillObjective),
typeof(SecondKillObjective),
typeof(ThirdKillObjective),
typeof(ReturnObjective)
};
public TerribleHatchlingsQuest(PlayerMobile from) : base(from)
{
}
// Serialization
public TerribleHatchlingsQuest()
{
}
public override Type[] TypeReferenceTable => m_TypeReferenceTable;
public override object Name => 1063314;
public override object OfferMessage => 1063315;
public override TimeSpan RestartDelay => TimeSpan.MaxValue;
public override bool IsTutorial => true;
public override int Picture => 0x15CF;
public override void Accept()
{
base.Accept();
AddConversation(new AcceptConversation());
}
}
}

View file

@ -0,0 +1,55 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Doom
{
public class AcceptConversation : QuestConversation
{
public override object Message => 1050027;
public override void OnRead()
{
System.AddObjective(new CollectBonesObjective());
}
}
public class VanquishDaemonConversation : QuestConversation
{
public override object Message => 1050021;
public override void OnRead()
{
Victoria victoria = ((TheSummoningQuest)System).Victoria;
if (victoria == null)
{
System.From.SendMessage("Internal error: unable to find Victoria. Quest unable to continue.");
System.Cancel();
}
else
{
SummoningAltar altar = victoria.Altar;
if (altar == null)
{
System.From.SendMessage("Internal error: unable to find summoning altar. Quest unable to continue.");
System.Cancel();
}
else if (altar.Daemon == null || !altar.Daemon.Alive)
{
BoneDemon daemon = new BoneDemon();
daemon.MoveToWorld(altar.Location, altar.Map);
altar.Daemon = daemon;
System.AddObjective(new VanquishDaemonObjective(daemon));
}
else
{
victoria.SayTo(System.From, "The devourer has already been summoned.");
((TheSummoningQuest)System).WaitForSummon = true;
}
}
}
}
}

View file

@ -0,0 +1,119 @@
using System;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Doom
{
public class BellOfTheDead : Item
{
[Constructible]
public BellOfTheDead() : base(0x91A)
{
Hue = 0x835;
Movable = false;
}
public BellOfTheDead(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1050018; // bell of the dead
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public Chyloth Chyloth{ get; set; }
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public SkeletalDragon Dragon{ get; set; }
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public bool Summoning{ get; set; }
public override void OnDoubleClick(Mobile from)
{
if (from.InRange(GetWorldLocation(), 2))
BeginSummon(from);
else
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
}
public virtual void BeginSummon(Mobile from)
{
if (Chyloth?.Deleted == false)
{
from.SendLocalizedMessage(
1050010); // The ferry man has already been summoned. There is no need to ring for him again.
}
else if (Dragon?.Deleted == false)
{
from.SendLocalizedMessage(
1050017); // The ferryman has recently been summoned already. You decide against ringing the bell again so soon.
}
else if (!Summoning)
{
Summoning = true;
Effects.PlaySound(GetWorldLocation(), Map, 0x100);
Timer.DelayCall(TimeSpan.FromSeconds(8.0), () => EndSummon(from));
}
}
public virtual void EndSummon(Mobile from)
{
if (Chyloth?.Deleted == false)
{
from.SendLocalizedMessage(
1050010); // The ferry man has already been summoned. There is no need to ring for him again.
}
else if (Dragon?.Deleted == false)
{
from.SendLocalizedMessage(
1050017); // The ferryman has recently been summoned already. You decide against ringing the bell again so soon.
}
else if (Summoning)
{
Summoning = false;
Point3D loc = GetWorldLocation();
loc.Z -= 16;
Effects.SendLocationParticles(EffectItem.Create(loc, Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 0, 0,
2023, 0);
Effects.PlaySound(loc, Map, 0x1FE);
Chyloth = new Chyloth { Direction = (Direction)(7 & (4 + (int)from.GetDirectionTo(loc))) };
Chyloth.MoveToWorld(loc, Map);
Chyloth.Bell = this;
Chyloth.AngryAt = from;
Chyloth.BeginGiveWarning();
Chyloth.BeginRemove(TimeSpan.FromSeconds(40.0));
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(Chyloth);
writer.Write(Dragon);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Chyloth = reader.ReadMobile() as Chyloth;
Dragon = reader.ReadMobile() as SkeletalDragon;
Chyloth?.Delete();
}
}
}

View file

@ -0,0 +1,30 @@
namespace Server.Engines.Quests.Doom
{
public class ChylothShroud : Item
{
[Constructible]
public ChylothShroud() : base(0x204E)
{
Hue = 0x846;
Layer = Layer.OuterTorso;
}
public ChylothShroud(Serial serial) : base(serial)
{
}
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,33 @@
using Server.Items;
namespace Server.Engines.Quests.Doom
{
public class ChylothStaff : BlackStaff
{
[Constructible]
public ChylothStaff()
{
Hue = 0x482;
}
public ChylothStaff(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1041111; // a magic staff
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,33 @@
namespace Server.Engines.Quests.Doom
{
public class GoldenSkull : Item
{
[Constructible]
public GoldenSkull() : base(Utility.Random(0x1AE2, 3))
{
Weight = 1.0;
Hue = 0x8A5;
LootType = LootType.Blessed;
}
public GoldenSkull(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1061619; // a golden skull
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,34 @@
namespace Server.Engines.Quests.Doom
{
public class GrandGrimoire : Item
{
[Constructible]
public GrandGrimoire() : base(0xEFA)
{
Weight = 1.0;
Hue = 0x835;
Layer = Layer.OneHanded;
LootType = LootType.Blessed;
}
public GrandGrimoire(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1060801; // The Grand Grimoire
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,62 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Doom
{
public class SummoningAltar : AbbatoirAddon
{
private BoneDemon m_Daemon;
[Constructible]
public SummoningAltar()
{
}
public SummoningAltar(Serial serial) : base(serial)
{
}
public BoneDemon Daemon
{
get => m_Daemon;
set
{
m_Daemon = value;
CheckDaemon();
}
}
public void CheckDaemon()
{
if (m_Daemon == null || !m_Daemon.Alive)
{
m_Daemon = null;
Hue = 0;
}
else
{
Hue = 0x66D;
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(m_Daemon);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Daemon = reader.ReadMobile() as BoneDemon;
CheckDaemon();
}
}
}

Some files were not shown because too many files have changed in this diff Show more