- Modified the quest system to allow non-BaseCreature quest givers, now requires IQuestGiver.

- Added base quest giver items, both timed and untimed.
- Added BatteredBucket and Lost and Found quest.
- Moved quester 'friendly names' to a class attribute. If left unspecified, the type name is used.
- Misc quest corrections.
- The bag of sending will now reject nontransferable items.
- Fixed quest items generating error messages when StackWith was attempted on them. (StackWith is not supposed to produce feedback.)
- Quest items can now be dropped onto the player's backpack.
This commit is contained in:
eos 2013-02-24 00:31:44 +00:00
parent 0fcd5821a5
commit 71a9e054de
36 changed files with 627 additions and 258 deletions

View file

@ -26,7 +26,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1075291; // (As you try to use the Spirit Bottle, the ghost snatches it out of your hand and smashes it on the rocks) Please, don't be frightened. I need your help!
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( SpiritBottle ), 1, "Spirit Bottle", typeof( Frederic ), "The Ghost of Frederic Smithson" ) );
Objectives.Add( new DeliverObjective( typeof( SpiritBottle ), 1, "Spirit Bottle", typeof( Frederic ) ) );
Rewards.Add( new DummyReward( 1075284 ) ); // Return the filled Spirit Bottle to Griswolt the Master Necromancer to receive a reward.
}
@ -55,7 +55,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1075342; // How may I help thee? You have the silk of a dread spider? Of course I can make you a bandage, but what happened to Frederic?
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new TimedDeliverObjective( TimeSpan.FromSeconds( 600 ), typeof( DreadSpiderSilk ), 1, "Dread Spider Silk", typeof( Leon ), "Leon" ) );
Objectives.Add( new TimedDeliverObjective( TimeSpan.FromSeconds( 600 ), typeof( DreadSpiderSilk ), 1, "Dread Spider Silk", typeof( Leon ) ) );
Rewards.Add( new DummyReward( 1075339 ) ); // Hurry! You must get the silk to Leon the Alchemist quickly, or it will crumble and become useless!
}
@ -84,7 +84,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1075348; // Sorry, Im not accepting commissions at the moment. What? You have the bandage I need from Leon? Thank you so much! But why didnt my son bring this to me himself? . . . Oh, no! You can't be serious! *sag* My Freddie, my son! Thank you for carrying out his last wish. Here -- I made this for my son, to give to him when he became a journeyman. I want you to have it.
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( AlchemistsBandage ), 1, "Alchemist's Bandage", typeof( Andros ), "Andros" ) );
Objectives.Add( new DeliverObjective( typeof( AlchemistsBandage ), 1, "Alchemist's Bandage", typeof( Andros ) ) );
Rewards.Add( new ItemReward( 1075345, typeof( AndrosGratitude ) ) ); // Andros Gratitude
}
@ -150,6 +150,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "The Ghost of Frederic Smithson" )]
public class Frederic : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -83,6 +83,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Mobiles
[QuesterName( "Kia (Bedlam)" )]
public class Kia : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -126,6 +127,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Emerillo (Bedlam)" )]
public class Emerillo : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -23,7 +23,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074968; // My friend, Iosep, is a weaponsmith in Jhelom. If anyone can help us, he can!
CompletionMessage = 1074991; // Greetings. What have you there? Ah, a sample from a poisonous tree, you say? My friend Jamal sent you? Well, let me see that then, and we'll get to work.
Objectives.Add( new DeliverObjective( typeof( TaintedTreeSample ), 1, "tainted tree sample", typeof( Iosep ), "Iosep (Jhelom)" ) );
Objectives.Add( new DeliverObjective( typeof( TaintedTreeSample ), 1, "tainted tree sample", typeof( Iosep ) ) );
Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove.
}
@ -126,7 +126,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074972; // I'm sure Jamal is eager to get this information. He's probably still hanging around near that big old blighted tree.
CompletionMessage = 1074995; // Heya! You're back. Was Iosep able to help? Let me see what he's sent.
Objectives.Add( new DeliverObjective( typeof( SealedNotesForJamal ), 1, "sealed note for Jamal", typeof( Jamal ), "Jamal (near Blighted Grove)" ) );
Objectives.Add( new DeliverObjective( typeof( SealedNotesForJamal ), 1, "sealed note for Jamal", typeof( Jamal ) ) );
Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove.
}
@ -175,6 +175,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Mobiles
[QuesterName( "Jamal (near Blighted Grove)" )]
public class Jamal : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -218,6 +219,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Iosep (Jhelom)" )]
public class Iosep : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -26,7 +26,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1075326; // What is this you give me? A basin of water?
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( BasinOfCrystalClearWater ), 1, 1075303, typeof( SkeletonOfSzandor ), "Szandor" ) );
Objectives.Add( new DeliverObjective( typeof( BasinOfCrystalClearWater ), 1, "Basin of Crystal Clear Water", typeof( SkeletonOfSzandor ) ) );
Rewards.Add( new DummyReward( 1075323 ) ); // Aurelia's gratitude.
}
@ -55,9 +55,9 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1075332; // Thank goodness! Now we can honor my father for the great man he was while he lived, rather than the horror he became.
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( BasinOfCrystalClearWater ), 1, 1075303, typeof( Aurelia ), "Aurelia" ) );
Objectives.Add( new DeliverObjective( typeof( BasinOfCrystalClearWater ), 1, "Basin of Crystal Clear Water", typeof( Aurelia ) ) );
Rewards.Add( new ItemReward( 1075304, typeof( MirrorOfPurification ) ) );
Rewards.Add( new ItemReward( 1075304, typeof( MirrorOfPurification ) ) ); // Mirror of Purification
}
public override void Generate()
@ -98,7 +98,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074460; // If I knew where my cousin was, I'd make the delivery myself.
CompletionMessage = 1074461; // Oh, hello there. What do you have for me?
Objectives.Add( new DeliverObjective( typeof( SpecialTreatForDrithen ), 1, "treat for Drithen", typeof( Drithen ), "Drithen (Umbra)" ) );
Objectives.Add( new DeliverObjective( typeof( SpecialTreatForDrithen ), 1, "treat for Drithen", typeof( Drithen ) ) );
Rewards.Add( ItemReward.BagOfTreasure );
}
@ -157,6 +157,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Szandor" )]
public class SkeletonOfSzandor : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -1110,7 +1110,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1073948; // I will be in your debt if you bring me kilts.
CompletionMessage = 1073974; // I say truly - that is a magnificent garment! You have more than earned a reward.
Objectives.Add( new CollectObjective( 10, typeof( Kilt ), 1015281 ) ); // kilt
Objectives.Add( new CollectObjective( 10, typeof( Kilt ), 1025431 ) ); // kilt
Rewards.Add( ItemReward.TailorSatchel );
}
@ -1128,7 +1128,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1073949; // I will be in your debt if you bring me fancy shirts.
CompletionMessage = 1073973; // I appreciate your service. Now, see what elven hands can create.
Objectives.Add( new CollectObjective( 10, typeof( FancyShirt ), 1015272 ) ); // fancy shirt
Objectives.Add( new CollectObjective( 10, typeof( FancyShirt ), 1027933 ) ); // fancy shirt
Rewards.Add( ItemReward.TailorSatchel );
}
@ -1146,7 +1146,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1073951; // I will be in your debt if you bring me studded bustiers.
CompletionMessage = 1073976; // Truly, it is worse than I feared. Still, I appreciate your efforts on my behalf.
Objectives.Add( new CollectObjective( 10, typeof( FemaleStuddedChest ), 1015310 ) ); // studded bustier
Objectives.Add( new CollectObjective( 10, typeof( FemaleStuddedChest ), 1027180 ) ); // studded bustier
Rewards.Add( ItemReward.TailorSatchel );
}
@ -1236,7 +1236,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1073952; // I will be in your debt if you bring me tinker's tools.
CompletionMessage = 1073977; // Now, I shall see what an elf can invent!
Objectives.Add( new CollectObjective( 10, typeof( TinkerTools ), 1011218 ) ); // tinker's tools
Objectives.Add( new CollectObjective( 10, typeof( TinkerTools ), 1027868 ) ); // tinker's tools
Rewards.Add( ItemReward.TinkerSatchel );
}
@ -1438,7 +1438,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1073959; // I will be in your debt if you bring me broadswords.
CompletionMessage = 1073978; // Enjoy my thanks for your service.
Objectives.Add( new CollectObjective( 12, typeof( Broadsword ), 1015055 ) ); // broadsword
Objectives.Add( new CollectObjective( 12, typeof( Broadsword ), 1023934 ) ); // broadsword
Rewards.Add( ItemReward.BlacksmithSatchel );
}
@ -1474,7 +1474,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1073957; // I will be in your debt if you bring me bascinets.
CompletionMessage = 1073978; // Enjoy my thanks for your service.
Objectives.Add( new CollectObjective( 15, typeof( Bascinet ), 1015040 ) ); // bascinet
Objectives.Add( new CollectObjective( 15, typeof( Bascinet ), 1025132 ) ); // bascinet
Rewards.Add( ItemReward.BlacksmithSatchel );
}
@ -1821,6 +1821,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Mobiles
[QuesterName( "Saril (The Heartwood)" )]
public class Saril : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -1881,6 +1882,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Cailla (The Heartwood)" )]
public class Cailla : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -1942,6 +1944,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Tamm (The Heartwood)" )]
public class Tamm : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2001,6 +2004,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Landy (The Heartwood)" )]
public class Landy : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2061,6 +2065,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Elder Alejaha (The Heartwood)" )]
public class Alejaha : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2120,6 +2125,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Mielan (The Heartwood)" )]
public class Mielan : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2177,6 +2183,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Ciala (The Heartwood)" )]
public class Ciala : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2238,6 +2245,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Aniel (The Heartwood)" )]
public class Aniel : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2295,6 +2303,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Aulan (The Heartwood)" )]
public class Aulan : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2366,6 +2375,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Brinnae (The Heartwood)" )]
public class Brinnae : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2420,6 +2430,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Elder Caelas (The Heartwood)" )]
public class Caelas : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2477,6 +2488,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Clehin (The Heartwood)" )]
public class Clehin : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2603,6 +2615,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Salaenih (The Heartwood)" )]
public class Salaenih : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2680,6 +2693,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Vilo (The Heartwood)" )]
public class Vilo : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2741,6 +2755,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Tholef (The Heartwood)" )]
public class Tholef : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2804,6 +2819,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Tillanil (The Heartwood)" )]
public class Tillanil : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2860,6 +2876,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Waelian (The Heartwood)" )]
public class Waelian : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2923,6 +2940,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Sleen (The Heartwood)" )]
public class Sleen : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -2980,6 +2998,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Unoelil (The Heartwood)" )]
public class Unoelil : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -3036,6 +3055,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Anolly (The Heartwood)" )]
public class Anolly : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -3084,6 +3104,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Jusae (The Heartwood)" )]
public class Jusae : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -3150,6 +3171,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Cillitha (The Heartwood)" )]
public class Cillitha : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -3206,6 +3228,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Lohn (The Heartwood)" )]
public class Lohn : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -3269,6 +3292,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Olla (The Heartwood)" )]
public class Olla : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -3328,6 +3352,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Thallary (The Heartwood)" )]
public class Thallary : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -3386,6 +3411,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Ahie (The Heartwood)" )]
public class Ahie : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -4195,6 +4221,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Nillaen (The Heartwood)" )]
public class LorekeeperNillaen : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -4245,6 +4272,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Ryal (The Heartwood)" )]
public class LorekeeperRyal : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -4303,6 +4331,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Braen (The Heartwood)" )]
public class Braen : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -4356,6 +4385,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Elder Acob (The Heartwood)" )]
public class ElderAcob : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -243,6 +243,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Human To Elf Mobiles
[QuesterName( "Maul" )]
public class MaulTheBear : GrizzlyBear
{
public override bool IsInvulnerable { get { return true; } }
@ -569,7 +570,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1074523; // Hey, if you have cargo for me, you can start unloading over here.
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new TimedDeliverObjective( TimeSpan.FromHours( 1 ), typeof( CrateForSledge ), 5, "Crates for Sledge", typeof( Sledge ), "Sledge (Buc's Den)" ) );
Objectives.Add( new TimedDeliverObjective( TimeSpan.FromHours( 1 ), typeof( CrateForSledge ), 5, "Crates for Sledge", typeof( Sledge ) ) );
Rewards.Add( new DummyReward( 1074875 ) ); // Another step closer to becoming human.
}
@ -647,6 +648,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Elf To Human Mobiles
[QuesterName( "Sledge (Buc's Den)" )]
public class Sledge : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -697,6 +699,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Patricus (Vesper)" )]
public class Patricus : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -738,6 +741,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Belulah (Nujel'm)" )] // On OSI it's "Belulah (Nu'Jelm)" (incorrect spelling)
public class Belulah : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -26,7 +26,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1075397; // Didst thou find my ring? I thank thee very much! It is an old ring, and a gift from my husband. I was most distraught when I realized it was missing.
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( ReginasRing ), 1, "Regina's Ring", typeof( Regina ), "Regina" ) );
Objectives.Add( new DeliverObjective( typeof( ReginasRing ), 1, "Regina's Ring", typeof( Regina ) ) );
Rewards.Add( new DummyReward( 1075394 ) ); // Find the rings owner.
}
@ -55,7 +55,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1075403; // What? For me? Let me see . . . these sapphire earrings are for you, it says. Oh, she wants to offer me a job! This is the most wonderful thing that ever happened to me!
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( ReginasLetter ), 1, "Regina's Letter", typeof( Evan ), "Evan" ) );
Objectives.Add( new DeliverObjective( typeof( ReginasLetter ), 1, "Regina's Letter", typeof( Evan ) ) );
Rewards.Add( new ItemReward( 1075400, typeof( TransparentHeart ) ) ); // Transparent Heart
}

