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,291 @@
namespace Server.Engines.Quests.Hag
{
public class DontOfferConversation : QuestConversation
{
public override object Message => 1055000;
public override bool Logged => false;
}
public class AcceptConversation : QuestConversation
{
public override object Message => 1055002;
public override void OnRead()
{
System.AddObjective(new FindApprenticeObjective(true));
}
}
public class HagDuringCorpseSearchConversation : QuestConversation
{
public override object Message => 1055003;
public override bool Logged => false;
}
public class ApprenticeCorpseConversation : QuestConversation
{
public override object Message => 1055004;
public override void OnRead()
{
System.AddObjective(new FindGrizeldaAboutMurderObjective());
}
}
public class MurderConversation : QuestConversation
{
public override object Message => 1055005;
public override void OnRead()
{
System.AddObjective(new KillImpsObjective(true));
}
}
public class HagDuringImpSearchConversation : QuestConversation
{
public override object Message => 1055006;
public override bool Logged => false;
}
public class ImpDeathConversation : QuestConversation
{
private Point3D m_ImpLocation;
public ImpDeathConversation(Point3D impLocation)
{
m_ImpLocation = impLocation;
}
public ImpDeathConversation()
{
}
public override object Message => 1055007;
public override void OnRead()
{
System.AddObjective(new FindZeefzorpulObjective(m_ImpLocation));
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_ImpLocation = reader.ReadPoint3D();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_ImpLocation);
}
}
public class ZeefzorpulConversation : QuestConversation
{
public override object Message => 1055008;
public override void OnRead()
{
System.AddObjective(new ReturnRecipeObjective());
}
}
public class RecipeConversation : QuestConversation
{
public override object Message => 1055009;
public override void OnRead()
{
System.AddObjective(new FindIngredientObjective(new Ingredient[0]));
}
}
public class HagDuringIngredientsConversation : QuestConversation
{
public override object Message => 1055012;
public override bool Logged => false;
}
public class BlackheartFirstConversation : QuestConversation
{
public override object Message => 1055010;
public override void OnRead()
{
FindIngredientObjective obj = System.FindObjective<FindIngredientObjective>();
if (obj != null)
System.AddObjective(new FindIngredientObjective(obj.Ingredients, true));
}
}
public class BlackheartNoPirateConversation : QuestConversation
{
private bool m_Drunken;
private bool m_Tricorne;
public BlackheartNoPirateConversation(bool tricorne, bool drunken)
{
m_Tricorne = tricorne;
m_Drunken = drunken;
}
public BlackheartNoPirateConversation()
{
}
public override object Message
{
get
{
if (m_Tricorne)
{
if (m_Drunken) return 1055059;
/* <I>Captain Blackheart looks up from polishing his cutlass, glaring at
* you with red-rimmed eyes.</I><BR><BR>
*
* Well, well. Lookit the wee little deck swabby. Aren't ye a cute lil'
* lassy? Don't ye look just fancy? Ye think yer ready te join me pirate
* crew? Ye think I should offer ye some've me special Blackheart brew?<BR><BR>
*
* I'll make ye walk the plank, I will! We'll see how sweet n' darlin' ye
* look when the sea serpents get at ye and rip ye te threads! Won't that be
* a pretty picture, eh?<BR><BR>
*
* Ye don't have the stomach fer the pirate life, that's plain enough te me. Ye
* prance around here like a wee lil' princess, ye do. If ye want to join my
* crew ye can't just look tha part - ye have to have the stomach fer it, filled
* up with rotgut until ye can't see straight. I don't drink with just any ol'
* landlubber! Ye'd best prove yer mettle before ye talk te me again!<BR><BR>
*
* <I>The drunken pirate captain leans back in his chair, taking another gulp of
* his drink before he starts in on another bawdy pirate song.</I>
*/
return 1055057;
}
if (m_Drunken) return 1055056;
/* <I>Captain Blackheart looks up from his drink, almost tipping over
* his chair as he looks you up and down.</I><BR><BR>
*
* You again? I thought I told ye te get lost? Go on with ye! Ye ain't
* no pirate - yer not even fit te clean the barnacles off me rear end!
* Don't ye come back babbling te me for any of me Blackheart Whiskey until
* ye look and act like a true pirate!<BR><BR>
*
* Now shove off, sewer rat - I've got drinkin' te do!<BR><BR>
*
* <I>The inebriated pirate bolts back another mug of ale and brushes you
* off with a wave of his hand.</I>
*/
return 1055058;
}
}
public override bool Logged => false;
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_Tricorne = reader.ReadBool();
m_Drunken = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_Tricorne);
writer.Write(m_Drunken);
}
}
public class BlackheartPirateConversation : QuestConversation
{
private bool m_FirstMet;
public BlackheartPirateConversation(bool firstMet)
{
m_FirstMet = firstMet;
}
public BlackheartPirateConversation()
{
}
public override object Message
{
get
{
if (m_FirstMet) return 1055054;
/* <I>The drunken pirate, Captain Blackheart, looks up from his bottle
* of whiskey with a pleased expression.</I><BR><BR>
*
* Well looky here! I didn't think a landlubber like yourself had the pirate
* blood in ye! But look at that! You certainly look the part now! Sure
* you can still keep on your feet? Har!<BR><BR>
*
* Avast ye, ye loveable pirate! Ye deserve a belt of better brew than the slop
* ye've been drinking, and I've just the thing.<BR><BR>
*
* I call it Captain Blackheart's Whiskey, and it'll give ye hairs on yer chest,
* that's for sure. Why, a keg of this stuff once spilled on my ship, and it ate
* a hole right through the deck!<BR><BR>
*
* Go on, drink up, or use it to clean the rust off your cutlass - it's the best
* brew, either way!<BR><BR>
*
* <I>Captain Blackheart hands you a jug of his famous Whiskey. You think it best
* to return it to the Hag, rather than drink any of the noxious swill.</I>
*/
return 1055011;
}
}
public override void OnRead()
{
System.FindObjective<FindIngredientObjective>()?.NextStep();
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_FirstMet = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_FirstMet);
}
}
public class EndConversation : QuestConversation
{
public override object Message => 1055013;
public override void OnRead()
{
System.Complete();
}
}
public class RecentlyFinishedConversation : QuestConversation
{
public override object Message => 1055064;
public override bool Logged => false;
}
}

