diff --git a/Data/MLQuests.cfg b/Data/MLQuests.cfg
new file mode 100644
index 000000000..dd47c4132
--- /dev/null
+++ b/Data/MLQuests.cfg
@@ -0,0 +1,292 @@
+# Escorts
+EscortToYew
+EscortToVesper
+EscortToTrinsic
+EscortToSkaraBrae
+EscortToSerpentsHold
+EscortToNujelm
+EscortToMoonglow
+EscortToMinoc
+EscortToMagincia
+EscortToJhelom
+EscortToCove
+EscortToBritain
+EscortToOcllo
+
+# Britannia
+Aemaeth1 Aurelia
+Aemaeth2 SkeletonOfSzandor
+OddsAndEnds Patricus
+
+# Honest Beggar
+HonestBeggar Evan
+ReginasThanks Regina
+
+# Unfading Memories
+# TODO: OneTimeOnly issue
+#UnfadingMemoriesPartOne Emilio
+#UnfadingMemoriesPartTwo Emilio
+#UnfadingMemoriesPartThree Thalia
+
+# A Ghost Of Covetous
+AGhostOfCovetous Ben
+SaveHisDad Frederic
+AFathersGratitude Leon Andros
+
+# Heartwood
+TheyreBreedingLikeRabbits Saril Tamm Yorus
+TheyllEatAnything Saril Tamm Yorus
+NoGoodFishStealing Saril Tamm Yorus
+AHeroInTheMaking Saril Yorus
+BullfightingSortOf Saril Tamm Yorus
+AFineFeast Saril Tamm Yorus
+ForcedMigration Saril Tamm Yorus
+FilthyPests Saril Tamm
+DeadManWalking Vilo Saril Tamm Cailla Tiana
+KingOfBears Vilo Cailla
+Specimens Vilo Clehin Salaenih Cailla Landy
+Spirits Cailla
+RollTheBones Vilo Cailla
+ItsAGhastlyJob Vilo Cailla
+Troglodytes Cailla Canir
+UnholyKnights Vilo Cailla
+AFeatherInYerCap Vilo Cailla
+ATaleOfTail Vilo Cailla
+ATrogAndHisDog Cailla Canir
+Overpopulation Saril Tamm Yorus ElderAcob
+WildBoarCull Saril Tamm Yorus ElderAcob
+ItsElemental Caelas Alejaha
+CircleOfLife Brinnae Aniel Ciala Mielan
+DustToDust Aniel Ciala
+CreepyCrawlies Clehin Aulan Landy
+VoraciousPlants Aulan Salaenih
+GibberJabber Aulan
+AnimatedMonstrosity Aulan Salaenih
+BirdsOfAFeather Aulan
+Frightmares Aulan
+MoltenReptiles Aulan
+BloodyNuisance Aulan
+BloodSuckers Aulan
+TheAfterlife Brinnae
+ForkedTongue Brinnae Saril Tamm Tiana
+ImpishDelights Brinnae
+ThreeWishes Brinnae
+EvilEye Brinnae
+GargoylesWrath Brinnae
+UndeadMages Brinnae
+FriendlyNeighborhoodSpiderkiller Vilo Brinnae Cailla
+MongbatMenace Clehin Brinnae Landy
+StirringTheNest Brinnae
+WarriorCaste Caelas Salaenih
+BigWorms Caelas
+OrcishElite Caelas
+ThinningTheHerd Clehin Saril Tamm Landy Yorus
+Squishy Salaenih
+OrcSlaying LorekeeperOolua
+ABigJob Salaenih
+TrollingForTrolls Saril Tamm Tiana
+ColdHearted Salaenih
+ForkedTongues
+ShakingThingsUp Salaenih
+Arachnophobia Salaenih
+MiniSwampThing Salaenih
+ThePerilsOfFarming Vilo Tiana
+IndustriousAsAnAntLion Vilo Tiana
+UnholyConstruct Vilo Tiana Braen
+AChillInTheAir Vilo Tiana
+# TODO: Restart delays
+#TheKingOfClothing Ahie Thallary
+#ThePuffyShirt Ahie Thallary
+#FromTheGaultierCollection Waelian Sleen Ahie Thallary
+#HauteCouture Ahie Thallary
+#TheSongOfTheWind Tholef Tillanil
+#BeerGoggles Tholef Tillanil
+#MessageInABottleQuest Tholef Tillanil
+#NecessitysMother Waelian Sleen
+#TickTock Waelian Sleen Danoel
+ReptilianDentist Sleen Danoel
+#StopHarpingOnMe Waelian Sleen Anolly Cillitha Jusae Unoelil
+#TheFarEye Waelian Sleen Anolly Unoelil
+#LethalDarts Cillitha Jusae
+#ASimpleBow Cillitha Jusae
+#IngeniousArcheryPartOne Cillitha Jusae
+#IngeniousArcheryPartTwo Cillitha Jusae
+#IngeniousArcheryPartThree Cillitha Jusae
+ScaleArmor Ahie Thallary Tallinin
+#CutsBothWays Lohn Olla
+#DragonProtection Lohn Olla
+#NothingFancy Anolly Lohn Olla Unoelil Danoel
+#TheBulwark Lohn Olla
+#ArchSupport Waelian Sleen Ciala Aniel
+ParoxysmusSuccubi LorekeeperNillaen LorekeeperOolua
+ParoxysmusMoloch LorekeeperNillaen LorekeeperOolua
+ParoxysmusDaemons LorekeeperNillaen LorekeeperOolua
+ParoxysmusArcaneDaemons LorekeeperNillaen LorekeeperOolua
+CausticCombo LorekeeperNillaen LorekeeperOolua
+PlagueLord LorekeeperNillaen LorekeeperOolua
+GlassyFoe Ciala Aniel LorekeeperRyal LorekeeperRollarn
+DaemonicPrism LorekeeperRyal LorekeeperRollarn
+Hailstorm LorekeeperRyal LorekeeperRollarn
+HowManyHeads LorekeeperRyal LorekeeperRollarn
+DreadhornQuest LorekeeperCalendor LorekeeperOolua
+NewLeadership ElderAcob
+ExAssassins ElderAcob
+ExtinguishingTheFlame ElderAcob
+CrimeAndPunishment ElderAcob
+DeathToTheNinja ElderAcob
+AllThatGlittersIsNotGood LorekeeperSiarra ElderBrae
+
+# The Ancient World
+TheAncientWorld LorekeeperBroolol
+TheGoldenHorn LorekeeperBroolol
+Bullish Braen
+LostCivilization Braen
+
+# Warriors Of The Gemkeeper
+WarriorsOfTheGemkeeper LorekeeperRollarn
+CloseEnough LorekeeperRollarn
+TakingTheBullByTheHorns Canir
+EmissaryToTheMinotaur Canir
+
+# Sanctuary
+# TODO: Restart delays
+#BrokenShaft Beotham
+#BendingTheBow Beotham
+#ArmsRace Beotham
+#ImprovedCrossbows Beotham
+#BuildingTheBetterCrossbow Beotham
+#InstrumentOfWar Danoel
+#TheShield Danoel
+#MusicToMyEars Danoel
+#TheGlassEye Danoel
+#LazyHumans Danoel
+#InventiveTools Danoel
+PixieDustToDust LorekeeperOolua
+#AnImpressivePlaid Tallinin
+#LeatherAndLace Danoel Tallinin
+#FeyHeadgear Tallinin
+NewCloak Tallinin
+ADishBestServedCold Tiana Koole
+ArchEnemies Tiana
+Vermin Tiana
+#ANiceShirt Tallinin
+MougGuurMustDie Dallid
+LeaderOfThePack Dallid
+SayonaraSzavetra Dallid
+#TappingTheKeg Dallid
+#WaitingToBeFilled Dallid
+#BreezesSong Dallid
+ProofOfTheDeed ElderOnallan Tiana
+Marauders ElderOnallan Tiana Koole
+TheBrainsOfTheOperation ElderOnallan Tiana
+TheBrawn ElderOnallan Tiana
+TheBiggerTheyAre ElderOnallan Tiana
+TroubleOnTheWing Koole
+BrotherlyLove LorekeeperRollarn
+
+# Elven heritage
+Seasons MaulTheBear
+CaretakerOfTheLand Strongroot
+WisdomOfTheSphynx Enigma
+DefendingTheHerd Bravehorn
+TheBalanceOfNature Huntsman
+TheJoysOfLife Arielle
+
+# Human heritage
+Ingenuity Sledge
+HeaveHo Patricus
+HumanInNeed
+AllSeasonAdventurer Belulah
+
+# Ilshenar
+Responsibility Lissbet
+SomethingToWailAbout Jelrice
+Runaways Jelrice
+ViciousPredator Jelrice
+GuileIrkAndSpite Yorus
+
+# New Haven
+EscortToNHAlchemist
+EscortToNHBard
+EscortToNHWarrior
+EscortToNHTailor
+EscortToNHCarpenter
+EscortToNHMapmaker
+EscortToNHMage
+EscortToNHInn
+EscortToNHFarm
+EscortToNHDocks
+EscortToNHBowyer
+EscortToNHBank
+
+# New Haven Training
+# TODO: Restart delays
+#SplitEnds Andric
+IShotAnArrowIntoTheAir Kashiel
+#BakersDozen Asandos
+#AStitchInTime Clairesse
+#BatteredBucklers Gervis
+#MoreOrePlease Mugg
+#ComfortableSeating Lowel
+#ThePenIsMightier Lyle
+#AClockworkPuzzle Nibbet
+#DeliciousFishes Norton
+#FleeAndFatigue Sadrah
+#ChopChopOnTheDouble Hargrove
+
+# New Haven Skill Training
+CleansingOldHaven Aelorn
+TheRudimentsOfSelfDefense Dimethro
+CrushingBonesAndTakingNames Churchill
+SwiftAsAnArrow Robyn
+EnGuarde Recaro
+TheArtOfWar AldenArmstrong
+TheWayOfTheBlade Jockles
+ThouAndThineShield TylAriadne
+DefyingTheArcane Alefian
+StoppingTheWorld Gustar
+ScribingArcaneKnowledge Jillian
+TheMagesApprentice Kaelynna
+ScholarlyTask Mithneral
+TheRightToolForTheJob AmeliaYoungstone
+KnowThineEnemy AndreasVesalius
+BruisesBandagesAndBlood Avicenna
+TheInnerWarrior SarsmeaSmythe
+TheArtOfStealth Ryuichi
+BecomingOneWithTheShadows Chiyo
+WalkingSilently Jun
+EyesOfARanger Walker
+TheWayOfTheSamurai Hamato
+TheAllureOfDarkMagic Mulcivikh
+ChannelingTheSupernatural Morganna
+TheDeluciansLostMine JacobWaltz
+ItsHammerTime GeorgeHephaestus
+
+# Spellweaving
+Patience Aeluva
+NeedsOfTheManyHeartwood1 Aeluva
+NeedsOfTheManyHeartwood2 Aeluva
+MakingAContributionHeartwood Aeluva
+UnnaturalCreations Aeluva
+
+Discipline Koole
+NeedsOfTheManySanctuary Koole
+MakingAContributionSanctuary Koole
+SuppliesForSanctuary Koole
+TheHumanBlight Koole
+
+FriendOfTheFey Synaeva
+TokenOfFriendship Synaeva
+Alliance Arielle
+
+FiendishFriends ElderBrae
+CrackingTheWhipI ElderBrae
+CrackingTheWhipII ElderBrae
+
+# ML dungeons
+VilePoison Jamal
+ARockAndAHardPlace Iosep
+SympatheticMagic Iosep
+AlreadyDead Iosep
+Eureka Iosep
+SubContracting Jamal
diff --git a/Data/Regions.xml b/Data/Regions.xml
index da2424e68..de4dce3c1 100644
--- a/Data/Regions.xml
+++ b/Data/Regions.xml
@@ -966,19 +966,76 @@
-
+
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Scripts/Engines/Craft/Core/CraftItem.cs b/Scripts/Engines/Craft/Core/CraftItem.cs
index 5fcc6d186..ea91ad182 100644
--- a/Scripts/Engines/Craft/Core/CraftItem.cs
+++ b/Scripts/Engines/Craft/Core/CraftItem.cs
@@ -1146,7 +1146,7 @@ namespace Server.Engines.Craft
}
}
- if ( tool.UsesRemaining < 1 )
+ if ( tool.UsesRemaining < 1 && tool.BreakOnDepletion )
toolBroken = true;
if ( toolBroken )
@@ -1267,7 +1267,7 @@ namespace Server.Engines.Craft
tool.UsesRemaining--;
- if ( tool.UsesRemaining < 1 )
+ if ( tool.UsesRemaining < 1 && tool.BreakOnDepletion )
toolBroken = true;
if ( toolBroken )
diff --git a/Scripts/Engines/Craft/Core/CraftSystem.cs b/Scripts/Engines/Craft/Core/CraftSystem.cs
index 474a6b167..6093588fa 100644
--- a/Scripts/Engines/Craft/Core/CraftSystem.cs
+++ b/Scripts/Engines/Craft/Core/CraftSystem.cs
@@ -26,6 +26,9 @@ namespace Server.Engines.Craft
private CraftSubResCol m_CraftSubRes;
private CraftSubResCol m_CraftSubRes2;
+ private List m_Recipes;
+ private List m_RareRecipes;
+
public int MinCraftEffect { get { return m_MinCraftEffect; } }
public int MaxCraftEffect { get { return m_MaxCraftEffect; } }
public double Delay { get { return m_Delay; } }
@@ -34,7 +37,7 @@ namespace Server.Engines.Craft
public CraftGroupCol CraftGroups{ get { return m_CraftGroups; } }
public CraftSubResCol CraftSubRes{ get { return m_CraftSubRes; } }
public CraftSubResCol CraftSubRes2{ get { return m_CraftSubRes2; } }
-
+
public abstract SkillName MainSkill{ get; }
public virtual int GumpTitleNumber{ get{ return 0; } }
@@ -114,6 +117,9 @@ namespace Server.Engines.Craft
m_CraftSubRes = new CraftSubResCol();
m_CraftSubRes2 = new CraftSubResCol();
+ m_Recipes = new List();
+ m_RareRecipes = new List();
+
InitCraftList();
}
@@ -135,6 +141,22 @@ namespace Server.Engines.Craft
}
}
+ public int RandomRecipe()
+ {
+ if ( m_Recipes.Count == 0 )
+ return -1;
+
+ return m_Recipes[Utility.Random( m_Recipes.Count )];
+ }
+
+ public int RandomRareRecipe()
+ {
+ if ( m_RareRecipes.Count == 0 )
+ return -1;
+
+ return m_RareRecipes[Utility.Random( m_RareRecipes.Count )];
+ }
+
public int AddCraft( Type typeItem, TextDefinition group, TextDefinition name, double minSkill, double maxSkill, Type typeRes, TextDefinition nameRes, int amount )
{
@@ -262,12 +284,29 @@ namespace Server.Engines.Craft
craftItem.UseSubRes2 = val;
}
- public void AddRecipe( int index, int id )
+ private void AddRecipeBase( int index, int id )
{
CraftItem craftItem = m_CraftItems.GetAt( index );
craftItem.AddRecipe( id, this );
}
+ public void AddRecipe( int index, int id )
+ {
+ AddRecipeBase( index, id );
+ m_Recipes.Add( id );
+ }
+
+ public void AddRareRecipe( int index, int id )
+ {
+ AddRecipeBase( index, id );
+ m_RareRecipes.Add( id );
+ }
+
+ public void AddQuestRecipe( int index, int id )
+ {
+ AddRecipeBase( index, id );
+ }
+
public void ForceNonExceptional( int index )
{
CraftItem craftItem = m_CraftItems.GetAt( index );
diff --git a/Scripts/Engines/Craft/DefBlacksmithy.cs b/Scripts/Engines/Craft/DefBlacksmithy.cs
index 9497f5cd0..da3130e8a 100644
--- a/Scripts/Engines/Craft/DefBlacksmithy.cs
+++ b/Scripts/Engines/Craft/DefBlacksmithy.cs
@@ -281,7 +281,7 @@ namespace Server.Engines.Craft
index = AddCraft( typeof( StandardPlateKabuto ), 1011079, 1030196, 90.0, 140.0, typeof( IronIngot ), 1044036, 25, 1044037 );
SetNeededExpansion( index, Expansion.SE );
- /*
+
if( Core.ML )
{
index = AddCraft( typeof( Circlet ), 1011079, 1032645, 62.1, 112.1, typeof( IronIngot ), 1044036, 6, 1044037 );
@@ -296,7 +296,6 @@ namespace Server.Engines.Craft
AddRes( index, typeof( BlueDiamond ), 1032696, 1, 1044240 );
SetNeededExpansion( index, Expansion.ML );
}
- * */
}
#endregion
@@ -351,7 +350,7 @@ namespace Server.Engines.Craft
SetNeededExpansion( index, Expansion.SE );
index = AddCraft( typeof( Sai ), 1011081, 1030234, 50.0, 100.0, typeof( IronIngot ), 1044036, 12, 1044037 );
SetNeededExpansion( index, Expansion.SE );
- /*
+
if( Core.ML )
{
index = AddCraft( typeof( RadiantScimitar ), 1011081, 1031571, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 );
@@ -379,7 +378,7 @@ namespace Server.Engines.Craft
AddRes( index, typeof( DreadHornMane ), 1032682, 1, 1053098 );
AddRes( index, typeof( Putrefication ), 1032678, 10, 1053098 );
AddRes( index, typeof( Muculent ), 1032680, 10, 1053098 );
- AddRecipe( index, 0 );
+ AddRareRecipe( index, 0 );
ForceNonExceptional( index );
SetNeededExpansion( index, Expansion.ML );
@@ -387,7 +386,7 @@ namespace Server.Engines.Craft
AddRes( index, typeof( GrizzledBones ), 1032684, 1, 1053098 );
AddRes( index, typeof( Taint ), 1032684, 10, 1053098 );
AddRes( index, typeof( Blight ), 1032675, 10, 1053098 );
- AddRecipe( index, 1 );
+ AddRareRecipe( index, 1 );
ForceNonExceptional( index );
SetNeededExpansion( index, Expansion.ML );
@@ -395,7 +394,7 @@ namespace Server.Engines.Craft
AddRes( index, typeof( GrizzledBones ), 1032684, 1, 1053098 );
AddRes( index, typeof( Blight ), 1032675, 10, 1053098 );
AddRes( index, typeof( Scourge ), 1032677, 10, 1053098 );
- AddRecipe( index, 2 );
+ AddRareRecipe( index, 2 );
ForceNonExceptional( index );
SetNeededExpansion( index, Expansion.ML );
@@ -403,7 +402,7 @@ namespace Server.Engines.Craft
AddRes( index, typeof( GrizzledBones ), 1032684, 1, 1053098 );
AddRes( index, typeof( Corruption ), 1032676, 10, 1053098 );
AddRes( index, typeof( Putrefication ), 1032678, 10, 1053098 );
- AddRecipe( index, 3 );
+ AddRareRecipe( index, 3 );
ForceNonExceptional( index );
SetNeededExpansion( index, Expansion.ML );
@@ -472,10 +471,11 @@ namespace Server.Engines.Craft
AddRecipe( index, 16 );
SetNeededExpansion( index, Expansion.ML );
- index = AddCraft( typeof( ButchersWarCleaver ), 1011081, 1073526, 75.0, 125.0, typeof( IronIngot ), 1044036, 18, 1044037 );
- AddRes( index, typeof( Turquoise ), 1032691, 1, 1044240 );
- AddRecipe( index, 17 );
- SetNeededExpansion( index, Expansion.ML );
+ // TODO
+ //index = AddCraft( typeof( ButchersWarCleaver ), 1011081, 1073526, 75.0, 125.0, typeof( IronIngot ), 1044036, 18, 1044037 );
+ //AddRes( index, typeof( Turquoise ), 1032691, 1, 1044240 );
+ //AddRecipe( index, 17 );
+ //SetNeededExpansion( index, Expansion.ML );
index = AddCraft( typeof( SerratedWarCleaver ), 1011081, 1073527, 75.0, 125.0, typeof( IronIngot ), 1044036, 18, 1044037 );
AddRes( index, typeof( EcruCitrine ), 1032693, 1, 1044240 );
@@ -507,10 +507,11 @@ namespace Server.Engines.Craft
AddRecipe( index, 23 );
SetNeededExpansion( index, Expansion.ML );
- index = AddCraft( typeof( RuneSabre ), 1011081, 1073537, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 );
- AddRes( index, typeof( Turquoise ), 1032691, 1, 1044240 );
- AddRecipe( index, 24 );
- SetNeededExpansion( index, Expansion.ML );
+ // TODO
+ //index = AddCraft( typeof( RuneSabre ), 1011081, 1073537, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 );
+ //AddRes( index, typeof( Turquoise ), 1032691, 1, 1044240 );
+ //AddRecipe( index, 24 );
+ //SetNeededExpansion( index, Expansion.ML );
index = AddCraft( typeof( MagesRuneBlade ), 1011081, 1073538, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 );
AddRes( index, typeof( BlueDiamond ), 1032696, 1, 1044240 );
@@ -547,12 +548,11 @@ namespace Server.Engines.Craft
AddRecipe( index, 31 );
SetNeededExpansion( index, Expansion.ML );
- index = AddCraft( typeof( BoneMachete ), 1011081, 1020526, 75.0, 125.0, typeof( IronIngot ), 1044036, 20, 1044037 );
+ index = AddCraft( typeof( BoneMachete ), 1011081, 1020526, 45.0, 95.0, typeof( IronIngot ), 1044036, 20, 1044037 );
AddRes( index, typeof( Bone ), 1049064, 6, 1049063 );
- AddRecipe( index, 32 );
+ AddQuestRecipe( index, 32 );
SetNeededExpansion( index, Expansion.ML );
}
- */
}
#endregion
@@ -564,7 +564,7 @@ namespace Server.Engines.Craft
AddCraft( typeof( LargeBattleAxe ), 1011082, 1025115, 28.0, 78.0, typeof( IronIngot ), 1044036, 12, 1044037 );
AddCraft( typeof( TwoHandedAxe ), 1011082, 1025187, 33.0, 83.0, typeof( IronIngot ), 1044036, 16, 1044037 );
AddCraft( typeof( WarAxe ), 1011082, 1025040, 39.1, 89.1, typeof( IronIngot ), 1044036, 16, 1044037 );
- /*
+
if( Core.ML )
{
index = AddCraft( typeof( OrnateAxe ), 1011082, 1031572, 70.0, 120.0, typeof( IronIngot ), 1044036, 18, 1044037 );
@@ -590,7 +590,7 @@ namespace Server.Engines.Craft
AddRecipe( index, 36 );
SetNeededExpansion( index, Expansion.ML );
- }*/
+ }
#endregion
#region Pole Arms
@@ -641,17 +641,17 @@ namespace Server.Engines.Craft
AddRes( index, typeof( Cloth ), 1044286, 10, 1044287 );
SetNeededExpansion( index, Expansion.SE );
}
- /*
+
if( Core.ML )
{
- index = AddCraft( typeof( DiamondMace ), 1011084, 1073568, 70.0, 120.0, typeof( IronIngot ), 1044036, 20, 1044037 );
+ index = AddCraft( typeof( DiamondMace ), 1011084, 1031556, 70.0, 120.0, typeof( IronIngot ), 1044036, 20, 1044037 );
SetNeededExpansion( index, Expansion.ML );
index = AddCraft( typeof( ShardThrasher ), 1011084, 1072918, 70.0, 120.0, typeof( IronIngot ), 1044036, 20, 1044037 );
AddRes( index, typeof( EyeOfTheTravesty ), 1073126, 1, 1042081 );
AddRes( index, typeof( Muculent ), 1072139, 10, 1042081 );
AddRes( index, typeof( Corruption ), 1072135, 10, 1042081 );
- AddRecipe( index, 37 );
+ AddRareRecipe( index, 37 );
ForceNonExceptional( index );
SetNeededExpansion( index, Expansion.ML );
@@ -674,7 +674,7 @@ namespace Server.Engines.Craft
AddRes( index, typeof( BlueDiamond ), 1032696, 1, 1044240 );
AddRecipe( index, 41 );
SetNeededExpansion( index, Expansion.ML );
- }*/
+ }
#endregion
#region Dragon Scale Armor
diff --git a/Scripts/Engines/Craft/DefBowFletching.cs b/Scripts/Engines/Craft/DefBowFletching.cs
index 2d267e278..b315e065e 100644
--- a/Scripts/Engines/Craft/DefBowFletching.cs
+++ b/Scripts/Engines/Craft/DefBowFletching.cs
@@ -126,6 +126,93 @@ namespace Server.Engines.Craft
SetNeededExpansion( index, Expansion.SE );
}
+ if ( Core.ML )
+ {
+ index = AddCraft( typeof( BlightGrippedLongbow ), 1044566, 1072907, 75.0, 125.0, typeof( Log ), 1044041, 20, 1044351 );
+ AddRes( index, typeof( LardOfParoxysmus ), 1032681, 1, 1053098 );
+ AddRes( index, typeof( Blight ), 1032675, 10, 1053098 );
+ AddRes( index, typeof( Corruption ), 1032676, 10, 1053098 );
+ AddRareRecipe( index, 200 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ /* TODO
+ index = AddCraft( typeof( FaerieFire ), 1044566, 1072908, 75.0, 125.0, typeof( Log ), 1044041, 20, 1044351 );
+ AddRes( index, typeof( LardOfParoxysmus ), 1032681, 1, 1053098 );
+ AddRes( index, typeof( Putrefication ), 1032678, 10, 1053098 );
+ AddRes( index, typeof( Taint ), 1032679, 10, 1053098 );
+ AddRareRecipe( index, 201 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+ */
+
+ index = AddCraft( typeof( SilvanisFeywoodBow ), 1044566, 1072955, 75.0, 125.0, typeof( Log ), 1044041, 20, 1044351 );
+ AddRes( index, typeof( LardOfParoxysmus ), 1032681, 1, 1053098 );
+ AddRes( index, typeof( Scourge ), 1032677, 10, 1053098 );
+ AddRes( index, typeof( Muculent ), 1032680, 10, 1053098 );
+ AddRareRecipe( index, 202 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ /* TODO
+ index = AddCraft( typeof( MischiefMaker ), 1044566, 1072910, 75.0, 125.0, typeof( Log ), 1044041, 15, 1044351 );
+ AddRes( index, typeof( DreadHornMane ), 1032682, 1, 1053098 );
+ AddRes( index, typeof( Corruption ), 1032676, 10, 1053098 );
+ AddRes( index, typeof( Putrefication ), 1032678, 10, 1053098 );
+ AddRareRecipe( index, 203 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+ */
+
+ index = AddCraft( typeof( TheNightReaper ), 1044566, 1072912, 75.0, 125.0, typeof( Log ), 1044041, 10, 1044351 );
+ AddRes( index, typeof( DreadHornMane ), 1032682, 1, 1053098 );
+ AddRes( index, typeof( Blight ), 1032675, 10, 1053098 );
+ AddRes( index, typeof( Scourge ), 1032677, 10, 1053098 );
+ AddRareRecipe( index, 204 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( BarbedLongbow ), 1044566, 1073505, 75.0, 125.0, typeof( Log ), 1044041, 20, 1044351 );
+ AddRes( index, typeof( FireRuby ), 1026254, 1, 1053098 );
+ AddRecipe( index, 205 );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( SlayerLongbow ), 1044566, 1073506, 75.0, 125.0, typeof( Log ), 1044041, 20, 1044351 );
+ AddRes( index, typeof( BrilliantAmber ), 1026256, 1, 1053098 );
+ AddRecipe( index, 206 );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( FrozenLongbow ), 1044566, 1073507, 75.0, 125.0, typeof( Log ), 1044041, 20, 1044351 );
+ AddRes( index, typeof( Turquoise ), 1026250, 1, 1053098 );
+ AddRecipe( index, 207 );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( LongbowOfMight ), 1044566, 1073508, 75.0, 125.0, typeof( Log ), 1044041, 10, 1044351 );
+ AddRes( index, typeof( BlueDiamond ), 1026255, 1, 1053098 );
+ AddRecipe( index, 208 );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( RangersShortbow ), 1044566, 1073509, 75.0, 125.0, typeof( Log ), 1044041, 15, 1044351 );
+ AddRes( index, typeof( PerfectEmerald ), 1026251, 1, 1053098 );
+ AddRecipe( index, 209 );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( LightweightShortbow ), 1044566, 1073510, 75.0, 125.0, typeof( Log ), 1044041, 15, 1044351 );
+ AddRes( index, typeof( WhitePearl ), 1026253, 1, 1053098 );
+ AddRecipe( index, 210 );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( MysticalShortbow ), 1044566, 1073511, 75.0, 125.0, typeof( Log ), 1044041, 15, 1044351 );
+ AddRes( index, typeof( EcruCitrine ), 1026252, 1, 1053098 );
+ AddRecipe( index, 211 );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( AssassinsShortbow ), 1044566, 1073512, 75.0, 125.0, typeof( Log ), 1044041, 15, 1044351 );
+ AddRes( index, typeof( DarkSapphire ), 1026249, 1, 1053098 );
+ AddRecipe( index, 212 );
+ SetNeededExpansion( index, Expansion.ML );
+ }
+
MarkOption = true;
Repair = Core.AOS;
}
diff --git a/Scripts/Engines/Craft/DefCarpentry.cs b/Scripts/Engines/Craft/DefCarpentry.cs
index 813ea7be2..7f307111a 100644
--- a/Scripts/Engines/Craft/DefCarpentry.cs
+++ b/Scripts/Engines/Craft/DefCarpentry.cs
@@ -97,6 +97,7 @@ namespace Server.Engines.Craft
AddCraft( typeof( ShortMusicStand ), 1044294, 1044313, 78.9, 103.9, typeof( Log ), 1044041, 15, 1044351 );
AddCraft( typeof( TallMusicStand ), 1044294, 1044315, 81.5, 106.5, typeof( Log ), 1044041, 20, 1044351 );
AddCraft( typeof( Easle ), 1044294, 1044317, 86.8, 111.8, typeof( Log ), 1044041, 20, 1044351 );
+
if( Core.SE )
{
index = AddCraft( typeof( RedHangingLantern ), 1044294, 1029412, 65.0, 90.0, typeof( Log ), 1044041, 5, 1044351 );
@@ -132,6 +133,33 @@ namespace Server.Engines.Craft
AddRes( index, typeof( RunedPrism ), 1073465, 1, 1053098 );
AddRes( index, typeof( JeweledFiligree ), 1072894, 1, 1053098 );
SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( WarriorStatueSouthDeed ), 1044294, 1072887, 0.0, 35.0, typeof( Log ), 1044041, 250, 1044351 );
+ AddRecipe( index, 300 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( WarriorStatueEastDeed ), 1044294, 1072888, 0.0, 35.0, typeof( Log ), 1044041, 250, 1044351 );
+ AddRecipe( index, 301 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( SquirrelStatueSouthDeed ), 1044294, 1072884, 0.0, 35.0, typeof( Log ), 1044041, 250, 1044351 );
+ AddRecipe( index, 302 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( SquirrelStatueEastDeed ), 1044294, 1073398, 0.0, 35.0, typeof( Log ), 1044041, 250, 1044351 );
+ AddRecipe( index, 303 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( AcidProofRope ), 1044294, 1074886, 80, 130.0, typeof( GreaterStrengthPotion ), 1073466, 2, 1044253 );
+ AddRes( index, typeof( ProtectionScroll ), 1044395, 1, 1053098 );
+ AddRes( index, typeof( SwitchItem ), 1032127, 1, 1053098 );
+ AddRecipe( index, 304 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
}
// Furniture
@@ -158,6 +186,13 @@ namespace Server.Engines.Craft
SetNeededExpansion( index, Expansion.SE );
}
+ if ( Core.ML )
+ {
+ index = AddCraft( typeof( OrnateElvenChair ), 1044291, 1072870, 80.0, 105.0, typeof( Log ), 1044041, 30, 1044351 );
+ AddRecipe( index, 305 );
+ SetNeededExpansion( index, Expansion.ML );
+ }
+
// Containers
AddCraft( typeof( WoodenBox ), 1044292, 1023709, 21.0, 46.0, typeof( Log ), 1044041, 10, 1044351 );
AddCraft( typeof( SmallCrate ), 1044292, 1044309, 10.0, 35.0, typeof( Log ), 1044041, 8 , 1044351 );
@@ -208,31 +243,124 @@ namespace Server.Engines.Craft
AddRes( index, typeof( BarrelHoops ), 1044289, 1, 1044253 );
AddRes( index, typeof( BarrelLid ), 1044251, 1, 1044253 );
+ if ( Core.ML )
+ {
+ index = AddCraft( typeof( ArcaneBookshelfSouthDeed ), 1044292, 1072871, 94.7, 119.7, typeof( Log ), 1044041, 80, 1044351 );
+ AddRecipe( index, 306 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( ArcaneBookshelfEastDeed ), 1044292, 1073371, 94.7, 119.7, typeof( Log ), 1044041, 80, 1044351 );
+ AddRecipe( index, 307 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ /* TODO
+ index = AddCraft( typeof( OrnateElvenChestSouthDeed ), 1044292, 1072862, 94.7, 119.7, typeof( Log ), 1044041, 40, 1044351 );
+ AddRecipe( index, 308 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( OrnateElvenChestEastDeed ), 1044292, 1073383, 94.7, 119.7, typeof( Log ), 1044041, 40, 1044351 );
+ AddRecipe( index, 309 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+ */
+
+ index = AddCraft( typeof( ElvenDresserSouthDeed ), 1044292, 1072864, 75.0, 100.0, typeof( Log ), 1044041, 45, 1044351 );
+ AddRecipe( index, 310 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( ElvenDresserEastDeed ), 1044292, 1073388, 75.0, 100.0, typeof( Log ), 1044041, 45, 1044351 );
+ AddRecipe( index, 311 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ /* TODO
+ index = AddCraft( typeof( FancyElvenArmoire ), 1044292, 1072866, 80.0, 105.0, typeof( Log ), 1044041, 60, 1044351 );
+ AddRecipe( index, 312 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+ */
+ }
+
// Staves and Shields
- AddCraft( typeof( ShepherdsCrook ), 1044295, 1023713, 78.9, 103.9, typeof( Log ), 1044041, 7, 1044351 );
- AddCraft( typeof( QuarterStaff ), 1044295, 1023721, 73.6, 98.6, typeof( Log ), 1044041, 6, 1044351 );
- AddCraft( typeof( GnarledStaff ), 1044295, 1025112, 78.9, 103.9, typeof( Log ), 1044041, 7, 1044351 );
- AddCraft( typeof( WoodenShield ), 1044295, 1027034, 52.6, 77.6, typeof( Log ), 1044041, 9, 1044351 );
+ AddCraft( typeof( ShepherdsCrook ), Core.ML ? 1044566 : 1044295, 1023713, 78.9, 103.9, typeof( Log ), 1044041, 7, 1044351 );
+ AddCraft( typeof( QuarterStaff ), Core.ML ? 1044566 : 1044295, 1023721, 73.6, 98.6, typeof( Log ), 1044041, 6, 1044351 );
+ AddCraft( typeof( GnarledStaff ), Core.ML ? 1044566 : 1044295, 1025112, 78.9, 103.9, typeof( Log ), 1044041, 7, 1044351 );
+ AddCraft( typeof( WoodenShield ), Core.ML ? 1062760 : 1044295, 1027034, 52.6, 77.6, typeof( Log ), 1044041, 9, 1044351 );
if( !Core.AOS ) //Duplicate Entries to preserve ordering depending on era
{
- index = AddCraft( typeof( FishingPole ), 1044295, 1023519, 68.4, 93.4, typeof( Log ), 1044041, 5, 1044351 ); //This is in the categor of Other during AoS
+ index = AddCraft( typeof( FishingPole ), Core.ML ? 1044294 : 1044295, 1023519, 68.4, 93.4, typeof( Log ), 1044041, 5, 1044351 ); //This is in the categor of Other during AoS
AddSkill( index, SkillName.Tailoring, 40.0, 45.0 );
AddRes( index, typeof( Cloth ), 1044286, 5, 1044287 );
}
if( Core.SE )
{
- index = AddCraft( typeof( Bokuto ), 1044295, 1030227, 70.0, 95.0, typeof( Log ), 1044041, 6, 1044351 );
+ index = AddCraft( typeof( Bokuto ), Core.ML ? 1044566 : 1044295, 1030227, 70.0, 95.0, typeof( Log ), 1044041, 6, 1044351 );
SetNeededExpansion( index, Expansion.SE );
- index = AddCraft( typeof( Fukiya ), 1044295, 1030229, 60.0, 85.0, typeof( Log ), 1044041, 6, 1044351 );
+ index = AddCraft( typeof( Fukiya ), Core.ML ? 1044566 : 1044295, 1030229, 60.0, 85.0, typeof( Log ), 1044041, 6, 1044351 );
SetNeededExpansion( index, Expansion.SE );
- index = AddCraft( typeof( Tetsubo ), 1044295, 1030225, 80.0, 140.3, typeof( Log ), 1044041, 10, 1044351 );
+ index = AddCraft( typeof( Tetsubo ), Core.ML ? 1044566 : 1044295, 1030225, 80.0, 140.3, typeof( Log ), 1044041, 10, 1044351 );
SetNeededExpansion( index, Expansion.SE );
}
+ if ( Core.ML )
+ {
+ index = AddCraft( typeof( PhantomStaff ), 1044566, 1072919, 90.0, 130.0, typeof( Log ), 1044041, 16, 1044351 );
+ AddRes( index, typeof( DiseasedBark ), 1032683, 1, 1053098 );
+ AddRes( index, typeof( Putrefication ), 1032678, 10, 1053098 );
+ AddRes( index, typeof( Taint ), 1032679, 10, 1053098 );
+ AddRareRecipe( index, 313 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( ArcanistsWildStaff ), 1044566, 1073549, 63.8, 113.8, typeof( Log ), 1044041, 16, 1044351 );
+ AddRes( index, typeof( WhitePearl ), 1026253, 1, 1053098 );
+ AddRecipe( index, 314 );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( AncientWildStaff ), 1044566, 1073550, 63.8, 113.8, typeof( Log ), 1044041, 16, 1044351 );
+ AddRes( index, typeof( PerfectEmerald ), 1026251, 1, 1053098 );
+ AddRecipe( index, 315 );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( ThornedWildStaff ), 1044566, 1073551, 63.8, 113.8, typeof( Log ), 1044041, 16, 1044351 );
+ AddRes( index, typeof( FireRuby ), 1026254, 1, 1053098 );
+ AddRecipe( index, 316 );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( HardenedWildStaff ), 1044566, 1073552, 63.8, 113.8, typeof( Log ), 1044041, 16, 1044351 );
+ AddRes( index, typeof( Turquoise ), 1026250, 1, 1053098 );
+ AddRecipe( index, 317 );
+ SetNeededExpansion( index, Expansion.ML );
+ }
+
+ // Armor
+ if ( Core.ML )
+ {
+ index = AddCraft( typeof( IronwoodCrown ), 1062760, 1072924, 85.0, 120.0, typeof( Log ), 1044041, 10, 1044351 );
+ AddRes( index, typeof( DiseasedBark ), 1032683, 1, 1053098 );
+ AddRes( index, typeof( Corruption ), 1032676, 10, 1053098 );
+ AddRes( index, typeof( Putrefication ), 1032678, 10, 1053098 );
+ AddRareRecipe( index, 318 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( BrambleCoat ), 1062760, 1072925, 85.0, 120.0, typeof( Log ), 1044041, 10, 1044351 );
+ AddRes( index, typeof( DiseasedBark ), 1032683, 1, 1053098 );
+ AddRes( index, typeof( Taint ), 1032679, 10, 1053098 );
+ AddRes( index, typeof( Scourge ), 1032677, 10, 1053098 );
+ AddRareRecipe( index, 319 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+ }
+
// Instruments
index = AddCraft( typeof( LapHarp ), 1044293, 1023762, 63.1, 88.1, typeof( Log ), 1044041, 20, 1044351 );
AddSkill( index, SkillName.Musicianship, 45.0, 50.0 );
@@ -265,6 +393,23 @@ namespace Server.Engines.Craft
SetNeededExpansion( index, Expansion.SE );
}
+ if ( Core.ML )
+ {
+ index = AddCraft( typeof( TallElvenBedSouthDeed ), 1044290, 1072858, 94.7, 119.7, typeof( Log ), 1044041, 200, 1044351 );
+ AddSkill( index, SkillName.Tailoring, 75.0, 80.0 );
+ AddRes( index, typeof( Cloth ), 1044286, 100, 1044287 );
+ AddRecipe( index, 320 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( TallElvenBedEastDeed ), 1044290, 1072859, 94.7, 119.7, typeof( Log ), 1044041, 200, 1044351 );
+ AddSkill( index, SkillName.Tailoring, 75.0, 80.0 );
+ AddRes( index, typeof( Cloth ), 1044286, 100, 1044287 );
+ AddRecipe( index, 321 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+ }
+
// Misc
index = AddCraft( typeof( SmallBedSouthDeed ), 1044290, 1044321, 94.7, 119.8, typeof( Log ), 1044041, 100, 1044351 );
AddSkill( index, SkillName.Tailoring, 75.0, 80.0 );
@@ -294,7 +439,7 @@ namespace Server.Engines.Craft
AddCraft( typeof( PlayerBBSouth ), 1044290, 1062421, 85.0, 110.0, typeof( Log ), 1044041, 50, 1044351 );
}
- // Blacksmithy
+ // Blacksmithy - This changed to Anvils and Forges (1111809) for SA
index = AddCraft( typeof( SmallForgeDeed ), 1044296, 1044330, 73.6, 98.6, typeof( Log ), 1044041, 5, 1044351 );
AddSkill( index, SkillName.Blacksmith, 75.0, 80.0 );
AddRes( index, typeof( IronIngot ), 1044036, 75, 1044037 );
@@ -343,20 +488,20 @@ namespace Server.Engines.Craft
AddRes( index, typeof( Cloth ), 1044286, 25, 1044287 );
// Cooking
- index = AddCraft( typeof( StoneOvenEastDeed ), 1044299, 1044345, 68.4, 93.4, typeof( Log ), 1044041, 85, 1044351 );
+ index = AddCraft( typeof( StoneOvenEastDeed ), Core.ML ? 1044298 : 1044299, 1044345, 68.4, 93.4, typeof( Log ), 1044041, 85, 1044351 );
AddSkill( index, SkillName.Tinkering, 50.0, 55.0 );
AddRes( index, typeof( IronIngot ), 1044036, 125, 1044037 );
- index = AddCraft( typeof( StoneOvenSouthDeed ), 1044299, 1044346, 68.4, 93.4, typeof( Log ), 1044041, 85, 1044351 );
+ index = AddCraft( typeof( StoneOvenSouthDeed ), Core.ML ? 1044298 : 1044299, 1044346, 68.4, 93.4, typeof( Log ), 1044041, 85, 1044351 );
AddSkill( index, SkillName.Tinkering, 50.0, 55.0 );
AddRes( index, typeof( IronIngot ), 1044036, 125, 1044037 );
- index = AddCraft( typeof( FlourMillEastDeed ), 1044299, 1044347, 94.7, 119.7, typeof( Log ), 1044041, 100, 1044351 );
+ index = AddCraft( typeof( FlourMillEastDeed ), Core.ML ? 1044298 : 1044299, 1044347, 94.7, 119.7, typeof( Log ), 1044041, 100, 1044351 );
AddSkill( index, SkillName.Tinkering, 50.0, 55.0 );
AddRes( index, typeof( IronIngot ), 1044036, 50, 1044037 );
- index = AddCraft( typeof( FlourMillSouthDeed ), 1044299, 1044348, 94.7, 119.7, typeof( Log ), 1044041, 100, 1044351 );
+ index = AddCraft( typeof( FlourMillSouthDeed ), Core.ML ? 1044298 : 1044299, 1044348, 94.7, 119.7, typeof( Log ), 1044041, 100, 1044351 );
AddSkill( index, SkillName.Tinkering, 50.0, 55.0 );
AddRes( index, typeof( IronIngot ), 1044036, 50, 1044037 );
- AddCraft( typeof( WaterTroughEastDeed ), 1044299, 1044349, 94.7, 119.7, typeof( Log ), 1044041, 150, 1044351 );
- AddCraft( typeof( WaterTroughSouthDeed ), 1044299, 1044350, 94.7, 119.7, typeof( Log ), 1044041, 150, 1044351 );
+ AddCraft( typeof( WaterTroughEastDeed ), Core.ML ? 1044298 : 1044299, 1044349, 94.7, 119.7, typeof( Log ), 1044041, 150, 1044351 );
+ AddCraft( typeof( WaterTroughSouthDeed ), Core.ML ? 1044298 : 1044299, 1044350, 94.7, 119.7, typeof( Log ), 1044041, 150, 1044351 );
MarkOption = true;
Repair = Core.AOS;
diff --git a/Scripts/Engines/Craft/DefInscription.cs b/Scripts/Engines/Craft/DefInscription.cs
index 2a262d813..9fba6060d 100644
--- a/Scripts/Engines/Craft/DefInscription.cs
+++ b/Scripts/Engines/Craft/DefInscription.cs
@@ -293,9 +293,8 @@ namespace Server.Engines.Craft
AddNecroSpell(16, 40, 79.6, typeof(ExorcismScroll), Reagent.NoxCrystal, Reagent.GraveDust);
}
-
int index;
-
+
if ( Core.ML )
{
index = AddCraft( typeof( EnchantedSwitch ), 1044294, 1072893, 45.0, 95.0, typeof( BlankScroll ), 1044377, 1, 1044378 );
@@ -312,7 +311,7 @@ namespace Server.Engines.Craft
ForceNonExceptional( index );
SetNeededExpansion( index, Expansion.ML );
}
-
+
// Runebook
index = AddCraft( typeof( Runebook ), 1044294, 1041267, 45.0, 95.0, typeof( BlankScroll ), 1044377, 8, 1044378 );
AddRes( index, typeof( RecallScroll ), 1044445, 1, 1044253 );
@@ -328,6 +327,19 @@ namespace Server.Engines.Craft
AddCraft(typeof(Spellbook), 1044294, 1023834, 50.0, 126, typeof(BlankScroll), 1044377, 10, 1044378);
}
+ /* TODO
+ if ( Core.ML )
+ {
+ index = AddCraft( typeof( ScrappersCompendium ), 1044294, 1072940, 75.0, 125.0, typeof( BlankScroll ), 1044377, 100, 1044378 );
+ AddRes( index, typeof( DreadHornMane ), 1032682, 1, 1044253 );
+ AddRes( index, typeof( Taint ), 1032679, 10, 1044253 );
+ AddRes( index, typeof( Corruption ), 1032676, 10, 1044253 );
+ AddRareRecipe( index, 400 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+ }
+ */
+
MarkOption = true;
}
}
diff --git a/Scripts/Engines/Craft/DefTailoring.cs b/Scripts/Engines/Craft/DefTailoring.cs
index f926b49f3..c48c0d741 100644
--- a/Scripts/Engines/Craft/DefTailoring.cs
+++ b/Scripts/Engines/Craft/DefTailoring.cs
@@ -271,6 +271,33 @@ namespace Server.Engines.Craft
#region Leather Armor
+ if ( Core.ML )
+ {
+ index = AddCraft( typeof( SpellWovenBritches ), 1015293, 1072929, 92.5, 117.5, typeof( Leather ), 1044462, 15, 1044463 );
+ AddRes( index, typeof( EyeOfTheTravesty ), 1032685, 1, 1044253 );
+ AddRes( index, typeof( Putrefication ), 1032678, 10, 1044253 );
+ AddRes( index, typeof( Scourge ), 1032677, 10, 1044253 );
+ AddRareRecipe( index, 506 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( SongWovenMantle ), 1015293, 1072931, 92.5, 117.5, typeof( Leather ), 1044462, 15, 1044463 );
+ AddRes( index, typeof( EyeOfTheTravesty ), 1032685, 1, 1044253 );
+ AddRes( index, typeof( Blight ), 1032675, 10, 1044253 );
+ AddRes( index, typeof( Muculent ), 1032680, 10, 1044253 );
+ AddRareRecipe( index, 507 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( StitchersMittens ), 1015293, 1072932, 92.5, 117.5, typeof( Leather ), 1044462, 15, 1044463 );
+ AddRes( index, typeof( CapturedEssence ), 1032686, 1, 1044253 );
+ AddRes( index, typeof( Corruption ), 1032676, 10, 1044253 );
+ AddRes( index, typeof( Taint ), 1032679, 10, 1044253 );
+ AddRareRecipe( index, 508 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+ }
+
AddCraft( typeof( LeatherGorget ), 1015293, 1025063, 53.9, 78.9, typeof( Leather ), 1044462, 4, 1044463 );
AddCraft( typeof( LeatherCap ), 1015293, 1027609, 6.2, 31.2, typeof( Leather ), 1044462, 2, 1044463 );
AddCraft( typeof( LeatherGloves ), 1015293, 1025062, 51.8, 76.8, typeof( Leather ), 1044462, 3, 1044463 );
diff --git a/Scripts/Engines/Craft/DefTinkering.cs b/Scripts/Engines/Craft/DefTinkering.cs
index b8a78e662..79d3ced6c 100644
--- a/Scripts/Engines/Craft/DefTinkering.cs
+++ b/Scripts/Engines/Craft/DefTinkering.cs
@@ -295,8 +295,7 @@ namespace Server.Engines.Craft
AddRes( index, typeof( Bottle ), 1044250, 10, 1044253 );
AddRes( index, typeof( BarrelLid ), 1044251, 1, 1044253 );
AddRes( index, typeof( BarrelTap ), 1044252, 1, 1044253 );
-
-
+
#endregion
#region Traps
@@ -337,6 +336,34 @@ namespace Server.Engines.Craft
AddRes( index, typeof( IronIngot ), 1044036, 10, 1044037 );
#endregion
+ // Magic Jewelry
+ if ( Core.ML )
+ {
+ index = AddCraft( typeof( ResilientBracer ), 1073107, 1072933, 100.0, 125.0, typeof( IronIngot ), 1044036, 2, 1044037 );
+ AddRes( index, typeof( CapturedEssence ), 1032686, 1, 1044253 );
+ AddRes( index, typeof( BlueDiamond ), 1032696, 10, 1044253 );
+ AddRes( index, typeof( Diamond ), 1062608, 50, 1044253 );
+ AddRareRecipe( index, 600 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( EssenceOfBattle ), 1073107, 1072935, 100.0, 125.0, typeof( IronIngot ), 1044036, 2, 1044037 );
+ AddRes( index, typeof( CapturedEssence ), 1032686, 1, 1044253 );
+ AddRes( index, typeof( FireRuby ), 1032695, 10, 1044253 );
+ AddRes( index, typeof( Ruby ), 1062603, 50, 1044253 );
+ AddRareRecipe( index, 601 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+
+ index = AddCraft( typeof( PendantOfTheMagi ), 1073107, 1072937, 100.0, 125.0, typeof( IronIngot ), 1044036, 2, 1044037 );
+ AddRes( index, typeof( EyeOfTheTravesty ), 1032685, 1, 1044253 );
+ AddRes( index, typeof( WhitePearl ), 1032694, 10, 1044253 );
+ AddRes( index, typeof( StarSapphire ), 1062600, 50, 1044253 );
+ AddRareRecipe( index, 602 );
+ ForceNonExceptional( index );
+ SetNeededExpansion( index, Expansion.ML );
+ }
+
// Set the overridable material
SetSubRes( typeof( IronIngot ), 1044022 );
diff --git a/Scripts/Engines/MLQuests/Definitions/AGhostOfCovetous.cs b/Scripts/Engines/MLQuests/Definitions/AGhostOfCovetous.cs
new file mode 100644
index 000000000..160d2fede
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/AGhostOfCovetous.cs
@@ -0,0 +1,295 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.ContextMenus;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Misc;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Quests
+
+ public class AGhostOfCovetous : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( SaveHisDad ); } }
+
+ public AGhostOfCovetous()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1075287; // A Ghost of Covetous
+ Description = 1075286; // What? Oh, you startled me! Sorry, I'm a little jumpy. My master Griswolt learned that a ghost has recently taken up residence in the Covetous dungeon. He sent me to capture it, but I . . . well, it terrified me, to be perfectly honest. If you think yourself courageous enough, I'll give you my Spirit Bottle, and you can try to capture it yourself. I'm certain my master would reward you richly for such service.
+ RefusalMessage = 1075288; // That's okay, I'm sure someone with more courage than either of us will come along eventually.
+ InProgressMessage = 1075290; // You'll find that ghost in the mountain pass above the Covetous dungeon.
+ 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!
+
+ Objectives.Add( new DeliverObjective( typeof( SpiritBottle ), 1, 1075283, typeof( Frederic ), "The Ghost of Frederic Smithson" ) ); // Spirit bottle
+
+ Rewards.Add( new DummyReward( 1075284 ) ); // Return the filled Spirit Bottle to Griswolt the Master Necromancer to receive a reward.
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Ben" ), new Point3D( 2467, 402, 15 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Ben" ), new Point3D( 2467, 402, 15 ), Map.Felucca );
+ }
+ }
+
+ public class SaveHisDad : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( AFathersGratitude ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public SaveHisDad()
+ {
+ Activated = true;
+ Title = 1075337; // Save His Dad
+ Description = 1075338; // My father, Andros, is a smith in Minoc. Last week his forge overturned and he was splashed by molten steel. He was horribly burned, and we feared he would die. An alchemist in Vesper promised to make a bandage that could heal him, but he needed the silk of a dread spider. I came here to get some, but I was careless, and succumbed to their poison. Please, won’t you help my father?
+ RefusalMessage = 1075340; // Oh . . . that’s your decision . . . OooOoooOOoo . . .
+ InProgressMessage = 1075341; // Thank you! Deliver it to Leon the Alchemist in Vesper. The silk crumbles easily, and much time has already passed since I died. Please! Hurry!
+ 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?
+
+ Objectives.Add( new TimedDeliverObjective( TimeSpan.FromSeconds( 600 ), typeof( DreadSpiderSilk ), 1, 1075319, typeof( Leon ), "Leon" ) ); // Dread Spider Silk
+
+ Rewards.Add( new DummyReward( 1075339 ) ); // Hurry! You must get the silk to Leon the Alchemist quickly, or it will crumble and become useless!
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Frederic" ), new Point3D( 2415, 887, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Frederic" ), new Point3D( 2415, 887, 0 ), Map.Felucca );
+ }
+ }
+
+ public class AFathersGratitude : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public AFathersGratitude()
+ {
+ Activated = true;
+ Title = 1075343; // A Father’s Gratitude
+ Description = 1075344; // That is simply terrible. First Andros, and now his son. Well, let’s make sure Frederic’s sacrifice wasn’t in vain. Will you take the bandages to his father? You can probably deliver them faster than I can, can’t you?
+ RefusalMessage = 1075346; // Well I’m sorry to hear you say that. Without your help, I don’t know if I can get these to Andros quickly enough to help him.
+ InProgressMessage = 1075347; // I don’t know how much longer Andros will survive. You’d better get this to him as quick as you can. Every second counts!
+ CompletionMessage = 1075348; // Sorry, I’m not accepting commissions at the moment. What? You have the bandage I need from Leon? Thank you so much! But why didn’t 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.
+
+ Objectives.Add( new DeliverObjective( typeof( AlchemistsBandage ), 1, 1075452, typeof( Andros ), "Andros" ) ); // Alchemist's Bandage
+
+ Rewards.Add( new ItemReward( 1075345, typeof( AndrosGratitude ) ) ); // Andros’ Gratitude
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Leon" ), new Point3D( 2918, 851, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Leon" ), new Point3D( 2918, 851, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Andros" ), new Point3D( 2531, 581, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Andros" ), new Point3D( 2531, 581, 0 ), Map.Felucca );
+ }
+ }
+
+ #endregion
+
+ #region Mobiles
+
+ public class Ben : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Ben()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Ben";
+ Title = "the Apprentice Necromancer";
+ BodyValue = 0x190;
+ Hue = 0x83FD;
+ HairItemID = 0x2048;
+ HairHue = 0x463;
+ FacialHairItemID = 0x204C;
+ FacialHairHue = 0x463;
+
+ InitStats( 100, 100, 25 );
+
+ AddItem( new Backpack() );
+ AddItem( new Shoes( 0x901 ) );
+ AddItem( new LongPants( 0x1BB ) );
+ AddItem( new FancyShirt( 0x756 ) );
+
+ }
+
+ public Ben( 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 class Frederic : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Frederic()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "The Ghost of Frederic Smithson";
+ BodyValue = 0x1A;
+ Hue = 0x455;
+ Frozen = true;
+
+ InitStats( 100, 100, 25 );
+
+ }
+
+ public Frederic( 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 class Leon : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Leon()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Leon";
+ Title = "the Alchemist";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Shoes( 0x901 ) );
+ AddItem( new Robe( 0x657 ) );
+
+ }
+
+ public Leon( 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 class Andros : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Andros()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Andros";
+ Title = "the Blacksmith";
+ BodyValue = 0x190;
+ Hue = 0x8409;
+ FacialHairItemID = 0x2041;
+ FacialHairHue = 0x45E;
+ HairItemID = 0x2049;
+ HairHue = 0x45E;
+
+ InitStats( 100, 100, 25 );
+
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x901 ) );
+ AddItem( new FancyShirt( 0x60B ) );
+ AddItem( new LongPants( 0x1BB ) );
+ AddItem( new FullApron( 0x901 ) );
+ AddItem( new SmithHammer() );
+
+ }
+
+ public Andros( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/BaseEscort.cs b/Scripts/Engines/MLQuests/Definitions/BaseEscort.cs
new file mode 100644
index 000000000..cad021951
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/BaseEscort.cs
@@ -0,0 +1,28 @@
+using System;
+using Server;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ // Base class for escorts providing the AwardHumanInNeed option
+ public class BaseEscort : MLQuest
+ {
+ public virtual bool AwardHumanInNeed { get { return true; } }
+
+ public BaseEscort()
+ {
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ if ( AwardHumanInNeed )
+ HumanInNeed.AwardTo( instance.Player );
+
+ base.GetRewards( instance );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/BlightedGrove.cs b/Scripts/Engines/MLQuests/Definitions/BlightedGrove.cs
new file mode 100644
index 000000000..e2ce7bf48
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/BlightedGrove.cs
@@ -0,0 +1,273 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server.Mobiles;
+using Server.Items;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Quests
+
+ public class VilePoison : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( ARockAndAHardPlace ); } }
+
+ public VilePoison()
+ {
+ Activated = true;
+ Title = 1074950; // Vile Poison
+ Description = 1074956; // Heya! I'm sure glad to see you. Listen I'm in a bit of a bind here. I'm supposed to be gathering poisoned water at the base of that corrupted tree there, but I can't get in under the roots to get a good sample. The branches and brush are so tainted that they can't be cut, burned or even magically passed. It's put my work at a real standstill. If you help me out, I'll help you get in there too. Whadda ya say?
+ RefusalMessage = 1074964; // Okay. If you change your mind, I'll probably still be stuck here trying to get in.
+ 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)" ) );
+
+ Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Jamal" ), new Point3D( 559, 1651, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Jamal" ), new Point3D( 559, 1651, 0 ), Map.Trammel );
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 2, "Iosep" ), new Point3D( 1354, 3754, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 2, "Iosep" ), new Point3D( 1354, 3754, 0 ), Map.Trammel );
+ }
+ }
+
+ public class ARockAndAHardPlace : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( SympatheticMagic ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public ARockAndAHardPlace()
+ {
+ Activated = true;
+ Title = 1074951; // A Rock and a Hard Place
+ Description = 1074957; // This is some nasty stuff, that's for certain. I don't even want to think about what sort of blight caused this venomous reaction from that old tree. Let's get to work … we'll need to try something really hard but still workable as our base material. Nothing's harder than stone and diamond. Let's try them first.
+ RefusalMessage = 1074965; // Sure, no problem. I thought you were interested in figuring this out.
+ InProgressMessage = 1074969; // If you're a miner, you should have no trouble getting that stuff. If not, you can probably buy some samples from a miner?
+ CompletionMessage = 1074992; // Have you got the granite and diamonds? Great, let me see them and we'll see what effect this venom has upon them.
+
+ // Any type of granite works
+ Objectives.Add( new CollectObjective( 4, typeof( BaseGranite ), 1026009 ) ); // rock
+ Objectives.Add( new CollectObjective( 2, typeof( BlueDiamond ), 1032696 ) ); // Blue Diamond
+
+ Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove.
+ }
+ }
+
+ public class SympatheticMagic : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( AlreadyDead ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public SympatheticMagic()
+ {
+ Activated = true;
+ Title = 1074952; // Sympathetic Magic
+ Description = 1074958; // Hmm, I've never even heard of something that can damage diamond like that. I guess we'll have to go with plan B. Let's try something similar. Sometimes there's a natural immunity to be found when you use a substance that's like the one you're trying to cut. A sort of "sympathetic" thing. Y'know?
+ RefusalMessage = 1074965; // Sure, no problem. I thought you were interested in figuring this out.
+ InProgressMessage = 1074970; // I think a lumberjack can help supply bark.
+ CompletionMessage = 1074993; // You're back with the bark already? Terrific! I bet this will do the trick.
+
+ Objectives.Add( new CollectObjective( 10, typeof( BarkFragment ), 1032687 ) ); // Bark Fragment
+
+ Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove.
+ }
+ }
+
+ public class AlreadyDead : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( Eureka ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public AlreadyDead()
+ {
+ Activated = true;
+ Title = 1074953; // Already Dead
+ Description = 1074959; // Amazing! The bark was reduced to ash in seconds. Whatever this taint is, it plays havok with living things. And of course, it took the edge off both diamonds and granite even faster. What we need is something workable but dead; something that can hold an edge without melting. See what you can come up with, please.
+ RefusalMessage = 1074965; // Sure, no problem. I thought you were interested in figuring this out.
+ InProgressMessage = 1074971; // I'm thinking we need something fairly brittle or it won't hold an edge. And, it can't be alive, of course.
+ CompletionMessage = 1074994; // Great thought! Bone might just do the trick.
+
+ Objectives.Add( new InternalObjective() );
+
+ Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove.
+ }
+
+ private class InternalObjective : CollectObjective
+ {
+ public override bool ShowDetailed { get { return false; } }
+
+ public InternalObjective()
+ : base( 10, typeof( Bone ), 1074963 ) // (10) workable samples
+ {
+ }
+ }
+ }
+
+ public class Eureka : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( SubContracting ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public Eureka()
+ {
+ Activated = true;
+ Title = 1074954; // Eureka!
+ Description = 1074960; // We're in business! I've put together the instructions for chopping sort of sword, in the style of one of those new-fangled elven machetes. Take those back to Jamal for me, if you would.
+ RefusalMessage = 1074966; // Well, okay. I guess I thought you'd want to see this through.
+ 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)" ) );
+
+ Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ PlayerMobile pm = instance.Player;
+
+ if ( !pm.HasRecipe( 32 ) )
+ {
+ // The ability is awarded regardless of blacksmithy skill
+ pm.AcquireRecipe( 32 );
+
+ if ( pm.Skills[SkillName.Blacksmith].Base < 45.0 ) // TODO: Verify threshold
+ pm.SendLocalizedMessage( 1075005 ); // You observe carefully but you can't grasp the complexities of smithing a bone handled machete.
+ else
+ pm.SendLocalizedMessage( 1075006 ); // You have learned how to smith a bone handled machete!
+ }
+
+ base.GetRewards( instance );
+ }
+ }
+
+ public class SubContracting : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public SubContracting()
+ {
+ Activated = true;
+ Title = 1074955; // Sub Contracting
+ Description = 1074961; // Wonderful! Now we can both get in there! Let me show you these instructions for making this machete. If you're not skilled in smithing, I'm not sure how much sense it will make though. Listen, if you're heading in there anyway … maybe you'd do me one more favor? I'm ah ... buried in work out here ... so if you'd go in and get me a few water samples, I'd be obliged.
+ RefusalMessage = 1074967; // Oh. Right, I guess you're really ... ah ... busy too.
+ InProgressMessage = 1074973; // Once you're inside, look for places where the water has twisted and warped the natural creatures.
+ CompletionMessage = 1074996; // I hear sloshing ... that must mean you've got my water samples. Whew, I'm so glad you braved the dangers in there ... I mean, I would have but I'm so busy out here. Here's your reward!
+
+ Objectives.Add( new CollectObjective( 3, typeof( SamplesOfCorruptedWater ), "samples of corrupted water" ) ); // On OSI the label is "#1074999"
+ // TODO: "Return to" should say "Jamal (near Blighted Grove)"
+ // Maybe every quest NPC has directions as a property?
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ #endregion
+
+ #region Mobiles
+
+ public class Jamal : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Jamal()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.2, 0.4 )
+ {
+ Name = "Jamal";
+ Title = "the Fisherman";
+ Body = 400;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this );
+ Utility.AssignRandomFacialHair( this, HairHue );
+
+ AddItem( new Shirt( 0x1BB ) );
+ AddItem( new ShortPants( Utility.RandomNeutralHue() ) );
+ AddItem( new ThighBoots( Utility.RandomAnimalHue() ) );
+ AddItem( new Backpack() );
+ }
+
+ public Jamal( 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 );
+
+ reader.ReadInt();
+ }
+ }
+
+ public class Iosep : BaseCreature
+ {
+ // TODO: EmbracingHumanity
+
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074209, // Hey, could you help me out with something?
+ 1074215 // Don’t test my patience you sniveling worm!
+ ) );
+ }
+
+ [Constructable]
+ public Iosep()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.2, 0.4 )
+ {
+ Name = "Iosep";
+ Title = "the Exporter";
+ Body = 400;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ AddItem( new FancyShirt( Utility.RandomBlueHue() ) );
+ AddItem( new LongPants( 0x1BB ) );
+ AddItem( new Shoes( Utility.RandomNeutralHue() ) );
+ AddItem( new Backpack() );
+ }
+
+ public Iosep( 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 );
+
+ reader.ReadInt();
+ }
+ }
+
+ #endregion
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/Britannia.cs b/Scripts/Engines/MLQuests/Definitions/Britannia.cs
new file mode 100644
index 000000000..e09af0c96
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/Britannia.cs
@@ -0,0 +1,204 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.ContextMenus;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Misc;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Quests
+
+ public class Aemaeth1 : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( Aemaeth2 ); } }
+
+ public Aemaeth1()
+ {
+ Activated = true;
+ Title = 1075321; // Aemaeth
+ Description = 1075322; // My father died in an accident some months ago. My mother refused to accept his death. We had a little money set by, and she took it to a necromancer, who promised to restore my father to life. Well, he revived my father, all right, the cheat! Now my father is a walking corpse, a travesty . . . a monster. My mother is beside herself -- she won't eat, she can't sleep. I prayed at the shrine of Spirituality for guidance, and I must have fallen asleep. When I awoke, there was this basin of clear water. I cannot leave my mother, for I fear what she might do to herself. Could you take this to the graveyard, and give it to what is left of my father?
+ RefusalMessage = 1075324; // Oh! Alright then. I hope someone comes along soon who can help me, or I dont know what will become of us.
+ InProgressMessage = 1075325; // My father - or what remains of him - can be found in the graveyard northwest of the city.
+ CompletionMessage = 1075326; // What is this you give me? A basin of water?
+
+ Objectives.Add( new DeliverObjective( typeof( BasinOfCrystalClearWater ), 1, 1075303, typeof( SkeletonOfSzandor ), "Szandor" ) );
+
+ Rewards.Add( new DummyReward( 1075323 ) ); // Aurelia's gratitude.
+ }
+
+ public override bool CanOffer( BaseCreature quester, PlayerMobile pm )
+ {
+ if ( !base.CanOffer( quester, pm ) )
+ return false;
+
+ MLQuestContext context = MLQuestSystem.GetContext( pm );
+
+ // This quest can be repeated, but only while the next quest has not been completed.
+ if ( context != null && context.HasDoneQuest( NextQuest ) )
+ {
+ MLQuestSystem.Tell( quester, pm, 1075454 ); // I cannot offer you the quest again.
+ return false;
+ }
+
+ return true;
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Aurelia" ), new Point3D( 1459, 3795, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Aurelia" ), new Point3D( 1459, 3795, 0 ), Map.Felucca );
+ }
+ }
+
+ public class Aemaeth2 : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public Aemaeth2()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1075327; // Aemaeth
+ Description = 1075328; // You tell me it is time to leave this flesh. I did not understand until now. I thought: I can see my wife and my daughter, I can speak. Is this not life? But now, as I regard my reflection, I see what I have become. This only a mockery of life. Thank you for having the courage to show me the truth. For the love I bear my wife and daughter, I know now that I must pass beyond the veil. Will you return this basin to Aurelia? She will know by this that I am at rest.
+ RefusalMessage = 1075330; // You wont take this back to my daughter? Please, I cannot leave until she knows I am at peace.
+ InProgressMessage = 1075331; // My daughter will be at my home, on the east side of the city.
+ 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.
+
+ Objectives.Add( new DeliverObjective( typeof( BasinOfCrystalClearWater ), 1, 1075303, typeof( Aurelia ), "Aurelia" ) );
+
+ Rewards.Add( new ItemReward( 1075304, typeof( MirrorOfPurification ) ) );
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 2, "SkeletonOfSzandor" ), new Point3D( 1277, 3731, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 2, "SkeletonOfSzandor" ), new Point3D( 1277, 3731, 0 ), Map.Felucca );
+ }
+ }
+
+ public class OddsAndEnds : MLQuest
+ {
+ public OddsAndEnds()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1074354; // Odds and Ends
+ Description = 1074677; // I've always been fascinated by primitive cultures -- especially the artifacts. I'm a collector, you see. I'm working on building my troglodyte display and I'm saddened to say that I'm short on examples of religion and superstition amongst the creatures. If you come across any primitive fetishes, I'd be happy to trade you something interesting for them.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1074678; // I don't really want to know where you get the primitive fetishes, as I can't support the destruction of their lifestyle and culture. That would be wrong.
+ CompletionMessage = 1074679; // Bravo! These fetishes are just what I needed. You've earned this reward.
+
+ Objectives.Add( new CollectObjective( 12, typeof( PrimitiveFetish ), 1151986 ) ); // Primitive Fetishes
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ #endregion
+
+ #region Mobiles
+
+ public class Aurelia : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Aurelia()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Aurelia";
+ Title = "the Architect's Daughter";
+ Race = Race.Human;
+ BodyValue = 0x191;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Sandals( Utility.RandomPinkHue() ) );
+
+ if ( Utility.RandomBool() )
+ AddItem( new Kilt( Utility.RandomPinkHue() ) );
+ else
+ AddItem( new Skirt( Utility.RandomPinkHue() ) );
+
+ AddItem( new FancyShirt( Utility.RandomRedHue() ) );
+ }
+
+ public Aurelia( 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 class SkeletonOfSzandor : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public SkeletonOfSzandor()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Skeleton of Szandor";
+ Title = "the Late Architect";
+ Hue = 0x83F2; // TODO: Random human hue? Why???
+ Body = 0x32;
+ InitStats( 100, 100, 25 );
+ }
+
+ public SkeletonOfSzandor( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/Heartwood.cs b/Scripts/Engines/MLQuests/Definitions/Heartwood.cs
new file mode 100644
index 000000000..453a65542
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/Heartwood.cs
@@ -0,0 +1,4501 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.ContextMenus;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Misc;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Quests
+
+ public class TheyreBreedingLikeRabbits : MLQuest
+ {
+ public TheyreBreedingLikeRabbits()
+ {
+ Activated = true;
+ Title = 1072244; // They're Breeding Like Rabbits
+ Description = 1072259; // Aaaahhhh! They're everywhere! Aaaaahhh! Ahem. Actually, friend, how do you feel about rabbits? Well, we're being overrun by them. We're finding fuzzy bunnies everywhere. Aaaaahhh!
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Rabbit ) }, "rabbits" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Saril" ), new Point3D( 7075, 376, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Saril" ), new Point3D( 7075, 376, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Cailla" ), new Point3D( 7075, 377, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Cailla" ), new Point3D( 7075, 377, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Tamm" ), new Point3D( 7075, 378, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Tamm" ), new Point3D( 7075, 378, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Landy" ), new Point3D( 7089, 390, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Landy" ), new Point3D( 7089, 390, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Alejaha" ), new Point3D( 7043, 387, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Alejaha" ), new Point3D( 7043, 387, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Mielan" ), new Point3D( 7063, 350, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Mielan" ), new Point3D( 7063, 350, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Ciala" ), new Point3D( 7031, 411, 7 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Ciala" ), new Point3D( 7031, 411, 7 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Aniel" ), new Point3D( 7034, 412, 6 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Aniel" ), new Point3D( 7034, 412, 6 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Aulan" ), new Point3D( 6986, 340, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Aulan" ), new Point3D( 6986, 340, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Brinnae" ), new Point3D( 6996, 351, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Brinnae" ), new Point3D( 6996, 351, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Caelas" ), new Point3D( 7039, 390, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Caelas" ), new Point3D( 7039, 390, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Clehin" ), new Point3D( 7092, 390, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Clehin" ), new Point3D( 7092, 390, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Cloorne" ), new Point3D( 7010, 364, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Cloorne" ), new Point3D( 7010, 364, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Salaenih" ), new Point3D( 7009, 362, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Salaenih" ), new Point3D( 7009, 362, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Vilo" ), new Point3D( 7029, 377, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Vilo" ), new Point3D( 7029, 377, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tholef" ), new Point3D( 6986, 386, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tholef" ), new Point3D( 6986, 386, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tillanil" ), new Point3D( 6987, 388, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tillanil" ), new Point3D( 6987, 388, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Waelian" ), new Point3D( 6996, 381, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Waelian" ), new Point3D( 6996, 381, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Sleen" ), new Point3D( 6997, 381, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Sleen" ), new Point3D( 6997, 381, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Unoelil" ), new Point3D( 7010, 388, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Unoelil" ), new Point3D( 7010, 388, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Anolly" ), new Point3D( 7009, 388, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Anolly" ), new Point3D( 7009, 388, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Jusae" ), new Point3D( 7042, 377, 2 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Jusae" ), new Point3D( 7042, 377, 2 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Cillitha" ), new Point3D( 7043, 377, 2 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Cillitha" ), new Point3D( 7043, 377, 2 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Lohn" ), new Point3D( 7062, 410, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Lohn" ), new Point3D( 7062, 410, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Olla" ), new Point3D( 7063, 410, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Olla" ), new Point3D( 7063, 410, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Thallary" ), new Point3D( 7032, 439, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Thallary" ), new Point3D( 7032, 439, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Ahie" ), new Point3D( 7033, 440, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Ahie" ), new Point3D( 7033, 440, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tyeelor" ), new Point3D( 7010, 364, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tyeelor" ), new Point3D( 7010, 364, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Athailon" ), new Point3D( 7011, 365, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Athailon" ), new Point3D( 7011, 365, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderTaellia" ), new Point3D( 7038, 387, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderTaellia" ), new Point3D( 7038, 387, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderMallew" ), new Point3D( 7047, 390, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderMallew" ), new Point3D( 7047, 390, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderAbbein" ), new Point3D( 7043, 390, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderAbbein" ), new Point3D( 7043, 390, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderVicaie" ), new Point3D( 7054, 390, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderVicaie" ), new Point3D( 7054, 390, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderJothan" ), new Point3D( 7056, 383, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderJothan" ), new Point3D( 7056, 383, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "ElderAlethanian" ), new Point3D( 7056, 380, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "ElderAlethanian" ), new Point3D( 7056, 380, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Rebinil" ), new Point3D( 7089, 380, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Rebinil" ), new Point3D( 7089, 380, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Aluniol" ), new Point3D( 7089, 383, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Aluniol" ), new Point3D( 7089, 383, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Olaeni" ), new Point3D( 7080, 363, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Olaeni" ), new Point3D( 7080, 363, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Bolaevin" ), new Point3D( 7066, 351, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Bolaevin" ), new Point3D( 7066, 351, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperAneen" ), new Point3D( 7053, 337, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperAneen" ), new Point3D( 7053, 337, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Daelas" ), new Point3D( 7036, 412, 7 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Daelas" ), new Point3D( 7036, 412, 7 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Alelle" ), new Point3D( 7028, 406, 7 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Alelle" ), new Point3D( 7028, 406, 7 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperNillaen" ), new Point3D( 7061, 370, 14 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperNillaen" ), new Point3D( 7061, 370, 14 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperRyal" ), new Point3D( 7009, 375, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperRyal" ), new Point3D( 7009, 375, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Braen" ), new Point3D( 7081, 366, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Braen" ), new Point3D( 7081, 366, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderAcob" ), new Point3D( 7037, 387, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderAcob" ), new Point3D( 7037, 387, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperCalendor" ), new Point3D( 7062, 370, 14 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperCalendor" ), new Point3D( 7062, 370, 14 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperSiarra" ), new Point3D( 7051, 339, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperSiarra" ), new Point3D( 7051, 339, 0 ), Map.Felucca );
+ }
+ }
+
+ public class TheyllEatAnything : MLQuest
+ {
+ public TheyllEatAnything()
+ {
+ Activated = true;
+ Title = 1072248; // They'll Eat Anything
+ Description = 1072262; // Pork is the fruit of the land! You can barbeque it, boil it, bake it, sautee it. There's pork kebabs, pork creole, pork gumbo, pan fried, deep fried, stir fried. There's apple pork, peppered pork, pork soup, pork salad, pork and potatoes, pork burger, pork sandwich, pork stew, pork chops, pork loins, shredded pork. So, lets get some piggies butchered!
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Pig ) }, "pigs" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+ }
+
+ public class NoGoodFishStealing : MLQuest
+ {
+ public NoGoodFishStealing()
+ {
+ Activated = true;
+ Title = 1072251; // No Good, Fish Stealing ...
+ Description = 1072265; // Mighty creatures they are, aye. Fierce and strong, can't blame 'em for wanting to feed themselves an' all. Blame or no, they're eating all the fish up, so they got to go. Lend a hand?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Walrus ) }, "walruses" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+ }
+
+ public class AHeroInTheMaking : MLQuest
+ {
+ public AHeroInTheMaking()
+ {
+ Activated = true;
+ Title = 1072246; // A Hero in the Making
+ Description = 1072257; // Are you new around here? Well, nevermind that. You look ready for adventure, I can see the gleam of glory in your eyes! Nothing is more valiant, more noble, more praiseworthy than mongbat slaying.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Mongbat ) }, "mongbats" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+ }
+
+ public class BullfightingSortOf : MLQuest
+ {
+ public BullfightingSortOf()
+ {
+ Activated = true;
+ Title = 1072247; // Bullfighting ... Sort Of
+ Description = 1072254; // You there! Yes, you. Listen, I've got a little problem on my hands, but a brave, bold hero like yourself should find it a snap to solve. Bottom line -- we need some of the bulls in the area culled. You're welcome to any meat or hides, and of course, I'll give you a nice reward.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Bull ) }, "bulls" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+ }
+
+ public class AFineFeast : MLQuest
+ {
+ public AFineFeast()
+ {
+ Activated = true;
+ Title = 1072243; // A Fine Feast.
+ Description = 1072261; // Mmm, I do love mutton! It's slaughtering time again and my usual hirelings haven't turned up. I've arranged for a butcher to come by and cut everything up but the basic sheep killing part I haven't gotten worked out yet. Are you up for the task?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Sheep ) }, "sheep" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+ }
+
+ public class ForcedMigration : MLQuest
+ {
+ public ForcedMigration()
+ {
+ Activated = true;
+ Title = 1072250; // Forced Migration
+ Description = 1072264; // Chirp chirp ... tweet chirp. Tra la la. Bloody birds and their blasted noise. I've tried everything but they just won't stop that infernal clamor. Return me to blessed silence and I'll make it worth your while.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Bird ) }, "birds" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+ }
+
+ public class FilthyPests : MLQuest
+ {
+ public FilthyPests()
+ {
+ Activated = true;
+ Title = 1072242; // Filthy Pests!
+ Description = 1072253; // They're everywhere I tell you! They crawl in the walls, they scurry in the bushes. Disgusting critters. Say ... I don't suppose you're up for some sewer rat killing? Sewer rats now, not any other kind of squeaker will do.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Sewerrat ) }, "sewer rats" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+ }
+
+ public class DeadManWalking : MLQuest
+ {
+ public DeadManWalking()
+ {
+ Activated = true;
+ Title = 1072983; // Dead Man Walking
+ Description = 1073009; // Why? I ask you why? They walk around after they're put in the ground. It's just wrong in so many ways. Put them to proper rest, I beg you. I'll find some way to pay you for the kindness. Just kill five zombies and five skeletons.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 5, new Type[] { typeof( Zombie ) }, "zombies" ) );
+ Objectives.Add( new KillObjective( 5, new Type[] { typeof( Skeleton ) }, "skeletons" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class KingOfBears : MLQuest
+ {
+ public KingOfBears()
+ {
+ Activated = true;
+ Title = 1072996; // King of Bears
+ Description = 1073030; // A pity really. With the balance of nature awry, we have no choice but to accept the responsibility of making it all right. It's all a part of the circle of life, after all. So, yes, the grizzly bears are running rampant. There are far too many in the region. Will you shoulder your obligations as a higher life form?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( GrizzlyBear ) }, "grizzly bears" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class Specimens : MLQuest
+ {
+ public Specimens()
+ {
+ Activated = true;
+ Title = 1072999; // Specimens
+ Description = 1073032; // I admire them, you know. The solen have their place -- regimented, organized. They're fascinating to watch with their constant strife between red and black. I can't help but want to stir things up from time to time. And that's where you come in. Kill either twelve red or twelve black solen workers and let's see what happens next!
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ ObjectiveType = ObjectiveType.Any;
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( RedSolenWorker ) }, "red solen workers" ) );
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( BlackSolenWorker ) }, "black solen workers" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class Spirits : MLQuest
+ {
+ public Spirits()
+ {
+ Activated = true;
+ Title = 1073076; // Spirits
+ Description = 1073566; // It is a piteous thing when the dead continue to walk the earth. Restless spirits are known to inhabit these parts, taking the lives of unwary travelers. It is about time a hero put the dead back in their graves. I'm sure such a hero would be justly rewarded.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073586; // The restless spirts still walk -- you must kill 15 of them.
+
+ Objectives.Add( new KillObjective( 15, new Type[] { typeof( Spectre ), typeof( Shade ), typeof( Wraith ) }, "spectres or shades or wraiths" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class RollTheBones : MLQuest
+ {
+ public RollTheBones()
+ {
+ Activated = true;
+ Title = 1073002; // Roll the Bones
+ Description = 1073011; // Why? I ask you why? They walk around after they're put in the ground. It's just wrong in so many ways. Put them to proper rest, I beg you. I'll find some way to pay you for the kindness. Just kill eight patchwork skeletons.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 8, new Type[] { typeof( PatchworkSkeleton ) }, "patchwork skeletons" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class ItsAGhastlyJob : MLQuest
+ {
+ public ItsAGhastlyJob()
+ {
+ Activated = true;
+ Title = 1073008; // It's a Ghastly Job
+ Description = 1073012; // Why? I ask you why? They walk around after they're put in the ground. It's just wrong in so many ways. Put them to proper rest, I beg you. I'll find some way to pay you for the kindness. Just kill twelve ghouls.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( Ghoul ) }, "ghouls" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class Troglodytes : MLQuest
+ {
+ public Troglodytes()
+ {
+ Activated = true;
+ Title = 1074688; // Troglodytes!
+ Description = 1074689; // Oh nevermind, you don't look capable of my task afterall. Haha! What was I thinking - you could never handle killing troglodytes. It'd be suicide. What? I don't know, I don't want to be responsible ... well okay if you're really sure?
+ RefusalMessage = 1074690; // Probably the wiser course of action.
+ InProgressMessage = 1074691; // You still need to kill those troglodytes, remember?
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( Troglodyte ) }, "troglodytes" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class UnholyKnights : MLQuest
+ {
+ public UnholyKnights()
+ {
+ Activated = true;
+ Title = 1073075; // Unholy Knights
+ Description = 1073565; // Please, hear me kind traveler. You know when a knight falls, sometimes they are cursed to roam the earth as undead mockeries of their former glory? That is too grim a fate for even any knight to suffer! Please, put them out of their misery. I will offer you what payment I can if you will end the torment of these undead wretches.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073585; // Your task is not done. Continue putting the Skeleton and Bone Knights to rest.
+
+ Objectives.Add( new KillObjective( 16, new Type[] { typeof( BoneKnight ), typeof( SkeletalKnight ) }, "bone knights or skeletal knights" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class AFeatherInYerCap : MLQuest
+ {
+ public AFeatherInYerCap()
+ {
+ Activated = true;
+ Title = 1074738; // A Feather in Yer Cap
+ Description = 1074737; // I've seen how you strut about, as if you were something special. I have some news for you, you don't impress me at all. It's not enough to have a fancy hat you know. That may impress people in the big city, but not here. If you want a reputation you have to climb a mountain, slay some great beast, and then write about it. Trust me, it's a long process. The first step is doing a great feat. If I were you, I'd go pluck a feather from the harpy Saliva, that would give you a good start.
+ RefusalMessage = 1074736; // The path to greatness isn't for everyone obviously.
+ InProgressMessage = 1074735; // If you're going to get anywhere in the adventuring game, you have to take some risks. A harpy, well, it's bad, but it's not a dragon.
+ CompletionMessage = 1074734; // The hero returns from the glorious battle and - oh, such a small feather?
+
+ Objectives.Add( new CollectObjective( 1, typeof( SalivasFeather ), 1151994 ) ); // Saliva's Feathers
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class ATaleOfTail : MLQuest
+ {
+ public ATaleOfTail()
+ {
+ Activated = true;
+ Title = 1074726; // A Tale of Tail
+ Description = 1074727; // I've heard of you, adventurer. Your reputation is impressive, and now I'll put it to the test. This is not something I ask lightly, for this task is fraught with danger, but it is vital. Seek out the vile hydra Abscess, slay it, and return to me with it's tail.
+ RefusalMessage = 1074728; // Well, the beast will still be there when you are ready I suppose.
+ InProgressMessage = 1074729; // Em, I thought I had explained already. Abscess, the hydra, you know? Lots of heads but just the one tail. I need the tail. I have my reasons. Go go go.
+ CompletionMessage = 1074730; // Ah, the tail. You did it! You know the rumours about dried ground hydra tail powder are all true? Thank you so much!
+
+ Objectives.Add( new CollectObjective( 1, typeof( AbscessTail ), 1074231 ) ); // Abscess' Tail
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class ATrogAndHisDog : MLQuest
+ {
+ public ATrogAndHisDog()
+ {
+ Activated = true;
+ Title = 1074681; // A Trog and His Dog
+ Description = 1074680; // I don't know if you can handle it, but I'll give you a go at it. Troglodyte chief - name of Lurg and his mangy wolf pet need killing. Do the deed and I'll reward you.
+ RefusalMessage = 1074655; // Perhaps I thought too highly of you.
+ InProgressMessage = 1074682; // The trog chief and his mutt should be easy enough to find. Just kill them and report back. Easy enough.
+ CompletionMessage = 1074683; // Not half bad. Here's your prize.
+
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( Lurg ) }, "Lurg" ) );
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( Grobu ) }, "Grobu" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class Overpopulation : MLQuest
+ {
+ public Overpopulation()
+ {
+ Activated = true;
+ Title = 1072252; // Overpopulation
+ Description = 1072267; // I just can't bear it any longer. Sure, it's my job to thin the deer out so they don't overeat the area and starve themselves come winter time. Sure, I know we killed off the predators that would do this naturally so now we have to make up for it. But they're so graceful and innocent. I just can't do it. Will you?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Hind ) }, "hinds" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+ }
+
+ public class WildBoarCull : MLQuest
+ {
+ public WildBoarCull()
+ {
+ Activated = true;
+ Title = 1072245; // Wild Boar Cull
+ Description = 1072260; // A pity really. With the balance of nature awry, we have no choice but to accept the responsibility of making it all right. It's all a part of the circle of life, after all. So, yes, the boars are running rampant. There are far too many in the region. Will you shoulder your obligations as a higher life form?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Boar ) }, "boars" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+ }
+
+ public class ItsElemental : MLQuest
+ {
+ public ItsElemental()
+ {
+ Activated = true;
+ Title = 1073089; // It's Elemental
+ Description = 1073579; // The universe is all about balance my friend. Tip one end, you must balance the other. That's why I must ask you to kill not just one kind of elemental, but three kinds. Snuff out some Fire, douse a few Water, and crush some Earth elementals and I'll pay you for your trouble.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073599; // Four of each, that's all I ask. Water, earth and fire.
+
+ Objectives.Add( new KillObjective( 4, new Type[] { typeof( FireElemental ) }, "fire elementals" ) );
+ Objectives.Add( new KillObjective( 4, new Type[] { typeof( WaterElemental ) }, "water elementals" ) );
+ Objectives.Add( new KillObjective( 4, new Type[] { typeof( EarthElemental ) }, "earth elementals" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class CircleOfLife : MLQuest
+ {
+ public CircleOfLife()
+ {
+ Activated = true;
+ Title = 1073656; // Circle of Life
+ Description = 1073695; // There's been a bumper crop of evil with the Bog Things in these parts, my friend. Though they are foul creatures, they are also most fecund. Slay one and you make the land more fertile. Even better, slay several and I will give you whatever coin I can spare.
+ RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point.
+ InProgressMessage = 1073736; // Continue to seek and kill the Bog Things.
+
+ Objectives.Add( new KillObjective( 8, new Type[] { typeof( BogThing ) }, "bog things" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class DustToDust : MLQuest
+ {
+ public DustToDust()
+ {
+ Activated = true;
+ Title = 1073074; // Dust to Dust
+ Description = 1073564; // You want to hear about trouble? I got trouble. How's angry piles of granite walking around for trouble? Maybe they don't like the mining, maybe it's the farming. I don't know. All I know is someone's got to turn them back to potting soil. And it'd be worth a pretty penny to the soul that does it.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073584; // You got rocks in your head? I said to kill 12 earth elementals, okay?
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( EarthElemental ) }, "earth elementals" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class CreepyCrawlies : MLQuest
+ {
+ public CreepyCrawlies()
+ {
+ Activated = true;
+ Title = 1072987; // Creepy Crawlies
+ Description = 1073016; // Disgusting! The way they scuttle on those hairy legs just makes me want to gag. I hate spiders! Rid the world of twelve and I'll find something nice to give you in thanks.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( GiantSpider ) }, "giant spiders" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class VoraciousPlants : MLQuest
+ {
+ public VoraciousPlants()
+ {
+ Activated = true;
+ Title = 1073001; // Voracious Plants
+ Description = 1073024; // I bet you can't tangle with those nasty plants ... say eight corpsers and two swamp tentacles! I bet they're too much for you. You may as well confess you can't ...
+ RefusalMessage = 1073019; // Hahahaha! I knew it!
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 8, new Type[] { typeof( Corpser ) }, "corpsers" ) );
+ Objectives.Add( new KillObjective( 2, new Type[] { typeof( SwampTentacle ) }, "swamp tentacles" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class GibberJabber : MLQuest
+ {
+ public GibberJabber()
+ {
+ Activated = true;
+ Title = 1073004; // Gibber Jabber
+ Description = 1073024; // I bet you can't kill ... ten gibberlings! I bet they're too much for you. You may as well confess you can't ...
+ RefusalMessage = 1073019; // Hahahaha! I knew it!
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Gibberling ) }, "gibberlings" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class AnimatedMonstrosity : MLQuest
+ {
+ public AnimatedMonstrosity()
+ {
+ Activated = true;
+ Title = 1072990; // Animated Monstrosity
+ Description = 1073020; // I bet you can't kill ... say twelve ... flesh golems! I bet they're too much for you. You may as well confess you can't ...
+ RefusalMessage = 1073019; // Hahahaha! I knew it!
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( FleshGolem ) }, "flesh golems" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class BirdsOfAFeather : MLQuest
+ {
+ public BirdsOfAFeather()
+ {
+ Activated = true;
+ Title = 1073007; // Birds of a Feather
+ Description = 1073022; // I bet you can't kill ... ten harpies! I bet they're too much for you. You may as well confess you can't ...
+ RefusalMessage = 1073019; // Hahahaha! I knew it!
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Harpy ) }, "harpies" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class Frightmares : MLQuest
+ {
+ public Frightmares()
+ {
+ Activated = true;
+ Title = 1073000; // Frightmares
+ Description = 1073036; // I bet you can't handle ten plague spawns! I bet they're too much for you. You may as well confess you can't ...
+ RefusalMessage = 1073019; // Hahahaha! I knew it!
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( PlagueSpawn ) }, "plague spawns" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class MoltenReptiles : MLQuest
+ {
+ public MoltenReptiles()
+ {
+ Activated = true;
+ Title = 1072989; // Molten Reptiles
+ Description = 1073018; // I bet you can't kill ... say ten ... lava lizards! I bet they're too much for you. You may as well confess you can't ...
+ RefusalMessage = 1073019; // Hahahaha! I knew it!
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( LavaLizard ) }, "lava lizards" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class BloodyNuisance : MLQuest
+ {
+ public BloodyNuisance()
+ {
+ Activated = true;
+ Title = 1072992; // Bloody Nuisance
+ Description = 1073021; // I bet you can't kill ... ten gore fiends! I bet they're too much for you. You may as well confess you can't ...
+ RefusalMessage = 1073019; // Hahahaha! I knew it!
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( GoreFiend ) }, "gore fiends" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class BloodSuckers : MLQuest
+ {
+ public BloodSuckers()
+ {
+ Activated = true;
+ Title = 1072997; // Blood Suckers
+ Description = 1073025; // I bet you can't tangle with those bloodsuckers ... say around ten vampire bats! I bet they're too much for you. You may as well confess you can't ...
+ RefusalMessage = 1073019; // Hahahaha! I knew it!
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( VampireBat ) }, "vampire bats" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class TheAfterlife : MLQuest
+ {
+ public TheAfterlife()
+ {
+ Activated = true;
+ Title = 1073073; // The Afterlife
+ Description = 1073563; // Nobody told me about the Mummy's Curse. How was I supposed to know you shouldn't disturb the tombs? Oh, sure, now all I hear about is the curse of the vengeful dead. I'll tell you what - make a few of these mummies go away and we'll keep this between you and me.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073583; // Uh, I don't think you're quite done killing Mummies yet.
+
+ Objectives.Add( new KillObjective( 15, new Type[] { typeof( Mummy ) }, "mummies" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class ForkedTongue : MLQuest
+ {
+ public ForkedTongue()
+ {
+ Activated = true;
+ Title = 1073655; // Forked Tongue
+ Description = 1073694; // I must implore you, brave traveler, to do battle with the vile reptiles which haunt these parts. Those hideous abominations, the Ophidians, are a blight across the land. If you were able to put down a host of the scaly warriors, the Knights or the Avengers, I would forever be in your debt.
+ RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point.
+ InProgressMessage = 1073735; // Have you killed the Ophidian Knights or Avengers?
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( OphidianKnight ) }, "ophidian avengers or ophidian knight-errants" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class ImpishDelights : MLQuest
+ {
+ public ImpishDelights()
+ {
+ Activated = true;
+ Title = 1073077; // Impish Delights
+ Description = 1073567; // Imps! Do you hear me? Imps! They're everywhere! They're in everything! Oh, don't be fooled by their size - they vicious little devils! Half-sized evil incarnate, they are! Somebody needs to send them back to where they came from, if you know what I mean.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073587; // Don't let the little devils scare you! You kill 12 imps - then we'll talk reward.
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( Imp ) }, "imps" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class ThreeWishes : MLQuest
+ {
+ public ThreeWishes()
+ {
+ Activated = true;
+ Title = 1073660; // Three Wishes
+ Description = 1073699; // If I had but one wish, it would be to rid myself of these dread Efreet! Fire and ash, they are cunning and deadly! You look a brave soul - would you be interested in earning a rich reward for slaughtering a few of the smoky devils?
+ RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point.
+ InProgressMessage = 1073740; // Those smoky devils, the Efreets, are still about.
+
+ Objectives.Add( new KillObjective( 8, new Type[] { typeof( Efreet ) }, "efreets" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class EvilEye : MLQuest
+ {
+ public EvilEye()
+ {
+ Activated = true;
+ Title = 1073084; // Evil Eye
+ Description = 1073574; // Kind traveler, hear my plea. You know of the evil orbs? The wrathful eyes? Some call them gazers? They must be a nest nearby, for they are tormenting us poor folk. We need to drive back their numbers. But we are not strong enough to face such horrors ourselves, we need a true hero.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073594; // Have you annihilated a dozen Gazers yet, kind traveler?
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( Gazer ) }, "gazers" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class GargoylesWrath : MLQuest
+ {
+ public GargoylesWrath()
+ {
+ Activated = true;
+ Title = 1073658; // Gargoyle's Wrath
+ Description = 1073697; // It is regretable that the Gargoyles insist upon warring with us. Their Enforcers attack men on sight, despite all efforts at reason. To help maintain order in this region, I have been authorized to encourage bounty hunters to reduce their numbers. Eradicate their number and I will reward you handsomely.
+ RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point.
+ InProgressMessage = 1073738; // I won't be able to pay you until you've gotten enough Gargoyle Enforcers.
+
+ Objectives.Add( new KillObjective( 6, new Type[] { typeof( GargoyleEnforcer ) }, "gargoyle enforcers" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class UndeadMages : MLQuest
+ {
+ public UndeadMages()
+ {
+ Activated = true;
+ Title = 1073080; // Undead Mages
+ Description = 1073570; // Why must the dead plague the living? With their foul necromancy and dark sorceries, the undead menace the countryside. I fear what will happen if no one is strong enough to face these nightmare sorcerers and thin their numbers.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073590; // Surely, a brave soul like yourself can kill 10 Bone Magi and Skeletal Mages?
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( BoneMagi ), typeof( SkeletalMage ) }, "bone mages or skeletal mages" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class FriendlyNeighborhoodSpiderkiller : MLQuest
+ {
+ public FriendlyNeighborhoodSpiderkiller()
+ {
+ Activated = true;
+ Title = 1073662; // Friendly Neighborhood Spider-killer
+ Description = 1073701; // They aren't called Dread Spiders because they're fluffy and cuddly now, are they? No, there's nothing appealing about those wretches so I sure wouldn't lose any sleep if you were to exterminate a few. I'd even part with a generous amount of gold, I would.
+ RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point.
+ InProgressMessage = 1073742; // Dread Spiders? I say keep exterminating the arachnid vermin.
+
+ Objectives.Add( new KillObjective( 8, new Type[] { typeof( DreadSpider ) }, "dread spiders" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class MongbatMenace : MLQuest
+ {
+ public MongbatMenace()
+ {
+ Activated = true;
+ Title = 1073003; // Mongbat Menace!
+ Description = 1073033; // I imagine you don't know about the mongbats. Well, you may think you do, but I know more than just about anyone. You see they come in two varieties ... the stronger and the weaker. Either way, they're a menace. Exterminate ten of the weaker ones and four of the stronger and I'll pay you an honest wage.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Mongbat ) }, "mongbats" ) );
+ Objectives.Add( new KillObjective( 4, new Type[] { typeof( GreaterMongbat ) }, "greater mongbats" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class StirringTheNest : MLQuest
+ {
+ public StirringTheNest()
+ {
+ Activated = true;
+ Title = 1073087; // Stirring the Nest
+ Description = 1073577; // Were you the sort of child that enjoyed knocking over anthills? Well, perhaps you'd like to try something a little bigger? There's a Solen nest nearby and I bet if you killed a queen or two, it would be quite the sight to behold. I'd even pay to see that - what do you say?
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073597; // Dead Solen Queens isn't too much to ask, is it?
+
+ ObjectiveType = ObjectiveType.Any;
+
+ Objectives.Add( new KillObjective( 3, new Type[] { typeof( RedSolenQueen ) }, "red solen queens" ) );
+ Objectives.Add( new KillObjective( 3, new Type[] { typeof( BlackSolenQueen ) }, "black solen queens" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class WarriorCaste : MLQuest
+ {
+ public WarriorCaste()
+ {
+ Activated = true;
+ Title = 1073078; // Warrior Caste
+ Description = 1073568; // The Terathan are an aggressive species. Left unchecked, they will swarm across our lands. And where will that leave us? Compost in the hive, that's what! Stop them, stop them cold my friend. Kill their warriors and you'll check their movement, that is certain.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073588; // Unless you kill at least 10 Terathan Warriors, you won't have any impact on their hive.
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( TerathanWarrior ) }, "terathan warriors" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class BigWorms : MLQuest
+ {
+ public BigWorms()
+ {
+ Activated = true;
+ Title = 1073088; // Big Worms
+ Description = 1073578; // It makes no sense! Cold blooded serpents cannot live in the ice! It's a biological impossibility! They are an abomination against reason! Please, I beg you - kill them! Make them disappear for me! Do this and I will reward you.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073598; // You wouldn't try and just pretend you murdered 10 Giant Ice Worms, would you?
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( IceSerpent ) }, "giant ice serpents" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class OrcishElite : MLQuest
+ {
+ public OrcishElite()
+ {
+ Activated = true;
+ Title = 1073081; // Orcish Elite
+ Description = 1073571; // Foul brutes! No one loves an orc, but some of them are worse than the rest. Their Captains and their Bombers, for instance, they're the worst of the lot. Kill a few of those, and the rest are just a rabble. Exterminate a few of them and you'll make the world a sunnier place, don't you know.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073591; // The only good orc is a dead orc - and 4 dead Captains and 6 dead Bombers is even better!
+
+ Objectives.Add( new KillObjective( 6, new Type[] { typeof( OrcBomber ) }, "orc bombers" ) );
+ Objectives.Add( new KillObjective( 4, new Type[] { typeof( OrcCaptain ) }, "orc captain" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class ThinningTheHerd : MLQuest
+ {
+ public ThinningTheHerd()
+ {
+ Activated = true;
+ Title = 1072249; // Thinning the Herd
+ Description = 1072263; // Psst! Hey ... psst! Listen, I need some help here but it's gotta be hush hush. I don't want THEM to know I'm onto them. They watch me. I've seen them, but they don't know that I know what I know. You know? Anyway, I need you to scare them off by killing a few of them. That'll send a clear message that I won't suffer goats watching me!
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Goat ) }, "goats" ) );
+
+ Rewards.Add( ItemReward.SmallBagOfTrinkets );
+ }
+ }
+
+ public class Squishy : MLQuest
+ {
+ public Squishy()
+ {
+ Activated = true;
+ Title = 1072998; // Squishy
+ Description = 1073031; // Have you ever seen what a slime can do to good gear? Well, it's not pretty, let me tell you! If you take on my task to destroy twelve of them, bear that in mind. They'll corrode your equipment faster than anything.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( Slime ) }, "slimes" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class OrcSlaying : MLQuest
+ {
+ public OrcSlaying()
+ {
+ Activated = true;
+ Title = 1072986; // Orc Slaying
+ Description = 1073015; // Those green-skinned freaks have run off with more of my livestock. I want an orc scout killed for each sheep I lost and an orc for each chicken. So that's four orc scouts and eight orcs I'll pay you to slay.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 8, new Type[] { typeof( Orc ) }, "orcs" ) );
+ // TODO: This needs to be orc scouts but they aren't in the SVN
+ Objectives.Add( new KillObjective( 4, new Type[] { typeof( OrcishLord ) }, "orcish lords" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class ABigJob : MLQuest
+ {
+ public ABigJob()
+ {
+ Activated = true;
+ Title = 1072988; // A Big Job
+ Description = 1073017; // It's a big job but you look to be just the adventurer to do it! I'm so glad you came by ... I'm paying well for the death of five ogres and five ettins.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 5, new Type[] { typeof( Ogre ) }, "ogres" ) );
+ Objectives.Add( new KillObjective( 5, new Type[] { typeof( Ettin ) }, "ettins" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class TrollingForTrolls : MLQuest
+ {
+ public TrollingForTrolls()
+ {
+ Activated = true;
+ Title = 1072985; // Trolling for Trolls
+ Description = 1073014; // They may not be bright, but they're incredibly destructive. Kill off ten trolls and I'll consider it a favor done for me.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Troll ) }, "trolls" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class ColdHearted : MLQuest
+ {
+ public ColdHearted()
+ {
+ Activated = true;
+ Title = 1072991; // Cold Hearted
+ Description = 1073027; // It's a big job but you look to be just the adventurer to do it! I'm so glad you came by ... I'm paying well for the death of six giant ice serpents and six frost spiders. Hop to it, if you're so inclined.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 6, new Type[] { typeof( IceSerpent ) }, "giant ice serpents" ) );
+ Objectives.Add( new KillObjective( 6, new Type[] { typeof( FrostSpider ) }, "frost spiders" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class ForkedTongues : MLQuest
+ {
+ public ForkedTongues()
+ {
+ Activated = true;
+ Title = 1072984; // Forked Tongues
+ Description = 1073013; // You can't trust them, you know. Lizardmen I mean. They have forked tongues ... and you know what that means. Exterminate ten of them and I'll reward you.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Lizardman ) }, "lizardmen" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class ShakingThingsUp : MLQuest
+ {
+ public ShakingThingsUp()
+ {
+ Activated = true;
+ Title = 1073083; // Shaking Things Up
+ Description = 1073573; // A Solen hive is a fascinating piece of ecology. It's put together like a finely crafted clock. Who knows what happens if you remove something? So let's find out. Exterminate a few of the warriors and I'll make it worth your while.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073593; // I don't think you've gotten their attention yet -- you need to kill at least 10 Solen Warriors.
+
+ ObjectiveType = ObjectiveType.Any;
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( RedSolenWarrior ) }, "red solen warriors" ) );
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( BlackSolenWarrior ) }, "black solen warriors" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class Arachnophobia : MLQuest
+ {
+ public Arachnophobia()
+ {
+ Activated = true;
+ Title = 1073079; // Arachnophobia
+ Description = 1073569; // I've seen them hiding in their webs among the woods. Glassy eyes, spindly legs, poisonous fangs. Monsters, I say! Deadly horrors, these black widows. Someone must exterminate the abominations! If only I could find a worthy hero for such a task, then I could give them this considerable reward.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073589; // You've got a good start, but to stop the black-eyed fiends, you need to kill a dozen.
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( GiantBlackWidow ) }, "giant black widows" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class MiniSwampThing : MLQuest
+ {
+ public MiniSwampThing()
+ {
+ Activated = true;
+ Title = 1073072; // Mini Swamp Thing
+ Description = 1073562; // Some say killing a boggling brings good luck. I don't place much stock in old wives' tales, but I can say a few dead bogglings would certainly be lucky for me! Help me out and I can reward you for your efforts.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073582; // Go back and kill all 20 bogglings!
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( Bogling ) }, "boglings" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class ThePerilsOfFarming : MLQuest
+ {
+ public ThePerilsOfFarming()
+ {
+ Activated = true;
+ Title = 1073664; // The Perils of Farming
+ Description = 1073703; // I should be trimming back the vegetation here, but something nasty has taken root. Viscious vines I can't go near. If there's any hope of getting things under control, some one's going to need to destroy a few of those Whipping Vines. Someone strong and fast and tough.
+ RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point.
+ InProgressMessage = 1073744; // How are farmers supposed to work with these Whipping Vines around?
+
+ Objectives.Add( new KillObjective( 15, new Type[] { typeof( WhippingVine ) }, "whipping vines" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class IndustriousAsAnAntLion : MLQuest
+ {
+ public IndustriousAsAnAntLion()
+ {
+ Activated = true;
+ Title = 1073665; // Industrious as an Ant Lion
+ Description = 1073704; // Ants are industrious and Lions are noble so who'd think an Ant Lion would be such a problem? The Ant Lion's have been causing mindless destruction in these parts. I suppose it's just how ants are. But I need you to help eliminate the infestation. Would you be willing to help for a bit of reward?
+ RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point.
+ InProgressMessage = 1073745; // Please, rid us of the Ant Lion infestation.
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( AntLion ) }, "ant lions" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class UnholyConstruct : MLQuest
+ {
+ public UnholyConstruct()
+ {
+ Activated = true;
+ Title = 1073666; // Unholy Construct
+ Description = 1073705; // They're unholy, I say. Golems, a walking mockery of all life, born of blackest magic. They're not truly alive, so destroying them isn't a crime, it's a service. A service I will gladly pay for.
+ RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point.
+ InProgressMessage = 1073746; // The unholy brutes, the Golems, must be smited!
+ CompletionMessage = 1073787; // Reduced those Golems to component parts? Good, then -- you deserve this reward!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Golem ) }, "golems" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class AChillInTheAir : MLQuest
+ {
+ public AChillInTheAir()
+ {
+ Activated = true;
+ Title = 1073663; // A Chill in the Air
+ Description = 1073702; // Feel that chill in the air? It means an icy death for the unwary, for deadly Ice Elementals are about. Who knows what magic summoned them, what's important now is getting rid of them. I don't have much, but I'll give all I can if you'd only stop the cold-hearted monsters.
+ RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point.
+ InProgressMessage = 1073746; // The chill won't lift until you eradicate a few Ice Elemenals.
+
+ Objectives.Add( new KillObjective( 15, new Type[] { typeof( IceElemental ) }, "ice elementals" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class TheKingOfClothing : MLQuest
+ {
+ public TheKingOfClothing()
+ {
+ Activated = true;
+ Title = 1073902; // The King of Clothing
+ Description = 1074092; // I have heard noble tales of a fine and proud human garment. An article of clothing fit for both man and god alike. It is called a "kilt" I believe? Could you fetch for me some of these kilts so I that I might revel in their majesty and glory?
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ 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
+
+ Rewards.Add( ItemReward.TailorSatchel );
+ }
+ }
+
+ public class ThePuffyShirt : MLQuest
+ {
+ public ThePuffyShirt()
+ {
+ Activated = true;
+ Title = 1073903; // The Puffy Shirt
+ Description = 1074093; // We elves believe that beauty is expressed in all things, including the garments we wear. I wish to understand more about human aesthetics, so please kind traveler - could you bring to me magnificent examples of human fancy shirts? For my thanks, I could teach you more about the beauty of elven vestements.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ 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
+
+ Rewards.Add( ItemReward.TailorSatchel );
+ }
+ }
+
+ public class FromTheGaultierCollection : MLQuest
+ {
+ public FromTheGaultierCollection()
+ {
+ Activated = true;
+ Title = 1073905; // From the Gaultier Collection
+ Description = 1074095; // It is my understanding, the females of humankind actually wear on certain occasions a studded bustier? This is not simply a fanciful tale? Remarkable! It sounds hideously uncomfortable as well as ludicrously impracticle. But perhaps, I simply do not understand the nuances of human clothing. Perhaps, I need to see such a studded bustier for myself?
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ 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
+
+ Rewards.Add( ItemReward.TailorSatchel );
+ }
+ }
+
+ public class HauteCouture : MLQuest
+ {
+ public HauteCouture()
+ {
+ Activated = true;
+ Title = 1073901; // Hâute Couture
+ Description = 1074091; // Most human apparel is interesting to elven eyes. But there is one garment - the flower garland - which sounds very elven indeed. Could I see how a human crafts such an object of beauty? In exchange, I could share with you the wonders of elven garments.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073947; // I will be in your debt if you bring me flower garlands.
+ CompletionMessage = 1073973; // I appreciate your service. Now, see what elven hands can create.
+
+ Objectives.Add( new CollectObjective( 10, typeof( FlowerGarland ), 1028965 ) ); // flower garland
+
+ Rewards.Add( ItemReward.TailorSatchel );
+ }
+ }
+
+ public class TheSongOfTheWind : MLQuest
+ {
+ public TheSongOfTheWind()
+ {
+ Activated = true;
+ Title = 1073910; // The Song of the Wind
+ Description = 1074100; // To give voice to the passing wind, this is an idea worthy of an elf! Friend, bring me some of the amazing fancy wind chimes so that I may listen to the song of the passing breeze. Do this, and I will share with you treasured elven secrets.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073956; // I will be in your debt if you bring me fancy wind chimes.
+ CompletionMessage = 1073980; // Such a delightful sound, I think I shall never tire of it.
+
+ Objectives.Add( new CollectObjective( 10, typeof( FancyWindChimes ), "fancy wind chimes" ) );
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class BeerGoggles : MLQuest
+ {
+ public BeerGoggles()
+ {
+ Activated = true;
+ Title = 1073895; // Beer Goggles
+ Description = 1074085; // Oh, the deviltry! Why would humans lock their precious liquors inside a wooden coffin? I understand I need a "keg tap" to access the golden brew within such a wooden abomination. Perhaps, if you could bring me such a tap, we could share a drink and I could teach you.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073941; // I will be in your debt if you bring me barrel taps.
+ CompletionMessage = 1073971; // My thanks for your service. Here is something for you to enjoy.
+
+ Objectives.Add( new CollectObjective( 25, typeof( BarrelTap ), 1024100 ) ); // barrel tap
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class MessageInABottleQuest : MLQuest
+ {
+ public MessageInABottleQuest()
+ {
+ Activated = true;
+ Title = 1073894; // Message in a Bottle
+ Description = 1074084; // We elves are interested in trading our wines with humans but we understand human usually trade such brew in strange transparent bottles. If you could provide some of these empty glass bottles, I might engage in a bit of elven winemaking.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073940; // I will be in your debt if you bring me empty bottles.
+ CompletionMessage = 1073971; // My thanks for your service. Here is something for you to enjoy.
+
+ Objectives.Add( new CollectObjective( 50, typeof( Bottle ), 1023854 ) ); // empty bottle
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class NecessitysMother : MLQuest
+ {
+ public NecessitysMother()
+ {
+ Activated = true;
+ Title = 1073906; // Necessity's Mother
+ Description = 1074096; // What a thing, this human need to tinker. It seems there is no end to what might be produced with a set of Tinker's Tools. Who knows what an elf might build with some? Could you obtain some tinker's tools and bring them to me? In exchange, I offer you elven lore and knowledge.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ 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
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class TickTock : MLQuest
+ {
+ public TickTock()
+ {
+ Activated = true;
+ Title = 1073907; // Tick Tock
+ Description = 1074097; // Elves find it remarkable the human preoccupation with the passage of time. To have built instruments to try and capture time -- it is a fascinating notion. I would like to see how a clock is put together. Maybe you could provide some clocks for my experimentation?
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073953; // I will be in your debt if you bring me clocks.
+ CompletionMessage = 1073978; // Enjoy my thanks for your service.
+
+ Objectives.Add( new CollectObjective( 10, typeof( Clock ), 1024171 ) ); // clock
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class ReptilianDentist : MLQuest
+ {
+ public ReptilianDentist()
+ {
+ Activated = true;
+ Title = 1074280; // Reptilian Dentist
+ Description = 1074710; // I'm working on a striking necklace -- something really unique -- and I know just what I need to finish it up. A huge fang! Won't that catch the eye? I would like to employ you to find me such an item, perhaps a snake would make the ideal donor. I'll make it worth your while, of course.
+ RefusalMessage = 1074723; // I understand. I don't like snakes much either. They're so creepy.
+ InProgressMessage = 1074722; // Those really big snakes like swamps, I've heard. You might try the blighted grove.
+ CompletionMessage = 1074721; // Do you have it? *gasp* What a tooth! Here … I must get right to work.
+
+ Objectives.Add( new CollectObjective( 1, typeof( CoilsFang ), "coil's fang" ) );
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class StopHarpingOnMe : MLQuest
+ {
+ public StopHarpingOnMe()
+ {
+ Activated = true;
+ Title = 1073881; // Stop Harping on Me
+ Description = 1074071; // Humans artistry can be a remarkable thing. For instance, I have heard of a wonderful instrument which creates the most melodious of music. A lap harp. I would be ever so grateful if I could examine one in person.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073927; // I will be in your debt if you bring me lap harp.
+ CompletionMessage = 1073969; // My thanks for your service. Now, I will show you something of elven carpentry.
+
+ Objectives.Add( new CollectObjective( 20, typeof( LapHarp ), 1023762 ) ); // lap harp
+
+ Rewards.Add( ItemReward.CarpentrySatchel );
+ }
+ }
+
+ public class TheFarEye : MLQuest
+ {
+ public TheFarEye()
+ {
+ Activated = true;
+ Title = 1073908; // The Far Eye
+ Description = 1074098; // The wonders of human invention! Turning sand and metal into a far-seeing eye! This is something I must experience for myself. Bring me some of these spyglasses friend human.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073954; // I will be in your debt if you bring me spyglasses.
+ CompletionMessage = 1073978; // Enjoy my thanks for your service.
+
+ Objectives.Add( new CollectObjective( 20, typeof( Spyglass ), 1025365 ) ); // spyglass
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class LethalDarts : MLQuest
+ {
+ public LethalDarts()
+ {
+ Activated = true;
+ Title = 1073876; // Lethal Darts
+ Description = 1074066; // We elves are no strangers to archery but I would be interested in learning whether there is anything to learn from the human approach. I would gladly trade you something I have if you could teach me of the deadly crossbow bolt.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073922; // I will be in your debt if you bring me crossbow bolts.
+ CompletionMessage = 1073968; // My thanks for your service. Now, I shall teach you of elven archery.
+
+ Objectives.Add( new CollectObjective( 10, typeof( Bolt ), 1027163 ) ); // crossbow bolt
+
+ Rewards.Add( ItemReward.FletchingSatchel );
+ }
+ }
+
+ public class ASimpleBow : MLQuest
+ {
+ public ASimpleBow()
+ {
+ Activated = true;
+ Title = 1073877; // A Simple Bow
+ Description = 1074067; // I wish to try a bow crafted in the human style. Is it possible for you to bring me such a weapon? I would be happy to return this favor.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073923; // I will be in your debt if you bring me bows.
+ CompletionMessage = 1073968; // My thanks for your service. Now, I shall teach you of elven archery.
+
+ Objectives.Add( new CollectObjective( 10, typeof( Bow ), 1025041 ) ); // bow
+
+ Rewards.Add( ItemReward.FletchingSatchel );
+ }
+ }
+
+ public class IngeniousArcheryPartOne : MLQuest
+ {
+ public IngeniousArcheryPartOne()
+ {
+ Activated = true;
+ Title = 1073878; // Ingenious Archery, Part I
+ Description = 1074068; // I have heard of a curious type of bow, you call it a "crossbow". It sounds fascinating and I would very much like to examine one closely. Would you be able to obtain such an instrument for me?
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073924; // I will be in your debt if you bring me crossbows.
+ CompletionMessage = 1073968; // My thanks for your service. Now, I shall teach you of elven archery.
+
+ Objectives.Add( new CollectObjective( 10, typeof( Crossbow ), 1023919 ) ); // crossbow
+
+ Rewards.Add( ItemReward.FletchingSatchel );
+ }
+
+ // TODO: Verified for this one, what about the others?
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1073967, "", 0x23 ); // You obtained what you seek, now receive your reward.
+ }
+ }
+
+ public class IngeniousArcheryPartTwo : MLQuest
+ {
+ public IngeniousArcheryPartTwo()
+ {
+ Activated = true;
+ Title = 1073879; // Ingenious Archery, Part II
+ Description = 1074069; // These human "crossbows" are complex and clever. The "heavy crossbow" is a remarkable instrument of war. I am interested in seeing one up close, if you could arrange for one to make its way to my hands.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073925; // I will be in your debt if you bring me heavy crossbows.
+ CompletionMessage = 1073968; // My thanks for your service. Now, I shall teach you of elven archery.
+
+ Objectives.Add( new CollectObjective( 8, typeof( HeavyCrossbow ), 1025116 ) ); // heavy crossbow
+
+ Rewards.Add( ItemReward.FletchingSatchel );
+ }
+ }
+
+ public class IngeniousArcheryPartThree : MLQuest
+ {
+ public IngeniousArcheryPartThree()
+ {
+ Activated = true;
+ Title = 1073880; // Ingenious Archery, Part III
+ Description = 1074070; // My friend, I am in search of a device, a instrument of remarkable human ingenuity. It is a repeating crossbow. If you were to obtain such a device, I would gladly reveal to you some of the secrets of elven craftsmanship.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073926; // I will be in your debt if you bring me repeating crossbows.
+ CompletionMessage = 1073968; // My thanks for your service. Now, I shall teach you of elven archery.
+
+ Objectives.Add( new CollectObjective( 10, typeof( RepeatingCrossbow ), 1029923 ) ); // repeating crossbow
+
+ Rewards.Add( ItemReward.FletchingSatchel );
+ }
+ }
+
+ public class ScaleArmor : MLQuest
+ {
+ public ScaleArmor()
+ {
+ Activated = true;
+ Title = 1074711; // Scale Armor
+ Description = 1074712; // Here's what I need ... there are some creatures called hydra, fearsome beasts, whose scales are especially suitable for a new sort of armor that I'm developing. I need a few such pieces and then some supple alligator skin for the backing. I'm going to need a really large piece that's shaped just right ... the tail I think would do nicely. I appreciate your help.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1074724; // Hydras have been spotted in the Blighted Grove. You won't get those scales without getting your feet wet, I'm afraid.
+ CompletionMessage = 1074725; // I can't wait to get to work now that you've returned with my scales.
+
+ Objectives.Add( new CollectObjective( 1, typeof( ThrashersTail ), 1074230 ) ); // Thrasher's Tail
+ Objectives.Add( new CollectObjective( 10, typeof( HydraScale ), 1151992 ) ); // Hydra Scales
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class CutsBothWays : MLQuest
+ {
+ public CutsBothWays()
+ {
+ Activated = true;
+ Title = 1073913; // Cuts Both Ways
+ Description = 1074103; // What would you say is a typical human instrument of war? Is a broadsword a typical example? I wish to see more of such human weapons, so I would gladly trade elven knowledge for human steel.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ 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
+
+ Rewards.Add( ItemReward.BlacksmithSatchel );
+ }
+ }
+
+ public class DragonProtection : MLQuest
+ {
+ public DragonProtection()
+ {
+ Activated = true;
+ Title = 1073915; // Dragon Protection
+ Description = 1074105; // Mankind, I am told, knows how to take the scales of a terrible dragon and forge them into powerful armor. Such a feat of craftsmanship! I would give anything to view such a creation - I would even teach some of the prize secrets of the elven people.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073961; // I will be in your debt if you bring me dragon armor.
+ CompletionMessage = 1073978; // Enjoy my thanks for your service.
+
+ Objectives.Add( new CollectObjective( 10, typeof( DragonHelm ), 1029797 ) ); // dragon helm
+
+ Rewards.Add( ItemReward.BlacksmithSatchel );
+ }
+ }
+
+ public class NothingFancy : MLQuest
+ {
+ public NothingFancy()
+ {
+ Activated = true;
+ Title = 1073911; // Nothing Fancy
+ Description = 1074101; // I am curious to see the results of human blacksmithing. To examine the care and quality of a simple item. Perhaps, a simple bascinet helmet? Yes, indeed -- if you could bring to me some bascinet helmets, I would demonstrate my gratitude.
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ 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
+
+ Rewards.Add( ItemReward.BlacksmithSatchel );
+ }
+ }
+
+ public class TheBulwark : MLQuest
+ {
+ public TheBulwark()
+ {
+ Activated = true;
+ Title = 1073912; // The Bulwark
+ Description = 1074102; // The clank of human iron and steel is strange to elven ears. For instance, the metallic heater shield which human warriors carry into battle. It is odd to an elf, but nevertheless intriguing. Tell me friend, could you bring me such an example of human smithing skill?
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073958; // I will be in your debt if you bring me heater shields.
+ CompletionMessage = 1073978; // Enjoy my thanks for your service.
+
+ Objectives.Add( new CollectObjective( 10, typeof( HeaterShield ), 1027030 ) ); // heater shield
+
+ Rewards.Add( ItemReward.BlacksmithSatchel );
+ }
+ }
+
+ public class ArchSupport : MLQuest
+ {
+ public ArchSupport()
+ {
+ Activated = true;
+ Title = 1073882; // Arch Support
+ Description = 1074072; // How clever humans are - to understand the need of feet to rest from time to time! Imagine creating a special stool just for weary toes. I would like to examine and learn the secret of their making. Would you bring me some foot stools to examine?
+ RefusalMessage = 1073921; // I will patiently await your reconsideration.
+ InProgressMessage = 1073928; // I will be in your debt if you bring me foot stools.
+ CompletionMessage = 1073969; // My thanks for your service. Now, I will show you something of elven carpentry.
+
+ Objectives.Add( new CollectObjective( 10, typeof( FootStool ), 1022910 ) ); // foot stool
+
+ Rewards.Add( ItemReward.CarpentrySatchel );
+ }
+ }
+
+ public class ParoxysmusSuccubi : MLQuest
+ {
+ public ParoxysmusSuccubi()
+ {
+ Activated = true;
+ Title = 1073067; // Paroxysmus' Succubi
+ Description = 1074696; // The succubi that have congregated within the sinkhole to worship Paroxysmus pose a tremendous danger. Will you enter the lair and see to their destruction?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 3, new Type[] { typeof( Succubus ) }, "succubi", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class ParoxysmusMoloch : MLQuest
+ {
+ public ParoxysmusMoloch()
+ {
+ Activated = true;
+ Title = 1073068; // Paroxysmus' Moloch
+ Description = 1074695; // The moloch daemons that have congregated to worship Paroxysmus pose a tremendous danger. Will you enter the lair and see to their destruction?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 3, new Type[] { typeof( Moloch ) }, "molochs", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class ParoxysmusDaemons : MLQuest
+ {
+ public ParoxysmusDaemons()
+ {
+ Activated = true;
+ Title = 1073069; // Paroxysmus' Daemons
+ Description = 1074694; // The daemons that have congregated to worship Paroxysmus pose a tremendous danger. Will you enter the lair and see to their destruction?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Daemon ) }, "daemons", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class ParoxysmusArcaneDaemons : MLQuest
+ {
+ public ParoxysmusArcaneDaemons()
+ {
+ Activated = true;
+ Title = 1073070; // Paroxysmus' Arcane Daemons
+ Description = 1074697; // The arcane daemons that worship Paroxysmus pose a tremendous danger. Will you enter the lair and see to their destruction?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( ArcaneDaemon ) }, "arcane daemons", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class CausticCombo : MLQuest
+ {
+ public CausticCombo()
+ {
+ Activated = true;
+ Title = 1073062; // Caustic Combo
+ Description = 1074693; // Vile creatures have exited the sinkhole and begun terrorizing the surrounding area. The demons are bad enough, but the elementals are an abomination, their poisons seeping into the fertile ground here. Will you enter the sinkhole and put a stop to their depredations?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 3, new Type[] { typeof( PoisonElemental ) }, "poison elementals", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus
+ Objectives.Add( new KillObjective( 6, new Type[] { typeof( AcidElemental ) }, "acid elementals", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class PlagueLord : MLQuest
+ {
+ public PlagueLord()
+ {
+ Activated = true;
+ Title = 1073061; // Plague Lord
+ Description = 1074692; // Some of the most horrific creatures have slithered out of the sinkhole there and begun terrorizing the surrounding area. The plague creatures are one of the most destruction of the minions of Paroxysmus. Are you willing to do something about them?
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( PlagueSpawn ) }, "plague spawns", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus
+ Objectives.Add( new KillObjective( 3, new Type[] { typeof( PlagueBeast ) }, "plague beasts", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( PlagueBeastLord ) }, "plague beast lord", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class GlassyFoe : MLQuest
+ {
+ public GlassyFoe()
+ {
+ Activated = true;
+ Title = 1073055; // Glassy Foe
+ Description = 1074669; // Good, you're here. The presence of a twisted creature deep under the earth near Nu'Jelm has corrupted the natural growth of crystals in that region. They've become infused with the twisting energy - they've come to a sort of life. This is an abomination that festers within Sosaria. You must eradicate the crystal lattice seekers.
+ RefusalMessage = 1074671; // These abominations must not be permitted to fester!
+ InProgressMessage = 1074672; // You must not waste time. Do not suffer these crystalline abominations to live.
+ CompletionMessage = 1074673; // You have done well. Enjoy this reward.
+
+ Objectives.Add( new KillObjective( 5, new Type[] { typeof( CrystalLatticeSeeker ) }, "crystal lattice seekers", new QuestArea( 1074805, "The Prism of Light" ) ) ); // The Prism of Light
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class DaemonicPrism : MLQuest
+ {
+ public DaemonicPrism()
+ {
+ Activated = true;
+ Title = 1073053; // Daemonic Prism
+ Description = 1074668; // Good, you're here. The presence of a twisted creature deep under the earth near Nu'Jelm has corrupted the natural growth of crystals in that region. They've become infused with the twisting energy - they've come to a sort of life. This is an abomination that festers within Sosaria. You must eradicate the crystal daemons.
+ RefusalMessage = 1074671; // These abominations must not be permitted to fester!
+ InProgressMessage = 1074672; // You must not waste time. Do not suffer these crystalline abominations to live.
+ CompletionMessage = 1074673; // You have done well. Enjoy this reward.
+
+ Objectives.Add( new KillObjective( 3, new Type[] { typeof( CrystalDaemon ) }, "crystal daemons", new QuestArea( 1074805, "The Prism of Light" ) ) ); // The Prism of Light
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class Hailstorm : MLQuest
+ {
+ public Hailstorm()
+ {
+ Activated = true;
+ Title = 1073057; // Hailstorm
+ Description = 1074670; // Good, you're here. The presence of a twisted creature deep under the earth near Nu'Jelm has corrupted the natural growth of crystals in that region. They've become infused with the twisting energy - they've come to a sort of life. This is an abomination that festers within Sosaria. You must eradicate the crystal vortices.
+ RefusalMessage = 1074671; // These abominations must not be permitted to fester!
+ InProgressMessage = 1074672; // You must not waste time. Do not suffer these crystalline abominations to live.
+ CompletionMessage = 1074673; // You have done well. Enjoy this reward.
+
+ Objectives.Add( new KillObjective( 8, new Type[] { typeof( CrystalVortex ) }, "crystal vortices", new QuestArea( 1074805, "The Prism of Light" ) ) ); // The Prism of Light
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ /* TODO: Uncomment when Crystal Hydra is added
+ public class HowManyHeads : MLQuest
+ {
+ public HowManyHeads()
+ {
+ Activated = true;
+ Title = 1073050; // How Many Heads?
+ Description = 1074674; // Good, you're here. The presence of a twisted creature deep under the earth near Nu'Jelm has corrupted the natural growth of crystals in that region. They've become infused with the twisting energy - they've come to a sort of life. This is an abomination that festers within Sosaria. You must eradicate the crystal hydras.
+ RefusalMessage = 1074671; // These abominations must not be permitted to fester!
+ InProgressMessage = 1074672; // You must not waste time. Do not suffer these crystalline abominations to live.
+ CompletionMessage = 1074673; // You have done well. Enjoy this reward.
+
+ Objectives.Add( new KillObjective( 3, new Type[] { typeof( CrystalHydra ) }, "crystal hydras", new QuestArea( 1074805, "The Prism of Light" ) ) ); // The Prism of Light
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+ */
+
+ /* TODO: Uncomment when Dreadhorn is added
+ public class DreadhornQuest : MLQuest
+ {
+ public DreadhornQuest()
+ {
+ Activated = true;
+ Title = 1074645; // Dreadhorn
+ Description = 1074646; // Can you comprehend it? I cannot, I confess. The most pristine and perfect Lord of Sosaria has fallen prey to the blight. From the depths of my heart I mourn his corruption; my thoughts are filled with pity for this glorious creature now tainted. And my blood boils with fury at those responsible for the innocent creature's undoing. Will you find Dread Horn, as he is now called, and free him from this misery?
+ RefusalMessage = 1074647; // How can you not feel as I do?
+ InProgressMessage = 1074648; // The lush and fertile land where Dread Horn now lives is twisted and tainted, a result of his corruption. The fey folk have sealed the land off through their magics, but you can enter through an enchanted mushroom fairy circle.
+ CompletionMessage = 1074649; // Thank you. I haven't the words to express my gratitude.
+
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( DreadHorn ) }, "dread horn" ) );
+
+ Rewards.Add( ItemReward.RewardStrongbox );
+ }
+ }
+ */
+
+ /* TODO: Uncomment when SerpentsFangHighExecutioner, TigersClawThief and DragonsFlameGrandMage are added
+ public class NewLeadership : MLQuest
+ {
+ public NewLeadership()
+ {
+ Activated = true;
+ Title = 1072905; // New Leadership
+ Description = 1072963; // I have a task for you ... adventurer. Will you risk all to win great renown? The Black Order is organized into three sects, each with their own speciality. The Dragon's Flame serves the will of the Grand Mage, the Tiger's Claw answers to the Master Thief, and the Serpent's Fang kills at the direction of the High Executioner. Slay all three and you will strike the order a devastating blow!
+ RefusalMessage = 1072973; // I do not fault your decision.
+ InProgressMessage = 1072974; // Once you gain entrance into The Citadel, you will need to move cautiously to find the sect leaders.
+
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( SerpentsFangHighExecutioner ) }, "serpent's fang high executioner", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( TigersClawThief ) }, "tiger's claw thief", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( DragonsFlameGrandMage ) }, "dragon's flame mage", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel
+
+ Rewards.Add( ItemReward.RewardStrongbox );
+ }
+ }
+ */
+
+ /* TODO: Uncomment when SerpentsFangAssassin is added
+ public class ExAssassins : MLQuest
+ {
+ public ExAssassins()
+ {
+ Activated = true;
+ Title = 1072917; // Ex-Assassins
+ Description = 1072969; // The Serpent's Fang sect members have gone too far! Express to them my displeasure by slaying ten of them. But remember, I do not condone war on women, so I will only accept the deaths of men, human and elf.
+ RefusalMessage = 1072979; // As you wish.
+ InProgressMessage = 1072980; // The Black Order's fortress home is well hidden. Legend has it that a humble fishing village disguises the magical portal.
+
+ // TODO: This has to be MALES only!
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( SerpentsFangAssassin ) }, "male serpent's fang assassins", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+ */
+
+ /* TODO: Uncomment when DragonsFlameMage is added
+ public class ExtinguishingTheFlame : MLQuest
+ {
+ public ExtinguishingTheFlame()
+ {
+ Activated = true;
+ Title = 1072911; // Extinguishing the Flame
+ Description = 1072966; // The Dragon's Flame sect members have gone too far! Express to them my displeasure by slaying ten of them. But remember, I do not condone war on women, so I will only accept the deaths of men, human or elf. Either race will do, I care not for the shape of their ears. Yes, this action will properly make clear my disapproval and has a pleasing harmony.
+ RefusalMessage = 1072979; // As you wish.
+ InProgressMessage = 1072980; // The Black Order's fortress home is well hidden. Legend has it that a humble fishing village disguises the magical portal.
+
+ // TODO: This has to be MALES only!
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( DragonsFlameMage ) }, "male dragon's flame mages", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+ */
+
+ public class DeathToTheNinja : MLQuest
+ {
+ public DeathToTheNinja()
+ {
+ Activated = true;
+ Title = 1072913; // Death to the Ninja!
+ Description = 1072966; // I wish to make a statement of censure against the elite ninjas of the Black Order. Deliver, in the strongest manner, my disdain. But do not make war on women, even those that take arms against you. It is not ... fitting.
+ RefusalMessage = 1072979; // As you wish.
+ InProgressMessage = 1072980; // The Black Order's fortress home is well hidden. Legend has it that a humble fishing village disguises the magical portal.
+
+ // TODO: Verify that this has to be males only (as per the description)
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( EliteNinja ) }, "elite ninjas", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ /* TODO: Uncomment when TigersClawThief is added
+ public class CrimeAndPunishment : MLQuest
+ {
+ public CrimeAndPunishment()
+ {
+ Activated = true;
+ Title = 1072914; // Crime and Punishment
+ Description = 1072968; // The Tiger's Claw sect members have gone too far! Express to them my displeasure by slaying ten of them. But remember, I do not condone war on women, so I will only accept the deaths of men, human and elf.
+ RefusalMessage = 1072979; // As you wish.
+ InProgressMessage = 1072980; // The Black Order's fortress home is well hidden. Legend has it that a humble fishing village disguises the magical portal.
+
+ // TODO: This has to be MALES only!
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( TigersClawThief ) }, "male tiger's claw thieves", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+ */
+
+ /* TODO: Uncomment when ShimmeringEffusion is added
+ public class AllThatGlittersIsNotGood : MLQuest
+ {
+ public AllThatGlittersIsNotGood()
+ {
+ Activated = true;
+ Title = 1073048; // All That Glitters is Not Good
+ Description = 1074654; // The most incredible tale has reached my ears! Deep within the bowels of Sosaria, somewhere under the city of Nu'Jelm, a twisted creature feeds. What created this abomination, no one knows ... though there is some speculation that the fumbling initial efforts to open the portal to The Heartwood, brought it into existence. Regardless of it's origin, it must be destroyed before it damages Sosaria. Will you undertake this quest?
+ RefusalMessage = 1074655; // Perhaps I thought too highly of you.
+ InProgressMessage = 1074656; // An explorer discovered the cave system under Nu'Jelm. He made multiple trips into the place bringing back fascinating crystals and artifacts that suggested the hollow place in Sosaria was inhabited by other creatures at some point. You'll need to follow in his footsteps to find this abomination and destroy it.
+ CompletionMessage = 1074657; // I am overjoyed with your efforts! Your devotion to Sosaria is noted and appreciated.
+
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( ShimmeringEffusion ) }, "shimmering effusion" ) );
+
+ Rewards.Add( ItemReward.RewardStrongbox );
+ }
+ }
+ */
+
+ #endregion
+
+ #region Mobiles
+
+ public class Saril : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074186, // Come here, I have a task.
+ 1074183 // You there! I have a job for you.
+ ) );
+ }
+
+ [Constructable]
+ public Saril()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Saril";
+ Title = "the guard";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new WoodlandLegs() );
+ AddItem( new WoodlandArms() );
+ AddItem( new WoodlandBelt() );
+ AddItem( new WingedHelm() );
+ AddItem( new FemaleElvenPlateChest() );
+ AddItem( new RadiantScimitar() );
+ }
+
+ public Saril( 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 class Cailla : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074187, // Want a job?
+ 1074210 // Hi. Looking for something to do?
+ ) );
+ }
+
+ [Constructable]
+ public Cailla()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Cailla";
+ Title = "the guard";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new HidePants() );
+ AddItem( new HidePauldrons() );
+ AddItem( new HideGloves() );
+ AddItem( new WoodlandBelt() );
+ AddItem( new RavenHelm() );
+ AddItem( new HideFemaleChest() );
+ AddItem( new MagicalShortbow() );
+ }
+
+ public Cailla( 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 class Tamm : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074213, // Hey buddy. Looking for work?
+ 1074187 // Want a job?
+ ) );
+ }
+
+ [Constructable]
+ public Tamm()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Tamm";
+ Title = "the guard";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new HidePants() );
+ AddItem( new HidePauldrons() );
+ AddItem( new WingedHelm() );
+ AddItem( new HideChest() );
+ AddItem( new ElvenCompositeLongbow() );
+ }
+
+ public Tamm( 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 class Landy : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074211, // I could use some help.
+ 1074218 // Hey! I want to talk to you, now.
+ ) );
+ }
+
+ [Constructable]
+ public Landy()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Landy";
+ Title = "the soil nurturer";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( Utility.RandomYellowHue() ) );
+ AddItem( new ShortPants( Utility.RandomYellowHue() ) );
+ AddItem( new Tunic( Utility.RandomYellowHue() ) );
+
+ Item gloves = new LeafGloves();
+ gloves.Hue = Utility.RandomYellowHue();
+ AddItem( gloves );
+ }
+
+ public Landy( 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 class Alejaha : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074223 ); // Have you done it yet? Oh, I haven’t told you, have I?
+ }
+
+ [Constructable]
+ public Alejaha()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Elder Alejaha";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( Utility.RandomYellowHue() ) );
+ AddItem( new ElvenShirt( Utility.RandomYellowHue() ) );
+ AddItem( new GemmedCirclet() );
+ AddItem( new Cloak( Utility.RandomBrightHue() ) );
+
+ if ( Utility.RandomBool() )
+ AddItem( new Kilt( 0x387 ) );
+ else
+ AddItem( new Skirt( 0x387 ) );
+ }
+
+ public Alejaha( 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 class Mielan : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074219, // Hello there, can I have a moment of your time?
+ 1074223 // Have you done it yet? Oh, I haven’t told you, have I?
+ ) );
+ }
+
+ [Constructable]
+ public Mielan()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Mielan";
+ Title = "the arcanist";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x901 ) );
+ AddItem( new ElvenShirt( 0x56 ) );
+ AddItem( new GemmedCirclet() );
+ AddItem( new ElvenPants( 0x901 ) );
+ }
+
+ public Mielan( 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 class Ciala : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074206, // Excuse me please traveler, might I have a little of your time?
+ 1074186 // Come here, I have a task.
+ ) );
+ }
+
+ [Constructable]
+ public Ciala()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Ciala";
+ Title = "the arborist";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Skirt( Utility.RandomBlueHue() ) );
+ AddItem( new ElvenShirt( Utility.RandomYellowHue() ) );
+ AddItem( new RoyalCirclet() );
+
+ if ( Utility.RandomBool() )
+ AddItem( new Boots( Utility.RandomYellowHue() ) );
+ else
+ AddItem( new ThighBoots( Utility.RandomYellowHue() ) );
+ }
+
+ public Ciala( 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 class Aniel : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074220, // May I call you friend? I have a favor to beg of you.
+ 1074222 // Could I trouble you for some assistance?
+ ) );
+ }
+
+ [Constructable]
+ public Aniel()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Aniel";
+ Title = "the arborist";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenPants( 0x901 ) );
+ AddItem( new LeafChest() );
+ AddItem( new HalfApron( Utility.RandomYellowHue() ) );
+ AddItem( new ElvenBoots( 0x901 ) );
+ }
+
+ public Aniel( 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 class Aulan : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074188, // Weakling! You are not up to the task I have.
+ 1074191, // Just keep walking away! I thought so. Coward! I’ll bite your legs off!
+ 1074195 // You there, in the stupid hat! Come here.
+ ) );
+ }
+
+ [Constructable]
+ public Aulan()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Aulan";
+ Title = "the expeditionist";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ Item item;
+
+ item = new ElvenBoots();
+ item.Hue = Utility.RandomYellowHue();
+ AddItem( item );
+
+ AddItem( new ElvenPants( Utility.RandomGreenHue() ) );
+ AddItem( new Cloak( Utility.RandomGreenHue() ) );
+ AddItem( new Circlet() );
+
+ item = new HideChest();
+ item.Hue = Utility.RandomYellowHue();
+ AddItem( item );
+
+ item = new HideGloves();
+ item.Hue = Utility.RandomYellowHue();
+ AddItem( item );
+ }
+
+ public Aulan( 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 class Brinnae : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074212, // *yawn* You busy?
+ 1074210 // Hi. Looking for something to do?
+ ) );
+ }
+
+ [Constructable]
+ public Brinnae()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Brinnae";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new FemaleLeafChest() );
+ AddItem( new LeafArms() );
+ AddItem( new HidePants() );
+ AddItem( new ElvenCompositeLongbow() );
+ }
+
+ public Brinnae( 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 class Caelas : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074204, // Greetings seeker. I have an urgent matter for you, if you are willing.
+ 1074201 // Waste not a minute! There’s work to be done.
+ ) );
+ }
+
+ [Constructable]
+ public Caelas()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Elder Caelas";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x1BB ) );
+ AddItem( new MaleElvenRobe( 0x489 ) );
+ AddItem( new Cloak( 0x718 ) );
+ AddItem( new RoyalCirclet() );
+ }
+
+ public Caelas( 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 class Clehin : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074211, // I could use some help.
+ 1074186 // Come here, I have a task.
+ ) );
+ }
+
+ [Constructable]
+ public Clehin()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Clehin";
+ Title = "the soil nurturer";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new ElvenShirt() );
+ AddItem( new LeafTonlet() );
+ }
+
+ public Clehin( 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 class Cloorne : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074185, // Hey you! Want to help me out?
+ 1074186 //Come here, I have a task.
+ ) );
+ }
+
+ [Constructable]
+ public Cloorne()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Cloorne";
+ Title = "the expeditionist";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x3B2 ) );
+ AddItem( new RadiantScimitar() );
+ AddItem( new WingedHelm() );
+
+ Item item;
+
+ item = new WoodlandLegs();
+ item.Hue = 0x74A;
+ AddItem( item );
+
+ item = new HideChest();
+ item.Hue = 0x726;
+ AddItem( item );
+
+ item = new LeafArms();
+ item.Hue = 0x73E;
+ AddItem( item );
+ }
+
+ public Cloorne( 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 class Salaenih : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074207, // Good day to you friend! Allow me to offer you a fabulous opportunity! Thrills and adventure await!
+ 1074209 // Hey, could you help me out with something?
+ ) );
+ }
+
+ [Constructable]
+ public Salaenih()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Salaenih";
+ Title = "the expeditionist";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new WarCleaver() );
+
+ Item item;
+
+ item = new WoodlandBelt();
+ item.Hue = 0x597;
+ AddItem( item );
+
+ item = new VultureHelm();
+ item.Hue = 0x1BB;
+ AddItem( item );
+
+ item = new WoodlandLegs();
+ item.Hue = 0x1BB;
+ AddItem( item );
+
+ item = new WoodlandChest();
+ item.Hue = 0x1BB;
+ AddItem( item );
+
+ item = new WoodlandArms();
+ item.Hue = 0x1BB;
+ AddItem( item );
+ }
+
+ public Salaenih( 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 class Vilo : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074210, // Hi. Looking for something to do?
+ 1074220 // May I call you friend? I have a favor to beg of you.
+ ) );
+ }
+
+ [Constructable]
+ public Vilo()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Vilo";
+ Title = "the guard";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x901 ) );
+ AddItem( new OrnateAxe() );
+ AddItem( new WoodlandBelt( 0x592 ) );
+ AddItem( new VultureHelm() );
+ AddItem( new WoodlandLegs() );
+ AddItem( new WoodlandChest() );
+ AddItem( new WoodlandArms() );
+ AddItem( new WoodlandGorget() );
+ }
+
+ public Vilo( 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 class Tholef : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074209, // Hey, could you help me out with something?
+ 1074184 // Come here, I have work for you.
+ ) );
+ }
+
+ [Constructable]
+ public Tholef()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Tholef";
+ Title = "the grape tender";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( 0x901 ) );
+ AddItem( new FullApron( 0x756 ) );
+ AddItem( new ShortPants( 0x28C ) );
+ AddItem( new Shirt( 0x28C ) );
+
+ Item item;
+
+ item = new LeafArms();
+ item.Hue = 0x28C;
+ AddItem( item );
+ }
+
+ public Tholef( 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 class Tillanil : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074187, // Want a job?
+ 1074222 // Could I trouble you for some assistance?
+ ) );
+ }
+
+ [Constructable]
+ public Tillanil()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Tillanil";
+ Title = "the grape tender";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( 0x1BB ) );
+ AddItem( new Tunic( 0x759 ) );
+ AddItem( new ShortPants( 0x21 ) );
+ }
+
+ public Tillanil( 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 class Waelian : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074221, // Greetings! I have a small task for you good traveler.
+ 1074201 // Waste not a minute! There’s work to be done.
+ ) );
+ }
+
+ [Constructable]
+ public Waelian()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Waelian";
+ Title = "the trinket weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Shoes( 0x901 ) );
+ AddItem( new SmithHammer() );
+ AddItem( new LongPants( 0x340 ) );
+ AddItem( new GemmedCirclet() );
+
+ Item item;
+
+ item = new LeafChest();
+ item.Hue = 0x344;
+ AddItem( item );
+ }
+
+ public Waelian( 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 class Sleen : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074200, // Thank goodness you are here, there’s no time to lose.
+ 1074206 // Excuse me please traveler, might I have a little of your time?
+ ) );
+ }
+
+ [Constructable]
+ public Sleen()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Sleen";
+ Title = "the trinket weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x901 ) );
+ AddItem( new SmithHammer() );
+ AddItem( new Cloak( 0x75A ) );
+ AddItem( new ElvenShirt() );
+ }
+
+ public Sleen( 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 class Unoelil : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074186, // Come here, I have a task.
+ 1074209 // Hey, could you help me out with something?
+ ) );
+ }
+
+ [Constructable]
+ public Unoelil()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Unoelil";
+ Title = "the bark weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x1BB ) );
+ AddItem( new ShortPants( 0x1BB ) );
+ AddItem( new Tunic( 0x64D ) );
+ }
+
+ public Unoelil( 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 class Anolly : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ [Constructable]
+ public Anolly()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Anolly";
+ Title = "the bark weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( 0x901 ) );
+ AddItem( new ShortPants( 0x3B3 ) );
+ AddItem( new FullApron( 0x1BB ) );
+ AddItem( new SmithHammer() );
+ }
+
+ public Anolly( 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 class Jusae : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074210, // Hi. Looking for something to do?
+ 1074213 // Hey buddy. Looking for work?
+ ) );
+ }
+
+ [Constructable]
+ public Jusae()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Jusae";
+ Title = "the bowcrafter";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( 0x901 ) );
+ AddItem( new ShortPants( 0x661 ) );
+ AddItem( new MagicalShortbow() );
+
+ Item item;
+
+ item = new HideChest();
+ item.Hue = 0x27B;
+ AddItem( item );
+
+ item = new HidePauldrons();
+ item.Hue = 0x27E;
+ AddItem( item );
+ }
+
+ public Jusae( 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 class Cillitha : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074223, // Have you done it yet? Oh, I haven’t told you, have I?
+ 1074213 // Hey buddy. Looking for work?
+ ) );
+ }
+
+ [Constructable]
+ public Cillitha()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Cillitha";
+ Title = "the bowcrafter";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x901 ) );
+ AddItem( new ElvenShirt( 0x731 ) );
+ AddItem( new LeafLegs() );
+ }
+
+ public Cillitha( 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 class Lohn : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074187, // Want a job?
+ 1074209 // Hey, could you help me out with something?
+ ) );
+ }
+
+ [Constructable]
+ public Lohn()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lohn";
+ Title = "the metal weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Shoes( 0x901 ) );
+ AddItem( new LongPants( 0x359 ) );
+ AddItem( new SmithHammer() );
+ AddItem( new GemmedCirclet() );
+
+ Item item;
+
+ item = new LeafChest();
+ item.Hue = 0x359;
+ AddItem( item );
+ }
+
+ public Lohn( 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 class Olla : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074187, // Want a job?
+ 1074185 // Hey you! Want to help me out?
+ ) );
+ }
+
+ [Constructable]
+ public Olla()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Olla";
+ Title = "the metal weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new LongPants( 0x3B3 ) );
+ AddItem( new SmithHammer() );
+ AddItem( new FullApron( 0x1BB ) );
+ AddItem( new ElvenShirt() );
+
+ }
+
+ public Olla( 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 class Thallary : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074221, // Greetings! I have a small task for you good traveler.
+ 1074212 // *yawn* You busy?
+ ) );
+ }
+
+ [Constructable]
+ public Thallary()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Thallary";
+ Title = "the cloth weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( 0x901 ) );
+ AddItem( new LongPants( 0x72E ) );
+ AddItem( new Cloak( 0x3B3 ) );
+ AddItem( new FancyShirt( 0x13 ) );
+
+ }
+
+ public Thallary( 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 class Ahie : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074206, // Excuse me please traveler, might I have a little of your time?
+ 1074203 // Hello friend. I realize you are busy but if you would be willing to render me a service I can assure you that you will be judiciously renumerated.
+ ) );
+ }
+
+ [Constructable]
+ public Ahie()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Ahie";
+ Title = "the cloth weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Boots( 0x901 ) );
+ AddItem( new Skirt( 0x1C ) );
+ AddItem( new Cloak( 0x62 ) );
+ AddItem( new FancyShirt( 0x738 ) );
+
+ }
+
+ public Ahie( 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 class Tyeelor : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Tyeelor()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Tyeelor";
+ Title = "the expeditionist";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots( 0x1BB ) );
+
+ Item item;
+
+ item = new WoodlandLegs();
+ item.Hue = 0x236;
+ AddItem( item );
+
+ item = new WoodlandChest();
+ item.Hue = 0x236;
+ AddItem( item );
+
+ item = new WoodlandArms();
+ item.Hue = 0x236;
+ AddItem( item );
+
+ item = new VultureHelm();
+ item.Hue = 0x236;
+ AddItem( item );
+
+ item = new WoodlandBelt();
+ item.Hue = 0x236;
+ AddItem( item );
+
+ }
+
+ public Tyeelor( 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 class Athailon : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Athailon()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Athailon";
+ Title = "the expeditionist";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots( 0x901 ) );
+ AddItem( new WoodlandBelt() );
+ AddItem( new DiamondMace() );
+
+ Item item;
+
+ item = new WoodlandLegs();
+ item.Hue = 0x3B2;
+ AddItem( item );
+
+ item = new FemaleElvenPlateChest();
+ item.Hue = 0x3B2;
+ AddItem( item );
+
+ item = new WoodlandArms();
+ item.Hue = 0x3B2;
+ AddItem( item );
+
+ item = new WingedHelm();
+ item.Hue = 0x3B2;
+ AddItem( item );
+
+ }
+
+ public Athailon( 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 class ElderTaellia : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public ElderTaellia()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Elder Taellia";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ThighBoots( 0x127 ) );
+ AddItem( new FemaleElvenRobe( Utility.RandomBrightHue() ) );
+ AddItem( new MagicWand() );
+ AddItem( new Circlet() );
+
+ }
+
+ public ElderTaellia( 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 class ElderMallew : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public ElderMallew()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Elder Mallew";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots( 0x1BB ) );
+ AddItem( new Cloak( 0x3B2 ) );
+ AddItem( new Circlet() );
+
+ Item item;
+
+ item = new LeafTonlet();
+ item.Hue = 0x544;
+ AddItem( item );
+
+ item = new LeafChest();
+ item.Hue = 0x538;
+ AddItem( item );
+
+ item = new LeafArms();
+ item.Hue = 0x528;
+ AddItem( item );
+
+ }
+
+ public ElderMallew( 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 class ElderAbbein : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public ElderAbbein()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Elder Abbein";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots( 0x72C ) );
+ AddItem( new FemaleElvenRobe( 0x8B0 ) );
+ AddItem( new RoyalCirclet() );
+
+ }
+
+ public ElderAbbein( 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 class ElderVicaie : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public ElderVicaie()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Elder Vicaie";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new Tunic( 0x732 ) );
+
+ Item item;
+
+ item = new LeafLegs();
+ item.Hue = 0x3B2;
+ AddItem( item );
+
+ }
+
+ public ElderVicaie( 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 class ElderJothan : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public ElderJothan()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Elder Jothan";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ThighBoots() );
+ AddItem( new ElvenPants( 0x58D ) );
+ AddItem( new ElvenShirt( Utility.RandomYellowHue() ) );
+ AddItem( new Cloak( Utility.RandomBrightHue() ) );
+ AddItem( new Circlet() );
+
+ }
+
+ public ElderJothan( 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 class ElderAlethanian : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public ElderAlethanian()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Elder Alethanian";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new HidePants() );
+ AddItem( new HideFemaleChest() );
+ AddItem( new HidePauldrons() );
+ AddItem( new GemmedCirclet() );
+
+ }
+
+ public ElderAlethanian( 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 class Rebinil : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Rebinil()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Rebinil";
+ Title = "the healer";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Sandals( 0x715 ) );
+ AddItem( new FemaleElvenRobe( 0x742 ) );
+ AddItem( new RoyalCirclet() );
+
+ }
+
+ public Rebinil( 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 class Aluniol : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Aluniol()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Aluniol";
+ Title = "the healer";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots( 0x1BB ) );
+ AddItem( new MaleElvenRobe( 0x47E ) );
+ AddItem( new WildStaff() );
+
+ }
+
+ public Aluniol( 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 class Olaeni : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Olaeni()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Olaeni";
+ Title = "the thaumaturgist";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Shoes( 0x75A ) );
+ AddItem( new FemaleElvenRobe( 0x13 ) );
+ AddItem( new MagicWand() );
+ AddItem( new GemmedCirclet() );
+
+ }
+
+ public Olaeni( 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 class Bolaevin : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Bolaevin()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Bolaevin";
+ Title = "the arcanist";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots( 0x3B2 ) );
+ AddItem( new RoyalCirclet() );
+ AddItem( new LeafChest() );
+ AddItem( new LeafArms() );
+
+ Item item;
+
+ item = new LeafLegs();
+ item.Hue = 0x1BB;
+ AddItem( item );
+
+ }
+
+ public Bolaevin( 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 class LorekeeperAneen : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public LorekeeperAneen()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lorekeeper Aneen";
+ Title = "the keeper of tradition";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Sandals( 0x1BB ) );
+ AddItem( new MaleElvenRobe( 0x48F) );
+ AddItem( new MagicWand() );
+
+ }
+
+ public LorekeeperAneen( 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 class Daelas : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Daelas()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Daelas";
+ Title = "the arborist";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots( 0x901 ) );
+ AddItem( new ElvenPants( 0x8AB) );
+
+ Item item;
+
+ item = new LeafChest();
+ item.Hue = 0x8B0;
+ AddItem( item );
+
+ item = new LeafGloves();
+ item.Hue = 0x1BB;
+ AddItem( item );
+
+ }
+
+ public Daelas( 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 class Alelle : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Alelle()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Alelle";
+ Title = "the arborist";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots( 0x1BB ) );
+
+ Item item;
+
+ item = new FemaleLeafChest();
+ item.Hue = 0x3A;
+ AddItem( item );
+
+ item = new LeafLegs();
+ item.Hue = 0x74C;
+ AddItem( item );
+
+ item = new LeafGloves();
+ item.Hue = 0x1BB;
+ AddItem( item );
+
+ }
+
+ public Alelle( 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 class LorekeeperNillaen : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ [Constructable]
+ public LorekeeperNillaen()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lorekeeper Nillaen";
+ Title = "the keeper of tradition";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Shoes( 0x1BB ) );
+ AddItem( new LongPants( 0x1FB ) );
+ AddItem( new ElvenShirt() );
+ AddItem( new GemmedCirclet() );
+ AddItem( new BodySash( 0x25 ) );
+ AddItem( new BlackStaff() );
+ }
+
+ public LorekeeperNillaen( 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 class LorekeeperRyal : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074204, // Greetings seeker. I have an urgent matter for you, if you are willing.
+ 1074200 // Thank goodness you are here, there’s no time to lose.
+ ) );
+ }
+
+ [Constructable]
+ public LorekeeperRyal()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lorekeeper Ryal";
+ Title = "the keeper of tradition";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x1BB ) );
+ AddItem( new LeafTonlet() );
+ AddItem( new ElvenShirt( 0x2DD ) );
+ AddItem( new Cloak( 0x219 ) );
+ AddItem( new GnarledStaff() );
+ }
+
+ public LorekeeperRyal( 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 class Braen : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074187 ); // Want a job?
+ }
+
+ [Constructable]
+ public Braen()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Braen";
+ Title = "the thaumaturgist";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( 0x714 ) );
+ AddItem( new MaleElvenRobe( 0x64A ) );
+ AddItem( new MagicWand() );
+ }
+
+ public Braen( 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 class ElderAcob : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074197 ); // Pardon me, but if you could spare some time I’d greatly appreciate it.
+ }
+
+ [Constructable]
+ public ElderAcob()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Elder Acob";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x714 ) );
+ AddItem( new ElvenShirt( Utility.RandomBrightHue() ) );
+ AddItem( new HidePants() );
+ }
+
+ public ElderAcob( 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 class LorekeeperCalendor : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074204 ); // Greetings seeker. I have an urgent matter for you, if you are willing.
+ }
+
+ [Constructable]
+ public LorekeeperCalendor()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lorekeeper Calendor";
+ Title = "the keeper of tradition";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x714 ) );
+ AddItem( new ElvenShirt( Utility.RandomOrangeHue() ) );
+ AddItem( new Kilt( Utility.RandomOrangeHue() ) );
+ AddItem( new RoyalCirclet() );
+ }
+
+ public LorekeeperCalendor( 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 class LorekeeperSiarra : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074206 ); // Excuse me please traveler, might I have a little of your time?
+ }
+
+ [Constructable]
+ public LorekeeperSiarra()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lorekeeper Siarra";
+ Title = "the keeper of tradition";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( 0x1BB ) );
+ AddItem( new ElvenShirt() );
+ AddItem( new LeafTonlet() );
+ AddItem( new GemmedCirclet() );
+ }
+
+ public LorekeeperSiarra( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/Heritage.cs b/Scripts/Engines/MLQuests/Definitions/Heritage.cs
new file mode 100644
index 000000000..d74aa50d5
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/Heritage.cs
@@ -0,0 +1,812 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server.Engines.MLQuests.Rewards;
+using Server.Engines.MLQuests.Objectives;
+using Server.Items;
+using Server.Gumps;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Human To Elf Quests
+
+ public class Seasons : MLQuest
+ {
+ public override bool RecordCompletion { get { return true; } }
+
+ public Seasons()
+ {
+ Activated = true;
+ Title = 1072782; // Seasons
+ Description = 1072802; // *rumbling growl* *sniff* ... not-smell ... seek-fight ... not-smell ... fear-stench ... *rumble* ... cold-soon-time comes ... hungry ... eat-fish ... sleep-soon-time ... *deep fang-filled yawn* ... much-fish.
+ RefusalMessage = 1072810; // *yawn* ... cold-soon-time ... *growl*
+ InProgressMessage = 1072811; // *sniff* *sniff* ... not-much-fish ... hungry ... *grumble*
+ CompletionMessage = 1074174; // *sniff* fish! much-fish!
+
+ Objectives.Add( new CollectObjective( 20, typeof( RawFishSteak ), 1022426 ) ); // raw fish steak
+
+ Rewards.Add( new DummyReward( 1072803 ) ); // The boon of Maul.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1074940, "", 0x2A ); // You have gained the boon of Maul! Your understanding of the seasons grows. You are one step closer to claiming your elven heritage.
+ instance.ClaimRewards(); // skip gump
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Darius" ), new Point3D( 4310, 954, 10 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Darius" ), new Point3D( 4310, 954, 10 ), Map.Trammel );
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "MaulTheBear" ), new Point3D( 1730, 257, 16 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "MaulTheBear" ), new Point3D( 1730, 257, 16 ), Map.Trammel );
+ }
+ }
+
+ public class CaretakerOfTheLand : MLQuest
+ {
+ public override bool RecordCompletion { get { return true; } }
+
+ public CaretakerOfTheLand()
+ {
+ Activated = true;
+ Title = 1072783; // Caretaker of the Land
+ Description = 1072812; // Hrrrrr. Hurrrr. Huuuman. *creaking branches* Suuun on baaark, roooooots diiig deeeeeep, wiiind caaaresses leeeaves … Hrrrrr. Saaap of Sooosaria feeeeeeds us. Hrrrrr. Huuuman leeearn. Caaaretaker of plaaants … teeend … prooove.
+ RefusalMessage = 1072813; // Hrrrrr. Hrrrrr. Huuuman.
+ InProgressMessage = 1072814; // Hrrrr. Hrrrr. Roooooots neeeeeed saaap of Sooosaria. Hrrrrr. Roooooots tiiingle neeeaaar Yeeew. Seeeaaarch. Hrrrr!
+ CompletionMessage = 1074175; // Thiiirsty. Hurrr. Hurrr.
+
+ Objectives.Add( new CollectObjective( 1, typeof( SapOfSosaria ), "sap of sosaria" ) );
+
+ Rewards.Add( new DummyReward( 1072804 ) ); // The boon of Strongroot.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1074941, "", 0x2A ); // You have gained the boon of Strongroot! You have been approved by one whose roots touch the bones of Sosaria. You are one step closer to claiming your elven heritage.
+ instance.ClaimRewards(); // skip gump
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Strongroot" ), new Point3D( 597, 1744, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Strongroot" ), new Point3D( 597, 1744, 0 ), Map.Trammel );
+
+ PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 30 ), TimeSpan.FromMinutes( 2 ), 0, 12, "SapOfSosaria" ), new Point3D( 757, 1004, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 30 ), TimeSpan.FromMinutes( 2 ), 0, 12, "SapOfSosaria" ), new Point3D( 757, 1004, 0 ), Map.Trammel );
+ }
+ }
+
+ public class WisdomOfTheSphynx : MLQuest
+ {
+ public override bool RecordCompletion { get { return true; } }
+
+ public WisdomOfTheSphynx()
+ {
+ Activated = true;
+ Title = 1072784; // Wisdom of the Sphynx
+ Description = 1072822; // I greet thee human and divine my boon thou seek. Convey hence the object of my riddle and I shall reward thee with thy desire.
Three lives have I.
Gentle enough to soothe the skin,
Light enough to caress the sky,
Hard enough to crack rocks
What am I?
+ RefusalMessage = 1072823; // As thou wish, human.
+ InProgressMessage = 1072824; // I give thee a hint then human. The answer to my riddle must be held carefully or it cannot be contained at all. Bring this elusive item to me in a suitable container.
+ CompletionMessage = 1074176; // Ah, thus it ends.
+
+ Objectives.Add( new InternalObjective() );
+
+ Rewards.Add( new DummyReward( 1072805 ) ); // The boon of Enigma.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1074945, "", 0x2A ); // You have gained the boon of Enigma! You are wise enough to know how little you know. You are one step closer to claiming your elven heritage.
+ instance.ClaimRewards(); // skip gump
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Enigma" ), new Point3D( 1828, 961, 7 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Enigma" ), new Point3D( 1828, 961, 7 ), Map.Trammel );
+ }
+
+ private class InternalObjective : CollectObjective
+ {
+ public override bool ShowDetailed { get { return false; } }
+
+ public InternalObjective()
+ : base( 1, typeof( Pitcher ), 1074869 ) // The answer to the riddle.
+ {
+ }
+
+ public override bool CheckItem( Item item )
+ {
+ Pitcher pitcher = item as Pitcher; // Only pitchers work
+
+ return ( pitcher != null && pitcher.Content == BeverageType.Water && pitcher.Quantity > 0 );
+ }
+ }
+ }
+
+ public class DefendingTheHerd : MLQuest
+ {
+ public override bool RecordCompletion { get { return true; } }
+
+ public DefendingTheHerd()
+ {
+ Activated = true;
+ Title = 1072785; // Defending the Herd
+ Description = 1072825; // *snort* ... guard-mates ... guard-herd *hoof stomp* ... defend-with-hoof-and-horn ... thirsty-drink. *proud head-toss*
+ RefusalMessage = 1072826; // *snort*
+ InProgressMessage = 1072827; // *impatient hoof stomp* ... thirsty herd ... water scent.
+
+ Objectives.Add( new EscortObjective( new QuestArea( 1074779, "Bravehorn's drinking pool" ) ) ); // Bravehorn's drinking pool
+
+ Rewards.Add( new DummyReward( 1072806 ) ); // The boon of Bravehorn.
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1074942, "", 0x2A ); // You have gained the boon of Bravehorn! You have glimpsed the nobility of those that sacrifice themselves for their people. You are one step closer to claiming your elven heritage.
+ instance.ClaimRewards(); // skip gump
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 30 ), TimeSpan.FromSeconds( 90 ), 0, 5, "Bravehorn" ), new Point3D( 1193, 2467, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 30 ), TimeSpan.FromSeconds( 90 ), 0, 5, "Bravehorn" ), new Point3D( 1193, 2467, 0 ), Map.Trammel );
+
+ PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 20 ), TimeSpan.FromSeconds( 30 ), 0, 8, "BravehornsMate" ), new Point3D( 1192, 2467, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 20 ), TimeSpan.FromSeconds( 30 ), 0, 8, "BravehornsMate" ), new Point3D( 1192, 2467, 0 ), Map.Trammel );
+ }
+ }
+
+ public class TheBalanceOfNature : MLQuest
+ {
+ public override bool RecordCompletion { get { return true; } }
+
+ public TheBalanceOfNature()
+ {
+ Activated = true;
+ Title = 1072786; // The Balance of Nature
+ Description = 1072829; // Ho, there human. Why do you seek out the Huntsman? The hunter serves the land by culling both predators and prey. The hunter maintains the essential balance of life and does not kill for sport or glory. If you seek my favor, human, then demonstrate you are capable of the duty. Cull the wolves nearby.
+ RefusalMessage = 1072830; // Then begone. I have no time to waste on you, human.
+ InProgressMessage = 1072831; // The timber wolves are easily tracked, human.
+
+ Objectives.Add( new KillObjective( 15, new Type[] { typeof( TimberWolf ) }, "timber wolves", new QuestArea( 1074833, "Huntsman's Forest" ) ) ); // Huntsman's Forest
+
+ Rewards.Add( new DummyReward( 1072807 ) ); // The boon of the Huntsman.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1074943, "", 0x2A ); // You have gained the boon of the Huntsman! You have been given a taste of the bittersweet duty of those who guard the balance. You are one step closer to claiming your elven heritage.
+ instance.ClaimRewards(); // skip gump
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Huntsman" ), new Point3D( 1676, 593, 16 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Huntsman" ), new Point3D( 1676, 593, 16 ), Map.Trammel );
+
+ PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 15 ), 0, 10, "TimberWolf" ), new Point3D( 1671, 592, 16 ), Map.Felucca );
+ PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 15 ), 0, 10, "TimberWolf" ), new Point3D( 1671, 592, 16 ), Map.Trammel );
+ }
+ }
+
+ public class TheJoysOfLife : MLQuest
+ {
+ public override bool RecordCompletion { get { return true; } }
+
+ public TheJoysOfLife()
+ {
+ Activated = true;
+ Title = 1072787; // The Joys of Life
+ Description = 1072832; // *giggle* So serious, so grim! *tickle* Enjoy life! Have fun! Laugh! Be merry! *giggle* Find three of my baubles ... *giggle* I hid them! *giggles hysterically* Hid them! La la la! Bring them quickly! They are magical and will hide themselves again if you are too slow.
+ RefusalMessage = 1072833; // *giggle* Too serious. Too thinky!
+ InProgressMessage = 1072834; // Magical baubles hidden, find them as you're bidden! *giggle*
+ CompletionMessage = 1074177; // *giggle* So pretty!
+
+ Objectives.Add( new CollectObjective( 3, typeof( ABauble ), "arielle's baubles" ) );
+
+ Rewards.Add( new DummyReward( 1072809 ) ); // The boon of Arielle.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1074944, "", 0x2A ); // You have gained the boon of Arielle! You have been taught the importance of laughter and light spirits. You are one step closer to claiming your elven heritage.
+ instance.ClaimRewards(); // skip gump
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Arielle" ), new Point3D( 1560, 1182, -27 ), Map.Ilshenar );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Arielle" ), new Point3D( 3366, 292, 9 ), Map.Felucca ); // Felucca spawn for reds
+
+ PutSpawner( new Spawner( 6, TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 30 ), 0, 20, "ABauble" ), new Point3D( 1585, 1212, -13 ), Map.Ilshenar );
+ }
+ }
+
+ #endregion
+
+ #region Human To Elf Mobiles
+
+ public class MaulTheBear : GrizzlyBear
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public MaulTheBear()
+ {
+ Name = "Maul";
+ AI = AIType.AI_Vendor;
+ FightMode = FightMode.None;
+ Tamable = false;
+ }
+
+ public MaulTheBear( 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 class Strongroot : Treefellow
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Strongroot()
+ {
+ Name = "Strongroot";
+ AI = AIType.AI_Vendor;
+ FightMode = FightMode.None;
+ }
+
+ public Strongroot( 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 class Enigma : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Enigma()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Enigma";
+ BodyValue = 788;
+ BaseSoundID = 0x3EE;
+
+ InitStats( 100, 100, 25 );
+ }
+
+ public Enigma( 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 class Bravehorn : BaseEscortable
+ {
+ public override bool StaticMLQuester { get { return true; } }
+ public override bool InitialInnocent { get { return true; } }
+
+ [Constructable]
+ public Bravehorn()
+ {
+ }
+
+ public override void InitBody()
+ {
+ Name = "Bravehorn";
+ Body = 0xEA;
+
+ SetStr( 41, 71 );
+ SetDex( 47, 77 );
+ SetInt( 27, 57 );
+
+ SetHits( 27, 41 );
+ SetMana( 0 );
+
+ SetDamage( 5, 9 );
+
+ SetDamageType( ResistanceType.Physical, 100 );
+
+ SetResistance( ResistanceType.Physical, 20, 25 );
+ SetResistance( ResistanceType.Cold, 5, 10 );
+
+ SetSkill( SkillName.MagicResist, 26.8, 44.5 );
+ SetSkill( SkillName.Tactics, 29.8, 47.5 );
+ SetSkill( SkillName.Wrestling, 29.8, 47.5 );
+
+ Fame = 300;
+ Karma = 0;
+
+ VirtualArmor = 24;
+ }
+
+ public override void InitOutfit()
+ {
+ }
+
+ public override int GetAttackSound()
+ {
+ return 0x82;
+ }
+
+ public override int GetHurtSound()
+ {
+ return 0x83;
+ }
+
+ public override int GetDeathSound()
+ {
+ return 0x84;
+ }
+
+ public Bravehorn( 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 class BravehornsMate : Hind
+ {
+ [Constructable]
+ public BravehornsMate()
+ {
+ Name = "bravehorn's mate";
+ Tamable = false;
+ }
+
+ public BravehornsMate( 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 class Huntsman : Centaur
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Huntsman()
+ {
+ Name = "Huntsman";
+ AI = AIType.AI_Vendor;
+ FightMode = FightMode.None;
+ }
+
+ public Huntsman( 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 class Arielle : Pixie
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Arielle()
+ {
+ Name = "Arielle";
+ AI = AIType.AI_Vendor;
+ FightMode = FightMode.None;
+ }
+
+ public Arielle( 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
+
+ #region Elf To Human Quests
+
+ public class Ingenuity : MLQuest
+ {
+ public override bool RecordCompletion { get { return true; } }
+
+ public Ingenuity()
+ {
+ Activated = true;
+ Title = 1074350; // Ingenuity
+ Description = 1074462; // The best thing about my job is that I do a little bit of everything, every day. It's what we're good at really. Just picking up something and making it do something else. Listen, I'm really low on parts. Are you interested in fetching me some supplies?
+ RefusalMessage = 1074508; // Okay. Best of luck with your other endeavors.
+ InProgressMessage = 1074509; // Lord overseers are the best source I know for power crystals of the type I need. Iron golems too, can have them but they're harder to find.
+ CompletionMessage = 1074510; // Do you have those power crystals? I'm ready to put the finishing touches on my latest experiment.
+
+ Objectives.Add( new CollectObjective( 10, typeof( PowerCrystal ), "Power Crystals" ) );
+
+ Rewards.Add( new DummyReward( 1074875 ) ); // Another step closer to becoming human.
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1073775, "", 0x23 ); // Your quest is complete. Return for your reward.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1074946, "", 0x2A ); // You have demonstrated your ingenuity! Humans are jacks of all trades and know a little about a lot of things. You are one step closer to achieving humanity.
+ instance.ClaimRewards(); // skip gump
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Nedrick" ), new Point3D( 2958, 3466, 15 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Nedrick" ), new Point3D( 2958, 3466, 15 ), Map.Trammel );
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Sledge" ), new Point3D( 2673, 2129, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Sledge" ), new Point3D( 2673, 2129, 0 ), Map.Trammel );
+ }
+ }
+
+ public class HeaveHo : MLQuest
+ {
+ public override bool RecordCompletion { get { return true; } }
+
+ public HeaveHo()
+ {
+ Activated = true;
+ Title = 1074351; // Heave Ho!
+ Description = 1074519; // Ho there! There's nothing quite like a day's honest labor to make you appreciate being alive. Hey, maybe you'd like to help out with this project? These crates need to be delivered to Sledge. The only thing is -- it's a bit of a rush job and if you don't make it in time, he won't take them. Can I trust you to help out?
+ RefusalMessage = 1074521; // Oh yah, if you're too busy, no problem.
+ InProgressMessage = 1074522; // Sledge can be found in Buc's Den. Better hurry, he won't take those crates if you take too long with them.
+ CompletionMessage = 1074523; // Hey, if you have cargo for me, you can start unloading over here.
+
+ Objectives.Add( new TimedDeliverObjective( TimeSpan.FromHours( 1 ), typeof( CrateForSledge ), 5, "Crates for Sledge", typeof( Sledge ), "Sledge (Buc's Den)" ) );
+
+ Rewards.Add( new DummyReward( 1074875 ) ); // Another step closer to becoming human.
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1074948, "", 0x2A ); // You have demonstrated your physical strength! Humans can carry vast loads without complaint. You are one step closer to achieving humanity.
+ instance.ClaimRewards(); // skip gump
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Patricus" ), new Point3D( 3007, 823, -2 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Patricus" ), new Point3D( 3007, 823, -2 ), Map.Trammel );
+ }
+ }
+
+ // This is not a real quest, it is only used as a reference
+ public class HumanInNeed : MLQuest
+ {
+ public override bool RecordCompletion { get { return true; } }
+
+ public HumanInNeed()
+ {
+ Title = 1075011; // A quest that asks you to defend a human in need.
+ Description = 0;
+ RefusalMessage = 0;
+ InProgressMessage = 0;
+ }
+
+ public static void AwardTo( PlayerMobile pm )
+ {
+ MLQuestSystem.GetOrCreateContext( pm ).SetDoneQuest( MLQuestSystem.FindQuest( typeof( HumanInNeed ) ) );
+ pm.SendLocalizedMessage( 1074949, "", 0x2A ); // You have demonstrated your compassion! Your kind actions have been noted.
+ }
+ }
+
+ public class AllSeasonAdventurer : MLQuest
+ {
+ public override bool RecordCompletion { get { return true; } }
+
+ public AllSeasonAdventurer()
+ {
+ Activated = true;
+ Title = 1074353; // All Season Adventurer
+ Description = 1074527; // It's all about hardship, suffering, struggle and pain. Without challenges, you've got nothing to test yourself against -- and that's what life is all about. Self improvement! Honing your body and mind! Overcoming obstacles ... You'll see what I mean if you take on my challenge.
+ RefusalMessage = 1074528; // My way of life isn't for everyone, that's true enough.
+ InProgressMessage = 1074529; // You're not making much progress in the honing-mind-and-body department, are you?
+
+ Objectives.Add( new KillObjective( 5, new Type[] { typeof( Efreet ) }, "efreets", new QuestArea( 1074808, "Fire" ) ) ); // Fire
+ Objectives.Add( new KillObjective( 5, new Type[] { typeof( IceFiend ) }, "ice fiends", new QuestArea( 1074809, "Ice" ) ) ); // Ice
+
+ Rewards.Add( new DummyReward( 1074875 ) ); // Another step closer to becoming human.
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1073775, "", 0x23 ); // Your quest is complete. Return for your reward.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1074947, "", 0x2A ); // You have demonstrated your toughness! Humans are able to endure unimaginable hardships in pursuit of their goals. You are one step closer to achieving humanity.
+ instance.ClaimRewards(); // skip gump
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Belulah" ), new Point3D( 3782, 1266, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Belulah" ), new Point3D( 3782, 1266, 0 ), Map.Trammel );
+ }
+ }
+
+ #endregion
+
+ #region Elf To Human Mobiles
+
+ public class Sledge : BaseCreature
+ {
+ // TODO: Pointy Ears
+
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074188, // Weakling! You are not up to the task I have.
+ 1074195 // You there, in the stupid hat! Come here.
+ ) );
+ }
+
+ [Constructable]
+ public Sledge()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Sledge";
+ Title = "the Versatile";
+ Body = 400;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ AddItem( new Tunic( Utility.RandomNeutralHue() ) );
+ AddItem( new LongPants( Utility.RandomBlueHue() ) );
+ AddItem( new Cloak( Utility.RandomBrightHue() ) );
+ AddItem( new ElvenBoots( Utility.RandomNeutralHue() ) );
+ AddItem( new Backpack() );
+ }
+
+ public Sledge( 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 class Patricus : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Patricus()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Patricus";
+ Title = "the Trader";
+ Body = 400;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ AddItem( new FancyShirt( Utility.RandomNeutralHue() ) );
+ AddItem( new LongPants( Utility.RandomBrightHue() ) );
+ AddItem( new Cloak( 0x1BB ) );
+ AddItem( new Shoes( Utility.RandomNeutralHue() ) );
+ AddItem( new Backpack() );
+ }
+
+ public Patricus( 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 class Belulah : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ /*
+ * 1074205 - Oh great adventurer, would you please assist a weak soul in need of aid?
+ * 1074206 - Excuse me please traveler, might I have a little of your time?
+ */
+ MLQuestSystem.Tell( this, pm, Utility.Random( 1074205, 2 ) );
+ }
+
+ [Constructable]
+ public Belulah()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Belulah";
+ Title = "the scorned";
+ Female = true;
+ Body = 401;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new FancyShirt( Utility.RandomBlueHue() ) );
+ AddItem( new LongPants( Utility.RandomNondyedHue() ) );
+ AddItem( new Boots() );
+ }
+
+ public Belulah( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/HonestBeggar.cs b/Scripts/Engines/MLQuests/Definitions/HonestBeggar.cs
new file mode 100644
index 000000000..542da92f5
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/HonestBeggar.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.ContextMenus;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Misc;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Quests
+
+ public class HonestBeggar : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( ReginasThanks ); } }
+
+ public HonestBeggar()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1075392; // Honest Beggar
+ Description = 1075393; // Beg pardon, sir. I mean, madam. Uh, can I ask a favor of you? I found this jeweled ring. Most people would sell it and keep the money, but not me. I ain't never stole nothing, and I ain't about to start. I tried to take it over to Brit castle, figgerin' it must belong to some highborn lady, but the guards threw me out. You look like they might let you pass. Will you take the ring over there and see if you can find the owner?
+ RefusalMessage = 1075395; // I see. Too good to help an honest beggar like me, eh?
+ InProgressMessage = 1075396; // A jewel like this must be worth a lot, so it must belong to some noble or another. I would show it around the castle. Someone’s bound to recognize it.
+ 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.
+
+ Objectives.Add( new DeliverObjective( typeof( ReginasRing ), 1, 1075305, typeof( Regina ), "Regina" ) );
+
+ Rewards.Add( new DummyReward( 1075394 ) ); // Find the ring’s owner.
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Evan" ), new Point3D( 1486, 1706, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Evan" ), new Point3D( 1486, 1706, 0 ), Map.Felucca );
+ }
+ }
+
+ public class ReginasThanks : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public ReginasThanks()
+ {
+ Activated = true;
+ Title = 1075398; // Regina’s Thanks
+ Description = 1075399; // What’s that you say? It was a humble beggar that found my ring? Such honesty must be rewarded. Here, take this packet and return it to him, and I will be in your debt.
+ RefusalMessage = 1075401; // Hmph. Very well. What did you say his name was?
+ InProgressMessage = 1075402; // Take the packet and return it to the beggar who found my ring.
+ 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!
+
+ Objectives.Add( new DeliverObjective( typeof( ReginasLetter ), 1, 1075306, typeof( Evan ), "Evan" ) );
+
+ Rewards.Add( new ItemReward( 1075400, typeof( TransparentHeart ) ) ); // Transparent Heart
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Regina" ), new Point3D( 1362, 1622, 50 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Regina" ), new Point3D( 1422, 1621, 20 ), Map.Felucca );
+ }
+ }
+
+ #endregion
+
+ #region Mobiles
+
+ public class Evan : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Evan()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Evan";
+ Title = "the Beggar";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Doublet() );
+ AddItem( new ShortPants( 0x755 ) );
+
+ }
+
+ public Evan( 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 class Regina : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Regina()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Regina";
+ Title = "the Noble";
+ Race = Race.Human;
+ BodyValue = 0x191;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new GildedDress() );
+ AddItem( new Boots() );
+
+ }
+
+ public Regina( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/Ilshenar.cs b/Scripts/Engines/MLQuests/Definitions/Ilshenar.cs
new file mode 100644
index 000000000..4729475fd
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/Ilshenar.cs
@@ -0,0 +1,333 @@
+using System;
+using Server;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ public class Responsibility : BaseEscort
+ {
+ public Responsibility()
+ {
+ Activated = true;
+ Title = 1074352; // Responsibility
+ Description = 1074524; // Oh! I just don't know what to do. My mother is away and my father told me not to talk to strangers ... *worried frown* But my grandfather has sent word that he has been hurt and needs me to tend his wounds. He has a small farm southeast of here. Would you ... could you ... escort me there safely?
+ RefusalMessage = 1074525; // I hope my grandfather will be alright.
+ InProgressMessage = 1074526; // Grandfather's farm is a ways west of the Shrine of Spirituality. So, we're not quite there yet. Thank you again for keeping me safe.
+
+ Objectives.Add( new EscortObjective( new QuestArea( 1074781, "Sheep Farm" ) ) ); // Sheep Farm
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+
+ // OSI sends this instead, but it doesn't make sense for an escortable
+ //public override void OnComplete( MLQuestInstance instance )
+ //{
+ // instance.Player.SendLocalizedMessage( 1073775, "", 0x23 ); // Your quest is complete. Return for your reward.
+ //}
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 10 ), TimeSpan.FromSeconds( 30 ), 0, 5, "Lissbet" ), new Point3D( 1568, 1040, -7 ), Map.Ilshenar );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 8, "GrandpaCharley" ), new Point3D( 1322, 1331, -14 ), Map.Ilshenar );
+ PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 10 ), TimeSpan.FromSeconds( 30 ), 0, 3, "Sheep" ), new Point3D( 1308, 1324, -14 ), Map.Ilshenar );
+ }
+ }
+
+ public class SomethingToWailAbout : MLQuest
+ {
+ public SomethingToWailAbout()
+ {
+ Activated = true;
+ Title = 1073071; // Something to Wail About
+ Description = 1073561; // Can you hear them? The never-ending howling? The incessant wailing? These banshees, they never cease! Never! They haunt my nights. Please, I beg you -- will you silence them? I would be ever so grateful.
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073581; // Until you kill 12 Wailing Banshees, there will be no peace.
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( WailingBanshee ) }, "wailing banshees" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Jelrice" ), new Point3D( 1176, 1196, -25 ), Map.Ilshenar );
+ }
+ }
+
+ public class Runaways : MLQuest
+ {
+ public Runaways()
+ {
+ Activated = true;
+ Title = 1072993; // Runaways!
+ Description = 1073026; // You've got to help me out! Those wild ostards have been causing absolute havok around here. Kill them off before they destroy my land. There are around twelve of them.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( FrenziedOstard ) }, "frenzied ostards" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class ViciousPredator : MLQuest
+ {
+ public ViciousPredator()
+ {
+ Activated = true;
+ Title = 1072994; // Vicious Predator
+ Description = 1073028; // You've got to help me out! Those dire wolves have been causing absolute havok around here. Kill them off before they destroy my land. They run around in a pack of around ten.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( DireWolf ) }, "dire wolves" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class GuileIrkAndSpite : MLQuest
+ {
+ public GuileIrkAndSpite()
+ {
+ Activated = true;
+ Title = 1074739; // Guile, Irk and Spite
+ Description = 1074740; // You know them, don't you. The three? They look like you, you'll see. They looked like me, I remember, they looked like, well, you'll see. The three. They'll drive you mad too, if you let them. They are trouble, and they need to be slain. Seek them out.
+ RefusalMessage = 1074745; // You just don't understand the gravity of the situation. If you did, you'd agree to my task.
+ InProgressMessage = 1074746; // Perhaps I was unclear. You'll know them when you see them, because you'll see you, and you, and you. Hurry now.
+ CompletionMessage = 1074747; // Are you one of THEM? Ahhhh! Oh, wait, if you were them, then you'd be me. So you're -- you. Good job!
+
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( Guile ) }, "Guile" ) );
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( Irk ) }, "Irk" ) );
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( Spite ) }, "Spite" ) );
+
+ Rewards.Add( ItemReward.Strongbox );
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Yorus" ), new Point3D( 1389, 423, -24 ), Map.Ilshenar );
+ }
+ }
+
+ public class Lissbet : BaseEscortable
+ {
+ public override bool StaticMLQuester { get { return true; } }
+ public override bool InitialInnocent { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074204, // Greetings seeker. I have an urgent matter for you, if you are willing.
+ 1074222 // Could I trouble you for some assistance?
+ ) );
+ }
+
+ [Constructable]
+ public Lissbet()
+ {
+ }
+
+ public override void InitBody()
+ {
+ SetStr( 40, 50 );
+ SetDex( 70, 80 );
+ SetInt( 80, 90 );
+
+ Hue = Utility.RandomSkinHue();
+ Female = true;
+ Body = 401;
+ Name = "Lissbet";
+ Title = "the flower girl";
+
+ HairItemID = 0x203D;
+ HairHue = 0x1BB;
+ }
+
+ public override void InitOutfit()
+ {
+ AddItem( new Kilt( Utility.RandomYellowHue() ) );
+ AddItem( new FancyShirt( Utility.RandomYellowHue() ) );
+ AddItem( new Sandals() );
+ }
+
+ public Lissbet( 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 class GrandpaCharley : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ [Constructable]
+ public GrandpaCharley()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Grandpa Charley";
+ Title = "the farmer";
+ Body = 400;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ int hairHue = 0x3B2 + Utility.Random( 2 );
+ Utility.AssignRandomHair( this, hairHue );
+
+ FacialHairItemID = 0x203E; // Long Beard
+ FacialHairHue = hairHue;
+
+ SetSkill( SkillName.ItemID, 80, 90 );
+
+ AddItem( new WideBrimHat( Utility.RandomNondyedHue() ) );
+ AddItem( new FancyShirt( Utility.RandomNondyedHue() ) );
+ AddItem( new LongPants( Utility.RandomNondyedHue() ) );
+ AddItem( new Sandals( Utility.RandomNeutralHue() ) );
+ AddItem( new ShepherdsCrook() );
+ AddItem( new Backpack() );
+ }
+
+ public GrandpaCharley( 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 class Jelrice : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074221 ); // Greetings! I have a small task for you good traveler.
+ }
+
+ [Constructable]
+ public Jelrice()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Jelrice";
+ Title = "the trader";
+ Race = Race.Human;
+ BodyValue = 0x191;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Shoes( Utility.RandomNeutralHue() ) );
+ AddItem( new Skirt( Utility.RandomBlueHue() ) );
+ AddItem( new FancyShirt( Utility.RandomRedHue() ) );
+ }
+
+ public Jelrice( 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 class Yorus : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074218 ); // Hey! I want to talk to you, now.
+ }
+
+ [Constructable]
+ public Yorus()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Yorus";
+ Title = "the tinker";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Shoes( Utility.RandomNeutralHue() ) );
+ AddItem( new LongPants( Utility.RandomBlueHue() ) );
+ AddItem( new FancyShirt( Utility.RandomOrangeHue() ) );
+ AddItem( new Cloak( Utility.RandomBrightHue() ) );
+ }
+
+ public Yorus( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/NewHaven.cs b/Scripts/Engines/MLQuests/Definitions/NewHaven.cs
new file mode 100644
index 000000000..6c119b759
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/NewHaven.cs
@@ -0,0 +1,126 @@
+using System;
+using Server;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ public class NewHavenEscort : BaseEscort
+ {
+ // New Haven escorts do not count for 'helping a human in need'
+ public override bool AwardHumanInNeed { get { return false; } }
+
+ // Escort reward
+ private static readonly BaseReward m_Reward = new ItemReward( "Gold", typeof( Gold ), 500 );
+
+ public NewHavenEscort( int title, int description, int progress, int destination, string region )
+ {
+ Activated = true;
+ Title = title;
+ Description = description;
+ RefusalMessage = 1072288; // I wish you would reconsider my offer. I'll be waiting right here for someone brave enough to assist me.
+ InProgressMessage = progress;
+
+ Objectives.Add( new EscortObjective( new QuestArea( destination, region ) ) );
+
+ Rewards.Add( m_Reward );
+ }
+ }
+
+ public class EscortToNHAlchemist : NewHavenEscort
+ {
+ public EscortToNHAlchemist()
+ : base( 1072314, 1042769, 1072326, 1073864, "the New Haven Alchemist" )
+ {
+ }
+ }
+
+ public class EscortToNHBard : NewHavenEscort
+ {
+ public EscortToNHBard()
+ : base( 1072315, 1042772, 1072327, 1073865, "the New Haven Bard" )
+ {
+ }
+ }
+
+ public class EscortToNHWarrior : NewHavenEscort
+ {
+ public EscortToNHWarrior()
+ : base( 1072316, 1042787, 1072328, 1073866, "the New Haven Warrior" )
+ {
+ }
+ }
+
+ public class EscortToNHTailor : NewHavenEscort
+ {
+ public EscortToNHTailor()
+ : base( 1072317, 1042781, 1072329, 1073867, "the New Haven Tailor" )
+ {
+ }
+ }
+
+ public class EscortToNHCarpenter : NewHavenEscort
+ {
+ public EscortToNHCarpenter()
+ : base( 1072318, 1042775, 1072330, 1073868, "the New Haven Carpenter" )
+ {
+ }
+ }
+
+ public class EscortToNHMapmaker : NewHavenEscort
+ {
+ public EscortToNHMapmaker()
+ : base( 1072319, 1042793, 1072331, 1073869, "the New Haven Mapmaker" )
+ {
+ }
+ }
+
+ public class EscortToNHMage : NewHavenEscort
+ {
+ public EscortToNHMage()
+ : base( 1072320, 1042790, 1072332, 1073870, "the New Haven Mage" )
+ {
+ }
+ }
+
+ public class EscortToNHInn : NewHavenEscort
+ {
+ public EscortToNHInn()
+ : base( 1072321, 1042796, 1072333, 1073871, "the New Haven Inn" )
+ {
+ }
+ }
+
+ public class EscortToNHFarm : NewHavenEscort
+ {
+ public EscortToNHFarm()
+ : base( 1072322, 1042799, 1072334, 1073872, "the New Haven Farm" )
+ {
+ }
+ }
+
+ public class EscortToNHDocks : NewHavenEscort
+ {
+ public EscortToNHDocks()
+ : base( 1072323, 1042802, 1072335, 1073873, "the New Haven Docks" )
+ {
+ }
+ }
+
+ public class EscortToNHBowyer : NewHavenEscort
+ {
+ public EscortToNHBowyer()
+ : base( 1072324, 1042805, 1072336, 1073874, "the New Haven Bowyer" )
+ {
+ }
+ }
+
+ public class EscortToNHBank : NewHavenEscort
+ {
+ public EscortToNHBank()
+ : base( 1072325, 1042784, 1072337, 1073875, "the New Haven Bank" )
+ {
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/NewHavenSkillTraining.cs b/Scripts/Engines/MLQuests/Definitions/NewHavenSkillTraining.cs
new file mode 100644
index 000000000..2e2b63cf9
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/NewHavenSkillTraining.cs
@@ -0,0 +1,2517 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.ContextMenus;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Misc;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Quests
+
+ public class CleansingOldHaven : MLQuest
+ {
+ public CleansingOldHaven()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077719; // Cleansing Old Haven
+ Description = 1077722; // Head East out of town to Old Haven. Consecrate your weapon, cast Divine Fury, and battle monsters there until you have raised your Chivalry skill to 50.
------
Hail, friend. The life of a Paladin is a life of much sacrifice, humility, bravery, and righteousness. If you wish to pursue such a life, I have an assignment for you. Adventure east to Old Haven, consecrate your weapon, and lay to rest the undead that inhabit there.
Each ability a Paladin wishes to invoke will require a certain amount of "tithing points" to use. A Paladin can earn these tithing points by donating gold at a shrine or holy place. You may tithe at this shrine.
Return to me once you feel that you are worthy of the rank of Apprentice Paladin.
+ RefusalMessage = 1077723; // Farewell to you my friend. Return to me if you wish to live the life of a Paladin.
+ InProgressMessage = 1077724; // There are still more undead to lay to rest. You still have more to learn. Return to me once you have done so.
+ CompletionMessage = 1077726; // Well done, friend. While I know you understand Chivalry is its own reward, I would like to reward you with something that will protect you in battle. It was passed down to me when I was a lad. Now, I am passing it on you. It is called the Bulwark Leggings. Thank you for your service.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Chivalry, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077727, typeof( BulwarkLeggings ) ) ); // Bulwark Leggings
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077725, "", 0x23 ); // You have achieved the rank of Apprentice Paladin. Return to Aelorn in New Haven to report your progress.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Aelorn" ), new Point3D( 3527, 2516, 45 ), Map.Trammel );
+ }
+ }
+
+ public class TheRudimentsOfSelfDefense : MLQuest
+ {
+ public TheRudimentsOfSelfDefense()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077609; // The Rudiments of Self Defense
+ Description = 1077610; // Head East out of town and go to Old Haven. Battle monster there until you have raised your Wrestling skill to 50.Listen up! If you want to learn the rudiments of self-defense, you need toughening up, and there's no better way to toughen up than engaging in combat. Head East out of town to Old Haven and battle the undead there in hand to hand combat. Afraid of dying, you say? Well, you should be! Being an adventurer isn't a bed of posies, or roses, or however that saying goes. If you take a dirt nap, go to one of the nearby wandering healers and they'll get you back on your feet.Come back to me once you feel that you are worthy of the rank Apprentice Wrestler and i will reward you wit a prize.
+ RefusalMessage = 1077611; // Ok, featherweight. come back to me if you want to learn the rudiments of self-defense.
+ InProgressMessage = 1077630; // You have not achived the rank of Apprentice Wrestler. Come back to me once you feel that you are worthy of the rank Apprentice Wrestler and i will reward you with something useful.
+ CompletionMessage = 1077613; // It's about time! Looks like you managed to make it through your self-defense training. As i promised, here's a little something for you. When worn, these Gloves of Safeguarding will increase your awareness and resistances to most elements except poison. Oh yeah, they also increase your natural health regeneration aswell. Pretty handy gloves, indeed. Oh, if you are wondering if your meditation will be hinered while wearing these gloves, it won't be. Mages can wear cloth and leather items without needing to worry about that. Now get out of here and make something of yourself.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Wrestling, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077614, typeof( GlovesOfSafeguarding ) ) ); // Gloves Of Safeguarding
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077612, "", 0x23 ); // You have achieved the rank of Apprentice Wrestler. Return to Dimethro in New Haven to receive your prize.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Dimethro" ), new Point3D( 3528, 2520, 25 ), Map.Trammel );
+ }
+ }
+
+ public class CrushingBonesAndTakingNames : MLQuest
+ {
+ public CrushingBonesAndTakingNames()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1078070; // Crushing Bones and Taking Names
+ Description = 1078065; // Head East out of town and go to Old Haven. While wielding your mace,battle monster there until you have raised your Mace Fighting skill to 50. I see you want to learn a real weapon skill and not that toothpick training Jockles hasto offer. Real warriors are called Armsmen, and they wield mace weapons. No doubt about it. Nothing is more satisfying than knocking the wind out of your enemies, smashing there armor, crushing their bones, and taking there names. Want to learn how to wield a mace? Well i have an assignment for you. Head East out of town and go to Old Haven. Undead have plagued the town, so there are plenty of bones for you to smash there. Come back to me after you have ahcived the rank of Apprentice Armsman, and i will reward you with a real weapon.
+ RefusalMessage = 1078068; // I thought you wanted to be an Armsman and really make something of yourself. You have potential, kid, but if you want to play with toothpicks, run to Jockles and he will teach you how to clean your teeth with a sword. If you change your mind, come back to me, and i will show you how to wield a real weapon.
+ InProgressMessage = 1078067; // Listen kid. There are a lot of undead in Old Haven, and you haven't smashed enough of them yet. So get back there and do some more cleansing.
+ CompletionMessage = 1078069; // Now that's what I'm talking about! Well done! Don't you like crushing bones and taking names? As i promised, here is a war mace for you. It hits hard. It swings fast. It hits often. What more do you need? Now get out of here and crush some more enemies!
+
+ Objectives.Add( new GainSkillObjective( SkillName.Macing, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1078062, typeof( ChurchillsWarMace ) ) ); // Churchill's War Mace
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1078068, "", 0x23 ); // You have achieved the rank of Apprentice Armsman. Return to Churchill in New Haven to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Churchill" ), new Point3D( 3531, 2531, 20 ), Map.Trammel );
+ }
+ }
+
+ public class SwiftAsAnArrow : MLQuest
+ {
+ public SwiftAsAnArrow()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1078201; // Swift as an Arrow
+ Description = 1078205; // Head East out of town and go to Old Haven. While wielding your bow or crossbow, battle monster there until you have raised your Archery skill to 50. Well met, friend. Imagine yourself in a distant grove of trees, You raise your bow, take slow, careful aim, and with the twitch of a finger, you impale your prey with a deadly arrow. You look like you would make a excellent archer, but you will need practice. There is no better way to practice Archery than when you life is on the line. I have a challenge for you. Head East out of town and go to Old Haven. While wielding your bow or crossbow, battle the undead that reside there. Make sure you bring a healthy supply of arrows (or bolts if you prefer a crossbow). If you wish to purchase a bow, crossbow, arrows, or bolts, you can purchase them from me or the Archery shop in town. You can also make your own arrows with the Bowcraft/Fletching skill. You will need fletcher's tools, wood to turn into sharft's, and feathers to make arrows or bolts. Come back to me after you have achived the rank of Apprentice Archer, and i will reward you with a fine Archery weapon.
+ RefusalMessage = 1078206; // I understand that Archery may not be for you. Feel free to visit me in the future if you change your mind.
+ InProgressMessage = 1078207; // You're doing great as an Archer! however, you need more practice.
+ CompletionMessage = 1078209; // Congratulation! I want to reward you for your accomplishment. Take this composite bow. It is called " Heartseeker". With it, you will shoot with swiftness, precision, and power. I hope "Heartseeker" serves you well.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Archery, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1078210, typeof( Heartseeker ) ) ); // Heartseeker
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1078208, "", 0x23 ); // You have achieved the rank of Apprentice Archer. Return to Robyn in New Haven to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Robyn" ), new Point3D( 3535, 2531, 20 ), Map.Trammel );
+ }
+ }
+
+ public class EnGuarde : MLQuest
+ {
+ public EnGuarde()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1078186; // En Guarde!
+ Description = 1078190; // Head East out of town to Old Haven. Battle monsters there until you have raised your Fencing skill to 50.
------
Well hello there, lad. Fighting with elegance and precision is far more enriching than slugging an enemy with a club or butchering an enemy with a sword. Learn the art of Fencing if you want to master combat and look good doing it!
The key to being a successful fencer is to be the complement and not the opposition to your opponent's strength. Watch for your opponent to become off balance. Then finish him off with finesse and flair.
There are some undead that need cleansing out in Old Haven towards the East. Head over there and slay them, but remember, do it with style!
Come back to me once you have achieved the rank of Apprentice Fencer, and I will reward you with a prize.
+ RefusalMessage = 1078191; // I understand, lad. Being a hero isn't for everyone. Run along, then. Come back to me if you change your mind.
+ InProgressMessage = 1078192; // You're doing well so far, but you're not quite ready yet. Head back to Old Haven, to the East, and kill some more undead.
+ CompletionMessage = 1078194; // Excellent! You are beginning to appreciate the art of Fencing. I told you fighting with elegance and precision is more enriching than fighting like an ogre.
Since you have returned victorious, please take this war fork and use it well. The war fork is a finesse weapon, and this one is magical! I call it "Recaro's Riposte". With it, you will be able to parry and counterstrike with ease! Your enemies will bask in your greatness and glory! Good luck to you, lad, and keep practicing!
+
+ Objectives.Add( new GainSkillObjective( SkillName.Fencing, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1078195, typeof( RecarosRiposte ) ) ); // Recaro's Riposte
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1078193, "", 0x23 ); // You have achieved the rank of Apprentice Fencer. Return to Recaro in New Haven to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Recaro" ), new Point3D( 3536, 2534, 20 ), Map.Trammel );
+ }
+ }
+
+ public class TheArtOfWar : MLQuest
+ {
+ public TheArtOfWar()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077667; // The Art of War
+ Description = 1077670; // Head East out of town to Old Haven. Battle monsters there until you have raised your Tactics skill to 50.
------
Knowing how to hold a weapon is only half of the battle. The other half is knowing how to use it against an opponent. It's one thing to kill a few bunnies now and then for fun, but a true warrior knows that the right moves to use against a lich will pretty much get your arse fried by a dragon.
I'll help teach you how to fight so that when you do come up against that dragon, maybe you won't have to walk out of there "OooOOooOOOooOO'ing" and looking for a healer.
There are some undead that need cleaning out in Old Haven towards the east. Why don't you head on over there and practice killing things?
When you feel like you've got the basics down, come back to me and I'll see if I can scrounge up an item to help you in your adventures later on.
+ RefusalMessage = 1077671; // That's too bad. I really thought you had it in you. Well, I'm sure those undead will still be there later, so if you change your mind, feel free to stop on by and I'll help you the best I can.
+ InProgressMessage = 1077672; // You're making some progress, that i can tell, but you're not quite good enough to last for very long out there by yourself. Head back to Old Haven, to the east, and kill some more undead.
+ CompletionMessage = 1077674; // Hey, good job killing those undead! Hopefully someone will come along and clean up the mess. All that blood and guts tends to stink after a few days, and when the wind blows in from the east, it can raise a mighty stink!
Since you performed valiantly, please take these arms and use them well. I've seen a few too many harvests to be running around out there myself, so you might as well take it.
There is a lot left for you to learn, but I think you'll do fine. Remember to keep your elbows in and stick'em where it hurts the most!
+
+ Objectives.Add( new GainSkillObjective( SkillName.Tactics, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077675, typeof( ArmsOfArmstrong ) ) ); // Arms of Armstrong
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077673, "", 0x23 ); // You have achieved the rank of Apprentice Warrior. Return to Alden Armstrong in New Haven to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "AldenArmstrong" ), new Point3D( 3535, 2538, 20 ), Map.Trammel );
+ }
+ }
+
+ public class TheWayOfTheBlade : MLQuest
+ {
+ public TheWayOfTheBlade()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077658; // The way of The Blade
+ Description = 1077661; // Head East out of town and go to Old Haven. While wielding your sword, battle monster there until you have raised your Swordsmanship skill to 50. *as you approach, you notice Jockles sizing you up with a skeptical look on his face* i can see you want to learn how to handle a blade. It's a lot harder than it looks, and you're going to have to put alot of time and effort if you ever want to be half as good as i am. I'll tell you what, kid, I'll help you get started, but you're going to have to do all the work if you want to learn something. East of here, outside of town, is Old Haven. It's been overrun with the nastiest of undead you've seen, which makes it a perfect place for you to turn that sloppy grin on your face into actual skill at handling a sword. Make sure you have a sturdy Swordsmanship weapon in good repair before you leave. 'tis no fun to travel all the way down there just to find out you forgot your blade! When you feel that you've cut down enough of those foul smelling things to learn how to handle a blade without hurting yourself, come back to me. If i think you've improved enough, I'll give you something suited for a real warrior.
+ RefusalMessage = 1077662; // Ha! I had a feeling you were a lily-livered pansy. You might have potential, but you're scared by a few smelly undead, maybe it's better that you stay away from sharp objects. After all, you wouldn't want to hurt yourself swinging a sword. If you change your mind, I might give you another chance...maybe.
+ InProgressMessage = 1077663; // *Jockles looks you up and down* Come on! You've got to work harder than that to get better. Now get out of here, go kill some more of those undead to the east in Old Haven, and don't come back till you've got real skill.
+ CompletionMessage = 1077665; // Well, well, look at what we have here! You managed to do it after all. I have to say, I'm a little surprised that you came back in one piece, but since you did. I've got a little something for you. This is a fine blade that served me well in my younger days. Of course I've got much better swords at my disposal now, so I'll let you go ahead and use it under one condition. Take goodcare of it and treat it with the respect that a fine sword deserves. You're one of the quickers learners I've seen, but you still have a long way to go. Keep at it, and you'll get there someday. Happy hunting, kid.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Swords, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077666, typeof( JocklesQuicksword ) ) ); // Jockles' Quicksword
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077664, "", 0x23 ); // You have achieved the rank of Apprentice Swordsman. Return to Jockles in New Haven to see what kind of reward he has waiting for you. Hopefully he'll be a little nicer this time!
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Jockles" ), new Point3D( 3535, 2544, 20 ), Map.Trammel );
+ }
+ }
+
+ public class ThouAndThineShield : MLQuest
+ {
+ public ThouAndThineShield()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077704; // Thou and Thine Shield
+ Description = 1077707; // Head East out of town and go to Old Haven. Battle monsters, or simply let them hit you, while holding a shield or a weapon until you have raised your Parrying skill to 50. Oh, hello. You probably want me to teach you how to parry, don't you? Very Well. First, you'll need a weapon or a shield. Obviously shields work best of all, but you can parry with a 2-handed weapon. Or if you're feeling particularly brave, a 1-handed weapon will do in a pinch, I'd advise you to go to Old Haven, which you'll find to the East, and practice blocking incoming blows from the undead there. You'll learn quickly if you have more than one opponent attacking you at the same time to practice parrying lots of blows at once. That's the quickest way to master the art of parrying. If you manage to improve your skill enough, i have a shield that you might find useful. Come back to me when you've trained to an apprentice level.
+ RefusalMessage = 1077708; // It's your choice, obviously, but I'd highly suggest that you learn to parry before adventuring out into the world. Come talk to me again when you get tired of being beat on by your opponents
+ InProgressMessage = 1077709; // You're doing well, but in my opinion, I Don't think you really want to continue on without improving your parrying skill a bit more. Go to Old Haven, to the East, and practice blocking blows with a shield.
+ CompletionMessage = 1077711; // Well done! You're much better at parrying blows than you were when we first met. You should be proud of your new ability and I bet your body is greatful to you aswell. *Tyl Ariadne laughs loudly at his ownn (mostly lame) joke* Oh yes, I did promise you a shield if I thought you were worthy of having it, so here you go. My father made these shields for the guards who served my father faithfully for many years, and I just happen to have obe that i can part with. You should find it useful as you explore the lands.Good luck, and may the Virtues be your guide.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Parry, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077694, typeof( EscutcheonDeAriadne ) ) ); // Escutcheon de Ariadne
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077710, "", 0x23 ); // You have achieved the rank of Apprentice Warrior (for Parrying). Return to Tyl Ariadne in New Haven as soon as you can to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "TylAriadne" ), new Point3D( 3525, 2556, 20 ), Map.Trammel );
+ }
+ }
+
+ public class DefyingTheArcane : MLQuest
+ {
+ public DefyingTheArcane()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077621; // Defying the Arcane
+ Description = 1077623; // Head East out of town and go to Old Haven. Battle spell casting monsters there until you have raised your Resisting Spells skill to 50.
------
Hail and well met! To become a true master of the arcane art of Magery, I suggest learning the complementary skill known as Resisting Spells. While the name of this skill may suggest that it helps with resisting all spells, this is not the case. This skill helps you lessen the severity of spells that lower your stats or ones that last for a specific duration of time. It does not lessen damage from spells such as Energy Bolt or Flamestrike.
The Magery spells that can be resisted are Clumsy, Curse, Feeblemind, Mana Drain, Mana Vampire, Paralyze, Paralyze Field, Poison, Poison Field, and Weaken.
The Necromancy spells that can be resisted are Blood Oath, Corpse Skin, Mind Rot, and Pain Spike.
At higher ranks, the Resisting Spells skill also benefits you by adding a bonus to your minimum elemental resists. This bonus is only applied after all other resist modifications - such as from equipment - has been calculated. It's also not cumulative. It compares the number of your minimum resists to the calculated value of your modifications and uses the higher of the two values.
As you can see, Resisting Spells is a difficult skill to understand, and even more difficult to master. This is because in order to improve it, you will have to put yourself in harm's way - as in the path of one of the above spells.
Undead have plagued the town of Old Haven. We need your assistance in cleansing the town of this evil influence. Old Haven is located east of here. Battle the undead spell casters that inhabit there.
Comeback to me once you feel that you are worthy of the rank of Apprentice Mage and I will reward you with an arcane prize.
+ RefusalMessage = 1077624; // The ability to resist powerful spells is a taxing experience. I understand your resistance in wanting to pursue it. If you wish to reconsider, feel free to return to me for Resisting Spells training. Good journey to you!
+ InProgressMessage = 1077632; // You have not achieved the rank of Apprentice Mage. Come back to me once you feel that you are worthy of the rank of Apprentice Mage and I will reward you with an arcane prize.
+ CompletionMessage = 1077626; // You have successfully begun your journey in becoming a true master of Magery. On behalf of the New Haven Mage Council I wish to present you with this bracelet. When worn, the Bracelet of Resilience will enhance your resistances vs. the elements, physical, and poison harm. The Bracelet of Resilience also magically enhances your ability fend off ranged and melee attacks. I hope it serves you well.
+
+ Objectives.Add( new GainSkillObjective( SkillName.MagicResist, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077627, typeof( BraceletOfResilience ) ) ); // Bracelet of Resilience
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077625, "", 0x23 ); // You have achieved the rank of Apprentice Mage (for Resisting Spells). Return to Alefian in New Haven to receive your arcane prize.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Alefian" ), new Point3D( 3473, 2497, 72 ), Map.Trammel );
+ }
+ }
+
+ public class StoppingTheWorld : MLQuest
+ {
+ public StoppingTheWorld()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077597; // Stopping the World
+ Description = 1077598; // Head East out of town and go to Old Haven. Use spells and abilites to deplete your mana and meditate there until you have raised your Meditation skill to 50. Well met! I can teach you how to 'Stop the World' around you and focus your inner energies on replenishing you mana. What is mana? Mana is the life force for everyone who practices arcane arts. When a practitioner of magic invokes a spell or scribes a scroll. It consumes mana. Having a abundant supply of mana is vital to excelling as a practitioner of the arcane. Those of us who study the art of Meditation are also known as stotics. The Meditation skill allows stoics to increase the rate at which they regenerate mana A Stoic needs to perform abilities or cast spells to deplete mana before he can meditate to replenish it. Meditation can occur passively or actively. Actively Meditation is more difficult to master but allows for the stoic to replenish mana at a significantly faster rate. Metal armor inerferes with the regenerative properties of Meditation. It is wise to wear leather or cloth protection when meditating. Head east out of town and go to Old Haven. Use spells and abilities to deplete your mana and actively meditate to replenish it. Come back once you feel you are at the worthy rank of Apprentice Stoic and i will reward you with a arcane prize.
+ RefusalMessage = 1077599; // Seek me out if you ever wish to study the art of Meditation. Good journey.
+ InProgressMessage = 1077628; // You have not achived the rank of Apprentice Stoic. Come back to me once you feel that you are worthy of the rank Apprentice Stoic and i will reward you with a arcane prize.
+ CompletionMessage = 1077626; // You have successfully begun your journey in becoming a true master of Magery. On behalf of the New Haven Mage Council I wish to present you with this bracelet. When worn, the Bracelet of Resilience will enhance your resistances vs. the elements, physical, and poison harm. The Bracelet of Resilience also magically enhances your ability fend off ranged and melee attacks. I hope it serves you well.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Meditation, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077602, typeof( PhilosophersHat ) ) ); // Philosopher's Hat
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077600, "", 0x23 ); // You have achieved the rank of Apprentice Stoic (for Meditation). Return to Gustar in New Haven to receive your arcane prize.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Gustar" ), new Point3D( 3474, 2492, 91 ), Map.Trammel );
+ }
+ }
+
+ public class ScribingArcaneKnowledge : MLQuest
+ {
+ public ScribingArcaneKnowledge()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077615; // Scribing Arcane Knowledge
+ Description = 1077616; // While Here ar the New Haven Magery Library, use scribe's pen and scribe 3rd and 4th circle Magery scrolls that you have in your spellbook. Remeber, you will need blank scrolls aswell. Do this until you have raised your Inscription skill to 50. Greetings and welcome to the New Haven Magery Library! You wish to learn how to scribe spell scrolls? You have come to the right place! Inscribeed in a steady hand and imbued with te power of reagents, a scroll can mean the difference between life and death in a perilous situation. Those knowledgeable in Inscription man transcribe spells to create useful and valuale magical scrolls. Before you can inscribe a spell, you must first be able to cast the spell without the aid of a scroll. This means that you need the appropriate level of proficiency as a mage, the required mana, and the required reagents. Second, you will need a blank scroll to write on and a scribe's pen. Then, you will need to decide which particular spell you wish to scribe. It may sound easy, but there is a bit more to it. As with the development of all skills, you need to practice Inscription of lower level spells before you can move onto the more difficult ones. The most important aspect of Inscription is mana. Inscribing a scroll with a magic spell drains your mana. When inscribing 3rd or lower spells this is will not be much of a problem for these spells consume a small amount of mana. However, when you are inscribing higher circle spells, you may see your mana drain rapidly. When this happens, pause or meditate before continuing.I suggest you begin scribing any 3rd and 4th circle spells that you know. If you don't possess ant, you can alwayers barter with one of the local mage merchants or a fellow adventurer that is a seasoned Scribe. Come back to me once you feel that you are the worthy rankof Apprentice Scribe and i will reward you with an arcane prize.
+ RefusalMessage = 1077617; // I understand. When you are ready, feel free to return to me for Inscription training. Thanks for stopping by!
+ InProgressMessage = 1077631; // You have not achived the rank of Apprentice Scribe. Come back to me once you feel that you are worthy of the rank Apprentice Scribe and i will reward you with a arcane prize.
+ CompletionMessage = 1077619; // Scribing is a very fulfilling pursuit. I am please to see you embark on this journey. You sling a pen well! On behalf of the New Haven Mage Council I wish to present you with this spellbook. When equipped, the Hallowed Spellbook greatly enhanced the potency of your offensive soells when used against Undead. Be mindful, though. While this book is equiped you invoke powerful spells and abilities vs Humanoids, such as other humans, orcs, ettins, and trolls. Your offensive spells will diminish in effectiveness. I suggest unequipping the Hallowed Spellbook when battling Humanoids. I hope this spellbook serves you well.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Inscribe, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077620, typeof( HallowedSpellbook ) ) ); // Hallowed Spellbook
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077618, "", 0x23 ); // You have achieved the rank of Apprentice Scribe. Return to Jillian in New Haven to receive your arcane prize.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Jillian" ), new Point3D( 3465, 2490, 71 ), Map.Trammel );
+ }
+ }
+
+ public class TheMagesApprentice : MLQuest
+ {
+ public TheMagesApprentice()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077576; // The Mage's Apprentice
+ Description = 1077577; // Head East out of town and go to Old Haven. Cast fireballs and lightning bolts against monsters there until you have raised your Magery skill to 50. Greetings. You seek to unlock the secrets of the arcane art of Magery. The New Haven Mage Council has an assignment for you. Undead have plagued the town of Old Haven. We need your assistance in cleansing the town of this evil influence. Old Haven is located east of here. I suggest using your offensive Magery spells such as Fireball and Lightning Bolt against the Undead that inhabit there. Make sure you have plenty of reagents before embarking on your journey. Reagents are required to cast Magery spells. You can purchase extra reagents at the nearby Reagent shop, or you can find reagents growing in the nearby wooded areas. You can see which reagents are required for each spell by looking in your spellbook. Come back to me once you feel that you are worthy of the rank of Apprentice Mage and I will reward you with an arcane prize.
+ RefusalMessage = 1077578; // Very well, come back to me when you are ready to practice Magery. You have so much arcane potential. 'Tis a shame to see it go to waste. The New Haven Mage Council could really use your help.
+ InProgressMessage = 1077579; // You have not achieved the rank of Apprentice Mage. Come back to me once you feel that you are worthy of the rank of Apprentice Mage and I will reward you with an arcane prize.
+ CompletionMessage = 1077581; // Well done! On behalf of the New Haven Mage Council I wish to present you with this staff. Normally a mage must unequip weapons before spell casting. While wielding your new Ember Staff, however, you will be able to invoke your Magery spells. Even if you do not currently possess skill in Mace Fighting, the Ember Staff will allow you to fight as if you do. However, your Magery skill will be temporarily reduced while doing so. Finally, the Ember Staff occasionally smites a foe with a Fireball while wielding it in melee combat. I hope the Ember Staff serves you well.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Magery, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077582, typeof( EmberStaff ) ) ); // Ember Staff
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077580, "", 0x23 ); // You have achieved the rank of Apprentice Mage. Return to Kaelynna in New Haven to receive your arcane prize.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Kaelynna" ), new Point3D( 3486, 2491, 52 ), Map.Trammel );
+ }
+ }
+
+ public class ScholarlyTask : MLQuest
+ {
+ public ScholarlyTask()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077603; // A Scholarly Task
+ Description = 1077604; // Head East out of town and go to Old Haven. Use Evaluating Intelligence on all creatures you see there. You can also cast Magery spells as well to raise Evaluating Intelligence. Do these activities until you have raised your Evaluating Intelligence skill to 50.
------
Hello. Truly knowing your opponent is essential for landing your offensive spells with precision. I can teach you how to enhance the effectiveness of your offensive spells, but first you must learn how to size up your opponents intellectually. I have a scholarly task for you. Head East out of town and go to Old Haven. Use Evaluating Intelligence on all creatures you see there. You can also cast Magery spells as well to raise Evaluating Intelligence.
Come back to me once you feel that you are worthy of the rank of Apprentice Scholar and I will reward you with an arcane prize.
+ RefusalMessage = 1077605; // Return to me if you reconsider and wish to become an Apprentice Scholar.
+ InProgressMessage = 1077629; // You have not achieved the rank of Apprentice Scholar. Come back to me once you feel that you are worthy of the rank of Apprentice Scholar and I will reward you with an arcane prize.
+ CompletionMessage = 1077607; // You have completed the task. Well done. On behalf of the New Haven Mage Council I wish to present you with this ring. When worn, the Ring of the Savant enhances your intellectual aptitude and increases your mana pool. Your spell casting abilities will take less time to invoke and recovering from such spell casting will be hastened. I hope the Ring of the Savant serves you well.
+
+ Objectives.Add( new GainSkillObjective( SkillName.EvalInt, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077608, typeof( RingOfTheSavant ) ) ); // Ring of the Savant
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077606, "", 0x23 ); // You have achieved the rank of Apprentice Scholar. Return to Mithneral in New Haven to receive your arcane prize.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Mithneral" ), new Point3D( 3485, 2491, 71 ), Map.Trammel );
+ }
+ }
+
+ public class TheRightToolForTheJob : MLQuest
+ {
+ public TheRightToolForTheJob()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077741; // The Right Tool for the Job
+ Description = 1077744; // Create new scissors and hammers while inside Amelia's workshop. Try making scissors up to 45 skill, the switch to making hammers until 50 skill.
-----
Hello! I guess you're here to learn something about Tinkering, eh? You've come to the right place, as Tinkering is what I've dedicated my life to.
You'll need two things to get started: a supply of ingots and the right tools for the job. You can either buy ingots from the market, or go mine them yourself. As for tools, you can try making your own set of Tinker's Tools, or if you'd prefer to buy them, I have some for sale.
Working here in my shop will let me give you pointers as you go, so you'll be able to learn faster than anywhere else. Start off making scissors until you reach 45 tinkering skill, then switch to hammers until you've achieved 50. Once you've done that, come talk to me and I'll give you something for your hard work.
+ RefusalMessage = 1077745; // I’m disappointed that you aren’t interested in learning more about Tinkering. It’s really such a useful skill!
*Amelia smiles*
At least you know where to find me if you change your mind, since I rarely spend time outside of this shop.
+ InProgressMessage = 1077746; // Nice going! You're not quite at Apprentice Tinkering yet, though, so you better get back to work. Remember that the quickest way to learn is to make scissors up until 45 skill, and then switch to hammers. Also, don't forget that working here in my shop will let me give you tips so you can learn faster.
+ CompletionMessage = 1077748; // You've done it! Look at our brand new Apprentice Tinker! You've still got quite a lot to learn if you want to be a Grandmaster Tinker, but I believe you can do it! Just keep in mind that if you're tinkering just to practice and improve your skill, make items that are moderately difficult (60-80% success chance), and try to stick to ones that use less ingots.
Come here, my brand new Apprentice Tinker, I want to give you something special. I created this just for you, so I hope you like it. It's a set of Tinker's Tools that contains a bit of magic. These tools have more charges than any Tinker's Tools a Tinker can make. You can even use them to make a normal set of tools, so that way you won't ever find yourself stuck somewhere with no tools!
+
+ Objectives.Add( new GainSkillObjective( SkillName.Tinkering, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077749, typeof( AmeliasToolbox ) ) ); // Amelia’s Toolbox
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077747, "", 0x23 ); // You have achieved the rank of Apprentice Tinker. Talk to Amelia Youngstone in New Haven to see what kind of reward she has waiting for you.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "AmeliaYoungstone" ), new Point3D( 3459, 2529, 53 ), Map.Trammel );
+ }
+ }
+
+ public class KnowThineEnemy : MLQuest
+ {
+ public KnowThineEnemy()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077685; // Know Thine Enemy
+ Description = 1077688; // Head East out of town to Old Haven. Battle monsters there, or heal yourself and other players, until you have raised your Anatomy skill to 50.
------
Hail and well met. You must be here to improve your knowledge of Anatomy. Well, you've come to the right place because I can teach you what you need to know. At least all you'll need to know for now. Haha!
Knowing about how living things work inside can be a very useful skill. Not only can you learn where to strike an opponent to hurt him the most, but you can use what you learn to heal wounds better as well. Just walking around town, you can even tell if someone is strong or weak or if they happen to be particularly dexterous or not.
If you're interested in learning more, I'd advise you to head out to Old Haven, just to the east, and jump into the fray. You'll learn best by engaging in combat while keeping you and your fellow adventurers healed, or you can even try sizing up your opponents.
While you're gone, I'll dig up something you may find useful.
+ RefusalMessage = 1077689; // It's your choice, but I wouldn't head out there without knowing what makes those things tick inside! If you change your mind, you can find me right here dissecting frogs, cats or even the occasional unlucky adventurer.
+ InProgressMessage = 1077690; // I'm surprised to see you back so soon. You've still got a ways to go if you want to really understand the science of Anatomy. Head out to Old Haven and practice combat and healing yourself or other adventurers.
+ CompletionMessage = 1077692; // By the Virtues, you've done it! Congratulations mate! You still have quite a ways to go if you want to perfect your knowledge of Anatomy, but I know you'll get there someday. Just keep at it.
In the meantime, here's a piece of armor that you might find useful. It's not fancy, but it'll serve you well if you choose to wear it.
Happy adventuring, and remember to keep your cranium separate from your clavicle!
+
+ Objectives.Add( new GainSkillObjective( SkillName.Anatomy, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077693, typeof( TunicOfGuarding ) ) ); // Tunic of Guarding
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077691, "", 0x23 ); // You have achieved the rank of Apprentice Healer (for Anatomy). Return to Andreas Vesalius in New Haven as soon as you can to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "AndreasVesalius" ), new Point3D( 3457, 2550, 35 ), Map.Trammel );
+ }
+ }
+
+ public class BruisesBandagesAndBlood : MLQuest
+ {
+ public BruisesBandagesAndBlood()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077676; // Bruises, Bandages and Blood
+ Description = 1077679; // Head East out of town and go to Old Haven. Heal yourself and other players until you have raised your Healing skill to 50.
------
Ah, welcome to my humble practice. I am Avicenna, New Haven's resident Healer. A lot of adventurers head out into the wild from here, so I keep rather busy when they come back bruised, bleeding, or worse.
I can teach you how to bandage a wound, sure, but it's not a job for the queasy! For some folks, the mere sight of blood is too much for them, but it's something you'll get used to over time. It is one thing to cut open a living thing, but it's quite another to sew it back up and save it from sure death. 'Tis noble work, healing.
Best way for you to practice fixing up wounds is to head east out to Old Haven and either practice binding up your own wounds, or practice on someone else. Surely they'll be grateful for the assistance.
Make sure to take enough bandages with you! You don't want to run out in the middle of a tough fight.
+ RefusalMessage = 1077680; // No? Are you sure? Well, when you feel that you're ready to practice your healing, come back to me. I'll be right here, fixing up adventurers and curing the occasional cold!
+ InProgressMessage = 1077681; // Hail! 'Tis good to see you again. Unfortunately, you're not quite ready to call yourself an Apprentice Healer quite yet. Head back out to Old Haven, due east from here, and bandage up some wounds. Yours or someone else's, it doesn't much matter.
+ CompletionMessage = 1077683; // Hello there, friend. I see you've returned in one piece, and you're an Apprentice Healer to boot! You should be proud of your accomplishment, as not everyone has "the touch" when it comes to healing.
I can't stand to see such good work go unrewarded, so I have something I'd like you to have. It's not much, but it'll help you heal just a little faster, and maybe keep you alive.
Good luck out there, friend, and don't forget to help your fellow adventurer whenever possible!
+
+ Objectives.Add( new GainSkillObjective( SkillName.Healing, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077684, typeof( HealersTouch ) ) ); // Healer's Touch
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077682, "", 0x23 ); // You have achieved the rank of Apprentice Healer. Return to Avicenna in New Haven as soon as you can to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Avicenna" ), new Point3D( 3464, 2558, 35 ), Map.Trammel );
+ }
+ }
+
+ public class TheInnerWarrior : MLQuest
+ {
+ public TheInnerWarrior()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077696; // The Inner Warrior
+ Description = 1077699; // Head East out of town to Old Haven. Expend stamina and mana until you have raised your Focus skill to 50.
------
Well, hello there. Don't you look like quite the adventurer!
You want to learn more about Focus, do you? I can teach you something about that, but first you should know that not everyone can be disciplined enough to excel at it. Focus is the ability to achieve inner balance in both body and spirit, so that you recover from physical and mental exertion faster than you otherwise would.
If you want to practice Focus, the best place to do that is east of here, in Old Haven, where you'll find an undead infestation. Exert yourself physically by engaging in combat and moving quickly. For testing your mental balance, expend mana in whatever way you find most suitable to your abilities. Casting spells and using abilities work well for consuming your mana.
Go. Train hard, and you will find that your concentration will improve naturally. When you've improved your ability to focus yourself at an Apprentice level, come back to me and I shall give you something worthy of your new ability.
+ RefusalMessage = 1077700; // I'm disappointed. You have a lot of inner potential, and it would pain me greatly to see you waste that. Oh well. If you change your mind, I'll be right here.
+ InProgressMessage = 1077701; // Hello again. I see you've returned, but it seems that your Focus skill hasn't improved as much as it could have. Just head east, to Old Haven, and exert yourself physically and mentally as much as possible. To do this physically, engage in combat and move as quickly as you can. For exerting yourself mentally, expend mana in whatever way you find most suitable to your abilities. Casting spells and using abilities work well for consuming your mana.
Return to me when you have gained enough Focus skill to be considered an Apprentice Stoic.
+ CompletionMessage = 1077703; // Look who it is! I knew you could do it if you just had the discipline to apply yourself. It feels good to recover from battle so quickly, doesn't it? Just wait until you become a Grandmaster, it's amazing!
Please take this gift, as you've more than earned it with your hard work. It will help you recover even faster during battle, and provides a bit of protection as well.
You have so much more potential, so don't stop trying to improve your Focus now! Safe travels!
+
+ Objectives.Add( new GainSkillObjective( SkillName.Focus, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077695, typeof( ClaspOfConcentration ) ) ); // Clasp of Concentration
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077702, "", 0x23 ); // You have achieved the rank of Apprentice Stoic (for Focus). Return to Sarsmea Smythe in New Haven to see what kind of reward she has waiting for you.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "SarsmeaSmythe" ), new Point3D( 3492, 2577, 15 ), Map.Trammel );
+ }
+ }
+
+ public class TheArtOfStealth : MLQuest
+ {
+ public TheArtOfStealth()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1078154; // The Art of Stealth
+ Description = 1078158; // Head East out of town and go to Old Haven. While wielding your fencing weapon, battle monsters with focus attack and summon mirror images up to 40 Ninjitsu skill, and continue practicing focus attack on monsters until 50 Ninjitsu skill.
------
Welcome, young one. You seek to learn Ninjitsu. With it, and the book of Ninjitsu, a Ninja can evoke a number of special abilities including transforming into a variety of creatures that give unique bonuses, using stealth to attack unsuspecting opponents or just plain disappear into thin air! If you do not have a book of Ninjitsu, you can purchase one from me.
I have an assignment for you. Head East out of town and go to Old Haven. While wielding your fencing weapon, battle monsters with focus attack and summon mirror images up to Novice rank, and continue focusing your attacks for greater damage on monsters until you become an Apprentice Ninja. Each image will absorb one attack. The art of deception is a strong defense. Use it wisely.
Come back to me once you have achieved the rank of Apprentice Ninja, and I shall reward you with something useful.
+ RefusalMessage = 1078159; // Come back to me if you with to learn Ninjitsu in the future.
+ InProgressMessage = 1078160; // You have not achieved the rank of Apprentice Ninja. Come back to me once you have done so.
+ CompletionMessage = 1078162; // You have done well, young one. Please accept this kryss as a gift. It is called the "Silver Serpent Blade". With it, you will strike with precision and power. This should aid you in your journey as a Ninja. Farewell.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Ninjitsu, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1078163, typeof( SilverSerpentBlade ) ) ); // Silver Serpent Blade
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1078161, "", 0x23 ); // You have achieved the rank of Apprentice Ninja. Return to Ryuichi in New Haven to see what kind of reward he has waiting for you.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Ryuichi" ), new Point3D( 3422, 2520, 21 ), Map.Trammel );
+ }
+ }
+
+ public class BecomingOneWithTheShadows : MLQuest
+ {
+ public BecomingOneWithTheShadows()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1078164; // Becoming One with the Shadows
+ Description = 1078168; // Practice hiding in the Ninja Dojo until you reach 50 Hiding skill.
------
Come closer. Don't be afraid. The shadows will not harm you. To be a successful Ninja, you must learn to become one with the shadows. The Ninja Dojo is the ideal place to learn the art of concealment. Practice hiding here.
Talk to me once you have achieved the rank of Apprentice Rogue (for Hiding), and I shall reward you.
+ RefusalMessage = 1078169; // If you wish to become one with the shadows, come back and talk to me.
+ InProgressMessage = 1078170; // You have not achieved the rank of Apprentice Rogue (for Hiding). Talk to me when you feel you have accomplished this.
+ CompletionMessage = 1078172; // Not bad at all. You have learned to control your fear of the dark and you are becoming one with the shadows. If you haven't already talked to Jun, I advise you do so. Jun can teach you how to stealth undetected. Hiding and Stealth are essential skills to master when becoming a Ninja.
As promised, I have a reward for you. Here are some smokebombs. As long as you are an Apprentice Ninja and have mana available you will be able to use them. They will allow you to hide while in the middle of combat. I hope these serve you well.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Hiding, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1078173, typeof( BagOfSmokeBombs ) ) ); // Bag of Smoke Bombs
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1078171, "", 0x23 ); // You have achieved the rank of Apprentice Rogue (for Hiding). Return to Chiyo in New Haven to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Chiyo" ), new Point3D( 3420, 2516, 21 ), Map.Trammel );
+ }
+ }
+
+ public class WalkingSilently : MLQuest
+ {
+ public WalkingSilently()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1078174; // Walking Silently
+ Description = 1078178; // Head East out of town and go to Old Haven. While wearing normal clothes, practice Stealth there until you reach 50 Stealth skill.
------
You there. You're not very quiet in your movements. I can help you with that. Not only must you must learn to become one with the shadows, but also you must learn to quiet your movements. Old Haven is the ideal place to learn how to Stealth.
Head East out of town and go to Old Haven. While wearing normal clothes, practice Stealth there. Stealth becomes more difficult as you wear heavier pieces of armor, so for now, only wear clothes while practicing Stealth.
You can only Stealth once you are hidden. If you become visible, use your Hiding skill, and begin slowing walking.
Come back to me once you have achieved the rank of Apprentice Rogue (for Stealth), and I will reward you with something useful.
+ RefusalMessage = 1078179; // If you want to learn to quiet your movements, talk to me, and I will help you.
+ InProgressMessage = 1078180; // You have not achieved the rank of Apprentice Rogue (for Stealth). Come back to me when you feel you have accomplished this.
+ CompletionMessage = 1078182; // Good. You have learned to quiet your movements. If you haven't already talked to Chiyo, I advise you do so. Chiyo can teach you how to become one with the shadows. Hiding and Stealth are essential skills to master when becoming a Ninja.
Here is your reward. This leather Ninja jacket is called "Twilight Jacket". It will offer greater protection to you. I hope this serve you well.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Stealth, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1078183, typeof( TwilightJacket ) ) ); // Twilight Jacket
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1078181, "", 0x23 ); // You have achieved the rank of Apprentice Rogue (for Stealth). Return to Jun in New Haven to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Jun" ), new Point3D( 3422, 2516, 21 ), Map.Trammel );
+ }
+ }
+
+ public class EyesOfARanger : MLQuest
+ {
+ public EyesOfARanger()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1078211; // Eyes of a Ranger
+ Description = 1078217; // Track animals, monsters, and people on Haven Island until you have raised your Tracking skill to 50.
------
Hello friend. I am Walker, Grandmaster Ranger. An adventurer needs to keep alive in the wilderness. Being able to track those around you is essential to surviving in dangerous places. Certain Ninja abilities are more potent when the Ninja possesses Tracking knowledge. If you want to be a Ninja, or if you simply want to get a leg up on the creatures that habit these parts, I advise you learn how to track them.
You can track any animals, monsters, or people on Haven Island. Clear your mind, focus, and note any tracks in the ground or sounds in the air that can help you find your mark. You can do it, friend. I have faith in you.
Come back to me once you have achieved the rank of Apprentice Ranger (for Tracking), and I will give you something that may help you in your travels. Take care, friend.
+ RefusalMessage = 1078218; // Farewell, friend. Be careful out here. If you change your mind and want to learn Tracking, come back and talk to me.
+ InProgressMessage = 1078219; // So far so good, kid. You are still alive, and you are getting the hang of Tracking. There are many more animals, monsters, and people to track. Come back to me once you have tracked them.
+ CompletionMessage = 1078221; // I knew you could do it! You have become a fine Ranger. Just keep practicing, and one day you will become a Grandmaster Ranger. Just like me.
I have a little something for you that will hopefully aid you in your journeys. These leggings offer some resistances that will hopefully protect you from harm. I hope these serve you well. Farewell, friend.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Tracking, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1078222, typeof( WalkersLeggings ) ) ); // Walker's Leggings
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1078220, "", 0x23 ); // You have achieved the rank of Apprentice Ranger (for Tracking). Return to Walker in New Haven to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Walker" ), new Point3D( 3429, 2518, 19 ), Map.Trammel );
+ }
+ }
+
+ public class TheWayOfTheSamurai : MLQuest
+ {
+ public TheWayOfTheSamurai()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1078007; // The Way of the Samurai
+ Description = 1078010; // Head East out of town and go to Old Haven. use the Confidence defensive stance and attempt to honorably execute monsters there until you have raised your Bushido skill to 50.
------
Greetings. I see you wish to learn the Way of the Samurai. Wielding a blade is easy. Anyone can grasp a sword's hilt. Learning how to fight properly and skillfully is to become an Armsman. Learning how to master weapons, and even more importantly when not to use them, is the Way of the Warrior. The Way of the Samurai. The Code of the Bushido. That is why you are here.
Adventure East to Old Haven. Use the Confidence defensive stance and attempt to honorably execute the undead that inhabit there. You will need a book of Bushido to perform these abilities. If you do not possess a book of Bushido, you can purchase one from me.
If you fail to honorably execute the undead, your defenses will be greatly weakened: Resistances will suffer and Resisting Spells will suffer. A successful parry instantly ends the weakness. If you succeed, however, you will be infused with strength and healing. Your swing speed will also be boosted for a short duration. With practice, you will learn how to master your Bushido abilities.
Return to me once you feel that you have become an Apprentice Samurai.
+ RefusalMessage = 1078011; // Good journey to you. Return to me if you wish to live the life of a Samurai.
+ InProgressMessage = 1078012; // You are not ready to become an Apprentice Samurai. There are still more undead to lay to rest. Return to me once you have done so.
+ CompletionMessage = 1078014; // You have proven yourself young one. You will continue to improve as your skills are honed with age. You are an honorable warrior, worthy of the rank of Apprentice Samurai. Please accept this no-dachi as a gift. It is called "The Dragon's Tail". Upon a successful strike in combat, there is a chance this mighty weapon will replenish your stamina equal to the damage of your attack. I hope "The Dragon's Tail" serves you well. You have earned it. Farewell for now.
+
+ Objectives.Add( new GainSkillObjective( SkillName.Bushido, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1078015, typeof( TheDragonsTail ) ) ); // The Dragon's Tail
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1078013, "", 0x23 ); // You have achieved the rank of Apprentice Samurai. Return to Hamato in New Haven to report your progress.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Hamato" ), new Point3D( 3493, 2414, 55 ), Map.Trammel );
+ }
+ }
+
+ public class TheAllureOfDarkMagic : MLQuest
+ {
+ public TheAllureOfDarkMagic()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1078036; // The Allure of Dark Magic
+ Description = 1078039; // Head East out of town and go to Old Haven. Cast Evil Omen and Pain Spike against monsters there until you have raised your Necromancy skill to 50.
------
Welcome! I see you are allured by the dark magic of Necromancy. First, you must prove yourself worthy of such knowledge. Undead currently occupy the town of Old Haven. Practice your harmful Necromancy spells on them such as Evil Omen and Pain Spike.
Make sure you have plenty of reagents before embarking on your journey. Reagents are required to cast Necromancy spells. You can purchase extra reagents from me, or you can find reagents growing in the nearby wooded areas. You can see which reagents are required for each spell by looking in your spellbook.
Come back to me once you feel that you are worthy of the rank of Apprentice Necromancer and I will reward you with the knowledge you desire.
+ RefusalMessage = 1078040; // You are weak after all. Come back to me when you are ready to practice Necromancy.
+ InProgressMessage = 1078041; // You have not achieved the rank of Apprentice Necromancer. Come back to me once you feel that you are worthy of the rank of Apprentice Necromancer and I will reward you with the knowledge you desire.
+ CompletionMessage = 1078043; // You have done well, my young apprentice. Behold! I now present to you the knowledge you desire. This spellbook contains all the Necromancer spells. The power is intoxicating, isn't it?
+
+ Objectives.Add( new GainSkillObjective( SkillName.Necromancy, 500, true, true ) );
+
+ Rewards.Add( new InternalReward() );
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1078042, "", 0x23 ); // You have achieved the rank of Apprentice Necromancer. Return to Mulcivikh in New Haven to receive the knowledge you desire.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Mulcivikh" ), new Point3D( 3548, 2456, 15 ), Map.Trammel );
+ }
+
+ private class InternalReward : ItemReward
+ {
+ public InternalReward()
+ : base( 1078052, typeof( NecromancerSpellbook ) ) // Complete Necromancer Spellbook
+ {
+ }
+
+ public override Item CreateItem()
+ {
+ Item item = base.CreateItem();
+
+ Spellbook book = item as Spellbook;
+
+ if ( book != null )
+ book.Content = ( 1ul << book.BookCount ) - 1;
+
+ return item;
+ }
+ }
+ }
+
+ public class ChannelingTheSupernatural : MLQuest
+ {
+ public ChannelingTheSupernatural()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1078044; // Channeling the Supernatural
+ Description = 1078047; // Head East out of town and go to Old Haven. Use Spirit Speak and channel energy from either yourself or nearby corpses there. You can also cast Necromancy spells as well to raise Spirit Speak. Do these activities until you have raised your Spirit Speak skill to 50.
------
How do you do? Channeling the supernatural through Spirit Speak allows you heal your wounds. Such channeling expends your mana, so be mindful of this. Spirit Speak enhances the potency of your Necromancy spells. The channeling powers of a Medium are quite useful when practicing the dark magic of Necromancy.
It is best to practice Spirit Speak where there are a lot of corpses. Head East out of town and go to Old Haven. Undead currently reside there. Use Spirit Speak and channel energy from either yourself or nearby corpses. You can also cast Necromancy spells as well to raise Spirit Speak.
Come back to me once you feel that you are worthy of the rank of Apprentice Medium and I will reward you with something useful.
+ RefusalMessage = 1078048; // Channeling the supernatural isn't for everyone. It is a dark art. See me if you ever wish to pursue the life of a Medium.
+ InProgressMessage = 1078049; // Back so soon? You have not achieved the rank of Apprentice Medium. Come back to me once you feel that you are worthy of the rank of Apprentice Medium and I will reward you with something useful.
+ CompletionMessage = 1078051; // Well done! Channeling the supernatural is taxing, indeed. As promised, I will reward you with this bag of Necromancer reagents. You will need these if you wish to also pursue the dark magic of Necromancy. Good journey to you.
+
+ Objectives.Add( new GainSkillObjective( SkillName.SpiritSpeak, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1078053, typeof( BagOfNecromancerReagents ) ) ); // Bag of Necromancer Reagents
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1078050, "", 0x23 ); // You have achieved the rank of Apprentice Medium. Return to Morganna in New Haven to receive your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Morganna" ), new Point3D( 3547, 2463, 15 ), Map.Trammel );
+ }
+ }
+
+ public class TheDeluciansLostMine : MLQuest
+ {
+ public TheDeluciansLostMine()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077750; // The Delucian’s Lost Mine
+ Description = 1077753; // Find Jacob's Lost Mine and mine iron ore there, using a pickaxe or shovel. Bring it back to Jacob's forge and smelt the ore into ingots, until you have raised your Mining skill to 50. You may find a packhorse useful for hauling the ore around. The animal trainer in New Haven has packhorses for sale.
-----
Howdy! Welcome to my camp. It's not much, I know, but it's all I'll be needin' up here. I don't need them fancy things those townspeople have down there in New Haven. Nope, not one bit. Just me, Bessie, my pick and a thick vein 'o valorite.
Anyhows, I'm guessin' that you're up here to ask me about minin', aren't ya? Well, don't be expectin' me to tell you where the valorite's at, cause I ain't gonna tell the King of Britannia, much less the likes of you. But I will show ya how to mine and smelt iron, cause there certainly is a 'nough of up in these hills.
*Jacob looks around, with a perplexed look on his face*
Problem is, I can't remember where my iron mine's at, so you'll have to find it yourself. Once you're there, have at it with a pickaxe or shovel, then haul it back to camp and I'll show ya how to smelt it. Ya look a bit wimpy, so you might wanna go buy yourself a packhorse in town from the animal trainer to help you haul around all that ore.
When you're an Apprentice Miner, talk to me and I'll give ya a little somethin' I've got layin' around here... somewhere.
+ RefusalMessage = 1077754; // Couldn’t find my iron mine, could ya? Well, neither can I!
*Jacob laughs*
Oh, ya don’t wanna find it? Well, allrighty then, ya might as well head on back down to town then and stop cluttering up my camp. Come back and talk to me if you’re interested in learnin’ ‘bout minin’.
+ InProgressMessage = 1077755; // Where ya been off a gallivantin’ all day, pilgrim? You ain’t seen no hard work yet! Get yer arse back out there to my mine and dig up some more iron. Don’t forget to take a pickaxe or shovel, and if you’re so inclined, a packhorse too.
+ CompletionMessage = 1077757; // Dang gun it! If that don't beat all! Ya went and did it, didn’t ya? What we got ourselves here is a mighty fine brand spankin’ new Apprentice Miner!
I can see ya put some meat on them bones too while you were at it!
Here’s that little somethin’ I told ya I had for ya. It’s a pickaxe with some high falutin’ magic inside that’ll help you find the good stuff when you’re off minin’. It wears out fast, though, so you can only use it a few times a day.
Welp, I’ve got some smeltin’ to do, so off with ya. Good luck, pilgrim!
+
+ Objectives.Add( new GainSkillObjective( SkillName.Mining, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077758, typeof( JacobsPickaxe ) ) ); // Jacob's Pickaxe
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077756, "", 0x23 ); // You have achieved the rank of Apprentice Miner. Return to Jacob Waltz in at his camp in the hills above New Haven as soon as you can to claim your reward.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "JacobWaltz" ), new Point3D( 3504, 2741, 0 ), Map.Trammel );
+ }
+ }
+
+ public class ItsHammerTime : MLQuest
+ {
+ public ItsHammerTime()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1077732; // It’s Hammer Time!
+ Description = 1077735; // Create new daggers and maces using the forge and anvil in George's shop. Try making daggers up to 45 skill, the switch to making maces until 50 skill.
-----
Hail, and welcome to my humble shop. I'm George Hephaestus, New Haven's blacksmith. I assume that you're here to ask me to train you to be an Apprentice Blacksmith. I certainly can do that, but you're going to have to supply your own ingots.
You can always buy them at the market, but I highly suggest that you mine your own. That way, any items you sell will be pure profit!
So, once you have a supply of ingots, use my forge and anvil here to create items. You'll also need a supply of the proper tools; you can use a smith's hammer, a sledgehammer or tongs. You can either make them yourself if you have the tinkering skill, or buy them from a tinker at the market.
Since I'll be around to give you advice, you'll learn faster here than anywhere else. Start off making daggers until you reach 45 blacksmithing skill, then switch to maces until you've achieved 50. Once you've done that, come talk to me and I'll give you something for your hard work.
+ RefusalMessage = 1077736; // You're not interested in learning to be a smith, eh? I thought for sure that's why you were here. Oh well, if you change your mind, you can always come back and talk to me.
+ InProgressMessage = 1077737; // You’re doing well, but you’re not quite there yet. Remember that the quickest way to learn is to make daggers up until 45 skill, and then switch to maces. Also, don’t forget that using my forge and anvil will help you learn faster.
+ CompletionMessage = 1077739; // I've been watching you get better and better as you've been smithing, and I have to say, you're a natural! It's a long road to being a Grandmaster Blacksmith, but I have no doubt that if you put your mind to it you'll get there someday. Let me give you one final piece of advice. If you're smithing just to practice and improve your skill, make items that are moderately difficult (60-80% success chance), and try to stick to ones that use less ingots.
Now that you're an Apprentice Blacksmith, I have something for you. While you were busy practicing, I was crafting this hammer for you. It's finely balanced, and has a bit of magic imbued within that will help you craft better items. However, that magic needs to restore itself over time, so you can only use it so many times per day. I hope you find it useful!
+
+ Objectives.Add( new GainSkillObjective( SkillName.Blacksmith, 500, true, true ) );
+
+ Rewards.Add( new ItemReward( 1077740, typeof( HammerOfHephaestus ) ) ); // Hammer of Hephaestus
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1077738, "", 0x23 ); // You have achieved the rank of Apprentice Blacksmith. Return to George Hephaestus in New Haven to see what kind of reward he has waiting for you.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "GeorgeHephaestus" ), new Point3D( 3471, 2542, 36 ), Map.Trammel );
+ }
+ }
+
+ #endregion
+
+ #region Mobiles
+
+ public class Aelorn : KeeperOfChivalry
+ {
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078133 ); // Hail, friend. Want to live the life of a paladin?
+ }
+
+ [Constructable]
+ public Aelorn()
+ {
+ Name = "Aelorn";
+ Title = "the Chivalry Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203C;
+ HairHue = 0x47D;
+ FacialHairItemID = 0x204D;
+ FacialHairHue = 0x47D;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.MagicResist, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Meditation, 120.0 );
+ SetSkill( SkillName.Focus, 120.0 );
+ SetSkill( SkillName.Chivalry, 120.0 );
+ }
+
+ public override void InitOutfit()
+ {
+ AddItem( new Backpack() );
+ AddItem( new VikingSword() );
+ AddItem( new PlateChest() );
+ AddItem( new PlateLegs() );
+ AddItem( new PlateGloves() );
+ AddItem( new PlateArms() );
+ AddItem( new PlateGorget() );
+ AddItem( new OrderShield() );
+ }
+
+ public Aelorn( 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 class Dimethro : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078128 ); // You there! Wanna master hand to hand defense? Of course you do!
+ }
+
+ [Constructable]
+ public Dimethro()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Dimethro";
+ Title = "the Wrestling Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203D;
+ HairHue = 0x455;
+ FacialHairItemID = 0x204D;
+ FacialHairHue = 0x455;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.EvalInt, 120.0 );
+ SetSkill( SkillName.Inscribe, 120.0 );
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.MagicResist, 120.0 );
+ SetSkill( SkillName.Wrestling, 120.0 );
+ SetSkill( SkillName.Meditation, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Sandals( 0x455 ) );
+ AddItem( new BodySash( 0x455 ) );
+ AddItem( new LongPants( 0x455 ) );
+ }
+
+ public Dimethro( 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 class Churchill : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078141 ); // Don't listen to Jockles. Real warriors wield mace weapons!
+ }
+
+ [Constructable]
+ public Churchill()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Churchill";
+ Title = "the Mace Fighting Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203C;
+ HairHue = 0x455;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.Parry, 120.0 );
+ SetSkill( SkillName.Healing, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Macing, 120.0 );
+ SetSkill( SkillName.Focus, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new OrderShield() );
+ AddItem( new WarMace() );
+
+ Item item;
+
+ item = new PlateLegs();
+ item.Hue = 0x966;
+ AddItem( item );
+
+ item = new PlateGloves();
+ item.Hue = 0x966;
+ AddItem( item );
+
+ item = new PlateGorget();
+ item.Hue = 0x966;
+ AddItem( item );
+
+ item = new PlateChest();
+ item.Hue = 0x966;
+ AddItem( item );
+
+ item = new PlateArms();
+ item.Hue = 0x966;
+ AddItem( item );
+ }
+
+ public Churchill( 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 class Robyn : Bowyer
+ {
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078202 ); // Archery requires a steady aim and dexterous fingers.
+ }
+
+ [Constructable]
+ public Robyn()
+ {
+ Name = "Robyn";
+ Title = "the Archery Instructor";
+ BodyValue = 0x191;
+ Hue = 0x83EA;
+ HairItemID = 0x203C;
+ HairHue = 0x47D;
+ Female = true;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.Parry, 120.0 );
+ SetSkill( SkillName.Fletching, 120.0 );
+ SetSkill( SkillName.Healing, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Archery, 120.0 );
+ SetSkill( SkillName.Focus, 120.0 );
+
+ }
+
+ public override void InitOutfit()
+ {
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x592 ) );
+ AddItem( new Cloak( 0x592 ) );
+ AddItem( new Bandana( 0x592 ) );
+ AddItem( new CompositeBow() );
+
+ Item item;
+
+ item = new StuddedLegs();
+ item.Hue = 0x592;
+ AddItem( item );
+
+ item = new StuddedGloves();
+ item.Hue = 0x592;
+ AddItem( item );
+
+ item = new StuddedGorget();
+ item.Hue = 0x592;
+ AddItem( item );
+
+ item = new StuddedChest();
+ item.Hue = 0x592;
+ AddItem( item );
+
+ item = new StuddedArms();
+ item.Hue = 0x592;
+ AddItem( item );
+ }
+
+ public Robyn( 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 class Recaro : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078187 ); // The art of fencing requires a dexterous hand, a quick wit and fleet feet.
+ }
+
+ [Constructable]
+ public Recaro()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Recaro";
+ Title = "the Fencer Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203C;
+ HairHue = 0x455;
+ FacialHairItemID = 0x204D;
+ FacialHairHue = 0x455;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.Parry, 120.0 );
+ SetSkill( SkillName.Healing, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Fencing, 120.0 );
+ SetSkill( SkillName.Focus, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Shoes( 0x455 ) );
+ AddItem( new WarFork() );
+
+ Item item;
+
+ item = new StuddedLegs();
+ item.Hue = 0x455;
+ AddItem( item );
+
+ item = new StuddedGloves();
+ item.Hue = 0x455;
+ AddItem( item );
+
+ item = new StuddedGorget();
+ item.Hue = 0x455;
+ AddItem( item );
+
+ item = new StuddedChest();
+ item.Hue = 0x455;
+ AddItem( item );
+
+ item = new StuddedArms();
+ item.Hue = 0x455;
+ AddItem( item );
+ }
+
+ public Recaro( 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 class AldenArmstrong : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078136 ); // There is an art to slaying your enemies swiftly. It's called tactics, and I can teach it to you.
+ }
+
+ [Constructable]
+ public AldenArmstrong()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Alden Armstrong";
+ Title = "the Tactics Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203B;
+ HairHue = 0x44E;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.Parry, 120.0 );
+ SetSkill( SkillName.Healing, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Focus, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Shoes() );
+ AddItem( new StuddedLegs() );
+ AddItem( new StuddedGloves() );
+ AddItem( new StuddedGorget() );
+ AddItem( new StuddedChest() );
+ AddItem( new StuddedArms() );
+ AddItem( new Katana() );
+ }
+
+ public AldenArmstrong( 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 class Jockles : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078135 ); // Talk to me to learn the way of the blade.
+ }
+
+ [Constructable]
+ public Jockles()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Jockles";
+ Title = "the Swordsmanship Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83FA;
+ HairItemID = 0x203C;
+ HairHue = 0x8A7;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.Parry, 120.0 );
+ SetSkill( SkillName.Healing, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Focus, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Broadsword() );
+ AddItem( new PlateChest() );
+ AddItem( new PlateLegs() );
+ AddItem( new PlateGloves() );
+ AddItem( new PlateArms() );
+ AddItem( new PlateGorget() );
+ AddItem( new OrderShield() );
+ }
+
+ public Jockles( 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 class TylAriadne : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078140 ); // Want to learn how to parry blows?
+ }
+
+ [Constructable]
+ public TylAriadne()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Tyl Ariadne";
+ Title = "the Parrying Instructor";
+ BodyValue = 0x190;
+ Hue = 0x8374;
+ HairItemID = 0;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.Parry, 120.0 );
+ SetSkill( SkillName.Healing, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Meditation, 120.0 );
+ SetSkill( SkillName.Focus, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new ElvenBoots( 0x96D ) );
+
+ Item item;
+
+ item = new StuddedLegs();
+ item.Hue = 0x96D;
+ AddItem( item );
+
+ item = new StuddedGloves();
+ item.Hue = 0x96D;
+ AddItem( item );
+
+ item = new StuddedGorget();
+ item.Hue = 0x96D;
+ AddItem( item );
+
+ item = new StuddedChest();
+ item.Hue = 0x96D;
+ AddItem( item );
+
+ item = new StuddedArms();
+ item.Hue = 0x96D;
+ AddItem( item );
+
+ item = new DiamondMace();
+ item.Hue = 0x96D;
+ AddItem( item );
+ }
+
+ public TylAriadne( 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 class Alefian : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078130 ); // A mage should learn how to resist spells.
+ }
+
+ [Constructable]
+ public Alefian()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Alefian";
+ Title = "the Resisting Spells Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203D;
+ HairHue = 0x457;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.EvalInt, 120.0 );
+ SetSkill( SkillName.Inscribe, 120.0 );
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.MagicResist, 120.0 );
+ SetSkill( SkillName.Wrestling, 120.0 );
+ SetSkill( SkillName.Meditation, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Robe() );
+ AddItem( new Sandals() );
+ }
+
+ public Alefian( 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 class Gustar : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078126 ); // Meditation allows a mage to replenish mana quickly. I can teach you.
+ }
+
+ [Constructable]
+ public Gustar()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Gustar";
+ Title = "the Meditation Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83F5;
+ HairItemID = 0x203B;
+ HairHue = 0x455;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.EvalInt, 120.0 );
+ SetSkill( SkillName.Inscribe, 120.0 );
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.MagicResist, 120.0 );
+ SetSkill( SkillName.Wrestling, 120.0 );
+ SetSkill( SkillName.Meditation, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new GustarShroud() );
+ AddItem( new Sandals() );
+ }
+
+ public Gustar( 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 class GustarShroud : BaseOuterTorso
+ {
+ public override string DefaultName{ get{ return " "; } }
+ [Constructable]
+ public GustarShroud() : base( 0x2684 )
+ {
+ Hue = 0x479;
+ }
+
+ public GustarShroud( 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 class Jillian : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078129 ); // I can teach you how to scribe magic scrolls.
+ }
+
+ [Constructable]
+ public Jillian()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Jillian";
+ Title = "the Inscription Instructor";
+ BodyValue = 0x191;
+ Female = true;
+ Hue = 0x83EA;
+ HairItemID = 0x203D;
+ HairHue = 0x455;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.EvalInt, 120.0 );
+ SetSkill( SkillName.Inscribe, 120.0 );
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.MagicResist, 120.0 );
+ SetSkill( SkillName.Wrestling, 120.0 );
+ SetSkill( SkillName.Meditation, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Robe( 0x479 ) );
+ AddItem( new Sandals() );
+ }
+
+ public Jillian( 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 class Kaelynna : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078125 ); // Want to unlock the secrets of magery?
+ }
+
+ [Constructable]
+ public Kaelynna()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Kaelynna";
+ Title = "the Magery Instructor";
+ BodyValue = 0x191;
+ Female = true;
+ Hue = 0x83EA;
+ HairItemID = 0x203C;
+ HairHue = 0x47D;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.EvalInt, 120.0 );
+ SetSkill( SkillName.Inscribe, 120.0 );
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.MagicResist, 120.0 );
+ SetSkill( SkillName.Wrestling, 120.0 );
+ SetSkill( SkillName.Meditation, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Robe( 0x592 ) );
+ AddItem( new Sandals() );
+ }
+
+ public Kaelynna( 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 class Mithneral : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078127 ); // Want to maximize your spell damage? I have a scholarly task for you!
+ }
+
+ [Constructable]
+ public Mithneral()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Mithneral";
+ Title = "the Evaluating Intelligence Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203C;
+ HairHue = 0x455;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.EvalInt, 120.0 );
+ SetSkill( SkillName.Inscribe, 120.0 );
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.MagicResist, 120.0 );
+ SetSkill( SkillName.Wrestling, 120.0 );
+ SetSkill( SkillName.Meditation, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Sandals() );
+
+ Item item;
+
+ item = new GustarShroud();
+ item.Hue = 0x51C;
+ AddItem( item );
+ }
+
+ public Mithneral( 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 class AmeliaYoungstone : Tinker
+ {
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078123 ); // Tinkering is very useful for a blacksmith. You can make your own tools.
+ }
+
+ [Constructable]
+ public AmeliaYoungstone()
+ {
+ Name = "Amelia Youngstone";
+ Title = "the Tinkering Instructor";
+ BodyValue = 0x191;
+ Female = true;
+ Hue = 0x83EA;
+ HairItemID = 0x203D;
+ HairHue = 0x46C;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.ArmsLore, 120.0 );
+ SetSkill( SkillName.Blacksmith, 120.0 );
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Tinkering, 120.0 );
+ SetSkill( SkillName.Mining, 120.0 );
+ }
+
+ public override void InitOutfit()
+ {
+ AddItem( new Backpack() );
+ AddItem( new Sandals() );
+ AddItem( new Doublet() );
+ AddItem( new ShortPants() );
+ AddItem( new HalfApron( 0x8AB ) );
+ }
+
+ public AmeliaYoungstone( 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 class AndreasVesalius : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078138 ); // Learning of the body will allow you to excel in combat.
+ }
+
+ [Constructable]
+ public AndreasVesalius()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Andreas Vesalius";
+ Title = "the Anatomy Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EC;
+ HairItemID = 0x203C;
+ HairHue = 0x477;
+ FacialHairItemID = 0x203E;
+ FacialHairHue = 0x477;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.Parry, 120.0 );
+ SetSkill( SkillName.Healing, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Focus, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Boots() );
+ AddItem( new BlackStaff() );
+ AddItem( new LongPants() );
+ AddItem( new Tunic( 0x66D ) );
+ }
+
+ public AndreasVesalius( 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 class Avicenna : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078137 ); // A warrior needs to learn how to apply bandages to wounds.
+ }
+
+ [Constructable]
+ public Avicenna()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Avicenna";
+ Title = "the Healing Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203B;
+ HairHue = 0x477;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.Parry, 120.0 );
+ SetSkill( SkillName.Healing, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Focus, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Robe( 0x66D ) );
+ AddItem( new Boots() );
+ AddItem( new GnarledStaff() );
+ }
+
+ public Avicenna( 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 class SarsmeaSmythe : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078139 ); // Know yourself, and you will become a true warrior.
+ }
+
+ [Constructable]
+ public SarsmeaSmythe()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Sarsmea Smythe";
+ Title = "the Focus Instructor";
+ BodyValue = 0x191;
+ Female = true;
+ Hue = 0x83EA;
+ HairItemID = 0x203C;
+ HairHue = 0x456;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.Parry, 120.0 );
+ SetSkill( SkillName.Healing, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Focus, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new ThighBoots() );
+ AddItem( new StuddedGorget() );
+ AddItem( new LeatherLegs() );
+ AddItem( new FemaleLeatherChest() );
+ AddItem( new StuddedGloves() );
+ AddItem( new LeatherNinjaBelt() );
+ AddItem( new LightPlateJingasa() );
+ }
+
+ public SarsmeaSmythe( 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 class Ryuichi : BaseVendor
+ {
+ private List m_SBInfos = new List();
+ protected override List SBInfos { get { return m_SBInfos; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078155 ); // I can teach you Ninjitsu. The Art of Stealth.
+ }
+
+ [Constructable]
+ public Ryuichi()
+ : base( "the Ninjitsu Instructor" )
+ {
+ Name = "Ryuichi";
+ Hue = 0x8403;
+
+ SetSkill( SkillName.Hiding, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Tracking, 120.0 );
+ SetSkill( SkillName.Fencing, 120.0 );
+ SetSkill( SkillName.Stealth, 120.0 );
+ SetSkill( SkillName.Ninjitsu, 120.0 );
+ }
+
+ public override void InitSBInfo()
+ {
+ m_SBInfos.Add( new SBNinja() );
+ }
+
+ public override bool GetGender()
+ {
+ return false;
+ }
+
+ public override void InitOutfit()
+ {
+ HairItemID = 0x203B;
+ HairHue = 0x455;
+
+ AddItem( new SamuraiTabi() );
+ AddItem( new LeatherNinjaPants() );
+ AddItem( new LeatherNinjaMitts() );
+ AddItem( new LeatherNinjaHood() );
+ AddItem( new LeatherNinjaJacket() );
+ AddItem( new LeatherNinjaBelt() );
+
+ PackGold( 100, 200 );
+ }
+
+ public Ryuichi( 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 class Chiyo : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078165 ); // To be undetected means you cannot be harmed.
+ }
+
+ [Constructable]
+ public Chiyo()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Chiyo";
+ Title = "the Hiding Instructor";
+ BodyValue = 0xF7;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Hiding, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Tracking, 120.0 );
+ SetSkill( SkillName.Fencing, 120.0 );
+ SetSkill( SkillName.Stealth, 120.0 );
+ SetSkill( SkillName.Ninjitsu, 120.0 );
+ }
+
+ public Chiyo( 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 class Jun : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078175 ); // Walk Silently. Remain unseen. I can teach you.
+ }
+
+ [Constructable]
+ public Jun()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Jun";
+ Title = "the Stealth Instructor";
+ BodyValue = 0x190;
+ Hue = 0x8403;
+ HairItemID = 0x203B;
+ HairHue = 0x455;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Hiding, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Tracking, 120.0 );
+ SetSkill( SkillName.Fencing, 120.0 );
+ SetSkill( SkillName.Stealth, 120.0 );
+ SetSkill( SkillName.Ninjitsu, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new SamuraiTabi() );
+ AddItem( new LeatherNinjaPants() );
+ AddItem( new LeatherNinjaMitts() );
+ AddItem( new LeatherNinjaHood() );
+ AddItem( new LeatherNinjaJacket() );
+ AddItem( new LeatherNinjaBelt() );
+ }
+
+ public Jun( 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 class Walker : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1078213, // I don't sleep. I wait.
+ 1078212, // There is no theory of evolution. Just a list of creatures I allow to live.
+ 1078214 // I can lead a horse to water and make it drink.
+ ) );
+ }
+
+ [Constructable]
+ public Walker()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Walker";
+ Title = "the Tracking Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203B;
+ HairHue = 0x47D;
+ FacialHairItemID = 0x204B;
+ FacialHairHue = 0x47D;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Hiding, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Tracking, 120.0 );
+ SetSkill( SkillName.Fencing, 120.0 );
+ SetSkill( SkillName.Wrestling, 120.0 );
+ SetSkill( SkillName.Stealth, 120.0 );
+ SetSkill( SkillName.Ninjitsu, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x455 ) );
+ AddItem( new LongPants( 0x455 ) );
+ AddItem( new FancyShirt( 0x47D ) );
+ AddItem( new FloppyHat( 0x455 ) );
+ }
+
+ public Walker( 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 class Hamato : BaseVendor
+ {
+ private List m_SBInfos = new List();
+ protected override List SBInfos { get { return m_SBInfos; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078134 ); // Seek me to learn the way of the samurai.
+ }
+
+ [Constructable]
+ public Hamato()
+ : base( "the Bushido Instructor" )
+ {
+ Name = "Hamato";
+ Hue = 0x8403;
+
+ SetSkill( SkillName.Anatomy, 120.0 );
+ SetSkill( SkillName.Parry, 120.0 );
+ SetSkill( SkillName.Healing, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Bushido, 120.0 );
+ }
+
+ public override void InitSBInfo()
+ {
+ m_SBInfos.Add( new SBSamurai() );
+ }
+
+ public override bool GetGender()
+ {
+ return false;
+ }
+
+ public override void InitOutfit()
+ {
+ HairItemID = 0x203D;
+ HairHue = 0x497;
+
+ AddItem( new Backpack() );
+ AddItem( new NoDachi() );
+ AddItem( new NinjaTabi() );
+ AddItem( new PlateSuneate() );
+ AddItem( new LightPlateJingasa() );
+ AddItem( new LeatherDo() );
+ AddItem( new LeatherHiroSode() );
+
+ PackGold( 100, 200 );
+ }
+
+ public Hamato( 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 class Mulcivikh : Mage
+ {
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078131 ); // Allured by dark magic, aren't you?
+ }
+
+ [Constructable]
+ public Mulcivikh()
+ {
+ Name = "Mulcivikh";
+ Title = "the Necromancy Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203D;
+ HairHue = 0x457;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.MagicResist, 120.0 );
+ SetSkill( SkillName.SpiritSpeak, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Meditation, 120.0 );
+ SetSkill( SkillName.Necromancy, 120.0 );
+ }
+
+ public override void InitOutfit()
+ {
+ AddItem( new Backpack() );
+ AddItem( new Sandals( 0x8FD ) );
+ AddItem( new BoneHelm() );
+
+ Item item;
+
+ item = new LeatherLegs();
+ item.Hue = 0x2C3;
+ AddItem( item );
+
+ item = new LeatherGloves();
+ item.Hue = 0x2C3;
+ AddItem( item );
+
+ item = new LeatherGorget();
+ item.Hue = 0x2C3;
+ AddItem( item );
+
+ item = new LeatherChest();
+ item.Hue = 0x2C3;
+ AddItem( item );
+
+ item = new LeatherArms();
+ item.Hue = 0x2C3;
+ AddItem( item );
+ }
+
+ public Mulcivikh( 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 class Morganna : Mage
+ {
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078132 ); // Want to learn how to channel the supernatural?
+ }
+
+ [Constructable]
+ public Morganna()
+ {
+ Name = "Morganna";
+ Title = "the Spirit Speak Instructor";
+ BodyValue = 0x191;
+ Female = true;
+ Hue = 0x83EA;
+ HairItemID = 0x203C;
+ HairHue = 0x455;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.MagicResist, 120.0 );
+ SetSkill( SkillName.SpiritSpeak, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Meditation, 120.0 );
+ SetSkill( SkillName.Necromancy, 120.0 );
+ }
+
+ public override void InitOutfit()
+ {
+ AddItem( new Backpack() );
+ AddItem( new Sandals() );
+ AddItem( new Robe( 0x47D ) );
+ AddItem( new SkullCap( 0x455 ) );
+ }
+
+ public Morganna( 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 class JacobWaltz : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078124 ); // You there! I can use some help mining these rocks!
+ }
+
+ [Constructable]
+ public JacobWaltz()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Jacob Waltz";
+ Title = "the Miner Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x2048;
+ HairHue = 0x44E;
+ FacialHairItemID = 0x204D;
+ FacialHairHue = 0x44E;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.ArmsLore, 120.0 );
+ SetSkill( SkillName.Blacksmith, 120.0 );
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Tinkering, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Mining, 120.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Pickaxe() );
+ AddItem( new Boots() );
+ AddItem( new WideBrimHat( 0x966 ) );
+ AddItem( new ShortPants( 0x370 ) );
+ AddItem( new Shirt( 0x966 ) );
+ AddItem( new HalfApron( 0x1BB ) );
+ }
+
+ public JacobWaltz( 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 class GeorgeHephaestus : Blacksmith
+ {
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1078122 ); // Wanna learn how to make powerful weapons and armor? Talk to me.
+ }
+
+ [Constructable]
+ public GeorgeHephaestus()
+ {
+ Name = "George Hephaestus";
+ Title = "the Blacksmith Instructor";
+ BodyValue = 0x190;
+ Hue = 0x83EA;
+ HairItemID = 0x203B;
+ HairHue = 0x47B;
+
+ InitStats( 100, 100, 25 );
+
+ SetSkill( SkillName.ArmsLore, 120.0 );
+ SetSkill( SkillName.Blacksmith, 120.0 );
+ SetSkill( SkillName.Magery, 120.0 );
+ SetSkill( SkillName.Tactics, 120.0 );
+ SetSkill( SkillName.Tinkering, 120.0 );
+ SetSkill( SkillName.Swords, 120.0 );
+ SetSkill( SkillName.Mining, 120.0 );
+
+ }
+
+ public override void InitOutfit()
+ {
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x973 ) );
+ AddItem( new LongPants() );
+ AddItem( new Bascinet() );
+ AddItem( new FullApron( 0x8AB ) );
+
+ Item item;
+
+ item = new SmithHammer();
+ item.Hue = 0x8AB;
+ AddItem( item );
+ }
+
+ public GeorgeHephaestus( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/NewHavenTraining.cs b/Scripts/Engines/MLQuests/Definitions/NewHavenTraining.cs
new file mode 100644
index 000000000..a8ad937f0
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/NewHavenTraining.cs
@@ -0,0 +1,994 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.ContextMenus;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Misc;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Quests
+ // TODO: Time delay on doing these quests (2 mins?)
+ // I'm sorry, but I don't have anything else for you right now. Could you check back with me in a few minutes?
+ // I'm sorry, I have nothing for you at this time.
+
+ public class SplitEnds : MLQuest
+ {
+ public SplitEnds()
+ {
+ Activated = true;
+ Title = 1075506; // Split Ends
+ Description = 1075507; // *sighs* I think bowcrafting is a might beyond my talents. Say there, you look a bit more confident with tools. Can I persuade thee to make a few arrows? You could have my satchel in return... 'tis useless to me! You'll need a fletching kit to start, some feathers, and a few arrow shafts. Just use the fletching kit while you have the other things, and I'm sure you'll figure out the rest.
+ RefusalMessage = 1075508; // Oh. Well. I'll just keep trying alone, I suppose...
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+ CompletionMessage = 1072272; // Thanks for helping me out. Here's the reward I promised you.
+
+ Objectives.Add( new CollectObjective( 20, typeof( Arrow ), 1023902 ) ); // arrow
+
+ Rewards.Add( new ItemReward( 1074282, typeof( AndricSatchel ) ) ); // Craftsmans's Satchel
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Andric" ), new Point3D( 3742, 2582, 40 ), Map.Trammel );
+ }
+ }
+
+ public class IShotAnArrowIntoTheAir : MLQuest
+ {
+ public IShotAnArrowIntoTheAir()
+ {
+ Activated = true;
+ Title = 1075486; // I Shot an Arrow Into the Air...
+ Description = 1075482; // Truth be told, the only way to get a feel for the bow is to shoot one and there's no better practice target than a sheep. If ye can shoot ten of them I think ye will have proven yer abilities. Just grab a bow and make sure to take enough ammunition. Bows tend to use arrows and crossbows use bolts. Ye can buy 'em or have someone craft 'em. How about it then? Come back here when ye are done.
+ RefusalMessage = 1075483; // Fair enough, the bow isn't for everyone. Good day then.
+ InProgressMessage = 1075484; // Return once ye have killed ten sheep with a bow and not a moment before.
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Sheep ) }, 1018270 ) ); // sheep
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Kashiel" ), new Point3D( 3744, 2586, 40 ), Map.Trammel );
+ }
+ }
+
+ public class BakersDozen : MLQuest
+ {
+ public BakersDozen()
+ {
+ Activated = true;
+ Title = 1075478; // Baker's Dozen
+ Description = 1075479; // You there! Do you know much about the ways of cooking? If you help me out, I'll show you a thing or two about how it's done. Bring me some cookie mix, about 5 batches will do it, and I will reward you. Although, I don't think you can buy it, you can make some in a snap! First get a rolling pin or frying pan or even a flour sifter. Then you mix one pinch of flour with some water and you've got some dough! Take that dough and add one dollop of honey and you've got sweet dough. add one more drop of honey and you've got cookie mix. See? Nothing to it! Now get to work!
+ RefusalMessage = 1075480; // Argh, I absolutely must have more of these 'cookies!' Come back if you change your mind.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+ CompletionMessage = 1075481; // Thank you! I haven't been this excited about food in months!
+
+ Objectives.Add( new CollectObjective( 5, typeof( CookieMix ), 1024159 ) ); // cookie mix
+
+ Rewards.Add( new ItemReward( 1074282, typeof( AsandosSatchel ) ) ); // Craftsmans's Satchel
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Asandos" ), new Point3D( 3505, 2513, 27 ), Map.Trammel );
+ }
+ }
+
+ public class AStitchInTime : MLQuest
+ {
+ public AStitchInTime()
+ {
+ Activated = true;
+ Title = 1075523; // A Stitch in Time
+ Description = 1075522; // Oh how I wish I had a fancy dress like the noble ladies of Castle British! I don't have much... but I have a few trinkets I might trade for it. It would mean the world to me to go to a fancy ball and dance the night away. Oh, and I could tell you how to make one! You just need to use your sewing kit on enough cut cloth, that's all.
+ RefusalMessage = 1075526; // Won't you reconsider? It'd mean the world to me, it would!
+ InProgressMessage = 1075527; // Hello again! Do you need anything? You may want to visit the tailor's shop for cloth and a sewing kit, if you don't already have them.
+ CompletionMessage = 1075528; // It's gorgeous! I only have a few things to give you in return, but I can't thank you enough! Maybe I'll even catch Uzeraan's eye at the, er, *blushes* I mean, I can't wait to wear it to the next town dance!
+
+ Objectives.Add( new CollectObjective( 1, typeof( FancyDress ), 1015275 ) ); // fancy dress
+
+ Rewards.Add( new ItemReward( 1075524, typeof( AnOldRing ) ) ); // an old ring
+ Rewards.Add( new ItemReward( 1075525, typeof( AnOldNecklace ) ) ); // an old necklace
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Clairesse" ), new Point3D( 3492, 2546, 20 ), Map.Trammel );
+ }
+ }
+
+ public class BatteredBucklers : MLQuest
+ {
+ public BatteredBucklers()
+ {
+ Activated = true;
+ Title = 1075511; // Battered Bucklers
+ Description = 1075512; // Hey there! Yeah... you! Ya' any good with a hammer? Tell ya what, if yer thinking about tryin' some metal work, and have a bit of skill, I can show ya how to bend it into shape. Just get some of those ingots there, and grab a hammer and use it over here at this forge. I need a few more bucklers hammered out to fill this here order with... hmmm about ten more. that'll give some taste of how to work the metal.
+ RefusalMessage = 1075514; // Not enough muscle on yer bones to use it? hmph, probably afraid of the sparks markin' up yer loverly skin... to good for some honest labor... ha!... off with ya!
+ 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
+
+ Rewards.Add( new ItemReward( 1074282, typeof( GervisSatchel ) ) ); // Craftsmans's Satchel
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Gervis" ), new Point3D( 3505, 2749, 0 ), Map.Trammel );
+ }
+ }
+
+ public class MoreOrePlease : MLQuest
+ {
+ public MoreOrePlease()
+ {
+ Activated = true;
+ Title = 1075530; // More Ore Please
+ Description = 1075529; // Have a pickaxe? My supplier is late and I need some iron ore so I can complete a bulk order for another merchant. If you can get me some soon I'll pay you double what it's worth on the market. Just find a cave or mountainside and try to use your pickaxe there, maybe you'll strike a good vein! 5 large pieces should do it.
+ RefusalMessage = 1075531; // Not feeling strong enough today? Its alright, I didn't need a bucket of rocks anyway.
+ 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
+
+ Rewards.Add( new ItemReward( 1074282, typeof( MuggSatchel ) ) ); // Craftsmans's Satchel
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Mugg" ), new Point3D( 3507, 2747, 0 ), Map.Trammel );
+ }
+ }
+
+ public class ComfortableSeating : MLQuest
+ {
+ public ComfortableSeating()
+ {
+ Activated = true;
+ Title = 1075517; // Comfortable Seating
+ Description = 1075518; // Hail friend, hast thou a moment? A mishap with a saw hath left me in a sorry state, for it shall be a while before I canst return to carpentry. In the meantime, I need a comfortable chair that I may rest. Could thou craft a straw chair? Only a tool, such as a dovetail saw, a few boards, and some skill as a carpenter is needed. Remember, this is a piece of furniture, so please pay attention to detail.
+ RefusalMessage = 1072687; // I quite understand your reluctance. If you reconsider, I'll be here.
+ 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
+
+ Rewards.Add( new ItemReward( 1074282, typeof( LowelSatchel ) ) ); // Craftsmans's Satchel
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Lowel" ), new Point3D( 3440, 2645, 27 ), Map.Trammel );
+ }
+ }
+
+ public class ThePenIsMightier : MLQuest
+ {
+ public ThePenIsMightier()
+ {
+ Activated = true;
+ Title = 1075542; // The Pen is Mightier
+ Description = 1075543; // Do you know anything about 'Inscription?' I've been trying to get my hands on some hand crafted Recall scrolls for a while now, and I could really use some help. I don't have a scribe's pen, let alone a spellbook with Recall in it, or blank scrolls, so there's no way I can do it on my own. How about you though? I could trade you one of my old leather bound books for some.
+ RefusalMessage = 1075546; // Hmm, thought I had your interest there for a moment. It's not everyday you see a book made from real daemon skin, after all!
+ InProgressMessage = 1075547; // Inscribing... yes, you'll need a scribe's pen, some reagents, some blank scroll, and of course your own magery book. You might want to visit the magery shop if you're lacking some materials.
+ CompletionMessage = 1075548; // Ha! Finally! I've had a rune to the waterfalls near Justice Isle that I've been wanting to use for the longest time, and now I can visit at last. Here's that book I promised you... glad to be rid of it, to be honest.
+
+ Objectives.Add( new CollectObjective( 5, typeof( RecallScroll ), "recall scroll" ) );
+
+ Rewards.Add( new ItemReward( 1075545, typeof( RedLeatherBook ) ) ); // a book bound in red leather
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Lyle" ), new Point3D( 3503, 2584, 14 ), Map.Trammel );
+ }
+ }
+
+ public class AClockworkPuzzle : MLQuest
+ {
+ public AClockworkPuzzle()
+ {
+ Activated = true;
+ Title = 1075535; // A clockwork puzzle
+ Description = 1075534; // 'Tis a riddle, you see! "What kind of clock is only right twice per day? A broken one!" *laughs heartily* Ah, yes *wipes eye*, that's one of my favorites! Ah... to business. Could you fashion me some clock parts? I wish my own clocks to be right all the day long! You'll need some tinker's tools and some iron ingots, I think, but from there it should be just a matter of working the metal.
+ RefusalMessage = 1072981; // Or perhaps you'd rather not.
+ 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
+
+ Rewards.Add( new ItemReward( 1074282, typeof( NibbetSatchel ) ) ); // Craftsmans's Satchel
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Nibbet" ), new Point3D( 3459, 2525, 53 ), Map.Trammel );
+ }
+ }
+
+ public class DeliciousFishes : MLQuest
+ {
+ public DeliciousFishes()
+ {
+ Activated = true;
+ Title = 1075555; // Delicious Fishes
+ Description = 1075556; // Ello there, looking for a good place on the dock to fish? I like the southeast corner meself. What's that? Oh, no, *sighs* me pole is broken and in for fixin'. My grandpappy gave me that pole, means a lot you see. Miss the taste of fish though... Oh say, since you're here, could you catch me a few fish? I can cook a mean fish steak, and I'll split 'em with you! But make sure it's one of the green kind, they're the best for seasoning!
+ RefusalMessage = 1075558; // Ah, you're missin' out my friend, you're missing out. My peppercorn fishsteaks are famous on this little isle of ours!
+ InProgressMessage = 1075559; // Eh? Find yerself a pole and get close to some water. Just toss the line on in and hopefully you won't snag someone's old boots! Remember, that's twenty of them green fish we'll be needin', so come back when you've got em, 'aight?
+ CompletionMessage = 1075560; // Just a moment my friend, just a moment! *rummages in his pack* Here we are! My secret blend of peppers always does the trick, never fails, no not once. These'll fill you up much faster than that tripe they sell in the market!
+
+ Objectives.Add( new CollectObjective( 5, typeof( Fish ), 1022508 ) ); // fish
+
+ Rewards.Add( new ItemReward( 1075557, typeof( PeppercornFishsteak ), 3 ) ); // peppercorn fishsteak
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Norton" ), new Point3D( 3502, 2603, 1 ), Map.Trammel );
+ }
+ }
+
+ public class FleeAndFatigue : MLQuest
+ {
+ public FleeAndFatigue()
+ {
+ Activated = true;
+ Title = 1075487; // Flee and Fatigue
+ Description = 1075488; // I was just *coughs* ambushed near the moongate. *wheeze* Why do I pay my taxes? Where were the guards? You then, you an Alchemist? If you can make me a few Refresh potions, I will be back on my feet and can give those lizards the what for! Find a mortar and pestle, a good amount of black pearl, and ten empty bottles to store the finished potions in. Just use the mortar and pestle and the rest will surely come to you. When you return, the favor will be repaid.
+ RefusalMessage = 1075489; // Fine fine, off with *cough* thee then! The next time you see a lizardman though, give him a whallop for me, eh?
+ 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
+
+ Rewards.Add( new ItemReward( 1074282, typeof( SadrahSatchel ) ) ); // Craftsmans's Satchel
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Sadrah" ), new Point3D( 3742, 2731, 7 ), Map.Trammel );
+ }
+ }
+
+ public class ChopChopOnTheDouble : MLQuest
+ {
+ public ChopChopOnTheDouble()
+ {
+ Activated = true;
+ Title = 1075537; // Chop Chop, On The Double!
+ Description = 1075538; // That's right, move it! I need sixty logs on the double, and they need to be freshly cut! If you can get them to me fast I'll have your payment in your hands before you have the scent of pine out from beneath your nostrils. Just get a sharp axe and hack away at some of the trees in the land and your lumberjacking skill will rise in no time.
+ RefusalMessage = 1072981; // Or perhaps you'd rather not.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+ CompletionMessage = 1075539; // Ahhh! The smell of fresh cut lumber. And look at you, all strong and proud, as if you had done an honest days work!
+
+ Objectives.Add( new CollectObjective( 60, typeof( Log ), 1027133 ) ); // log
+
+ Rewards.Add( new ItemReward( 1074282, typeof( HargroveSatchel ) ) ); // Craftsmans's Satchel
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Hargrove" ), new Point3D( 3445, 2633, 28 ), Map.Trammel );
+ }
+ }
+
+ #endregion
+
+ #region Mobiles
+
+ public class Andric : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid?
+ 1074213 // Hey buddy. Looking for work?
+ ) );
+ }
+
+ [Constructable]
+ public Andric()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Andric";
+ Title = "the archer trainer";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Archery, 60.0, 80.0 );
+
+ AddItem( new Backpack() );
+
+ Item item;
+
+ item = new LeatherChest();
+ item.Hue = 0x1BB;
+ AddItem( item );
+
+ item = new LeatherLegs();
+ item.Hue = 0x6AD;
+ AddItem( item );
+
+ item = new LeatherArms();
+ item.Hue = 0x6AD;
+ AddItem( item );
+
+ item = new LeatherGloves();
+ item.Hue = 0x1BB;
+ AddItem( item );
+
+ AddItem( new Boots( 0x1BB ) );
+ AddItem( new CompositeBow() );
+ }
+
+ public Andric( 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 class Kashiel : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Kashiel()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Kashiel";
+ Title = "the archer";
+ Race = Race.Human;
+ BodyValue = 0x191;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+
+ Item item;
+
+ item = new LeatherChest();
+ item.Hue = 0x1BB;
+ AddItem( item );
+
+ item = new LeatherLegs();
+ item.Hue = 0x901;
+ AddItem( item );
+
+ item = new LeatherArms();
+ item.Hue = 0x901;
+ AddItem( item );
+
+ item = new LeatherGloves();
+ item.Hue = 0x1BB;
+ AddItem( item );
+
+ AddItem( new Boots( 0x1BB ) );
+ AddItem( new CompositeBow() );
+ }
+
+ public Kashiel( 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 class Asandos : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid?
+ 1074213 // Hey buddy. Looking for work?
+ ) );
+ }
+
+ [Constructable]
+ public Asandos()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Asandos";
+ Title = "the chef";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x901 ) );
+ AddItem( new ShortPants() );
+ AddItem( new Shirt() );
+ AddItem( new Cap() );
+ AddItem( new HalfApron( 0x28 ) );
+ }
+
+ public Asandos( 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 class Clairesse : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid?
+ 1074213 // Hey buddy. Looking for work?
+ ) );
+ }
+
+ [Constructable]
+ public Clairesse()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Clairesse";
+ Title = "the servant";
+ Race = Race.Human;
+ BodyValue = 0x191;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Shoes( Utility.RandomNeutralHue() ) );
+ AddItem( new PlainDress( 0x3C9 ) );
+ }
+
+ public Clairesse( 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 class Gervis : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid?
+ 1074213, // Hey buddy. Looking for work?
+ 1074211 // I could use some help.
+ ) );
+ }
+
+ [Constructable]
+ public Gervis()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Gervis";
+ Title = "the blacksmith trainer";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Blacksmith, 60.0, 80.0 );
+
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x3B3 ) );
+ AddItem( new ShortPants( 0x1BB ) );
+ AddItem( new Doublet( 0x652 ) );
+ AddItem( new SmithHammer() );
+
+ Item item;
+
+ item = new LeatherGloves();
+ item.Hue = 0x3B2;
+ AddItem( item );
+ }
+
+ public Gervis( 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 class Mugg : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074211 ); // I could use some help.
+ }
+
+ [Constructable]
+ public Mugg()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Mugg";
+ Title = "the miner";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x901 ) );
+ AddItem( new ShortPants( 0x3B3 ) );
+ AddItem( new Shirt( 0x22B ) );
+ AddItem( new HalfApron( 0x5F1 ) );
+ AddItem( new SkullCap( 0x177 ) );
+ AddItem( new Pickaxe() );
+ }
+
+ public Mugg( 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 class Lowel : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid?
+ 1074213 // Hey buddy. Looking for work?
+ ) );
+ }
+
+ [Constructable]
+ public Lowel()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lowel";
+ Title = "the carpenter";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x543 ) );
+ AddItem( new ShortPants( 0x758 ) );
+ AddItem( new FancyShirt( 0x53A ) );
+ AddItem( new HalfApron( 0x6D2 ) );
+ }
+
+ public Lowel( 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 class Lyle : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid?
+ 1074213 // Hey buddy. Looking for work?
+ ) );
+ }
+
+ [Constructable]
+ public Lyle()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lyle";
+ Title = "the mage";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Robe( 0x2FD ) );
+ AddItem( new ThighBoots() );
+ }
+
+ public Lyle( 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 class Nibbet : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Nibbet()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Nibbet";
+ Title = "the tinker";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x591 ) );
+ AddItem( new ShortPants( 0xF8 ) );
+ AddItem( new Shirt( 0x2D ) );
+ AddItem( new FullApron( 0x288 ) );
+ }
+
+ public Nibbet( 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 class Norton : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid?
+ 1074213, // Hey buddy. Looking for work?
+ 1074211 // I could use some help.
+ ) );
+ }
+
+ [Constructable]
+ public Norton()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Norton";
+ Title = "the fisher";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new ThighBoots() );
+ AddItem( new LongPants( 0x6C2 ) );
+ AddItem( new Shirt( 0x11D ) );
+ }
+
+ public Norton( 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 class Sadrah : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid?
+ 1074213, // Hey buddy. Looking for work?
+ 1074211 // I could use some help.
+ ) );
+ }
+
+ [Constructable]
+ public Sadrah()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Sadrah";
+ Title = "the courier";
+ Race = Race.Human;
+ BodyValue = 0x191;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x901 ) );
+ AddItem( new Skirt( 0x52 ) );
+ AddItem( new Shirt( 0x127 ) );
+ AddItem( new Cloak( 0x65) );
+ AddItem( new Longsword() );
+ }
+
+ public Sadrah( 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 class Hargrove : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074213, // Hey buddy. Looking for work?
+ 1074211 // I could use some help.
+ ) );
+ }
+
+ [Constructable]
+ public Hargrove()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Hargrove";
+ Title = "the Lumberjack";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Boots( 0x901 ) );
+ AddItem( new StuddedLegs() );
+ AddItem( new Shirt( 0x288 ) );
+ AddItem( new Bandana( 0x20 ) );
+ AddItem( new BattleAxe() );
+
+ Item item;
+
+ item = new PlateGloves();
+ item.Hue = 0x21E;
+ AddItem( item );
+
+ }
+
+ public Hargrove( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/Sanctuary.cs b/Scripts/Engines/MLQuests/Definitions/Sanctuary.cs
new file mode 100644
index 000000000..068d14ade
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/Sanctuary.cs
@@ -0,0 +1,1206 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.ContextMenus;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Misc;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Quests
+
+ public class BrokenShaft : MLQuest
+ {
+ public BrokenShaft()
+ {
+ Activated = true;
+ Title = 1074018; // Broken Shaft
+ Description = 1074112; // What do humans know of archery? Humans can barely shoot straight. Why, your efforts are absurd. In fact, I will make a wager - if these so called human arrows I've heard about are really as effective and innovative as human braggarts would have me believe, then I'll trade you something useful. I might even teach you something of elven craftsmanship.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( Arrow ), 1023902 ) ); // arrow
+
+ Rewards.Add( ItemReward.FletchingSatchel );
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Beotham" ), new Point3D( 6285, 114, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Beotham" ), new Point3D( 6285, 114, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Danoel" ), new Point3D( 6282, 116, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Danoel" ), new Point3D( 6282, 116, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Tallinin" ), new Point3D( 6279, 122, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Tallinin" ), new Point3D( 6279, 122, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Tiana" ), new Point3D( 6257, 112, -10 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Tiana" ), new Point3D( 6257, 112, -10 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "LorekeeperOolua" ), new Point3D( 6250, 124, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "LorekeeperOolua" ), new Point3D( 6250, 124, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "LorekeeperRollarn" ), new Point3D( 6244, 110, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "LorekeeperRollarn" ), new Point3D( 6244, 110, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Dallid" ), new Point3D( 6277, 104, -10 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Dallid" ), new Point3D( 6277, 104, -10 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Canir" ), new Point3D( 6274, 130, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Canir" ), new Point3D( 6274, 130, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Yellienir" ), new Point3D( 6257, 126, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Yellienir" ), new Point3D( 6257, 126, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "ElderOnallan" ), new Point3D( 6258, 108, -10 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "ElderOnallan" ), new Point3D( 6258, 108, -10 ), Map.Felucca );
+ }
+ }
+
+ public class BendingTheBow : MLQuest
+ {
+ public BendingTheBow()
+ {
+ Activated = true;
+ Title = 1074019; // Bending the Bow
+ Description = 1074113; // Human craftsmanship! Ha! Why, take an elven bow. It will last for a lifetime, never break and always shoot an arrow straight and true. Can't say the same for a human, can you? Bring me some of these human made bows, and I will show you.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( Bow ), 1025041 ) ); // bow
+
+ Rewards.Add( ItemReward.FletchingSatchel );
+ }
+ }
+
+ public class ArmsRace : MLQuest
+ {
+ public ArmsRace()
+ {
+ Activated = true;
+ Title = 1074020; // Arms Race
+ Description = 1074114; // Leave it to a human to try and improve upon perfection. To take a bow and turn it into a mechanical contraption like a crossbow. I wish to see more of this sort of "invention". Fetch for me a crossbow, human.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( Crossbow ), 1023919 ) ); // crossbow
+
+ Rewards.Add( ItemReward.FletchingSatchel );
+ }
+ }
+
+ public class ImprovedCrossbows : MLQuest
+ {
+ public ImprovedCrossbows()
+ {
+ Activated = true;
+ Title = 1074021; // Improved Crossbows
+ Description = 1074115; // How lazy is man! You cannot even be bothered to pull your own drawstring and hold an arrow ready? You must invent a device to do it for you? I cannot understand, but perhaps if I examine a heavy crossbow for myself, I will see their appeal. Go and bring me such a device and I will repay your meager favor.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( HeavyCrossbow ), 1025116 ) ); // heavy crossbow
+
+ Rewards.Add( ItemReward.FletchingSatchel );
+ }
+ }
+
+ public class BuildingTheBetterCrossbow : MLQuest
+ {
+ public BuildingTheBetterCrossbow()
+ {
+ Activated = true;
+ Title = 1074022; // Building the Better Crossbow
+ Description = 1074116; // More is always better for a human, eh? Take these repeating crossbows. What sort of mind invents such a thing? I must look at it more closely. Bring such a contraption to me and you'll receive a token for your efforts.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( RepeatingCrossbow ), 1029923 ) ); // repeating crossbow
+
+ Rewards.Add( ItemReward.FletchingSatchel );
+ }
+ }
+
+ public class InstrumentOfWar : MLQuest
+ {
+ public InstrumentOfWar()
+ {
+ Activated = true;
+ Title = 1074055; // Instrument of War
+ Description = 1074149; // Pathetic, this human craftsmanship! Take their broadswords - overgrown butter knives, in reality. No, I cannot do them justice - you must see for yourself. Bring me broadswords and I will demonstrate their feebleness.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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
+
+ Rewards.Add( ItemReward.BlacksmithSatchel );
+ }
+ }
+
+ public class TheShield : MLQuest
+ {
+ public TheShield()
+ {
+ Activated = true;
+ Title = 1074054; // The Shield
+ Description = 1074148; // I doubt very much a human shield would stop a good stout elven arrow. You doubt me? I will show you - get me some of these heater shields and I will piece them with sharp elven arrows!
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( HeaterShield ), 1027030 ) ); // heater shield
+
+ Rewards.Add( ItemReward.BlacksmithSatchel );
+ }
+ }
+
+ public class MusicToMyEars : MLQuest
+ {
+ public MusicToMyEars()
+ {
+ Activated = true;
+ Title = 1074023; // Music to my Ears
+ Description = 1074117; // You think you know something of music? Laughable! Take your lap harp. Crude, indelicate instruments that make a noise not unlike the wailing of a choleric child or a dying cat. I will show you - bring lap harps, and I will demonstrate.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( LapHarp ), 1023762 ) ); // lap harp
+
+ Rewards.Add( ItemReward.CarpentrySatchel );
+ }
+ }
+
+ public class TheGlassEye : MLQuest
+ {
+ public TheGlassEye()
+ {
+ Activated = true;
+ Title = 1074050; // The Glass Eye
+ Description = 1074144; // Humans are so pathetically weak, they must be augmented by glass and metal! Imagine such a thing! I must see one of these spyglasses for myself, to understand the pathetic limits of human sight!
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( Spyglass ), 1025365 ) ); // spyglass
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class LazyHumans : MLQuest
+ {
+ public LazyHumans()
+ {
+ Activated = true;
+ Title = 1074024; // Lazy Humans
+ Description = 1074118; // Human fancy knows no bounds! It's pathetic that they are so weak that they must create a special stool upon which to rest their feet when they recline! Humans don't have any clue how to live. Bring me some of these foot stools to examine and I may teach you something worthwhile.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( FootStool ), 1022910 ) ); // foot stool
+
+ Rewards.Add( ItemReward.CarpentrySatchel );
+ }
+ }
+
+ public class InventiveTools : MLQuest
+ {
+ public InventiveTools()
+ {
+ Activated = true;
+ Title = 1074048; // Inventive Tools
+ Description = 1074142; // Bring me some of these tinker's tools! I am certain, in the hands of an elf, they will fashion objects of ingenuity and delight that will shame all human invention! Hurry, do this quickly and I might deign to show you my skill.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class PixieDustToDust : MLQuest
+ {
+ public PixieDustToDust()
+ {
+ Activated = true;
+ Title = 1073661; // Pixie dust to dust
+ Description = 1073700; // Is there anything more foul than a pixie? They have cruel eyes and a mind for mischief, I say. I don't care if some think they're cute -- I say kill them and let the Avatar sort them out. In fact, if you were to kill a few pixies, I'd make sure you had a few coins to rub together, if you get my meaning.
+ RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point.
+ InProgressMessage = 1073741; // There's too much cuteness in the world -- kill those pixies!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Pixie ) }, "pixies" ) );
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class AnImpressivePlaid : MLQuest
+ {
+ public AnImpressivePlaid()
+ {
+ Activated = true;
+ Title = 1074044; // An Impressive Plaid
+ Description = 1074138; // I do not believe humans are so ridiculous as to wear something called a "kilt". Bring for me some of these kilts, if they truly exist, and I will offer you meager reward.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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
+
+ Rewards.Add( ItemReward.TailorSatchel );
+ }
+ }
+
+ public class ANiceShirt : MLQuest
+ {
+ public ANiceShirt()
+ {
+ Activated = true;
+ Title = 1074045; // A Nice Shirt
+ Description = 1074139; // Humans call that a fancy shirt? I would wager the ends are frayed, the collar worn, the buttons loosely stitched. Bring me fancy shirts and I will demonstrate the many ways in which they are inferior.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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
+
+ Rewards.Add( ItemReward.TailorSatchel );
+ }
+ }
+
+ public class LeatherAndLace : MLQuest
+ {
+ public LeatherAndLace()
+ {
+ Activated = true;
+ Title = 1074047; // Leather and Lace
+ Description = 1074141; // No self respecting elf female would ever wear a studded bustier! I will prove it - bring me such clothing and I will show you how ridiculous they are!
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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
+
+ Rewards.Add( ItemReward.TailorSatchel );
+ }
+ }
+
+ public class FeyHeadgear : MLQuest
+ {
+ public FeyHeadgear()
+ {
+ Activated = true;
+ Title = 1074043; // Fey Headgear
+ Description = 1074137; // Humans do not deserve to wear a thing such as a flower garland. Help me prevent such things from falling into the clumsy hands of humans -- bring me flower garlands!
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( FlowerGarland ), 1028965 ) ); // flower garland
+
+ Rewards.Add( ItemReward.TailorSatchel );
+ }
+ }
+
+ public class NewCloak : MLQuest
+ {
+ public NewCloak()
+ {
+ Activated = true;
+ Title = 1074684; // New Cloak
+ Description = 1074685; // I have created a masterpiece! And all I need to finish it off is the soft fur of a wolf. But not just ANY wolf -- oh no, no, that wouldn't do. I've heard tales of a mighty beast, Grobu, who is bonded to the leader of the troglodytes. Only Grobu's fur will do. Will you retrieve it for me?
+ RefusalMessage = 1074655; // Perhaps I thought too highly of you.
+ InProgressMessage = 1074686; // I've told you all I know of the creature. Until you return with Grobu's fur I can't finish my cloak.
+ CompletionMessage = 1074687; // Ah! So soft, so supple. What a wonderful texture. Here you are ... my thanks.
+
+ Objectives.Add( new CollectObjective( 1, typeof( GrobusFur ), 1074676 ) ); // Grobu's Fur
+
+ Rewards.Add( ItemReward.TailorSatchel );
+ }
+ }
+
+ public class ADishBestServedCold : MLQuest
+ {
+ public ADishBestServedCold()
+ {
+ Activated = true;
+ Title = 1072372; // A Dish Best Served Cold
+ Description = 1072657; // *mutter* I'll have my revenge. Oh! You there. Fancy some orc extermination? I despise them all. Bombers, brutes -- you name it, if it's orcish I want it killed.
+ RefusalMessage = 1072667; // Hrmph. Well maybe another time then.
+ InProgressMessage = 1072668; // Shouldn't you be slaying orcs?
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Orc ) }, "orcs", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+ Objectives.Add( new KillObjective( 5, new Type[] { typeof( OrcBomber ) }, "orc bombers", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+ Objectives.Add( new KillObjective( 3, new Type[] { typeof( OrcBrute ) }, "orc brutes", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class ArchEnemies : MLQuest
+ {
+ public ArchEnemies()
+ {
+ Activated = true;
+ Title = 1073085; // Arch Enemies
+ Description = 1073575; // Vermin! They get into everything! I told the boy to leave out some poisoned cheese -- and they shot him. What else can I do? Unless…these ratmen are skilled with a bow, but I'd lay a wager you're better, eh? Could you skin a few of the wretches for me?
+ RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell.
+ InProgressMessage = 1073595; // I don't see 10 tails from Ratman Archers on your belt -- and until I do, no reward for you.
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( RatmanArcher ) }, "ratman archers" ) );
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class Vermin : MLQuest
+ {
+ public Vermin()
+ {
+ Activated = true;
+ Title = 1072995; // Vermin
+ Description = 1073029; // You've got to help me out! Those ratmen have been causing absolute havok around here. Kill them off before they destroy my land. I'll pay you if you kill off twelve of those dirty rats.
+ RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me.
+ InProgressMessage = 1072271; // You're not quite done yet. Get back to work!
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( Ratman ) }, "ratmen" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class MougGuurMustDie : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( LeaderOfThePack ); } }
+
+ public MougGuurMustDie()
+ {
+ Activated = true;
+ Title = 1072368; // Moug-Guur Must Die
+ Description = 1072561; // You there! Yes, you. Kill Moug-Guur, the leader of the orcs in this depressing place, and I'll make it worth your while.
+ RefusalMessage = 1072571; // Fine. It's no skin off my teeth.
+ InProgressMessage = 1072572; // Small words. Kill Moug-Guur. Go. Now!
+ CompletionMessage = 1072573; // You're better than I thought you'd be. Not particularly bad, but not entirely inept.
+
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( MougGuur ) }, "Moug-Guur", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class LeaderOfThePack : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( SayonaraSzavetra ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public LeaderOfThePack()
+ {
+ Activated = true;
+ Title = 1072560; // Leader of the Pack
+ Description = 1072574; // Well now that Moug-Guur is no more -- and I can't say I'm weeping for his demise -- it's time for the ratmen to experience a similar loss of leadership. Slay Chiikkaha. In return, I'll satisfy your greed temporarily.
+ RefusalMessage = 1072575; // Alright, if you'd rather not, then run along and do whatever worthless things you do when I'm not giving you direction.
+ InProgressMessage = 1072576; // How difficult is this? The rats live in the tunnels. Go into the tunnels and find the biggest, meanest rat and execute him. Loitering around here won't get the task done.
+ CompletionMessage = 1072577; // It's about time! Could you have taken longer?
+
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( Chiikkaha ) }, "Chiikkaha", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class SayonaraSzavetra : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public SayonaraSzavetra()
+ {
+ Activated = true;
+ Title = 1072375; // Sayonara, Szavetra
+ Description = 1072578; // Hmm, maybe you aren't entirely worthless. I suspect a demoness of Szavetra's calibre will tear you apart ... We might as well find out. Kill the succubus, yada yada, and you'll be richly rewarded.
+ RefusalMessage = 1072579; // Hah! I knew you couldn't handle it.
+ InProgressMessage = 1072581; // Hahahaha! I can see the fear in your eyes. Pathetic. Szavetra is waiting for you.
+ CompletionMessage = 1072582; // Amazing! Simply astonishing ... you survived. Well, I supposed I should indulge your avarice with a reward.
+
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( Szavetra ) }, "Szavetra", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+
+ Rewards.Add( ItemReward.Strongbox );
+ }
+ }
+
+ public class TappingTheKeg : MLQuest
+ {
+ public TappingTheKeg()
+ {
+ Activated = true;
+ Title = 1074037; // Tapping the Keg
+ Description = 1074131; // I have acquired a barrel of human brewed beer. I am loathe to drink it, but how else to prove how inferior it is? I suppose I shall need a barrel tap to drink. Go, bring me a barrel tap quickly, so I might get this over with.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( BarrelTap ), 1024100 ) ); // barrel tap
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class WaitingToBeFilled : MLQuest
+ {
+ public WaitingToBeFilled()
+ {
+ Activated = true;
+ Title = 1074036; // Waiting to be Filled
+ Description = 1074130; // The only good thing I can say about human made bottles is that they are empty and may yet still be filled with elven wine. Go now, fetch a number of empty bottles so that I might save them from the fate of carrying human-made wine.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( 20, typeof( Bottle ), 1023854 ) ); // empty bottle
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class BreezesSong : MLQuest
+ {
+ public BreezesSong()
+ {
+ Activated = true;
+ Title = 1074052; // Breeze's Song
+ Description = 1074146; // I understand humans cruely enslave the very wind to their selfish whims! Fancy wind chimes, what a monstrous idea! You must bring me proof of this terrible depredation - hurry, bring me wind chimes!
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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( FancyWindChimes ), 1030291 ) ); // fancy wind chimes
+
+ Rewards.Add( ItemReward.TinkerSatchel );
+ }
+ }
+
+ public class ProofOfTheDeed : MLQuest
+ {
+ public ProofOfTheDeed()
+ {
+ Activated = true;
+ Title = 1072339; // Proof of the Deed
+ Description = 1072340; // These human vermin must be erradicated! They despoil fair Sosaria with their every footfall upon her soil, every exhalation of breath upon her pristine air. Prove yourself an ally of Sosaria and bring me 20 human ears as proof of your devotion to our cause.
+ RefusalMessage = 1072342; // Do you find the task distasteful? Are you too weak to shoulder the duty of cleansing Sosaria? So be it.
+ InProgressMessage = 1072343; // Well, where is the proof of your deed? I will honor your actions when you have brought me the ears of the human scum.
+ CompletionMessage = 1072344; // Ah, well done. You have chosen the path of duty and fulfilled your task with honor.
+
+ Objectives.Add( new CollectObjective( 20, typeof( SeveredHumanEars ), 1032591 ) ); // severed human ears
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class Marauders : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( TheBrainsOfTheOperation ); } }
+
+ public Marauders()
+ {
+ Activated = true;
+ Title = 1072374; // Marauders
+ Description = 1072686; // What a miserable place we live in. Look around you at the changes we've wrought. The trees are sprouting leaves once more and the grass is reclaiming the blood-soaked soil. Who would have imagined we'd find ourselves here? Our "neighbors" are anything but friendly and those ogres are the worst of the lot. Maybe you'd be interested in helping our community by disposing of some of our least amiable neighbors?
+ RefusalMessage = 1072687; // I quite understand your reluctance. If you reconsider, I'll be here.
+ InProgressMessage = 1072688; // You can't miss those ogres, they're huge and just outside the gates here.
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( Ogre ) }, "ogres", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+
+ Rewards.Add( ItemReward.BagOfTreasure );
+ }
+ }
+
+ public class TheBrainsOfTheOperation : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( TheBrawn ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public TheBrainsOfTheOperation()
+ {
+ Activated = true;
+ Title = 1072692; // The Brains of the Operation
+ Description = 1072707; // *sigh* We have so much to do to clean this area up. Even the fine work you did on those ogres didn't have much of an impact on the community. It's the ogre lords that direct the actions of the other ogres, let's strike at the leaders and perhaps that will thwart the miserable curs.
+ RefusalMessage = 1072708; // Reluctance doesn't become a hero like you. But, as you wish.
+ InProgressMessage = 1072709; // Ogre Lords are pretty easy to recognize. They're the ones ordering the other ogres about in a lordly manner. Striking down their leadership will throw the ogres into confusion and dismay!
+
+ Objectives.Add( new KillObjective( 10, new Type[] { typeof( OgreLord ) }, "ogre lords", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class TheBrawn : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( TheBiggerTheyAre ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public TheBrawn()
+ {
+ Activated = true;
+ Title = 1072693; // The Brawn
+ Description = 1072710; // Inconceiveable! We've learned that the ogre leadership has recruited some heavy-duty guards to their cause. I've never personally fought a cyclopian warrior, but I'm sure you could easily best a few and report back how much trouble they'll cause to our growing community?
+ RefusalMessage = 1072711; // Oh, I see. *sigh* Perhaps I overestimated your abilities.
+ InProgressMessage = 1072712; // Make sure you fully assess all of the cyclopian tactical abilities!
+
+ Objectives.Add( new KillObjective( 6, new Type[] { typeof( Cyclops ) }, "cyclops", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class TheBiggerTheyAre : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public TheBiggerTheyAre()
+ {
+ Activated = true;
+ Title = 1072694; // The Bigger They Are ...
+ Description = 1072713; // The ogre insurgency has taken a turn for the worse! I've just been advised that the titans have concluded their discussions with the ogres and they've allied. We have virtually no information about titans. Engage them and appraise their mettle.
+ RefusalMessage = 1072714; // Certainly. You've done enough to merit a breather. When you're ready for more, report back to me.
+ InProgressMessage = 1072715; // Those titans don't skulk very well. You should be able to track them easily ... their footsteps are easily the largest around.
+
+ Objectives.Add( new KillObjective( 3, new Type[] { typeof( Titan ) }, "titans", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+
+ Rewards.Add( ItemReward.LargeBagOfTreasure );
+ }
+ }
+
+ public class TroubleOnTheWing : MLQuest
+ {
+ public TroubleOnTheWing()
+ {
+ Activated = true;
+ Title = 1072371; // Trouble on the Wing
+ Description = 1072593; // Those gargoyles need to get knocked down a peg or two, if you ask me. They're always flying over here and lobbing things at us. What a nuisance. Drop a dozen of them for me, would you?
+ RefusalMessage = 1072594; // Don't tell me you're a gargoyle sympathizer? *spits*
+ InProgressMessage = 1072595; // Those blasted gargoyles hang around the old tower. That's the best place to hunt them down.
+
+ Objectives.Add( new KillObjective( 12, new Type[] { typeof( Gargoyle ) }, "gargoyles", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+ }
+
+ public class BrotherlyLove : MLQuest
+ {
+ public BrotherlyLove()
+ {
+ Activated = true;
+ OneTimeOnly = true;
+ Title = 1072369; // Brotherly Love
+ Description = 1072585; // *looks around nervously* Do you travel to The Heartwood? I have an urgent letter that must be delivered there in the next 30 minutes -- to Ahie the Cloth Weaver. Will you undertake this journey?
+ RefusalMessage = 1072587; // *looks disappointed* Let me know if you change your mind.
+ InProgressMessage = 1072588; // You haven't lost the letter have you? It must be delivered to Ahie directly. Give it into no other hands.
+ CompletionMessage = 1074579; // Yes, can I help you?
+
+ Objectives.Add( new DeliverObjective( typeof( APersonalLetterAddressedToAhie ), 1, "letter", typeof( Ahie ), "Ahie (The Heartwood)" ) );
+
+ Rewards.Add( ItemReward.BagOfTrinkets );
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+ }
+
+ #endregion
+
+ #region Mobiles
+
+ public class Beotham : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074187, // Want a job?
+ 1074184 // Come here, I have work for you.
+ ) );
+ }
+
+ [Constructable]
+ public Beotham()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Beotham";
+ Title = "the bowcrafter";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( 0x901 ) );
+ AddItem( new ShortPants( 0x522 ) );
+ AddItem( new FancyShirt( 0x515 ) );
+
+ Item item;
+
+ item = new LeafGloves();
+ item.Hue = 0x901;
+ AddItem( item );
+ }
+
+ public Beotham( 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 class Danoel : BaseCreature
+ {
+ // TODO: Add quests: Spring Cleaning
+
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074197 ); // Pardon me, but if you could spare some time I’d greatly appreciate it.
+ }
+
+ [Constructable]
+ public Danoel()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Danoel";
+ Title = "the metal weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x901 ) );
+ AddItem( new ElvenPants( 0x386 ) );
+ AddItem( new ElvenShirt( 0x75F ) );
+ AddItem( new FullApron( 0x1BB ) );
+ AddItem( new RoyalCirclet() );
+ AddItem( new SmithHammer() );
+ }
+
+ public Danoel( 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 class Tallinin : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074188, // Weakling! You are not up to the task I have.
+ 1074211 // I could use some help.
+ ) );
+ }
+
+ [Constructable]
+ public Tallinin()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Tallinin";
+ Title = "the cloth weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x901 ) );
+ AddItem( new Tunic( 0x37 ) );
+ AddItem( new Cloak( 0x735 ) );
+ }
+
+ public Tallinin( 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 class Tiana : BaseCreature
+ {
+ // TODO: Add quests, Common Brigands (needs Elf and Human Brigands put in first)
+
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074214, // Knave! Come here right now!
+ 1074218 // Hey! I want to talk to you, now.
+ ) );
+ }
+
+ [Constructable]
+ public Tiana()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Tiana";
+ Title = "the guard";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new HidePants() );
+ AddItem( new HideFemaleChest() );
+ AddItem( new HidePauldrons() );
+
+ Item item;
+
+ item = new WoodlandBelt();
+ item.Hue = 0x673;
+ AddItem( item );
+
+ item = new RavenHelm();
+ item.Hue = 0x443;
+ AddItem( item );
+ }
+
+ public Tiana( 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 class LorekeeperOolua : BaseCreature
+ {
+ // TODO: Add quest Dreadhorn
+
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074187 ); // Want a job?
+ }
+
+ [Constructable]
+ public LorekeeperOolua()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lorekeeper Oolua";
+ Title = "the keeper of tradition";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x75A ) );
+ AddItem( new Skirt( Utility.RandomBrightHue() ) );
+ AddItem( new FancyShirt( 0x742 ) );
+ AddItem( new Cloak( 0x1BB ) );
+ AddItem( new WildStaff() );
+ }
+
+ public LorekeeperOolua( 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 class LorekeeperRollarn : BaseCreature
+ {
+ // TODO: Add quest Brotherly Love
+
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074196, // Excuse me! I’m sorry to interrupt but I urgently need some assistance.
+ 1074197 // Pardon me, but if you could spare some time I’d greatly appreciate it.
+ ) );
+ }
+
+ [Constructable]
+ public LorekeeperRollarn()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lorekeeper Rollarn";
+ Title = "the keeper of tradition";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( 0x1BB ) );
+ AddItem( new Cloak( 0x296 ) );
+ AddItem( new Circlet() );
+ AddItem( new LeafChest() );
+
+ Item item;
+
+ item = new LeafLegs();
+ item.Hue = 0x71A;
+ AddItem( item );
+ }
+
+ public LorekeeperRollarn( 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 class Dallid : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074185, // Hey you! Want to help me out?
+ 1074195 // You there, in the stupid hat! Come here.
+ ) );
+ }
+
+ [Constructable]
+ public Dallid()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Dallid";
+ Title = "the cook";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Boots( 0x901 ) );
+ AddItem( new ShortPants( 0x73C ) );
+ AddItem( new Shirt( 0x744 ) );
+ AddItem( new FullApron( 0x1BE ) );
+ AddItem( new Cleaver() );
+ }
+
+ public Dallid( 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 class Canir : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074193, // You there! Yes you. Stop looking about like a toadie and come here.
+ 1074186 // Come here, I have a task.
+ ) );
+ }
+
+ [Constructable]
+ public Canir()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Canir";
+ Title = "the thaumaturgist";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Sandals( 0x1BB ) );
+ AddItem( new FemaleElvenRobe( 0x5A7 ) );
+ AddItem( new GemmedCirclet() );
+ AddItem( new MagicWand() );
+ }
+
+ public Canir( 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 class Yellienir : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Yellienir()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Yellienir";
+ Title = "the bark weaver";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new ElvenBoots() );
+ AddItem( new LeafTonlet() );
+ AddItem( new FemaleLeafChest() );
+ AddItem( new LeafArms() );
+ AddItem( new Cloak( 0x3B2 ) );
+ }
+
+ public Yellienir( 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 class ElderOnallan : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074217, // I want to make you an offer you’d be a fool to refuse.
+ 1074218 // Hey! I want to talk to you, now.
+ ) );
+ }
+
+ [Constructable]
+ public ElderOnallan()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Elder Onallan";
+ Title = "the wise";
+ Race = Race.Elf;
+ BodyValue = 0x25D;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new Shoes( 0x729 ) );
+ AddItem( new WildStaff() );
+ AddItem( new Cloak( 0x64E ) );
+ }
+
+ public ElderOnallan( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/Spellweaving.cs b/Scripts/Engines/MLQuests/Definitions/Spellweaving.cs
new file mode 100644
index 000000000..1abd54ef0
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/Spellweaving.cs
@@ -0,0 +1,691 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server.Engines.MLQuests.Objectives;
+using Server.Items;
+using Server.Engines.MLQuests.Rewards;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ public static class Spellweaving
+ {
+ public static void AwardTo( PlayerMobile pm )
+ {
+ if ( pm == null )
+ return;
+
+ MLQuestContext context = MLQuestSystem.GetOrCreateContext( pm );
+
+ if ( !context.Spellweaving )
+ {
+ context.Spellweaving = true;
+
+ Effects.SendLocationParticles( EffectItem.Create( pm.Location, pm.Map, EffectItem.DefaultDuration ), 0, 0, 0, 0, 0, 5060, 0 );
+ Effects.PlaySound( pm.Location, pm.Map, 0x243 );
+
+ Effects.SendMovingParticles( new Entity( Server.Serial.Zero, new Point3D( pm.X - 6, pm.Y - 6, pm.Z + 15 ), pm.Map ), pm, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 );
+ Effects.SendMovingParticles( new Entity( Server.Serial.Zero, new Point3D( pm.X - 4, pm.Y - 6, pm.Z + 15 ), pm.Map ), pm, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 );
+ Effects.SendMovingParticles( new Entity( Server.Serial.Zero, new Point3D( pm.X - 6, pm.Y - 4, pm.Z + 15 ), pm.Map ), pm, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 );
+
+ Effects.SendTargetParticles( pm, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100 );
+ }
+ }
+ }
+
+ #region Patience
+
+ public class Patience : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( NeedsOfTheManyHeartwood1 ); } }
+
+ public Patience()
+ {
+ Activated = true;
+ Title = 1072753; // Patience
+ Description = 1072762; // Learning to weave spells and control the forces of nature requires sacrifice, discipline, focus, and an unwavering dedication to Sosaria herself. We do not teach the unworthy. They do not comprehend the lessons nor the dedication required. If you would walk the path of the Arcanist, then you must do as I require without hesitation or question. Your first task is to gather miniature mushrooms ... 20 of them from the branches of our mighty home. I give you one hour to complete the task.
+ RefusalMessage = 1072767; // *nods* Not everyone has the temperment to undertake the way of the Arcanist.
+ InProgressMessage = 1072774; // The mushrooms I seek can be found growing here in The Heartwood. Seek them out and gather them. You are running out of time.
+ CompletionMessage = 1074166; // Have you gathered the mushrooms?
+
+ Objectives.Add( new TimedCollectObjective( TimeSpan.FromHours( 1 ), 20, typeof( MiniatureMushroom ), "miniature mushrooms" ) );
+
+ Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Aeluva" ), new Point3D( 7064, 349, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Aeluva" ), new Point3D( 7064, 349, 0 ), Map.Trammel );
+
+ // Split up to prevent stacking on the spawner
+ PutSpawner( new Spawner( 20, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 30, "MiniatureMushroom" ), new Point3D( 7015, 366, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 20, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 30, "MiniatureMushroom" ), new Point3D( 7015, 366, 0 ), Map.Trammel );
+
+ PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 20, "MiniatureMushroom" ), new Point3D( 7081, 373, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 20, "MiniatureMushroom" ), new Point3D( 7081, 373, 0 ), Map.Trammel );
+
+ PutSpawner( new Spawner( 15, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 20, "MiniatureMushroom" ), new Point3D( 7052, 414, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 15, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 20, "MiniatureMushroom" ), new Point3D( 7052, 414, 0 ), Map.Trammel );
+ }
+ }
+
+ public class NeedsOfTheManyHeartwood1 : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( NeedsOfTheManyHeartwood2 ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public NeedsOfTheManyHeartwood1()
+ {
+ Activated = true;
+ Title = 1072797; // Needs of the Many - The Heartwood
+ Description = 1072763; // The way of the Arcanist involves cooperation with others and a strong committment to the community of your people. We have run low on the cotton we use to pack wounds and our people have need. Bring 10 bales of cotton to me.
+ RefusalMessage = 1072768; // You endanger your progress along the path with your unwillingness.
+ InProgressMessage = 1072775; // I care not where you acquire the cotton, merely that you provide it.
+ CompletionMessage = 1074110; // Well, where are the cotton bales?
+
+ Objectives.Add( new CollectObjective( 10, typeof( Cotton ), 1023577 ) ); // bale of cotton
+
+ Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist.
+ }
+ }
+
+ public class NeedsOfTheManyHeartwood2 : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( MakingAContributionHeartwood ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public NeedsOfTheManyHeartwood2()
+ {
+ Activated = true;
+ Title = 1072797; // Needs of the Many - The Heartwood
+ Description = 1072764; // We must look to the defense of our people! Bring boards for new arrows.
+ RefusalMessage = 1072769; // The people have need of these items. You are proving yourself inadequate to the demands of a member of this community.
+ InProgressMessage = 1072776; // The requirements are simple -- 250 boards.
+ CompletionMessage = 1074152; // Well, where are the boards?
+
+ Objectives.Add( new CollectObjective( 250, typeof( Board ), 1027127 ) ); // board
+
+ Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist.
+ }
+ }
+
+ public class MakingAContributionHeartwood : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( UnnaturalCreations ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public MakingAContributionHeartwood()
+ {
+ Activated = true;
+ Title = 1072798; // Making a Contribution - The Heartwood
+ Description = 1072765; // With health and defense assured, we need look to the need of the community for food and drink. We will feast on fish steaks, sweets, and wine. You will supply the ingredients, the cooks will prepare the meal. As a Arcanist relies upon others to build focus and lend their power to her workings, the community needs the effort of all to survive.
+ RefusalMessage = 1072770; // Do not falter now. You have begun to show promise.
+ InProgressMessage = 1072777; // Where are the items you've been tasked to supply for the feast?
+ CompletionMessage = 1074158; // Ah good, you're back. We're eager for the feast.
+
+ Objectives.Add( new CollectObjective( 1, typeof( SackFlour ), 1024153 ) ); // sack of flour
+ Objectives.Add( new CollectObjective( 10, typeof( JarHoney ), 1022540 ) ); // jar of honey
+ Objectives.Add( new CollectObjective( 20, typeof( FishSteak ), 1022427 ) ); // fish steak
+
+ Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist.
+ }
+ }
+
+ public class UnnaturalCreations : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public UnnaturalCreations()
+ {
+ Activated = true;
+ Title = 1072758; // Unnatural Creations
+ Description = 1072780; // You have proven your desire to contribute to the community and serve the people. Now you must demonstrate your willingness to defend Sosaria from the greatest blight that plagues her. Unnatural creatures, brought to a sort of perverted life, despoil our fair world. Destroy them -- 5 Exodus Overseers and 2 Exodus Minions.
+ RefusalMessage = 1072771; // You must serve Sosaria with all your heart and strength. Your unwillingness does not reflect favorably upon you.
+ InProgressMessage = 1072779; // Every moment you procrastinate, these unnatural creatures damage Sosaria.
+ CompletionMessage = 1074167; // Well done! Well done, indeed. You are worthy to become an arcanist!
+
+ Objectives.Add( new KillObjective( 5, new Type[] { typeof( ExodusOverseer ) }, "Exodus Overseers" ) );
+ Objectives.Add( new KillObjective( 2, new Type[] { typeof( ExodusMinion ) }, "Exodus Minions" ) );
+
+ Rewards.Add( new ItemReward( 1031601, typeof( ArcaneCircleScroll ) ) ); // Arcane Circle
+ Rewards.Add( new ItemReward( 1031600, typeof( SpellweavingBook ) ) ); // Spellweaving Spellbook
+ Rewards.Add( new ItemReward( 1031602, typeof( GiftOfRenewalScroll ) ) ); // Gift of Renewal
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ Spellweaving.AwardTo( instance.Player );
+ base.GetRewards( instance );
+ }
+ }
+
+ #endregion
+
+ #region Discipline
+
+ public class Discipline : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( NeedsOfTheManySanctuary ); } }
+
+ public Discipline()
+ {
+ Activated = true;
+ Title = 1072752; // Discipline
+ Description = 1072761; // Learning to weave spells and control the forces of nature requires sacrifice, discipline, focus, and an unwavering dedication to Sosaria herself. We do not teach the unworthy. They do not comprehend the lessons nor the dedication required. If you would walk the path of the Arcanist, then you must do as I require without hesitation or question. Your first task is to rid our home of rats ... 50 of them in the next hour.
+ RefusalMessage = 1072767; // *nods* Not everyone has the temperment to undertake the way of the Arcanist.
+ InProgressMessage = 1072773; // You waste my time. The task is simple. Kill 50 rats in an hour.
+ // No completion message
+
+ Objectives.Add( new TimedKillObjective( TimeSpan.FromHours( 1 ), 50, new Type[] { typeof( Rat ) }, "rats", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary
+
+ Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Koole" ), new Point3D( 6257, 110, -10 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Koole" ), new Point3D( 6257, 110, -10 ), Map.Trammel );
+ }
+ }
+
+ public class NeedsOfTheManySanctuary : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( MakingAContributionSanctuary ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public NeedsOfTheManySanctuary()
+ {
+ Activated = true;
+ Title = 1072754; // Needs of the Many - Sanctuary
+ Description = 1072763; // The way of the Arcanist involves cooperation with others and a strong committment to the community of your people. We have run low on the cotton we use to pack wounds and our people have need. Bring 10 bales of cotton to me.
+ RefusalMessage = 1072768; // You endanger your progress along the path with your unwillingness.
+ InProgressMessage = 1072775; // I care not where you acquire the cotton, merely that you provide it.
+ CompletionMessage = 1074110; // Well, where are the cotton bales?
+
+ Objectives.Add( new CollectObjective( 10, typeof( Cotton ), 1023577 ) ); // bale of cotton
+
+ Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist.
+ }
+ }
+
+ public class MakingAContributionSanctuary : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( SuppliesForSanctuary ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public MakingAContributionSanctuary()
+ {
+ Activated = true;
+ Title = 1072755; // Making a Contribution - Sanctuary
+ Description = 1072764; // We must look to the defense of our people! Bring boards for new arrows.
+ RefusalMessage = 1072769; // The people have need of these items. You are proving yourself inadequate to the demands of a member of this community.
+ InProgressMessage = 1072776; // The requirements are simple -- 250 boards.
+ CompletionMessage = 1074152; // Well, where are the boards?
+
+ Objectives.Add( new CollectObjective( 250, typeof( Board ), 1027127 ) ); // board
+
+ Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist.
+ }
+ }
+
+ public class SuppliesForSanctuary : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( TheHumanBlight ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public SuppliesForSanctuary()
+ {
+ Activated = true;
+ Title = 1072756; // Supplies for Sanctuary
+ Description = 1072765; // With health and defense assured, we need look to the need of the community for food and drink. We will feast on fish steaks, sweets, and wine. You will supply the ingredients, the cooks will prepare the meal. As a Arcanist relies upon others to build focus and lend their power to her workings, the community needs the effort of all to survive.
+ RefusalMessage = 1072770; // Do not falter now. You have begun to show promise.
+ InProgressMessage = 1072777; // Where are the items you've been tasked to supply for the feast?
+ CompletionMessage = 1074158; // Ah good, you're back. We're eager for the feast.
+
+ Objectives.Add( new CollectObjective( 1, typeof( SackFlour ), 1024153 ) ); // sack of flour
+ Objectives.Add( new CollectObjective( 10, typeof( JarHoney ), 1022540 ) ); // jar of honey
+ Objectives.Add( new CollectObjective( 20, typeof( FishSteak ), 1022427 ) ); // fish steak
+
+ Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist.
+ }
+ }
+
+ public class TheHumanBlight : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public TheHumanBlight()
+ {
+ Activated = true;
+ Title = 1072757; // The Human Blight
+ Description = 1072766; // You have proven your desire to contribute to the community and serve the people. Now you must demonstrate your willingness to defend Sosaria from the greatest blight that plagues her. The human vermin that have spread as a disease, despoiling the land are the greatest blight we face. Kill humans and return to me the proof of your actions. Bring me 30 human ears.
+ RefusalMessage = 1072771; // You must serve Sosaria with all your heart and strength. Your unwillingness does not reflect favorably upon you.
+ InProgressMessage = 1072778; // Why do you delay? The human blight must be averted.
+ CompletionMessage = 1074160; // I will take the ears you have collected now. Hand them here.
+
+ Objectives.Add( new CollectObjective( 30, typeof( SeveredHumanEars ), 1032591 ) ); // severed human ears
+
+ Rewards.Add( new ItemReward( 1031601, typeof( ArcaneCircleScroll ) ) ); // Arcane Circle
+ Rewards.Add( new ItemReward( 1031600, typeof( SpellweavingBook ) ) ); // Spellweaving Spellbook
+ Rewards.Add( new ItemReward( 1031602, typeof( GiftOfRenewalScroll ) ) ); // Gift of Renewal
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ Spellweaving.AwardTo( instance.Player );
+ base.GetRewards( instance );
+ }
+ }
+
+ #endregion
+
+ #region Friend of the Fey
+
+ public class FriendOfTheFey : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( TokenOfFriendship ); } }
+
+ public FriendOfTheFey()
+ {
+ Activated = true;
+ Title = 1074284; // Friend of the Fey
+ Description = 1074286; // The children of Sosaria understand the dedication and committment of an arcanist -- and will, from time to time offer their friendship. If you would forge such a bond, first seek out a goodwill offering to present. Pixies enjoy sweets and pretty things.
+ RefusalMessage = 1074288; // There's always time to make new friends.
+ InProgressMessage = 1074290; // I think honey and some sparkly beads would please a pixie.
+ CompletionMessage = 1074292; // What have we here? Oh yes, gifts for a pixie.
+
+ Objectives.Add( new CollectObjective( 1, typeof( Beads ), 1024235 ) ); // beads
+ Objectives.Add( new CollectObjective( 1, typeof( JarHoney ), 1022540 ) ); // jar of honey
+
+ 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)
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Synaeva" ), new Point3D( 7064, 350, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Synaeva" ), new Point3D( 7064, 350, 0 ), Map.Trammel );
+ }
+ }
+
+ public class TokenOfFriendship : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( Alliance ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public TokenOfFriendship()
+ {
+ Activated = true;
+ Title = 1074293; // Token of Friendship
+ Description = 1074297; // I've wrapped your gift suitably to present to a pixie of discriminating taste. Seek out Arielle and give her your offering.
+ RefusalMessage = 1074310; // I'll hold onto this gift in case you change your mind.
+ 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" ) );
+
+ 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)
+ }
+ }
+
+ public class Alliance : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public Alliance()
+ {
+ Activated = true;
+ Title = 1074294; // Alliance
+ Description = 1074298; // *giggle* Mean reapers make pixies unhappy. *light-hearted giggle* You could fix them!
+ RefusalMessage = 1074311; // *giggle* Okies!
+ InProgressMessage = 1074316; // Mean reapers are all around trees! *giggle* You fix them up, please.
+
+ Objectives.Add( new KillObjective( 20, new Type[] { typeof( Reaper ) }, "reapers" ) );
+
+ Rewards.Add( new ItemReward( 1031607, typeof( SummonFeyScroll ) ) ); // Summon Fey
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1073775, "", 0x23 ); // Your quest is complete. Return for your reward.
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.PlayerContext.SummonFey = true;
+ instance.Player.SendLocalizedMessage( 1074320, "", 0x2A ); // *giggle* Mean reapers got fixed! Pixie friend now! *giggle* When mean thingies bother you, a brave pixie will help.
+
+ base.GetRewards( instance );
+ }
+ }
+
+ #endregion
+
+ #region Fiendish Friends
+
+ public class FiendishFriends : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( CrackingTheWhipI ); } }
+
+ public FiendishFriends()
+ {
+ Activated = true;
+ Title = 1074283; // Fiendish Friends
+ Description = 1074285; // It is true that a skilled arcanist can summon and dominate an imp to serve at their pleasure. To do such at thing though, you must master the miserable little fiends utterly by demonstrating your superiority. Rough them up some -- kill a few. That will do the trick.
+ RefusalMessage = 1074287; // You're probably right. They're not worth the effort.
+ InProgressMessage = 1074289; // Surely you're not having difficulties swatting down those annoying pests?
+ // TODO: Verify
+ CompletionMessage = 1074291; // Hah! You showed them!
+
+ Objectives.Add( new KillObjective( 50, new Type[] { typeof( Imp ) }, "imps" ) );
+
+ Rewards.Add( new DummyReward( 1074873 ) ); // The opportunity to prove yourself worthy of learning to Summon Fiends. (Sufficient spellweaving skill is required to cast the spell)
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "ElderBrae" ), new Point3D( 6266, 124, 0 ), Map.Felucca );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 0, "ElderBrae" ), new Point3D( 6266, 124, 0 ), Map.Trammel );
+ }
+ }
+
+ // TODO: Verify
+ public class CrackingTheWhipI : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( CrackingTheWhipII ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public CrackingTheWhipI()
+ {
+ Activated = true;
+ Title = 1074295; // Cracking the Whip
+ Description = 1074300; // Now that you've shown those mini pests your might, you should collect suitable implements to use to train your summoned pet. I suggest a stout whip.
+ RefusalMessage = 1074313; // Heh. Changed your mind, eh?
+ InProgressMessage = 1074317; // Well, hurry up. If you don't get a whip how do you expect to control the little devil?
+ CompletionMessage = 1074321; // That's a well-made whip. No imp will ignore the sting of that lash.
+
+ Objectives.Add( new CollectObjective( 1, typeof( StoutWhip ), "Stout Whip" ) );
+
+ Rewards.Add( new DummyReward( 1074873 ) ); // The opportunity to prove yourself worthy of learning to Summon Fiends. (Sufficient spellweaving skill is required to cast the spell)
+ }
+ }
+
+ // TODO: Verify
+ public class CrackingTheWhipII : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public CrackingTheWhipII()
+ {
+ Activated = true;
+ Title = 1074295; // Cracking the Whip
+ Description = 1074302; // Now you just need to make the little buggers fear you -- if you can slay an arcane daemon, you'll earn their subservience.
+ RefusalMessage = 1074314; // If you're not up for it, so be it.
+ InProgressMessage = 1074318; // You need to vanquish an arcane daemon before the imps will fear you properly.
+
+ Objectives.Add( new KillObjective( 1, new Type[] { typeof( ArcaneDaemon ) }, 1029733 ) ); // arcane demon
+
+ Rewards.Add( new ItemReward( 1031608, typeof( SummonFiendScroll ) ) ); // Summon Fiend
+ }
+
+ public override void GetRewards( MLQuestInstance instance )
+ {
+ instance.PlayerContext.SummonFiend = true;
+ instance.Player.SendLocalizedMessage( 1074322, "", 0x2A ); // You've demonstrated your strength, got a means of control, and taught the imps to fear you. You're ready now to summon them.
+
+ base.GetRewards( instance );
+ }
+ }
+
+ #endregion
+
+ #region Mobiles
+
+ public class Aeluva : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ /*
+ * 1074206 - Excuse me please traveler, might I have a little of your time?
+ * 1074207 - Good day to you friend! Allow me to offer you a fabulous opportunity! Thrills and adventure await!
+ */
+ MLQuestSystem.Tell( this, pm, Utility.Random( 1074206, 2 ) );
+ }
+
+ [Constructable]
+ public Aeluva()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2.0 )
+ {
+ Name = "Aeluva";
+ Title = "the arcanist";
+ Race = Race.Elf;
+ Female = true;
+ Body = 606;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenShirt() );
+ AddItem( new Kilt( Utility.RandomNondyedHue() ) ); // Note: OSI hue = 0x1516, typo?
+ AddItem( new ElvenBoots() );
+ AddItem( new Circlet() );
+ }
+
+ public Aeluva( 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 class Koole : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074186, // Come here, I have a task.
+ 1074218 // Hey! I want to talk to you, now.
+ ) );
+ }
+
+ [Constructable]
+ public Koole()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2.0 )
+ {
+ Name = "Koole";
+ Title = "the arcanist";
+ Race = Race.Elf;
+ Body = 605;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ Item item;
+
+ item = new LeafChest();
+ item.Hue = 443;
+ AddItem( item );
+
+ item = new LeafArms();
+ item.Hue = 443;
+ AddItem( item );
+
+ AddItem( new LeafTonlet() );
+ AddItem( new ThighBoots( Utility.RandomAnimalHue() ) );
+ AddItem( new RoyalCirclet() );
+ }
+
+ public Koole( 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 class Synaeva : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074223 ); // Have you done it yet? Oh, I haven’t told you, have I?
+ }
+
+ [Constructable]
+ public Synaeva()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2.0 )
+ {
+ Name = "Synaeva";
+ Title = "the arcanist";
+ Race = Race.Elf;
+ Female = true;
+ Body = 606;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ Item item = new RavenHelm();
+ item.Hue = Utility.RandomGreenHue();
+ AddItem( item );
+
+ AddItem( new FemaleLeafChest() );
+ AddItem( new LeafArms() );
+ AddItem( new LeafTonlet() );
+ AddItem( new ElvenBoots() );
+ AddItem( new WildStaff() );
+ }
+
+ public Synaeva( 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 class ElderBrae : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, Utility.RandomList(
+ 1074215, // Don’t test my patience you sniveling worm!
+ 1074218 // Hey! I want to talk to you, now.
+ ) );
+ }
+
+ [Constructable]
+ public ElderBrae()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2.0 )
+ {
+ Name = "Elder Brae";
+ Title = "the wise";
+ Race = Race.Elf;
+ Female = true;
+ Body = 606;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new GemmedCirclet() );
+ AddItem( new FemaleElvenRobe( Utility.RandomBrightHue() ) );
+ AddItem( new ElvenBoots( Utility.RandomAnimalHue() ) );
+ }
+
+ public ElderBrae( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/TheAncientWorld.cs b/Scripts/Engines/MLQuests/Definitions/TheAncientWorld.cs
new file mode 100644
index 000000000..ee6b34dc3
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/TheAncientWorld.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.ContextMenus;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Misc;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Quests
+
+ public class TheAncientWorld : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( TheGoldenHorn ); } }
+
+ public TheAncientWorld()
+ {
+ Activated = true;
+ Title = 1074534; // The Ancient World
+ Description = 1074535; // The lore of my people mentions Mondain many times. In one tale, it is revealed that he created and enslaved a race -- a sort of man bull, known as a 'minotaur'. The tales speak of mighty warriors who charged with blood-soaked horns into the heat of battle. But, alas, the fate of the bull-men is unknown after the rupture. Will you seek information about their civilization?
+ RefusalMessage = 1074538; // I am disappointed, but I respect your decision.
+ InProgressMessage = 1074539; // A traveler has told me that worshippers of Mondain still exist and wander the land. Perhaps their lore speaks of whether the bull-men survived. I do not think they share their secrets gladly. You may need to be 'persuasive'.
+ CompletionMessage = 1074542; // What have you found?
+
+ Objectives.Add( new CollectObjective( 1, typeof( FragmentOfAMap ), "fragment of a map" ) );
+
+ Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperBroolol" ), new Point3D( 7011, 375, 0 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperBroolol" ), new Point3D( 7011, 375, 0 ), Map.Felucca );
+ }
+ }
+
+ public class TheGoldenHorn : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( Bullish ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public TheGoldenHorn()
+ {
+ Activated = true;
+ Title = 1074543; // The Golden Horn
+ Description = 1074545; // Ah ha! You see here ... and over here ... The map fragment places the city of the bull-men, Labyrinth, on that piece of Sosaria that was thrown into the sky. Hmmm, I would have you go there and find any artifacts that remain that help tell the story. But, legend speaks of a mighty barrier to prevent invasion of the city. Take this map to Braen and explain the problem. Perhaps he can devise a solution.
+ RefusalMessage = 1074538; // I am disappointed, but I respect your decision.
+ 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)" ) );
+
+ Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur.
+ }
+ }
+
+ public class Bullish : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( LostCivilization ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public Bullish()
+ {
+ Activated = true;
+ Title = 1074550; // Bullish
+ Description = 1074552; // Oh, I see. I will need some materials to infuse you with the essence of a bull-man, so you can fool their defenses. The most similar beast to the original Baratarian bull that the minotaur were bred from is undoubtedly the mighty Gaman, native to the Lands of the Feudal Lords. I need horns, in great quantity to undertake this magic.
+ RefusalMessage = 1074554; // Oh come now, don't be afraid. The magic won't harm you.
+ InProgressMessage = 1074555; // I cannot grant you the ability to pass through the bull-men's defenses without the gaman horns.
+ CompletionMessage = 1074556; // You've returned at last! Give me just a moment to examine what you've brought and I can perform the magic that will allow you enter the Labyrinth.
+
+ Objectives.Add( new CollectObjective( 20, typeof( GamanHorns ), "gaman horns" ) );
+
+ Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur.
+ }
+ }
+
+ public class LostCivilization : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public LostCivilization()
+ {
+ Activated = true;
+ Title = 1074823; // Lost Civilization
+ Description = 1074825; // *whew* It is done! The fierce essence of the bull has been infused into your aura. You are able now to breach the ancient defenses of the city. Go forth and seek the minotaur -- and then return with wonderous tales and evidence of your visit to the Labyrinth.
+ RefusalMessage = 1074827; // As you wish. I can't understand why you'd pass up such a remarkable opportunity. Think of the adventures you would have.
+ InProgressMessage = 1074828; // You won't reach the minotaur city by loitering around here! What are you waiting for? You need to get to Malas and find the access point for the island. You'll be renowned for your discovery!
+ CompletionMessage = 1074829; // Oh! You've returned at last! I can't wait to hear the tales ... but first, let me see those artifacts. You've certainly earned this reward.
+
+ Objectives.Add( new CollectObjective( 3, typeof( MinotaurArtifact ), "minotaur artifacts" ) );
+
+ Rewards.Add( ItemReward.Strongbox );
+ }
+ }
+
+ #endregion
+
+ #region Mobiles
+
+ public class LorekeeperBroolol : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+ public override bool CanTeach { get { return true; } }
+
+ public override bool CanShout { get { return true; } }
+ public override void Shout( PlayerMobile pm )
+ {
+ MLQuestSystem.Tell( this, pm, 1074200 ); // Thank goodness you are here, there’s no time to lose.
+ }
+
+ [Constructable]
+ public LorekeeperBroolol()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Lorekeeper Broolol";
+ Title = "the keeper of tradition";
+ Race = Race.Elf;
+ BodyValue = 0x25E;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ SetSkill( SkillName.Meditation, 60.0, 80.0 );
+ SetSkill( SkillName.Focus, 60.0, 80.0 );
+
+ AddItem( new ElvenBoots( 0x70D ) );
+ AddItem( new FemaleElvenRobe( 0x3A ) );
+ AddItem( new WildStaff() );
+ }
+
+ public LorekeeperBroolol( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/TownEscorts.cs b/Scripts/Engines/MLQuests/Definitions/TownEscorts.cs
new file mode 100644
index 000000000..244161c74
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/TownEscorts.cs
@@ -0,0 +1,131 @@
+using System;
+using Server;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ public class TownEscort : BaseEscort
+ {
+ // Escort reward
+ private static readonly BaseReward m_Reward = new ItemReward( "Gold", typeof( Gold ), 500 );
+
+ public TownEscort( int title, int progress, int destination, string region )
+ {
+ Activated = true;
+ Title = title;
+ Description = 1072287; // I seek a worthy escort. I can offer some small pay to any able bodied adventurer who can assist me. It is imperative that I reach my destination.
+ RefusalMessage = 1072288; // I wish you would reconsider my offer. I'll be waiting right here for someone brave enough to assist me.
+ InProgressMessage = progress;
+
+ Objectives.Add( new EscortObjective( new QuestArea( destination, region ) ) );
+
+ Rewards.Add( m_Reward );
+ }
+ }
+
+ public class EscortToYew : TownEscort
+ {
+ public EscortToYew()
+ : base( 1072275, 1072289, 1072227, "Yew" )
+ {
+ }
+ }
+
+ public class EscortToVesper : TownEscort
+ {
+ public EscortToVesper()
+ : base( 1072276, 1072290, 1072229, "Vesper" )
+ {
+ }
+ }
+
+ public class EscortToTrinsic : TownEscort
+ {
+ public EscortToTrinsic()
+ : base( 1072277, 1072291, 1072236, "Trinsic" )
+ {
+ }
+ }
+
+ public class EscortToSkaraBrae : TownEscort
+ {
+ public EscortToSkaraBrae()
+ : base( 1072278, 1072292, 1072235, "Skara Brae" )
+ {
+ }
+ }
+
+ public class EscortToSerpentsHold : TownEscort
+ {
+ public EscortToSerpentsHold()
+ : base( 1072279, 1072293, 1072238, "Serpent's Hold" )
+ {
+ }
+ }
+
+ public class EscortToNujelm : TownEscort
+ {
+ public EscortToNujelm()
+ : base( 1072280, 1072294, 1072237, "Nujel'm" )
+ {
+ }
+ }
+
+ public class EscortToMoonglow : TownEscort
+ {
+ public EscortToMoonglow()
+ : base( 1072281, 1072295, 1072232, "Moonglow" )
+ {
+ }
+ }
+
+ public class EscortToMinoc : TownEscort
+ {
+ public EscortToMinoc()
+ : base( 1072282, 1072296, 1072228, "Minoc" )
+ {
+ }
+ }
+
+ public class EscortToMagincia : TownEscort
+ {
+ public EscortToMagincia()
+ : base( 1072283, 1072297, 1072233, "Magincia" )
+ {
+ }
+ }
+
+ public class EscortToJhelom : TownEscort
+ {
+ public EscortToJhelom()
+ : base( 1072284, 1072298, 1072239, "Jhelom" )
+ {
+ }
+ }
+
+ public class EscortToCove : TownEscort
+ {
+ public EscortToCove()
+ : base( 1072285, 1072299, 1072230, "Cove" )
+ {
+ }
+ }
+
+ public class EscortToBritain : TownEscort
+ {
+ public EscortToBritain()
+ : base( 1072286, 1072300, 1072231, "Britain" )
+ {
+ }
+ }
+
+ public class EscortToOcllo : TownEscort
+ {
+ public EscortToOcllo()
+ : base( 1072312, 1072313, 1072234, "Ocllo" )
+ {
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/UnfadingMemories.cs b/Scripts/Engines/MLQuests/Definitions/UnfadingMemories.cs
new file mode 100644
index 000000000..eb0413e83
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/UnfadingMemories.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.ContextMenus;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Misc;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ #region Quests
+
+ public class UnfadingMemoriesPartOne : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( UnfadingMemoriesPartTwo ); } }
+
+ public UnfadingMemoriesPartOne()
+ {
+ Activated = true;
+ OneTimeOnly = true; // TODO: Similar issue as Aemaeth, part one may be taken while part three is not finished
+ Title = 1075355; // Unfading Memories
+ Description = 1075356; // Aargh! It’s just not right! It doesn’t capture the unique color of her hair at all! If only I had some Prismatic Amber. That would be perfect. They used to mine it in Malas, but alas, those veins ran dry some time ago. I hear it may have been found in the Prism of Light. Oh, if only there were a bold adventurer within earshot who would go to the Prism of Light and retrieve some for me!
+ RefusalMessage = 1075358; // Is there no one who can help a humble artist pursue his Muse?
+ InProgressMessage = 1075359; // You can find Prismatic Amber in the Prism of Light, located just north of the city of Nujel'm.
+ CompletionMessage = 1075360; // I knew it! See, it’s just the color I needed! Look how it brings out the highlights of her wheaten tresses!
+
+ Objectives.Add( new CollectObjective( 1, typeof( PrismaticAmber ), "Prismatic Amber" ) );
+
+ Rewards.Add( new DummyReward( 1075357 ) ); // The joy of contributing to a noble artistic effort, however paltry the end product.
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Emilio" ), new Point3D( 1447, 1664, 10 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Emilio" ), new Point3D( 1447, 1664, 10 ), Map.Felucca );
+ }
+ }
+
+ public class UnfadingMemoriesPartTwo : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( UnfadingMemoriesPartThree ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public UnfadingMemoriesPartTwo()
+ {
+ Activated = true;
+ Title = 1075367; // Unfading Memories
+ Description = 1075368; // Finished! With the pigment I was able to create from the Prismatic Amber you brought me, I was able to complete my humble work. I should explain. Once, I loved a noble lady of gentleness and refinement, who possessed such beauty that I have found myself unable to love another to this day. But it was from afar that I admired her, for it is not for one so lowly as I to pay court to the likes of her. You have heard of the fair Thalia, Lady of Nujel'm? No? Well, she was my Muse, my inspiration, and when I heard she was to be married, I lost whatever pitiful talent I possessed. I felt I must compose a portrait of her, my masterpiece, or I would never be able to paint again. You, my friend, have helped me complete my work. Now I ask another favor of you. Will you take it to her as a wedding gift? She will probably reject it, but I must make the offer.
+ RefusalMessage = 1075370; // Alright then, you have already helped me more than I deserved. I shall find someone else to undertake this task.
+ InProgressMessage = 1075371; // The wedding is taking place in the palace in Nujel'm. You will likely find her there.
+ CompletionMessage = 1075372; // I’m sorry, I’m getting ready to be married. I don’t have time to . . . what’s that you say?
+
+ Objectives.Add( new DeliverObjective( typeof( PortraitOfTheBride ), 1, "Portrait of the Bride", typeof( Thalia ), "Bride" ) );
+
+ Rewards.Add( new DummyReward( 1075369 ) ); // The Artist’s gratitude.
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+ }
+
+ public class UnfadingMemoriesPartThree : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public UnfadingMemoriesPartThree()
+ {
+ Activated = true;
+ Title = 1075373; // Unfading Memories
+ Description = 1075374; // Emilio painted this? It is absolutely wonderful! I used to love looking at his paintings, but I don’t remember him creating anything like this before. Would you be so kind as to carry a letter to him? Fate may have it that I am to marry another, yet I am compelled to reveal to him that his love was not entirely unrequited.
+ RefusalMessage = 1075376; // Very well, then. If you will excuse me, I need to get ready.
+ InProgressMessage = 1075377; // Take the letter back to the Artist’s Guild in Britain, if you would do me this kindness.
+ CompletionMessage = 1075378; // She said what? She thinks what of me? I . . . I can’t 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.
+
+ Objectives.Add( new DeliverObjective( typeof( BridesLetter ), 1, "Bride's Letter", typeof( Emilio ), "Artist" ) );
+
+ Rewards.Add( new ItemReward( 1075375, typeof( Bleach ) ) ); // Bleach
+ }
+
+ public override void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1046258, "", 0x23 ); // Your quest is complete.
+ }
+
+ public override void Generate()
+ {
+ base.Generate();
+
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Thalia" ), new Point3D( 3675, 1322, 20 ), Map.Trammel );
+ PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Thalia" ), new Point3D( 3675, 1322, 20 ), Map.Felucca );
+ }
+ }
+
+ #endregion
+
+ #region Mobiles
+
+ public class Emilio : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Emilio()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Emilio";
+ Title = "the Tortured Artist";
+ Race = Race.Human;
+ BodyValue = 0x190;
+ Female = false;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Sandals( 0x72B ) );
+ AddItem( new LongPants( 0x525 ) );
+ AddItem( new FancyShirt( 0x53F ) );
+ AddItem( new FloppyHat( 0x58C ) );
+ AddItem( new BodySash( 0x1C ) );
+
+ }
+
+ public Emilio( 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 class Thalia : BaseCreature
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ [Constructable]
+ public Thalia()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ Name = "Thalia";
+ Title = "the Bride";
+ Race = Race.Human;
+ BodyValue = 0x191;
+ Female = true;
+ Hue = Race.RandomSkinHue();
+ InitStats( 100, 100, 25 );
+
+ Utility.AssignRandomHair( this, true );
+
+ AddItem( new Backpack() );
+ AddItem( new Sandals( 0x8FD ) );
+ AddItem( new FancyDress( 0x8FD ) );
+
+ }
+
+ public Thalia( 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
+}
diff --git a/Scripts/Engines/MLQuests/Definitions/WarriorsOfTheGemKeeper.cs b/Scripts/Engines/MLQuests/Definitions/WarriorsOfTheGemKeeper.cs
new file mode 100644
index 000000000..2b9fb229f
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Definitions/WarriorsOfTheGemKeeper.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.ContextMenus;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Items;
+using Server.Misc;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Definitions
+{
+ public class WarriorsOfTheGemkeeper : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( CloseEnough ); } }
+
+ public WarriorsOfTheGemkeeper()
+ {
+ Activated = true;
+ Title = 1074536; // Warriors of the Gemkeeper
+ Description = 1074537; // Here we honor the Gemkeeper's Apprentice and seek to aid her efforts against the humans responsible for the death of her teacher - and the destruction of the elven way of life. Our tales speak of a fierce race of servants of the Gemkeeper, the men-bulls whose battle-skill was renowned. It is desireable to discover the fate of these noble creatures after the Rupture. Will you seek information?
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ InProgressMessage = 1074540; // I care not how you get the information. Kill as many humans as you must ... but find the fate of the minotaurs. Perhaps another of the Gemkeeper's servants has the knowledge we seek.
+ CompletionMessage = 1074542; // What have you found?
+
+ Objectives.Add( new CollectObjective( 1, typeof( FragmentOfAMap ), "fragment of a map" ) );
+
+ Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur.
+ }
+ }
+
+ public class CloseEnough : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( TakingTheBullByTheHorns ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public CloseEnough()
+ {
+ Activated = true;
+ Title = 1074544; // Close Enough
+ Description = 1074546; // Ah ha! You see here ... and over here ... The map fragment places the city of the bull-men, Labyrinth, on that piece of Sosaria that was thrown into the sky. Hmmm, I would have you go there and seek out these warriors to see if they might join our cause. But, legend speaks of a mighty barrier to prevent invasion of the city. Take this map to Canir and explain the problem. Perhaps she can devise a solution.
+ RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then.
+ 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)" ) );
+
+ Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur.
+ }
+ }
+
+ public class TakingTheBullByTheHorns : MLQuest
+ {
+ public override Type NextQuest { get { return typeof( EmissaryToTheMinotaur ); } }
+ public override bool IsChainTriggered { get { return true; } }
+
+ public TakingTheBullByTheHorns()
+ {
+ Activated = true;
+ Title = 1074551; // Taking the Bull by the Horns
+ Description = 1074553; // Interesting. I believe I have a way. I will need some materials to infuse you with the essence of a bull-man, so you can fool their defenses. The most similar beast to the original Baratarian bull that the minotaur were bred from is undoubtedly the mighty Gaman, native to the Lands of the Feudal Lords. I need horns, in great quantity to undertake this magic.
+ RefusalMessage = 1074554; // Oh come now, don't be afraid. The magic won't harm you.
+ InProgressMessage = 1074555; // I cannot grant you the ability to pass through the bull-men's defenses without the gaman horns.
+ CompletionMessage = 1074556; // You've returned at last! Give me just a moment to examine what you've brought and I can perform the magic that will allow you enter the Labyrinth.
+
+ Objectives.Add( new CollectObjective( 20, typeof( GamanHorns ), "gaman horns" ) );
+
+ Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur.
+ }
+ }
+
+ public class EmissaryToTheMinotaur : MLQuest
+ {
+ public override bool IsChainTriggered { get { return true; } }
+
+ public EmissaryToTheMinotaur()
+ {
+ Activated = true;
+ Title = 1074824; // Emissary to the Minotaur
+ Description = 1074825; // *whew* It is done! The fierce essence of the bull has been infused into your aura. You are able now to breach the ancient defenses of the city. Go forth and seek the minotaur -- and then return with wonderous tales and evidence of your visit to the Labyrinth.
+ RefusalMessage = 1074827; // As you wish. I can't understand why you'd pass up such a remarkable opportunity. Think of the adventures you would have.
+ InProgressMessage = 1074828; // You won't reach the minotaur city by loitering around here! What are you waiting for? You need to get to Malas and find the access point for the island. You'll be renowned for your discovery!
+ CompletionMessage = 1074829; // Oh! You've returned at last! I can't wait to hear the tales ... but first, let me see those artifacts. You've certainly earned this reward.
+
+ Objectives.Add( new CollectObjective( 3, typeof( MinotaurArtifact ), "minotaur artifacts" ) );
+
+ Rewards.Add( ItemReward.Strongbox );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Gumps/BaseQuestGump.cs b/Scripts/Engines/MLQuests/Gumps/BaseQuestGump.cs
new file mode 100644
index 000000000..026c09560
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Gumps/BaseQuestGump.cs
@@ -0,0 +1,293 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+
+namespace Server.Engines.MLQuests.Gumps
+{
+ public enum ButtonPosition : byte
+ {
+ Left,
+ Right
+ }
+
+ public enum ButtonGraphic : ushort
+ {
+ Invalid,
+ Accept = 0x2EE0,
+ Clear = 0x2EE3,
+ Close = 0x2EE6,
+ Continue = 0x2EE9,
+ Okay = 0x2EEC,
+ Previous = 0x2EEF,
+ Refuse = 0x2EF2,
+ Resign = 0x2EF5
+ }
+
+ public abstract class BaseQuestGump : Gump
+ {
+ private struct ButtonInfo
+ {
+ private ButtonPosition m_Position;
+ private ButtonGraphic m_Graphic;
+ private int m_ButtonID;
+
+ public ButtonPosition Position { get { return m_Position; } }
+ public ButtonGraphic Graphic { get { return m_Graphic; } }
+ public int ButtonID { get { return m_ButtonID; } }
+
+ public ButtonInfo( ButtonPosition position, ButtonGraphic graphic, int buttonID )
+ {
+ m_Position = position;
+ m_Graphic = graphic;
+ m_ButtonID = buttonID;
+ }
+ }
+
+ private int m_Page;
+ private int m_MaxPages;
+ private int m_Label;
+ private string m_Title;
+ private List m_Buttons;
+
+#if false
+ // OSI clone, inefficient layout
+ public BaseQuestGump( int label ) : base( 75, 25 )
+ {
+ m_Page = 0;
+ m_MaxPages = 0;
+ m_Label = label;
+ m_Title = null;
+ m_Buttons = new List( 2 );
+ }
+
+ public void BuildPage()
+ {
+ AddPage( ++m_Page );
+
+ Closable = false;
+ AddImageTiled( 50, 20, 400, 460, 0x1404 );
+ AddImageTiled( 50, 29, 30, 450, 0x28DC );
+ AddImageTiled( 34, 140, 17, 339, 0x242F );
+ AddImage( 48, 135, 0x28AB );
+ AddImage( -16, 285, 0x28A2 );
+ AddImage( 0, 10, 0x28B5 );
+ AddImage( 25, 0, 0x28B4 );
+ AddImageTiled( 83, 15, 350, 15, 0x280A );
+ AddImage( 34, 479, 0x2842 );
+ AddImage( 442, 479, 0x2840 );
+ AddImageTiled( 51, 479, 392, 17, 0x2775 );
+ AddImageTiled( 415, 29, 44, 450, 0xA2D );
+ AddImageTiled( 415, 29, 30, 450, 0x28DC );
+ AddLabel( 100, 50, 0x481, "" );
+ AddImage( 370, 50, 0x589 );
+ AddImage( 379, 60, 0x15A9 );
+ AddImage( 425, 0, 0x28C9 );
+ AddImage( 90, 33, 0x232D );
+ AddHtmlLocalized( 130, 45, 270, 16, m_Label, 0xFFFFFF, false, false );
+ AddImageTiled( 130, 65, 175, 1, 0x238D );
+
+ if ( m_Page > 1 )
+ AddButton( 130, 430, (int)ButtonGraphic.Previous, (int)ButtonGraphic.Previous + 2, 0, GumpButtonType.Page, m_Page - 1 );
+
+ if ( m_Page < m_MaxPages )
+ AddButton( 275, 430, (int)ButtonGraphic.Continue, (int)ButtonGraphic.Continue + 2, 0, GumpButtonType.Page, m_Page + 1 );
+
+ foreach ( ButtonInfo button in m_Buttons )
+ AddButton( button.Position == ButtonPosition.Left ? 95 : 313, 455, (int)button.Graphic, (int)button.Graphic + 2, button.ButtonID, GumpButtonType.Reply, 0 );
+
+ if ( m_Title != null )
+ AddHtmlLocalized( 130, 68, 220, 48, 1114513, m_Title, 0x2710, false, false ); // ~1_TOKEN~
+ }
+#else
+ // RunUO optimized version
+ public BaseQuestGump( int label )
+ : base( 75, 25 )
+ {
+ m_Page = 0;
+ m_MaxPages = 0;
+ m_Label = label;
+ m_Title = null;
+ m_Buttons = new List( 2 );
+
+ Closable = false;
+
+ AddPage( 0 );
+
+ AddImageTiled( 50, 20, 400, 460, 0x1404 );
+ AddImageTiled( 50, 29, 30, 450, 0x28DC );
+ AddImageTiled( 34, 140, 17, 339, 0x242F );
+ AddImage( 48, 135, 0x28AB );
+ AddImage( -16, 285, 0x28A2 );
+ AddImage( 0, 10, 0x28B5 );
+ AddImage( 25, 0, 0x28B4 );
+ AddImageTiled( 83, 15, 350, 15, 0x280A );
+ AddImage( 34, 479, 0x2842 );
+ AddImage( 442, 479, 0x2840 );
+ AddImageTiled( 51, 479, 392, 17, 0x2775 );
+ AddImageTiled( 415, 29, 44, 450, 0xA2D );
+ AddImageTiled( 415, 29, 30, 450, 0x28DC );
+ //AddLabel( 100, 50, 0x481, "" );
+ AddImage( 370, 50, 0x589 );
+ AddImage( 379, 60, 0x15A9 );
+ AddImage( 425, 0, 0x28C9 );
+ AddImage( 90, 33, 0x232D );
+ AddHtmlLocalized( 130, 45, 270, 16, label, 0xFFFFFF, false, false );
+ AddImageTiled( 130, 65, 175, 1, 0x238D );
+ }
+
+ public void BuildPage()
+ {
+ AddPage( ++m_Page );
+
+ if ( m_Page > 1 )
+ AddButton( 130, 430, (int)ButtonGraphic.Previous, (int)ButtonGraphic.Previous + 2, 0, GumpButtonType.Page, m_Page - 1 );
+
+ if ( m_Page < m_MaxPages )
+ AddButton( 275, 430, (int)ButtonGraphic.Continue, (int)ButtonGraphic.Continue + 2, 0, GumpButtonType.Page, m_Page + 1 );
+
+ foreach ( ButtonInfo button in m_Buttons )
+ AddButton( button.Position == ButtonPosition.Left ? 95 : 313, 455, (int)button.Graphic, (int)button.Graphic + 2, button.ButtonID, GumpButtonType.Reply, 0 );
+
+ if ( m_Title != null )
+ AddHtmlLocalized( 130, 68, 220, 48, 1114513, m_Title, 0x2710, false, false ); // ~1_TOKEN~
+ }
+#endif
+
+ public void SetPageCount( int maxPages )
+ {
+ m_MaxPages = maxPages;
+ }
+
+ public void SetTitle( TextDefinition def )
+ {
+ if ( def.Number > 0 )
+ m_Title = String.Format( "#{0}", def.Number ); // OSI does "@@#{0}" instead, why? KR client related?
+ else
+ m_Title = def.String;
+ }
+
+ public void RegisterButton( ButtonPosition position, ButtonGraphic graphic, int buttonID )
+ {
+ m_Buttons.Add( new ButtonInfo( position, graphic, buttonID ) );
+ }
+
+ #region Elaborate Formatting Shortcuts
+
+ public void AddDescription( MLQuest quest )
+ {
+ AddHtmlLocalized( 98, 140, 312, 16, ( quest.IsChainTriggered || quest.NextQuest != null ) ? 1075024 : 1072202, 0x2710, false, false ); // Description [(quest chain)]
+ TextDefinition.AddHtmlText( this, 98, 156, 312, 240, quest.Description, false, true, 0x15F90, 0xBDE784 );
+ }
+
+ public void AddObjectives( MLQuest quest )
+ {
+ AddHtmlLocalized( 98, 140, 312, 16, 1049073, 0x2710, false, false ); // Objective:
+ AddHtmlLocalized( 98, 156, 312, 16, ( quest.ObjectiveType == ObjectiveType.All ) ? 1072208 : 1072209, 0x2710, false, false ); // All of the following / Only one of the following
+
+ int y = 172;
+
+ foreach ( BaseObjective objective in quest.Objectives )
+ {
+ objective.WriteToGump( this, ref y );
+
+ if ( objective.IsTimed )
+ {
+ if ( objective is CollectObjective )
+ y -= 16;
+
+ BaseObjectiveInstance.WriteTimeRemaining( this, ref y, objective.Duration );
+ }
+ }
+ }
+
+ public void AddObjectivesProgress( MLQuestInstance instance )
+ {
+ MLQuest quest = instance.Quest;
+
+ AddHtmlLocalized( 98, 140, 312, 16, 1049073, 0x2710, false, false ); // Objective:
+ AddHtmlLocalized( 98, 156, 312, 16, ( quest.ObjectiveType == ObjectiveType.All ) ? 1072208 : 1072209, 0x2710, false, false ); // All of the following / Only one of the following
+
+ int y = 172;
+
+ foreach ( BaseObjectiveInstance objInstance in instance.Objectives )
+ objInstance.WriteToGump( this, ref y );
+ }
+
+ public void AddRewardsPage( MLQuest quest ) // For the quest log/offer gumps
+ {
+ AddHtmlLocalized( 98, 140, 312, 16, 1072201, 0x2710, false, false ); // Reward
+
+ int y = 162;
+
+ if ( quest.Rewards.Count > 1 )
+ {
+ // TODO: Is this what this is for? Does "Only one of the following" occur?
+ AddHtmlLocalized( 98, 156, 312, 16, 1072208, 0x2710, false, false ); // All of the following
+ y += 16;
+ }
+
+ AddRewards( quest, 105, y, 16 );
+ }
+
+ public void AddRewards( MLQuest quest ) // For the claim rewards gump
+ {
+ int y = 146;
+
+ if ( quest.Rewards.Count > 1 )
+ {
+ // TODO: Is this what this is for? Does "Only one of the following" occur?
+ AddHtmlLocalized( 100, 140, 312, 16, 1072208, 0x2710, false, false ); // All of the following
+ y += 16;
+ }
+
+ AddRewards( quest, 107, y, 26 );
+ }
+
+ public void AddRewards( MLQuest quest, int x, int y, int spacing )
+ {
+ int xReward = x + 28;
+
+ foreach ( BaseReward reward in quest.Rewards )
+ {
+ AddImage( x, y + 1, 0x4B9 );
+ reward.WriteToGump( this, xReward, ref y );
+ y += spacing;
+ }
+ }
+
+ public void AddConversation( TextDefinition text )
+ {
+ TextDefinition.AddHtmlText( this, 98, 140, 312, 180, text, false, true, 0x15F90, 0xBDE784 );
+ }
+
+ #endregion
+
+ /* OSI gump IDs:
+ * 800 - QuestOfferGump
+ * 801 - QuestCancelConfirmGump
+ * 802 - ?? (gets closed by Toggle Quest Item)
+ * 803 - QuestRewardGump
+ * 804 - ?? (gets closed by Toggle Quest Item)
+ * 805 - QuestLogGump
+ * 806 - QuestConversationGump (refuse / in progress)
+ * 807 - ?? (gets closed by Toggle Quest Item and most quest gumps)
+ * 808 - InfoNPCGump
+ * 809 - QuestLogDetailedGump
+ * 810 - QuestReportBackGump
+ */
+ public static void CloseOtherGumps( PlayerMobile pm )
+ {
+ pm.CloseGump( typeof( InfoNPCGump ) );
+ pm.CloseGump( typeof( QuestRewardGump ) );
+ pm.CloseGump( typeof( QuestConversationGump ) );
+ pm.CloseGump( typeof( QuestReportBackGump ) );
+ //pm.CloseGump( typeof( UnknownGump807 ) );
+ pm.CloseGump( typeof( QuestCancelConfirmGump ) );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Gumps/InfoNPCGump.cs b/Scripts/Engines/MLQuests/Gumps/InfoNPCGump.cs
new file mode 100644
index 000000000..f672fe199
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Gumps/InfoNPCGump.cs
@@ -0,0 +1,22 @@
+using System;
+using Server;
+using Server.Gumps;
+using Server.Network;
+
+namespace Server.Engines.MLQuests.Gumps
+{
+ public class InfoNPCGump : BaseQuestGump
+ {
+ public InfoNPCGump( TextDefinition title, TextDefinition message )
+ : base( 1060668 ) // INFORMATION
+ {
+ RegisterButton( ButtonPosition.Left, ButtonGraphic.Close, 3 );
+
+ SetPageCount( 1 );
+
+ BuildPage();
+ TextDefinition.AddHtmlText( this, 160, 108, 250, 16, title, false, false, 0x2710, 0x4AC684 );
+ TextDefinition.AddHtmlText( this, 98, 156, 312, 180, message, false, true, 0x15F90, 0xBDE784 );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Gumps/QuestCancelConfirmGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestCancelConfirmGump.cs
new file mode 100644
index 000000000..d14413f4a
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Gumps/QuestCancelConfirmGump.cs
@@ -0,0 +1,105 @@
+using System;
+using Server;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Engines.MLQuests.Gumps
+{
+ public class QuestCancelConfirmGump : Gump
+ {
+ private MLQuestInstance m_Instance;
+ private bool m_CloseGumps;
+
+ public QuestCancelConfirmGump( MLQuestInstance instance )
+ : this( instance, true )
+ {
+ }
+
+ public QuestCancelConfirmGump( MLQuestInstance instance, bool closeGumps )
+ : base( 120, 50 )
+ {
+ m_Instance = instance;
+ m_CloseGumps = closeGumps;
+
+ if ( closeGumps )
+ BaseQuestGump.CloseOtherGumps( instance.Player );
+
+ AddPage( 0 );
+
+ Closable = false;
+
+ AddImageTiled( 0, 0, 348, 262, 0xA8E );
+ AddAlphaRegion( 0, 0, 348, 262 );
+
+ AddImage( 0, 15, 0x27A8 );
+ AddImageTiled( 0, 30, 17, 200, 0x27A7 );
+ AddImage( 0, 230, 0x27AA );
+
+ AddImage( 15, 0, 0x280C );
+ AddImageTiled( 30, 0, 300, 17, 0x280A );
+ AddImage( 315, 0, 0x280E );
+
+ AddImage( 15, 244, 0x280C );
+ AddImageTiled( 30, 244, 300, 17, 0x280A );
+ AddImage( 315, 244, 0x280E );
+
+ AddImage( 330, 15, 0x27A8 );
+ AddImageTiled( 330, 30, 17, 200, 0x27A7 );
+ AddImage( 330, 230, 0x27AA );
+
+ AddImage( 333, 2, 0x2716 );
+ AddImage( 333, 248, 0x2716 );
+ AddImage( 2, 248, 0x2716 );
+ AddImage( 2, 2, 0x2716 );
+
+ AddHtmlLocalized( 25, 22, 200, 20, 1049000, 0x7D00, false, false ); // Confirm Quest Cancellation
+ AddImage( 25, 40, 0xBBF );
+
+ /*
+ * This quest will give you valuable information, skills
+ * and equipment that will help you advance in the
+ * game at a quicker pace.
+ *
+ * Are you certain you wish to cancel at this time?
+ */
+ AddHtmlLocalized( 25, 55, 300, 120, 1060836, 0xFFFFFF, false, false );
+
+ MLQuest quest = instance.Quest;
+
+ if ( quest.IsChainTriggered || quest.NextQuest != null )
+ {
+ AddRadio( 25, 145, 0x25F8, 0x25FB, false, 2 );
+ AddHtmlLocalized( 60, 150, 280, 20, 1075023, 0xFFFFFF, false, false ); // Yes, I want to quit this entire chain!
+ }
+
+ AddRadio( 25, 180, 0x25F8, 0x25FB, true, 1 );
+ AddHtmlLocalized( 60, 185, 280, 20, 1049005, 0xFFFFFF, false, false ); // Yes, I really want to quit this quest!
+
+ AddRadio( 25, 215, 0x25F8, 0x25FB, false, 0 );
+ AddHtmlLocalized( 60, 220, 280, 20, 1049006, 0xFFFFFF, false, false ); // No, I don't want to quit.
+
+ AddButton( 265, 220, 0xF7, 0xF8, 7, GumpButtonType.Reply, 0 );
+ }
+
+ public override void OnResponse( NetState sender, RelayInfo info )
+ {
+ if ( m_Instance.Removed )
+ return;
+
+ switch ( info.ButtonID )
+ {
+ case 7: // Okay
+ {
+ if ( info.IsSwitched( 2 ) )
+ m_Instance.Cancel( true );
+ else if ( info.IsSwitched( 1 ) )
+ m_Instance.Cancel( false );
+
+ sender.Mobile.SendGump( new QuestLogGump( m_Instance.Player, m_CloseGumps ) );
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Gumps/QuestConversationGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestConversationGump.cs
new file mode 100644
index 000000000..a0cfd65b6
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Gumps/QuestConversationGump.cs
@@ -0,0 +1,25 @@
+using System;
+using Server;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Engines.MLQuests.Gumps
+{
+ public class QuestConversationGump : BaseQuestGump
+ {
+ public QuestConversationGump( MLQuest quest, PlayerMobile pm, TextDefinition text )
+ : base( 3006156 ) // Quest Conversation
+ {
+ CloseOtherGumps( pm );
+
+ SetTitle( quest.Title );
+ RegisterButton( ButtonPosition.Right, ButtonGraphic.Close, 3 );
+
+ SetPageCount( 1 );
+
+ BuildPage();
+ AddConversation( text );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Gumps/QuestLogDetailedGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestLogDetailedGump.cs
new file mode 100644
index 000000000..1ee68df1d
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Gumps/QuestLogDetailedGump.cs
@@ -0,0 +1,81 @@
+using System;
+using Server;
+using Server.Engines.MLQuests;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Engines.MLQuests.Gumps
+{
+ public class QuestLogDetailedGump : BaseQuestGump
+ {
+ private MLQuestInstance m_Instance;
+ private bool m_CloseGumps;
+
+ public QuestLogDetailedGump( MLQuestInstance instance )
+ : this( instance, true )
+ {
+ }
+
+ public QuestLogDetailedGump( MLQuestInstance instance, bool closeGumps )
+ : base( 1046026 ) // Quest Log
+ {
+ m_Instance = instance;
+ m_CloseGumps = closeGumps;
+
+ PlayerMobile pm = instance.Player;
+ MLQuest quest = instance.Quest;
+
+ if ( closeGumps )
+ {
+ CloseOtherGumps( pm );
+ pm.CloseGump( typeof( QuestLogDetailedGump ) );
+ }
+
+ SetTitle( quest.Title );
+ RegisterButton( ButtonPosition.Left, ButtonGraphic.Resign, 1 );
+ RegisterButton( ButtonPosition.Right, ButtonGraphic.Okay, 2 );
+
+ SetPageCount( 3 );
+
+ BuildPage();
+ AddDescription( quest );
+
+ if ( instance.Failed ) // only displayed on the first page
+ AddHtmlLocalized( 160, 80, 250, 16, 500039, 0x3C00, false, false ); // Failed!
+
+ BuildPage();
+ AddObjectivesProgress( instance );
+
+ BuildPage();
+ AddRewardsPage( quest );
+ }
+
+ public override void OnResponse( NetState sender, RelayInfo info )
+ {
+ if ( m_Instance.Removed )
+ return;
+
+ switch ( info.ButtonID )
+ {
+ case 1: // Resign
+ {
+ // TODO: Custom reward loss protection? OSI doesn't have this
+ //if ( m_Instance.ClaimReward )
+ // pm.SendMessage( "You cannot cancel a quest with rewards pending." );
+ //else
+
+ sender.Mobile.SendGump( new QuestCancelConfirmGump( m_Instance, m_CloseGumps ) );
+
+ break;
+ }
+ case 2: // Okay
+ {
+ sender.Mobile.SendGump( new QuestLogGump( m_Instance.Player, m_CloseGumps ) );
+
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Gumps/QuestLogGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestLogGump.cs
new file mode 100644
index 000000000..96e794da7
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Gumps/QuestLogGump.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Engines.MLQuests.Gumps
+{
+ public class QuestLogGump : BaseQuestGump
+ {
+ private PlayerMobile m_Owner;
+ private bool m_CloseGumps;
+
+ public QuestLogGump( PlayerMobile pm )
+ : this( pm, true )
+ {
+ }
+
+ public QuestLogGump( PlayerMobile pm, bool closeGumps )
+ : base( 1046026 ) // Quest Log
+ {
+ m_Owner = pm;
+ m_CloseGumps = closeGumps;
+
+ if ( closeGumps )
+ {
+ pm.CloseGump( typeof( QuestLogGump ) );
+ pm.CloseGump( typeof( QuestLogDetailedGump ) );
+ }
+
+ RegisterButton( ButtonPosition.Right, ButtonGraphic.Okay, 3 );
+
+ SetPageCount( 1 );
+
+ BuildPage();
+
+ int numberColor, stringColor;
+
+ MLQuestContext context = MLQuestSystem.GetContext( pm );
+
+ if ( context != null )
+ {
+ List instances = context.QuestInstances;
+
+ for ( int i = 0; i < instances.Count; ++i )
+ {
+ if ( instances[i].Failed )
+ {
+ numberColor = 0x3C00;
+ stringColor = 0x7B0000;
+ }
+ else
+ {
+ numberColor = stringColor = 0xFFFFFF;
+ }
+
+ TextDefinition.AddHtmlText( this, 98, 140 + 21 * i, 270, 21, instances[i].Quest.Title, false, false, numberColor, stringColor );
+ AddButton( 368, 140 + 21 * i, 0x26B0, 0x26B1, 6 + i, GumpButtonType.Reply, 1 );
+ }
+ }
+ }
+
+ public override void OnResponse( NetState sender, RelayInfo info )
+ {
+ if ( info.ButtonID < 6 )
+ return;
+
+ MLQuestContext context = MLQuestSystem.GetContext( m_Owner );
+
+ if ( context == null )
+ return;
+
+ List instances = context.QuestInstances;
+ int index = info.ButtonID - 6;
+
+ if ( index >= instances.Count )
+ return;
+
+ sender.Mobile.SendGump( new QuestLogDetailedGump( instances[index], m_CloseGumps ) );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Gumps/QuestOfferGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestOfferGump.cs
new file mode 100644
index 000000000..0f256d93c
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Gumps/QuestOfferGump.cs
@@ -0,0 +1,62 @@
+using System;
+using Server;
+using Server.Engines.MLQuests;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Engines.MLQuests.Gumps
+{
+ public class QuestOfferGump : BaseQuestGump
+ {
+ private MLQuest m_Quest;
+ private BaseCreature m_Quester;
+
+ public QuestOfferGump( MLQuest quest, BaseCreature quester, PlayerMobile pm )
+ : base( 1049010 ) // Quest Offer
+ {
+ m_Quest = quest;
+ m_Quester = quester;
+
+ CloseOtherGumps( pm );
+ pm.CloseGump( typeof( QuestOfferGump ) );
+
+ SetTitle( quest.Title );
+ RegisterButton( ButtonPosition.Left, ButtonGraphic.Accept, 1 );
+ RegisterButton( ButtonPosition.Right, ButtonGraphic.Refuse, 2 );
+
+ SetPageCount( 3 );
+
+ BuildPage();
+ AddDescription( quest );
+
+ BuildPage();
+ AddObjectives( quest );
+
+ BuildPage();
+ AddRewardsPage( quest );
+ }
+
+ public override void OnResponse( NetState sender, RelayInfo info )
+ {
+ PlayerMobile pm = sender.Mobile as PlayerMobile;
+
+ if ( pm == null )
+ return;
+
+ switch ( info.ButtonID )
+ {
+ case 1: // Accept
+ {
+ m_Quest.OnAccept( m_Quester, pm );
+ break;
+ }
+ case 2: // Refuse
+ {
+ m_Quest.OnRefuse( m_Quester, pm );
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Gumps/QuestReportBackGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestReportBackGump.cs
new file mode 100644
index 000000000..af75d66a6
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Gumps/QuestReportBackGump.cs
@@ -0,0 +1,40 @@
+using System;
+using Server;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Engines.MLQuests.Gumps
+{
+ public class QuestReportBackGump : BaseQuestGump
+ {
+ private MLQuestInstance m_Instance;
+
+ public QuestReportBackGump( MLQuestInstance instance )
+ : base( 3006156 ) // Quest Conversation
+ {
+ m_Instance = instance;
+
+ MLQuest quest = instance.Quest;
+ PlayerMobile pm = instance.Player;
+
+ // TODO: Check close sequence
+ CloseOtherGumps( pm );
+
+ SetTitle( quest.Title );
+ RegisterButton( ButtonPosition.Left, ButtonGraphic.Continue, 4 );
+ RegisterButton( ButtonPosition.Right, ButtonGraphic.Close, 3 );
+
+ SetPageCount( 1 );
+
+ BuildPage();
+ AddConversation( quest.CompletionMessage );
+ }
+
+ public override void OnResponse( NetState sender, RelayInfo info )
+ {
+ if ( info.ButtonID == 4 )
+ m_Instance.ContinueReportBack();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Gumps/QuestRewardGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestRewardGump.cs
new file mode 100644
index 000000000..529bd7253
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Gumps/QuestRewardGump.cs
@@ -0,0 +1,38 @@
+using System;
+using Server;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Engines.MLQuests.Gumps
+{
+ public class QuestRewardGump : BaseQuestGump
+ {
+ private MLQuestInstance m_Instance;
+
+ public QuestRewardGump( MLQuestInstance instance )
+ : base( 1072201 ) // Reward
+ {
+ m_Instance = instance;
+
+ MLQuest quest = instance.Quest;
+ PlayerMobile pm = instance.Player;
+
+ CloseOtherGumps( pm );
+
+ SetTitle( quest.Title );
+ RegisterButton( ButtonPosition.Left, ButtonGraphic.Accept, 1 );
+
+ SetPageCount( 1 );
+
+ BuildPage();
+ AddRewards( quest );
+ }
+
+ public override void OnResponse( NetState sender, RelayInfo info )
+ {
+ if ( info.ButtonID == 1 )
+ m_Instance.ClaimRewards();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs b/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs
new file mode 100644
index 000000000..a7e79d188
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs
@@ -0,0 +1,356 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.Engines.MLQuests.Mobiles;
+using Server.Gumps;
+using Server.Items;
+using Server.Mobiles;
+using Server.Network;
+using Server.Spells.Fifth;
+using Server.Spells.Ninjitsu;
+using Server.Spells.Seventh;
+
+namespace Server.Engines.MLQuests.Gumps
+{
+ public interface IRaceChanger
+ {
+ bool CheckComplete( PlayerMobile from );
+ void ConsumeNeeded( PlayerMobile from );
+ void OnCancel( PlayerMobile from );
+ }
+
+ public class RaceChangeConfirmGump : Gump
+ {
+ public static readonly Type Type = typeof( RaceChangeConfirmGump );
+
+ private IRaceChanger m_Owner;
+ private PlayerMobile m_From;
+ private Race m_Race;
+
+ public RaceChangeConfirmGump( IRaceChanger owner, PlayerMobile from, Race targetRace )
+ : base( 50, 50 )
+ {
+ from.CloseGump( Type );
+
+ m_Owner = owner;
+ m_From = from;
+ m_Race = targetRace;
+
+ AddPage( 0 );
+ AddBackground( 0, 0, 240, 135, 0x2422 );
+
+ if ( targetRace == Race.Human )
+ AddHtmlLocalized( 15, 15, 210, 75, 1073643, 0, false, false ); // Are you sure you wish to embrace your humanity?
+ else if ( targetRace == Race.Elf )
+ AddHtmlLocalized( 15, 15, 210, 75, 1073642, 0, false, false ); // Are you sure you want to follow the elven ways?
+ else
+ AddHtml( 15, 15, 210, 75, String.Format( "Are you sure you want to change your race to {0}?", targetRace.Name ), false, false );
+
+ AddButton( 160, 95, 0xF7, 0xF8, 1, GumpButtonType.Reply, 0 );
+ AddButton( 90, 95, 0xF2, 0xF1, 0, GumpButtonType.Reply, 0 );
+ }
+
+ public override void OnResponse( NetState sender, RelayInfo info )
+ {
+ switch ( info.ButtonID )
+ {
+ case 0: // Cancel
+ {
+ if ( m_Owner != null )
+ m_Owner.OnCancel( m_From );
+
+ break;
+ }
+ case 1: // Okay
+ {
+ if ( m_Owner == null || m_Owner.CheckComplete( m_From ) )
+ Offer( m_Owner, m_From, m_Race );
+
+ break;
+ }
+ }
+ }
+
+ private class RaceChangeState
+ {
+ private static readonly TimeSpan m_TimeoutDelay = TimeSpan.FromMinutes( 1 );
+ private static readonly TimerStateCallback m_TimeoutCallback = new TimerStateCallback( Timeout );
+
+ public IRaceChanger m_Owner;
+ public Race m_TargetRace;
+ public Timer m_Timeout;
+
+ public RaceChangeState( IRaceChanger owner, NetState ns, Race targetRace )
+ {
+ m_Owner = owner;
+ m_TargetRace = targetRace;
+ m_Timeout = Timer.DelayCall( m_TimeoutDelay, m_TimeoutCallback, ns );
+ }
+ }
+
+ private static Dictionary m_Pending;
+
+ public static void Initialize()
+ {
+ m_Pending = new Dictionary();
+
+ PacketHandlers.RegisterExtended( 0x2A, true, new OnPacketReceive( RaceChangeReply ) );
+ }
+
+ public static bool IsPending( NetState state )
+ {
+ return ( state != null && m_Pending.ContainsKey( state ) );
+ }
+
+ private static void Offer( IRaceChanger owner, PlayerMobile from, Race targetRace )
+ {
+ NetState ns = from.NetState;
+
+ if ( ns == null || !CanChange( from, targetRace ) )
+ return;
+
+ CloseCurrent( ns );
+
+ m_Pending[ns] = new RaceChangeState( owner, ns, targetRace );
+ ns.Send( new RaceChanger( from.Female, targetRace ) );
+ }
+
+ private static void CloseCurrent( NetState ns )
+ {
+ RaceChangeState state;
+
+ if ( m_Pending.TryGetValue( ns, out state ) )
+ {
+ state.m_Timeout.Stop();
+ m_Pending.Remove( ns );
+ }
+
+ ns.Send( CloseRaceChanger.Instance );
+ }
+
+ private static void Timeout( NetState ns )
+ {
+ if ( m_Pending.ContainsKey( ns ) )
+ {
+ m_Pending.Remove( ns );
+ ns.Send( CloseRaceChanger.Instance );
+ }
+ }
+
+ public static bool IsWearingEquipment( Mobile from )
+ {
+ foreach ( Item item in from.Items )
+ {
+ switch ( item.Layer )
+ {
+ case Layer.Hair:
+ case Layer.FacialHair:
+ case Layer.Backpack:
+ case Layer.Mount:
+ case Layer.Bank:
+ {
+ continue; // ignore
+ }
+ default:
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static bool CanChange( PlayerMobile from, Race targetRace )
+ {
+ if ( from.Deleted )
+ return false;
+
+ if ( from.Race == targetRace )
+ from.SendLocalizedMessage( 1111918 ); // You are already that race.
+ else if ( !MondainsLegacy.CheckML( from, false ) )
+ from.SendLocalizedMessage( 1073651 ); // You must have Mondain's Legacy before proceeding...
+ else if ( !from.Alive )
+ from.SendLocalizedMessage( 1073646 ); // Only the living may proceed...
+ else if ( from.Mounted )
+ from.SendLocalizedMessage( 1073647 ); // You may not continue while mounted...
+ else if ( !from.CanBeginAction( typeof( PolymorphSpell ) ) || DisguiseTimers.IsDisguised( from ) || AnimalForm.UnderTransformation( from ) || !from.CanBeginAction( typeof( IncognitoSpell ) ) || from.IsBodyMod ) // TODO: Does this cover everything?
+ from.SendLocalizedMessage( 1073648 ); // You may only proceed while in your original state...
+ else if ( from.Spell != null && from.Spell.IsCasting )
+ from.SendLocalizedMessage( 1073649 ); // One may not proceed while embracing magic...
+ else if ( from.Poisoned )
+ from.SendLocalizedMessage( 1073652 ); // You must be healthy to proceed...
+ else if ( IsWearingEquipment( from ) )
+ from.SendLocalizedMessage( 1073650 ); // To proceed you must be unburdened by equipment...
+ else
+ return true;
+
+ return false;
+ }
+
+ private static void RaceChangeReply( NetState state, PacketReader pvSrc )
+ {
+ RaceChangeState raceChangeState;
+
+ if ( !m_Pending.TryGetValue( state, out raceChangeState ) )
+ return;
+
+ CloseCurrent( state );
+
+ PlayerMobile pm = state.Mobile as PlayerMobile;
+
+ if ( pm == null )
+ return;
+
+ IRaceChanger owner = raceChangeState.m_Owner;
+ Race targetRace = raceChangeState.m_TargetRace;
+
+ if ( pvSrc.Size == 5 )
+ {
+ if ( owner != null )
+ owner.OnCancel( pm );
+
+ return;
+ }
+
+ if ( !CanChange( pm, targetRace ) || ( owner != null && !owner.CheckComplete( pm ) ) )
+ return;
+
+ int hue = pvSrc.ReadUInt16();
+ int hairItemId = pvSrc.ReadUInt16();
+ int hairHue = pvSrc.ReadUInt16();
+ int facialHairItemId = pvSrc.ReadUInt16();
+ int facialHairHue = pvSrc.ReadUInt16();
+
+ pm.Race = targetRace;
+ pm.Hue = targetRace.ClipSkinHue( hue ) | 0x8000;
+
+ if ( targetRace.ValidateHair( pm, hairItemId ) )
+ {
+ pm.HairItemID = hairItemId;
+ pm.HairHue = targetRace.ClipHairHue( hairHue );
+ }
+ else
+ {
+ pm.HairItemID = 0;
+ }
+
+ if ( targetRace.ValidateFacialHair( pm, facialHairItemId ) )
+ {
+ pm.FacialHairItemID = facialHairItemId;
+ pm.FacialHairHue = targetRace.ClipHairHue( facialHairHue );
+ }
+ else
+ {
+ pm.FacialHairItemID = 0;
+ }
+
+ if ( targetRace == Race.Human )
+ pm.SendLocalizedMessage( 1073654 ); // You are now fully human.
+ else if ( targetRace == Race.Elf )
+ pm.SendLocalizedMessage( 1073653 ); // You are now fully initiated into the Elven culture.
+ else
+ pm.SendMessage( "You have fully changed your race to {0}.", targetRace.Name );
+
+ if ( owner != null )
+ owner.ConsumeNeeded( pm );
+ }
+ }
+
+ public sealed class RaceChanger : Packet
+ {
+ public RaceChanger( bool female, Race targetRace )
+ : base( 0xBF )
+ {
+ EnsureCapacity( 7 );
+
+ m_Stream.Write( (short)0x2A );
+ m_Stream.Write( (byte)( female ? 1 : 0 ) );
+ m_Stream.Write( (byte)( targetRace.RaceID + 1 ) );
+ }
+ }
+
+ public sealed class CloseRaceChanger : Packet
+ {
+ public static readonly Packet Instance = Packet.SetStatic( new CloseRaceChanger() );
+
+ private CloseRaceChanger()
+ : base( 0xBF )
+ {
+ EnsureCapacity( 7 );
+
+ m_Stream.Write( (short)0x2A );
+ m_Stream.Write( (byte)0 );
+ m_Stream.Write( (byte)0xFF );
+ }
+ }
+
+ #region For testing
+
+ public class RaceChangeDeed : Item, IRaceChanger
+ {
+ public override string DefaultName { get { return "a race change deed"; } }
+
+ [Constructable]
+ public RaceChangeDeed()
+ : base( 0x14F0 )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public bool CheckComplete( PlayerMobile pm )
+ {
+ if ( Deleted )
+ return false;
+
+ if ( !IsChildOf( pm.Backpack ) )
+ {
+ pm.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it.
+ return false;
+ }
+
+ return true;
+ }
+
+ public void ConsumeNeeded( PlayerMobile pm )
+ {
+ Consume();
+ }
+
+ public void OnCancel( PlayerMobile pm )
+ {
+ }
+
+ public override void OnDoubleClick( Mobile from )
+ {
+ PlayerMobile pm = from as PlayerMobile;
+
+ if ( pm == null )
+ return;
+
+ if ( CheckComplete( pm ) )
+ pm.SendGump( new RaceChangeConfirmGump( this, pm, ( pm.Race == Race.Human ) ? Race.Elf : Race.Human ) );
+ }
+
+ public RaceChangeDeed( 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
+}
diff --git a/Scripts/Engines/MLQuests/Items/ABauble.cs b/Scripts/Engines/MLQuests/Items/ABauble.cs
new file mode 100644
index 000000000..dbe344d99
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/ABauble.cs
@@ -0,0 +1,34 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class ABauble : Item
+ {
+ public override int LabelNumber{ get{ return 1073137; } } // A bauble
+
+ [Constructable]
+ public ABauble() : base( 0x23B )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public ABauble( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/APersonalLetterAddressedToAhie.cs b/Scripts/Engines/MLQuests/Items/APersonalLetterAddressedToAhie.cs
new file mode 100644
index 000000000..5b14c73b4
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/APersonalLetterAddressedToAhie.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class APersonalLetterAddressedToAhie : TransientItem
+ {
+ public override int LabelNumber{ get{ return 1073128; } } // A personal letter addressed to: Ahie
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public APersonalLetterAddressedToAhie() : base( 0x14ED, TimeSpan.FromMinutes( 30 ) )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public APersonalLetterAddressedToAhie( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/AlchemistsBandage.cs b/Scripts/Engines/MLQuests/Items/AlchemistsBandage.cs
new file mode 100644
index 000000000..82bf7813f
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/AlchemistsBandage.cs
@@ -0,0 +1,43 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class AlchemistsBandage : Item
+ {
+ public override int LabelNumber{ get{ return 1075452; } } // Alchemist's Bandage
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public AlchemistsBandage() : base( 0xE21 )
+ {
+ LootType = LootType.Blessed;
+ Hue = 0x482;
+ }
+
+ public AlchemistsBandage( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/AnOldNecklace.cs b/Scripts/Engines/MLQuests/Items/AnOldNecklace.cs
new file mode 100644
index 000000000..7a05ba19f
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/AnOldNecklace.cs
@@ -0,0 +1,34 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class AnOldNecklace : Necklace
+ {
+ public override int LabelNumber{ get{ return 1075525; } } // an old necklace
+
+ [Constructable]
+ public AnOldNecklace() : base()
+ {
+ Hue = 0x222;
+ }
+
+ public AnOldNecklace( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/AnOldRing.cs b/Scripts/Engines/MLQuests/Items/AnOldRing.cs
new file mode 100644
index 000000000..122c1284e
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/AnOldRing.cs
@@ -0,0 +1,34 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class AnOldRing : GoldRing
+ {
+ public override int LabelNumber{ get{ return 1075524; } } // an old ring
+
+ [Constructable]
+ public AnOldRing() : base()
+ {
+ Hue = 0x222;
+ }
+
+ public AnOldRing( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/AndricSatchel.cs b/Scripts/Engines/MLQuests/Items/AndricSatchel.cs
new file mode 100644
index 000000000..ab42353c0
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/AndricSatchel.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class AndricSatchel : Backpack
+ {
+ [Constructable]
+ public AndricSatchel()
+ {
+ Hue = Utility.RandomBrightHue();
+ DropItem( new Feather( 10 ) );
+ DropItem( new FletcherTools() );
+ }
+
+ public AndricSatchel( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/AndrosGratitude.cs b/Scripts/Engines/MLQuests/Items/AndrosGratitude.cs
new file mode 100644
index 000000000..95b58caaf
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/AndrosGratitude.cs
@@ -0,0 +1,34 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class AndrosGratitude : SmithHammer
+ {
+ public override int LabelNumber{ get{ return 1075345; } } // Andros Gratitude
+
+ [Constructable]
+ public AndrosGratitude() : base( 10 )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public AndrosGratitude( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/AsandosSatchel.cs b/Scripts/Engines/MLQuests/Items/AsandosSatchel.cs
new file mode 100644
index 000000000..5d71df62c
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/AsandosSatchel.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class AsandosSatchel : Backpack
+ {
+ [Constructable]
+ public AsandosSatchel()
+ {
+ Hue = Utility.RandomBrightHue();
+ DropItem( new SackFlour() );
+ DropItem( new Skillet() );
+ }
+
+ public AsandosSatchel( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/BasinOfCrystalClearWater.cs b/Scripts/Engines/MLQuests/Items/BasinOfCrystalClearWater.cs
new file mode 100644
index 000000000..c646e6ccd
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/BasinOfCrystalClearWater.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class BasinOfCrystalClearWater : Item
+ {
+ public override int LabelNumber{ get{ return 1075303; } } // Basin of Crystal-Clear Water
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public BasinOfCrystalClearWater() : base( 0x1008 )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public BasinOfCrystalClearWater( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/Bleach.cs b/Scripts/Engines/MLQuests/Items/Bleach.cs
new file mode 100644
index 000000000..0cff9a870
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/Bleach.cs
@@ -0,0 +1,34 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class Bleach : PigmentsOfTokuno
+ {
+ public override int LabelNumber { get { return 1075375; } } // Bleach
+
+ [Constructable]
+ public Bleach() : base( PigmentType.None )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public Bleach( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/BridesLetter.cs b/Scripts/Engines/MLQuests/Items/BridesLetter.cs
new file mode 100644
index 000000000..545e06c3f
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/BridesLetter.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class BridesLetter : Item
+ {
+ public override int LabelNumber{ get{ return 1075301; } } // Bride's Letter
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public BridesLetter() : base( 0x14ED )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public BridesLetter( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/CompletedTuitionReimbursementForm.cs b/Scripts/Engines/MLQuests/Items/CompletedTuitionReimbursementForm.cs
new file mode 100644
index 000000000..14cfcfb60
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/CompletedTuitionReimbursementForm.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class CompletedTuitionReimbursementForm : Item
+ {
+ public override int LabelNumber{ get{ return 1074625; } } // Completed Tuition Reimbursement Form
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public CompletedTuitionReimbursementForm() : base( 0x14F0 )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public CompletedTuitionReimbursementForm( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/CraftmansSatchel.cs b/Scripts/Engines/MLQuests/Items/CraftmansSatchel.cs
new file mode 100644
index 000000000..f7d9b125b
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/CraftmansSatchel.cs
@@ -0,0 +1,229 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server;
+using Server.Engines.Craft;
+using Server.Items;
+
+namespace Server.Engines.MLQuests.Items
+{
+ public abstract class BaseCraftmansSatchel : Backpack
+ {
+ protected static readonly Type[] m_TalismanType = new Type[] { typeof( RandomTalisman ) };
+
+ public BaseCraftmansSatchel()
+ {
+ Hue = Utility.RandomBrightHue();
+ }
+
+ protected void AddBaseLoot( params Type[][] lootSets )
+ {
+ Item loot = Loot.Construct( lootSets[Utility.Random( lootSets.Length )] );
+
+ if ( loot == null )
+ return;
+
+ RewardBag.Enhance( loot );
+ DropItem( loot );
+ }
+
+ protected void AddRecipe( CraftSystem system )
+ {
+ // TODO: change craftable artifact recipes to a rarer drop
+ int recipeID = system.RandomRecipe();
+
+ if ( recipeID != -1 )
+ DropItem( new RecipeScroll( recipeID ) );
+ }
+
+ public BaseCraftmansSatchel( 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 class TailorSatchel : BaseCraftmansSatchel
+ {
+ [Constructable]
+ public TailorSatchel()
+ {
+ AddBaseLoot( Loot.MLArmorTypes, Loot.JewelryTypes, m_TalismanType );
+
+ if ( Utility.RandomDouble() < 0.50 )
+ AddRecipe( DefTailoring.CraftSystem );
+ }
+
+ public TailorSatchel( 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 class BlacksmithSatchel : BaseCraftmansSatchel
+ {
+ [Constructable]
+ public BlacksmithSatchel()
+ {
+ AddBaseLoot( Loot.MLWeaponTypes, Loot.JewelryTypes, m_TalismanType );
+
+ if ( Utility.RandomDouble() < 0.50 )
+ AddRecipe( DefBlacksmithy.CraftSystem );
+ }
+
+ public BlacksmithSatchel( 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 class TinkerSatchel : BaseCraftmansSatchel
+ {
+ [Constructable]
+ public TinkerSatchel()
+ {
+ AddBaseLoot( Loot.MLArmorTypes, Loot.MLWeaponTypes, Loot.MLRangedWeaponTypes, Loot.JewelryTypes, m_TalismanType );
+
+ if ( Utility.RandomDouble() < 0.50 )
+ {
+ // TODO: Add recipe drops (drops include inscription, alchemy and drops from non-artifact recipes for tailoring, blacksmith, carpentry and fletching.
+ switch ( Utility.Random( 6 ) )
+ {
+ case 0: AddRecipe( DefInscription.CraftSystem ); break;
+ case 1: AddRecipe( DefAlchemy.CraftSystem ); break;
+ // TODO
+ //case 2: AddNonArtifactRecipe( DefTailoring.CraftSystem ); break;
+ //case 3: AddNonArtifactRecipe( DefBlacksmithy.CraftSystem ); break;
+ //case 4: AddNonArtifactRecipe( DefCarpentry.CraftSystem ); break;
+ //case 5: AddNonArtifactRecipe( DefBowFletching.CraftSystem ); break;
+ }
+ }
+ }
+
+ public TinkerSatchel( 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 class FletchingSatchel : BaseCraftmansSatchel
+ {
+ [Constructable]
+ public FletchingSatchel()
+ {
+ AddBaseLoot( Loot.MLRangedWeaponTypes, Loot.JewelryTypes, m_TalismanType );
+
+ if ( Utility.RandomDouble() < 0.50 )
+ AddRecipe( DefBowFletching.CraftSystem );
+
+ // TODO: runic fletching kit
+ }
+
+ public FletchingSatchel( 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 class CarpentrySatchel : BaseCraftmansSatchel
+ {
+ [Constructable]
+ public CarpentrySatchel()
+ {
+ AddBaseLoot( Loot.MLArmorTypes, Loot.MLWeaponTypes, Loot.MLRangedWeaponTypes, Loot.JewelryTypes, m_TalismanType );
+
+ if ( Utility.RandomDouble() < 0.50 )
+ AddRecipe( DefCarpentry.CraftSystem );
+
+ // TODO: Add runic dovetail saw
+ }
+
+ public CarpentrySatchel( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/CrateForSledge.cs b/Scripts/Engines/MLQuests/Items/CrateForSledge.cs
new file mode 100644
index 000000000..97c03d8c6
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/CrateForSledge.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class CrateForSledge : TransientItem
+ {
+ public override int LabelNumber{ get{ return 1074520; } } // Crate for Sledge
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public CrateForSledge() : base( 0x1FFF, TimeSpan.FromHours( 1 ) )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public CrateForSledge( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/DreadSpiderSilk.cs b/Scripts/Engines/MLQuests/Items/DreadSpiderSilk.cs
new file mode 100644
index 000000000..1f1c05008
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/DreadSpiderSilk.cs
@@ -0,0 +1,43 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class DreadSpiderSilk : Item
+ {
+ public override int LabelNumber{ get{ return 1075319; } } // Dread Spider Silk
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public DreadSpiderSilk() : base( 0xDF8 )
+ {
+ LootType = LootType.Blessed;
+ Hue = 0x481;
+ }
+
+ public DreadSpiderSilk( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/FragmentOfAMap.cs b/Scripts/Engines/MLQuests/Items/FragmentOfAMap.cs
new file mode 100644
index 000000000..6ff3e6027
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/FragmentOfAMap.cs
@@ -0,0 +1,34 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class FragmentOfAMap : Item
+ {
+ public override int LabelNumber{ get{ return 1074533; } } // Fragment of a Map
+
+ [Constructable]
+ public FragmentOfAMap() : base( 0x14ED )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public FragmentOfAMap( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/FragmentOfAMapDelivery.cs b/Scripts/Engines/MLQuests/Items/FragmentOfAMapDelivery.cs
new file mode 100644
index 000000000..40c6b5149
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/FragmentOfAMapDelivery.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class FragmentOfAMapDelivery : Item
+ {
+ public override int LabelNumber{ get{ return 1074533; } } // Fragment of a Map
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public FragmentOfAMapDelivery() : base( 0x14ED )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public FragmentOfAMapDelivery( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/FriendOfTheLibraryToken.cs b/Scripts/Engines/MLQuests/Items/FriendOfTheLibraryToken.cs
new file mode 100644
index 000000000..6b91a3893
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/FriendOfTheLibraryToken.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class FriendOfTheLibraryToken : Item
+ {
+ public override int LabelNumber{ get{ return 1073136; } } // Friend of the Library Token (allows donations to be made)
+
+ [Constructable]
+ public FriendOfTheLibraryToken() : base( 0x2F58 )
+ {
+ Layer = Layer.Talisman;
+ Hue = 0x28A;
+ }
+
+ public FriendOfTheLibraryToken( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/FriendsOfTheLibraryApplication.cs b/Scripts/Engines/MLQuests/Items/FriendsOfTheLibraryApplication.cs
new file mode 100644
index 000000000..d6b893264
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/FriendsOfTheLibraryApplication.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class FriendsOfTheLibraryApplication : Item
+ {
+ public override int LabelNumber{ get{ return 1073131; } } // Friends of the Library Application
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public FriendsOfTheLibraryApplication() : base( 0xEC0 )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public FriendsOfTheLibraryApplication( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/GamanHorns.cs b/Scripts/Engines/MLQuests/Items/GamanHorns.cs
new file mode 100644
index 000000000..569c931cf
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/GamanHorns.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class GamanHorns : Item
+ {
+ public override int LabelNumber{ get{ return 1074557; } } // Gaman Horns
+
+ [Constructable]
+ public GamanHorns() : this( 1 )
+ {
+ }
+
+ [Constructable]
+ public GamanHorns( int amount ) : base( 0x1084 )
+ {
+ LootType = LootType.Blessed;
+ Stackable = true;
+ Amount = amount;
+ Hue = 0x395;
+ }
+
+ public GamanHorns( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/GervisSatchel.cs b/Scripts/Engines/MLQuests/Items/GervisSatchel.cs
new file mode 100644
index 000000000..bbbbb84d5
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/GervisSatchel.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class GervisSatchel : Backpack
+ {
+ [Constructable]
+ public GervisSatchel()
+ {
+ Hue = Utility.RandomBrightHue();
+ DropItem( new IronIngot( 10 ) );
+ DropItem( new SmithHammer() );
+ }
+
+ public GervisSatchel( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/GiftForArielle.cs b/Scripts/Engines/MLQuests/Items/GiftForArielle.cs
new file mode 100644
index 000000000..837cbc6ac
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/GiftForArielle.cs
@@ -0,0 +1,43 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class GiftForArielle : BaseContainer
+ {
+ public override int LabelNumber{ get{ return 1074356; } } // gift for arielle
+ public override int DefaultGumpID { get { return 0x41; } }
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public GiftForArielle() : base( 0x1882 )
+ {
+ Hue = 0x2C4;
+ }
+
+ public GiftForArielle( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/HargroveSatchel.cs b/Scripts/Engines/MLQuests/Items/HargroveSatchel.cs
new file mode 100644
index 000000000..3d76d04f9
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/HargroveSatchel.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class HargroveSatchel : Backpack
+ {
+ [Constructable]
+ public HargroveSatchel()
+ {
+ Hue = Utility.RandomBrightHue();
+ DropItem( new Gold( 15 ) );
+ DropItem( new Hatchet() );
+ }
+
+ public HargroveSatchel( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/KirinBrains.cs b/Scripts/Engines/MLQuests/Items/KirinBrains.cs
new file mode 100644
index 000000000..5a9118ee0
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/KirinBrains.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class KirinBrains : Item
+ {
+ public override int LabelNumber{ get{ return 1074612; } } // Ki-Rin Brains
+
+ [Constructable]
+ public KirinBrains() : base( 0x1CF0 )
+ {
+ LootType = LootType.Blessed;
+ Hue = 0xD7;
+ }
+
+ public KirinBrains( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/LowelSatchel.cs b/Scripts/Engines/MLQuests/Items/LowelSatchel.cs
new file mode 100644
index 000000000..44db55fe5
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/LowelSatchel.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class LowelSatchel : Backpack
+ {
+ [Constructable]
+ public LowelSatchel()
+ {
+ Hue = Utility.RandomBrightHue();
+ DropItem( new Board( 10 ) );
+ DropItem( new DovetailSaw() );
+ }
+
+ public LowelSatchel( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/MiniatureMushroom.cs b/Scripts/Engines/MLQuests/Items/MiniatureMushroom.cs
new file mode 100644
index 000000000..a43ba5c58
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/MiniatureMushroom.cs
@@ -0,0 +1,34 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class MiniatureMushroom : Food
+ {
+ public override int LabelNumber{ get{ return 1073138; } } // Miniature mushroom
+
+ [Constructable]
+ public MiniatureMushroom() : base( 0xD16 )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public MiniatureMushroom( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/MirrorOfPurification.cs b/Scripts/Engines/MLQuests/Items/MirrorOfPurification.cs
new file mode 100644
index 000000000..321d0913c
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/MirrorOfPurification.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class MirrorOfPurification : Item
+ {
+ public override int LabelNumber{ get{ return 1075304; } } // Mirror of Purification
+
+ [Constructable]
+ public MirrorOfPurification() : base( 0x1008 )
+ {
+ LootType = LootType.Blessed;
+ Hue = 0x530;
+ }
+
+ public MirrorOfPurification( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/MuggSatchel.cs b/Scripts/Engines/MLQuests/Items/MuggSatchel.cs
new file mode 100644
index 000000000..81a74fa91
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/MuggSatchel.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class MuggSatchel : Backpack
+ {
+ [Constructable]
+ public MuggSatchel()
+ {
+ Hue = Utility.RandomBrightHue();
+ DropItem( new Pickaxe() );
+ DropItem( new Pickaxe() );
+ }
+
+ public MuggSatchel( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/NibbetSatchel.cs b/Scripts/Engines/MLQuests/Items/NibbetSatchel.cs
new file mode 100644
index 000000000..96c9abbe7
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/NibbetSatchel.cs
@@ -0,0 +1,49 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class NibbetSatchel : Backpack
+ {
+ [Constructable]
+ public NibbetSatchel()
+ {
+ Hue = Utility.RandomBrightHue();
+ DropItem( new TinkerTools() );
+
+ switch ( Utility.Random( 10 ) )
+ {
+ case 0: DropItem( new Springs( 3 ) ); break;
+ case 1: DropItem( new Axle( 3 ) ); break;
+ case 2: DropItem( new Hinge( 3 ) ); break;
+ case 3: DropItem( new Key() ); break;
+ case 4: DropItem( new Scissors() ); break;
+ case 5: DropItem( new BarrelTap( 3 ) ); break;
+ case 6: DropItem( new BarrelHoops() ); break;
+ case 7: DropItem( new Gears( 3 ) ); break;
+ case 8: DropItem( new Lockpick( 3 ) ); break;
+ case 9: DropItem( new ClockFrame( 3 ) ); break;
+
+ }
+ }
+
+ public NibbetSatchel( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/NotarizedApplication.cs b/Scripts/Engines/MLQuests/Items/NotarizedApplication.cs
new file mode 100644
index 000000000..9a273094b
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/NotarizedApplication.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class NotarizedApplication : Item
+ {
+ public override int LabelNumber{ get{ return 1073135; } } // Notarized Application
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public NotarizedApplication() : base( 0x14EF )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public NotarizedApplication( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/OfficialSealingWax.cs b/Scripts/Engines/MLQuests/Items/OfficialSealingWax.cs
new file mode 100644
index 000000000..55e1f65a3
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/OfficialSealingWax.cs
@@ -0,0 +1,43 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class OfficialSealingWax : Item
+ {
+ public override int LabelNumber{ get{ return 1072744; } } // Official Sealing Wax
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public OfficialSealingWax() : base( 0x1426 )
+ {
+ LootType = LootType.Blessed;
+ Hue = 0x84;
+ }
+
+ public OfficialSealingWax( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/PeppercornFishsteak.cs b/Scripts/Engines/MLQuests/Items/PeppercornFishsteak.cs
new file mode 100644
index 000000000..8f6786b97
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/PeppercornFishsteak.cs
@@ -0,0 +1,34 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class PeppercornFishsteak : FishSteak
+ {
+ public override int LabelNumber{ get{ return 1075557; } } // peppercorn fishsteak
+
+ [Constructable]
+ public PeppercornFishsteak() : base()
+ {
+ Hue = 0x222;
+ }
+
+ public PeppercornFishsteak( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/PixieLeg.cs b/Scripts/Engines/MLQuests/Items/PixieLeg.cs
new file mode 100644
index 000000000..8413d2521
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/PixieLeg.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class PixieLeg : Item
+ {
+ public override int LabelNumber{ get{ return 1074613; } } // Pixie Leg
+
+ [Constructable]
+ public PixieLeg() : this( 1 )
+ {
+ }
+
+ [Constructable]
+ public PixieLeg( int amount ) : base( 0x1608 )
+ {
+ LootType = LootType.Blessed;
+ Hue = 0x1C2;
+ Stackable = true;
+ Amount = amount;
+ }
+
+ public PixieLeg( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/PortraitOfTheBride.cs b/Scripts/Engines/MLQuests/Items/PortraitOfTheBride.cs
new file mode 100644
index 000000000..9c0cdc4ac
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/PortraitOfTheBride.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class PortraitOfTheBride : Item
+ {
+ public override int LabelNumber{ get{ return 1075300; } } // Portrait of the Bride
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public PortraitOfTheBride() : base( 0xE9F )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public PortraitOfTheBride( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/PrismaticAmber.cs b/Scripts/Engines/MLQuests/Items/PrismaticAmber.cs
new file mode 100644
index 000000000..22788e795
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/PrismaticAmber.cs
@@ -0,0 +1,76 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class PrismaticAmber : Amber
+ {
+ public override int LabelNumber{ get{ return 1075299; } } // Prismatic Amber
+
+ [Constructable]
+ public PrismaticAmber() : base()
+ {
+ }
+
+ public PrismaticAmber( Serial serial ) : base( serial )
+ {
+ }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+
+ list.Add( 1075269 ); // Destroyed when dropped
+ }
+
+ public override bool DropToWorld( Mobile from, Point3D p )
+ {
+ bool ret = base.DropToWorld( from, p );
+
+ if ( ret )
+ DestroyItem( from );
+
+ return ret;
+ }
+
+ public override bool DropToMobile( Mobile from, Mobile target, Point3D p )
+ {
+ bool ret = base.DropToMobile( from, target, p );
+
+ if ( ret )
+ DestroyItem( from );
+
+ return ret;
+ }
+
+ public override bool DropToItem( Mobile from, Item target, Point3D p )
+ {
+ bool ret = base.DropToItem( from, target, p );
+
+ if ( ret && Parent != from.Backpack )
+ DestroyItem( from );
+
+ return ret;
+ }
+
+ public virtual void DestroyItem( Mobile from )
+ {
+ from.SendLocalizedMessage( 500424 ); // You destroyed the item.
+ Delete();
+ }
+
+ 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/PrismaticCrystal.cs b/Scripts/Engines/MLQuests/Items/PrismaticCrystal.cs
new file mode 100644
index 000000000..e2ff52fbe
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/PrismaticCrystal.cs
@@ -0,0 +1,72 @@
+using System;
+using Server;
+using Server.Engines.MLQuests;
+using Server.Engines.MLQuests.Definitions;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Items
+{
+ public class PrismaticCrystal : Item
+ {
+ public override int LabelNumber{ get{ return 1074269; } } // prismatic crystal
+
+ [Constructable]
+ public PrismaticCrystal() : base( 0x2DA )
+ {
+ Movable = false;
+ Hue = 0x32;
+ }
+
+ public PrismaticCrystal( Serial serial ) : base( serial )
+ {
+ }
+
+ public override void OnDoubleClick( Mobile from )
+ {
+ PlayerMobile pm = from as PlayerMobile;
+
+ if ( pm == null || pm.Backpack == null )
+ return;
+
+ if ( pm.InRange( GetWorldLocation(), 2 ) )
+ {
+ MLQuestContext context = MLQuestSystem.GetContext( pm );
+
+ if ( context != null && context.IsDoingQuest( typeof( UnfadingMemoriesPartOne ) ) && pm.Backpack.FindItemByType( typeof( PrismaticAmber ), false ) == null )
+ {
+ Item amber = new PrismaticAmber();
+
+ if ( pm.PlaceInBackpack( amber ) )
+ {
+ MLQuestSystem.MarkQuestItem( pm, amber );
+ Delete();
+ }
+ else
+ {
+ pm.SendLocalizedMessage( 502385 ); // Your pack cannot hold this item.
+ amber.Delete();
+ }
+ }
+ else
+ pm.SendLocalizedMessage( 1075464 ); // You already have as many of those as you need.
+ }
+ else
+ pm.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
+ }
+
+ 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/RedLeatherBook.cs b/Scripts/Engines/MLQuests/Items/RedLeatherBook.cs
new file mode 100644
index 000000000..faa639a56
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/RedLeatherBook.cs
@@ -0,0 +1,33 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class RedLeatherBook : BlueBook
+ {
+ [Constructable]
+ public RedLeatherBook()
+ {
+ Hue = 0x485;
+ }
+
+ public RedLeatherBook( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/ReginasLetter.cs b/Scripts/Engines/MLQuests/Items/ReginasLetter.cs
new file mode 100644
index 000000000..a8bd71def
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/ReginasLetter.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class ReginasLetter : Item
+ {
+ public override int LabelNumber{ get{ return 1075306; } } // Regina's Letter
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public ReginasLetter() : base( 0x14ED )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public ReginasLetter( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/ReginasRing.cs b/Scripts/Engines/MLQuests/Items/ReginasRing.cs
new file mode 100644
index 000000000..346679109
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/ReginasRing.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class ReginasRing : SilverRing
+ {
+ public override int LabelNumber{ get{ return 1075305; } } // Regina's Ring
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public ReginasRing() : base()
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public ReginasRing( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/RewardBags.cs b/Scripts/Engines/MLQuests/Items/RewardBags.cs
new file mode 100644
index 000000000..bd220666c
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/RewardBags.cs
@@ -0,0 +1,196 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server;
+using Server.Items;
+
+namespace Server.Engines.MLQuests.Items
+{
+ public static class RewardBag
+ {
+ public static void Fill( Container c, int itemCount, double talismanChance )
+ {
+ c.Hue = Utility.RandomNondyedHue();
+
+ int done = 0;
+
+ if ( Utility.RandomDouble() < talismanChance )
+ {
+ c.DropItem( new RandomTalisman() );
+ ++done;
+ }
+
+ for ( ; done < itemCount; ++done )
+ {
+ Item loot = null;
+
+ switch ( Utility.Random( 5 ) )
+ {
+ case 0: loot = Loot.RandomWeapon( false, true ); break;
+ case 1: loot = Loot.RandomArmor( false, true ); break;
+ case 2: loot = Loot.RandomRangedWeapon( false, true ); break;
+ case 3: loot = Loot.RandomJewelry(); break;
+ case 4: loot = Loot.RandomHat( false ); break;
+ }
+
+ if ( loot == null )
+ continue;
+
+ Enhance( loot );
+ c.DropItem( loot );
+ }
+ }
+
+ public static void Enhance( Item loot )
+ {
+ if ( loot is BaseWeapon )
+ BaseRunicTool.ApplyAttributesTo( (BaseWeapon)loot, Utility.RandomMinMax( 1, 5 ), 10, 80 );
+ else if ( loot is BaseArmor )
+ BaseRunicTool.ApplyAttributesTo( (BaseArmor)loot, Utility.RandomMinMax( 1, 5 ), 10, 80 );
+ else if ( loot is BaseShield )
+ BaseRunicTool.ApplyAttributesTo( (BaseShield)loot, Utility.RandomMinMax( 1, 5 ), 10, 80 );
+ else if ( loot is BaseJewel )
+ BaseRunicTool.ApplyAttributesTo( (BaseJewel)loot, Utility.RandomMinMax( 1, 5 ), 10, 80 );
+ }
+ }
+
+ public class SmallBagOfTrinkets : Bag
+ {
+ [Constructable]
+ public SmallBagOfTrinkets()
+ {
+ RewardBag.Fill( this, 1, 0.0 );
+ }
+
+ public SmallBagOfTrinkets( 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 class BagOfTrinkets : Bag
+ {
+ [Constructable]
+ public BagOfTrinkets()
+ {
+ RewardBag.Fill( this, 2, 0.05 );
+ }
+
+ public BagOfTrinkets( 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 class BagOfTreasure : Bag
+ {
+ [Constructable]
+ public BagOfTreasure()
+ {
+ RewardBag.Fill( this, 3, 0.20 );
+ }
+
+ public BagOfTreasure( 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 class LargeBagOfTreasure : Bag
+ {
+ [Constructable]
+ public LargeBagOfTreasure()
+ {
+ RewardBag.Fill( this, 4, 0.50 );
+ }
+
+ public LargeBagOfTreasure( 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 class RewardStrongbox : WoodenBox
+ {
+ [Constructable]
+ public RewardStrongbox()
+ {
+ RewardBag.Fill( this, 5, 1.0 );
+ }
+
+ public RewardStrongbox( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/SadrahSatchel.cs b/Scripts/Engines/MLQuests/Items/SadrahSatchel.cs
new file mode 100644
index 000000000..e7d7fd8dd
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/SadrahSatchel.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class SadrahSatchel : Backpack
+ {
+ [Constructable]
+ public SadrahSatchel()
+ {
+ Hue = Utility.RandomBrightHue();
+ DropItem( new Bloodmoss( 10 ) );
+ DropItem( new MortarPestle() );
+ }
+
+ public SadrahSatchel( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/SapOfSosaria.cs b/Scripts/Engines/MLQuests/Items/SapOfSosaria.cs
new file mode 100644
index 000000000..f9086bcac
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/SapOfSosaria.cs
@@ -0,0 +1,41 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class SapOfSosaria : Item
+ {
+ public override int LabelNumber{ get{ return 1074178; } } // Sap of Sosaria
+
+ [Constructable]
+ public SapOfSosaria() : this( 1 )
+ {
+ }
+
+ [Constructable]
+ public SapOfSosaria( int amount ) : base( 0x1848 )
+ {
+ LootType = LootType.Blessed;
+ Stackable = true;
+ Amount = amount;
+ }
+
+ public SapOfSosaria( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/SealedNotesForJamal.cs b/Scripts/Engines/MLQuests/Items/SealedNotesForJamal.cs
new file mode 100644
index 000000000..d3b054393
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/SealedNotesForJamal.cs
@@ -0,0 +1,43 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class SealedNotesForJamal : Item
+ {
+ public override int LabelNumber{ get{ return 1074998; } } // Sealed Notes For Jamal
+ public override double DefaultWeight{ get{ return 1.0; } }
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public SealedNotesForJamal() : base( 0xEF9 )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public SealedNotesForJamal( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/SealingWaxOrderAddressedToPetrus.cs b/Scripts/Engines/MLQuests/Items/SealingWaxOrderAddressedToPetrus.cs
new file mode 100644
index 000000000..d0c24eddf
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/SealingWaxOrderAddressedToPetrus.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class SealingWaxOrderAddressedToPetrus : Item
+ {
+ public override int LabelNumber{ get{ return 1073132; } } // Sealing Wax Order addressed to Petrus
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public SealingWaxOrderAddressedToPetrus() : base( 0xEBF )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public SealingWaxOrderAddressedToPetrus( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/SeveredElfEars.cs b/Scripts/Engines/MLQuests/Items/SeveredElfEars.cs
new file mode 100644
index 000000000..217bdc527
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/SeveredElfEars.cs
@@ -0,0 +1,39 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ [Flipable(0x312D, 0x312E)]
+ public class SeveredElfEars : Item
+ {
+ [Constructable]
+ public SeveredElfEars() : this( 1 )
+ {
+ }
+
+ [Constructable]
+ public SeveredElfEars( int amount ) : base( Utility.RandomList( 0x312D, 0x312E ) )
+ {
+ Stackable = true;
+ Amount = amount;
+ }
+
+ public SeveredElfEars( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/SeveredHumanEars.cs b/Scripts/Engines/MLQuests/Items/SeveredHumanEars.cs
new file mode 100644
index 000000000..d4c6b5dda
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/SeveredHumanEars.cs
@@ -0,0 +1,39 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ [Flipable(0x312F, 0x3130)]
+ public class SeveredHumanEars : Item
+ {
+ [Constructable]
+ public SeveredHumanEars() : this( 1 )
+ {
+ }
+
+ [Constructable]
+ public SeveredHumanEars( int amount ) : base( Utility.RandomList( 0x312F, 0x3130 ) )
+ {
+ Stackable = true;
+ Amount = amount;
+ }
+
+ public SeveredHumanEars( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/SignedTuitionReimbursementForm.cs b/Scripts/Engines/MLQuests/Items/SignedTuitionReimbursementForm.cs
new file mode 100644
index 000000000..698a4fbbb
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/SignedTuitionReimbursementForm.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class SignedTuitionReimbursementForm : Item
+ {
+ public override int LabelNumber{ get{ return 1074614; } } // Signed Tuition Reimbursement Form
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public SignedTuitionReimbursementForm() : base( 0x14F0 )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public SignedTuitionReimbursementForm( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/SpecialTreatForDrithen.cs b/Scripts/Engines/MLQuests/Items/SpecialTreatForDrithen.cs
new file mode 100644
index 000000000..f2b771d6a
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/SpecialTreatForDrithen.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class SpecialTreatForDrithen : Item
+ {
+ public override int LabelNumber{ get{ return 1074517; } } // Special Treat for Drithen
+
+ [Constructable]
+ public SpecialTreatForDrithen() : base( 0x21B )
+ {
+ LootType = LootType.Blessed;
+ Hue = 0x489;
+ }
+
+ public SpecialTreatForDrithen( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/SpeckledPoisonSac.cs b/Scripts/Engines/MLQuests/Items/SpeckledPoisonSac.cs
new file mode 100644
index 000000000..9dd6b426d
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/SpeckledPoisonSac.cs
@@ -0,0 +1,34 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class SpeckledPoisonSac : TransientItem
+ {
+ public override int LabelNumber{ get{ return 1073133; } } // Speckled Poison Sac
+
+ [Constructable]
+ public SpeckledPoisonSac() : base( 0x23A, TimeSpan.FromHours( 1 ) )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public SpeckledPoisonSac( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/SpiritBottle.cs b/Scripts/Engines/MLQuests/Items/SpiritBottle.cs
new file mode 100644
index 000000000..f500c1d6c
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/SpiritBottle.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class SpiritBottle : Item
+ {
+ public override int LabelNumber{ get{ return 1075283; } } // Spirit bottle
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public SpiritBottle() : base( 0xEFB )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public SpiritBottle( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/StoutWhip.cs b/Scripts/Engines/MLQuests/Items/StoutWhip.cs
new file mode 100644
index 000000000..a69c6f1fd
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/StoutWhip.cs
@@ -0,0 +1,34 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class StoutWhip : Item
+ {
+ public override int LabelNumber{ get{ return 1074812; } } // Stout Whip
+
+ [Constructable]
+ public StoutWhip() : base( 0x166F )
+ {
+ LootType = LootType.Blessed;
+ }
+
+ public StoutWhip( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/TaintedTreeSample.cs b/Scripts/Engines/MLQuests/Items/TaintedTreeSample.cs
new file mode 100644
index 000000000..1ea70e774
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/TaintedTreeSample.cs
@@ -0,0 +1,43 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class TaintedTreeSample : Item // On OSI the base class is Kindling, and it's ignitable...
+ {
+ public override int LabelNumber{ get{ return 1074997; } } // Tainted Tree Sample
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public TaintedTreeSample() : base( 0xDE2 )
+ {
+ LootType = LootType.Blessed;
+ Hue = 0x9D;
+ }
+
+ public TaintedTreeSample( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/Teleporters.cs b/Scripts/Engines/MLQuests/Items/Teleporters.cs
new file mode 100644
index 000000000..a778ebee2
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/Teleporters.cs
@@ -0,0 +1,223 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server;
+using Server.Items;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Items
+{
+ public class MLQuestTeleporter : Teleporter
+ {
+ private MLQuest m_RequiredQuest;
+ private TextDefinition m_Message;
+
+ [CommandProperty( AccessLevel.GameMaster )]
+ public MLQuest RequiredQuest
+ {
+ get { return m_RequiredQuest; }
+ // Needs work for in-game
+ set { m_RequiredQuest = value; InvalidateProperties(); }
+ }
+
+ [CommandProperty( AccessLevel.GameMaster )]
+ public TextDefinition Message
+ {
+ get { return m_Message; }
+ set { m_Message = value; }
+ }
+
+ [Constructable]
+ public MLQuestTeleporter()
+ : this( Point3D.Zero, null, null, null )
+ {
+ }
+
+ [Constructable]
+ public MLQuestTeleporter( Point3D pointDest, Map mapDest )
+ : this( pointDest, mapDest, null, null )
+ {
+ }
+
+ [Constructable]
+ public MLQuestTeleporter( Point3D pointDest, Map mapDest, MLQuest quest, TextDefinition message )
+ : base( pointDest, mapDest )
+ {
+ m_RequiredQuest = quest;
+ m_Message = message;
+ }
+
+ public override bool CanTeleport( Mobile m )
+ {
+ if ( !base.CanTeleport( m ) )
+ return false;
+
+ if ( m_RequiredQuest != null )
+ {
+ PlayerMobile pm = m as PlayerMobile;
+
+ if ( pm == null )
+ return false;
+
+ MLQuestContext context = MLQuestSystem.GetContext( pm );
+
+ if ( context == null || ( !context.IsDoingQuest( m_RequiredQuest ) && !context.HasDoneQuest( m_RequiredQuest ) ) )
+ {
+ TextDefinition.SendMessageTo( m, m_Message );
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override void GetProperties( ObjectPropertyList list )
+ {
+ base.GetProperties( list );
+
+ if ( m_RequiredQuest != null )
+ list.Add( String.Format( "Required quest: {0}", m_RequiredQuest ) );
+ }
+
+ public MLQuestTeleporter( Serial serial )
+ : base( serial )
+ {
+ }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( (int) 0 ); // version
+
+ MLQuestSystem.WriteQuestRef( writer, m_RequiredQuest );
+ TextDefinition.Serialize( writer, m_Message );
+ }
+
+ public override void Deserialize( GenericReader reader )
+ {
+ base.Deserialize( reader );
+
+ int version = reader.ReadInt();
+
+ m_RequiredQuest = MLQuestSystem.ReadQuestRef( reader );
+ m_Message = TextDefinition.Deserialize( reader );
+ }
+ }
+
+ public interface ITicket
+ {
+ void OnTicketUsed( Mobile from );
+ }
+
+ public class TicketTeleporter : Teleporter
+ {
+ private Type m_TicketType;
+ private TextDefinition m_Message;
+
+ [CommandProperty( AccessLevel.GameMaster )]
+ public Type TicketType
+ {
+ get { return m_TicketType; }
+ set { m_TicketType = value; InvalidateProperties(); }
+ }
+
+ [CommandProperty( AccessLevel.GameMaster )]
+ public TextDefinition Message
+ {
+ get { return m_Message; }
+ set { m_Message = value; }
+ }
+
+ [Constructable]
+ public TicketTeleporter()
+ : this( Point3D.Zero, null, null, null )
+ {
+ }
+
+ [Constructable]
+ public TicketTeleporter( Point3D pointDest, Map mapDest )
+ : this( pointDest, mapDest, null, null )
+ {
+ }
+
+ [Constructable]
+ public TicketTeleporter( Point3D pointDest, Map mapDest, Type ticketType, TextDefinition message )
+ : base( pointDest, mapDest )
+ {
+ m_TicketType = ticketType;
+ m_Message = message;
+ }
+
+ public override bool CanTeleport( Mobile m )
+ {
+ if ( !base.CanTeleport( m ) )
+ return false;
+
+ if ( m_TicketType != null )
+ {
+ Item ticket = null;
+ Container pack = m.Backpack;
+
+ if ( pack != null )
+ ticket = pack.FindItemByType( m_TicketType, false ); // Check (top level) backpack
+
+ if ( ticket == null )
+ {
+ foreach ( Item item in m.Items ) // Check paperdoll
+ {
+ if ( m_TicketType.IsAssignableFrom( item.GetType() ) )
+ {
+ ticket = item;
+ break;
+ }
+ }
+ }
+
+ if ( ticket == null )
+ {
+ TextDefinition.SendMessageTo( m, m_Message );
+ return false;
+ }
+
+ if ( ticket is ITicket )
+ ((ITicket)ticket).OnTicketUsed( m );
+ }
+
+ return true;
+ }
+
+ public override void GetProperties( ObjectPropertyList list )
+ {
+ base.GetProperties( list );
+
+ if ( m_TicketType != null )
+ list.Add( String.Format( "Required ticket: {0}", m_TicketType.Name ) );
+ }
+
+ public TicketTeleporter( Serial serial )
+ : base( serial )
+ {
+ }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( (int)0 ); // version
+
+ writer.Write( m_TicketType.FullName );
+ TextDefinition.Serialize( writer, m_Message );
+ }
+
+ public override void Deserialize( GenericReader reader )
+ {
+ base.Deserialize( reader );
+
+ int version = reader.ReadInt();
+
+ m_TicketType = ScriptCompiler.FindTypeByFullName( reader.ReadString(), false );
+ m_Message = TextDefinition.Deserialize( reader );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/TransparentHeart.cs b/Scripts/Engines/MLQuests/Items/TransparentHeart.cs
new file mode 100644
index 000000000..bde8985ee
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/TransparentHeart.cs
@@ -0,0 +1,35 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class TransparentHeart : GoldEarrings
+ {
+ public override int LabelNumber{ get{ return 1075400; } } // Transparent Heart
+
+ [Constructable]
+ public TransparentHeart() : base()
+ {
+ LootType = LootType.Blessed;
+ Hue = 0x4AB;
+ }
+
+ public TransparentHeart( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/TuitionReimbursementForm.cs b/Scripts/Engines/MLQuests/Items/TuitionReimbursementForm.cs
new file mode 100644
index 000000000..540fe99d7
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/TuitionReimbursementForm.cs
@@ -0,0 +1,43 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class TuitionReimbursementForm : Item
+ {
+ public override int LabelNumber{ get{ return 1074610; } } // Tuition Reimbursement Form (in triplicate)
+
+ public override bool Nontransferable { get { return true; } }
+
+ public override void AddNameProperties( ObjectPropertyList list )
+ {
+ base.AddNameProperties( list );
+ AddQuestItemProperty( list );
+ }
+
+ [Constructable]
+ public TuitionReimbursementForm() : base( 0xE3A )
+ {
+ LootType = LootType.Blessed;
+ Hue = 0x395;
+ }
+
+ public TuitionReimbursementForm( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Items/UnicornRibs.cs b/Scripts/Engines/MLQuests/Items/UnicornRibs.cs
new file mode 100644
index 000000000..cf02c2174
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Items/UnicornRibs.cs
@@ -0,0 +1,42 @@
+using System;
+using Server;
+
+namespace Server.Items
+{
+ public class UnicornRibs : Item
+ {
+ public override int LabelNumber{ get{ return 1074611; } } // Unicorn Ribs
+
+ [Constructable]
+ public UnicornRibs() : this( 1 )
+ {
+ }
+
+ [Constructable]
+ public UnicornRibs( int amount ) : base( 0x9F1 )
+ {
+ LootType = LootType.Blessed;
+ Hue = 0x14B;
+ Stackable = true;
+ Amount = amount;
+ }
+
+ public UnicornRibs( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/MLQuest.cs b/Scripts/Engines/MLQuests/MLQuest.cs
new file mode 100644
index 000000000..6405c91ca
--- /dev/null
+++ b/Scripts/Engines/MLQuests/MLQuest.cs
@@ -0,0 +1,332 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.Engines.MLQuests.Gumps;
+using Server.Engines.MLQuests.Objectives;
+using Server.Engines.MLQuests.Rewards;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests
+{
+ public enum ObjectiveType
+ {
+ All,
+ Any
+ }
+
+ public class MLQuest
+ {
+ private bool m_Deserialized;
+ private bool m_SaveEnabled;
+
+ public bool Deserialized
+ {
+ get { return m_Deserialized; }
+ set { m_Deserialized = value; }
+ }
+
+ public bool SaveEnabled
+ {
+ get { return m_SaveEnabled; }
+ set { m_SaveEnabled = value; }
+ }
+
+ private bool m_Activated;
+ private List m_Objectives;
+ private ObjectiveType m_ObjectiveType;
+ private List m_Rewards;
+ private List m_Questers;
+
+ private List m_Instances;
+
+ private TextDefinition m_Title;
+ private TextDefinition m_Description;
+ private TextDefinition m_RefuseMessage;
+ private TextDefinition m_InProgressMessage;
+ private TextDefinition m_CompleteMessage;
+
+ // TODO: Flags? (Deserialized, SaveEnabled, Activated)
+ private bool m_OneTimeOnly;
+
+ public bool Activated
+ {
+ get { return m_Activated; }
+ set { m_Activated = value; }
+ }
+
+ public List Objectives
+ {
+ get { return m_Objectives; }
+ set { m_Objectives = value; }
+ }
+
+ public ObjectiveType ObjectiveType
+ {
+ get { return m_ObjectiveType; }
+ set { m_ObjectiveType = value; }
+ }
+
+ public List Rewards
+ {
+ get { return m_Rewards; }
+ set { m_Rewards = value; }
+ }
+
+ public List Questers
+ {
+ get { return m_Questers; }
+ set { m_Questers = value; }
+ }
+
+ public List Instances
+ {
+ get { return m_Instances; }
+ set { m_Instances = value; }
+ }
+
+ public bool OneTimeOnly
+ {
+ get { return m_OneTimeOnly; }
+ set { m_OneTimeOnly = value; }
+ }
+
+ public bool HasObjective() where T : BaseObjective
+ {
+ foreach ( BaseObjective obj in m_Objectives )
+ {
+ if ( obj is T )
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool IsEscort
+ {
+ get { return HasObjective(); }
+ }
+
+ public bool IsSkillTrainer
+ {
+ get { return HasObjective(); }
+ }
+
+ public bool RequiresCollection
+ {
+ get { return HasObjective() || HasObjective(); }
+ }
+
+ public virtual bool RecordCompletion
+ {
+ // TODO
+ get { return ( m_OneTimeOnly /* || HasRestartDelay */ ); }
+ }
+
+ public virtual bool IsChainTriggered { get { return false; } }
+ public virtual Type NextQuest { get { return null; } }
+
+ public TextDefinition Title { get { return m_Title; } set { m_Title = value; } }
+ public TextDefinition Description { get { return m_Description; } set { m_Description = value; } }
+ public TextDefinition RefusalMessage { get { return m_RefuseMessage; } set { m_RefuseMessage = value; } }
+ public TextDefinition InProgressMessage { get { return m_InProgressMessage; } set { m_InProgressMessage = value; } }
+ public TextDefinition CompletionMessage { get { return m_CompleteMessage; } set { m_CompleteMessage = value; } }
+
+ public MLQuest()
+ {
+ m_Activated = false;
+ m_Objectives = new List();
+ m_ObjectiveType = ObjectiveType.All;
+ m_Rewards = new List();
+
+ m_Questers = new List();
+ m_Instances = new List();
+
+ 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 )
+ Console.WriteLine( "INFO: Generating quest: {0}", GetType() );
+ }
+
+ #region Generation Methods
+
+ public void PutSpawner( Spawner s, Point3D loc, Map map )
+ {
+ // Auto cleanup on regeneration
+ /*
+ List- toDelete = new List
- ();
+
+ foreach ( Item item in map.GetItemsInRange( loc, 0 ) )
+ {
+ if ( item is Spawner )
+ toDelete.Add( item );
+ }
+
+ foreach ( Item item in toDelete )
+ item.Delete();
+ */
+
+ s.Name = String.Format( "MLQS-{0}", GetType().Name );
+ s.MoveToWorld( loc, map );
+ }
+
+ #endregion
+
+ public MLQuestInstance CreateInstance( BaseCreature quester, PlayerMobile pm )
+ {
+ return new MLQuestInstance( this, quester, pm );
+ }
+
+ public virtual bool CanOffer( BaseCreature quester, PlayerMobile pm )
+ {
+ if ( !m_Activated || quester.Deleted || !m_Questers.Contains( quester ) )
+ return false;
+
+ MLQuestContext context = MLQuestSystem.GetContext( pm );
+
+ if ( context != null )
+ {
+ if ( context.IsFull )
+ {
+ MLQuestSystem.Tell( quester, pm, 1080107 ); // I'm sorry, I have nothing for you at this time.
+ return false;
+ }
+
+ DateTime lastDone;
+
+ // TODO: Also recursively check NextQuest? (This would explain Aemaeth1)
+ if ( context.HasDoneQuest( this, out lastDone ) )
+ {
+ if ( m_OneTimeOnly )
+ {
+ MLQuestSystem.Tell( quester, pm, 1075454 ); // I cannot offer you the quest again.
+ return false;
+ }
+ //else if ( m_RestartDelay > TimeSpan.Zero && lastDone + m_RestartDelay > DateTime.Now )
+ //{
+ // MLQuestSystem.Tell( quester, pm, "Piss off!" );
+ // return false;
+ //}
+ }
+ }
+
+ // Note: On OSI this is checked before max concurrent / one time only (at least for EscortObjective),
+ // but it's more intuitive for players to have it here
+ foreach ( BaseObjective obj in m_Objectives )
+ {
+ if ( !obj.CanOffer( quester, pm ) )
+ return false;
+ }
+
+ return true;
+ }
+
+ public virtual void SendOffer( BaseCreature quester, PlayerMobile pm )
+ {
+ pm.SendGump( new QuestOfferGump( this, quester, pm ) );
+ }
+
+ public virtual void OnAccept( BaseCreature quester, PlayerMobile pm )
+ {
+ if ( !CanOffer( quester, pm ) )
+ return;
+
+ MLQuestInstance instance = CreateInstance( quester, pm );
+
+ pm.SendLocalizedMessage( 1049019 ); // You have accepted the Quest.
+ pm.SendSound( 0x2E7 ); // private sound
+
+ foreach ( BaseObjectiveInstance obj in instance.Objectives )
+ obj.OnQuestAccepted();
+ }
+
+ public virtual void OnRefuse( BaseCreature quester, PlayerMobile pm )
+ {
+ if ( !CanOffer( quester, pm ) )
+ return;
+
+ pm.SendGump( new QuestConversationGump( this, pm, RefusalMessage ) );
+ }
+
+ // Note: Be careful with awarding stuff in OnComplete (like fame), this CAN
+ // be triggered multiple times for certain objectives. Use OnRewardClaimed instead.
+ public virtual void OnComplete( MLQuestInstance instance )
+ {
+ instance.Player.SendLocalizedMessage( 1072273, "", 0x23 ); // You've completed a quest! Don't forget to collect your reward.
+
+ // Note: For some quests this message is sent instead:
+ //instance.Player.SendLocalizedMessage( 1073775, "", 0x23 ); // Your quest is complete. Return for your reward.
+ }
+
+ public virtual void GetRewards( MLQuestInstance instance )
+ {
+ instance.SendRewardGump();
+ }
+
+ public virtual void OnRewardClaimed( MLQuestInstance instance )
+ {
+ }
+
+ public virtual void OnCancel( MLQuestInstance instance )
+ {
+ }
+
+ public virtual void OnQuesterDeleted( MLQuestInstance instance )
+ {
+ }
+
+ public virtual void OnPlayerDeath( MLQuestInstance instance )
+ {
+ }
+
+ public static void Serialize( GenericWriter writer, MLQuest quest )
+ {
+ MLQuestSystem.WriteQuestRef( writer, quest );
+ writer.Write( quest.Version );
+ }
+
+ public static void Deserialize( GenericReader reader, int version )
+ {
+ MLQuest quest = MLQuestSystem.ReadQuestRef( reader );
+ int oldVersion = reader.ReadInt();
+
+ if ( quest == null )
+ return; // not saved or no longer exists
+
+ quest.Refresh( oldVersion );
+ quest.m_Deserialized = true;
+ }
+
+ public virtual int Version { get { return 0; } }
+
+ public virtual void Refresh( int oldVersion )
+ {
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/MLQuestContext.cs b/Scripts/Engines/MLQuests/MLQuestContext.cs
new file mode 100644
index 000000000..8c75bcf96
--- /dev/null
+++ b/Scripts/Engines/MLQuests/MLQuestContext.cs
@@ -0,0 +1,287 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server.Mobiles;
+using Server.Engines.MLQuests.Objectives;
+
+namespace Server.Engines.MLQuests
+{
+ [Flags]
+ public enum MLQuestFlag
+ {
+ None = 0x00,
+ Spellweaving = 0x01,
+ SummonFey = 0x02,
+ SummonFiend = 0x04
+ }
+
+ [PropertyObject]
+ public class MLQuestContext
+ {
+ private class MLDoneQuestInfo
+ {
+ public MLQuest m_Quest;
+ public DateTime m_Completed;
+
+ public MLDoneQuestInfo( MLQuest quest, DateTime completed )
+ {
+ m_Quest = quest;
+ m_Completed = completed;
+ }
+
+ public void Serialize( GenericWriter writer )
+ {
+ MLQuestSystem.WriteQuestRef( writer, m_Quest );
+ writer.Write( m_Completed );
+ }
+
+ public static MLDoneQuestInfo Deserialize( GenericReader reader, int version )
+ {
+ MLQuest quest = MLQuestSystem.ReadQuestRef( reader );
+ DateTime completed = reader.ReadDateTime();
+
+ if ( quest == null || !quest.RecordCompletion )
+ return null; // forget about this record
+
+ return new MLDoneQuestInfo( quest, completed );
+ }
+ }
+
+ private PlayerMobile m_Owner;
+ private List m_QuestInstances;
+ private List m_DoneQuests;
+ private List m_ChainOffers;
+ private MLQuestFlag m_Flags;
+
+ public PlayerMobile Owner
+ {
+ get { return m_Owner; }
+ }
+
+ public List QuestInstances
+ {
+ get { return m_QuestInstances; }
+ }
+
+ public List ChainOffers
+ {
+ get { return m_ChainOffers; }
+ }
+
+ [CommandProperty( AccessLevel.GameMaster )]
+ public bool IsFull
+ {
+ get { return m_QuestInstances.Count >= MLQuestSystem.MaxConcurrentQuests; }
+ }
+
+ [CommandProperty( AccessLevel.GameMaster )]
+ public bool Spellweaving
+ {
+ get { return GetFlag( MLQuestFlag.Spellweaving ); }
+ set { SetFlag( MLQuestFlag.Spellweaving, value ); }
+ }
+
+ [CommandProperty( AccessLevel.GameMaster )]
+ public bool SummonFey
+ {
+ get { return GetFlag( MLQuestFlag.SummonFey ); }
+ set { SetFlag( MLQuestFlag.SummonFey, value ); }
+ }
+
+ [CommandProperty( AccessLevel.GameMaster )]
+ public bool SummonFiend
+ {
+ get { return GetFlag( MLQuestFlag.SummonFiend ); }
+ set { SetFlag( MLQuestFlag.SummonFiend, value ); }
+ }
+
+ public MLQuestContext( PlayerMobile owner )
+ {
+ m_Owner = owner;
+ m_QuestInstances = new List();
+ m_DoneQuests = new List();
+ m_ChainOffers = new List();
+ m_Flags = MLQuestFlag.None;
+ }
+
+ public bool HasDoneQuest( Type questType )
+ {
+ MLQuest quest = MLQuestSystem.FindQuest( questType );
+
+ return ( quest != null && HasDoneQuest( quest ) );
+ }
+
+ public bool HasDoneQuest( MLQuest quest )
+ {
+ foreach ( MLDoneQuestInfo info in m_DoneQuests )
+ {
+ if ( info.m_Quest == quest )
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool HasDoneQuest( MLQuest quest, out DateTime completed )
+ {
+ completed = DateTime.MinValue;
+
+ foreach ( MLDoneQuestInfo info in m_DoneQuests )
+ {
+ if ( info.m_Quest == quest )
+ {
+ completed = info.m_Completed;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public void SetDoneQuest( MLQuest quest )
+ {
+ foreach ( MLDoneQuestInfo info in m_DoneQuests )
+ {
+ if ( info.m_Quest == quest )
+ {
+ info.m_Completed = DateTime.Now;
+ return;
+ }
+ }
+
+ m_DoneQuests.Add( new MLDoneQuestInfo( quest, DateTime.Now ) );
+ }
+
+ public void RemoveDoneQuest( MLQuest quest )
+ {
+ for ( int i = m_DoneQuests.Count - 1; i >= 0; --i )
+ {
+ MLDoneQuestInfo info = m_DoneQuests[i];
+
+ if ( info.m_Quest == quest )
+ m_DoneQuests.RemoveAt( i );
+ }
+ }
+
+ public void HandleDeath()
+ {
+ for ( int i = m_QuestInstances.Count - 1; i >= 0; --i )
+ m_QuestInstances[i].OnPlayerDeath();
+ }
+
+ public void HandleDeletion()
+ {
+ for ( int i = m_QuestInstances.Count - 1; i >= 0; --i )
+ m_QuestInstances[i].Remove();
+ }
+
+ public MLQuestInstance FindInstance( Type questType )
+ {
+ MLQuest quest = MLQuestSystem.FindQuest( questType );
+
+ if ( quest == null )
+ return null;
+
+ return FindInstance( quest );
+ }
+
+ public MLQuestInstance FindInstance( MLQuest quest )
+ {
+ foreach ( MLQuestInstance instance in m_QuestInstances )
+ {
+ if ( instance.Quest == quest )
+ return instance;
+ }
+
+ return null;
+ }
+
+ public bool IsDoingQuest( Type questType )
+ {
+ MLQuest quest = MLQuestSystem.FindQuest( questType );
+
+ return ( quest != null && IsDoingQuest( quest ) );
+ }
+
+ public bool IsDoingQuest( MLQuest quest )
+ {
+ return ( FindInstance( quest ) != null );
+ }
+
+ public void Serialize( GenericWriter writer )
+ {
+ // Version info is written in MLQuestPersistence.Serialize
+
+ writer.WriteMobile( m_Owner );
+ writer.Write( m_QuestInstances.Count );
+
+ foreach ( MLQuestInstance instance in m_QuestInstances )
+ instance.Serialize( writer );
+
+ writer.Write( m_DoneQuests.Count );
+
+ foreach ( MLDoneQuestInfo info in m_DoneQuests )
+ info.Serialize( writer );
+
+ writer.Write( m_ChainOffers.Count );
+
+ foreach ( MLQuest quest in m_ChainOffers )
+ MLQuestSystem.WriteQuestRef( writer, quest );
+
+ writer.WriteEncodedInt( (int)m_Flags );
+ }
+
+ public MLQuestContext( GenericReader reader, int version )
+ {
+ m_Owner = reader.ReadMobile();
+ m_QuestInstances = new List();
+ m_DoneQuests = new List();
+ m_ChainOffers = new List();
+
+ int instances = reader.ReadInt();
+
+ for ( int i = 0; i < instances; ++i )
+ {
+ MLQuestInstance instance = MLQuestInstance.Deserialize( reader, version, m_Owner );
+
+ if ( instance != null )
+ m_QuestInstances.Add( instance );
+ }
+
+ int doneQuests = reader.ReadInt();
+
+ for ( int i = 0; i < doneQuests; ++i )
+ {
+ MLDoneQuestInfo info = MLDoneQuestInfo.Deserialize( reader, version );
+
+ if ( info != null )
+ m_DoneQuests.Add( info );
+ }
+
+ int chainOffers = reader.ReadInt();
+
+ for ( int i = 0; i < chainOffers; ++i )
+ {
+ MLQuest quest = MLQuestSystem.ReadQuestRef( reader );
+
+ if ( quest != null && quest.IsChainTriggered )
+ m_ChainOffers.Add( quest );
+ }
+
+ m_Flags = (MLQuestFlag)reader.ReadEncodedInt();
+ }
+
+ public bool GetFlag( MLQuestFlag flag )
+ {
+ return ( ( m_Flags & flag ) != 0 );
+ }
+
+ public void SetFlag( MLQuestFlag flag, bool value )
+ {
+ if ( value )
+ m_Flags |= flag;
+ else
+ m_Flags &= ~flag;
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/MLQuestEntry.cs b/Scripts/Engines/MLQuests/MLQuestEntry.cs
new file mode 100644
index 000000000..6636f8c2f
--- /dev/null
+++ b/Scripts/Engines/MLQuests/MLQuestEntry.cs
@@ -0,0 +1,522 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.Engines.MLQuests.Objectives;
+using Server.Mobiles;
+using Server.Network;
+using Server.Engines.MLQuests.Gumps;
+using Server.Engines.MLQuests.Rewards;
+
+namespace Server.Engines.MLQuests
+{
+ [Flags]
+ public enum MLQuestInstanceFlags : byte
+ {
+ None = 0x00,
+ ClaimReward = 0x01,
+ Removed = 0x02,
+ Failed = 0x04
+ }
+
+ public class MLQuestInstance
+ {
+ private MLQuest m_Quest;
+
+ private BaseCreature m_Quester;
+ private Type m_QuesterType;
+ private PlayerMobile m_Player;
+
+ private DateTime m_Accepted;
+ private MLQuestInstanceFlags m_Flags;
+
+ private BaseObjectiveInstance[] m_ObjectiveInstances;
+
+ private Timer m_Timer;
+
+ public MLQuestInstance( MLQuest quest, BaseCreature quester, PlayerMobile player )
+ {
+ m_Quest = quest;
+
+ m_Quester = quester;
+ m_QuesterType = ( quester == null ) ? null : quester.GetType();
+ m_Player = player;
+
+ m_Accepted = DateTime.Now;
+ m_Flags = MLQuestInstanceFlags.None;
+
+ m_ObjectiveInstances = new BaseObjectiveInstance[quest.Objectives.Count];
+
+ BaseObjectiveInstance obj;
+ bool timed = false;
+
+ for ( int i = 0; i < quest.Objectives.Count; ++i )
+ {
+ m_ObjectiveInstances[i] = obj = quest.Objectives[i].CreateInstance( this );
+
+ if ( obj.IsTimed )
+ timed = true;
+ }
+
+ Register();
+
+ if ( timed )
+ m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 5 ), Slice );
+ }
+
+ private void Register()
+ {
+ if ( m_Quest != null && m_Quest.Instances != null )
+ m_Quest.Instances.Add( this );
+
+ if ( m_Player != null )
+ PlayerContext.QuestInstances.Add( this );
+ }
+
+ private void Unregister()
+ {
+ if ( m_Quest != null && m_Quest.Instances != null )
+ m_Quest.Instances.Remove( this );
+
+ if ( m_Player != null )
+ PlayerContext.QuestInstances.Remove( this );
+
+ Removed = true;
+ }
+
+ public MLQuest Quest
+ {
+ get { return m_Quest; }
+ set { m_Quest = value; }
+ }
+
+ public BaseCreature Quester
+ {
+ get { return m_Quester; }
+ set
+ {
+ m_Quester = value;
+ m_QuesterType = ( value == null ) ? null : value.GetType();
+ }
+ }
+
+ public Type QuesterType
+ {
+ get { return m_QuesterType; }
+ }
+
+ public PlayerMobile Player
+ {
+ get { return m_Player; }
+ set { m_Player = value; }
+ }
+
+ public MLQuestContext PlayerContext
+ {
+ get { return MLQuestSystem.GetOrCreateContext( m_Player ); }
+ }
+
+ public DateTime Accepted
+ {
+ get { return m_Accepted; }
+ set { m_Accepted = value; }
+ }
+
+ public bool ClaimReward
+ {
+ get { return GetFlag( MLQuestInstanceFlags.ClaimReward ); }
+ set { SetFlag( MLQuestInstanceFlags.ClaimReward, value ); }
+ }
+
+ public bool Removed
+ {
+ get { return GetFlag( MLQuestInstanceFlags.Removed ); }
+ set { SetFlag( MLQuestInstanceFlags.Removed, value ); }
+ }
+
+ public bool Failed
+ {
+ get { return GetFlag( MLQuestInstanceFlags.Failed ); }
+ set { SetFlag( MLQuestInstanceFlags.Failed, value ); }
+ }
+
+ public BaseObjectiveInstance[] Objectives
+ {
+ get { return m_ObjectiveInstances; }
+ set { m_ObjectiveInstances = value; }
+ }
+
+ public bool AllowsQuestItem( Item item, Type type )
+ {
+ foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances )
+ {
+ if ( !objective.Expired && objective.AllowsQuestItem( item, type ) )
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool IsCompleted()
+ {
+ bool requiresAll = ( m_Quest.ObjectiveType == ObjectiveType.All );
+
+ foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances )
+ {
+ bool complete = obj.IsCompleted();
+
+ if ( complete && !requiresAll )
+ return true;
+ else if ( !complete && requiresAll )
+ return false;
+ }
+
+ return requiresAll;
+ }
+
+ public void CheckComplete()
+ {
+ if ( IsCompleted() )
+ {
+ m_Player.PlaySound( 0x5B5 ); // public sound
+
+ foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances )
+ obj.OnQuestCompleted();
+
+ m_Quest.OnComplete( this );
+
+ if ( !Removed && SkipReportBack && !m_Quest.RequiresCollection ) // An OnComplete can potentially have removed this instance already
+ ClaimReward = true;
+ }
+ }
+
+ public void Fail()
+ {
+ Failed = true;
+ }
+
+ private void Slice()
+ {
+ if ( ClaimReward || Removed )
+ {
+ StopTimer();
+ return;
+ }
+
+ bool hasAnyFails = false;
+ bool hasAnyLeft = false;
+
+ foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances )
+ {
+ if ( !obj.Expired )
+ {
+ if ( obj.IsTimed && obj.EndTime <= DateTime.Now )
+ {
+ m_Player.SendLocalizedMessage( 1072258 ); // You failed to complete an objective in time!
+
+ obj.Expired = true;
+ obj.OnExpire();
+
+ hasAnyFails = true;
+ }
+ else
+ {
+ hasAnyLeft = true;
+ }
+ }
+ }
+
+ if ( ( m_Quest.ObjectiveType == ObjectiveType.All && hasAnyFails ) || !hasAnyLeft )
+ Fail();
+
+ if ( !hasAnyLeft )
+ StopTimer();
+ }
+
+ public void SendProgressGump()
+ {
+ m_Player.SendGump( new QuestConversationGump( m_Quest, m_Player, m_Quest.InProgressMessage ) );
+ }
+
+ public void SendRewardOffer()
+ {
+ m_Quest.GetRewards( this );
+ }
+
+ // TODO: Split next quest stuff from SendRewardGump stuff?
+ public void SendRewardGump()
+ {
+ Type nextQuestType = m_Quest.NextQuest;
+
+ if ( nextQuestType != null )
+ {
+ ClaimRewards(); // skip reward gump
+
+ if ( Removed ) // rewards were claimed successfully
+ {
+ MLQuest nextQuest = MLQuestSystem.FindQuest( nextQuestType );
+
+ if ( nextQuest != null )
+ nextQuest.SendOffer( m_Quester, m_Player );
+ }
+ }
+ else
+ {
+ m_Player.SendGump( new QuestRewardGump( this ) );
+ }
+ }
+
+ public bool SkipReportBack
+ {
+ get { return TextDefinition.IsNullOrEmpty( m_Quest.CompletionMessage ); }
+ }
+
+ public void SendReportBackGump()
+ {
+ if ( SkipReportBack )
+ ContinueReportBack(); // skip ahead
+ else
+ m_Player.SendGump( new QuestReportBackGump( this ) );
+ }
+
+ public void ContinueReportBack()
+ {
+ // There is a backpack check here on OSI for the rewards as well (even though it's not needed...)
+
+ if ( m_Quest.ObjectiveType == ObjectiveType.All )
+ {
+ 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
+ return;
+ }
+
+ foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances )
+ {
+ if ( !objective.OnBeforeClaimReward() )
+ return;
+ }
+
+ foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances )
+ objective.OnClaimReward();
+ }
+ 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.
+ bool complete = false;
+
+ foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances )
+ {
+ if ( objective.IsCompleted() )
+ {
+ if ( objective.OnBeforeClaimReward() )
+ {
+ complete = true;
+ objective.OnClaimReward();
+ }
+
+ break;
+ }
+ }
+
+ if ( !complete )
+ return;
+ }
+
+ ClaimReward = true;
+
+ // This is correct for ObjectiveType.Any as well
+ foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances )
+ objective.OnAfterClaimReward();
+
+ SendRewardOffer();
+ }
+
+ public void ClaimRewards()
+ {
+ if ( m_Quest == null || m_Player == null || m_Player.Deleted || !ClaimReward || Removed )
+ return;
+
+ List
- rewards = new List
- ();
+
+ foreach ( BaseReward reward in m_Quest.Rewards )
+ reward.AddRewardItems( m_Player, rewards );
+
+ if ( rewards.Count != 0 )
+ {
+ // On OSI a more naive method of checking is used.
+ // For containers, only the actual container item counts.
+ bool canFit = true;
+
+ foreach ( Item rewardItem in rewards )
+ {
+ if ( !m_Player.AddToBackpack( rewardItem ) )
+ {
+ canFit = false;
+ break;
+ }
+ }
+
+ if ( !canFit )
+ {
+ foreach ( Item rewardItem in rewards )
+ rewardItem.Delete();
+
+ m_Player.SendLocalizedMessage( 1078524 ); // Your backpack is full. You cannot complete the quest and receive your reward.
+ return;
+ }
+
+ foreach ( Item rewardItem in rewards )
+ {
+ string rewardName = ( rewardItem.Name != null ) ? rewardItem.Name : String.Concat( "#", rewardItem.LabelNumber );
+
+ if ( rewardItem.Stackable )
+ m_Player.SendLocalizedMessage( 1115917, String.Concat( rewardItem.Amount, "\t", rewardName ) ); // You receive a reward: ~1_QUANTITY~ ~2_ITEM~
+ else
+ m_Player.SendLocalizedMessage( 1074360, rewardName ); // You receive a reward: ~1_REWARD~
+ }
+ }
+
+ foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances )
+ objective.OnRewardClaimed();
+
+ m_Quest.OnRewardClaimed( this );
+
+ MLQuestContext context = PlayerContext;
+
+ if ( m_Quest.RecordCompletion )
+ context.SetDoneQuest( m_Quest );
+
+ if ( m_Quest.IsChainTriggered )
+ context.ChainOffers.Remove( m_Quest );
+
+ Type nextQuestType = m_Quest.NextQuest;
+
+ if ( nextQuestType != null )
+ {
+ MLQuest nextQuest = MLQuestSystem.FindQuest( nextQuestType );
+
+ if ( nextQuest != null && !context.ChainOffers.Contains( nextQuest ) )
+ context.ChainOffers.Add( nextQuest );
+ }
+
+ Remove();
+ }
+
+ public void Cancel()
+ {
+ Cancel( false );
+ }
+
+ public void Cancel( bool removeChain )
+ {
+ Remove();
+
+ m_Player.SendSound( 0x5B3 ); // private sound
+
+ foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances )
+ obj.OnQuestCancelled();
+
+ m_Quest.OnCancel( this );
+
+ if ( removeChain )
+ PlayerContext.ChainOffers.Remove( m_Quest );
+ }
+
+ public void Remove()
+ {
+ Unregister();
+ StopTimer();
+ }
+
+ private void StopTimer()
+ {
+ if ( m_Timer != null )
+ {
+ m_Timer.Stop();
+ m_Timer = null;
+ }
+ }
+
+ public void OnQuesterDeleted()
+ {
+ foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances )
+ obj.OnQuesterDeleted();
+
+ m_Quest.OnQuesterDeleted( this );
+ }
+
+ public void OnPlayerDeath()
+ {
+ foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances )
+ obj.OnPlayerDeath();
+
+ 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 );
+ }
+
+ private void SetFlag( MLQuestInstanceFlags flag, bool value )
+ {
+ if ( value )
+ m_Flags |= flag;
+ else
+ m_Flags &= ~flag;
+ }
+
+ public void Serialize( GenericWriter writer )
+ {
+ // Version info is written in MLQuestPersistence.Serialize
+
+ MLQuestSystem.WriteQuestRef( writer, m_Quest );
+ writer.WriteMobile( m_Quester );
+
+ writer.Write( ClaimReward );
+ writer.Write( m_ObjectiveInstances.Length );
+
+ foreach ( BaseObjectiveInstance objInstance in m_ObjectiveInstances )
+ objInstance.Serialize( writer );
+ }
+
+ public static MLQuestInstance Deserialize( GenericReader reader, int version, PlayerMobile pm )
+ {
+ MLQuest quest = MLQuestSystem.ReadQuestRef( reader );
+ BaseCreature quester = reader.ReadMobile();
+
+ bool claimReward = reader.ReadBool();
+ int objectives = reader.ReadInt();
+
+ MLQuestInstance instance;
+
+ if ( quest != null && quester != null && pm != null )
+ {
+ instance = quest.CreateInstance( quester, pm );
+ instance.ClaimReward = claimReward;
+ }
+ else
+ {
+ instance = null;
+ }
+
+ for ( int i = 0; i < objectives; ++i )
+ BaseObjectiveInstance.Deserialize( reader, version, ( instance != null && i < instance.Objectives.Length ) ? instance.Objectives[i] : null );
+
+ if ( instance != null )
+ instance.Slice();
+
+ return instance;
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/MLQuestPersistence.cs b/Scripts/Engines/MLQuests/MLQuestPersistence.cs
new file mode 100644
index 000000000..a3233d7d0
--- /dev/null
+++ b/Scripts/Engines/MLQuests/MLQuestPersistence.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests
+{
+ public class MLQuestPersistence : Item
+ {
+ private static MLQuestPersistence m_Instance;
+
+ public static void EnsureExistence()
+ {
+ if ( m_Instance == null )
+ m_Instance = new MLQuestPersistence();
+ }
+
+ public override string DefaultName
+ {
+ get { return "ML quests persistence - Internal"; }
+ }
+
+ private MLQuestPersistence()
+ : base( 1 )
+ {
+ Movable = false;
+ }
+
+ public MLQuestPersistence( Serial serial ) : base( serial )
+ {
+ m_Instance = this;
+ }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( (int) 2 ); // version
+ writer.Write( MLQuestSystem.Contexts.Count );
+
+ foreach ( MLQuestContext context in MLQuestSystem.Contexts.Values )
+ context.Serialize( writer );
+
+ writer.Write( MLQuestSystem.Quests.Count );
+
+ foreach ( MLQuest quest in MLQuestSystem.Quests.Values )
+ MLQuest.Serialize( writer, quest );
+ }
+
+ public override void Deserialize( GenericReader reader )
+ {
+ base.Deserialize( reader );
+
+ int version = reader.ReadInt();
+ int contexts = reader.ReadInt();
+
+ for ( int i = 0; i < contexts; ++i )
+ {
+ MLQuestContext context = new MLQuestContext( reader, version );
+
+ if ( context.Owner != null )
+ MLQuestSystem.Contexts[context.Owner] = context;
+ }
+
+ int quests = reader.ReadInt();
+
+ for ( int i = 0; i < quests; ++i )
+ MLQuest.Deserialize( reader, version );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/MLQuestSystem.cs b/Scripts/Engines/MLQuests/MLQuestSystem.cs
new file mode 100644
index 000000000..906ec6ead
--- /dev/null
+++ b/Scripts/Engines/MLQuests/MLQuestSystem.cs
@@ -0,0 +1,729 @@
+using System;
+using System.Collections.Generic;
+using Server;
+using Server.Commands;
+using Server.Engines.MLQuests.Definitions;
+using Server.Engines.MLQuests.Gumps;
+using Server.Engines.MLQuests.Objectives;
+using Server.Gumps;
+using Server.Mobiles;
+using Server.Network;
+using System.Collections;
+using Server.Commands.Generic;
+using Server.Items;
+using Server.Targeting;
+using System.IO;
+
+namespace Server.Engines.MLQuests
+{
+ public static class MLQuestSystem
+ {
+ public static bool Enabled { get { return Core.ML; } }
+
+ public const int MaxConcurrentQuests = 10;
+ public const int SpeechColor = 0x3B2;
+
+ public static readonly bool AutoGenerateNew = true;
+ public static readonly bool Debug = false;
+
+ private static Dictionary m_Quests;
+ private static Dictionary> m_QuestGivers;
+ private static Dictionary m_Contexts;
+
+ public static readonly List EmptyList = new List();
+
+ public static Dictionary Quests
+ {
+ get { return m_Quests; }
+ }
+
+ public static Dictionary> QuestGivers
+ {
+ get { return m_QuestGivers; }
+ }
+
+ public static Dictionary Contexts
+ {
+ get { return m_Contexts; }
+ }
+
+ static MLQuestSystem()
+ {
+ m_Quests = new Dictionary();
+ m_QuestGivers = new Dictionary>();
+ m_Contexts = new Dictionary();
+
+ string cfgPath = Path.Combine( Core.BaseDirectory, Path.Combine( "Data", "MLQuests.cfg" ) );
+ Type baseType = typeof( MLQuest );
+
+ if ( File.Exists( cfgPath ) )
+ {
+ using ( StreamReader sr = new StreamReader( cfgPath ) )
+ {
+ string line;
+
+ while ( ( line = sr.ReadLine() ) != null )
+ {
+ if ( line.Length == 0 || line.StartsWith( "#" ) )
+ continue;
+
+ string[] split = line.Split( '\t' );
+
+ Type type = ScriptCompiler.FindTypeByName( split[0] );
+
+ if ( type == null || !baseType.IsAssignableFrom( type ) )
+ continue;
+
+ MLQuest quest = null;
+
+ try
+ {
+ quest = Activator.CreateInstance( type ) as MLQuest;
+ }
+ catch { }
+
+ if ( quest == null )
+ continue;
+
+ Register( type, quest );
+
+ for ( int i = 1; i < split.Length; ++i )
+ {
+ Type questerType = ScriptCompiler.FindTypeByName( split[i] );
+
+ if ( questerType == null )
+ continue;
+
+ RegisterQuestGiver( quest, questerType );
+ }
+ }
+ }
+ }
+ }
+
+ private static void Register( Type type, MLQuest quest )
+ {
+ m_Quests[type] = quest;
+ }
+
+ private static void RegisterQuestGiver( MLQuest quest, Type questerType )
+ {
+ List questList;
+
+ if ( !m_QuestGivers.TryGetValue( questerType, out questList ) )
+ m_QuestGivers[questerType] = questList = new List();
+
+ questList.Add( quest );
+ }
+
+ public static void Initialize()
+ {
+ if ( !Enabled )
+ return;
+
+ if ( AutoGenerateNew )
+ {
+ foreach ( MLQuest quest in m_Quests.Values )
+ {
+ if ( quest != null && !quest.Deserialized )
+ quest.Generate();
+ }
+ }
+
+ MLQuestPersistence.EnsureExistence();
+
+ CommandSystem.Register( "MLQuestsInfo", AccessLevel.Administrator, new CommandEventHandler( MLQuestsInfo_OnCommand ) );
+ CommandSystem.Register( "SaveQuest", AccessLevel.Administrator, new CommandEventHandler( SaveQuest_OnCommand ) );
+ CommandSystem.Register( "SaveAllQuests", AccessLevel.Administrator, new CommandEventHandler( SaveAllQuests_OnCommand ) );
+ CommandSystem.Register( "InvalidQuestItems", AccessLevel.Administrator, new CommandEventHandler( InvalidQuestItems_OnCommand ) );
+
+ TargetCommands.Register( new ViewQuestsCommand() );
+ TargetCommands.Register( new ViewContextCommand() );
+
+ EventSink.QuestGumpRequest += new QuestGumpRequestHandler( EventSink_QuestGumpRequest );
+ }
+
+ [Usage( "MLQuestsInfo" )]
+ [Description( "Displays general information about the ML quest system, or a quest by type name." )]
+ public static void MLQuestsInfo_OnCommand( CommandEventArgs e )
+ {
+ Mobile m = e.Mobile;
+
+ if ( e.Length == 0 )
+ {
+ m.SendMessage( "Quest table length: {0}", m_Quests.Count );
+ return;
+ }
+
+ Type index = ScriptCompiler.FindTypeByName( e.GetString( 0 ) );
+ MLQuest quest;
+
+ if ( index == null || !m_Quests.TryGetValue( index, out quest ) )
+ {
+ m.SendMessage( "Invalid quest type name." );
+ return;
+ }
+
+ 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 );
+ }
+
+ public class ViewQuestsCommand : BaseCommand
+ {
+ public ViewQuestsCommand()
+ {
+ AccessLevel = AccessLevel.GameMaster;
+ Supports = CommandSupport.Simple;
+ Commands = new string[] { "ViewQuests" };
+ ObjectTypes = ObjectTypes.Mobiles;
+ Usage = "ViewQuests";
+ Description = "Displays a targeted mobile's quest overview.";
+ }
+
+ public override void Execute( CommandEventArgs e, object obj )
+ {
+ Mobile from = e.Mobile;
+ PlayerMobile pm = obj as PlayerMobile;
+
+ if ( pm == null )
+ {
+ LogFailure( "That is not a player." );
+ return;
+ }
+
+ CommandLogging.WriteLine( from, "{0} {1} viewing quest overview of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( pm ) );
+ from.SendGump( new QuestLogGump( pm, false ) );
+ }
+ }
+
+ private class ViewContextCommand : BaseCommand
+ {
+ public ViewContextCommand()
+ {
+ AccessLevel = AccessLevel.GameMaster;
+ Supports = CommandSupport.Simple;
+ Commands = new string[] { "ViewMLContext" };
+ ObjectTypes = ObjectTypes.Mobiles;
+ Usage = "ViewMLContext";
+ Description = "Opens the ML quest context for a targeted mobile.";
+ }
+
+ public override void Execute( CommandEventArgs e, object obj )
+ {
+ PlayerMobile pm = obj as PlayerMobile;
+
+ if ( pm == null )
+ LogFailure( "They have no ML quest context." );
+ else
+ e.Mobile.SendGump( new PropertiesGump( e.Mobile, GetOrCreateContext( pm ) ) );
+ }
+ }
+
+ [Usage( "SaveQuest [saveEnabled=true]" )]
+ [Description( "Allows serialization for a specific quest to be turned on or off." )]
+ public static void SaveQuest_OnCommand( CommandEventArgs e )
+ {
+ Mobile m = e.Mobile;
+
+ if ( e.Length == 0 || e.Length > 2 )
+ {
+ m.SendMessage( "Syntax: SaveQuest [saveEnabled=true]" );
+ return;
+ }
+
+ Type index = ScriptCompiler.FindTypeByName( e.GetString( 0 ) );
+ MLQuest quest;
+
+ if ( index == null || !m_Quests.TryGetValue( index, out quest ) )
+ {
+ m.SendMessage( "Invalid quest type name." );
+ return;
+ }
+
+ bool enable = ( e.Length == 2 ) ? e.GetBoolean( 1 ) : true;
+
+ quest.SaveEnabled = enable;
+ m.SendMessage( "Serialization for quest {0} is now {1}.", quest.GetType().Name, enable ? "enabled" : "disabled" );
+
+ if ( AutoGenerateNew && !enable )
+ m.SendMessage( "Please note that automatic generation of new quests is ON. This quest will be regenerated on the next server start." );
+ }
+
+ [Usage( "SaveAllQuests [saveEnabled=true]" )]
+ [Description( "Allows serialization for all quests to be turned on or off." )]
+ public static void SaveAllQuests_OnCommand( CommandEventArgs e )
+ {
+ Mobile m = e.Mobile;
+
+ if ( e.Length > 1 )
+ {
+ m.SendMessage( "Syntax: SaveAllQuests [saveEnabled=true]" );
+ return;
+ }
+
+ bool enable = ( e.Length == 1 ) ? e.GetBoolean( 0 ) : true;
+
+ foreach ( MLQuest quest in m_Quests.Values )
+ quest.SaveEnabled = enable;
+
+ m.SendMessage( "Serialization for all quests is now {0}.", enable ? "enabled" : "disabled" );
+
+ if ( AutoGenerateNew && !enable )
+ m.SendMessage( "Please note that automatic generation of new quests is ON. All quests will be regenerated on the next server start." );
+ }
+
+ [Usage( "InvalidQuestItems" )]
+ [Description( "Provides an overview of all quest items not located in the top-level of a player's backpack." )]
+ public static void InvalidQuestItems_OnCommand( CommandEventArgs e )
+ {
+ Mobile m = e.Mobile;
+
+ ArrayList found = new ArrayList();
+
+ foreach ( Item item in World.Items.Values )
+ {
+ if ( item.QuestItem )
+ {
+ Backpack pack = item.Parent as Backpack;
+
+ if ( pack != null )
+ {
+ PlayerMobile player = pack.Parent as PlayerMobile;
+
+ if ( player != null && player.Backpack == pack )
+ continue;
+ }
+
+ found.Add( item );
+ }
+ }
+
+ if ( found.Count == 0 )
+ m.SendMessage( "No matching objects found." );
+ else
+ m.SendGump( new InterfaceGump( m, new string[] { "Object" }, found, 0, null ) );
+ }
+
+ private static bool FindQuest( BaseCreature quester, PlayerMobile pm, out MLQuest quest, out MLQuestInstance entry )
+ {
+ quest = null;
+ entry = null;
+
+ List quests = quester.MLQuests;
+ Type questerType = quester.GetType();
+
+ MLQuestContext context = GetContext( pm );
+
+ // 1. Check quests in progress with this NPC (overriding deliveries is intended)
+ if ( context != null )
+ {
+ foreach ( MLQuest questEntry in quests )
+ {
+ MLQuestInstance instance = context.FindInstance( questEntry );
+
+ if ( instance != null && instance.QuesterType == questerType )
+ {
+ entry = instance;
+ quest = instance.Quest;
+ return true;
+ }
+ }
+ }
+
+ // 2. Check deliveries (overriding chain offers is intended)
+ if ( ( entry = HandleDelivery( pm, quester, questerType ) ) != null )
+ {
+ quest = entry.Quest;
+ return true;
+ }
+
+ // 3. Check chain quest offers
+ if ( context != null )
+ {
+ foreach ( MLQuest questEntry in quests )
+ {
+ if ( questEntry.IsChainTriggered && context.ChainOffers.Contains( questEntry ) )
+ {
+ quest = questEntry;
+ return true;
+ }
+ }
+ }
+
+ // 4. Random quest
+ quest = RandomStarterQuest( quester, pm );
+
+ return ( quest != null );
+ }
+
+ public static void OnDoubleClick( BaseCreature quester, PlayerMobile pm )
+ {
+ if ( quester.Deleted || !quester.CanGiveMLQuest || !pm.Alive )
+ return;
+
+ MLQuest quest;
+ MLQuestInstance entry;
+
+ if ( !FindQuest( quester, pm, out quest, out entry ) )
+ {
+ Tell( quester, pm, 1080107 ); // I'm sorry, I have nothing for you at this time.
+ return;
+ }
+
+ if ( entry != null && ( entry.Quester == quester || !quest.IsEscort ) ) // TODO: It's possible to move the NPC requirement to FindQuest now
+ {
+ TurnToFace( quester, pm );
+
+ if ( entry.Failed )
+ return; // Note: OSI sends no gump at all for failed quests, they have to be cancelled in the quest overview
+ else if ( entry.ClaimReward )
+ entry.SendRewardOffer();
+ else if ( entry.IsCompleted() )
+ entry.SendReportBackGump();
+ else
+ entry.SendProgressGump();
+ }
+ else if ( quest.CanOffer( quester, pm ) )
+ {
+ TurnToFace( quester, pm );
+
+ quest.SendOffer( quester, pm );
+ }
+ }
+
+ public static bool CanMarkQuestItem( PlayerMobile pm, Item item, Type type )
+ {
+ MLQuestContext context = GetContext( pm );
+
+ if ( context != null )
+ {
+ foreach ( MLQuestInstance quest in context.QuestInstances )
+ {
+ if ( !quest.ClaimReward && quest.AllowsQuestItem( item, type ) )
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static void OnMarkQuestItem( PlayerMobile pm, Item item, Type type )
+ {
+ MLQuestContext context = GetContext( pm );
+
+ if ( context == null )
+ return;
+
+ List instances = context.QuestInstances;
+
+ // We don't foreach because CheckComplete() can potentially modify the MLQuests list
+ for ( int i = instances.Count - 1; i >= 0; --i )
+ {
+ MLQuestInstance instance = instances[i];
+
+ if ( instance.ClaimReward )
+ continue;
+
+ foreach ( BaseObjectiveInstance objective in instance.Objectives )
+ {
+ if ( !objective.Expired && objective.AllowsQuestItem( item, type ) )
+ {
+ objective.CheckComplete(); // yes, this can happen multiple times (for multiple quests)
+ break;
+ }
+ }
+ }
+ }
+
+ public static bool MarkQuestItem( PlayerMobile pm, Item item )
+ {
+ Type type = item.GetType();
+
+ if ( CanMarkQuestItem( pm, item, type ) )
+ {
+ item.QuestItem = true;
+ OnMarkQuestItem( pm, item, type );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public static void HandleSkillGain( PlayerMobile pm, SkillName skill )
+ {
+ MLQuestContext context = GetContext( pm );
+
+ if ( context == null )
+ return;
+
+ List instances = context.QuestInstances;
+
+ for ( int i = instances.Count - 1; i >= 0; --i )
+ {
+ MLQuestInstance instance = instances[i];
+
+ if ( instance.ClaimReward )
+ continue;
+
+ foreach ( BaseObjectiveInstance objective in instance.Objectives )
+ {
+ if ( !objective.Expired && objective is GainSkillObjectiveInstance && ( (GainSkillObjectiveInstance)objective ).Handles( skill ) )
+ {
+ objective.CheckComplete();
+ break;
+ }
+ }
+ }
+ }
+
+ public static void HandleKill( PlayerMobile pm, Mobile mob )
+ {
+ MLQuestContext context = GetContext( pm );
+
+ if ( context == null )
+ return;
+
+ List instances = context.QuestInstances;
+
+ Type type = null;
+
+ for ( int i = instances.Count - 1; i >= 0; --i )
+ {
+ MLQuestInstance instance = instances[i];
+
+ if ( instance.ClaimReward )
+ continue;
+
+ /* A kill only counts for a single objective within a quest,
+ * but it can count for multiple quests. This is something not
+ * currently observable on OSI, so it is assumed behavior.
+ */
+ foreach ( BaseObjectiveInstance objective in instance.Objectives )
+ {
+ if ( !objective.Expired && objective is KillObjectiveInstance )
+ {
+ KillObjectiveInstance kill = (KillObjectiveInstance)objective;
+
+ if ( type == null )
+ type = mob.GetType();
+
+ if ( kill.AddKill( mob, type ) )
+ {
+ kill.CheckComplete();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ public static MLQuestInstance HandleDelivery( PlayerMobile pm, BaseCreature quester, Type questerType )
+ {
+ MLQuestContext context = GetContext( pm );
+
+ if ( context == null )
+ return null;
+
+ List instances = context.QuestInstances;
+ MLQuestInstance deliverInstance = null;
+
+ for ( int i = instances.Count - 1; i >= 0; --i )
+ {
+ MLQuestInstance instance = instances[i];
+
+ // Do NOT skip quests on ClaimReward, because the quester still needs the quest ref!
+ //if ( instance.ClaimReward )
+ // continue;
+
+ foreach ( BaseObjectiveInstance objective in instance.Objectives )
+ {
+ // Note: On OSI, expired deliveries can still be completed. Bug?
+ if ( !objective.Expired && objective is DeliverObjectiveInstance )
+ {
+ DeliverObjectiveInstance deliver = (DeliverObjectiveInstance)objective;
+
+ if ( deliver.IsDestination( quester, questerType ) )
+ {
+ if ( !deliver.HasCompleted ) // objective completes only once
+ {
+ deliver.HasCompleted = true;
+ deliver.CheckComplete();
+
+ // The quest is continued with this NPC (important for chains)
+ instance.Quester = quester;
+ }
+
+ if ( deliverInstance == null )
+ deliverInstance = instance;
+
+ break; // don't return, we may have to complete more deliveries
+ }
+ }
+ }
+ }
+
+ return deliverInstance;
+ }
+
+ public static MLQuestContext GetContext( PlayerMobile pm )
+ {
+ MLQuestContext context;
+ m_Contexts.TryGetValue( pm, out context );
+
+ return context;
+ }
+
+ public static MLQuestContext GetOrCreateContext( PlayerMobile pm )
+ {
+ MLQuestContext context;
+
+ if ( !m_Contexts.TryGetValue( pm, out context ) )
+ m_Contexts[pm] = context = new MLQuestContext( pm );
+
+ return context;
+ }
+
+ public static void HandleDeath( PlayerMobile pm )
+ {
+ MLQuestContext context = GetContext( pm );
+
+ if ( context != null )
+ context.HandleDeath();
+ }
+
+ public static void HandleDeletion( PlayerMobile pm )
+ {
+ MLQuestContext context = GetContext( pm );
+
+ if ( context != null )
+ {
+ context.HandleDeletion();
+ m_Contexts.Remove( pm );
+ }
+ }
+
+ public static void EventSink_QuestGumpRequest( QuestGumpRequestArgs args )
+ {
+ PlayerMobile pm = args.Mobile as PlayerMobile;
+
+ if ( !Enabled || pm == null )
+ return;
+
+ pm.SendGump( new QuestLogGump( pm ) );
+ }
+
+ private static List m_EligiblePool = new List();
+
+ public static MLQuest RandomStarterQuest( BaseCreature quester, PlayerMobile pm )
+ {
+ List quests = quester.MLQuests;
+
+ if ( quests.Count == 0 )
+ return null;
+
+ MLQuestContext context = GetContext( pm );
+ m_EligiblePool.Clear();
+
+ foreach ( MLQuest quest in quests )
+ {
+ if ( !quest.Activated )
+ continue;
+
+ if ( quest.IsChainTriggered )
+ continue;
+
+ if ( context != null )
+ {
+ if ( context.IsDoingQuest( quest ) )
+ continue;
+
+ // TODO: Maybe this is more complex and it checks CanOffer... but this'll do for now
+ if ( quests.Count > 1 && quest.OneTimeOnly && context.HasDoneQuest( quest ) )
+ continue;
+ }
+
+ m_EligiblePool.Add( quest );
+ }
+
+ if ( m_EligiblePool.Count == 0 )
+ return null;
+
+ return m_EligiblePool[Utility.Random( m_EligiblePool.Count )];
+ }
+
+ public static void TurnToFace( BaseCreature quester, Mobile mob )
+ {
+ quester.Direction = quester.GetDirectionTo( mob );
+ }
+
+ public static void Tell( BaseCreature quester, PlayerMobile pm, int cliloc )
+ {
+ TurnToFace( quester, pm );
+ quester.PrivateOverheadMessage( MessageType.Regular, SpeechColor, cliloc, pm.NetState );
+ }
+
+ public static void Tell( BaseCreature quester, PlayerMobile pm, int cliloc, string args )
+ {
+ TurnToFace( quester, pm );
+ quester.PrivateOverheadMessage( MessageType.Regular, SpeechColor, cliloc, args, pm.NetState );
+ }
+
+ public static void Tell( BaseCreature quester, PlayerMobile pm, string message )
+ {
+ TurnToFace( quester, pm );
+ quester.PrivateOverheadMessage( MessageType.Regular, SpeechColor, false, message, pm.NetState );
+ }
+
+ public static void TellDef( BaseCreature quester, PlayerMobile pm, TextDefinition def )
+ {
+ if ( def == null )
+ return;
+
+ if ( def.Number > 0 )
+ Tell( quester, pm, def.Number );
+ else if ( def.String != null )
+ Tell( quester, pm, def.String );
+ }
+
+ public static void WriteQuestRef( GenericWriter writer, MLQuest quest )
+ {
+ writer.Write( ( quest != null && quest.SaveEnabled ) ? quest.GetType().FullName : null );
+ }
+
+ public static MLQuest ReadQuestRef( GenericReader reader )
+ {
+ string typeName = reader.ReadString();
+
+ if ( typeName == null )
+ return null; // not serialized
+
+ Type questType = ScriptCompiler.FindTypeByFullName( typeName );
+
+ if ( questType == null )
+ return null; // no longer a type
+
+ return FindQuest( questType );
+ }
+
+ public static MLQuest FindQuest( Type questType )
+ {
+ MLQuest result;
+ m_Quests.TryGetValue( questType, out result );
+
+ return result;
+ }
+
+ public static List FindQuestList( Type questerType )
+ {
+ List result;
+
+ if ( m_QuestGivers.TryGetValue( questerType, out result ) )
+ return result;
+
+ return EmptyList;
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Mobiles/BoonCollector.cs b/Scripts/Engines/MLQuests/Mobiles/BoonCollector.cs
new file mode 100644
index 000000000..fe861ba01
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Mobiles/BoonCollector.cs
@@ -0,0 +1,427 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server.Mobiles;
+using Server.Items;
+using Server.Network;
+using Server.Engines.MLQuests.Gumps;
+using Server.Engines.MLQuests.Definitions;
+
+namespace Server.Engines.MLQuests.Mobiles
+{
+ public abstract class DoneQuestCollector : BaseCreature, IRaceChanger
+ {
+ public override bool IsInvulnerable { get { return true; } }
+
+ public abstract TextDefinition[] Offer { get; }
+ public abstract TextDefinition[] Incomplete { get; }
+ public abstract TextDefinition[] Complete { get; }
+ public abstract Type[] Needed { get; }
+
+ private InternalTimer m_Timer;
+
+ public DoneQuestCollector()
+ : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
+ {
+ }
+
+ public override void OnDoubleClick( Mobile from )
+ {
+ TryTalkTo( from, true );
+ }
+
+ public override void OnDoubleClickDead( Mobile from )
+ {
+ TryTalkTo( from, true );
+ }
+
+ public override void OnMovement( Mobile m, Point3D oldLocation )
+ {
+ if ( m.Player && InRange( m, 6 ) && !InRange( oldLocation, 6 ) )
+ TryTalkTo( m, false );
+
+ base.OnMovement( m, oldLocation );
+ }
+
+ public void TryTalkTo( Mobile from, bool fromClick )
+ {
+ if ( !from.Hidden && !from.HasGump( typeOfRaceChangeConfirmGump ) && !RaceChangeConfirmGump.IsPending( from.NetState ) && CanTalkTo( from ) )
+ TalkTo( from as PlayerMobile );
+ else if ( fromClick )
+ DenyTalk( from );
+ }
+
+ public virtual bool CanTalkTo( Mobile from )
+ {
+ return true;
+ }
+
+ public virtual void DenyTalk( Mobile from )
+ {
+ }
+
+ private static Type typeOfRaceChangeConfirmGump = typeof( RaceChangeConfirmGump );
+
+ public void TalkTo( PlayerMobile pm )
+ {
+ if ( pm == null || ( m_Timer != null && m_Timer.Running ) )
+ return;
+
+ int completed = CompletedCount( pm );
+
+ if ( completed == Needed.Length )
+ {
+ m_Timer = new InternalTimer( this, pm, Complete, true );
+ }
+ else if ( completed == 0 )
+ {
+ m_Timer = new InternalTimer( this, pm, Offer, false );
+ }
+ else
+ {
+ List conversation = new List();
+ conversation.AddRange( Incomplete );
+
+ MLQuestContext context = MLQuestSystem.GetContext( pm );
+
+ if ( context != null )
+ {
+ foreach ( Type type in Needed )
+ {
+ MLQuest quest = MLQuestSystem.FindQuest( type );
+
+ if ( quest == null || context.HasDoneQuest( quest ) )
+ continue;
+
+ conversation.Add( quest.Title );
+ }
+ }
+
+ m_Timer = new InternalTimer( this, pm, conversation, false );
+ }
+
+ m_Timer.Start();
+ }
+
+ private int CompletedCount( PlayerMobile pm )
+ {
+ MLQuestContext context = MLQuestSystem.GetContext( pm );
+
+ if ( context == null )
+ return 0;
+
+ int result = 0;
+
+ foreach ( Type type in Needed )
+ {
+ MLQuest quest = MLQuestSystem.FindQuest( type );
+
+ if ( quest == null || context.HasDoneQuest( quest ) )
+ ++result;
+ }
+
+ return result;
+ }
+
+ public bool CheckComplete( PlayerMobile pm )
+ {
+ if ( CompletedCount( pm ) == Needed.Length )
+ return true;
+
+ pm.SendLocalizedMessage( 1073644 ); // You must complete all the tasks before proceeding...
+ return false;
+ }
+
+ public void ConsumeNeeded( PlayerMobile pm )
+ {
+ MLQuestContext context = MLQuestSystem.GetContext( pm );
+
+ if ( context != null )
+ {
+ foreach ( Type type in Needed )
+ {
+ MLQuest quest = MLQuestSystem.FindQuest( type );
+
+ if ( quest != null )
+ context.RemoveDoneQuest( quest );
+ }
+ }
+ }
+
+ public void OnCancel( PlayerMobile pm )
+ {
+ pm.SendLocalizedMessage( 1073645 ); // You may try this again later...
+ }
+
+ public virtual void OnComplete( PlayerMobile pm )
+ {
+ }
+
+ public DoneQuestCollector( 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();
+ }
+
+ private class InternalTimer : Timer
+ {
+ private DoneQuestCollector m_Owner;
+ private PlayerMobile m_Target;
+ private IList m_Conversation;
+ private bool m_IsComplete;
+ private int m_Index;
+
+ private static TimeSpan GetDelay()
+ {
+ return TimeSpan.FromSeconds( Utility.RandomBool() ? 3 : 4 );
+ }
+
+ public InternalTimer( DoneQuestCollector owner, PlayerMobile target, IList conversation, bool isComplete )
+ : base( TimeSpan.Zero, GetDelay() )
+ {
+ m_Owner = owner;
+ m_Target = target;
+ m_Conversation = conversation;
+ m_IsComplete = isComplete;
+ m_Index = 0;
+ }
+
+ protected override void OnTick()
+ {
+ if ( m_Owner.Deleted )
+ {
+ Stop();
+ return;
+ }
+
+ if ( m_Index >= m_Conversation.Count )
+ {
+ if ( m_IsComplete )
+ m_Owner.OnComplete( m_Target );
+
+ Stop();
+ }
+ else
+ {
+ if ( m_Index == 0 )
+ {
+ if ( m_Target.ShowFameTitle && m_Target.Fame >= 10000 )
+ m_Owner.Say( true, String.Format( "{0} {1}", m_Target.Female ? "Lady" : "Lord", m_Target.Name ) );
+ else
+ m_Owner.Say( true, m_Target.Name );
+ }
+
+ TextDefinition.PublicOverheadMessage( m_Owner, MessageType.Regular, 0x3B2, m_Conversation[m_Index++] );
+ Interval = GetDelay();
+ }
+ }
+ }
+ }
+
+ public class Darius : DoneQuestCollector
+ {
+ private static readonly TextDefinition[] m_Offer =
+ {
+ 1073998, // Blessings of Sosaria to you and merry met, friend.
+ 1073999, // I am glad for your company and wonder if you seek the heritage of your people? I sense within you an elven bloodline -- the purity of which was lost when our brothers and sisters were exiled here in the Rupture.
+ 1074000, // If it is your desire to reclaim your place amongst the people, you must demonstrate that you understand and embrace the responsibilities expected of you as an elf.
+ 1074001, // The most basic lessons of our Sosaria are taught by her humblest children. Seek Maul, the great bear, who understands instictively the seasons.
+ 1074398, // Seek Strongroot, the great treefellow, whose very roots reach to the heart of the world. Seek Enigma, whose wisdom can only be conveyed in riddles and rhymes. Seek Bravehorn, the great hart, who exemplifies the fierce dedication of a protector of his people.
+ 1074399, // Seek the Huntsman, the centuar tasked with maintaining the balance. And lastly seek Arielle, the pixie, who has perhaps the most important lesson -- not to take yourself too seriously.
+ 1074400 // Or do none of these things. You must choose your own path in the world, and what use you'll make of your existence.
+ };
+
+ private static readonly TextDefinition[] m_Incomplete =
+ {
+ 1074002, // You have begun to walk the path of reclaiming your heritage, but you have not learned all the lessons before you.
+ 1074003 // You yet must perform these services:
+ };
+
+ private static readonly TextDefinition[] m_Complete =
+ {
+ 1074004, // You have carved a path in history, sought to understand the way from our sage companions.
+ 1074005, // And now you have returned full circle to the place of your origin within the arms of Mother Sosaria. There is but one thing left to do if you truly wish to embrace your elven heritage.
+ 1074006, // To be born once more an elf, you must strip of all worldly possessions. Nothing of man or beast much touch your skin.
+ 1074007 // Then you may step forth into history.
+ };
+
+ private static readonly Type[] m_Needed =
+ {
+ typeof( Seasons ),
+ typeof( CaretakerOfTheLand ),
+ typeof( WisdomOfTheSphynx ),
+ typeof( DefendingTheHerd ),
+ typeof( TheBalanceOfNature ),
+ typeof( TheJoysOfLife )
+ };
+
+ public override TextDefinition[] Offer { get { return m_Offer; } }
+ public override TextDefinition[] Incomplete { get { return m_Incomplete; } }
+ public override TextDefinition[] Complete { get { return m_Complete; } }
+ public override Type[] Needed { get { return m_Needed; } }
+
+ [Constructable]
+ public Darius()
+ {
+ Name = "Darius";
+ Title = "the wise";
+ Race = Race.Elf;
+ Hue = Race.RandomSkinHue();
+ SpeechHue = Utility.RandomDyedHue();
+
+ AddItem( new WildStaff() );
+ AddItem( new Sandals( 0x1BB ) );
+ AddItem( new GemmedCirclet() );
+ AddItem( new Tunic( Utility.RandomBrightHue() ) );
+
+ Utility.AssignRandomHair( this );
+
+ SetStr( 40, 50 );
+ SetDex( 60, 70 );
+ SetInt( 90, 100 ); // Verified int
+ }
+
+ public override bool CanTalkTo( Mobile from )
+ {
+ return ( from.Race == Race.Human );
+ }
+
+ public override void DenyTalk( Mobile from )
+ {
+ from.SendLocalizedMessage( 1074017 ); // He's too busy right now, so he ignores you.
+ }
+
+ public override void OnComplete( PlayerMobile from )
+ {
+ from.SendGump( new RaceChangeConfirmGump( this, from, Race.Elf ) );
+ }
+
+ public Darius( 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 class Nedrick : DoneQuestCollector
+ {
+ private static readonly TextDefinition[] m_Offer =
+ {
+ 1074403, // Greetings, traveler and welcome.
+ 1074404, // Perhaps you have heard of the service I offer? Perhaps you wish to avail yourself of the opportunity I lay before you.
+ 1074405, // Elves and humans; we lived together once in peace. Mighty relics that attest to our friendship remain, of course. Yet, memories faded when the Gem was shattered and the world torn asunder. Alone in The Heartwood, our elven brothers and sisters wondered what terrible evil had befallen Sosaria.
+ 1074406, // Violent change marked the sundering of our ties. We are different -- elves and humans. And yet we are much alike. I can give an elf the chance to walk as a human upon Sosaria. I can undertake the transformation.
+ 1074407, // But you must prove yourself to me. Humans possess a strength of character and back. Humans are quick-witted and able to pick up a smattering of nearly any talent. Humans are tough both mentally and physically. And of course, humans defend their own -- sometimes with their own lives.
+ 1074408, // Seek Sledge the Versatile and learn about human ingenuity and creativity. Seek Patricus and demonstrate your integrity and strength.
+ 1074409, // Seek out a human in need and prove your worth as a defender of humanity. Seek Belulah in Nu'Jelm and heartily challenge the elements in a display of toughness to rival any human.
+ 1074411 // Or turn away and embrace your heritage. It matters not to me.
+ };
+
+ private static readonly TextDefinition[] m_Incomplete =
+ {
+ 1074412, // You have made a good start but have more yet to do.
+ 1074413 // You must yet perform these deeds:
+ };
+
+ private static readonly TextDefinition[] m_Complete =
+ {
+ 1074410, // You have proven yourself capable and commited and so I will grant you the transformation you seek.
+ 1074531, // The first time you were born, you entered the world bare of all possessions and concerns. So too as you transform to your new life as a human, you must remove all worldly goods from the touch of your flesh.
+ 1074532 // I call upon all nearby to witness your rebirth!
+ };
+
+ private static readonly Type[] m_Needed =
+ {
+ typeof( Ingenuity ),
+ typeof( HeaveHo ),
+ typeof( HumanInNeed ),
+ typeof( AllSeasonAdventurer )
+ };
+
+ public override TextDefinition[] Offer { get { return m_Offer; } }
+ public override TextDefinition[] Incomplete { get { return m_Incomplete; } }
+ public override TextDefinition[] Complete { get { return m_Complete; } }
+ public override Type[] Needed { get { return m_Needed; } }
+
+ [Constructable]
+ public Nedrick()
+ {
+ Name = "Nedrick";
+ Title = "the iron worker";
+ Race = Race.Human;
+ Hue = Race.RandomSkinHue();
+ SpeechHue = Utility.RandomDyedHue();
+
+ AddItem( new Boots() );
+ AddItem( new LongPants( Utility.RandomNondyedHue() ) );
+ AddItem( new FancyShirt( Utility.RandomNondyedHue() ) );
+
+ Utility.AssignRandomHair( this );
+ Utility.AssignRandomFacialHair( this, HairHue );
+
+ SetStr( 70, 80 );
+ SetDex( 50, 60 );
+ SetInt( 60, 70 ); // Verified int
+ }
+
+ public override bool CanTalkTo( Mobile from )
+ {
+ return ( from.Race == Race.Elf );
+ }
+
+ public override void DenyTalk( Mobile from )
+ {
+ from.SendLocalizedMessage( 1074017 ); // He's too busy right now, so he ignores you.
+ }
+
+ public override void OnComplete( PlayerMobile from )
+ {
+ from.SendGump( new RaceChangeConfirmGump( this, from, Race.Human ) );
+ }
+
+ public Nedrick( 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();
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Mobiles/SirHelper.cs b/Scripts/Engines/MLQuests/Mobiles/SirHelper.cs
new file mode 100644
index 000000000..c6dded1d8
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Mobiles/SirHelper.cs
@@ -0,0 +1,141 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server;
+using Server.Engines.MLQuests.Gumps;
+using Server.Gumps;
+using Server.Items;
+using Server.Mobiles;
+using Server.Network;
+
+namespace Server.Engines.MLQuests.Mobiles
+{
+ public class SirHelper : Mage
+ {
+ private static readonly Gump m_Gump = new InfoNPCGump( 1078029, 1078028 );
+ private static readonly TimeSpan m_ShoutDelay = TimeSpan.FromSeconds( 20 );
+ private static readonly TimeSpan m_ShoutCooldown = TimeSpan.FromDays( 1 ); // TODO: Verify, could be a lot longer... or until a restart even
+
+ private DateTime m_NextShout;
+
+ public override bool IsActiveVendor { get { return false; } }
+
+ [Constructable]
+ public SirHelper()
+ {
+ Name = "Sir Helper";
+ Title = "the Profession Guide"; // TODO: Don't display in paperdoll
+
+ Hue = 0x83EA;
+
+ Direction = Direction.South;
+ Frozen = true;
+ }
+
+ public override void InitSBInfo()
+ {
+ }
+
+ public override bool GetGender()
+ {
+ return false; // male
+ }
+
+ public override void CheckMorph()
+ {
+ }
+
+ public override void InitOutfit()
+ {
+ HairItemID = 0x203C;
+ FacialHairItemID = 0x204D;
+ HairHue = FacialHairHue = 0x8A7;
+
+ AddItem( new Sandals() );
+
+ Item item;
+
+ item = new Cloak();
+ item.ItemID = 0x26AD;
+ item.Hue = 0x455;
+ AddItem( item );
+
+ item = new Robe();
+ item.ItemID = 0x26AE;
+ item.Hue = 0x4AB;
+ AddItem( item );
+
+ item = new Backpack();
+ item.Movable = false;
+ AddItem( item );
+ }
+
+ public override void OnDoubleClick( Mobile from )
+ {
+ if ( from.CanBeginAction( this ) )
+ {
+ from.BeginAction( this );
+ Timer.DelayCall( m_ShoutCooldown, EndLock, from );
+ }
+
+ MLQuestSystem.TurnToFace( this, from );
+ from.SendGump( m_Gump );
+
+ // Paperdoll doesn't open
+ //base.OnDoubleClick( from );
+ }
+
+ public override void OnThink()
+ {
+ base.OnThink();
+
+ if ( m_NextShout <= DateTime.Now )
+ {
+ Packet shoutPacket = null;
+
+ foreach ( NetState state in GetClientsInRange( 12 ) )
+ {
+ Mobile m = state.Mobile;
+
+ if ( m.CanSee( this ) && m.InLOS( this ) && m.CanBeginAction( this ) )
+ {
+ if ( shoutPacket == null )
+ shoutPacket = Packet.Acquire( new MessageLocalized( Serial, Body, MessageType.Regular, 946, 3, 1078099, Name, "" ) ); // Double Click On Me For Help!
+
+ state.Send( shoutPacket );
+ }
+ }
+
+ Packet.Release( shoutPacket );
+
+ m_NextShout = DateTime.Now + m_ShoutDelay;
+ }
+ }
+
+ private void EndLock( Mobile m )
+ {
+ m.EndAction( this );
+ }
+
+ public SirHelper( 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();
+
+ Frozen = true;
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Objectives/BaseObjective.cs b/Scripts/Engines/MLQuests/Objectives/BaseObjective.cs
new file mode 100644
index 000000000..277362055
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Objectives/BaseObjective.cs
@@ -0,0 +1,214 @@
+using System;
+using Server;
+using Server.Engines.MLQuests;
+using Server.Mobiles;
+using Server.Gumps;
+using System.Collections.Generic;
+
+namespace Server.Engines.MLQuests.Objectives
+{
+ public abstract class BaseObjective
+ {
+ public virtual bool IsTimed { get { return false; } }
+ public virtual TimeSpan Duration { get { return TimeSpan.Zero; } }
+
+ public BaseObjective()
+ {
+ }
+
+ public virtual bool CanOffer( BaseCreature quester, PlayerMobile pm )
+ {
+ return true;
+ }
+
+ public abstract void WriteToGump( Gump g, ref int y );
+
+ public virtual BaseObjectiveInstance CreateInstance( MLQuestInstance instance )
+ {
+ return null;
+ }
+ }
+
+ public abstract class BaseObjectiveInstance
+ {
+ private MLQuestInstance m_Instance;
+ private DateTime m_EndTime;
+ private bool m_Expired;
+
+ public MLQuestInstance Instance
+ {
+ get { return m_Instance; }
+ }
+
+ public bool IsTimed
+ {
+ get { return ( m_EndTime != DateTime.MinValue ); }
+ }
+
+ public DateTime EndTime
+ {
+ get { return m_EndTime; }
+ set { m_EndTime = value; }
+ }
+
+ public bool Expired
+ {
+ get { return m_Expired; }
+ set { m_Expired = value; }
+ }
+
+ public BaseObjectiveInstance( MLQuestInstance instance, BaseObjective obj )
+ {
+ m_Instance = instance;
+
+ if ( obj.IsTimed )
+ m_EndTime = DateTime.Now + obj.Duration;
+ }
+
+ public virtual void WriteToGump( Gump g, ref int y )
+ {
+ if ( IsTimed )
+ WriteTimeRemaining( g, ref y, ( m_EndTime > DateTime.Now ) ? ( m_EndTime - DateTime.Now ) : TimeSpan.Zero );
+ }
+
+ public static void WriteTimeRemaining( Gump g, ref int y, TimeSpan timeRemaining )
+ {
+ g.AddHtmlLocalized( 103, y, 120, 16, 1062379, 0x15F90, false, false ); // Est. time remaining:
+ g.AddLabel( 223, y, 0x481, timeRemaining.TotalSeconds.ToString( "F0" ) );
+ y += 16;
+ }
+
+ public virtual bool AllowsQuestItem( Item item, Type type )
+ {
+ return false;
+ }
+
+ public virtual bool IsCompleted()
+ {
+ return false;
+ }
+
+ public virtual void CheckComplete()
+ {
+ if ( IsCompleted() )
+ {
+ m_Instance.Player.PlaySound( 0x5B6 ); // public sound
+ m_Instance.CheckComplete();
+ }
+ }
+
+ public virtual void OnQuestAccepted()
+ {
+ }
+
+ public virtual void OnQuestCancelled()
+ {
+ }
+
+ public virtual void OnQuestCompleted()
+ {
+ }
+
+ public virtual bool OnBeforeClaimReward()
+ {
+ return true;
+ }
+
+ public virtual void OnClaimReward()
+ {
+ }
+
+ public virtual void OnAfterClaimReward()
+ {
+ }
+
+ public virtual void OnRewardClaimed()
+ {
+ }
+
+ public virtual void OnQuesterDeleted()
+ {
+ }
+
+ public virtual void OnPlayerDeath()
+ {
+ }
+
+ public virtual void OnExpire()
+ {
+ }
+
+ public enum DataType : byte
+ {
+ None,
+ EscortObjective,
+ KillObjective,
+ DeliverObjective
+ }
+
+ public virtual DataType ExtraDataType { get { return DataType.None; } }
+
+ public virtual void Serialize( GenericWriter writer )
+ {
+ // Version info is written in MLQuestPersistence.Serialize
+
+ if ( IsTimed )
+ {
+ writer.Write( true );
+ writer.WriteDeltaTime( m_EndTime );
+ }
+ else
+ {
+ writer.Write( false );
+ }
+
+ // For type checks on deserialization
+ // (This way quest objectives can be changed without breaking serialization)
+ writer.Write( (byte)ExtraDataType );
+ }
+
+ public static void Deserialize( GenericReader reader, int version, BaseObjectiveInstance objInstance )
+ {
+ if ( reader.ReadBool() )
+ {
+ DateTime endTime = reader.ReadDeltaTime();
+
+ if ( objInstance != null )
+ objInstance.EndTime = endTime;
+ }
+
+ DataType extraDataType = (DataType)reader.ReadByte();
+
+ switch ( extraDataType )
+ {
+ case DataType.EscortObjective:
+ {
+ bool completed = reader.ReadBool();
+
+ if ( objInstance is EscortObjectiveInstance )
+ ( (EscortObjectiveInstance)objInstance ).HasCompleted = completed;
+
+ break;
+ }
+ case DataType.KillObjective:
+ {
+ int slain = reader.ReadInt();
+
+ if ( objInstance is KillObjectiveInstance )
+ ( (KillObjectiveInstance)objInstance ).Slain = slain;
+
+ break;
+ }
+ case DataType.DeliverObjective:
+ {
+ bool completed = reader.ReadBool();
+
+ if ( objInstance is DeliverObjectiveInstance )
+ ( (DeliverObjectiveInstance)objInstance ).HasCompleted = completed;
+
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Objectives/CollectObjective.cs b/Scripts/Engines/MLQuests/Objectives/CollectObjective.cs
new file mode 100644
index 000000000..741c0345c
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Objectives/CollectObjective.cs
@@ -0,0 +1,258 @@
+using System;
+using Server;
+using Server.Engines.MLQuests;
+using Server.Mobiles;
+using Server.Gumps;
+using Server.Items;
+
+namespace Server.Engines.MLQuests.Objectives
+{
+ public class CollectObjective : BaseObjective
+ {
+ private int m_DesiredAmount;
+ private Type m_AcceptedType;
+ private TextDefinition m_Name;
+
+ public int DesiredAmount
+ {
+ get { return m_DesiredAmount; }
+ set { m_DesiredAmount = value; }
+ }
+
+ public Type AcceptedType
+ {
+ get { return m_AcceptedType; }
+ set { m_AcceptedType = value; }
+ }
+
+ public TextDefinition Name
+ {
+ get { return m_Name; }
+ set { m_Name = value; }
+ }
+
+ public virtual bool ShowDetailed
+ {
+ get { return true; }
+ }
+
+ public CollectObjective()
+ : this( 0, null, null )
+ {
+ }
+
+ public CollectObjective( int amount, Type type, TextDefinition name )
+ {
+ m_DesiredAmount = amount;
+ m_AcceptedType = type;
+ m_Name = name;
+ }
+
+ public bool CheckType( Type type )
+ {
+ return ( m_AcceptedType != null && m_AcceptedType.IsAssignableFrom( type ) );
+ }
+
+ public virtual bool CheckItem( Item item )
+ {
+ return true;
+ }
+
+ public static int LabelToItemID( int label )
+ {
+ int result;
+
+ if ( label < 1078872 )
+ result = ( label - 1020000 );
+ else
+ result = ( label - 1078872 );
+
+ if ( MLQuestSystem.Debug && result > 0x4000 )
+ Console.WriteLine( "Warning: cliloc {0} is likely giving the wrong item ID", label );
+
+ return result;
+ }
+
+ public override void WriteToGump( Gump g, ref int y )
+ {
+ if ( ShowDetailed )
+ {
+ string amount = m_DesiredAmount.ToString();
+
+ g.AddHtmlLocalized( 98, y, 350, 16, 1072205, 0x15F90, false, false ); // Obtain
+ g.AddLabel( 143, y, 0x481, amount );
+
+ if ( m_Name.Number > 0 )
+ {
+ g.AddHtmlLocalized( 143 + amount.Length * 15, y, 190, 18, m_Name.Number, 0x77BF, false, false );
+ g.AddItem( 350, y, LabelToItemID( m_Name.Number ) );
+ }
+ else if ( m_Name.String != null )
+ {
+ g.AddLabel( 143 + amount.Length * 15, y, 0x481, m_Name.String );
+ }
+ }
+ else
+ {
+ if ( m_Name.Number > 0 )
+ g.AddHtmlLocalized( 98, y, 312, 32, m_Name.Number, 0x15F90, false, false );
+ else if ( m_Name.String != null )
+ g.AddLabel( 98, y, 0x481, m_Name.String );
+ }
+
+ y += 32;
+ }
+
+ public override BaseObjectiveInstance CreateInstance( MLQuestInstance instance )
+ {
+ return new CollectObjectiveInstance( this, instance );
+ }
+ }
+
+ #region Timed
+
+ public class TimedCollectObjective : CollectObjective
+ {
+ private TimeSpan m_Duration;
+
+ public override bool IsTimed { get { return true; } }
+ public override TimeSpan Duration { get { return m_Duration; } }
+
+ public TimedCollectObjective( TimeSpan duration, int amount, Type type, TextDefinition name )
+ : base( amount, type, name )
+ {
+ m_Duration = duration;
+ }
+ }
+
+ #endregion
+
+ public class CollectObjectiveInstance : BaseObjectiveInstance
+ {
+ private CollectObjective m_Objective;
+
+ public CollectObjective Objective
+ {
+ get { return m_Objective; }
+ set { m_Objective = value; }
+ }
+
+ public CollectObjectiveInstance( CollectObjective objective, MLQuestInstance instance )
+ : base( instance, objective )
+ {
+ m_Objective = objective;
+ }
+
+ private int GetCurrentTotal()
+ {
+ Container pack = Instance.Player.Backpack;
+
+ if ( pack == null )
+ return 0;
+
+ Item[] items = pack.FindItemsByType( m_Objective.AcceptedType, false ); // Note: subclasses are included
+ int total = 0;
+
+ foreach ( Item item in items )
+ {
+ if ( item.QuestItem && m_Objective.CheckItem( item ) )
+ total += item.Amount;
+ }
+
+ return total;
+ }
+
+ public override bool AllowsQuestItem( Item item, Type type )
+ {
+ return ( m_Objective.CheckType( type ) && m_Objective.CheckItem( item ) );
+ }
+
+ public override bool IsCompleted()
+ {
+ return ( GetCurrentTotal() >= m_Objective.DesiredAmount );
+ }
+
+ public override void OnQuestCancelled()
+ {
+ PlayerMobile pm = Instance.Player;
+ Container pack = pm.Backpack;
+
+ if ( pack == null )
+ return;
+
+ Type checkType = m_Objective.AcceptedType;
+ Item[] items = pack.FindItemsByType( checkType, false );
+
+ foreach ( Item item in items )
+ {
+ if ( item.QuestItem && !MLQuestSystem.CanMarkQuestItem( pm, item, checkType ) ) // does another quest still need this item? (OSI just unmarks everything)
+ item.QuestItem = false;
+ }
+ }
+
+ // Should only be called after IsComplete() is checked to be true
+ public override void OnClaimReward()
+ {
+ Container pack = Instance.Player.Backpack;
+
+ if ( pack == null )
+ return;
+
+ // TODO: OSI also counts the item in the cursor?
+
+ Item[] items = pack.FindItemsByType( m_Objective.AcceptedType, false );
+ int left = m_Objective.DesiredAmount;
+
+ foreach ( Item item in items )
+ {
+ if ( item.QuestItem && m_Objective.CheckItem( item ) )
+ {
+ if ( left == 0 )
+ return;
+
+ if ( item.Amount > left )
+ {
+ item.Consume( left );
+ left = 0;
+ }
+ else
+ {
+ item.Delete();
+ left -= item.Amount;
+ }
+ }
+ }
+ }
+
+ public override void OnAfterClaimReward()
+ {
+ OnQuestCancelled(); // same thing, clear other quest items
+ }
+
+ public override void OnExpire()
+ {
+ OnQuestCancelled();
+
+ // No message
+ }
+
+ public override void WriteToGump( Gump g, ref int y )
+ {
+ m_Objective.WriteToGump( g, ref y );
+ y -= 16;
+
+ if ( m_Objective.ShowDetailed )
+ {
+ base.WriteToGump( g, ref y );
+
+ g.AddHtmlLocalized( 103, y, 120, 16, 3000087, 0x15F90, false, false ); // Total
+ g.AddLabel( 223, y, 0x481, GetCurrentTotal().ToString() );
+ y += 16;
+
+ g.AddHtmlLocalized( 103, y, 120, 16, 1074782, 0x15F90, false, false ); // Return to
+ g.AddLabel( 223, y, 0x481, Instance.GetReturnTo() );
+ y += 16;
+ }
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Objectives/DeliverObjective.cs b/Scripts/Engines/MLQuests/Objectives/DeliverObjective.cs
new file mode 100644
index 000000000..2b70a2f02
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Objectives/DeliverObjective.cs
@@ -0,0 +1,270 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server.Gumps;
+using Server.Items;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Objectives
+{
+ public class DeliverObjective : BaseObjective
+ {
+ private Type m_Delivery;
+ private int m_Amount;
+ private TextDefinition m_Name;
+ private Type m_Destination;
+ private TextDefinition m_DestinationName;
+
+ public Type Delivery
+ {
+ get { return m_Delivery; }
+ set { m_Delivery = value; }
+ }
+
+ public int Amount
+ {
+ get { return m_Amount; }
+ set { m_Amount = value; }
+ }
+
+ public TextDefinition Name
+ {
+ get { return m_Name; }
+ set { m_Name = value; }
+ }
+
+ public Type Destination
+ {
+ get { return m_Destination; }
+ set { m_Destination = value; }
+ }
+
+ public TextDefinition DestinationName
+ {
+ get { return m_DestinationName; }
+ set { m_DestinationName = value; }
+ }
+
+ public DeliverObjective( Type delivery, int amount, TextDefinition name, Type destination, TextDefinition destinationName )
+ {
+ m_Delivery = delivery;
+ m_Amount = amount;
+ m_Name = name;
+ m_Destination = destination;
+ m_DestinationName = destinationName;
+ }
+
+ public override void WriteToGump( Gump g, ref int y )
+ {
+ string amount = m_Amount.ToString();
+
+ g.AddHtmlLocalized( 98, y, 312, 16, 1072207, 0x15F90, false, false ); // Deliver
+ g.AddLabel( 143, y, 0x481, amount );
+
+ if ( m_Name.Number > 0 )
+ {
+ g.AddHtmlLocalized( 143 + amount.Length * 15, y, 190, 18, m_Name.Number, 0x77BF, false, false );
+ g.AddItem( 350, y, CollectObjective.LabelToItemID( m_Name.Number ) );
+ }
+ else if ( m_Name.String != null )
+ {
+ g.AddLabel( 143 + amount.Length * 15, y, 0x481, m_Name.String );
+ }
+
+ 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 );
+
+ y += 16;
+ }
+
+ public override BaseObjectiveInstance CreateInstance( MLQuestInstance instance )
+ {
+ return new DeliverObjectiveInstance( this, instance );
+ }
+ }
+
+ #region Timed
+
+ public class TimedDeliverObjective : DeliverObjective
+ {
+ private TimeSpan m_Duration;
+
+ 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 )
+ {
+ m_Duration = duration;
+ }
+ }
+
+ #endregion
+
+ public class DeliverObjectiveInstance : BaseObjectiveInstance
+ {
+ private DeliverObjective m_Objective;
+ private bool m_HasCompleted;
+
+ public DeliverObjective Objective
+ {
+ get { return m_Objective; }
+ set { m_Objective = value; }
+ }
+
+ public bool HasCompleted
+ {
+ get { return m_HasCompleted; }
+ set { m_HasCompleted = value; }
+ }
+
+ public DeliverObjectiveInstance( DeliverObjective objective, MLQuestInstance instance )
+ : base( instance, objective )
+ {
+ m_Objective = objective;
+ }
+
+ public virtual bool IsDestination( BaseCreature quester, Type type )
+ {
+ Type destType = m_Objective.Destination;
+
+ return ( destType != null && destType.IsAssignableFrom( type ) );
+ }
+
+ public override bool IsCompleted()
+ {
+ return m_HasCompleted;
+ }
+
+ 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
- delivery = new List
- ();
+
+ 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
+ }
+
+ // This is VERY similar to CollectObjective.GetCurrentTotal
+ private int GetCurrentTotal()
+ {
+ Container pack = Instance.Player.Backpack;
+
+ if ( pack == null )
+ return 0;
+
+ Item[] items = pack.FindItemsByType( m_Objective.Delivery, false ); // Note: subclasses are included
+ int total = 0;
+
+ foreach ( Item item in items )
+ total += item.Amount;
+
+ return total;
+ }
+
+ public override bool OnBeforeClaimReward()
+ {
+ PlayerMobile pm = Instance.Player;
+
+ int total = GetCurrentTotal();
+ int desired = m_Objective.Amount;
+
+ if ( total < desired )
+ {
+ pm.SendLocalizedMessage( 1074861 ); // You do not have everything you need!
+ pm.SendLocalizedMessage( 1074885, String.Format( "{0}\t{1}", total, desired ) ); // You have ~1_val~ item(s) but require ~2_val~
+ return false;
+ }
+
+ return true;
+ }
+
+ // TODO: This is VERY similar to CollectObjective.OnClaimReward
+ public override void OnClaimReward()
+ {
+ Container pack = Instance.Player.Backpack;
+
+ if ( pack == null )
+ return;
+
+ Item[] items = pack.FindItemsByType( m_Objective.Delivery, false );
+ int left = m_Objective.Amount;
+
+ foreach ( Item item in items )
+ {
+ if ( left == 0 )
+ break;
+
+ if ( item.Amount > left )
+ {
+ item.Consume( left );
+ left = 0;
+ }
+ else
+ {
+ item.Delete();
+ left -= item.Amount;
+ }
+ }
+ }
+
+ public override void OnQuestCancelled()
+ {
+ OnClaimReward(); // same effect
+ }
+
+ public override void OnExpire()
+ {
+ OnQuestCancelled();
+
+ Instance.Player.SendLocalizedMessage( 1074813 ); // You have failed to complete your delivery.
+ }
+
+ public override void WriteToGump( Gump g, ref int y )
+ {
+ m_Objective.WriteToGump( g, ref y );
+
+ base.WriteToGump( g, ref y );
+
+ // No extra instance stuff printed for this objective
+ }
+
+ public override DataType ExtraDataType { get { return DataType.DeliverObjective; } }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( m_HasCompleted );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Objectives/EscortObjective.cs b/Scripts/Engines/MLQuests/Objectives/EscortObjective.cs
new file mode 100644
index 000000000..872ea99e1
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Objectives/EscortObjective.cs
@@ -0,0 +1,289 @@
+using System;
+using Server;
+using Server.Engines.MLQuests;
+using Server.Mobiles;
+using Server.Gumps;
+using System.Collections.Generic;
+using Server.Misc;
+using Server.Items;
+
+namespace Server.Engines.MLQuests.Objectives
+{
+ public class EscortObjective : BaseObjective
+ {
+ private QuestArea m_Destination;
+
+ public QuestArea Destination
+ {
+ get { return m_Destination; }
+ set { m_Destination = value; }
+ }
+
+ public EscortObjective()
+ : this( null )
+ {
+ }
+
+ public EscortObjective( QuestArea destination )
+ {
+ m_Destination = destination;
+ }
+
+ public override bool CanOffer( BaseCreature quester, PlayerMobile pm )
+ {
+ BaseEscortable escortable = quester as BaseEscortable;
+
+ if ( quester.Controlled || ( escortable != null && escortable.IsBeingDeleted ) )
+ return false;
+
+ MLQuestContext context = MLQuestSystem.GetContext( pm );
+
+ if ( context != null )
+ {
+ foreach ( MLQuestInstance instance in context.QuestInstances )
+ {
+ if ( instance.Quest.IsEscort )
+ {
+ MLQuestSystem.Tell( quester, pm, 500896 ); // I see you already have an escort.
+ return false;
+ }
+ }
+ }
+
+ 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 )
+ {
+ int minutes = (int)Math.Ceiling( ( nextEscort - DateTime.Now ).TotalMinutes );
+
+ if ( minutes == 1 )
+ MLQuestSystem.Tell( quester, pm, "You must rest 1 minute before we set out on this journey." );
+ else
+ MLQuestSystem.Tell( quester, pm, 1071195, minutes.ToString() ); // You must rest ~1_minsleft~ minutes before we set out on this journey.
+
+ return false;
+ }
+
+ return true;
+ }
+
+ public override void WriteToGump( Gump g, ref int y )
+ {
+ g.AddHtmlLocalized( 98, y, 312, 16, 1072206, 0x15F90, false, false ); // Escort to
+
+ if ( m_Destination.Name.Number > 0 )
+ g.AddHtmlLocalized( 173, y, 312, 20, m_Destination.Name.Number, 0xFFFFFF, false, false );
+ else if ( m_Destination.Name.String != null )
+ g.AddLabel( 173, y, 0x481, m_Destination.Name.String );
+
+ y += 16;
+ }
+
+ public override BaseObjectiveInstance CreateInstance( MLQuestInstance instance )
+ {
+ if ( instance == null || m_Destination == null )
+ return null;
+
+ return new EscortObjectiveInstance( this, instance );
+ }
+ }
+
+ public class EscortObjectiveInstance : BaseObjectiveInstance
+ {
+ private EscortObjective m_Objective;
+ private bool m_HasCompleted;
+ private Timer m_Timer;
+ private DateTime m_LastSeenEscorter;
+
+ public bool HasCompleted
+ {
+ get { return m_HasCompleted; }
+ set { m_HasCompleted = value; }
+ }
+
+ public EscortObjectiveInstance( EscortObjective objective, MLQuestInstance instance )
+ : base( instance, objective )
+ {
+ m_Objective = objective;
+ m_HasCompleted = false;
+ m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 5 ), new TimerCallback( CheckDestination ) );
+ m_LastSeenEscorter = DateTime.Now;
+ }
+
+ public override bool IsCompleted()
+ {
+ // Once complete, it stays complete
+ return m_HasCompleted;
+ }
+
+ private void CheckDestination()
+ {
+ if ( 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
+ {
+ Abandon();
+ }
+ else if ( m_Objective.Destination.Contains( escort ) ) // We've arrived!
+ {
+ m_HasCompleted = true;
+ CheckComplete();
+ InternalOnQuestCompleted();
+ StopTimer();
+ }
+ else if ( pm.Map != escort.Map || !pm.InRange( escort, 30 ) ) // Player abandoned us (range not verified)
+ {
+ if ( m_LastSeenEscorter + BaseEscortable.AbandonDelay <= DateTime.Now )
+ Abandon();
+ }
+ else // Player is still with us
+ {
+ m_LastSeenEscorter = DateTime.Now;
+ }
+ }
+
+ private void StopTimer()
+ {
+ if ( m_Timer != null )
+ {
+ m_Timer.Stop();
+ m_Timer = null;
+ }
+ }
+
+ public static void BeginFollow( BaseCreature quester, PlayerMobile pm )
+ {
+ quester.ControlSlots = 0;
+ quester.SetControlMaster( pm );
+
+ quester.ActiveSpeed = 0.1;
+ quester.PassiveSpeed = 0.2;
+
+ quester.ControlOrder = OrderType.Follow;
+ quester.ControlTarget = pm;
+
+ quester.CantWalk = false;
+ quester.CurrentSpeed = 0.1;
+ }
+
+ public static void EndFollow( BaseCreature quester )
+ {
+ quester.ActiveSpeed = 0.2;
+ quester.PassiveSpeed = 1.0;
+
+ quester.ControlOrder = OrderType.None;
+ quester.ControlTarget = null;
+
+ quester.CurrentSpeed = 1.0;
+
+ quester.SetControlMaster( null );
+
+ if ( quester is BaseEscortable )
+ ( (BaseEscortable)quester ).BeginDelete();
+ }
+
+ public override void OnQuestAccepted()
+ {
+ MLQuestInstance instance = Instance;
+ PlayerMobile pm = instance.Player;
+
+ pm.LastEscortTime = DateTime.Now;
+
+ BeginFollow( instance.Quester, pm );
+ }
+
+ public void Abandon()
+ {
+ StopTimer();
+
+ MLQuestInstance instance = Instance;
+ BaseCreature quester = instance.Quester;
+ PlayerMobile pm = instance.Player;
+
+ if ( !quester.Deleted )
+ {
+ if ( !pm.Alive )
+ quester.Say( 500901 ); // Ack! My escort has come to haunt me!
+ else
+ quester.Say( 500902 ); // My escort seems to have abandoned me!
+
+ EndFollow( quester );
+ }
+
+ // Note: this sound is sent twice on OSI (once here and once in Cancel())
+ //m_Player.SendSound( 0x5B3 ); // private sound
+ pm.SendLocalizedMessage( 1071194 ); // You have failed your escort quest...
+
+ if ( !instance.Removed )
+ 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 )
+ return;
+
+ Abandon();
+ }
+
+ public override void OnPlayerDeath()
+ {
+ // Note: OSI also cancels it when the quest is already complete
+ if ( /*IsCompleted() ||*/ Instance.Removed )
+ return;
+
+ Instance.Cancel();
+ }
+
+ public override void OnExpire()
+ {
+ Abandon();
+ }
+
+ public override void WriteToGump( Gump g, ref int y )
+ {
+ m_Objective.WriteToGump( g, ref y );
+
+ base.WriteToGump( g, ref y );
+
+ // No extra instance stuff printed for this objective
+ }
+
+ public override DataType ExtraDataType { get { return DataType.EscortObjective; } }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( m_HasCompleted );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Objectives/GainSkillObjective.cs b/Scripts/Engines/MLQuests/Objectives/GainSkillObjective.cs
new file mode 100644
index 000000000..3a23fa927
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Objectives/GainSkillObjective.cs
@@ -0,0 +1,190 @@
+using System;
+using Server;
+using Server.Engines.MLQuests;
+using Server.Mobiles;
+using Server.Gumps;
+
+namespace Server.Engines.MLQuests.Objectives
+{
+ public enum GainSkillObjectiveFlags : byte
+ {
+ None = 0x00,
+ UseReal = 0x01,
+ Accelerate = 0x02
+ }
+
+ public class GainSkillObjective : BaseObjective
+ {
+ private SkillName m_Skill;
+ private int m_ThresholdFixed;
+ private GainSkillObjectiveFlags m_Flags;
+
+ public SkillName Skill
+ {
+ get { return m_Skill; }
+ set { m_Skill = value; }
+ }
+
+ public int ThresholdFixed
+ {
+ get { return m_ThresholdFixed; }
+ set { m_ThresholdFixed = value; }
+ }
+
+ public bool UseReal
+ {
+ get { return GetFlag( GainSkillObjectiveFlags.UseReal ); }
+ set { SetFlag( GainSkillObjectiveFlags.UseReal, value ); }
+ }
+
+ public bool Accelerate
+ {
+ get { return GetFlag( GainSkillObjectiveFlags.Accelerate ); }
+ set { SetFlag( GainSkillObjectiveFlags.Accelerate, value ); }
+ }
+
+ public GainSkillObjective()
+ : this( SkillName.Alchemy, 0 )
+ {
+ }
+
+ public GainSkillObjective( SkillName skill, int thresholdFixed )
+ : this( skill, thresholdFixed, false, false )
+ {
+ }
+
+ public GainSkillObjective( SkillName skill, int thresholdFixed, bool useReal, bool accelerate )
+ {
+ m_Skill = skill;
+ m_ThresholdFixed = thresholdFixed;
+ m_Flags = GainSkillObjectiveFlags.None;
+
+ if ( useReal )
+ m_Flags |= GainSkillObjectiveFlags.UseReal;
+
+ if ( accelerate )
+ m_Flags |= GainSkillObjectiveFlags.Accelerate;
+ }
+
+ public override bool CanOffer( BaseCreature quester, PlayerMobile pm )
+ {
+ Skill skill = pm.Skills[m_Skill];
+
+ if ( ( UseReal ? skill.Fixed : skill.BaseFixedPoint ) >= m_ThresholdFixed )
+ {
+ // On OSI both 1077772 and 1080107 are sent.
+ MLQuestSystem.Tell( quester, pm, 1077772 ); // I cannot teach you, for you know all I can teach!
+ //MLQuestSystem.Tell( quester, pm, 1080107 ); // I'm sorry, I have nothing for you at this time.
+ return false;
+ }
+
+ return true;
+ }
+
+ public override void WriteToGump( Gump g, ref int y )
+ {
+ int skillLabel = AosSkillBonuses.GetLabel( m_Skill );
+ string args;
+
+ if ( m_ThresholdFixed % 10 == 0 )
+ args = String.Format( "#{0}\t{1}", skillLabel, m_ThresholdFixed / 10 ); // as seen on OSI
+ else
+ args = String.Format( "#{0}\t{1:0.0}", skillLabel, (double)m_ThresholdFixed / 10 ); // for non-integer skill levels
+
+ g.AddHtmlLocalized( 98, y, 312, 16, 1077485, args, 0x15F90, false, false ); // Increase ~1_SKILL~ to ~2_VALUE~
+ y += 16;
+ }
+
+ public override BaseObjectiveInstance CreateInstance( MLQuestInstance instance )
+ {
+ return new GainSkillObjectiveInstance( this, instance );
+ }
+
+ private bool GetFlag( GainSkillObjectiveFlags flag )
+ {
+ return ( ( m_Flags & flag ) != 0 );
+ }
+
+ private void SetFlag( GainSkillObjectiveFlags flag, bool value )
+ {
+ if ( value )
+ m_Flags |= flag;
+ else
+ m_Flags &= ~flag;
+ }
+ }
+
+ // On OSI, once this is complete, it will *stay* complete, even if you lower your skill again
+ public class GainSkillObjectiveInstance : BaseObjectiveInstance
+ {
+ private GainSkillObjective m_Objective;
+
+ public GainSkillObjective Objective
+ {
+ get { return m_Objective; }
+ set { m_Objective = value; }
+ }
+
+ public GainSkillObjectiveInstance( GainSkillObjective objective, MLQuestInstance instance )
+ : base( instance, objective )
+ {
+ m_Objective = objective;
+ }
+
+ public bool Handles( SkillName skill )
+ {
+ return ( m_Objective.Skill == skill );
+ }
+
+ public override bool IsCompleted()
+ {
+ PlayerMobile pm = Instance.Player;
+
+ int valueFixed = m_Objective.UseReal ? pm.Skills[m_Objective.Skill].Fixed : pm.Skills[m_Objective.Skill].BaseFixedPoint;
+
+ return ( valueFixed >= m_Objective.ThresholdFixed );
+ }
+
+ // TODO: This may interfere with scrolls, or even quests among each other
+ // How does OSI deal with this?
+ public override void OnQuestAccepted()
+ {
+ if ( !m_Objective.Accelerate )
+ return;
+
+ PlayerMobile pm = Instance.Player;
+
+ pm.AcceleratedSkill = m_Objective.Skill;
+ pm.AcceleratedStart = DateTime.Now + TimeSpan.FromMinutes( 15 ); // TODO: Is there a max duration?
+ }
+
+ public override void OnQuestCancelled()
+ {
+ if ( !m_Objective.Accelerate )
+ return;
+
+ PlayerMobile pm = Instance.Player;
+
+ pm.AcceleratedStart = DateTime.Now;
+ pm.PlaySound( 0x100 );
+ }
+
+ public override void OnQuestCompleted()
+ {
+ OnQuestCancelled();
+ }
+
+ public override void WriteToGump( Gump g, ref int y )
+ {
+ m_Objective.WriteToGump( g, ref y );
+
+ base.WriteToGump( g, ref y );
+
+ if ( IsCompleted() )
+ {
+ g.AddHtmlLocalized( 113, y, 312, 20, 1055121, 0xFFFFFF, false, false ); // Complete
+ y += 16;
+ }
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Objectives/KillObjective.cs b/Scripts/Engines/MLQuests/Objectives/KillObjective.cs
new file mode 100644
index 000000000..05772adfc
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Objectives/KillObjective.cs
@@ -0,0 +1,194 @@
+using System;
+using Server;
+using Server.Engines.MLQuests;
+using Server.Mobiles;
+using Server.Gumps;
+
+namespace Server.Engines.MLQuests.Objectives
+{
+ public class KillObjective : BaseObjective
+ {
+ private int m_DesiredAmount;
+ private Type[] m_AcceptedTypes; // Example of Type[] requirement on OSI: killing X bone magis or skeletal mages (probably the same type on OSI though?)
+ private TextDefinition m_Name;
+ private QuestArea m_Area;
+
+ public int DesiredAmount
+ {
+ get { return m_DesiredAmount; }
+ set { m_DesiredAmount = value; }
+ }
+
+ public Type[] AcceptedTypes
+ {
+ get { return m_AcceptedTypes; }
+ set { m_AcceptedTypes = value; }
+ }
+
+ public TextDefinition Name
+ {
+ get { return m_Name; }
+ set { m_Name = value; }
+ }
+
+ public QuestArea Area
+ {
+ get { return m_Area; }
+ set { m_Area = value; }
+ }
+
+ public KillObjective()
+ : this( 0, null, null, null )
+ {
+ }
+
+ public KillObjective( int amount, Type[] types, TextDefinition name )
+ : this( amount, types, name, null )
+ {
+ }
+
+ public KillObjective( int amount, Type[] types, TextDefinition name, QuestArea area )
+ {
+ m_DesiredAmount = amount;
+ m_AcceptedTypes = types;
+ m_Name = name;
+ m_Area = area;
+ }
+
+ public override void WriteToGump( Gump g, ref int y )
+ {
+ string amount = m_DesiredAmount.ToString();
+
+ g.AddHtmlLocalized( 98, y, 312, 16, 1072204, 0x15F90, false, false ); // Slay
+ g.AddLabel( 133, y, 0x481, amount );
+
+ if ( m_Name.Number > 0 )
+ g.AddHtmlLocalized( 133 + amount.Length * 15, y, 190, 18, m_Name.Number, 0x77BF, false, false );
+ else if ( m_Name.String != null )
+ g.AddLabel( 133 + amount.Length * 15, y, 0x481, m_Name.String );
+
+ y += 16;
+
+ #region Location
+ if ( m_Area != null )
+ {
+ g.AddHtmlLocalized( 103, y, 312, 20, 1018327, 0x15F90, false, false ); // Location
+
+ if ( m_Area.Name.Number > 0 )
+ g.AddHtmlLocalized( 223, y, 312, 20, m_Area.Name.Number, 0xFFFFFF, false, false );
+ else if ( m_Area.Name.String != null )
+ g.AddLabel( 223, y, 0x481, m_Area.Name.String );
+
+ y += 16;
+ }
+ #endregion
+ }
+
+ public override BaseObjectiveInstance CreateInstance( MLQuestInstance instance )
+ {
+ return new KillObjectiveInstance( this, instance );
+ }
+ }
+
+ #region Timed
+
+ public class TimedKillObjective : KillObjective
+ {
+ private TimeSpan m_Duration;
+
+ public override bool IsTimed { get { return true; } }
+ public override TimeSpan Duration { get { return m_Duration; } }
+
+ public TimedKillObjective( TimeSpan duration, int amount, Type[] types, TextDefinition name )
+ : this( duration, amount, types, name, null )
+ {
+ }
+
+ public TimedKillObjective( TimeSpan duration, int amount, Type[] types, TextDefinition name, QuestArea area )
+ : base( amount, types, name, area )
+ {
+ m_Duration = duration;
+ }
+ }
+
+ #endregion
+
+ public class KillObjectiveInstance : BaseObjectiveInstance
+ {
+ private KillObjective m_Objective;
+ private int m_Slain;
+
+ public KillObjective Objective
+ {
+ get { return m_Objective; }
+ set { m_Objective = value; }
+ }
+
+ public int Slain
+ {
+ get { return m_Slain; }
+ set { m_Slain = value; }
+ }
+
+ public KillObjectiveInstance( KillObjective objective, MLQuestInstance instance )
+ : base( instance, objective )
+ {
+ m_Objective = objective;
+ m_Slain = 0;
+ }
+
+ public bool AddKill( Mobile mob, Type type )
+ {
+ int desired = m_Objective.DesiredAmount;
+
+ foreach ( Type acceptedType in m_Objective.AcceptedTypes )
+ {
+ if ( acceptedType.IsAssignableFrom( type ) )
+ {
+ if ( m_Objective.Area != null && !m_Objective.Area.Contains( mob ) )
+ return false;
+
+ PlayerMobile pm = Instance.Player;
+
+ if ( ++m_Slain >= desired )
+ pm.SendLocalizedMessage( 1075050 ); // You have killed all the required quest creatures of this type.
+ else
+ pm.SendLocalizedMessage( 1075051, ( desired - m_Slain ).ToString() ); // You have killed a quest creature. ~1_val~ more left.
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public override bool IsCompleted()
+ {
+ return ( m_Slain >= m_Objective.DesiredAmount );
+ }
+
+ public override void WriteToGump( Gump g, ref int y )
+ {
+ m_Objective.WriteToGump( g, ref y );
+
+ base.WriteToGump( g, ref y );
+
+ g.AddHtmlLocalized( 103, y, 120, 16, 3000087, 0x15F90, false, false ); // Total
+ g.AddLabel( 223, y, 0x481, m_Slain.ToString() );
+ y += 16;
+
+ g.AddHtmlLocalized( 103, y, 120, 16, 1074782, 0x15F90, false, false ); // Return to
+ g.AddLabel( 223, y, 0x481, Instance.GetReturnTo() );
+ y += 16;
+ }
+
+ public override DataType ExtraDataType { get { return DataType.KillObjective; } }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.Write( m_Slain );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/QuestArea.cs b/Scripts/Engines/MLQuests/QuestArea.cs
new file mode 100644
index 000000000..17f36808a
--- /dev/null
+++ b/Scripts/Engines/MLQuests/QuestArea.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Server.Engines.MLQuests
+{
+ public class QuestArea
+ {
+ private TextDefinition m_Name; // So we can add custom names, different from the Region name
+ private string m_RegionName;
+ private Map m_ForceMap;
+
+ public TextDefinition Name
+ {
+ get { return m_Name; }
+ set { m_Name = value; }
+ }
+
+ public string RegionName
+ {
+ get { return m_RegionName; }
+ set { m_RegionName = value; }
+ }
+
+ public Map ForceMap
+ {
+ get { return m_ForceMap; }
+ set { m_ForceMap = value; }
+ }
+
+ public QuestArea( TextDefinition name, string region )
+ : this( name, region, null )
+ {
+ }
+
+ public QuestArea( TextDefinition name, string region, Map forceMap )
+ {
+ m_Name = name;
+ m_RegionName = region;
+ m_ForceMap = forceMap;
+ }
+
+ public bool Contains( Mobile mob )
+ {
+ return Contains( mob.Region );
+ }
+
+ public bool Contains( Region reg )
+ {
+ if ( reg == null || ( m_ForceMap != null && reg.Map != m_ForceMap ) )
+ return false;
+
+ return reg.IsPartOf( m_RegionName );
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Rewards/BaseReward.cs b/Scripts/Engines/MLQuests/Rewards/BaseReward.cs
new file mode 100644
index 000000000..bd7cd794e
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Rewards/BaseReward.cs
@@ -0,0 +1,33 @@
+using System;
+using Server;
+using Server.Mobiles;
+using Server.Gumps;
+using System.Collections.Generic;
+
+namespace Server.Engines.MLQuests.Rewards
+{
+ public abstract class BaseReward
+ {
+ private TextDefinition m_Name;
+
+ public TextDefinition Name
+ {
+ get { return m_Name; }
+ set { m_Name = value; }
+ }
+
+ public BaseReward( TextDefinition name )
+ {
+ m_Name = name;
+ }
+
+ protected virtual int LabelHeight { get { return 16; } }
+
+ public void WriteToGump( Gump g, int x, ref int y )
+ {
+ TextDefinition.AddHtmlText( g, x, y, 280, LabelHeight, m_Name, false, false, 0x15F90, 0xBDE784 );
+ }
+
+ public abstract void AddRewardItems( PlayerMobile pm, List
- rewards );
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Rewards/DummyReward.cs b/Scripts/Engines/MLQuests/Rewards/DummyReward.cs
new file mode 100644
index 000000000..a1189f535
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Rewards/DummyReward.cs
@@ -0,0 +1,22 @@
+using System;
+using Server;
+using Server.Mobiles;
+using Server.Gumps;
+using System.Collections.Generic;
+
+namespace Server.Engines.MLQuests.Rewards
+{
+ public class DummyReward : BaseReward
+ {
+ public DummyReward( TextDefinition name )
+ : base( name )
+ {
+ }
+
+ protected override int LabelHeight { get { return 180; } }
+
+ public override void AddRewardItems( PlayerMobile pm, List
- rewards )
+ {
+ }
+ }
+}
diff --git a/Scripts/Engines/MLQuests/Rewards/ItemReward.cs b/Scripts/Engines/MLQuests/Rewards/ItemReward.cs
new file mode 100644
index 000000000..acf8def94
--- /dev/null
+++ b/Scripts/Engines/MLQuests/Rewards/ItemReward.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Server.Engines.MLQuests.Items;
+using Server.Mobiles;
+
+namespace Server.Engines.MLQuests.Rewards
+{
+ public class ItemReward : BaseReward
+ {
+ public static readonly ItemReward SmallBagOfTrinkets = new ItemReward( 1072268, typeof( SmallBagOfTrinkets ) ); // A small bag of trinkets.
+ public static readonly ItemReward BagOfTrinkets = new ItemReward( 1072341, typeof( BagOfTrinkets ) ); // A bag of trinkets.
+ public static readonly ItemReward BagOfTreasure = new ItemReward( 1072583, typeof( BagOfTreasure ) ); // A bag of treasure.
+ public static readonly ItemReward LargeBagOfTreasure = new ItemReward( 1072706, typeof( LargeBagOfTreasure ) ); // A large bag of treasure.
+ public static readonly ItemReward Strongbox = new ItemReward( 1072584, typeof( RewardStrongbox ) ); // A strongbox.
+
+ public static readonly ItemReward TailorSatchel = new ItemReward( 1074282, typeof( TailorSatchel ) ); // Craftsman's Satchel
+ public static readonly ItemReward BlacksmithSatchel = new ItemReward( 1074282, typeof( BlacksmithSatchel ) ); // Craftsman's Satchel
+ public static readonly ItemReward FletchingSatchel = new ItemReward( 1074282, typeof( FletchingSatchel ) ); // Craftsman's Satchel
+ public static readonly ItemReward CarpentrySatchel = new ItemReward( 1074282, typeof( CarpentrySatchel ) ); // Craftsman's Satchel
+ public static readonly ItemReward TinkerSatchel = new ItemReward( 1074282, typeof( TinkerSatchel ) ); // Craftsman's Satchel
+
+ private Type m_Type;
+ private int m_Amount;
+
+ public ItemReward()
+ : this( null, null )
+ {
+ }
+
+ public ItemReward( TextDefinition name, Type type )
+ : this( name, type, 1 )
+ {
+ }
+
+ public ItemReward( TextDefinition name, Type type, int amount )
+ : base( name )
+ {
+ m_Type = type;
+ m_Amount = amount;
+ }
+
+ public virtual Item CreateItem()
+ {
+ Item spawnedItem = null;
+
+ try
+ {
+ spawnedItem = Activator.CreateInstance( m_Type ) as Item;
+ }
+ catch ( Exception e )
+ {
+ if ( MLQuestSystem.Debug )
+ Console.WriteLine( "WARNING: ItemReward.CreateItem failed for {0}: {1}", m_Type, e );
+ }
+
+ return spawnedItem;
+ }
+
+ public override void AddRewardItems( PlayerMobile pm, List
- rewards )
+ {
+ Item reward = CreateItem();
+
+ if ( reward == null )
+ return;
+
+ if ( reward.Stackable )
+ {
+ if ( m_Amount > 1 )
+ reward.Amount = m_Amount;
+
+ rewards.Add( reward );
+ }
+ else
+ {
+ for ( int i = 0; i < m_Amount; ++i )
+ {
+ rewards.Add( reward );
+
+ if ( i < m_Amount - 1 )
+ {
+ reward = CreateItem();
+
+ if ( reward == null )
+ return;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Scripts/Engines/Spawner/Spawner.cs b/Scripts/Engines/Spawner/Spawner.cs
index b6ac9b149..ec66a7413 100644
--- a/Scripts/Engines/Spawner/Spawner.cs
+++ b/Scripts/Engines/Spawner/Spawner.cs
@@ -175,7 +175,13 @@ namespace Server.Mobiles
}
[Constructable]
- public Spawner(int amount, int minDelay, int maxDelay, int team, int homeRange, string spawnName)
+ public Spawner( int amount, int minDelay, int maxDelay, int team, int homeRange, string spawnName )
+ : this( amount, TimeSpan.FromMinutes( minDelay ), TimeSpan.FromMinutes( maxDelay ), team, homeRange, spawnName )
+ {
+ }
+
+ [Constructable]
+ public Spawner(int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, string spawnName)
: base(0x1f13)
{
List spawnNames = new List();
@@ -183,7 +189,7 @@ namespace Server.Mobiles
if (!String.IsNullOrEmpty(spawnName))
spawnNames.Add(spawnName);
- InitSpawner(amount, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), team, homeRange, spawnNames);
+ InitSpawner(amount, minDelay, maxDelay, team, homeRange, spawnNames);
}
public Spawner(int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, List spawnNames)
@@ -553,10 +559,8 @@ namespace Server.Mobiles
Point3D loc = ( spawned is BaseVendor ? this.Location : GetSpawnPosition( spawned ) );
spawned.OnBeforeSpawn( loc, map );
-
- InvalidateProperties();
-
spawned.MoveToWorld( loc, map );
+ spawned.OnAfterSpawn();
if ( spawned is BaseCreature )
{
@@ -574,6 +578,8 @@ namespace Server.Mobiles
bc.Home = this.HomeLocation;
}
+
+ InvalidateProperties();
}
public Point3D GetSpawnPosition()
diff --git a/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs b/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs
index 5bb70eef8..25e6e02d8 100644
--- a/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs
+++ b/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs
@@ -134,6 +134,8 @@ namespace Server.Items
from.SendLocalizedMessage( 1070930 ); // Can't dye artifacts or enhanced magic items that are being worn.
else if( i.IsLockedDown )
from.SendLocalizedMessage( 1070932 ); // You may not dye artifacts and enhanced magic items which are locked down.
+ else if( i.QuestItem )
+ from.SendLocalizedMessage( 1151836 ); // You may not dye toggled quest items.
else if( i is MetalPigmentsOfTokuno )
from.SendLocalizedMessage( 1042417 ); // You cannot dye that.
else if( i is LesserPigmentsOfTokuno )
diff --git a/Scripts/Engines/Virtues/VirtueHelper.cs b/Scripts/Engines/Virtues/VirtueHelper.cs
index 9ce18bb1a..6e984b675 100644
--- a/Scripts/Engines/Virtues/VirtueHelper.cs
+++ b/Scripts/Engines/Virtues/VirtueHelper.cs
@@ -1,4 +1,5 @@
using System;
+using Server.Mobiles;
namespace Server
{
@@ -86,6 +87,7 @@ namespace Server
{
return Atrophy( from, virtue, 1 );
}
+
public static bool Atrophy( Mobile from, VirtueName virtue, int amount )
{
int current = from.Virtues.GetValue( (int)virtue );
@@ -112,5 +114,49 @@ namespace Server
{
return ( GetLevel( from, virtue ) >= VirtueLevel.Knight );
}
+
+ public static void AwardVirtue( PlayerMobile pm, VirtueName virtue, int amount )
+ {
+ if ( virtue == VirtueName.Compassion )
+ {
+ if ( pm.CompassionGains > 0 && DateTime.Now > pm.NextCompassionDay )
+ {
+ pm.NextCompassionDay = DateTime.MinValue;
+ pm.CompassionGains = 0;
+ }
+
+ if ( pm.CompassionGains >= 5 )
+ {
+ pm.SendLocalizedMessage( 1053004 ); // You must wait about a day before you can gain in compassion again.
+ return;
+ }
+ }
+
+ bool gainedPath = false;
+ string virtueName = Enum.GetName( typeof( VirtueName ), virtue );
+
+ if ( VirtueHelper.Award( pm, virtue, amount, ref gainedPath ) )
+ {
+ // TODO: Localize?
+ if ( gainedPath )
+ pm.SendMessage( "You have gained a path in {0}!", virtueName );
+ else
+ pm.SendMessage( "You have gained in {0}.", virtueName );
+
+ if ( virtue == VirtueName.Compassion )
+ {
+ pm.NextCompassionDay = DateTime.Now + TimeSpan.FromDays( 1.0 );
+ ++pm.CompassionGains;
+
+ if ( pm.CompassionGains >= 5 )
+ pm.SendLocalizedMessage( 1053004 ); // You must wait about a day before you can gain in compassion again.
+ }
+ }
+ else
+ {
+ // TODO: Localize?
+ pm.SendMessage( "You have achieved the highest path of {0} and can no longer gain any further.", virtueName );
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Items/Containers/SalvageBag.cs b/Scripts/Items/Containers/SalvageBag.cs
index c55ec9c0f..1db987046 100644
--- a/Scripts/Items/Containers/SalvageBag.cs
+++ b/Scripts/Items/Containers/SalvageBag.cs
@@ -252,23 +252,22 @@ namespace Server.Items
Container sBag = this;
- List
- Scissorables = sBag.FindItemsByType
- ();
+ List
- scissorables = sBag.FindItemsByType
- ();
- for (int i = Scissorables.Count - 1; i >= 0; i--)
+ for ( int i = scissorables.Count - 1; i >= 0; --i )
+ {
+ Item item = scissorables[i];
+
+ if ( item is IScissorable )
{
- Item item = Scissorables[i];
- if( item is IScissorable )
- {
- if( ( (IScissorable)item ).Scissor( from, scissors ) )
- {
- salvaged++;
- }
- else
- {
- notSalvaged++;
- }
- }
+ IScissorable scissorable = (IScissorable)item;
+
+ if ( Scissors.CanScissor( from, scissorable ) && scissorable.Scissor( from, scissors ) )
+ ++salvaged;
+ else
+ ++notSalvaged;
}
+ }
from.SendLocalizedMessage( 1079974, String.Format( "{0}\t{1}", salvaged, salvaged + notSalvaged ) ); // Salvaged: ~1_COUNT~/~2_NUM~ tailored items
diff --git a/Scripts/Items/New Haven Quest Rewards/HammerOfHephaestus.cs b/Scripts/Items/New Haven Quest Rewards/HammerOfHephaestus.cs
new file mode 100644
index 000000000..bd324ee32
--- /dev/null
+++ b/Scripts/Items/New Haven Quest Rewards/HammerOfHephaestus.cs
@@ -0,0 +1,74 @@
+using System;
+using Server.Mobiles;
+
+namespace Server.Items
+{
+ [FlipableAttribute( 0x13E3, 0x13E4 )]
+ public class HammerOfHephaestus : SmithHammer
+ {
+ public override int LabelNumber{ get{ return 1077740; } } // Hammer of Hephaestus
+
+ public static readonly TimeSpan RechargeDelay = TimeSpan.FromMinutes( 5 );
+
+ [Constructable]
+ public HammerOfHephaestus()
+ {
+ UsesRemaining = 20;
+ LootType = LootType.Blessed;
+
+ // TODO: Blacksmith +10 bonus when equipped
+
+ StartRechargeTimer();
+ }
+
+ public override bool BreakOnDepletion { get { return false; } }
+ /* Note:
+ * On EA, it also leaves the crafting gump open when it reaches 0 charges.
+ * When crafting again, only then the crafting gump closes with the 1072306 system message.
+ */
+
+ public override void OnDoubleClick( Mobile from )
+ {
+ if ( !IsChildOf( from.Backpack ) && Parent != from ) // TODO: These checks don't match EA, but they match BaseTool for now
+ from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it.
+ else if ( UsesRemaining <= 0 )
+ from.SendLocalizedMessage( 1072306 ); // You must wait a moment for it to recharge.
+ else
+ base.OnDoubleClick( from );
+ }
+
+ private void StartRechargeTimer()
+ {
+ // TODO: Needs work
+ //Timer.DelayCall( RechargeDelay, RechargeDelay, new TimerCallback( Recharge ) );
+ }
+
+ public void Recharge()
+ {
+ // TODO: Stop timer at 20? Count downtime? Something more generic so we can use it for JacobsPickaxe too (both are IUsesRemaining)?
+ if ( UsesRemaining < 20 )
+ ++UsesRemaining;
+ }
+
+ public HammerOfHephaestus( Serial serial )
+ : base( serial )
+ {
+ }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.WriteEncodedInt( 0 ); // version
+ }
+
+ public override void Deserialize( GenericReader reader )
+ {
+ base.Deserialize( reader );
+
+ int version = reader.ReadEncodedInt();
+
+ StartRechargeTimer();
+ }
+ }
+}
diff --git a/Scripts/Items/New Haven Quest Rewards/JacobsPickaxe.cs b/Scripts/Items/New Haven Quest Rewards/JacobsPickaxe.cs
new file mode 100644
index 000000000..a36dbf355
--- /dev/null
+++ b/Scripts/Items/New Haven Quest Rewards/JacobsPickaxe.cs
@@ -0,0 +1,40 @@
+using System;
+using Server.Mobiles;
+
+namespace Server.Items
+{
+ public class JacobsPickaxe : Pickaxe
+ {
+ public override int LabelNumber{ get{ return 1077758; } } // Jacob's Pickaxe
+
+ // TODO: Recharges 1 use every 5 minutes. Doesn't break when it reaches 0, you get a system message "You must wait a moment for it to recharge" 1072306 if you attempt to use it with no uses remaining.
+
+ [Constructable]
+ public JacobsPickaxe()
+ {
+ UsesRemaining = 20;
+ LootType = LootType.Blessed;
+
+ SkillBonuses.SetValues( 0, SkillName.Mining, 10.0 );
+ }
+
+ public JacobsPickaxe( Serial serial )
+ : base( serial )
+ {
+ }
+
+ public override void Serialize( GenericWriter writer )
+ {
+ base.Serialize( writer );
+
+ writer.WriteEncodedInt( 0 ); // version
+ }
+
+ public override void Deserialize( GenericReader reader )
+ {
+ base.Deserialize( reader );
+
+ int version = reader.ReadEncodedInt();
+ }
+ }
+}
diff --git a/Scripts/Items/Skill Items/Misc/RecipeScroll.cs b/Scripts/Items/Skill Items/Misc/RecipeScroll.cs
index 5f3a7f040..7378a1ae9 100644
--- a/Scripts/Items/Skill Items/Misc/RecipeScroll.cs
+++ b/Scripts/Items/Skill Items/Misc/RecipeScroll.cs
@@ -23,13 +23,12 @@ namespace Server.Items
{
get
{
- if( Recipe.Recipes.ContainsKey( m_RecipeID ) )
+ if ( Recipe.Recipes.ContainsKey( m_RecipeID ) )
return Recipe.Recipes[m_RecipeID];
return null;
}
}
-
public override void GetProperties( ObjectPropertyList list )
{
diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs
index 397f71729..13440b1e9 100644
--- a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs
+++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs
@@ -177,7 +177,11 @@ namespace Server.Items
{
Item item = (Item)targeted;
- if ( item is IDyable && m_Tub.AllowDyables )
+ if ( item.QuestItem )
+ {
+ from.SendLocalizedMessage( 1151836 ); // You may not dye toggled quest items.
+ }
+ else if ( item is IDyable && m_Tub.AllowDyables )
{
if ( !from.InRange( m_Tub.GetWorldLocation(), 1 ) || !from.InRange( item.GetWorldLocation(), 1 ) )
from.SendLocalizedMessage( 500446 ); // That is too far away.
diff --git a/Scripts/Items/Skill Items/Tailor Items/Misc/Scissors.cs b/Scripts/Items/Skill Items/Tailor Items/Misc/Scissors.cs
index ab77d82f0..de8e82da1 100644
--- a/Scripts/Items/Skill Items/Tailor Items/Misc/Scissors.cs
+++ b/Scripts/Items/Skill Items/Tailor Items/Misc/Scissors.cs
@@ -77,15 +77,15 @@ namespace Server.Items
{
IScissorable obj = (IScissorable) targeted;
- if( obj.Scissor( from, m_Item ) )
+ if ( CanScissor( from, obj ) && obj.Scissor( from, m_Item ) )
from.PlaySound( 0x248 );
}
}
- else if( targeted is IScissorable )
+ else if ( targeted is IScissorable )
{
IScissorable obj = (IScissorable)targeted;
- if( obj.Scissor( from, m_Item ) )
+ if ( CanScissor( from, obj ) && obj.Scissor( from, m_Item ) )
from.PlaySound( 0x248 );
}
else
@@ -100,12 +100,25 @@ namespace Server.Items
{
IScissorable obj = (IScissorable) targeted;
- if ( obj.Scissor( from, m_Item ) )
+ if ( CanScissor( from, obj ) && obj.Scissor( from, m_Item ) )
from.PlaySound( 0x248 );
}
else
base.OnNonlocalTarget( from, targeted );
}
}
+
+ public static bool CanScissor( Mobile from, IScissorable obj )
+ {
+ if ( obj is Item && ( (Item)obj ).Nontransferable )
+ {
+ from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything.
+ return false;
+ }
+
+ // TODO: Move other general checks from the different implementations here
+
+ return true;
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Items/Skill Items/Tools/BaseTool.cs b/Scripts/Items/Skill Items/Tools/BaseTool.cs
index 73d2b66c8..bfe1ce1b4 100644
--- a/Scripts/Items/Skill Items/Tools/BaseTool.cs
+++ b/Scripts/Items/Skill Items/Tools/BaseTool.cs
@@ -39,6 +39,8 @@ namespace Server.Items
set { m_UsesRemaining = value; InvalidateProperties(); }
}
+ public virtual bool BreakOnDepletion { get { return true; } }
+
public void ScaleUses()
{
m_UsesRemaining = (m_UsesRemaining * GetUsesScalar()) / 100;
diff --git a/Scripts/Items/Talismans/TalismanSummons.cs b/Scripts/Items/Talismans/TalismanSummons.cs
index 520d6f08a..5b37d0def 100644
--- a/Scripts/Items/Talismans/TalismanSummons.cs
+++ b/Scripts/Items/Talismans/TalismanSummons.cs
@@ -13,10 +13,11 @@ namespace Server.Mobiles
{
public override bool Commandable{ get{ return false; } }
public override bool InitialInnocent{ get{ return true; } }
- public virtual bool IsInvulnerable{ get{ return true; } }
+ //public override bool IsInvulnerable{ get{ return true; } } // TODO: Wailing banshees are NOT invulnerable, are any of the others?
public BaseTalismanSummon() : base( AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4 )
{
+ // TODO: Stats/skills
}
public BaseTalismanSummon( Serial serial ) : base( serial )
@@ -368,8 +369,10 @@ namespace Server.Mobiles
public override void OnThink()
{
+ /*
if ( m_NextWave < DateTime.Now )
AreaHeatDamage();
+ */
}
public override void Serialize( GenericWriter writer )
@@ -386,6 +389,9 @@ namespace Server.Mobiles
int version = reader.ReadEncodedInt();
}
+ /*
+ // An area attack that only damages staff, wtf?
+
private DateTime m_NextWave;
public void AreaHeatDamage()
@@ -417,6 +423,7 @@ namespace Server.Mobiles
m_NextWave = DateTime.Now + TimeSpan.FromSeconds( 3 );
}
+ */
}
public class SummonedOrcBrute : BaseTalismanSummon
diff --git a/Scripts/Items/Weapons/Swords/BoneMachete.cs b/Scripts/Items/Weapons/Swords/BoneMachete.cs
index 17255af3d..04353b014 100644
--- a/Scripts/Items/Weapons/Swords/BoneMachete.cs
+++ b/Scripts/Items/Weapons/Swords/BoneMachete.cs
@@ -1,19 +1,31 @@
using System;
using Server.Items;
+using Server.Engines.MLQuests.Items;
namespace Server.Items
{
- public class BoneMachete : ElvenMachete
+ public class BoneMachete : ElvenMachete, ITicket
{
- public override int LabelNumber{ get{ return 1020526; } } // bone machete
+ public override WeaponAbility PrimaryAbility { get { return null; } }
+ public override WeaponAbility SecondaryAbility { get { return null; } }
+
+ public override int PhysicalResistance { get { return 1; } }
+ public override int FireResistance { get { return 1; } }
+ public override int ColdResistance { get { return 1; } }
+ public override int PoisonResistance { get { return 1; } }
+ public override int EnergyResistance { get { return 1; } }
+
+ public override int InitMinHits { get { return 5; } }
+ public override int InitMaxHits { get { return 5; } }
[Constructable]
public BoneMachete()
{
- // TODO attributes
+ ItemID = 0x20E;
}
- public BoneMachete( Serial serial ) : base( serial )
+ public BoneMachete( Serial serial )
+ : base( serial )
{
}
@@ -30,5 +42,22 @@ namespace Server.Items
int version = reader.ReadEncodedInt();
}
+
+ #region ITicket Members
+
+ public void OnTicketUsed( Mobile from )
+ {
+ if ( Utility.RandomDouble() < 0.25 )
+ {
+ from.SendLocalizedMessage( 1075007 ); // Your bone handled machete snaps in half as you force your way through the poisonous undergrowth.
+ Delete();
+ }
+ else
+ {
+ from.SendLocalizedMessage( 1075008 ); // Your bone handled machete has grown dull but you still manage to force your way past the venomous branches.
+ }
+ }
+
+ #endregion
}
}
diff --git a/Scripts/Misc/Notoriety.cs b/Scripts/Misc/Notoriety.cs
index 5a8b08b79..e9233ee8e 100644
--- a/Scripts/Misc/Notoriety.cs
+++ b/Scripts/Misc/Notoriety.cs
@@ -367,7 +367,7 @@ namespace Server.Misc
public static int MobileNotoriety( Mobile source, Mobile target )
{
- if( Core.AOS && (target.Blessed || (target is BaseVendor && ((BaseVendor)target).IsInvulnerable) || target is PlayerVendor || target is TownCrier) )
+ if ( Core.AOS && ( target.Blessed || ( target is BaseCreature && ( (BaseCreature)target ).IsInvulnerable ) || target is PlayerVendor || target is TownCrier ) )
return Notoriety.Invulnerable;
#region Dueling
diff --git a/Scripts/Misc/TextDefinition.cs b/Scripts/Misc/TextDefinition.cs
index fa4e0a98c..97221dd36 100644
--- a/Scripts/Misc/TextDefinition.cs
+++ b/Scripts/Misc/TextDefinition.cs
@@ -2,6 +2,7 @@ using System;
using System.Globalization;
using Server;
using Server.Gumps;
+using Server.Network;
namespace Server
{
@@ -14,6 +15,8 @@ namespace Server
public int Number { get { return m_Number; } }
public string String { get { return m_String; } }
+ public bool IsEmpty { get { return ( m_Number <= 0 && m_String == null ); } }
+
public TextDefinition() : this( 0, null )
{
}
@@ -142,14 +145,14 @@ namespace Server
if ( def.m_Number > 0 )
{
- if ( numberColor >= 0 )
+ if ( numberColor >= 0 ) // 5 bits per RGB component (15 bit RGB)
g.AddHtmlLocalized( x, y, width, height, def.m_Number, numberColor, back, scroll );
else
g.AddHtmlLocalized( x, y, width, height, def.m_Number, back, scroll );
}
else if ( def.m_String != null )
{
- if ( stringColor >= 0 )
+ if ( stringColor >= 0 ) // 8 bits per RGB component (24 bit RGB)
g.AddHtml( x, y, width, height, String.Format( "{1}", stringColor, def.m_String ), back, scroll );
else
g.AddHtml( x, y, width, height, def.m_String, back, scroll );
@@ -172,6 +175,17 @@ namespace Server
m.SendMessage( def.m_String );
}
+ public static void PublicOverheadMessage( Mobile m, MessageType messageType, int hue, TextDefinition def )
+ {
+ if ( def == null )
+ return;
+
+ if ( def.m_Number > 0 )
+ m.PublicOverheadMessage( messageType, hue, def.m_Number );
+ else if ( def.m_String != null )
+ m.PublicOverheadMessage( messageType, hue, false, def.m_String );
+ }
+
public static TextDefinition Parse( string value )
{
if ( value == null )
@@ -190,5 +204,10 @@ namespace Server
else
return new TextDefinition( value );
}
+
+ public static bool IsNullOrEmpty( TextDefinition def )
+ {
+ return ( def == null || def.IsEmpty );
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Mobiles/Animals/Misc/Gaman.cs b/Scripts/Mobiles/Animals/Misc/Gaman.cs
index 568776904..2bb184331 100644
--- a/Scripts/Mobiles/Animals/Misc/Gaman.cs
+++ b/Scripts/Mobiles/Animals/Misc/Gaman.cs
@@ -71,6 +71,12 @@ namespace Server.Mobiles
public override int Hides{ get{ return 15; } }
public override FoodType FavoriteFood{ get{ return FoodType.GrainsAndHay; } }
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+ c.DropItem( new GamanHorns( Utility.RandomBool() ? 1 : 2 ) );
+ }
+
public Gaman( Serial serial ) : base( serial )
{
}
diff --git a/Scripts/Mobiles/BaseCreature.cs b/Scripts/Mobiles/BaseCreature.cs
index 13e5cb12e..69035c201 100644
--- a/Scripts/Mobiles/BaseCreature.cs
+++ b/Scripts/Mobiles/BaseCreature.cs
@@ -9,6 +9,7 @@ using Server.Misc;
using Server.Items;
using Server.ContextMenus;
using Server.Engines.Quests;
+using Server.Engines.MLQuests;
using Server.Engines.PartySystem;
using Server.Factions;
using Server.SkillHandlers;
@@ -312,6 +313,86 @@ namespace Server.Mobiles
public virtual Faction FactionAllegiance{ get{ return null; } }
public virtual int FactionSilverWorth{ get{ return 30; } }
+ #region ML Quest System
+
+ private List m_MLQuests;
+
+ public List MLQuests
+ {
+ get
+ {
+ if ( m_MLQuests == null )
+ {
+ if ( StaticMLQuester )
+ m_MLQuests = MLQuestSystem.FindQuestList( GetType() );
+ else
+ m_MLQuests = ConstructQuestList();
+
+ if ( m_MLQuests == null )
+ return MLQuestSystem.EmptyList; // return EmptyList, but don't cache it (run construction again next time)
+ }
+
+ return m_MLQuests;
+ }
+ }
+
+ public virtual bool StaticMLQuester { get { return true; } }
+
+ protected virtual List ConstructQuestList()
+ {
+ return null;
+ }
+
+ public virtual bool CanGiveMLQuest { get { return ( MLQuests.Count != 0 ); } }
+ public virtual bool CanShout { get { return false; } }
+
+ public const int ShoutRange = 8;
+ public static readonly TimeSpan ShoutDelay = TimeSpan.FromMinutes( 1 );
+
+ private DateTime m_MLNextShout;
+
+ private void CheckShout( PlayerMobile pm, Point3D oldLocation )
+ {
+ if ( m_MLNextShout > DateTime.Now || pm.Hidden || !pm.Alive )
+ return;
+
+ int shoutRange = ShoutRange;
+
+ if ( !InRange( pm.Location, shoutRange ) || InRange( oldLocation, shoutRange ) || !CanSee( pm ) || !InLOS( pm ) )
+ return;
+
+ MLQuestContext context = MLQuestSystem.GetContext( pm );
+
+ if ( context != null && context.IsFull )
+ return;
+
+ MLQuest quest = MLQuestSystem.RandomStarterQuest( this, pm );
+
+ if ( quest == null || !quest.Activated || ( context != null && context.IsDoingQuest( quest ) ) )
+ return;
+
+ Shout( pm );
+ m_MLNextShout = DateTime.Now + ShoutDelay;
+ }
+
+ public virtual void Shout( PlayerMobile pm )
+ {
+ }
+
+ 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
public const bool BondingEnabled = true;
@@ -784,6 +865,8 @@ namespace Server.Mobiles
#endregion
+ public virtual bool IsInvulnerable { get { return false; } }
+
public BaseAI AIObject{ get{ return m_AI; } }
public const int MaxOwners = 5;
@@ -1647,7 +1730,13 @@ namespace Server.Mobiles
if ( speechType != null )
speechType.OnConstruct( this );
+ if ( IsInvulnerable && !Core.AOS )
+ NameHue = 0x35;
+
GenerateLoot( true );
+
+ if ( MLQuestSystem.Enabled && StaticMLQuester )
+ RegisterQuests();
}
public BaseCreature( Serial serial ) : base( serial )
@@ -2010,6 +2099,9 @@ namespace Server.Mobiles
Hue = Paragon.Hue; //Paragon hue fixed, should now be 0x501.
}
+ if ( Core.AOS && NameHue == 0x35 )
+ NameHue = -1;
+
CheckStatTimers();
ChangeAIType(m_CurrentAI);
@@ -2018,6 +2110,9 @@ namespace Server.Mobiles
if ( IsAnimatedDead )
Spells.Necromancy.AnimateDeadSpell.Register( m_SummonMaster, this );
+
+ if ( MLQuestSystem.Enabled && StaticMLQuester )
+ RegisterQuests();
}
public virtual bool IsHumanInTown()
@@ -2283,6 +2378,14 @@ namespace Server.Mobiles
else if ( CheckGold( from, dropped ) )
return true;
+ // Note: Yes, this happens for all questers (regardless of type, e.g. escorts),
+ // even if they can't offer you anything at the moment
+ if ( MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile )
+ {
+ MLQuestSystem.Tell( this, (PlayerMobile)from, 1074893 ); // You need to mark your quest items so I don't take the wrong object. Then speak to me.
+ return false;
+ }
+
return base.OnDragDrop( from, dropped );
}
@@ -2886,6 +2989,9 @@ namespace Server.Mobiles
if ( IsAnimatedDead )
Spells.Necromancy.AnimateDeadSpell.Unregister( m_SummonMaster, this );
+ if ( MLQuestSystem.Enabled )
+ UnregisterQuests();
+
base.OnAfterDelete();
}
@@ -3549,6 +3655,9 @@ namespace Server.Mobiles
}
/* End notice sound */
+ if ( MLQuestSystem.Enabled && CanShout && m is PlayerMobile )
+ CheckShout( (PlayerMobile)m, oldLocation );
+
if ( m_NoDupeGuards == m )
return;
@@ -4323,6 +4432,9 @@ namespace Server.Mobiles
}
}
+ if ( MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile )
+ MLQuestSystem.OnDoubleClick( this, (PlayerMobile)from );
+
base.OnDoubleClick( from );
}
@@ -4362,6 +4474,9 @@ namespace Server.Mobiles
{
base.AddNameProperties( list );
+ if ( MLQuestSystem.Enabled && CanGiveMLQuest )
+ list.Add( 1072269 ); // Quest Giver
+
if ( Core.ML )
{
if ( DisplayWeight )
@@ -4720,6 +4835,7 @@ namespace Server.Mobiles
{
int totalFame = Fame / 100;
int totalKarma = -Karma / 100;
+
if (Map == Map.Felucca)
{
totalFame += ((totalFame/10)*3);
@@ -4794,13 +4910,21 @@ namespace Server.Mobiles
TreasuresOfTokuno.HandleKill( this, ds.m_Mobile );
}
- if ( givenQuestKill )
- continue;
-
PlayerMobile pm = ds.m_Mobile as PlayerMobile;
if ( pm != null )
{
+ if ( MLQuestSystem.Enabled )
+ {
+ MLQuestSystem.HandleKill( pm, this );
+
+ // Kills are given to *everyone* with looting right in the ML quest system
+ //givenQuestKill = true;
+ }
+
+ if ( givenQuestKill )
+ continue;
+
QuestSystem qs = pm.Quest;
if ( qs != null )
@@ -4810,6 +4934,7 @@ namespace Server.Mobiles
}
}
}
+
for ( int i = 0; i < titles.Count; ++i )
{
Titles.AwardFame( titles[ i ], fame[ i ], true );
@@ -4862,12 +4987,12 @@ namespace Server.Mobiles
if ( target is BaseFactionGuard )
return false;
- if ( (target is BaseVendor && ((BaseVendor)target).IsInvulnerable) || target is PlayerVendor || target is TownCrier )
+ if ( ( target is BaseCreature && ( (BaseCreature)target ).IsInvulnerable ) || target is PlayerVendor || target is TownCrier )
{
if ( message )
{
if ( target.Title == null )
- SendMessage( "{0} the vendor cannot be harmed.", target.Name );
+ SendMessage( "{0} cannot be harmed.", target.Name );
else
SendMessage( "{0} {1} cannot be harmed.", target.Name, target.Title );
}
@@ -5501,7 +5626,7 @@ namespace Server.Mobiles
public override bool CanBeDamaged()
{
- if ( IsDeadPet )
+ if ( IsDeadPet || IsInvulnerable )
return false;
return base.CanBeDamaged();
diff --git a/Scripts/Mobiles/Healers/EvilWanderingHealer.cs b/Scripts/Mobiles/Healers/EvilWanderingHealer.cs
index 916274bc3..9a50e0dac 100644
--- a/Scripts/Mobiles/Healers/EvilWanderingHealer.cs
+++ b/Scripts/Mobiles/Healers/EvilWanderingHealer.cs
@@ -47,6 +47,14 @@ namespace Server.Mobiles
return true;
}
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ if ( Utility.RandomDouble() < 0.5 )
+ c.DropItem( new FragmentOfAMap() );
+ }
+
public EvilWanderingHealer( Serial serial ) : base( serial )
{
}
diff --git a/Scripts/Mobiles/Healers/FortuneTeller.cs b/Scripts/Mobiles/Healers/FortuneTeller.cs
index 67487e387..145d910d5 100644
--- a/Scripts/Mobiles/Healers/FortuneTeller.cs
+++ b/Scripts/Mobiles/Healers/FortuneTeller.cs
@@ -42,7 +42,7 @@ namespace Server.Mobiles
public override int GetRobeColor()
{
- return RandomBrightHue();
+ return Utility.RandomBrightHue();
}
public override void InitOutfit()
@@ -51,9 +51,9 @@ namespace Server.Mobiles
switch ( Utility.Random( 3 ) )
{
- case 0: AddItem( new SkullCap( RandomBrightHue() ) ); break;
- case 1: AddItem( new WizardsHat( RandomBrightHue() ) ); break;
- case 2: AddItem( new Bandana( RandomBrightHue() ) ); break;
+ case 0: AddItem( new SkullCap( Utility.RandomBrightHue() ) ); break;
+ case 1: AddItem( new WizardsHat( Utility.RandomBrightHue() ) ); break;
+ case 2: AddItem( new Bandana( Utility.RandomBrightHue() ) ); break;
}
AddItem( new Spellbook() );
diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Brigand.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Brigand.cs
index 57134fe6f..ec91b864f 100644
--- a/Scripts/Mobiles/Monsters/Humanoid/Melee/Brigand.cs
+++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Brigand.cs
@@ -65,6 +65,14 @@ namespace Server.Mobiles
Utility.AssignRandomHair( this );
}
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ if ( Utility.RandomDouble() < 0.9 )
+ c.DropItem( new SeveredHumanEars() );
+ }
+
public override void GenerateLoot()
{
AddLoot( LootPack.Average );
diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs
index 795e506dd..73d964e42 100644
--- a/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs
+++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs
@@ -59,6 +59,15 @@ namespace Server.Mobiles
PackItem( Loot.RandomNecromancyReagent() );
}
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ // TODO: Check drop rate
+ if ( Utility.RandomDouble() < 0.05 )
+ c.DropItem( new StoutWhip() );
+ }
+
public override void GenerateLoot()
{
AddLoot( LootPack.Meager, 2 );
diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Abscess.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Abscess.cs
new file mode 100644
index 000000000..cdb8bb47c
--- /dev/null
+++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Abscess.cs
@@ -0,0 +1,79 @@
+using System;
+using Server;
+using Server.Items;
+
+namespace Server.Mobiles
+{
+ [CorpseName( "an Abscess corpse" )]
+ public class Abscess : Hydra
+ {
+ [Constructable]
+ public Abscess()
+ {
+ IsParagon = true;
+
+ Name = "Abscess";
+ Hue = 0x8FD;
+
+ SetStr( 845, 871 );
+ SetDex( 121, 134 );
+ SetInt( 124, 142 );
+
+ SetHits( 7470, 7540 );
+
+ SetDamage( 26, 31 );
+
+ SetDamageType( ResistanceType.Physical, 60 );
+ SetDamageType( ResistanceType.Fire, 10 );
+ SetDamageType( ResistanceType.Cold, 10 );
+ SetDamageType( ResistanceType.Poison, 10 );
+ SetDamageType( ResistanceType.Energy, 10 );
+
+ SetResistance( ResistanceType.Physical, 65, 75 );
+ SetResistance( ResistanceType.Fire, 70, 80 );
+ SetResistance( ResistanceType.Cold, 25, 35 );
+ SetResistance( ResistanceType.Poison, 35, 45 );
+ SetResistance( ResistanceType.Energy, 35, 45 );
+
+ SetSkill( SkillName.Wrestling, 132.3, 143.8 );
+ SetSkill( SkillName.Tactics, 121.0, 130.5 );
+ SetSkill( SkillName.MagicResist, 102.9, 119.0 );
+ SetSkill( SkillName.Anatomy, 91.8, 94.3 );
+
+ // TODO: Fame/Karma
+ }
+
+ public override void GenerateLoot()
+ {
+ AddLoot( LootPack.UltraRich, 4 );
+ }
+
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ c.DropItem( new AbscessTail() );
+ }
+
+ public override bool GivesMLMinorArtifact { get { return true; } }
+
+ public Abscess( 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();
+ }
+ }
+}
diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Coil.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Coil.cs
new file mode 100644
index 000000000..862aeac34
--- /dev/null
+++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Coil.cs
@@ -0,0 +1,106 @@
+using System;
+using Server;
+using Server.Items;
+
+namespace Server.Mobiles
+{
+ [CorpseName( "a Coil corpse" )]
+ public class Coil : SilverSerpent
+ {
+ // TODO: Check faction allegiance
+
+ [Constructable]
+ public Coil()
+ {
+ IsParagon = true;
+
+ Name = "Coil";
+ Hue = 0x3F;
+
+ SetStr( 205, 343 );
+ SetDex( 202, 283 );
+ SetInt( 88, 142 );
+
+ SetHits( 628, 1291 );
+
+ SetDamage( 19, 28 );
+
+ SetDamageType( ResistanceType.Physical, 50 );
+ SetDamageType( ResistanceType.Poison, 50 );
+
+ SetResistance( ResistanceType.Physical, 56, 62 );
+ SetResistance( ResistanceType.Fire, 25, 30 );
+ SetResistance( ResistanceType.Cold, 25, 30 );
+ SetResistance( ResistanceType.Poison, 100 );
+ SetResistance( ResistanceType.Energy, 25, 30 );
+
+ SetSkill( SkillName.Wrestling, 124.5, 141.3 );
+ SetSkill( SkillName.Tactics, 130.2, 142.0 );
+ SetSkill( SkillName.MagicResist, 102.3, 113.0 );
+ SetSkill( SkillName.Anatomy, 120.8, 138.1 );
+ SetSkill( SkillName.Poisoning, 110.1, 133.4 );
+
+ // TODO: Fame/Karma
+
+ PackGem( 2 );
+ PackItem( new Bone() );
+ }
+
+ public override void GenerateLoot()
+ {
+ AddLoot( LootPack.UltraRich, 3 );
+ }
+
+ public override WeaponAbility GetWeaponAbility()
+ {
+ return WeaponAbility.MortalStrike;
+ }
+
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ c.DropItem( new CoilsFang() );
+
+ /*
+ // TODO: uncomment once added
+ if ( Utility.RandomDouble() < 0.025 )
+ {
+ switch ( Utility.Random( 5 ) )
+ {
+ case 0: c.DropItem( new AssassinChest() ); break;
+ case 1: c.DropItem( new DeathGloves() ); break;
+ case 2: c.DropItem( new LeafweaveLegs() ); break;
+ case 3: c.DropItem( new HunterLegs() ); break;
+ case 4: c.DropItem( new MyrmidonLegs() ); break;
+ }
+ }
+ */
+ }
+
+ public override Poison HitPoison { get { return Poison.Lethal; } }
+ public override Poison PoisonImmune { get { return Poison.Lethal; } }
+ public override bool GivesMLMinorArtifact { get { return true; } }
+ public override int Hides { get { return 48; } }
+ public override int Meat { get { return 1; } }
+
+ public Coil( 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();
+ }
+ }
+}
diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/EnslavedSatyr.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/EnslavedSatyr.cs
new file mode 100644
index 000000000..05baefcce
--- /dev/null
+++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/EnslavedSatyr.cs
@@ -0,0 +1,46 @@
+using System;
+using Server;
+using Server.Items;
+
+namespace Server.Mobiles
+{
+ [CorpseName( "an enslaved satyr corpse" )]
+ public class EnslavedSatyr : Satyr
+ {
+ [Constructable]
+ public EnslavedSatyr()
+ {
+ Name = "an enslaved satyr";
+ }
+
+ /*
+ // TODO: uncomment once added
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ if ( Utility.RandomDouble() < 0.1 )
+ c.DropItem( new ParrotItem() );
+ }
+ */
+
+ public EnslavedSatyr( 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();
+ }
+ }
+}
diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs
new file mode 100644
index 000000000..89e176c3c
--- /dev/null
+++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs
@@ -0,0 +1,91 @@
+using System;
+using Server;
+using Server.Items;
+
+namespace Server.Mobiles
+{
+ [CorpseName( "a hydra corpse" )]
+ public class Hydra : BaseCreature
+ {
+ [Constructable]
+ public Hydra()
+ : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 )
+ {
+ Name = "a hydra";
+ Body = 0x109;
+ BaseSoundID = 0x16A;
+
+ SetStr( 801, 828 );
+ SetDex( 102, 118 );
+ SetInt( 102, 120 );
+
+ SetHits( 1480, 1500 );
+
+ SetDamage( 21, 26 );
+
+ SetDamageType( ResistanceType.Physical, 60 );
+ SetDamageType( ResistanceType.Fire, 10 );
+ SetDamageType( ResistanceType.Cold, 10 );
+ SetDamageType( ResistanceType.Poison, 10 );
+ SetDamageType( ResistanceType.Energy, 10 );
+
+ SetResistance( ResistanceType.Physical, 65, 75 );
+ SetResistance( ResistanceType.Fire, 70, 85 );
+ SetResistance( ResistanceType.Cold, 25, 35 );
+ SetResistance( ResistanceType.Poison, 35, 43 );
+ SetResistance( ResistanceType.Energy, 36, 45 );
+
+ SetSkill( SkillName.Wrestling, 103.5, 117.4 );
+ SetSkill( SkillName.Tactics, 100.1, 109.8 );
+ SetSkill( SkillName.MagicResist, 85.5, 98.5 );
+ SetSkill( SkillName.Anatomy, 75.4, 79.8 );
+
+ // TODO: Fame/Karma
+ }
+
+ public override void GenerateLoot()
+ {
+ AddLoot( LootPack.UltraRich, 3 );
+ }
+
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ c.DropItem( new HydraScale() );
+
+ /*
+ // TODO: uncomment once added
+ if ( Utility.RandomDouble() < 0.2 )
+ c.DropItem( new ParrotItem() );
+
+ if ( Utility.RandomDouble() < 0.05 )
+ c.DropItem( new ThorvaldsMedallion() );
+ */
+ }
+
+ public override bool HasBreath { get { return true; } }
+ public override int Hides { get { return 40; } }
+ public override int Meat { get { return 19; } }
+ public override int TreasureMapLevel { get { return 5; } }
+
+ public Hydra( 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();
+ }
+ }
+}
diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/InsaneDryad.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/InsaneDryad.cs
new file mode 100644
index 000000000..c4222b8d8
--- /dev/null
+++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/InsaneDryad.cs
@@ -0,0 +1,50 @@
+using System;
+using Server;
+using Server.Items;
+
+namespace Server.Mobiles
+{
+ [CorpseName( "an insane dryad corpse" )]
+ public class InsaneDryad : MLDryad
+ {
+ public override bool InitialInnocent { get { return false; } }
+
+ [Constructable]
+ public InsaneDryad()
+ {
+ Name = "an insane dryad";
+
+ // TODO: Perhaps these should have negative karma?
+ }
+
+ /*
+ // TODO: uncomment once added
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ if ( Utility.RandomDouble() < 0.1 )
+ c.DropItem( new ParrotItem() );
+ }
+ */
+
+ public InsaneDryad( 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();
+ }
+ }
+}
diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Saliva.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Saliva.cs
new file mode 100644
index 000000000..c39008bac
--- /dev/null
+++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Saliva.cs
@@ -0,0 +1,77 @@
+using System;
+using Server;
+using Server.Items;
+
+namespace Server.Mobiles
+{
+ [CorpseName( "a Saliva corpse" )]
+ public class Saliva : Harpy
+ {
+ [Constructable]
+ public Saliva()
+ {
+ // TODO: Not a paragon? No ML arties?
+ // It moves like a paragon on OSI...
+
+ Name = "Saliva";
+ Hue = 0x11E;
+
+ SetStr( 110, 206 );
+ SetDex( 123, 222 );
+ SetInt( 80, 127 );
+
+ SetHits( 409, 842 );
+
+ SetDamage( 20, 22 );
+
+ SetDamageType( ResistanceType.Physical, 100 );
+
+ SetResistance( ResistanceType.Physical, 46, 48 );
+ SetResistance( ResistanceType.Fire, 32, 40 );
+ SetResistance( ResistanceType.Cold, 34, 49 );
+ SetResistance( ResistanceType.Poison, 40, 48 );
+ SetResistance( ResistanceType.Energy, 35, 39 );
+
+ SetSkill( SkillName.Wrestling, 106.4, 128.8 );
+ SetSkill( SkillName.Tactics, 129.9, 141.0 );
+ SetSkill( SkillName.MagicResist, 84.3, 105.0 );
+
+ // TODO: Fame/Karma?
+ }
+
+ public override void GenerateLoot()
+ {
+ AddLoot( LootPack.UltraRich, 2 );
+ }
+
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ c.DropItem( new SalivasFeather() );
+
+ // TODO: uncomment once added
+ //if ( Utility.RandomDouble() < 0.1 )
+ // c.DropItem( new ParrotItem() );
+ }
+
+ public Saliva( 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();
+ }
+ }
+}
diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Tangle.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Tangle.cs
new file mode 100644
index 000000000..158122ff8
--- /dev/null
+++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Tangle.cs
@@ -0,0 +1,78 @@
+using System;
+using Server;
+using Server.Items;
+
+namespace Server.Mobiles
+{
+ [CorpseName( "a Tangle corpse" )]
+ public class Tangle : BogThing
+ {
+ [Constructable]
+ public Tangle()
+ {
+ // TODO: Not a paragon? No ML arties?
+ // It moves like a paragon on OSI...
+
+ Name = "Tangle";
+ Hue = 0x21;
+
+ SetStr( 870, 940 );
+ SetDex( 58, 74 );
+ SetInt( 46, 58 );
+
+ SetHits( 2468, 2733 );
+ SetMana( 8, 12 );
+
+ SetDamage( 15, 28 );
+
+ SetDamageType( ResistanceType.Physical, 60 );
+ SetDamageType( ResistanceType.Poison, 40 );
+
+ SetResistance( ResistanceType.Physical, 50, 57 );
+ SetResistance( ResistanceType.Fire, 40, 43 );
+ SetResistance( ResistanceType.Cold, 30, 35 );
+ SetResistance( ResistanceType.Poison, 61, 69 );
+ SetResistance( ResistanceType.Energy, 41, 45 );
+
+ SetSkill( SkillName.Wrestling, 77.8, 94.6 );
+ SetSkill( SkillName.Tactics, 90.6, 100.4 );
+ SetSkill( SkillName.MagicResist, 108.4, 114.0 );
+
+ // TODO: Fame/Karma?
+ }
+
+ public override void GenerateLoot()
+ {
+ AddLoot( LootPack.UltraRich, 3 );
+ }
+
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ if ( Utility.RandomDouble() < 0.3 )
+ c.DropItem( new TaintedSeeds() );
+ }
+
+ public override Poison PoisonImmune { get { return Poison.Lethal; } }
+
+ public Tangle( 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();
+ }
+ }
+}
diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Thrasher.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Thrasher.cs
new file mode 100644
index 000000000..ccd413af3
--- /dev/null
+++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Thrasher.cs
@@ -0,0 +1,81 @@
+using System;
+using Server;
+using Server.Items;
+
+namespace Server.Mobiles
+{
+ [CorpseName( "a Thrasher corpse" )]
+ public class Thrasher : Alligator
+ {
+ [Constructable]
+ public Thrasher()
+ {
+ IsParagon = true;
+
+ Name = "Thrasher";
+ Hue = 0x497;
+
+ SetStr( 93, 327 );
+ SetDex( 7, 201 );
+ SetInt( 15, 67 );
+
+ SetHits( 260, 984 );
+ SetStam( 56, 75 );
+ SetMana( 25, 30 );
+
+ SetDamage( 20, 30 );
+
+ SetDamageType( ResistanceType.Physical, 100 );
+
+ SetResistance( ResistanceType.Physical, 50, 55 );
+ SetResistance( ResistanceType.Fire, 25, 29 );
+ SetResistance( ResistanceType.Poison, 25, 28 );
+
+ SetSkill( SkillName.Wrestling, 101.2, 118.3 );
+ SetSkill( SkillName.Tactics, 96.3, 117.3 );
+ SetSkill( SkillName.MagicResist, 102.4, 118.6 );
+
+ // TODO: Fame/Karma
+ }
+
+ public override void GenerateLoot()
+ {
+ AddLoot( LootPack.FilthyRich, 4 );
+ }
+
+ public override WeaponAbility GetWeaponAbility()
+ {
+ return WeaponAbility.ArmorIgnore;
+ }
+
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ c.DropItem( new ThrashersTail() );
+ }
+
+ public override bool GivesMLMinorArtifact { get { return true; } }
+ public override int Hides { get { return 48; } }
+ public override int Meat { get { return 1; } }
+
+ public Thrasher( 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();
+ }
+ }
+}
diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs
index 4f1928748..5c69dd165 100644
--- a/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs
+++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs
@@ -54,6 +54,14 @@ namespace Server.Mobiles
AddLoot( LootPack.Rich ); // Need to verify
}
+ public override void OnDeath( Container c )
+ {
+ base.OnDeath( c );
+
+ if ( Utility.RandomDouble() < 0.1 )
+ c.DropItem( new PrimitiveFetish() );
+ }
+
public Troglodyte( Serial serial ) : base( serial )
{
}
diff --git a/Scripts/Mobiles/PlayerMobile.cs b/Scripts/Mobiles/PlayerMobile.cs
index 142c277d7..5392dc870 100644
--- a/Scripts/Mobiles/PlayerMobile.cs
+++ b/Scripts/Mobiles/PlayerMobile.cs
@@ -24,6 +24,7 @@ using Server.Engines.CannedEvil;
using Server.Engines.Craft;
using Server.Spells.Spellweaving;
using Server.Engines.PartySystem;
+using Server.Engines.MLQuests;
namespace Server.Mobiles
{
@@ -112,7 +113,7 @@ namespace Server.Mobiles
private int m_Profession;
private bool m_IsStealthing; // IsStealthing should be moved to Server.Mobiles
private bool m_IgnoreMobiles; // IgnoreMobiles should be moved to Server.Mobiles
- private int m_NonAutoreinsuredItems; // number of items that could not be automaitically reinsured because gold in bank was not enough
+ private int m_NonAutoreinsuredItems; // number of items that could not be automatically reinsured because gold in bank was not enough
private bool m_NinjaWepCooldown;
/*
* a value of zero means, that the mobile is not executing the spell. Otherwise,
@@ -1257,12 +1258,12 @@ namespace Server.Mobiles
if ( m_DesignContext != null || (target is PlayerMobile && ((PlayerMobile)target).m_DesignContext != null) )
return false;
- if ( (target is BaseVendor && ((BaseVendor)target).IsInvulnerable) || target is PlayerVendor || target is TownCrier )
+ if ( (target is BaseCreature && ((BaseCreature)target).IsInvulnerable) || target is PlayerVendor || target is TownCrier )
{
if ( message )
{
if ( target.Title == null )
- SendMessage( "{0} the vendor cannot be harmed.", target.Name );
+ SendMessage( "{0} cannot be harmed.", target.Name );
else
SendMessage( "{0} {1} cannot be harmed.", target.Name, target.Title );
}
@@ -1590,14 +1591,20 @@ namespace Server.Mobiles
if ( m_Quest != null )
m_Quest.GetContextMenuEntries( list );
- if ( Alive && InsuranceEnabled )
+ if ( Alive )
{
- list.Add( new CallbackEntry( 6201, new ContextCallback( ToggleItemInsurance ) ) );
+ if ( InsuranceEnabled )
+ {
+ list.Add( new CallbackEntry( 6201, new ContextCallback( ToggleItemInsurance ) ) ); // Toggle Item Insurance
- if ( AutoRenewInsurance )
- list.Add( new CallbackEntry( 6202, new ContextCallback( CancelRenewInventoryInsurance ) ) );
- else
- list.Add( new CallbackEntry( 6200, new ContextCallback( AutoRenewInventoryInsurance ) ) );
+ if ( AutoRenewInsurance )
+ list.Add( new CallbackEntry( 6202, new ContextCallback( CancelRenewInventoryInsurance ) ) ); // Cancel Renewing Inventory Insurance
+ else
+ list.Add( new CallbackEntry( 6200, new ContextCallback( AutoRenewInventoryInsurance ) ) ); // Auto Renew Inventory Insurance
+ }
+
+ if ( MLQuestSystem.Enabled )
+ list.Add( new CallbackEntry( 6169, new ContextCallback( ToggleQuestItem ) ) ); // Toggle Quest Item
}
BaseHouse house = BaseHouse.FindHouseAt( this );
@@ -1815,6 +1822,62 @@ namespace Server.Mobiles
#endregion
+ #region Toggle Quest Item
+
+ private void ToggleQuestItem()
+ {
+ if ( !CheckAlive() )
+ return;
+
+ ToggleQuestItemTarget();
+ }
+
+ private void ToggleQuestItemTarget()
+ {
+ Server.Engines.MLQuests.Gumps.BaseQuestGump.CloseOtherGumps( this );
+ CloseGump( typeof( Server.Engines.MLQuests.Gumps.QuestLogDetailedGump ) );
+ CloseGump( typeof( Server.Engines.MLQuests.Gumps.QuestLogGump ) );
+ CloseGump( typeof( Server.Engines.MLQuests.Gumps.QuestOfferGump ) );
+ //CloseGump( typeof( UnknownGump802 ) );
+ //CloseGump( typeof( UnknownGump804 ) );
+
+ BeginTarget( -1, false, TargetFlags.None, new TargetCallback( ToggleQuestItem_Callback ) );
+ SendLocalizedMessage( 1072352 ); // Target the item you wish to toggle Quest Item status on to cancel
+ }
+
+ private void ToggleQuestItem_Callback( Mobile from, object obj )
+ {
+ if ( !CheckAlive() )
+ return;
+
+ Item item = obj as Item;
+
+ if ( item == null )
+ return;
+
+ if ( from.Backpack == null || item.Parent != from.Backpack )
+ {
+ SendLocalizedMessage( 1074769 ); // An item must be in your backpack (and not in a container within) to be toggled as a quest item.
+ }
+ else if ( item.QuestItem )
+ {
+ item.QuestItem = false;
+ SendLocalizedMessage( 1072354 ); // You remove Quest Item status from the item
+ }
+ else if ( MLQuestSystem.MarkQuestItem( this, item ) )
+ {
+ SendLocalizedMessage( 1072353 ); // You set the item to Quest Item status
+ }
+ else
+ {
+ SendLocalizedMessage( 1072355, "", 0x23 ); // That item does not match any of your quest criteria
+ }
+
+ ToggleQuestItemTarget();
+ }
+
+ #endregion
+
private void GetVendor()
{
BaseHouse house = BaseHouse.FindHouseAt( this );
@@ -2341,6 +2404,10 @@ namespace Server.Mobiles
public override DeathMoveResult GetParentMoveResultFor( Item item )
{
+ // It seems all items are unmarked on death, even blessed/insured ones
+ if ( item.QuestItem )
+ item.QuestItem = false;
+
if ( CheckInsuranceOnDeath( item ) )
return DeathMoveResult.MoveToBackpack;
@@ -2354,6 +2421,10 @@ namespace Server.Mobiles
public override DeathMoveResult GetInventoryMoveResultFor( Item item )
{
+ // It seems all items are unmarked on death, even blessed/insured ones
+ if ( item.QuestItem )
+ item.QuestItem = false;
+
if ( CheckInsuranceOnDeath( item ) )
return DeathMoveResult.MoveToBackpack;
@@ -2466,6 +2537,8 @@ namespace Server.Mobiles
Server.Guilds.Guild.HandleDeath( this, killer );
+ MLQuestSystem.HandleDeath( this );
+
#region Dueling
if ( m_DuelContext != null )
m_DuelContext.OnDeath( this, c );
@@ -3366,6 +3439,8 @@ namespace Server.Mobiles
if ( faction != null )
faction.RemoveMember( this );
+ MLQuestSystem.HandleDeletion( this );
+
BaseHouse.HandleDeletion( this );
DisguiseTimers.RemoveTimer( this );
@@ -3653,6 +3728,9 @@ namespace Server.Mobiles
acc.RemoveYoungStatus( 1019036 ); // You have successfully obtained a respectable skill level, and have outgrown your status as a young player!
}
+ if ( MLQuestSystem.Enabled )
+ MLQuestSystem.HandleSkillGain( this, skill );
+
InvalidateMyRunUO();
}
@@ -3874,7 +3952,9 @@ namespace Server.Mobiles
private int m_CompassionGains;
public DateTime LastCompassionLoss{ get{ return m_LastCompassionLoss; } set{ m_LastCompassionLoss = value; } }
+ [CommandProperty( AccessLevel.GameMaster )]
public DateTime NextCompassionDay{ get{ return m_NextCompassionDay; } set{ m_NextCompassionDay = value; } }
+ [CommandProperty( AccessLevel.GameMaster )]
public int CompassionGains{ get{ return m_CompassionGains; } set{ m_CompassionGains = value; } }
private DateTime m_LastValorLoss;
diff --git a/Scripts/Mobiles/Townfolk/BaseEscortable.cs b/Scripts/Mobiles/Townfolk/BaseEscortable.cs
index 4b94463d8..f3477cb08 100644
--- a/Scripts/Mobiles/Townfolk/BaseEscortable.cs
+++ b/Scripts/Mobiles/Townfolk/BaseEscortable.cs
@@ -6,18 +6,109 @@ using Server.Items;
using Server.Network;
using Server.ContextMenus;
using EDI = Server.Mobiles.EscortDestinationInfo;
+using Server.Engines.MLQuests;
+using Server.Engines.MLQuests.Definitions;
+using Server.Engines.MLQuests.Objectives;
namespace Server.Mobiles
{
public class BaseEscortable : BaseCreature
{
+ public static readonly TimeSpan EscortDelay = TimeSpan.FromMinutes( 5.0 );
+ public static readonly TimeSpan AbandonDelay = MLQuestSystem.Enabled ? TimeSpan.FromMinutes( 1.0 ) : TimeSpan.FromMinutes( 2.0 );
+ public static readonly TimeSpan DeleteTime = MLQuestSystem.Enabled ? TimeSpan.FromSeconds( 100 ) : TimeSpan.FromSeconds( 30 );
+
+ public override bool StaticMLQuester { get { return false; } } // Suppress automatic quest registration on creation/deserialization
+
+ private MLQuest m_MLQuest;
+
+ protected override List ConstructQuestList()
+ {
+ if ( m_MLQuest == null )
+ {
+ 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 )
+ {
+ Type questType = list[randomIdx];
+
+ MLQuest quest = MLQuestSystem.FindQuest( questType );
+
+ if ( quest != null )
+ {
+ bool okay = true;
+
+ foreach ( BaseObjective obj in quest.Objectives )
+ {
+ if ( obj is EscortObjective && ( (EscortObjective)obj ).Destination.Contains( reg ) )
+ {
+ okay = false; // We're already there!
+ break;
+ }
+ }
+
+ if ( okay )
+ {
+ SetMLQuest( quest );
+ break;
+ }
+ }
+ else if ( MLQuestSystem.Debug )
+ {
+ Console.WriteLine( "WARNING: Type {0} should not be eligible as it is not a registered quest", questType.Name );
+ }
+
+ randomIdx = ( randomIdx + 1 ) % list.Length;
+ }
+
+ if ( m_MLQuest == null )
+ {
+ if ( MLQuestSystem.Debug )
+ Console.WriteLine( "WARNING: No suitable quest found for escort {0}", Serial );
+
+ return null;
+ }
+ }
+
+ List result = new List();
+ result.Add( m_MLQuest );
+
+ return result;
+ }
+
+ public override bool CanShout { get { return ( !Controlled && !IsBeingDeleted ); } }
+
+ public override void Shout( PlayerMobile pm )
+ {
+ /*
+ * 1072301 - You there! Care to hear how to earn some easy gold?
+ * 1072302 - Adventurer! I have an offer for you.
+ * 1072303 - Wait! I have an opportunity for you to make some gold!
+ */
+ MLQuestSystem.Tell( this, pm, Utility.Random( 1072301, 3 ) );
+ }
+
private EDI m_Destination;
private string m_DestinationString;
private DateTime m_DeleteTime;
private Timer m_DeleteTimer;
+ private bool m_DeleteCorpse = false;
+
+ public bool IsBeingDeleted
+ {
+ get { return ( m_DeleteTimer != null ); }
+ }
+
public override bool Commandable { get { return false; } } // Our master cannot boss us around!
+ public override bool DeleteCorpseOnDeath { get { return m_DeleteCorpse; } }
[CommandProperty(AccessLevel.GameMaster)]
public string Destination
@@ -26,26 +117,78 @@ namespace Server.Mobiles
set { m_DestinationString = value; m_Destination = EDI.Find(value); }
}
+ // Classic list
+ // Used when: !MLQuestSystem.Enabled && !Core.ML
private static string[] m_TownNames = new string[]
{
"Cove", "Britain", "Jhelom",
"Minoc", "Ocllo", "Trinsic",
- "Vesper", "Yew", "Skara Brae", //Original List, will need to add it back for Pre-ML shards
+ "Vesper", "Yew", "Skara Brae",
"Nujel'm", "Moonglow", "Magincia"
};
+ // ML list, pre-ML quest system
+ // Used when: !MLQuestSystem.Enabled && Core.ML
private static string[] m_MLTownNames = new string[]
{
- "Cove", "Serpent's Hold", "Jhelom", //ML List
+ "Cove", "Serpent's Hold", "Jhelom",
"Nujel'm"
};
+ // ML quest system general list
+ // Used when: MLQuestSystem.Enabled && !Region.IsPartOf( "Haven Island" )
+ private static Type[] m_MLQuestTypes =
+ {
+ typeof( EscortToYew ),
+ typeof( EscortToVesper ),
+ typeof( EscortToTrinsic ),
+ typeof( EscortToSkaraBrae ),
+ typeof( EscortToSerpentsHold ),
+ typeof( EscortToNujelm ),
+ typeof( EscortToMoonglow ),
+ typeof( EscortToMinoc ),
+ typeof( EscortToMagincia ),
+ typeof( EscortToJhelom ),
+ typeof( EscortToCove ),
+ typeof( EscortToBritain )
+ // Ocllo was removed in pub 56
+ //typeof( EscortToOcllo )
+ };
+
+ // ML quest system New Haven list
+ // Used when: MLQuestSystem.Enabled && Region.IsPartOf( "Haven Island" )
+ private static Type[] m_MLQuestTypesNH =
+ {
+ typeof( EscortToNHAlchemist ),
+ typeof( EscortToNHBard ),
+ typeof( EscortToNHWarrior ),
+ typeof( EscortToNHTailor ),
+ typeof( EscortToNHCarpenter ),
+ typeof( EscortToNHMapmaker ),
+ typeof( EscortToNHMage ),
+ typeof( EscortToNHInn ),
+ // Farm destination was removed
+ //typeof( EscortToNHFarm ),
+ typeof( EscortToNHDocks ),
+ typeof( EscortToNHBowyer ),
+ 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)
{
InitBody();
InitOutfit();
+
+ Fame = 200;
+ Karma = 4000;
}
public virtual void InitBody()
@@ -109,8 +252,6 @@ namespace Server.Mobiles
get { return m_EscortTable; }
}
- private static TimeSpan m_EscortDelay = TimeSpan.FromMinutes(5.0);
-
public virtual bool AcceptEscorter(Mobile m)
{
EDI dest = GetDestination();
@@ -130,9 +271,9 @@ namespace Server.Mobiles
Say("I see you already have an escort.");
return false;
}
- else if (m is PlayerMobile && (((PlayerMobile)m).LastEscortTime + m_EscortDelay) >= DateTime.Now)
+ else if (m is PlayerMobile && (((PlayerMobile)m).LastEscortTime + EscortDelay) >= DateTime.Now)
{
- int minutes = (int)Math.Ceiling(((((PlayerMobile)m).LastEscortTime + m_EscortDelay) - DateTime.Now).TotalMinutes);
+ int minutes = (int)Math.Ceiling(((((PlayerMobile)m).LastEscortTime + EscortDelay) - DateTime.Now).TotalMinutes);
Say("You must rest {0} minute{1} before we set out on this journey.", minutes, minutes == 1 ? "" : "s");
return false;
@@ -155,6 +296,9 @@ namespace Server.Mobiles
public override bool HandlesOnSpeech(Mobile from)
{
+ if ( MLQuestSystem.Enabled )
+ return false;
+
if (from.InRange(this.Location, 3))
return true;
@@ -202,6 +346,8 @@ namespace Server.Mobiles
return true;
}
+ // TODO: Pre-ML methods below, might be mergeable with the ML methods in EscortObjective
+
public virtual void StartFollow()
{
StartFollow(GetEscorter());
@@ -240,13 +386,13 @@ namespace Server.Mobiles
public virtual Mobile GetEscorter()
{
- if (!Controlled)
+ if ( !Controlled )
return null;
Mobile master = ControlMaster;
- if (master == null)
- return null;
+ if ( MLQuestSystem.Enabled || master == null )
+ return master;
if (master.Deleted || master.Map != this.Map || !master.InRange(Location, 30) || !master.Alive)
{
@@ -254,7 +400,7 @@ namespace Server.Mobiles
TimeSpan lastSeenDelay = DateTime.Now - m_LastSeenEscorter;
- if (lastSeenDelay >= TimeSpan.FromMinutes(2.0))
+ if (lastSeenDelay >= AbandonDelay)
{
master.SendLocalizedMessage(1042473); // You have lost the person you were escorting.
Say(1005653); // Hmmm. I seem to have lost my master.
@@ -284,7 +430,7 @@ namespace Server.Mobiles
if (m_DeleteTimer != null)
m_DeleteTimer.Stop();
- m_DeleteTime = DateTime.Now + TimeSpan.FromSeconds(30.0);
+ m_DeleteTime = DateTime.Now + DeleteTime;
m_DeleteTimer = new DeleteTimer(this, m_DeleteTime - DateTime.Now);
m_DeleteTimer.Start();
@@ -292,6 +438,9 @@ namespace Server.Mobiles
public virtual bool CheckAtDestination()
{
+ if ( MLQuestSystem.Enabled )
+ return false;
+
EDI dest = GetDestination();
if (dest == null)
@@ -352,6 +501,9 @@ namespace Server.Mobiles
pm.NextCompassionDay = DateTime.Now + TimeSpan.FromDays(1.0); // in one day CompassionGains gets reset to 0
++pm.CompassionGains;
+
+ if (pm.CompassionGains >= 5)
+ pm.SendLocalizedMessage(1053004); // You must wait about a day before you can gain in compassion again.
}
else
{
@@ -365,6 +517,13 @@ namespace Server.Mobiles
return false;
}
+ public override bool OnBeforeDeath()
+ {
+ m_DeleteCorpse = ( Controlled || IsBeingDeleted );
+
+ return base.OnBeforeDeath();
+ }
+
public BaseEscortable(Serial serial)
: base(serial)
{
@@ -374,7 +533,7 @@ namespace Server.Mobiles
{
base.Serialize(writer);
- writer.Write((int)0); // version
+ writer.Write((int)1); // version
EDI dest = GetDestination();
@@ -387,6 +546,8 @@ namespace Server.Mobiles
if (m_DeleteTimer != null)
writer.WriteDeltaTime(m_DeleteTime);
+
+ MLQuestSystem.WriteQuestRef( writer, StaticMLQuester ? null : m_MLQuest );
}
public override void Deserialize(GenericReader reader)
@@ -404,6 +565,14 @@ namespace Server.Mobiles
m_DeleteTimer = new DeleteTimer(this, m_DeleteTime - DateTime.Now);
m_DeleteTimer.Start();
}
+
+ if ( version >= 1 )
+ {
+ MLQuest quest = MLQuestSystem.ReadQuestRef( reader );
+
+ if ( quest != null && !StaticMLQuester )
+ SetMLQuest( quest );
+ }
}
public override bool CanBeRenamedBy(Mobile from)
@@ -411,24 +580,26 @@ namespace Server.Mobiles
return (from.AccessLevel >= AccessLevel.GameMaster);
}
- public override void AddCustomContextEntries(Mobile from, List list)
+ public override void AddCustomContextEntries( Mobile from, List list )
{
- EDI dest = GetDestination();
-
- if (dest != null && from.Alive)
+ if ( from.Alive )
{
Mobile escorter = GetEscorter();
- if (escorter == null || escorter == from)
- list.Add(new AskDestinationEntry(this, from));
+ if ( !MLQuestSystem.Enabled && GetDestination() != null )
+ {
+ if ( escorter == null || escorter == from )
+ list.Add( new AskDestinationEntry( this, from ) );
- if (escorter == null)
- list.Add(new AcceptEscortEntry(this, from));
- else if (escorter == from)
- list.Add(new AbandonEscortEntry(this, from));
+ if ( escorter == null )
+ list.Add( new AcceptEscortEntry( this, from ) );
+ }
+
+ if ( escorter == from )
+ list.Add( new AbandonEscortEntry( this, from ) );
}
- base.AddCustomContextEntries(from, list);
+ base.AddCustomContextEntries( from, list );
}
public virtual string[] GetPossibleDestinations()
@@ -461,6 +632,9 @@ namespace Server.Mobiles
public EDI GetDestination()
{
+ if ( MLQuestSystem.Enabled )
+ return null;
+
if (m_DestinationString == null && m_DeleteTimer == null)
m_DestinationString = PickRandomDestination();
diff --git a/Scripts/Mobiles/Townfolk/BrideGroom.cs b/Scripts/Mobiles/Townfolk/BrideGroom.cs
index acc537c22..d543575d6 100644
--- a/Scripts/Mobiles/Townfolk/BrideGroom.cs
+++ b/Scripts/Mobiles/Townfolk/BrideGroom.cs
@@ -11,10 +11,9 @@ namespace Server.Mobiles
public BrideGroom()
{
if ( Female )
- Title = "the bride";
+ Title = "the bride";
else
- Title = "the groom";
-
+ Title = "the groom";
}
public override bool CanTeach{ get{ return true; } }
@@ -37,8 +36,7 @@ namespace Server.Mobiles
public override void InitOutfit()
{
if ( Female )
-
- AddItem( new FancyDress() );
+ AddItem( new FancyDress() );
else
AddItem( new FancyShirt() );
@@ -51,8 +49,6 @@ namespace Server.Mobiles
else
AddItem( new Boots( lowHue ) );
-
-
if( Utility.RandomBool() )
HairItemID = 0x203B;
else
diff --git a/Scripts/Mobiles/Townfolk/Messenger.cs b/Scripts/Mobiles/Townfolk/Messenger.cs
index 456a02c46..03bf2a22c 100644
--- a/Scripts/Mobiles/Townfolk/Messenger.cs
+++ b/Scripts/Mobiles/Townfolk/Messenger.cs
@@ -11,7 +11,6 @@ namespace Server.Mobiles
public Messenger()
{
Title = "the messenger";
-
}
public override bool CanTeach{ get{ return true; } }
diff --git a/Scripts/Mobiles/Townfolk/Prisoner.cs b/Scripts/Mobiles/Townfolk/Prisoner.cs
new file mode 100644
index 000000000..044fc93ba
--- /dev/null
+++ b/Scripts/Mobiles/Townfolk/Prisoner.cs
@@ -0,0 +1,83 @@
+using System;
+using Server.Items;
+using Server.Engines.MLQuests;
+
+namespace Server.Mobiles.Townfolk
+{
+ public class Prisoner : BaseEscortable
+ {
+ [Constructable]
+ public Prisoner()
+ {
+ Title = Female ? "the noblewoman" : "the nobleman";
+
+ CantWalk = true;
+ IsPrisoner = true;
+ }
+
+ public override bool CanTeach { get { return true; } }
+ public override bool ClickTitle { get { return false; } }
+
+ public override void InitOutfit()
+ {
+ if ( Female )
+ {
+ AddItem( new FancyDress( Utility.RandomNondyedHue() ) );
+ }
+ else
+ {
+ AddItem( new FancyShirt( Utility.RandomNondyedHue() ) );
+ AddItem( new LongPants( Utility.RandomNondyedHue() ) );
+ }
+
+ if ( Utility.RandomBool() )
+ AddItem( new Boots() );
+ else
+ AddItem( new ThighBoots() );
+
+ Utility.AssignRandomHair( this );
+ Utility.AssignRandomFacialHair( this, HairHue );
+ }
+
+ public override void Shout( PlayerMobile pm )
+ {
+ /*
+ * 502261 - HELP!
+ * 502262 - Help me!
+ * 502263 - Canst thou aid me?!
+ * 502264 - Help a poor prisoner!
+ * 502265 - Help! Please!
+ * 502266 - Aaah! Help me!
+ * 502267 - Go and get some help!
+ */
+ MLQuestSystem.Tell( this, pm, Utility.Random( 502261, 7 ) );
+ }
+
+ public override void OnMovement( Mobile m, Point3D oldLocation )
+ {
+ base.OnMovement( m, oldLocation );
+
+ if ( CantWalk && InRange( m, 1 ) && !InRange( oldLocation, 1 ) && ( !m.Hidden || m.AccessLevel == AccessLevel.Player ) )
+ Say( 502268 ); // Quickly, I beg thee! Unlock my chains! If thou dost look at me close thou canst see them.
+ }
+
+ public Prisoner( 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();
+ }
+ }
+}
diff --git a/Scripts/Mobiles/Vendors/BaseVendor.cs b/Scripts/Mobiles/Vendors/BaseVendor.cs
index b252a14ba..98c798106 100644
--- a/Scripts/Mobiles/Vendors/BaseVendor.cs
+++ b/Scripts/Mobiles/Vendors/BaseVendor.cs
@@ -46,7 +46,7 @@ namespace Server.Mobiles
public virtual NpcGuild NpcGuild { get { return NpcGuild.None; } }
- public virtual bool IsInvulnerable { get { return true; } }
+ public override bool IsInvulnerable { get { return true; } }
public virtual DateTime NextTrickOrTreat { get { return m_NextTrickOrTreat; } set { m_NextTrickOrTreat = value; } }
@@ -265,9 +265,6 @@ namespace Server.Mobiles
SpeechHue = Utility.RandomDyedHue();
Hue = Utility.RandomSkinHue();
- if ( IsInvulnerable && !Core.AOS )
- NameHue = 0x35;
-
if ( Female = GetGender() )
{
Body = 0x191;
@@ -306,14 +303,6 @@ namespace Server.Mobiles
get { return VendorShoeType.Shoes; }
}
- public virtual int RandomBrightHue()
- {
- if ( 0.1 > Utility.RandomDouble() )
- return Utility.RandomList( 0x62, 0x71 );
-
- return Utility.RandomList( 0x03, 0x0D, 0x13, 0x1C, 0x21, 0x30, 0x37, 0x3A, 0x44, 0x59 );
- }
-
public virtual void CheckMorph()
{
if ( CheckGargoyle() )
@@ -439,7 +428,7 @@ namespace Server.Mobiles
FacialHairItemID = 0;
Body = 0x2F6;
- Hue = RandomBrightHue() | 0x8000;
+ Hue = Utility.RandomBrightHue() | 0x8000;
Name = NameList.RandomName( "gargoyle vendor" );
CapitalizeTitle();
@@ -1015,7 +1004,7 @@ namespace Server.Mobiles
if ( cont.ConsumeTotal( typeof( Gold ), totalCost ) )
bought = true;
else if ( totalCost < 2000 )
- SayTo( buyer, 500192 );//Begging thy pardon, but thou casnt afford that.
+ SayTo( buyer, 500192 ); // Begging thy pardon, but thou canst not afford that.
}
if ( !bought && totalCost >= 2000 )
@@ -1394,9 +1383,6 @@ namespace Server.Mobiles
if ( IsParagon )
IsParagon = false;
- if ( Core.AOS && NameHue == 0x35 )
- NameHue = -1;
-
Timer.DelayCall( TimeSpan.Zero, new TimerCallback( CheckMorph ) );
}
@@ -1426,11 +1412,6 @@ namespace Server.Mobiles
{
return (IBuyItemInfo[])m_ArmorBuyInfo.ToArray( typeof( IBuyItemInfo ) );
}
-
- public override bool CanBeDamaged()
- {
- return !IsInvulnerable;
- }
}
}
diff --git a/Scripts/Mobiles/Vendors/GenericSell.cs b/Scripts/Mobiles/Vendors/GenericSell.cs
index 135f3cf7e..6e2de70bb 100644
--- a/Scripts/Mobiles/Vendors/GenericSell.cs
+++ b/Scripts/Mobiles/Vendors/GenericSell.cs
@@ -104,7 +104,7 @@ namespace Server.Mobiles
public bool IsSellable( Item item )
{
- if ( item.QuestItem )
+ if ( item.Nontransferable )
return false;
//if ( item.Hue != 0 )
@@ -115,7 +115,7 @@ namespace Server.Mobiles
public bool IsResellable( Item item )
{
- if ( item.QuestItem )
+ if ( item.Nontransferable )
return false;
//if ( item.Hue != 0 )
diff --git a/Scripts/Mobiles/Vendors/NPC/Barkeeper.cs b/Scripts/Mobiles/Vendors/NPC/Barkeeper.cs
index 7386ca632..3926f8f5e 100644
--- a/Scripts/Mobiles/Vendors/NPC/Barkeeper.cs
+++ b/Scripts/Mobiles/Vendors/NPC/Barkeeper.cs
@@ -25,7 +25,7 @@ namespace Server.Mobiles
{
base.InitOutfit();
- AddItem( new HalfApron( RandomBrightHue() ) );
+ AddItem( new HalfApron( Utility.RandomBrightHue() ) );
}
[Constructable]
diff --git a/Scripts/Mobiles/Vendors/NPC/CustomHairstylist.cs b/Scripts/Mobiles/Vendors/NPC/CustomHairstylist.cs
index 6d9fd8fa0..ba3a6e5d5 100644
--- a/Scripts/Mobiles/Vendors/NPC/CustomHairstylist.cs
+++ b/Scripts/Mobiles/Vendors/NPC/CustomHairstylist.cs
@@ -59,7 +59,7 @@ namespace Server.Mobiles
public override int GetHairHue()
{
- return RandomBrightHue();
+ return Utility.RandomBrightHue();
}
public override VendorShoeType ShoeType
diff --git a/Scripts/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs b/Scripts/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs
index 85b4e7d51..6aed13ffc 100644
--- a/Scripts/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs
+++ b/Scripts/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs
@@ -37,32 +37,32 @@ namespace Server.Mobiles
Item item = FindItemOnLayer( Layer.Pants );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.OuterLegs );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.InnerLegs );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.OuterTorso );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.InnerTorso );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.Shirt );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
}
public GypsyAnimalTrainer( Serial serial ) : base( serial )
diff --git a/Scripts/Mobiles/Vendors/NPC/GypsyBanker.cs b/Scripts/Mobiles/Vendors/NPC/GypsyBanker.cs
index c7f523b44..2dc4729c3 100644
--- a/Scripts/Mobiles/Vendors/NPC/GypsyBanker.cs
+++ b/Scripts/Mobiles/Vendors/NPC/GypsyBanker.cs
@@ -27,45 +27,45 @@ namespace Server.Mobiles
switch ( Utility.Random( 4 ) )
{
- case 0: AddItem( new JesterHat( RandomBrightHue() ) ); break;
- case 1: AddItem( new Bandana( RandomBrightHue() ) ); break;
- case 2: AddItem( new SkullCap( RandomBrightHue() ) ); break;
+ case 0: AddItem( new JesterHat( Utility.RandomBrightHue() ) ); break;
+ case 1: AddItem( new Bandana( Utility.RandomBrightHue() ) ); break;
+ case 2: AddItem( new SkullCap( Utility.RandomBrightHue() ) ); break;
}
Item item = FindItemOnLayer( Layer.Pants );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.Shoes );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.OuterLegs );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.InnerLegs );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.OuterTorso );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.InnerTorso );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.Shirt );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
}
public GypsyBanker( Serial serial ) : base( serial )
diff --git a/Scripts/Mobiles/Vendors/NPC/GypsyMaiden.cs b/Scripts/Mobiles/Vendors/NPC/GypsyMaiden.cs
index c6a60080c..a56c21714 100644
--- a/Scripts/Mobiles/Vendors/NPC/GypsyMaiden.cs
+++ b/Scripts/Mobiles/Vendors/NPC/GypsyMaiden.cs
@@ -35,28 +35,28 @@ namespace Server.Mobiles
switch ( Utility.Random( 4 ) )
{
- case 0: AddItem( new JesterHat( RandomBrightHue() ) ); break;
- case 1: AddItem( new Bandana( RandomBrightHue() ) ); break;
- case 2: AddItem( new SkullCap( RandomBrightHue() ) ); break;
+ case 0: AddItem( new JesterHat( Utility.RandomBrightHue() ) ); break;
+ case 1: AddItem( new Bandana( Utility.RandomBrightHue() ) ); break;
+ case 2: AddItem( new SkullCap( Utility.RandomBrightHue() ) ); break;
}
if ( Utility.RandomBool() )
- AddItem( new HalfApron( RandomBrightHue() ) );
+ AddItem( new HalfApron( Utility.RandomBrightHue() ) );
Item item = FindItemOnLayer( Layer.Pants );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.OuterLegs );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.InnerLegs );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
}
public GypsyMaiden( Serial serial ) : base( serial )
diff --git a/Scripts/Mobiles/Vendors/NPC/IronWorker.cs b/Scripts/Mobiles/Vendors/NPC/IronWorker.cs
index b75a65cd4..05135edbf 100644
--- a/Scripts/Mobiles/Vendors/NPC/IronWorker.cs
+++ b/Scripts/Mobiles/Vendors/NPC/IronWorker.cs
@@ -62,12 +62,12 @@ namespace Server.Mobiles
switch ( Utility.Random( 3 ) )
{
case 0:
- case 1: AddItem( new JesterHat( RandomBrightHue() ) ); break;
- case 2: AddItem( new Bandana( RandomBrightHue() ) ); break;
+ case 1: AddItem( new JesterHat( Utility.RandomBrightHue() ) ); break;
+ case 2: AddItem( new Bandana( Utility.RandomBrightHue() ) ); break;
}
if ( item == null )
- AddItem( new FullApron( RandomBrightHue() ) );
+ AddItem( new FullApron( Utility.RandomBrightHue() ) );
AddItem( new Bascinet() );
AddItem( new SmithHammer() );
@@ -75,32 +75,32 @@ namespace Server.Mobiles
item = FindItemOnLayer( Layer.Pants );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.OuterLegs );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.InnerLegs );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.OuterTorso );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.InnerTorso );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
item = FindItemOnLayer( Layer.Shirt );
if ( item != null )
- item.Hue = RandomBrightHue();
+ item.Hue = Utility.RandomBrightHue();
}
public IronWorker( Serial serial ) : base( serial )
diff --git a/Scripts/Mobiles/Vendors/NPC/Scribe.cs b/Scripts/Mobiles/Vendors/NPC/Scribe.cs
index 4745af5f7..5872a686e 100644
--- a/Scripts/Mobiles/Vendors/NPC/Scribe.cs
+++ b/Scripts/Mobiles/Vendors/NPC/Scribe.cs
@@ -11,6 +11,9 @@ namespace Server.Mobiles
public override NpcGuild NpcGuild{ get{ return NpcGuild.MagesGuild; } }
+ private DateTime m_NextShush;
+ public static readonly TimeSpan ShushDelay = TimeSpan.FromMinutes( 1 );
+
[Constructable]
public Scribe() : base( "the scribe" )
{
@@ -35,6 +38,27 @@ namespace Server.Mobiles
AddItem( new Server.Items.Robe( Utility.RandomNeutralHue() ) );
}
+ public override bool HandlesOnSpeech( Mobile from )
+ {
+ return from.Player;
+ }
+
+ public override void OnSpeech( SpeechEventArgs e )
+ {
+ base.OnSpeech( e );
+
+ if ( !e.Handled && m_NextShush <= DateTime.Now && InLOS( e.Mobile ) )
+ {
+ Direction = GetDirectionTo( e.Mobile );
+
+ PlaySound( Female ? 0x32F : 0x441 );
+ PublicOverheadMessage( Network.MessageType.Regular, 0x3B2, 1073990 ); // Shhhh!
+
+ m_NextShush = DateTime.Now + ShushDelay;
+ e.Handled = true;
+ }
+ }
+
public Scribe( Serial serial ) : base( serial )
{
}
diff --git a/Scripts/Mobiles/Vendors/NPC/Vagabond.cs b/Scripts/Mobiles/Vendors/NPC/Vagabond.cs
index 80b94cb65..6f514a703 100644
--- a/Scripts/Mobiles/Vendors/NPC/Vagabond.cs
+++ b/Scripts/Mobiles/Vendors/NPC/Vagabond.cs
@@ -24,12 +24,12 @@ namespace Server.Mobiles
public override void InitOutfit()
{
- AddItem( new FancyShirt( RandomBrightHue() ) );
+ AddItem( new FancyShirt( Utility.RandomBrightHue() ) );
AddItem( new Shoes( GetShoeHue() ) );
AddItem( new LongPants( GetRandomHue() ) );
if ( Utility.RandomBool() )
- AddItem( new Cloak( RandomBrightHue() ) );
+ AddItem( new Cloak( Utility.RandomBrightHue() ) );
switch ( Utility.Random( 2 ) )
{
diff --git a/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs b/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs
index c39c534af..43ed9c0b5 100644
--- a/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs
+++ b/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs
@@ -193,7 +193,7 @@ namespace Server.Mobiles
{
base.InitOutfit();
- AddItem( new HalfApron( RandomBrightHue() ) );
+ AddItem( new HalfApron( Utility.RandomBrightHue() ) );
Container pack = this.Backpack;
diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBInfo.cs b/Scripts/Mobiles/Vendors/SBInfo/SBInfo.cs
index 5987a5b14..f24173281 100644
--- a/Scripts/Mobiles/Vendors/SBInfo/SBInfo.cs
+++ b/Scripts/Mobiles/Vendors/SBInfo/SBInfo.cs
@@ -6,11 +6,13 @@ namespace Server.Mobiles
{
public abstract class SBInfo
{
+ public static readonly List Empty = new List();
+
public SBInfo()
{
}
public abstract IShopSellInfo SellInfo { get; }
- public abstract List BuyInfo { get; }
+ public abstract List BuyInfo { get; }
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBNinja.cs b/Scripts/Mobiles/Vendors/SBInfo/SBNinja.cs
new file mode 100644
index 000000000..eba1a2fcd
--- /dev/null
+++ b/Scripts/Mobiles/Vendors/SBInfo/SBNinja.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using Server.Items;
+
+namespace Server.Mobiles
+{
+ public class SBNinja : SBInfo
+ {
+ private List m_BuyInfo = new InternalBuyInfo();
+ private IShopSellInfo m_SellInfo = new InternalSellInfo();
+
+ public SBNinja()
+ {
+ }
+
+ public override IShopSellInfo SellInfo { get { return m_SellInfo; } }
+ public override List BuyInfo { get { return m_BuyInfo; } }
+
+ public class InternalBuyInfo : List
+ {
+ public InternalBuyInfo()
+ {
+ Add( new GenericBuyInfo( typeof( BookOfNinjitsu ), 335, 20, 0x23A0, 0 ) );
+ }
+ }
+
+ public class InternalSellInfo : GenericSellInfo
+ {
+ public InternalSellInfo()
+ {
+ }
+ }
+ }
+}
diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBSamurai.cs b/Scripts/Mobiles/Vendors/SBInfo/SBSamurai.cs
new file mode 100644
index 000000000..8dfa2ae7e
--- /dev/null
+++ b/Scripts/Mobiles/Vendors/SBInfo/SBSamurai.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using Server.Items;
+
+namespace Server.Mobiles
+{
+ public class SBSamurai : SBInfo
+ {
+ private List m_BuyInfo = new InternalBuyInfo();
+ private IShopSellInfo m_SellInfo = new InternalSellInfo();
+
+ public SBSamurai()
+ {
+ }
+
+ public override IShopSellInfo SellInfo { get { return m_SellInfo; } }
+ public override List BuyInfo { get { return m_BuyInfo; } }
+
+ public class InternalBuyInfo : List
+ {
+ public InternalBuyInfo()
+ {
+ Add( new GenericBuyInfo( typeof( BookOfBushido ), 280, 20, 0x238C, 0 ) );
+ }
+ }
+
+ public class InternalSellInfo : GenericSellInfo
+ {
+ public InternalSellInfo()
+ {
+ }
+ }
+ }
+}
diff --git a/Scripts/Spells/Spellweaving/ArcanistSpell.cs b/Scripts/Spells/Spellweaving/ArcanistSpell.cs
index 7b5f1860b..95b577862 100644
--- a/Scripts/Spells/Spellweaving/ArcanistSpell.cs
+++ b/Scripts/Spells/Spellweaving/ArcanistSpell.cs
@@ -2,6 +2,7 @@ using System;
using System.Text;
using Server.Items;
using Server.Mobiles;
+using Server.Engines.MLQuests;
namespace Server.Spells.Spellweaving
{
@@ -64,24 +65,35 @@ namespace Server.Spells.Spellweaving
if( !base.CheckCast() )
return false;
- if( !CheckExpansion( Caster ) )
+ Mobile caster = Caster;
+
+ if ( !CheckExpansion( caster ) )
{
- Caster.SendLocalizedMessage( 1072176 ); // You must upgrade to the Mondain's Legacy Expansion Pack before using that ability
+ caster.SendLocalizedMessage( 1072176 ); // You must upgrade to the Mondain's Legacy Expansion Pack before using that ability
return false;
}
- //TODO: Spellweaving quest completion
+ if ( caster is PlayerMobile )
+ {
+ MLQuestContext context = MLQuestSystem.GetContext( (PlayerMobile)caster );
+
+ if ( context == null || !context.Spellweaving )
+ {
+ caster.SendLocalizedMessage( 1073220 ); // You must have completed the epic arcanist quest to use this ability.
+ return false;
+ }
+ }
int mana = ScaleMana( RequiredMana );
- if( Caster.Mana < mana )
+ if ( caster.Mana < mana )
{
- Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
+ caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
return false;
}
- else if( Caster.Skills[CastSkill].Value < RequiredSkill )
+ else if ( caster.Skills[CastSkill].Value < RequiredSkill )
{
- Caster.SendLocalizedMessage( 1063013, String.Format( "{0}\t{1}", RequiredSkill.ToString( "F1" ), "#1044114" ) ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
+ caster.SendLocalizedMessage( 1063013, String.Format( "{0}\t{1}", RequiredSkill.ToString( "F1" ), "#1044114" ) ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
return false;
}
diff --git a/Scripts/Spells/Spellweaving/SummonFey.cs b/Scripts/Spells/Spellweaving/SummonFey.cs
index b1e23fa6e..786b388ab 100644
--- a/Scripts/Spells/Spellweaving/SummonFey.cs
+++ b/Scripts/Spells/Spellweaving/SummonFey.cs
@@ -1,5 +1,6 @@
using System;
using Server.Mobiles;
+using Server.Engines.MLQuests;
namespace Server.Spells.Spellweaving
{
@@ -21,5 +22,24 @@ namespace Server.Spells.Spellweaving
}
public override int Sound { get { return 0x217; } }
+
+ public override bool CheckSequence()
+ {
+ Mobile caster = Caster;
+
+ // This is done after casting completes
+ if ( caster is PlayerMobile )
+ {
+ MLQuestContext context = MLQuestSystem.GetContext( (PlayerMobile)caster );
+
+ if ( context == null || !context.SummonFey )
+ {
+ caster.SendLocalizedMessage( 1074563 ); // You haven't forged a friendship with the fey and are unable to summon their aid.
+ return false;
+ }
+ }
+
+ return base.CheckSequence();
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Scripts/Spells/Spellweaving/SummonFiend.cs b/Scripts/Spells/Spellweaving/SummonFiend.cs
index 6285354df..40b2fe8e3 100644
--- a/Scripts/Spells/Spellweaving/SummonFiend.cs
+++ b/Scripts/Spells/Spellweaving/SummonFiend.cs
@@ -1,5 +1,6 @@
using System;
using Server.Mobiles;
+using Server.Engines.MLQuests;
namespace Server.Spells.Spellweaving
{
@@ -21,5 +22,24 @@ namespace Server.Spells.Spellweaving
}
public override int Sound { get { return 0x216; } }
+
+ public override bool CheckSequence()
+ {
+ Mobile caster = Caster;
+
+ // This is done after casting completes
+ if ( caster is PlayerMobile )
+ {
+ MLQuestContext context = MLQuestSystem.GetContext( (PlayerMobile)caster );
+
+ if ( context == null || !context.SummonFiend )
+ {
+ caster.SendLocalizedMessage( 1074564 ); // You haven't demonstrated mastery to summon a fiend.
+ return false;
+ }
+ }
+
+ return base.CheckSequence();
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Server/Item.cs b/Server/Item.cs
index 8c3e72e39..14109da78 100644
--- a/Server/Item.cs
+++ b/Server/Item.cs
@@ -1508,7 +1508,7 @@ namespace Server
{
get
{
- return (Movable && Visible);
+ return (Movable && Visible && Spawner == null);
}
}
@@ -1541,6 +1541,15 @@ namespace Server
public virtual bool StackWith( Mobile from, Item dropped, bool playSound )
{
+ // TODO: OSI actually just ignores the stacking attempt and places the item over it, can we do that?
+ if( Nontransferable || dropped.Nontransferable )
+ {
+ if ( dropped.Nontransferable )
+ HandleInvalidTransfer( from );
+
+ return false;
+ }
+
if ( dropped.Stackable && Stackable && dropped.GetType() == GetType() && dropped.ItemID == ItemID && dropped.Hue == Hue && dropped.Name == Name && (dropped.Amount + Amount) <= 60000 && dropped != this )
{
if ( m_LootType != dropped.m_LootType )
@@ -2840,7 +2849,7 @@ namespace Server
{
get
{
- return (QuestItem ? QuestItemHue : m_Hue);
+ return m_Hue;
}
set
{
@@ -2854,10 +2863,7 @@ namespace Server
}
}
- public virtual int QuestItemHue
- {
- get { return 0x04EA; } //HMMMM... For EA?
- }
+ public const int QuestItemHue = 0x4EA; // Hmmmm... "for EA"?
public virtual bool Nontransferable
{
@@ -2866,8 +2872,9 @@ namespace Server
public virtual void HandleInvalidTransfer( Mobile from )
{
+ // OSI sends 1074769, bug!
if( QuestItem )
- from.SendLocalizedMessage( 1074769 ); // An item must be in your backpack (and not in a container within) to be toggled as a quest item.
+ from.SendLocalizedMessage( 1049343 ); // You can only drop quest items into the top-most level of your backpack while you still need them for your quest.
}
[CommandProperty( AccessLevel.GameMaster )]
@@ -3797,7 +3804,7 @@ namespace Server
public virtual bool OnDroppedToMobile( Mobile from, Mobile target )
{
- if( Nontransferable && from.Player && from.AccessLevel <= AccessLevel.GameMaster )
+ if( Nontransferable && from.Player )
{
HandleInvalidTransfer( from );
return false;
@@ -3830,7 +3837,7 @@ namespace Server
{
return false;
}
- else if( Nontransferable && from.Player && target != from.Backpack && from.AccessLevel <= AccessLevel.GameMaster )
+ else if( Nontransferable && from.Player && target != from.Backpack )
{
HandleInvalidTransfer( from );
return false;
@@ -3851,7 +3858,7 @@ namespace Server
return false;
else if ( !from.OnDroppedItemOnto( this, target ) )
return false;
- else if( Nontransferable && from.Player && from.AccessLevel <= AccessLevel.GameMaster )
+ else if( Nontransferable && from.Player )
{
HandleInvalidTransfer( from );
return false;
@@ -3885,7 +3892,7 @@ namespace Server
public virtual bool OnDroppedToWorld( Mobile from, Point3D p )
{
- if( Nontransferable && from.Player && from.AccessLevel <= AccessLevel.GameMaster )
+ if( Nontransferable && from.Player )
{
HandleInvalidTransfer( from );
return false;
diff --git a/Server/Mobile.cs b/Server/Mobile.cs
index 189b1103f..a6060cc0e 100644
--- a/Server/Mobile.cs
+++ b/Server/Mobile.cs
@@ -4201,7 +4201,7 @@ namespace Server
public virtual void Use( Item item )
{
- if( item == null || item.Deleted || this.Deleted )
+ if( item == null || item.Deleted || item.QuestItem || this.Deleted )
return;
DisruptiveAction();
@@ -4303,6 +4303,13 @@ namespace Server
{
reject = LRReason.CannotLift;
}
+ else if( item.Nontransferable && amount != item.Amount )
+ {
+ if ( item.QuestItem )
+ from.SendLocalizedMessage( 1074868 ); // Stacks of quest items cannot be unstacked.
+
+ reject = LRReason.CannotLift;
+ }
else if( !item.CheckLift( from, item, ref reject ) )
{
}
@@ -4354,7 +4361,7 @@ namespace Server
foreach( NetState ns in eable )
{
- if( !ns.StygianAbyss && ns.Mobile != from && ns.Mobile.CanSee( from ) )
+ if( ns.Mobile != from && ns.Mobile.CanSee( from ) )
{
if( p == null )
{
@@ -4492,7 +4499,7 @@ namespace Server
foreach( NetState ns in eable )
{
- if( !ns.StygianAbyss && ns.Mobile != this && ns.Mobile.CanSee( this ) )
+ if( ns.Mobile != this && ns.Mobile.CanSee( this ) )
{
if( p == null )
{
@@ -9693,6 +9700,13 @@ namespace Server
/// True if the request is accepted, false if otherwise.
public virtual bool OnEquip( Item item )
{
+ // For some reason OSI allows equipping quest items, but they are unmarked in the process
+ if ( item.QuestItem )
+ {
+ item.QuestItem = false;
+ SendLocalizedMessage( 1074769 ); // An item must be in your backpack (and not in a container within) to be toggled as a quest item.
+ }
+
return true;
}
diff --git a/Server/Network/PacketHandlers.cs b/Server/Network/PacketHandlers.cs
index a4635f291..b9db79bb2 100644
--- a/Server/Network/PacketHandlers.cs
+++ b/Server/Network/PacketHandlers.cs
@@ -820,6 +820,18 @@ namespace Server.Network
break;
}
+ case 0x2F: // Old scroll double click
+ {
+ /*
+ * This command is still sent for items 0xEF3 - 0xEF9
+ *
+ * Command is one of three, depending on the item ID of the scroll:
+ * - [scroll serial]
+ * - [scroll serial] [target serial]
+ * - [scroll serial] [x] [y] [z]
+ */
+ break;
+ }
default:
{
Console.WriteLine( "Client: {0}: Unknown text-command type 0x{1:X2}: {2}", state, type, command );
diff --git a/Server/Network/Packets.cs b/Server/Network/Packets.cs
index 9bcb17f17..4cd3d3479 100644
--- a/Server/Network/Packets.cs
+++ b/Server/Network/Packets.cs
@@ -1837,7 +1837,7 @@ namespace Server.Network
m_Stream.Write( (short) item.X );
m_Stream.Write( (short) item.Y );
m_Stream.Write( (int) parentSerial );
- m_Stream.Write( (ushort) item.Hue );
+ m_Stream.Write( (ushort) ( item.QuestItem ? Item.QuestItemHue : item.Hue ) );
}
}
@@ -1865,7 +1865,7 @@ namespace Server.Network
m_Stream.Write( (short) item.Y );
m_Stream.Write( (byte) 0 ); // Grid Location?
m_Stream.Write( (int) parentSerial );
- m_Stream.Write( (ushort) item.Hue );
+ m_Stream.Write( (ushort) ( item.QuestItem ? Item.QuestItemHue : item.Hue ) );
}
}
@@ -1899,7 +1899,7 @@ namespace Server.Network
m_Stream.Write( (short) loc.m_X );
m_Stream.Write( (short) loc.m_Y );
m_Stream.Write( (int) beheld.Serial );
- m_Stream.Write( (ushort) child.Hue );
+ m_Stream.Write( (ushort) ( child.QuestItem ? Item.QuestItemHue : child.Hue ) );
++written;
}
@@ -1941,7 +1941,7 @@ namespace Server.Network
m_Stream.Write( (short) loc.m_Y );
m_Stream.Write( (byte) 0 ); // Grid Location?
m_Stream.Write( (int) beheld.Serial );
- m_Stream.Write( (ushort) child.Hue );
+ m_Stream.Write( (ushort) ( child.QuestItem ? Item.QuestItemHue : child.Hue ) );
++written;
}
diff --git a/Server/Serialization.cs b/Server/Serialization.cs
index 200ee4baa..ea8955309 100644
--- a/Server/Serialization.cs
+++ b/Server/Serialization.cs
@@ -193,7 +193,7 @@ namespace Server
public abstract void WriteGuildSet( HashSet set ) where T : BaseGuild;
public abstract void WriteGuildSet( HashSet set, bool tidy ) where T : BaseGuild;
#endif
- //Stupid compiler won't notice there 'where' to differentiate the generic methods.
+ // Compiler won't notice their 'where' to differentiate the generic methods.
}
public class BinaryFileWriter : GenericWriter
diff --git a/Server/Utility.cs b/Server/Utility.cs
index 164b1e2d7..116da164f 100644
--- a/Server/Utility.cs
+++ b/Server/Utility.cs
@@ -833,6 +833,9 @@ namespace Server
#region Random Hues
+ ///
+ /// Random pink, blue, green, orange, red or yellow hue
+ ///
public static int RandomNondyedHue()
{
switch ( Random( 6 ) )
@@ -848,61 +851,97 @@ namespace Server
return 0;
}
+ ///
+ /// Random hue in the range 1201-1254
+ ///
public static int RandomPinkHue()
{
return Random( 1201, 54 );
}
+ ///
+ /// Random hue in the range 1301-1354
+ ///
public static int RandomBlueHue()
{
return Random( 1301, 54 );
}
+ ///
+ /// Random hue in the range 1401-1454
+ ///
public static int RandomGreenHue()
{
return Random( 1401, 54 );
}
+ ///
+ /// Random hue in the range 1501-1554
+ ///
public static int RandomOrangeHue()
{
return Random( 1501, 54 );
}
+ ///
+ /// Random hue in the range 1601-1654
+ ///
public static int RandomRedHue()
{
return Random( 1601, 54 );
}
+ ///
+ /// Random hue in the range 1701-1754
+ ///
public static int RandomYellowHue()
{
return Random( 1701, 54 );
}
+ ///
+ /// Random hue in the range 1801-1908
+ ///
public static int RandomNeutralHue()
{
return Random( 1801, 108 );
}
+ ///
+ /// Random hue in the range 2001-2018
+ ///
public static int RandomSnakeHue()
{
return Random( 2001, 18 );
}
+ ///
+ /// Random hue in the range 2101-2130
+ ///
public static int RandomBirdHue()
{
return Random( 2101, 30 );
}
+ ///
+ /// Random hue in the range 2201-2224
+ ///
public static int RandomSlimeHue()
{
return Random( 2201, 24 );
}
+ ///
+ /// Random hue in the range 2301-2318
+ ///
public static int RandomAnimalHue()
{
return Random( 2301, 18 );
}
+ ///
+ /// Random hue in the range 2401-2430
+ ///
public static int RandomMetalHue()
{
return Random( 2401, 30 );
@@ -918,11 +957,25 @@ namespace Server
return hue;
}
+ ///
+ /// Random hue in the range 2-1001
+ ///
public static int RandomDyedHue()
{
return Random( 2, 1000 );
}
+ ///
+ /// Random hue from 0x62, 0x71, 0x03, 0x0D, 0x13, 0x1C, 0x21, 0x30, 0x37, 0x3A, 0x44, 0x59
+ ///
+ public static int RandomBrightHue()
+ {
+ if ( Utility.RandomDouble() < 0.1 )
+ return Utility.RandomList( 0x62, 0x71 );
+
+ return Utility.RandomList( 0x03, 0x0D, 0x13, 0x1C, 0x21, 0x30, 0x37, 0x3A, 0x44, 0x59 );
+ }
+
//[Obsolete( "Depreciated, use the methods for the Mobile's race", false )]
public static int ClipSkinHue( int hue )
{
@@ -1234,11 +1287,13 @@ namespace Server
{
AssignRandomHair( m, true );
}
+
public static void AssignRandomHair( Mobile m, int hue )
{
m.HairItemID = m.Race.RandomHair( m );
m.HairHue = hue;
}
+
public static void AssignRandomHair( Mobile m, bool randomHue )
{
m.HairItemID = m.Race.RandomHair( m );
@@ -1251,11 +1306,13 @@ namespace Server
{
AssignRandomFacialHair( m, true );
}
+
public static void AssignRandomFacialHair( Mobile m, int hue )
{
- m.FacialHairHue = m.Race.RandomFacialHair( m );
+ m.FacialHairItemID = m.Race.RandomFacialHair( m );
m.FacialHairHue = hue;
}
+
public static void AssignRandomFacialHair( Mobile m, bool randomHue )
{
m.FacialHairItemID = m.Race.RandomFacialHair( m );