View file

@ -232,6 +232,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Jelrice (Ilshenar)" )]
public class Jelrice : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -281,6 +282,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Yorus (Ilshenar)" )]
public class Yorus : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -0,0 +1,70 @@
using System;
using Server;
using Server.Engines.MLQuests;
using Server.Engines.MLQuests.Items;
using Server.Engines.MLQuests.Objectives;
using Server.Engines.MLQuests.Rewards;
namespace Server.Engines.MLQuests.Definitions
{
// TODO: Assassination Contract, Evidence, Lost in Transit, Last Words
#region Quests
public class LostAndFound : MLQuest
{
public LostAndFound()
{
Activated = true;
Title = 1072370; // Lost and Found
Description = 1072589; // The battered, old bucket is inscribed with barely legible writing that indicates it belongs to someone named "Dallid". Maybe they'd pay for its return?
RefusalMessage = 1072590; // You're right, who cares if Dallid might pay for his battered old bucket back. This way you can carry it around with you!
InProgressMessage = 1072591; // Whoever this "Dallid" might be, he's probably looking for his bucket.
CompletionMessage = 1074580; // Is that my bucket? I had to ditch my favorite bucket when a group of ratmen jumped me!
Objectives.Add( new TimedDeliverObjective( TimeSpan.FromSeconds( 600 ), typeof( BatteredBucket ), 1, "battered bucket", typeof( Dallid ), false ) );
Rewards.Add( ItemReward.BagOfTrinkets );
}
}
#endregion
#region Items
public class BatteredBucket : TransientQuestGiverItem
{
// Original label, doesn't fit the expiration message well
//public override int LabelNumber { get { return 1073129; } } // A battered bucket.
public override string DefaultName { get { return "battered bucket"; } }
[Constructable]
public BatteredBucket()
: base( 0x2004, TimeSpan.FromMinutes( 10 ) )
{
LootType = LootType.Blessed;
}
public BatteredBucket( Serial serial )
: base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int)0 ); // version
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
}
}
#endregion
}

View file