View file

@ -0,0 +1,106 @@
using System;
using Server.Mobiles;
namespace Server.Engines.Quests.Hag
{
public enum Ingredient
{
SheepLiver,
RabbitsFoot,
MongbatWing,
ChickenGizzard,
RatTail,
FrogsLeg,
DeerHeart,
LizardTongue,
SlimeOoze,
SpiritEssence,
SwampWater,
RedMushrooms,
Bones,
StarChart,
Whiskey
}
public class IngredientInfo
{
private static IngredientInfo[] m_Table =
{
// sheep liver
new IngredientInfo(1055020, 5, typeof(Sheep)),
// rabbit's foot
new IngredientInfo(1055021, 5, typeof(Rabbit), typeof(JackRabbit)),
// mongbat wing
new IngredientInfo(1055022, 5, typeof(Mongbat), typeof(GreaterMongbat)),
// chicken gizzard
new IngredientInfo(1055023, 5, typeof(Chicken)),
// rat tail
new IngredientInfo(1055024, 5, typeof(Rat), typeof(GiantRat), typeof(SewerRat)),
// frog's leg
new IngredientInfo(1055025, 5, typeof(BullFrog)),
// deer heart
new IngredientInfo(1055026, 5, typeof(Hind), typeof(GreatHart)),
// lizard tongue
new IngredientInfo(1055027, 5, typeof(LavaLizard), typeof(Lizardman)),
// slime ooze
new IngredientInfo(1055028, 5, typeof(Slime)),
// spirit essence
new IngredientInfo(1055029, 5, typeof(Ghoul), typeof(Spectre), typeof(Shade), typeof(Wraith), typeof(Bogle)),
// Swamp Water
new IngredientInfo(1055030, 1),
// Freshly Cut Red Mushrooms
new IngredientInfo(1055031, 1),
// Bones Buried In Hallowed Ground
new IngredientInfo(1055032, 1),
// Star Chart
new IngredientInfo(1055033, 1),
// Captain Blackheart's Whiskey
new IngredientInfo(1055034, 1)
};
private IngredientInfo(int name, int quantity, params Type[] creatures)
{
Name = name;
Creatures = creatures;
Quantity = quantity;
}
public int Name{ get; }
public Type[] Creatures{ get; }
public int Quantity{ get; }
public static IngredientInfo Get(Ingredient ingredient)
{
int index = (int)ingredient;
if (index >= 0 && index < m_Table.Length)
return m_Table[index];
return m_Table[0];
}
public static Ingredient RandomIngredient(Ingredient[] oldIngredients)
{
int length = m_Table.Length - oldIngredients.Length;
Ingredient[] ingredients = new Ingredient[length];
for (int i = 0, n = 0; i < m_Table.Length && n < ingredients.Length; i++)
{
Ingredient currIngredient = (Ingredient)i;
bool found = false;
for (int j = 0; !found && j < oldIngredients.Length; j++)
if (oldIngredients[j] == currIngredient)
found = true;
if (!found)
ingredients[n++] = currIngredient;
}
int index = Utility.Random(ingredients.Length);
return ingredients[index];
}
}
}