@ -23,7 +23,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074643; // I can't pay a bounty if you don't bring bag the ears.
CompletionMessage = 1074644; // Here to collect on a bounty?
Objectives.Add( new CollectObjective( 20, typeof( SeveredElfEars ), "severed elf ears" ) );
Objectives.Add( new CollectObjective( 20, typeof( SeveredElfEars ), 1032590 ) ); // severed elf ears
Rewards.Add( ItemReward.BagOfTrinkets );
}
@ -40,6 +40,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Mobiles
[QuesterName( "Drithen (Umbra)" )]
public class Drithen : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -27,7 +27,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1074607; // Oh blast! Not another of those forms. I'm so sick of this endless paperwork.
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( TuitionReimbursementForm ), 1, "Tuition Reimbursement Form", typeof( Gorrow ), "Gorrow (Luna)" ) );
Objectives.Add( new DeliverObjective( typeof( TuitionReimbursementForm ), 1, "Tuition Reimbursement Form", typeof( Gorrow ) ) );
Rewards.Add( new DummyReward( 1074634 ) ); // Tuition Reimbursement
}
@ -85,7 +85,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1074622; // What? Hrmph. Gorrow signed your form did he? Let me see that. *squint*
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( SignedTuitionReimbursementForm ), 1, "Signed Tuition Reimbursement Form", typeof( Aernya ), "Aernya (Umbra)" ) );
Objectives.Add( new DeliverObjective( typeof( SignedTuitionReimbursementForm ), 1, "Signed Tuition Reimbursement Form", typeof( Aernya ) ) );
Rewards.Add( new DummyReward( 1074634 ) ); // Tuition Reimbursement
}
@ -106,7 +106,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1074628; // Made it through did you? Did you happen to see Red Death out there? Big horse, skeletal ... burning eyes? No? What's this? Forms? FORMS? I'm up to my eyebrows in ravenous out-of-control undead and you want a signature?
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( SignedTuitionReimbursementForm ), 1, "Signed Tuition Reimbursement Form", typeof( MasterGnosos ), "Master Gnosos (Bedlam)" ) );
Objectives.Add( new DeliverObjective( typeof( SignedTuitionReimbursementForm ), 1, "Signed Tuition Reimbursement Form", typeof( MasterGnosos ) ) );
Rewards.Add( new DummyReward( 1074634 ) ); // Tuition Reimbursement
}
@ -170,7 +170,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1074638; // *disinterested stare* What? Oh, you've gotten your form filled in. How nice. *glare* And I'd hoped you'd drop this charade before I was forced to rub your nose in it. *nasty smile* You're not even a student and as such, you're not eligible for a refund -- you've never paid tuition. For your services, Master Gnosos has recommended you receive pay. So here. Now go away.
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( CompletedTuitionReimbursementForm ), 1, "Completed Tuition Reimbursement Form", typeof( Aernya ), "Aernya (Umbra)" ) );
Objectives.Add( new DeliverObjective( typeof( CompletedTuitionReimbursementForm ), 1, "Completed Tuition Reimbursement Form", typeof( Aernya ) ) );
Rewards.Add( ItemReward.Strongbox );
}
@ -180,6 +180,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Mobiles
[QuesterName( "Aernya (Umbra)" )]
public class Aernya : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -225,6 +226,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Gorrow (Luna)" )]
public class Gorrow : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -277,6 +279,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Master Gnosos (Bedlam)" )]
public class MasterGnosos : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -123,7 +123,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1075515; // Come On! Whats that... a bucket? We need ten bucklers... not spitoons.
CompletionMessage = 1075516; // Thanks for the help. Here's something for ya to remember me by.
Objectives.Add( new CollectObjective( 10, typeof( Buckler ), 1015044 ) ); // buckler
Objectives.Add( new CollectObjective( 10, typeof( Buckler ), 1027027 ) ); // buckler
Rewards.Add( new ItemReward( 1074282, typeof( GervisSatchel ) ) ); // Craftsmans's Satchel
}
@ -148,7 +148,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1075532; // Hmmm… we need some more Ore. Try finding a mountain or cave, and give it a whack.
CompletionMessage = 1075533; // I see you found a good vien! Great! This will help get this order out on time. Good work!
Objectives.Add( new CollectObjective( 5, typeof( IronOre ), 1042853 ) ); // iron ore
Objectives.Add( new InternalObjective() );
Rewards.Add( new ItemReward( 1074282, typeof( MuggSatchel ) ) ); // Craftsmans's Satchel
}
@ -159,6 +159,20 @@ namespace Server.Engines.MLQuests.Definitions
PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Mugg" ), new Point3D( 3507, 2747, 0 ), Map.Trammel );
}
private class InternalObjective : CollectObjective
{
// Any type of ore is allowed
public InternalObjective()
: base( 5, typeof( BaseOre ), 1026585 ) // ore
{
}
public override bool CheckItem( Item item )
{
return ( item.ItemID == 6585 ); // Only large pieces count
}
}
}
public class ComfortableSeating : MLQuest
@ -173,7 +187,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1075509; // Is all going well? I look forward to the simple comforts in my very own home.
CompletionMessage = 1074720; // This is perfect!
Objectives.Add( new CollectObjective( 1, typeof( BambooChair ), 1044300 ) ); // straw chair
Objectives.Add( new CollectObjective( 1, typeof( BambooChair ), "straw chair" ) );
Rewards.Add( new ItemReward( 1074282, typeof( LowelSatchel ) ) ); // Craftsmans's Satchel
}
@ -223,7 +237,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
CompletionMessage = 1075536; // Wonderful! Tick tock, tick tock, soon all shall be well with grandfather's clock!
Objectives.Add( new CollectObjective( 5, typeof( ClockParts ), 1011205 ) ); // clock parts
Objectives.Add( new CollectObjective( 5, typeof( ClockParts ), 1024175 ) ); // clock parts
Rewards.Add( new ItemReward( 1074282, typeof( NibbetSatchel ) ) ); // Craftsmans's Satchel
}
@ -273,7 +287,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1075490; // Just remember you need to use your mortar and pestle while you have empty bottles and some black pearl. Refresh potions are what I need.
CompletionMessage = 1075491; // *glug* *glug* Ahh... Yes! Yes! That feels great! Those lizardmen will never know what hit 'em! Here, take this, I can get more from the lizards.
Objectives.Add( new CollectObjective( 10, typeof( RefreshPotion ), 1048029 ) ); // refresh potion
Objectives.Add( new CollectObjective( 10, typeof( RefreshPotion ), "refresh potions" ) );
Rewards.Add( new ItemReward( 1074282, typeof( SadrahSatchel ) ) ); // Craftsmans's Satchel
}
@ -506,6 +520,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
//[QuesterName( "Clarisse" )] // On OSI the gumps refer to her as this, different from actual name
public class Clairesse : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -140,7 +140,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire!
CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of!
Objectives.Add( new CollectObjective( 12, typeof( Broadsword ), 1015055 ) ); // broadsword
Objectives.Add( new CollectObjective( 12, typeof( Broadsword ), 1023934 ) ); // broadsword
Rewards.Add( ItemReward.BlacksmithSatchel );
}
@ -230,7 +230,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire!
CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of!
Objectives.Add( new CollectObjective( 10, typeof( TinkerTools ), 1011218 ) ); // tinker's tools
Objectives.Add( new CollectObjective( 10, typeof( TinkerTools ), 1027868 ) ); // tinker's tools
Rewards.Add( ItemReward.TinkerSatchel );
}
@ -264,7 +264,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire!
CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of!
Objectives.Add( new CollectObjective( 10, typeof( Kilt ), 1015281 ) ); // kilt
Objectives.Add( new CollectObjective( 10, typeof( Kilt ), 1025431 ) ); // kilt
Rewards.Add( ItemReward.TailorSatchel );
}
@ -282,7 +282,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire!
CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of!
Objectives.Add( new CollectObjective( 10, typeof( FancyShirt ), 1015272 ) ); // fancy shirt
Objectives.Add( new CollectObjective( 10, typeof( FancyShirt ), 1027933 ) ); // fancy shirt
Rewards.Add( ItemReward.TailorSatchel );
}
@ -300,7 +300,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire!
CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of!
Objectives.Add( new CollectObjective( 10, typeof( FemaleStuddedChest ), 1015310 ) ); // studded bustier
Objectives.Add( new CollectObjective( 10, typeof( FemaleStuddedChest ), 1027180 ) ); // studded bustier
Rewards.Add( ItemReward.TailorSatchel );
}
@ -623,7 +623,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1074579; // Yes, can I help you?
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( APersonalLetterAddressedToAhie ), 1, "letter", typeof( Ahie ), "Ahie (The Heartwood)" ) );
Objectives.Add( new DeliverObjective( typeof( APersonalLetterAddressedToAhie ), 1, "letter", typeof( Ahie ) ) );
Rewards.Add( ItemReward.BagOfTrinkets );
}
@ -639,7 +639,7 @@ namespace Server.Engines.MLQuests.Definitions
RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
InProgressMessage = 1073592; // The Brigands still plague us. Have you killed 20 of their number?<br>
Objectives.Add( new KillObjective( 20, new Type[] { typeof( Brigand ) }, "common brigands" ) );
Objectives.Add( new KillObjective( 20, new Type[] { typeof( Brigand ) }, 1074894 ) ); // Common brigands
Rewards.Add( ItemReward.BagOfTreasure );
}
@ -649,6 +649,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Mobiles
[QuesterName( "Beotham (Sanctuary)" )]
public class Beotham : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -711,6 +712,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Danoel (Sanctuary)" )]
public class Danoel : BaseCreature
{
// TODO: Add quests: Spring Cleaning
@ -769,6 +771,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Tallinin (Sanctuary)" )]
public class Tallinin : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -825,6 +828,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Tiana (Sanctuary)" )]
public class Tiana : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -892,6 +896,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Oolua (Sanctuary)" )]
public class LorekeeperOolua : BaseCreature
{
// TODO: Add quest Dreadhorn
@ -949,6 +954,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Rollarn (Sanctuary)" )]
public class LorekeeperRollarn : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -1012,6 +1018,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Dallid (Sanctuary)" )]
public class Dallid : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -1070,6 +1077,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Canir (Sanctuary)" )]
public class Canir : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -1172,6 +1180,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Elder Onallan (Sanctuary)" )]
public class ElderOnallan : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -328,7 +328,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074315; // Arielle wanders quite a bit, so I'm not sure exactly where to find her. I'm sure she's going to love your gift.
CompletionMessage = 1074319; // *giggle* Oooh! For me?
Objectives.Add( new DeliverObjective( typeof( GiftForArielle ), 1, "gift for Arielle", typeof( Arielle ), "Arielle" ) );
Objectives.Add( new DeliverObjective( typeof( GiftForArielle ), 1, "gift for Arielle", typeof( Arielle ) ) );
Rewards.Add( new DummyReward( 1074874 ) ); // The opportunity to prove yourself worthy of learning to Summon Fey. (Sufficient spellweaving skill is required to cast the spell)
}
@ -445,6 +445,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Mobiles
[QuesterName( "Aeluva (The Heartwood)" )]
public class Aeluva : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -503,6 +504,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Koole (Sanctuary)" )]
public class Koole : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -568,6 +570,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Synaeva (The Heartwood)" )]
public class Synaeva : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -627,6 +630,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Elder Brae (Sanctuary)" )]
public class ElderBrae : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -53,7 +53,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074547; // Braen is nearby, run and speak with him.
CompletionMessage = 1074549; // Yes? What do you want? I'm very busy.
Objectives.Add( new DeliverObjective( typeof( FragmentOfAMapDelivery ), 1, "fragment of a map", typeof( Braen ), "Braen (The Heartwood)" ) );
Objectives.Add( new DeliverObjective( typeof( FragmentOfAMapDelivery ), 1, "fragment of a map", typeof( Braen ) ) );
Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur.
}
@ -102,6 +102,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Mobiles
[QuesterName( "Broolol (The Heartwood)" )]
public class LorekeeperBroolol : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -55,7 +55,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1075372; // Im sorry, Im getting ready to be married. I dont have time to . . . whats that you say?
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( PortraitOfTheBride ), 1, "Portrait of the Bride", typeof( Thalia ), "Thalia (Nujel'm)" ) ); // OSI's description is "Bride"
Objectives.Add( new DeliverObjective( typeof( PortraitOfTheBride ), 1, "Portrait of the Bride", typeof( Thalia ) ) );
Rewards.Add( new DummyReward( 1075369 ) ); // The Artists gratitude.
}
@ -76,7 +76,7 @@ namespace Server.Engines.MLQuests.Definitions
CompletionMessage = 1075378; // She said what? She thinks what of me? I . . . I cant believe it! All this time, I never knew how she truly felt. Thank you, my friend. I believe now I will be able to paint once again. Here, take this bleach. I was going to use it to destroy all of my works. Perhaps you can find a better use for it now.
CompletionNotice = CompletionNoticeShort;
Objectives.Add( new DeliverObjective( typeof( BridesLetter ), 1, "Bride's Letter", typeof( Emilio ), "Emilio (Britain)" ) ); // OSI's description is "Artist"
Objectives.Add( new DeliverObjective( typeof( BridesLetter ), 1, "Bride's Letter", typeof( Emilio ) ) );
Rewards.Add( new ItemReward( 1075375, typeof( Bleach ) ) ); // Bleach
}
@ -94,6 +94,7 @@ namespace Server.Engines.MLQuests.Definitions
#region Mobiles
[QuesterName( "Emilio (Britain)" )] // OSI's description is "Artist", not very helpful
public class Emilio : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }
@ -141,6 +142,7 @@ namespace Server.Engines.MLQuests.Definitions
}
}
[QuesterName( "Thalia (Nujel'm)" )] // OSI's description is "Bride", not very helpful
public class Thalia : BaseCreature
{
public override bool IsInvulnerable { get { return true; } }

View file

@ -43,7 +43,7 @@ namespace Server.Engines.MLQuests.Definitions
InProgressMessage = 1074548; // Canir is nearby, run and speak with her.
CompletionMessage = 1074549; // Yes? What do you want? I'm very busy.
Objectives.Add( new DeliverObjective( typeof( FragmentOfAMapDelivery ), 1, "fragment of a map", typeof( Canir ), "Canir (Sanctuary)" ) );
Objectives.Add( new DeliverObjective( typeof( FragmentOfAMapDelivery ), 1, "fragment of a map", typeof( Canir ) ) );
Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur.
}

View file

@ -10,9 +10,9 @@ namespace Server.Engines.MLQuests.Gumps
public class QuestOfferGump : BaseQuestGump
{
private MLQuest m_Quest;
private BaseCreature m_Quester;
private IQuestGiver m_Quester;
public QuestOfferGump( MLQuest quest, BaseCreature quester, PlayerMobile pm )
public QuestOfferGump( MLQuest quest, IQuestGiver quester, PlayerMobile pm )
: base( 1049010 ) // Quest Offer
{
m_Quest = quest;

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using Server;
namespace Server.Engines.MLQuests
{
public interface IQuestGiver
{
List<MLQuest> MLQuests { get; }
Serial Serial { get; }
bool Deleted { get; }
Type GetType();
}
}

View file

@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Engines.MLQuests.Items
{
public abstract class QuestGiverItem : Item, IQuestGiver
{
private List<MLQuest> m_MLQuests;
public List<MLQuest> MLQuests
{
get
{
if ( m_MLQuests == null )
{
m_MLQuests = MLQuestSystem.FindQuestList( GetType() );
if ( m_MLQuests == null )
m_MLQuests = MLQuestSystem.EmptyList;
}
return m_MLQuests;
}
}
public bool CanGiveMLQuest { get { return ( MLQuests.Count != 0 ); } }
public QuestGiverItem( int itemId )
: base( itemId )
{
}
public override bool Nontransferable { get { return true; } }
public override void AddNameProperties( ObjectPropertyList list )
{
base.AddNameProperties( list );
AddQuestItemProperty( list );
if ( CanGiveMLQuest )
list.Add( 1072269 ); // Quest Giver
}
public override void OnDoubleClick( Mobile from )
{
if ( !from.InRange( GetWorldLocation(), 2 ) )
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
else if ( !IsChildOf( from.Backpack ) )
from.SendLocalizedMessage( 1042593 ); // That is not in your backpack.
else if ( MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile )
MLQuestSystem.OnDoubleClick( this, (PlayerMobile)from );
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if ( MLQuestSystem.Enabled )
MLQuestSystem.HandleDeletion( this );
}
public QuestGiverItem( Serial serial )
: base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int)0 ); // version
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
}
}
public abstract class TransientQuestGiverItem : TransientItem, IQuestGiver
{
private List<MLQuest> m_MLQuests;
public List<MLQuest> MLQuests
{
get
{
if ( m_MLQuests == null )
{
m_MLQuests = MLQuestSystem.FindQuestList( GetType() );
if ( m_MLQuests == null )
m_MLQuests = MLQuestSystem.EmptyList;
}
return m_MLQuests;
}
}
public bool CanGiveMLQuest { get { return ( MLQuests.Count != 0 ); } }
public TransientQuestGiverItem( int itemId, TimeSpan lifeSpan )
: base( itemId, lifeSpan )
{
}
public override bool Nontransferable { get { return true; } }
public override void HandleInvalidTransfer( Mobile from )
{
}
public override void AddNameProperties( ObjectPropertyList list )
{
base.AddNameProperties( list );
AddQuestItemProperty( list );
if ( CanGiveMLQuest )
list.Add( 1072269 ); // Quest Giver
}
public override void OnDoubleClick( Mobile from )
{
if ( !from.InRange( GetWorldLocation(), 2 ) )
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
else if ( !IsChildOf( from.Backpack ) )
from.SendLocalizedMessage( 1042593 ); // That is not in your backpack.
else if ( MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile )
MLQuestSystem.OnDoubleClick( this, (PlayerMobile)from );
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if ( MLQuestSystem.Enabled )
MLQuestSystem.HandleDeletion( this );
}
public TransientQuestGiverItem( Serial serial )
: base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int)0 ); // version
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
}
}
}