View file

@ -0,0 +1,31 @@
namespace Server.Items
{
public class Cauldron : Item
{
[Constructible]
public Cauldron() : base(0x9ED)
{
Weight = 1.0;
}
public Cauldron(Serial serial) : base(serial)
{
}
public override string DefaultName => "a cauldron";
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,102 @@
using System.Collections.Generic;
using Server.Items;
using Server.Misc;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Hag
{
public class HagApprenticeCorpse : Corpse
{
[Constructible]
public HagApprenticeCorpse() : base(GetOwner(), GetEquipment())
{
Direction = Direction.South;
foreach (Item item in EquipItems)
DropItem(item);
}
public HagApprenticeCorpse(Serial serial) : base(serial)
{
}
// TODO: What is this? Why are we creating a mobile and deleting it?
private static Mobile GetOwner()
{
Mobile apprentice = new Mobile();
apprentice.Hue = Race.Human.RandomSkinHue();
apprentice.Female = false;
apprentice.Body = 0x190;
apprentice.Delete();
return apprentice;
}
private static List<Item> GetEquipment()
{
return new List<Item>();
}
public override void AddNameProperty(ObjectPropertyList list)
{
list.Add("a charred corpse");
}
public override void OnSingleClick(Mobile from)
{
int hue = Notoriety.GetHue(NotorietyHandlers.CorpseNotoriety(from, this));
from.Send(new AsciiMessage(Serial, ItemID, MessageType.Label, hue, 3, "", "a charred corpse"));
}
public override void Open(Mobile from, bool checkSelfLoot)
{
if (!from.InRange(GetWorldLocation(), 2))
return;
if (from is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is WitchApprenticeQuest)
{
FindApprenticeObjective obj = qs.FindObjective<FindApprenticeObjective>();
if (obj?.Completed == false)
{
if (obj.Corpse == this)
{
obj.Complete();
Delete();
}
else
{
SendLocalizedMessageTo(from,
1055047); // You examine the corpse, but it doesn't fit the description of the particular apprentice the Hag tasked you with finding.
}
return;
}
}
}
SendLocalizedMessageTo(from, 1055048); // You examine the corpse, but find nothing of interest.
}
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,36 @@
namespace Server.Items
{
public class HagCauldron : BaseAddon
{
[Constructible]
public HagCauldron()
{
AddonComponent pot;
pot = new AddonComponent(2420);
AddComponent(pot, 0, 0, 0); //pot w/ support
AddonComponent fire;
fire = new AddonComponent(4012); //fire pit
fire.Light = LightType.Circle150;
AddComponent(fire, 0, 0, 0);
}
public HagCauldron(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,73 @@
using System;
namespace Server.Items
{
public class HagStew : BaseAddon
{
[Constructible]
public HagStew()
{
AddonComponent stew;
stew = new AddonComponent(2416);
stew.Name = "stew";
stew.Visible = true;
AddComponent(stew, 0, 0, -7); //stew
}
public HagStew(Serial serial) : base(serial)
{
}
public override void OnComponentUsed(AddonComponent stew, Mobile from)
{
if (!from.InRange(GetWorldLocation(), 2))
{
from.SendMessage("You are too far away.");
}
else
{
stew.Visible = false;
BreadLoaf hagstew = new BreadLoaf(); //this decides your fillrate
hagstew.Eat(from);
Timer m_timer = new ShowStew(stew);
m_timer.Start();
}
}
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 ShowStew : Timer
{
private AddonComponent stew;
public ShowStew(AddonComponent ac) : base(TimeSpan.FromSeconds(30))
{
stew = ac;
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
if (stew.Visible == false)
{
Stop();
stew.Visible = true;
}
}
}
}
}

View file

@ -0,0 +1,81 @@
namespace Server.Engines.Quests.Hag
{
public class HangoverCure : Item
{
[Constructible]
public HangoverCure() : base(0xE2B)
{
Weight = 1.0;
Hue = 0x2D;
Uses = 20;
}
public HangoverCure(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1055060; // Grizelda's Extra Strength Hangover Cure
[CommandProperty(AccessLevel.GameMaster)]
public int Uses{ get; set; }
public override void OnDoubleClick(Mobile from)
{
if (!IsChildOf(from.Backpack))
{
SendLocalizedMessageTo(from, 1042038); // You must have the object in your backpack to use it.
return;
}
if (Uses > 0)
{
from.PlaySound(0x2D6);
from.SendLocalizedMessage(501206); // An awful taste fills your mouth.
if (from.BAC > 0)
{
from.BAC = 0;
from.SendLocalizedMessage(501204); // You are now sober!
}
Uses--;
}
else
{
Delete();
from.SendLocalizedMessage(501201); // There wasn't enough left to have any effect.
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
writer.WriteEncodedInt(Uses);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 1:
{
Uses = reader.ReadEncodedInt();
break;
}
case 0:
{
Uses = 20;
break;
}
}
}
}
}

View file

@ -0,0 +1,73 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Hag
{
public class MagicFlute : Item
{
[Constructible]
public MagicFlute() : base(0x1421)
{
Hue = 0x8AB;
}
public MagicFlute(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1055051; // magic flute
public override void OnDoubleClick(Mobile from)
{
if (!IsChildOf(from.Backpack))
{
SendLocalizedMessageTo(from, 1042292); // You must have the object in your backpack to use it.
return;
}
from.PlaySound(0x3D);
if (from is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is WitchApprenticeQuest)
{
FindZeefzorpulObjective obj = qs.FindObjective<FindZeefzorpulObjective>();
if (obj?.Completed == false)
{
if (player.Map != Map.Trammel && player.Map != Map.Felucca || !player.InRange(obj.ImpLocation, 8))
{
player.SendLocalizedMessage(
1055053); // Nothing happens. Zeefzorpul must not be hiding in this area.
}
else if (player.InRange(obj.ImpLocation, 4))
{
Delete();
obj.Complete();
}
else
{
player.SendLocalizedMessage(
1055052); // The flute sparkles. Zeefzorpul must be in a good hiding place nearby.
}
}
}
}
}
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,31 @@
namespace Server.Engines.Quests.Hag
{
public class MoonfireBrew : Item
{
[Constructible]
public MoonfireBrew() : base(0xF04)
{
Weight = 1.0;
}
public MoonfireBrew(Serial serial) : base(serial)
{
}
public override int LabelNumber => 1055065; // a bottle of magical moonfire brew
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,116 @@
using System;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.Quests.Hag
{
public class Blackheart : BaseQuester
{
[Constructible]
public Blackheart() : base("the Drunken Pirate")
{
}
public Blackheart(Serial serial) : base(serial)
{
}
public override string DefaultName => "Captain Blackheart";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83EF;
Female = false;
Body = 0x190;
}
public override void InitOutfit()
{
AddItem(new FancyShirt());
AddItem(new LongPants(0x66D));
AddItem(new ThighBoots());
AddItem(new TricorneHat(0x1));
AddItem(new BodySash(0x66D));
LeatherGloves gloves = new LeatherGloves();
gloves.Hue = 0x66D;
AddItem(gloves);
FacialHairItemID = 0x203E; // Long Beard
FacialHairHue = 0x455;
Item sword = new Cutlass();
sword.Movable = false;
AddItem(sword);
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
Direction = GetDirectionTo(player);
Animate(33, 20, 1, true, false, 0);
QuestSystem qs = player.Quest;
if (qs is WitchApprenticeQuest)
{
FindIngredientObjective obj = qs.FindObjective<FindIngredientObjective>();
if (obj?.Completed == false && obj.Ingredient == Ingredient.Whiskey)
{
PlaySound(Utility.RandomBool() ? 0x42E : 0x43F);
Item hat = player.FindItemOnLayer(Layer.Helm);
bool tricorne = hat is TricorneHat;
if (tricorne && player.BAC >= 20)
{
obj.Complete();
qs.AddConversation(new BlackheartPirateConversation(!obj.BlackheartMet));
}
else if (!obj.BlackheartMet)
{
obj.Complete();
qs.AddConversation(new BlackheartFirstConversation());
}
else
{
qs.AddConversation(new BlackheartNoPirateConversation(tricorne, player.BAC > 0));
}
return;
}
}
PlaySound(0x42C);
SayTo(player, 1055041); // The drunken pirate shakes his fist at you and goes back to drinking.
}
private void Heave()
{
PublicOverheadMessage(MessageType.Regular, 0x3B2, 500849); // *hic*
Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(60, 180)), Heave);
}
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();
Heave();
}
}
}

View file

@ -0,0 +1,218 @@
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Hag
{
public class Grizelda : BaseQuester
{
[Constructible]
public Grizelda() : base("the Hag")
{
}
public Grizelda(Serial serial) : base(serial)
{
}
public override bool ClickTitle => true;
public override string DefaultName => "Grizelda";
public override void InitBody()
{
InitStats(100, 100, 25);
Hue = 0x83EA;
Female = true;
Body = 0x191;
}
public override void InitOutfit()
{
AddItem(new Robe(0x1));
AddItem(new Sandals());
AddItem(new WizardsHat(0x1));
AddItem(new GoldBracelet());
HairItemID = 0x203C;
Item staff = new GnarledStaff();
staff.Movable = false;
AddItem(staff);
}
public override void OnTalk(PlayerMobile player, bool contextMenu)
{
Direction = GetDirectionTo(player);
QuestSystem qs = player.Quest;
if (qs is WitchApprenticeQuest)
{
if (qs.IsObjectiveInProgress(typeof(FindApprenticeObjective)))
{
PlaySound(0x259);
PlaySound(0x206);
qs.AddConversation(new HagDuringCorpseSearchConversation());
}
else
{
QuestObjective obj = qs.FindObjective<FindGrizeldaAboutMurderObjective>();
if (obj?.Completed == false)
{
PlaySound(0x420);
PlaySound(0x20);
obj.Complete();
}
else if (qs.IsObjectiveInProgress(typeof(KillImpsObjective))
|| qs.IsObjectiveInProgress(typeof(FindZeefzorpulObjective)))
{
PlaySound(0x259);
PlaySound(0x206);
qs.AddConversation(new HagDuringImpSearchConversation());
}
else
{
obj = qs.FindObjective<ReturnRecipeObjective>();
if (obj?.Completed == false)
{
PlaySound(0x258);
PlaySound(0x41B);
obj.Complete();
}
else if (qs.IsObjectiveInProgress(typeof(FindIngredientObjective)))
{
PlaySound(0x259);
PlaySound(0x206);
qs.AddConversation(new HagDuringIngredientsConversation());
}
else
{
obj = qs.FindObjective<ReturnIngredientsObjective>();
if (obj?.Completed == false)
{
Container cont = GetNewContainer();
cont.DropItem(new BlackPearl(30));
cont.DropItem(new Bloodmoss(30));
cont.DropItem(new Garlic(30));
cont.DropItem(new Ginseng(30));
cont.DropItem(new MandrakeRoot(30));
cont.DropItem(new Nightshade(30));
cont.DropItem(new SulfurousAsh(30));
cont.DropItem(new SpidersSilk(30));
cont.DropItem(new Cauldron());
cont.DropItem(new MoonfireBrew());
cont.DropItem(new TreasureMap(Utility.RandomMinMax(1, 4), Map));
cont.DropItem(new Gold(2000, 2200));
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);
}
cont.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);
}
cont.DropItem(item);
}
if (player.BAC > 0)
cont.DropItem(new HangoverCure());
if (player.PlaceInBackpack(cont))
{
bool gainedPath = false;
if (VirtueHelper.Award(player, VirtueName.Sacrifice, 250, ref gainedPath)
) // TODO: Check amount on OSI.
player.SendLocalizedMessage(1054160); // You have gained in sacrifice.
PlaySound(0x253);
PlaySound(0x20);
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
{
QuestSystem newQuest = new WitchApprenticeQuest(player);
if (qs != null)
{
newQuest.AddConversation(new DontOfferConversation());
}
else if (QuestSystem.CanOfferQuest(player, typeof(WitchApprenticeQuest), out bool inRestartPeriod))
{
PlaySound(0x20);
PlaySound(0x206);
newQuest.SendOffer();
}
else if (inRestartPeriod)
{
PlaySound(0x259);
PlaySound(0x206);
newQuest.AddConversation(new RecentlyFinishedConversation());
}
}
}
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,47 @@
using Server.Mobiles;
namespace Server.Engines.Quests.Hag
{
public class Zeefzorpul : BaseQuester
{
public Zeefzorpul()
{
}
public Zeefzorpul(Serial serial) : base(serial)
{
}
public override string DefaultName => "Zeefzorpul";
public override void InitBody()
{
Body = 0x4A;
}
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();
Delete();
}
}
}

View file

@ -0,0 +1,438 @@
using System;
using Server.Items;
using Server.Mobiles;
namespace Server.Engines.Quests.Hag
{
public class FindApprenticeObjective : QuestObjective
{
private static Point3D[] m_CorpseLocations =
{
new Point3D(778, 1158, 0),
new Point3D(698, 1443, 0),
new Point3D(785, 1548, 0),
new Point3D(734, 1504, 0),
new Point3D(819, 1266, 0)
};
private Point3D m_CorpseLocation;
public FindApprenticeObjective(bool init)
{
if (init)
m_CorpseLocation = RandomCorpseLocation();
}
public FindApprenticeObjective()
{
}
public override object Message => 1055014;
public Corpse Corpse{ get; private set; }
private static Point3D RandomCorpseLocation()
{
int index = Utility.Random(m_CorpseLocations.Length);
return m_CorpseLocations[index];
}
public override void CheckProgress()
{
PlayerMobile player = System.From;
Map map = player.Map;
if (Corpse?.Deleted == false || map != Map.Trammel && map != Map.Felucca ||
!player.InRange(m_CorpseLocation, 8))
return;
Corpse = new HagApprenticeCorpse();
Corpse.MoveToWorld(m_CorpseLocation, map);
Effects.SendLocationEffect(m_CorpseLocation, map, 0x3728, 10, 10);
Effects.PlaySound(m_CorpseLocation, map, 0x1FE);
Mobile imp = new Zeefzorpul();
imp.MoveToWorld(m_CorpseLocation, map);
// * You see a strange imp stealing a scrap of paper from the bloodied corpse *
Corpse.SendLocalizedMessageTo(player, 1055049);
Timer.DelayCall(TimeSpan.FromSeconds(3.0), () => DeleteImp(imp));
}
private void DeleteImp(Mobile m)
{
if (m?.Deleted == false)
{
Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10, 10);
Effects.PlaySound(m.Location, m.Map, 0x1FE);
m.Delete();
}
}
public override void OnComplete()
{
System.AddConversation(new ApprenticeCorpseConversation());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
switch (version)
{
case 1:
{
m_CorpseLocation = reader.ReadPoint3D();
goto case 0;
}
case 0:
{
Corpse = (Corpse)reader.ReadItem();
break;
}
}
if (version == 0)
m_CorpseLocation = RandomCorpseLocation();
}
public override void ChildSerialize(GenericWriter writer)
{
if (Corpse?.Deleted == true)
Corpse = null;
writer.WriteEncodedInt(1); // version
writer.Write(m_CorpseLocation);
writer.Write(Corpse);
}
}
public class FindGrizeldaAboutMurderObjective : QuestObjective
{
public override object Message => 1055015;
public override void OnComplete()
{
System.AddConversation(new MurderConversation());
}
}
public class KillImpsObjective : QuestObjective
{
private int m_MaxProgress;
public KillImpsObjective(bool init)
{
if (init)
m_MaxProgress = Utility.RandomMinMax(1, 4);
}
public KillImpsObjective()
{
}
public override object Message => 1055016;
public override int MaxProgress => m_MaxProgress;
public override bool IgnoreYoungProtection(Mobile from)
{
if (!Completed && from is Imp)
return true;
return false;
}
public override void OnKill(BaseCreature creature, Container corpse)
{
if (creature is Imp)
CurProgress++;
}
public override void OnComplete()
{
PlayerMobile from = System.From;
Point3D loc = WitchApprenticeQuest.RandomZeefzorpulLocation();
MapItem mapItem = new MapItem();
mapItem.SetDisplay(loc.X - 200, loc.Y - 200, loc.X + 200, loc.Y + 200, 200, 200);
mapItem.AddWorldPin(loc.X, loc.Y);
from.AddToBackpack(mapItem);
from.AddToBackpack(new MagicFlute());
from.SendLocalizedMessage(1055061); // You have received a map and a magic flute.
System.AddConversation(new ImpDeathConversation(loc));
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
m_MaxProgress = reader.ReadInt();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(m_MaxProgress);
}
}
public class FindZeefzorpulObjective : QuestObjective
{
public FindZeefzorpulObjective(Point3D impLocation)
{
ImpLocation = impLocation;
}
public FindZeefzorpulObjective()
{
}
public override object Message => 1055017;
public Point3D ImpLocation{ get; private set; }
public override void OnComplete()
{
Mobile from = System.From;
Map map = from.Map;
Effects.SendLocationEffect(ImpLocation, map, 0x3728, 10, 10);
Effects.PlaySound(ImpLocation, map, 0x1FE);
Mobile imp = new Zeefzorpul();
imp.MoveToWorld(ImpLocation, map);
imp.Direction = imp.GetDirectionTo(from);
Timer.DelayCall(TimeSpan.FromSeconds(3.0), () => DeleteImp(imp));
}
private void DeleteImp(object imp)
{
if (imp is Mobile m && !m.Deleted)
{
Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10, 10);
Effects.PlaySound(m.Location, m.Map, 0x1FE);
m.Delete();
}
System.From.SendLocalizedMessage(1055062); // You have received the Magic Brew Recipe.
System.AddConversation(new ZeefzorpulConversation());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
ImpLocation = reader.ReadPoint3D();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(ImpLocation);
}
}
public class ReturnRecipeObjective : QuestObjective
{
public override object Message => 1055018;
public override void OnComplete()
{
System.AddConversation(new RecipeConversation());
}
}
public class FindIngredientObjective : QuestObjective
{
public FindIngredientObjective(Ingredient[] oldIngredients, bool blackheartMet = false)
{
if (!blackheartMet)
{
Ingredients = new Ingredient[oldIngredients.Length + 1];
for (int i = 0; i < oldIngredients.Length; i++)
Ingredients[i] = oldIngredients[i];
Ingredients[Ingredients.Length - 1] = IngredientInfo.RandomIngredient(oldIngredients);
}
else
{
Ingredients = new Ingredient[oldIngredients.Length];
for (int i = 0; i < oldIngredients.Length; i++)
Ingredients[i] = oldIngredients[i];
}
BlackheartMet = blackheartMet;
}
public FindIngredientObjective()
{
}
public override object Message
{
get
{
if (!BlackheartMet)
switch (Step)
{
case 1:
/* You must gather each ingredient on the Hag's list so that she can cook
* up her vile Magic Brew. The first ingredient is :
*/
return 1055019;
case 2:
/* You must gather each ingredient on the Hag's list so that she can cook
* up her vile Magic Brew. The second ingredient is :
*/
return 1055044;
default:
/* You must gather each ingredient on the Hag's list so that she can cook
* up her vile Magic Brew. The final ingredient is :
*/
return 1055045;
}
/* You are still attempting to obtain a jug of Captain Blackheart's
* Whiskey, but the drunkard Captain refuses to share his unique brew.
* You must prove your worthiness as a pirate to Blackheart before he'll
* offer you a jug.
*/
return 1055055;
}
}
public override int MaxProgress
{
get
{
IngredientInfo info = IngredientInfo.Get(Ingredient);
return info.Quantity;
}
}
public Ingredient[] Ingredients{ get; private set; }
public Ingredient Ingredient => Ingredients[Ingredients.Length - 1];
public int Step => Ingredients.Length;
public bool BlackheartMet{ get; private set; }
public override void RenderProgress(BaseQuestGump gump)
{
if (!Completed)
{
IngredientInfo info = IngredientInfo.Get(Ingredient);
gump.AddHtmlLocalized(70, 260, 270, 100, info.Name, BaseQuestGump.Blue);
gump.AddLabel(70, 280, 0x64, CurProgress.ToString());
gump.AddLabel(100, 280, 0x64, "/");
gump.AddLabel(130, 280, 0x64, info.Quantity.ToString());
}
else
{
base.RenderProgress(gump);
}
}
public override bool IgnoreYoungProtection(Mobile from)
{
if (Completed)
return false;
IngredientInfo info = IngredientInfo.Get(Ingredient);
Type fromType = from.GetType();
for (int i = 0; i < info.Creatures.Length; i++)
if (fromType == info.Creatures[i])
return true;
return false;
}
public override void OnKill(BaseCreature creature, Container corpse)
{
IngredientInfo info = IngredientInfo.Get(Ingredient);
for (int i = 0; i < info.Creatures.Length; i++)
{
Type type = info.Creatures[i];
if (creature.GetType() == type)
{
System.From.SendLocalizedMessage(1055043,
"#" + info.Name); // You gather a ~1_INGREDIENT_NAME~ from the corpse.
CurProgress++;
break;
}
}
}
public override void OnComplete()
{
if (Ingredient != Ingredient.Whiskey) NextStep();
}
public void NextStep()
{
System.From.SendLocalizedMessage(
1055046); // You have completed your current task on the Hag's Magic Brew Recipe list.
if (Step < 3)
System.AddObjective(new FindIngredientObjective(Ingredients));
else
System.AddObjective(new ReturnIngredientsObjective());
}
public override void ChildDeserialize(GenericReader reader)
{
int version = reader.ReadEncodedInt();
Ingredients = new Ingredient[reader.ReadEncodedInt()];
for (int i = 0; i < Ingredients.Length; i++)
Ingredients[i] = (Ingredient)reader.ReadEncodedInt();
BlackheartMet = reader.ReadBool();
}
public override void ChildSerialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.WriteEncodedInt(Ingredients.Length);
for (int i = 0; i < Ingredients.Length; i++)
writer.WriteEncodedInt((int)Ingredients[i]);
writer.Write(BlackheartMet);
}
}
public class ReturnIngredientsObjective : QuestObjective
{
public override object Message => 1055050;
public override void OnComplete()
{
System.AddConversation(new EndConversation());
}
}
}

View file

@ -0,0 +1,92 @@
using System;
using Server.Mobiles;
namespace Server.Engines.Quests.Hag
{
public class WitchApprenticeQuest : QuestSystem
{
private static Type[] m_TypeReferenceTable =
{
typeof(FindApprenticeObjective),
typeof(FindGrizeldaAboutMurderObjective),
typeof(KillImpsObjective),
typeof(FindZeefzorpulObjective),
typeof(ReturnRecipeObjective),
typeof(FindIngredientObjective),
typeof(ReturnIngredientsObjective),
typeof(DontOfferConversation),
typeof(AcceptConversation),
typeof(HagDuringCorpseSearchConversation),
typeof(ApprenticeCorpseConversation),
typeof(MurderConversation),
typeof(HagDuringImpSearchConversation),
typeof(ImpDeathConversation),
typeof(ZeefzorpulConversation),
typeof(RecipeConversation),
typeof(HagDuringIngredientsConversation),
typeof(BlackheartFirstConversation),
typeof(BlackheartNoPirateConversation),
typeof(BlackheartPirateConversation),
typeof(EndConversation),
typeof(RecentlyFinishedConversation)
};
private static Point3D[] m_ZeefzorpulLocations =
{
new Point3D(1226, 1573, 0),
new Point3D(1929, 1148, 0),
new Point3D(1366, 2723, 0),
new Point3D(1675, 2984, 0),
new Point3D(2177, 3367, 10),
new Point3D(1171, 3594, 0),
new Point3D(1010, 2667, 5),
new Point3D(1591, 2156, 5),
new Point3D(2592, 464, 60),
new Point3D(474, 1654, 0),
new Point3D(897, 2411, 0),
new Point3D(1471, 2505, 5),
new Point3D(1257, 872, 16),
new Point3D(2581, 1118, 0),
new Point3D(2513, 1102, 0),
new Point3D(1608, 3371, 0),
new Point3D(4687, 1179, 0),
new Point3D(3704, 2196, 20),
new Point3D(3346, 572, 0),
new Point3D(569, 1309, 0)
};
public WitchApprenticeQuest(PlayerMobile from) : base(from)
{
}
// Serialization
public WitchApprenticeQuest()
{
}
public override Type[] TypeReferenceTable => m_TypeReferenceTable;
public override object Name => 1055042;
public override object OfferMessage => 1055001;
public override TimeSpan RestartDelay => TimeSpan.FromMinutes(5.0);
public override bool IsTutorial => false;
public override int Picture => 0x15D3;
public override void Accept()
{
base.Accept();
AddConversation(new AcceptConversation());
}
public static Point3D RandomZeefzorpulLocation()
{
int index = Utility.Random(m_ZeefzorpulLocations.Length);
return m_ZeefzorpulLocations[index];
}
}
}