View file

@ -35,7 +35,6 @@ namespace Server.Engines.MLQuests
private List<BaseObjective> m_Objectives;
private ObjectiveType m_ObjectiveType;
private List<BaseReward> m_Rewards;
private List<BaseCreature> m_Questers;
private List<MLQuestInstance> m_Instances;
@ -74,12 +73,6 @@ namespace Server.Engines.MLQuests
set { m_Rewards = value; }
}
public List<BaseCreature> Questers
{
get { return m_Questers; }
set { m_Questers = value; }
}
public List<MLQuestInstance> Instances
{
get { return m_Instances; }
@ -152,36 +145,11 @@ namespace Server.Engines.MLQuests
m_Rewards = new List<BaseReward>();
m_CompletionNotice = CompletionNoticeDefault;
m_Questers = new List<BaseCreature>();
m_Instances = new List<MLQuestInstance>();
m_SaveEnabled = true;
}
public void Register( BaseCreature quester )
{
if ( MLQuestSystem.Debug )
Console.WriteLine( "INFO: Registering quester: {0} => {1}", quester.Serial, GetType().Name );
m_Questers.Add( quester );
}
public void Unregister( BaseCreature quester )
{
if ( MLQuestSystem.Debug )
Console.WriteLine( "INFO: Unregistering quester: {0} => {1}", quester.Serial, GetType().Name );
m_Questers.Remove( quester );
for ( int i = m_Instances.Count - 1; i >= 0; --i )
{
MLQuestInstance instance = m_Instances[i];
if ( instance.Quester == quester )
instance.OnQuesterDeleted();
}
}
public virtual void Generate()
{
if ( MLQuestSystem.Debug )
@ -229,19 +197,19 @@ namespace Server.Engines.MLQuests
#endregion
public MLQuestInstance CreateInstance( BaseCreature quester, PlayerMobile pm )
public MLQuestInstance CreateInstance( IQuestGiver quester, PlayerMobile pm )
{
return new MLQuestInstance( this, quester, pm );
}
public bool CanOffer( BaseCreature quester, PlayerMobile pm, bool message )
public bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message )
{
return CanOffer( quester, pm, MLQuestSystem.GetContext( pm ), message );
}
public virtual bool CanOffer( BaseCreature quester, PlayerMobile pm, MLQuestContext context, bool message )
public virtual bool CanOffer( IQuestGiver quester, PlayerMobile pm, MLQuestContext context, bool message )
{
if ( !m_Activated || quester.Deleted || !m_Questers.Contains( quester ) )
if ( !m_Activated || quester.Deleted )
return false;
if ( context != null )
@ -294,12 +262,12 @@ namespace Server.Engines.MLQuests
return true;
}
public virtual void SendOffer( BaseCreature quester, PlayerMobile pm )
public virtual void SendOffer( IQuestGiver quester, PlayerMobile pm )
{
pm.SendGump( new QuestOfferGump( this, quester, pm ) );
}
public virtual void OnAccept( BaseCreature quester, PlayerMobile pm )
public virtual void OnAccept( IQuestGiver quester, PlayerMobile pm )
{
if ( !CanOffer( quester, pm, true ) )
return;
@ -319,7 +287,7 @@ namespace Server.Engines.MLQuests
{
}
public virtual void OnRefuse( BaseCreature quester, PlayerMobile pm )
public virtual void OnRefuse( IQuestGiver quester, PlayerMobile pm )
{
pm.SendGump( new QuestConversationGump( this, pm, RefusalMessage ) );
}

View file

@ -22,7 +22,7 @@ namespace Server.Engines.MLQuests
{
private MLQuest m_Quest;
private BaseCreature m_Quester;
private IQuestGiver m_Quester;
private Type m_QuesterType;
private PlayerMobile m_Player;
@ -33,7 +33,7 @@ namespace Server.Engines.MLQuests
private Timer m_Timer;
public MLQuestInstance( MLQuest quest, BaseCreature quester, PlayerMobile player )
public MLQuestInstance( MLQuest quest, IQuestGiver quester, PlayerMobile player )
{
m_Quest = quest;
@ -89,7 +89,7 @@ namespace Server.Engines.MLQuests
set { m_Quest = value; }
}
public BaseCreature Quester
public IQuestGiver Quester
{
get { return m_Quester; }
set
@ -292,9 +292,10 @@ namespace Server.Engines.MLQuests
if ( m_Quest.ObjectiveType == ObjectiveType.All )
{
// TODO: 1115877 - You no longer have the required items to complete this quest.
foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances )
{
if ( !objective.IsCompleted() ) // Checking this isn't enough, Delivery is "complete" but claiming the items may not be possible
if ( !objective.IsCompleted() )
return;
}
@ -309,9 +310,10 @@ namespace Server.Engines.MLQuests
}
else
{
// The following behavior is unverified, as OSI (currently) has no collect quest requiring
// only one objective to be completed. It is assumed that only one objective is claimed
// (the first completed one), even when multiple are complete.
/* The following behavior is unverified, as OSI (currently) has no collect quest requiring
* only one objective to be completed. It is assumed that only one objective is claimed
* (the first completed one), even when multiple are complete.
*/
bool complete = false;
foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances )
@ -467,14 +469,6 @@ namespace Server.Engines.MLQuests
m_Quest.OnPlayerDeath( this );
}
public string GetReturnTo()
{
if ( m_Quester == null )
return "";
return ( m_Quester.Region.Name == null ) ? m_Quester.Name : String.Format( "{0} ({1})", m_Quester.Name, m_Quester.Region.Name );
}
private bool GetFlag( MLQuestInstanceFlags flag )
{
return ( ( m_Flags & flag ) != 0 );
@ -493,7 +487,11 @@ namespace Server.Engines.MLQuests
// Version info is written in MLQuestPersistence.Serialize
MLQuestSystem.WriteQuestRef( writer, m_Quest );
writer.WriteMobile<BaseCreature>( m_Quester );
if ( m_Quester == null || m_Quester.Deleted )
writer.Write( Serial.MinusOne );
else
writer.Write( m_Quester.Serial );
writer.Write( ClaimReward );
writer.Write( m_ObjectiveInstances.Length );
@ -505,7 +503,9 @@ namespace Server.Engines.MLQuests
public static MLQuestInstance Deserialize( GenericReader reader, int version, PlayerMobile pm )
{
MLQuest quest = MLQuestSystem.ReadQuestRef( reader );
BaseCreature quester = reader.ReadMobile<BaseCreature>();
// TODO: Serialize quester TYPE too, the quest giver reference then becomes optional (only for escorts)
IQuestGiver quester = World.FindEntity( reader.ReadInt() ) as IQuestGiver;
bool claimReward = reader.ReadBool();
int objectives = reader.ReadInt();

View file

@ -54,7 +54,9 @@ namespace Server.Engines.MLQuests
m_Contexts = new Dictionary<PlayerMobile, MLQuestContext>();
string cfgPath = Path.Combine( Core.BaseDirectory, Path.Combine( "Data", "MLQuests.cfg" ) );
Type baseType = typeof( MLQuest );
Type baseQuestType = typeof( MLQuest );
Type baseQuesterType = typeof( IQuestGiver );
if ( File.Exists( cfgPath ) )
{
@ -71,8 +73,13 @@ namespace Server.Engines.MLQuests
Type type = ScriptCompiler.FindTypeByName( split[0] );
if ( type == null || !baseType.IsAssignableFrom( type ) )
if ( type == null || !baseQuestType.IsAssignableFrom( type ) )
{
if ( Debug )
Console.WriteLine( "Warning: {1} quest type '{0}'", split[0], ( type == null ) ? "Unknown" : "Invalid" );
continue;
}
MLQuest quest = null;
@ -91,8 +98,13 @@ namespace Server.Engines.MLQuests
{
Type questerType = ScriptCompiler.FindTypeByName( split[i] );
if ( questerType == null )
if ( questerType == null || !baseQuesterType.IsAssignableFrom( questerType ) )
{
if ( Debug )
Console.WriteLine( "Warning: {1} quester type '{0}'", split[i], ( questerType == null ) ? "Unknown" : "Invalid" );
continue;
}
RegisterQuestGiver( quest, questerType );
}
@ -175,7 +187,7 @@ namespace Server.Engines.MLQuests
m.SendMessage( "Activated: {0}", quest.Activated );
m.SendMessage( "Number of objectives: {0}", quest.Objectives.Count );
m.SendMessage( "Objective type: {0}", quest.ObjectiveType );
m.SendMessage( "Number of registered questers: {0}", quest.Questers.Count );
m.SendMessage( "Number of active instances: {0}", quest.Instances.Count );
}
public class ViewQuestsCommand : BaseCommand
@ -314,7 +326,7 @@ namespace Server.Engines.MLQuests
m.SendGump( new InterfaceGump( m, new string[] { "Object" }, found, 0, null ) );
}
private static bool FindQuest( BaseCreature quester, PlayerMobile pm, MLQuestContext context, out MLQuest quest, out MLQuestInstance entry )
private static bool FindQuest( IQuestGiver quester, PlayerMobile pm, MLQuestContext context, out MLQuest quest, out MLQuestInstance entry )
{
quest = null;
entry = null;
@ -364,9 +376,9 @@ namespace Server.Engines.MLQuests
return ( quest != null );
}
public static void OnDoubleClick( BaseCreature quester, PlayerMobile pm )
public static void OnDoubleClick( IQuestGiver quester, PlayerMobile pm )
{
if ( quester.Deleted || !quester.CanGiveMLQuest || !pm.Alive )
if ( quester.Deleted || !pm.Alive )
return;
MLQuestContext context = GetContext( pm );
@ -528,7 +540,7 @@ namespace Server.Engines.MLQuests
}
}
public static MLQuestInstance HandleDelivery( PlayerMobile pm, BaseCreature quester, Type questerType )
public static MLQuestInstance HandleDelivery( PlayerMobile pm, IQuestGiver quester, Type questerType )
{
MLQuestContext context = GetContext( pm );
@ -613,6 +625,22 @@ namespace Server.Engines.MLQuests
}
}
public static void HandleDeletion( IQuestGiver quester )
{
foreach ( MLQuest quest in quester.MLQuests )
{
List<MLQuestInstance> instances = quest.Instances;
for ( int i = instances.Count - 1; i >= 0; --i )
{
MLQuestInstance instance = instances[i];
if ( instance.Quester == quester )
instance.OnQuesterDeleted();
}
}
}
public static void EventSink_QuestGumpRequest( QuestGumpRequestArgs args )
{
PlayerMobile pm = args.Mobile as PlayerMobile;
@ -625,7 +653,7 @@ namespace Server.Engines.MLQuests
private static List<MLQuest> m_EligiblePool = new List<MLQuest>();
public static MLQuest RandomStarterQuest( BaseCreature quester, PlayerMobile pm, MLQuestContext context )
public static MLQuest RandomStarterQuest( IQuestGiver quester, PlayerMobile pm, MLQuestContext context )
{
List<MLQuest> quests = quester.MLQuests;
@ -657,30 +685,52 @@ namespace Server.Engines.MLQuests
return m_EligiblePool[Utility.Random( m_EligiblePool.Count )];
}
public static void TurnToFace( BaseCreature quester, Mobile mob )
public static void TurnToFace( IQuestGiver quester, Mobile mob )
{
quester.Direction = quester.GetDirectionTo( mob );
if ( quester is Mobile )
{
Mobile m = (Mobile)quester;
m.Direction = m.GetDirectionTo( mob );
}
}
public static void Tell( BaseCreature quester, PlayerMobile pm, int cliloc )
public static void Tell( IQuestGiver quester, PlayerMobile pm, int cliloc )
{
TurnToFace( quester, pm );
quester.PrivateOverheadMessage( MessageType.Regular, SpeechColor, cliloc, pm.NetState );
if ( quester is Mobile )
((Mobile)quester).PrivateOverheadMessage( MessageType.Regular, SpeechColor, cliloc, pm.NetState );
else if ( quester is Item )
MessageHelper.SendLocalizedMessageTo( (Item)quester, pm, cliloc, SpeechColor );
else
pm.SendLocalizedMessage( cliloc, "", SpeechColor );
}
public static void Tell( BaseCreature quester, PlayerMobile pm, int cliloc, string args )
public static void Tell( IQuestGiver quester, PlayerMobile pm, int cliloc, string args )
{
TurnToFace( quester, pm );
quester.PrivateOverheadMessage( MessageType.Regular, SpeechColor, cliloc, args, pm.NetState );
if ( quester is Mobile )
((Mobile)quester).PrivateOverheadMessage( MessageType.Regular, SpeechColor, cliloc, args, pm.NetState );
else if ( quester is Item )
MessageHelper.SendLocalizedMessageTo( (Item)quester, pm, cliloc, args, SpeechColor );
else
pm.SendLocalizedMessage( cliloc, args, SpeechColor );
}
public static void Tell( BaseCreature quester, PlayerMobile pm, string message )
public static void Tell( IQuestGiver quester, PlayerMobile pm, string message )
{
TurnToFace( quester, pm );
quester.PrivateOverheadMessage( MessageType.Regular, SpeechColor, false, message, pm.NetState );
if ( quester is Mobile )
((Mobile)quester).PrivateOverheadMessage( MessageType.Regular, SpeechColor, false, message, pm.NetState );
else if ( quester is Item )
MessageHelper.SendMessageTo( (Item)quester, pm, message, SpeechColor );
else
pm.SendMessage( SpeechColor, message );
}
public static void TellDef( BaseCreature quester, PlayerMobile pm, TextDefinition def )
public static void TellDef( IQuestGiver quester, PlayerMobile pm, TextDefinition def )
{
if ( def == null )
return;

View file

@ -16,7 +16,7 @@ namespace Server.Engines.MLQuests.Objectives
{
}
public virtual bool CanOffer( BaseCreature quester, PlayerMobile pm, bool message )
public virtual bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message )
{
return true;
}

View file

@ -46,6 +46,14 @@ namespace Server.Engines.MLQuests.Objectives
m_DesiredAmount = amount;
m_AcceptedType = type;
m_Name = name;
if ( MLQuestSystem.Debug && ShowDetailed && name.Number > 0 )
{
int itemid = LabelToItemID( name.Number );
if ( itemid <= 0 || itemid > 0x4000 )
Console.WriteLine( "Warning: cliloc {0} is likely giving the wrong item ID", name.Number );
}
}
public bool CheckType( Type type )
@ -60,17 +68,10 @@ namespace Server.Engines.MLQuests.Objectives
public static int LabelToItemID( int label )
{
int result;
if ( label < 1078872 )
result = ( label - 1020000 );
return ( label - 1020000 );
else
result = ( label - 1078872 );
if ( MLQuestSystem.Debug && ( result <= 0 || result > 0x4000 ) )
Console.WriteLine( "Warning: cliloc {0} is likely giving the wrong item ID", label );
return result;
return ( label - 1078872 );
}
public override void WriteToGump( Gump g, ref int y )
@ -250,7 +251,7 @@ namespace Server.Engines.MLQuests.Objectives
y += 16;
g.AddHtmlLocalized( 103, y, 120, 16, 1074782, 0x15F90, false, false ); // Return to
g.AddLabel( 223, y, 0x481, Instance.GetReturnTo() );
g.AddLabel( 223, y, 0x481, QuesterNameAttribute.GetQuesterNameFor( Instance.QuesterType ) );
y += 16;
}
}

View file

@ -13,7 +13,7 @@ namespace Server.Engines.MLQuests.Objectives
private int m_Amount;
private TextDefinition m_Name;
private Type m_Destination;
private TextDefinition m_DestinationName;
private bool m_SpawnsDelivery;
public Type Delivery
{
@ -39,19 +39,59 @@ namespace Server.Engines.MLQuests.Objectives
set { m_Destination = value; }
}
public TextDefinition DestinationName
public bool SpawnsDelivery
{
get { return m_DestinationName; }
set { m_DestinationName = value; }
get { return m_SpawnsDelivery; }
set { m_SpawnsDelivery = value; }
}
public DeliverObjective( Type delivery, int amount, TextDefinition name, Type destination, TextDefinition destinationName )
public DeliverObjective( Type delivery, int amount, TextDefinition name, Type destination )
: this( delivery, amount, name, destination, true )
{
}
public DeliverObjective( Type delivery, int amount, TextDefinition name, Type destination, bool spawnsDelivery )
{
m_Delivery = delivery;
m_Amount = amount;
m_Name = name;
m_Destination = destination;
m_DestinationName = destinationName;
m_SpawnsDelivery = spawnsDelivery;
if ( MLQuestSystem.Debug && name.Number > 0 )
{
int itemid = CollectObjective.LabelToItemID( name.Number );
if ( itemid <= 0 || itemid > 0x4000 )
Console.WriteLine( "Warning: cliloc {0} is likely giving the wrong item ID", name.Number );
}
}
public virtual void SpawnDelivery( Container pack )
{
if ( !m_SpawnsDelivery || pack == null )
return;
List<Item> delivery = new List<Item>();
for ( int i = 0; i < m_Amount; ++i )
{
Item item = Activator.CreateInstance( m_Delivery ) as Item;
if ( item == null )
continue;
delivery.Add( item );
if ( item.Stackable && m_Amount > 1 )
{
item.Amount = m_Amount;
break;
}
}
foreach ( Item item in delivery )
pack.DropItem( item ); // Confirmed: on OSI items are added even if your pack is full
}
public override void WriteToGump( Gump g, ref int y )
@ -74,11 +114,7 @@ namespace Server.Engines.MLQuests.Objectives
y += 32;
g.AddHtmlLocalized( 103, y, 120, 16, 1072379, 0x15F90, false, false ); // Deliver to
if ( m_DestinationName.Number > 0 )
g.AddHtmlLocalized( 223, y, 190, 18, m_DestinationName.Number, false, false );
else
g.AddLabel( 223, y, 0x481, m_DestinationName.String );
g.AddLabel( 223, y, 0x481, QuesterNameAttribute.GetQuesterNameFor( m_Destination ) );
y += 16;
}
@ -98,8 +134,13 @@ namespace Server.Engines.MLQuests.Objectives
public override bool IsTimed { get { return true; } }
public override TimeSpan Duration { get { return m_Duration; } }
public TimedDeliverObjective( TimeSpan duration, Type delivery, int amount, TextDefinition name, Type destination, TextDefinition destinationName )
: base( delivery, amount, name, destination, destinationName )
public TimedDeliverObjective( TimeSpan duration, Type delivery, int amount, TextDefinition name, Type destination )
: this( duration, delivery, amount, name, destination, true )
{
}
public TimedDeliverObjective( TimeSpan duration, Type delivery, int amount, TextDefinition name, Type destination, bool spawnsDelivery )
: base( delivery, amount, name, destination, spawnsDelivery )
{
m_Duration = duration;
}
@ -130,7 +171,7 @@ namespace Server.Engines.MLQuests.Objectives
m_Objective = objective;
}
public virtual bool IsDestination( BaseCreature quester, Type type )
public virtual bool IsDestination( IQuestGiver quester, Type type )
{
Type destType = m_Objective.Destination;
@ -144,34 +185,7 @@ namespace Server.Engines.MLQuests.Objectives
public override void OnQuestAccepted()
{
Container pack = Instance.Player.Backpack;
if ( pack == null )
return; // where are we supposed to put them?
Type type = m_Objective.Delivery;
int amount = m_Objective.Amount;
List<Item> delivery = new List<Item>();
for ( int i = 0; i < amount; ++i )
{
Item item = Activator.CreateInstance( type ) as Item;
if ( item == null )
continue;
delivery.Add( item );
if ( item.Stackable && amount > 1 )
{
item.Amount = amount;
break;
}
}
foreach ( Item item in delivery )
pack.DropItem( item ); // Confirmed: on OSI items are added even if your pack is full
m_Objective.SpawnDelivery( Instance.Player.Backpack );
}
// This is VERY similar to CollectObjective.GetCurrentTotal

View file

@ -29,11 +29,9 @@ namespace Server.Engines.MLQuests.Objectives
m_Destination = destination;
}
public override bool CanOffer( BaseCreature quester, PlayerMobile pm, bool message )
public override bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message )
{
BaseEscortable escortable = quester as BaseEscortable;
if ( quester.Controlled || ( escortable != null && escortable.IsBeingDeleted ) )
if ( ( quester is BaseCreature && ( (BaseCreature)quester ).Controlled ) || ( quester is BaseEscortable && ( (BaseEscortable)quester ).IsBeingDeleted ) )
return false;
MLQuestContext context = MLQuestSystem.GetContext( pm );
@ -54,7 +52,6 @@ namespace Server.Engines.MLQuests.Objectives
DateTime nextEscort = pm.LastEscortTime + BaseEscortable.EscortDelay;
// Note: On OSI Bravehorn doesn't check the time limit, but it does SET the last escort time... bug!
if ( nextEscort > DateTime.Now )
{
if ( message )
@ -100,6 +97,7 @@ namespace Server.Engines.MLQuests.Objectives
private bool m_HasCompleted;
private Timer m_Timer;
private DateTime m_LastSeenEscorter;
private BaseCreature m_Escort;
public bool HasCompleted
{
@ -114,43 +112,56 @@ namespace Server.Engines.MLQuests.Objectives
m_HasCompleted = false;
m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 5 ), new TimerCallback( CheckDestination ) );
m_LastSeenEscorter = DateTime.Now;
m_Escort = instance.Quester as BaseCreature;
if ( MLQuestSystem.Debug && m_Escort == null && instance.Quester != null )
Console.WriteLine( "Warning: EscortObjective is not supported for type '{0}'", instance.Quester.GetType().Name );
}
public override bool IsCompleted()
{
// Once complete, it stays complete
return m_HasCompleted;
}
private void CheckDestination()
{
if ( m_HasCompleted ) // Completed by deserialization
if ( m_Escort == null || m_HasCompleted ) // Completed by deserialization
{
StopTimer();
return;
}
MLQuestInstance instance = Instance;
BaseCreature escort = instance.Quester;
PlayerMobile pm = instance.Player;
if ( instance.Removed ) // Player cancelled or player died
if ( instance.Removed )
{
Abandon();
}
else if ( m_Objective.Destination.Contains( escort ) ) // We've arrived!
else if ( m_Objective.Destination.Contains( m_Escort ) )
{
m_Escort.Say( 1042809, pm.Name ); // We have arrived! I thank thee, ~1_PLAYER_NAME~! I have no further need of thy services. Here is thy pay.
if ( pm.Young || m_Escort.Region.IsPartOf( "Haven Island" ) )
Titles.AwardFame( pm, 10, true );
else
VirtueHelper.AwardVirtue( pm, VirtueName.Compassion, ( m_Escort is BaseEscortable && ( (BaseEscortable)m_Escort ).IsPrisoner ) ? 400 : 200 );
EndFollow( m_Escort );
StopTimer();
m_HasCompleted = true;
CheckComplete();
InternalOnQuestCompleted();
StopTimer();
// Auto claim reward
MLQuestSystem.OnDoubleClick( m_Escort, pm );
}
else if ( pm.Map != escort.Map || !pm.InRange( escort, 30 ) ) // Player abandoned us (range not verified)
else if ( pm.Map != m_Escort.Map || !pm.InRange( m_Escort, 30 ) ) // TODO: verify range
{
if ( m_LastSeenEscorter + BaseEscortable.AbandonDelay <= DateTime.Now )
Abandon();
}
else // Player is still with us
else
{
m_LastSeenEscorter = DateTime.Now;
}
@ -203,7 +214,8 @@ namespace Server.Engines.MLQuests.Objectives
pm.LastEscortTime = DateTime.Now;
BeginFollow( instance.Quester, pm );
if ( m_Escort != null )
BeginFollow( m_Escort, pm );
}
public void Abandon()
@ -211,17 +223,16 @@ namespace Server.Engines.MLQuests.Objectives
StopTimer();
MLQuestInstance instance = Instance;
BaseCreature quester = instance.Quester;
PlayerMobile pm = instance.Player;
if ( !quester.Deleted )
if ( m_Escort != null && !m_Escort.Deleted )
{
if ( !pm.Alive )
quester.Say( 500901 ); // Ack! My escort has come to haunt me!
m_Escort.Say( 500901 ); // Ack! My escort has come to haunt me!
else
quester.Say( 500902 ); // My escort seems to have abandoned me!
m_Escort.Say( 500902 ); // My escort seems to have abandoned me!
EndFollow( quester );
EndFollow( m_Escort );
}
// Note: this sound is sent twice on OSI (once here and once in Cancel())
@ -232,25 +243,6 @@ namespace Server.Engines.MLQuests.Objectives
instance.Cancel();
}
private void InternalOnQuestCompleted() // To make sure it's never executed twice (when combined with a CollectObjective for example)
{
MLQuestInstance instance = Instance;
PlayerMobile pm = instance.Player;
BaseCreature quester = instance.Quester;
quester.Say( 1042809, pm.Name ); // We have arrived! I thank thee, ~1_PLAYER_NAME~! I have no further need of thy services. Here is thy pay.
// Verified: auto double click goes here
MLQuestSystem.OnDoubleClick( quester, pm ); // Auto claim reward
if ( pm.Young || quester.Region.IsPartOf( "Haven Island" ) )
Titles.AwardFame( pm, 10, true );
else
VirtueHelper.AwardVirtue( pm, VirtueName.Compassion, ( quester is BaseEscortable && ( (BaseEscortable)quester ).IsPrisoner ) ? 400 : 200 );
EndFollow( quester );
}
public override void OnQuesterDeleted()
{
if ( IsCompleted() || Instance.Removed )

View file

@ -66,7 +66,7 @@ namespace Server.Engines.MLQuests.Objectives
m_Flags |= GainSkillObjectiveFlags.Accelerate;
}
public override bool CanOffer( BaseCreature quester, PlayerMobile pm, bool message )
public override bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message )
{
Skill skill = pm.Skills[m_Skill];

View file

@ -178,7 +178,7 @@ namespace Server.Engines.MLQuests.Objectives
y += 16;
g.AddHtmlLocalized( 103, y, 120, 16, 1074782, 0x15F90, false, false ); // Return to
g.AddLabel( 223, y, 0x481, Instance.GetReturnTo() );
g.AddLabel( 223, y, 0x481, QuesterNameAttribute.GetQuesterNameFor( Instance.QuesterType ) );
y += 16;
}

View file

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using Server;
namespace Server.Engines.MLQuests
{
[AttributeUsage( AttributeTargets.Class )]
public class QuesterNameAttribute : Attribute
{
private string m_QuesterName;
public string QuesterName { get { return m_QuesterName; } }
public QuesterNameAttribute( string questerName )
{
m_QuesterName = questerName;
}
private static readonly Type m_Type = typeof( QuesterNameAttribute );
private static readonly Dictionary<Type, string> m_Cache = new Dictionary<Type, string>();
public static string GetQuesterNameFor( Type t )
{
if ( t == null )
return "";
string result;
if ( m_Cache.TryGetValue( t, out result ) )
return result;
object[] attributes = t.GetCustomAttributes( m_Type, false );
if ( attributes.Length != 0 )
result = ( (QuesterNameAttribute)attributes[0] ).QuesterName;
else
result = t.Name;
return ( m_Cache[t] = result );
}
}
}

View file

@ -216,7 +216,7 @@ namespace Server.Items
{
MessageHelper.SendLocalizedMessageTo( m_Bag, from, 1054108, 0x59 ); // The bag of sending rejects the cursed item.
}
else if ( !item.VerifyMove( from ) || item is Server.Engines.Quests.QuestItem )
else if ( !item.VerifyMove( from ) || item is Server.Engines.Quests.QuestItem || item.Nontransferable )
{
MessageHelper.SendLocalizedMessageTo( m_Bag, from, 1054109, 0x59 ); // The bag of sending rejects that item.
}

View file

@ -14,5 +14,10 @@ namespace Server
{
to.Send( new MessageLocalized( from.Serial, from.ItemID, MessageType.Regular, hue, 3, number, "", args ) );
}
public static void SendMessageTo( Item from, Mobile to, string text, int hue )
{
to.Send( new UnicodeMessage( from.Serial, from.ItemID, MessageType.Regular, hue, 3, "ENU", "", text ) );
}
}
}
}

View file

@ -165,7 +165,7 @@ namespace Server.Mobiles
}
}
public partial class BaseCreature : Mobile, IHonorTarget
public partial class BaseCreature : Mobile, IHonorTarget, IQuestGiver
{
public const int MaxLoyalty = 100;
@ -336,14 +336,14 @@ namespace Server.Mobiles
}
}
public virtual bool CanGiveMLQuest { get { return ( MLQuests.Count != 0 ); } }
public virtual bool StaticMLQuester { get { return true; } }
protected virtual List<MLQuest> ConstructQuestList()
{
return null;
}
public virtual bool CanGiveMLQuest { get { return ( MLQuests.Count != 0 ); } }
public virtual bool CanShout { get { return false; } }
public const int ShoutRange = 8;
@ -379,18 +379,6 @@ namespace Server.Mobiles
{
}
private void RegisterQuests()
{
foreach ( MLQuest quest in MLQuests )
quest.Register( this );
}
private void UnregisterQuests()
{
foreach ( MLQuest quest in MLQuests )
quest.Unregister( this );
}
#endregion
#region Bonding
@ -1751,9 +1739,6 @@ namespace Server.Mobiles
NameHue = 0x35;
GenerateLoot( true );
if ( MLQuestSystem.Enabled && StaticMLQuester )
RegisterQuests();
}
public BaseCreature( Serial serial ) : base( serial )
@ -2127,9 +2112,6 @@ namespace Server.Mobiles
if ( IsAnimatedDead )
Spells.Necromancy.AnimateDeadSpell.Register( m_SummonMaster, this );
if ( MLQuestSystem.Enabled && StaticMLQuester )
RegisterQuests();
}
public virtual bool IsHumanInTown()
@ -3007,7 +2989,7 @@ namespace Server.Mobiles
Spells.Necromancy.AnimateDeadSpell.Unregister( m_SummonMaster, this );
if ( MLQuestSystem.Enabled )
UnregisterQuests();
MLQuestSystem.HandleDeletion( this );
base.OnAfterDelete();
}

View file

@ -29,9 +29,6 @@ namespace Server.Mobiles
Region reg = Region;
Type[] list = reg.IsPartOf( "Haven Island" ) ? m_MLQuestTypesNH : m_MLQuestTypes;
if ( MLQuestSystem.Debug )
Console.WriteLine( "DEBUG: Assigning quest to BaseEscortable {0}, Region = {1}", Serial, ( reg == null ) ? "-null-" : reg.Name );
int randomIdx = Utility.Random( list.Length );
for ( int i = 0; i < list.Length; ++i )
@ -55,13 +52,13 @@ namespace Server.Mobiles
if ( okay )
{
SetMLQuest( quest );
m_MLQuest = quest;
break;
}
}
else if ( MLQuestSystem.Debug )
{
Console.WriteLine( "WARNING: Type {0} should not be eligible as it is not a registered quest", questType.Name );
Console.WriteLine( "Warning: Escortable cannot be assigned quest type '{0}', it is not registered", questType.Name );
}
randomIdx = ( randomIdx + 1 ) % list.Length;
@ -70,7 +67,7 @@ namespace Server.Mobiles
if ( m_MLQuest == null )
{
if ( MLQuestSystem.Debug )
Console.WriteLine( "WARNING: No suitable quest found for escort {0}", Serial );
Console.WriteLine( "Warning: No suitable quest found for escort {0}", Serial );
return null;
}
@ -174,12 +171,6 @@ namespace Server.Mobiles
typeof( EscortToNHBank )
};
public void SetMLQuest( MLQuest quest )
{
m_MLQuest = quest;
quest.Register( this );
}
[Constructable]
public BaseEscortable()
: base(AIType.AI_Melee, FightMode.Aggressor, 22, 1, 0.2, 1.0)
@ -571,7 +562,7 @@ namespace Server.Mobiles
MLQuest quest = MLQuestSystem.ReadQuestRef( reader );
if ( MLQuestSystem.Enabled && quest != null && !StaticMLQuester )
SetMLQuest( quest );
m_MLQuest = quest;
}
}