From 43e5982fbb34494c70922ed133e368b560cec14e Mon Sep 17 00:00:00 2001 From: eos Date: Sun, 26 Feb 2012 05:11:25 +0000 Subject: [PATCH] - Terrible Hatchlings quest fixed to only reward SE weapons and armor. - Slayer and opposition systems now account for inheritance. - Added Satyrs to the fey opposition group. - Added fey slayer vulnerability to cu sidhes. - Added reptilian and dragon slayer vulnerabilities to reptalons. - Various mage AI additions for necromancers. (Spirit speak for healing, pain spike and strangle for damage, automatic mage/necro bias by skill value.) - Fixed a targeting issue not accounting for FightMode.Evil versus low karma targeting. - Added melee damage bonus for Talisman killer properties. - Added general ML loot for ML areas. - Added ML minor artifact drops for named ML mobs. - Added named ML mobs for Bedlam. --- .../Mobiles/AnsellaGryen.cs | 18 +- .../BasePigmentsOfTokuno.cs | 51 ++-- Scripts/Items/Weapons/SlayerEntry.cs | 2 +- Scripts/Items/Weapons/SlayerGroup.cs | 6 +- Scripts/Misc/Loot.cs | 151 +++++++++--- Scripts/Misc/LootPack.cs | 56 ++++- Scripts/Misc/MondainsLegacy.cs | 46 ++++ Scripts/Mobiles/AI/MageAI.cs | 220 +++++++++--------- Scripts/Mobiles/AI/OppositionGroup.cs | 5 +- Scripts/Mobiles/BaseCreature.cs | 94 +++++--- .../Monsters/Humanoid/Melee/SkeletalKnight.cs | 2 +- .../Monsters/ML/Bedlam/LadyJennifyr.cs | 136 +++++++++++ .../Mobiles/Monsters/ML/Bedlam/LadyMarai.cs | 88 +++++++ .../Monsters/ML/Bedlam/MasterJonath.cs | 96 ++++++++ .../Monsters/ML/Bedlam/MasterMikael.cs | 94 ++++++++ .../Monsters/ML/Bedlam/MasterTheophilus.cs | 104 +++++++++ .../Mobiles/Monsters/ML/Bedlam/RedDeath.cs | 91 ++++++++ .../Mobiles/Monsters/ML/Bedlam/SirPatrick.cs | 129 ++++++++++ .../ML/Humanoid/Magic/FetidEssence.cs | 7 +- .../Monsters/ML/Humanoid/Magic/Satyr.cs | 5 + .../Mobiles/Monsters/ML/Special/Ilhenir.cs | 31 +-- Scripts/Spells/Necromancy/AnimateDeadSpell.cs | 6 +- 22 files changed, 1207 insertions(+), 231 deletions(-) create mode 100644 Scripts/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs create mode 100644 Scripts/Mobiles/Monsters/ML/Bedlam/LadyMarai.cs create mode 100644 Scripts/Mobiles/Monsters/ML/Bedlam/MasterJonath.cs create mode 100644 Scripts/Mobiles/Monsters/ML/Bedlam/MasterMikael.cs create mode 100644 Scripts/Mobiles/Monsters/ML/Bedlam/MasterTheophilus.cs create mode 100644 Scripts/Mobiles/Monsters/ML/Bedlam/RedDeath.cs create mode 100644 Scripts/Mobiles/Monsters/ML/Bedlam/SirPatrick.cs diff --git a/Scripts/Engines/Quests/Terrible Hatchlings/Mobiles/AnsellaGryen.cs b/Scripts/Engines/Quests/Terrible Hatchlings/Mobiles/AnsellaGryen.cs index fa95dca2b..b33cecefe 100644 --- a/Scripts/Engines/Quests/Terrible Hatchlings/Mobiles/AnsellaGryen.cs +++ b/Scripts/Engines/Quests/Terrible Hatchlings/Mobiles/AnsellaGryen.cs @@ -71,17 +71,23 @@ namespace Server.Engines.Quests.Zento if ( Utility.RandomBool() ) { - BaseWeapon weapon = Loot.RandomWeapon( true ); - BaseRunicTool.ApplyAttributesTo( weapon, 3, 10, 30 ); + BaseWeapon weapon = Loot.Construct( Loot.SEWeaponTypes ) as BaseWeapon; - cont.DropItem( weapon ); + if ( weapon != null ) + { + BaseRunicTool.ApplyAttributesTo( weapon, 3, 10, 30 ); + cont.DropItem( weapon ); + } } else { - BaseArmor armor = Loot.RandomArmor( true ); - BaseRunicTool.ApplyAttributesTo( armor, 1, 10, 20 ); + BaseArmor armor = Loot.Construct( Loot.SEArmorTypes ) as BaseArmor; - cont.DropItem( armor ); + if ( armor != null ) + { + BaseRunicTool.ApplyAttributesTo( armor, 1, 10, 20 ); + cont.DropItem( armor ); + } } if ( player.PlaceInBackpack( cont ) ) diff --git a/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs b/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs index 90fa09c9b..5bb70eef8 100644 --- a/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs +++ b/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs @@ -7,7 +7,6 @@ namespace Server.Items { public abstract class BasePigmentsOfTokuno : Item, IUsesRemaining { - private static Type[] m_Glasses = new Type[] { typeof( MaritimeGlasses ), @@ -61,23 +60,23 @@ namespace Server.Items }; public override int LabelNumber { get { return 1070933; } } // Pigments of Tokuno - + private int m_UsesRemaining; private TextDefinition m_Label; - - protected TextDefinition Label - { + + protected TextDefinition Label + { get { return m_Label; } set { m_Label = value; InvalidateProperties(); } } - + #region Old Item Serialization Vars /* DO NOT USE! Only used in serialization of pigments that originally derived from Item */ private bool m_InheritsItem; - + protected bool InheritsItem - { - get{ return m_InheritsItem; } + { + get{ return m_InheritsItem; } } #endregion @@ -86,13 +85,13 @@ namespace Server.Items Weight = 1.0; m_UsesRemaining = 1; } - + public BasePigmentsOfTokuno( int uses ) : base( 0xEFF ) { Weight = 1.0; m_UsesRemaining = uses; } - + public BasePigmentsOfTokuno( Serial serial ) : base( serial ) { } @@ -117,7 +116,7 @@ namespace Server.Items else from.SendLocalizedMessage( 502436 ); // That is not accessible. } - + private void InternalCallback( Mobile from, object targeted, object state ) { BasePigmentsOfTokuno pigment = (BasePigmentsOfTokuno)state; @@ -154,7 +153,7 @@ namespace Server.Items from.PlaySound(0x23E); // As per OSI TC1 } } - + public static bool IsValidItem( Item i ) { if( i is BasePigmentsOfTokuno ) @@ -177,12 +176,12 @@ namespace Server.Items if ( i is ITokunoDyable ) return true; - return( + return( IsInTypeList( t, TreasuresOfTokuno.LesserArtifactsTotal ) - || IsInTypeList( t, TreasuresOfTokuno.GreaterArtifacts ) + || IsInTypeList( t, TreasuresOfTokuno.GreaterArtifacts ) || IsInTypeList( t, DemonKnight.ArtifactRarity10 ) || IsInTypeList( t, DemonKnight.ArtifactRarity11 ) - || IsInTypeList( t, BaseCreature.MinorArtifactsMl ) + || IsInTypeList( t, MondainsLegacy.Artifacts ) || IsInTypeList( t, StealableArtifactsSpawner.TypesOfEntires ) || IsInTypeList( t, Paragon.Artifacts ) || IsInTypeList( t, Leviathan.Artifacts ) @@ -191,7 +190,7 @@ namespace Server.Items || IsInTypeList( t, m_DyableHeritageItems ) || IsInTypeList( t, m_Glasses ) ); - } + } private static bool IsInTypeList( Type t, Type[] list ) { @@ -202,7 +201,7 @@ namespace Server.Items return false; } - + public override void Serialize( GenericWriter writer ) { base.Serialize( writer ); @@ -217,10 +216,10 @@ namespace Server.Items base.Deserialize( reader ); int version = reader.ReadInt(); - + switch ( version ) { - case 1: + case 1: { m_UsesRemaining = reader.ReadEncodedInt(); break; @@ -228,23 +227,23 @@ namespace Server.Items case 0: // Old pigments that inherited from item { m_InheritsItem = true; - + if ( this is LesserPigmentsOfTokuno ) ((LesserPigmentsOfTokuno)this).Type = (LesserPigmentType)reader.ReadEncodedInt(); else if ( this is PigmentsOfTokuno ) ((PigmentsOfTokuno)this).Type = (PigmentType)reader.ReadEncodedInt(); else if ( this is MetalPigmentsOfTokuno ) reader.ReadEncodedInt(); - + m_UsesRemaining = reader.ReadEncodedInt(); - + break; } } - + } - + #region IUsesRemaining Members [CommandProperty( AccessLevel.GameMaster )] @@ -259,7 +258,7 @@ namespace Server.Items get { return true; } set {} } - + #endregion } } diff --git a/Scripts/Items/Weapons/SlayerEntry.cs b/Scripts/Items/Weapons/SlayerEntry.cs index 598c6deb2..649311ce4 100644 --- a/Scripts/Items/Weapons/SlayerEntry.cs +++ b/Scripts/Items/Weapons/SlayerEntry.cs @@ -98,7 +98,7 @@ namespace Server.Items for ( int i = 0; i < m_Types.Length; ++i ) { - if ( m_Types[i] == t ) + if ( m_Types[i].IsAssignableFrom( t ) ) return true; } diff --git a/Scripts/Items/Weapons/SlayerGroup.cs b/Scripts/Items/Weapons/SlayerGroup.cs index 17253c256..258bfba5b 100644 --- a/Scripts/Items/Weapons/SlayerGroup.cs +++ b/Scripts/Items/Weapons/SlayerGroup.cs @@ -80,7 +80,7 @@ namespace Server.Items undead.Entries = new SlayerEntry[0]; fey.Opposition = new SlayerGroup[]{ abyss }; - fey.Super = new SlayerEntry( SlayerName.Fey, typeof( Centaur ), typeof( EtherealWarrior ), typeof( Kirin ), typeof( LordOaks ), typeof( Pixie ), typeof( Silvani ), typeof( Treefellow ), typeof( Unicorn ), typeof( Wisp ), typeof( MLDryad ), typeof( Satyr ) ); + fey.Super = new SlayerEntry( SlayerName.Fey, typeof( Centaur ), typeof( CuSidhe ), typeof( EtherealWarrior ), typeof( Kirin ), typeof( LordOaks ), typeof( Pixie ), typeof( Silvani ), typeof( Treefellow ), typeof( Unicorn ), typeof( Wisp ), typeof( MLDryad ), typeof( Satyr ) ); fey.Entries = new SlayerEntry[0]; elemental.Opposition = new SlayerGroup[]{ abyss }; @@ -134,10 +134,10 @@ namespace Server.Items reptilian.Opposition = new SlayerGroup[]{ arachnid }; reptilian.FoundOn = new Type[]{ typeof( TerathanAvenger ), typeof( TerathanMatriarch ) }; - reptilian.Super = new SlayerEntry( SlayerName.ReptilianDeath, typeof( AncientWyrm ), typeof( DeepSeaSerpent ), typeof( GreaterDragon ), typeof( Dragon ), typeof( Drake ), typeof( GiantIceWorm ), typeof( IceSerpent ), typeof( GiantSerpent ), typeof( Hiryu ), typeof( IceSnake ), typeof( JukaLord ), typeof( JukaMage ), typeof( JukaWarrior ), typeof( LavaSerpent ), typeof( LavaSnake ), typeof( LesserHiryu ), typeof( Lizardman ), typeof( OphidianArchmage ), typeof( OphidianKnight ), typeof( OphidianMage ), typeof( OphidianMatriarch ), typeof( OphidianWarrior ), typeof( SeaSerpent ), typeof( Serado ), typeof( SerpentineDragon ), typeof( ShadowWyrm ), typeof( SilverSerpent ), typeof( SkeletalDragon ), typeof( Snake ), typeof( SwampDragon ), typeof( WhiteWyrm ), typeof( Wyvern ), typeof( Yamandon ) ); + reptilian.Super = new SlayerEntry( SlayerName.ReptilianDeath, typeof( AncientWyrm ), typeof( DeepSeaSerpent ), typeof( GreaterDragon ), typeof( Dragon ), typeof( Drake ), typeof( GiantIceWorm ), typeof( IceSerpent ), typeof( GiantSerpent ), typeof( Hiryu ), typeof( IceSnake ), typeof( JukaLord ), typeof( JukaMage ), typeof( JukaWarrior ), typeof( LavaSerpent ), typeof( LavaSnake ), typeof( LesserHiryu ), typeof( Lizardman ), typeof( OphidianArchmage ), typeof( OphidianKnight ), typeof( OphidianMage ), typeof( OphidianMatriarch ), typeof( OphidianWarrior ), typeof( Reptalon ), typeof( SeaSerpent ), typeof( Serado ), typeof( SerpentineDragon ), typeof( ShadowWyrm ), typeof( SilverSerpent ), typeof( SkeletalDragon ), typeof( Snake ), typeof( SwampDragon ), typeof( WhiteWyrm ), typeof( Wyvern ), typeof( Yamandon ) ); reptilian.Entries = new SlayerEntry[] { - new SlayerEntry( SlayerName.DragonSlaying, typeof( AncientWyrm ), typeof( GreaterDragon ), typeof( Dragon ), typeof( Drake ), typeof( Hiryu ), typeof( LesserHiryu ), typeof( SerpentineDragon ), typeof( ShadowWyrm ), typeof( SkeletalDragon ), typeof( SwampDragon ), typeof( WhiteWyrm ), typeof( Wyvern ) ), + new SlayerEntry( SlayerName.DragonSlaying, typeof( AncientWyrm ), typeof( GreaterDragon ), typeof( Dragon ), typeof( Drake ), typeof( Hiryu ), typeof( LesserHiryu ), typeof( Reptalon ), typeof( SerpentineDragon ), typeof( ShadowWyrm ), typeof( SkeletalDragon ), typeof( SwampDragon ), typeof( WhiteWyrm ), typeof( Wyvern ) ), new SlayerEntry( SlayerName.LizardmanSlaughter, typeof( Lizardman ) ), new SlayerEntry( SlayerName.Ophidian, typeof( OphidianArchmage ), typeof( OphidianKnight ), typeof( OphidianMage ), typeof( OphidianMatriarch ), typeof( OphidianWarrior ) ), new SlayerEntry( SlayerName.SnakesBane, typeof( DeepSeaSerpent ), typeof( GiantIceWorm ), typeof( GiantSerpent ), typeof( IceSerpent ), typeof( IceSnake ), typeof( LavaSerpent ), typeof( LavaSnake ), typeof( SeaSerpent ), typeof( Serado ), typeof( SilverSerpent ), typeof( Snake ), typeof( Yamandon ) ) diff --git a/Scripts/Misc/Loot.cs b/Scripts/Misc/Loot.cs index 27a94fcaf..1782c218d 100644 --- a/Scripts/Misc/Loot.cs +++ b/Scripts/Misc/Loot.cs @@ -9,6 +9,49 @@ namespace Server public class Loot { #region List definitions + + #region Mondain's Legacy + private static Type[] m_MLWeaponTypes = new Type[] + { + typeof( AssassinSpike ), typeof( DiamondMace ), typeof( ElvenMachete ), + typeof( ElvenSpellblade ), typeof( Leafblade ), typeof( OrnateAxe ), + typeof( RadiantScimitar ), typeof( RuneBlade ), typeof( WarCleaver ), + typeof( WildStaff ) + }; + + public static Type[] MLWeaponTypes{ get{ return m_MLWeaponTypes; } } + + private static Type[] m_MLRangedWeaponTypes = new Type[] + { + typeof( ElvenCompositeLongbow ), typeof( MagicalShortbow ) + }; + + public static Type[] MLRangedWeaponTypes{ get{ return m_MLRangedWeaponTypes; } } + + private static Type[] m_MLArmorTypes = new Type[] + { + typeof( Circlet ), typeof( GemmedCirclet ), typeof( LeafTonlet ), + typeof( RavenHelm ), typeof( RoyalCirclet ), typeof( VultureHelm ), + typeof( WingedHelm ), typeof( LeafArms ), typeof( LeafChest ), + typeof( LeafGloves ), typeof( LeafGorget ), typeof( LeafLegs ), + typeof( WoodlandArms ), typeof( WoodlandChest ), typeof( WoodlandGloves ), + typeof( WoodlandGorget ), typeof( WoodlandLegs ), typeof( HideChest ), + typeof( HideGloves ), typeof( HideGorget ), typeof( HidePants ), + typeof( HidePauldrons ) + }; + + public static Type[] MLArmorTypes{ get{ return m_MLArmorTypes; } } + + private static Type[] m_MLClothingTypes = new Type[] + { + typeof( MaleElvenRobe ), typeof( FemaleElvenRobe ), typeof( ElvenPants ), + typeof( ElvenShirt ), typeof( ElvenDarkShirt ), typeof( ElvenBoots ), + typeof( VultureHelm ), typeof( WoodlandBelt ) + }; + + public static Type[] MLClothingTypes{ get{ return m_MLClothingTypes; } } + #endregion + private static Type[] m_SEWeaponTypes = new Type[] { typeof( Bokuto ), typeof( Daisho ), typeof( Kama ), @@ -224,19 +267,23 @@ namespace Server private static Type[] m_PaladinScrollTypes = new Type[0]; - private static Type[] m_ArcaneScrollTypes = new Type[] + #region Mondain's Legacy + private static Type[] m_ArcanistScrollTypes = new Type[] { - typeof( ArcaneCircleScroll ), typeof ( GiftOfRenewalScroll ), typeof( ImmolatingWeaponScroll ), typeof( AttuneWeaponScroll ), - typeof( ThunderstormScroll ), typeof( NatureFuryScroll ), typeof( ReaperFormScroll ), typeof( WildfireScroll ), - typeof( EssenceOfWindScroll ), typeof( DryadAllureScroll ), typeof( EtherealVoyageScroll ), typeof( WordOfDeathScroll ), - typeof( GiftOfLifeScroll ), typeof( ArcaneEmpowermentScroll ) + typeof( ArcaneCircleScroll ), typeof( GiftOfRenewalScroll ), typeof( ImmolatingWeaponScroll ), typeof( AttuneWeaponScroll ), + typeof( ThunderstormScroll ), typeof( NatureFuryScroll ), /*typeof( SummonFeyScroll ), typeof( SummonFiendScroll ),*/ + typeof( ReaperFormScroll ), typeof( WildfireScroll ), typeof( EssenceOfWindScroll ), typeof( DryadAllureScroll ), + typeof( EtherealVoyageScroll ), typeof( WordOfDeathScroll ), typeof( GiftOfLifeScroll ), typeof( ArcaneEmpowermentScroll ) }; + #endregion public static Type[] RegularScrollTypes{ get{ return m_RegularScrollTypes; } } public static Type[] NecromancyScrollTypes{ get{ return m_NecromancyScrollTypes; } } public static Type[] SENecromancyScrollTypes{ get{ return m_SENecromancyScrollTypes; } } public static Type[] PaladinScrollTypes{ get{ return m_PaladinScrollTypes; } } - public static Type[] ArcaneScrollTypes{ get{ return m_ArcaneScrollTypes; } } + #region Mondain's Legacy + public static Type[] ArcanistScrollTypes{ get{ return m_ArcanistScrollTypes; } } + #endregion private static Type[] m_GrimmochJournalTypes = new Type[] { @@ -371,11 +418,16 @@ namespace Server public static BaseClothing RandomClothing() { - return RandomClothing( false ); + return RandomClothing( false, false ); } - public static BaseClothing RandomClothing( bool inTokuno ) + public static BaseClothing RandomClothing( bool inTokuno, bool isMondain ) { + #region Mondain's Legacy + if ( Core.ML && isMondain ) + return Construct( m_MLClothingTypes, m_AosClothingTypes, m_ClothingTypes ) as BaseClothing; + #endregion + if ( Core.SE && inTokuno ) return Construct( m_SEClothingTypes, m_AosClothingTypes, m_ClothingTypes ) as BaseClothing; @@ -387,11 +439,16 @@ namespace Server public static BaseWeapon RandomRangedWeapon() { - return RandomRangedWeapon( false ); + return RandomRangedWeapon( false, false ); } - public static BaseWeapon RandomRangedWeapon( bool inTokuno ) + public static BaseWeapon RandomRangedWeapon( bool inTokuno, bool isMondain ) { + #region Mondain's Legacy + if ( Core.ML && isMondain ) + return Construct( m_MLRangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes ) as BaseWeapon; + #endregion + if ( Core.SE && inTokuno ) return Construct( m_SERangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes ) as BaseWeapon; @@ -403,11 +460,16 @@ namespace Server public static BaseWeapon RandomWeapon() { - return RandomWeapon( false ); + return RandomWeapon( false, false ); } - public static BaseWeapon RandomWeapon( bool inTokuno ) + public static BaseWeapon RandomWeapon( bool inTokuno, bool isMondain ) { + #region Mondain's Legacy + if ( Core.ML && isMondain ) + return Construct( m_MLWeaponTypes, m_AosWeaponTypes, m_WeaponTypes ) as BaseWeapon; + #endregion + if ( Core.SE && inTokuno ) return Construct( m_SEWeaponTypes, m_AosWeaponTypes, m_WeaponTypes ) as BaseWeapon; @@ -419,11 +481,16 @@ namespace Server public static Item RandomWeaponOrJewelry() { - return RandomWeaponOrJewelry( false ); + return RandomWeaponOrJewelry( false, false ); } - public static Item RandomWeaponOrJewelry( bool inTokuno ) + public static Item RandomWeaponOrJewelry( bool inTokuno, bool isMondain ) { + #region Mondain's Legacy + if ( Core.ML && isMondain ) + return Construct( m_MLWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_JewelryTypes ); + #endregion + if ( Core.SE && inTokuno ) return Construct( m_SEWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_JewelryTypes ); @@ -440,11 +507,16 @@ namespace Server public static BaseArmor RandomArmor() { - return RandomArmor( false ); + return RandomArmor( false, false ); } - public static BaseArmor RandomArmor( bool inTokuno ) + public static BaseArmor RandomArmor( bool inTokuno, bool isMondain ) { + #region Mondain's Legacy + if ( Core.ML && isMondain ) + return Construct( m_MLArmorTypes, m_ArmorTypes ) as BaseArmor; + #endregion + if ( Core.SE && inTokuno ) return Construct( m_SEArmorTypes, m_ArmorTypes ) as BaseArmor; @@ -469,11 +541,16 @@ namespace Server public static Item RandomArmorOrHat() { - return RandomArmorOrHat( false ); + return RandomArmorOrHat( false, false ); } - public static Item RandomArmorOrHat( bool inTokuno ) + public static Item RandomArmorOrHat( bool inTokuno, bool isMondain ) { + #region Mondain's Legacy + if ( Core.ML && isMondain ) + return Construct( m_MLArmorTypes, m_ArmorTypes, m_AosHatTypes, m_HatTypes ); + #endregion + if ( Core.SE && inTokuno ) return Construct( m_SEArmorTypes, m_ArmorTypes, m_SEHatTypes, m_AosHatTypes, m_HatTypes ); @@ -493,11 +570,16 @@ namespace Server public static BaseArmor RandomArmorOrShield() { - return RandomArmorOrShield( false ); + return RandomArmorOrShield( false, false ); } - public static BaseArmor RandomArmorOrShield( bool inTokuno ) + public static BaseArmor RandomArmorOrShield( bool inTokuno, bool isMondain ) { + #region Mondain's Legacy + if ( Core.ML && isMondain ) + return Construct( m_MLArmorTypes, m_ArmorTypes, m_AosShieldTypes, m_ShieldTypes ) as BaseArmor; + #endregion + if ( Core.SE && inTokuno ) return Construct( m_SEArmorTypes, m_ArmorTypes, m_AosShieldTypes, m_ShieldTypes ) as BaseArmor; @@ -509,11 +591,16 @@ namespace Server public static Item RandomArmorOrShieldOrJewelry() { - return RandomArmorOrShieldOrJewelry( false ); + return RandomArmorOrShieldOrJewelry( false, false ); } - public static Item RandomArmorOrShieldOrJewelry( bool inTokuno ) + public static Item RandomArmorOrShieldOrJewelry( bool inTokuno, bool isMondain ) { + #region Mondain's Legacy + if ( Core.ML && isMondain ) + return Construct( m_MLArmorTypes, m_ArmorTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes, m_JewelryTypes ); + #endregion + if ( Core.SE && inTokuno ) return Construct( m_SEArmorTypes, m_ArmorTypes, m_SEHatTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes, m_JewelryTypes ); @@ -525,11 +612,16 @@ namespace Server public static Item RandomArmorOrShieldOrWeapon() { - return RandomArmorOrShieldOrWeapon( false ); + return RandomArmorOrShieldOrWeapon( false, false ); } - public static Item RandomArmorOrShieldOrWeapon( bool inTokuno ) + public static Item RandomArmorOrShieldOrWeapon( bool inTokuno, bool isMondain ) { + #region Mondain's Legacy + if ( Core.ML && isMondain ) + return Construct( m_MLWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_MLRangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes, m_MLArmorTypes, m_ArmorTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes ); + #endregion + if ( Core.SE && inTokuno ) return Construct( m_SEWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_SERangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes, m_SEArmorTypes, m_ArmorTypes, m_SEHatTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes ); @@ -541,11 +633,16 @@ namespace Server public static Item RandomArmorOrShieldOrWeaponOrJewelry() { - return RandomArmorOrShieldOrWeaponOrJewelry( false ); + return RandomArmorOrShieldOrWeaponOrJewelry( false, false ); } - public static Item RandomArmorOrShieldOrWeaponOrJewelry( bool inTokuno ) + public static Item RandomArmorOrShieldOrWeaponOrJewelry( bool inTokuno, bool isMondain ) { + #region Mondain's Legacy + if ( Core.ML && isMondain ) + return Construct( m_MLWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_MLRangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes, m_MLArmorTypes, m_ArmorTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes, m_JewelryTypes ); + #endregion + if ( Core.SE && inTokuno ) return Construct( m_SEWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_SERangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes, m_SEArmorTypes, m_ArmorTypes, m_SEHatTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes, m_JewelryTypes ); @@ -613,7 +710,7 @@ namespace Server case SpellbookType.Regular: types = m_RegularScrollTypes; break; case SpellbookType.Necromancer: types = (Core.SE ? m_SENecromancyScrollTypes : m_NecromancyScrollTypes ); break; case SpellbookType.Paladin: types = m_PaladinScrollTypes; break; - case SpellbookType.Arcanist: types = m_ArcaneScrollTypes; break; + case SpellbookType.Arcanist: types = m_ArcanistScrollTypes; break; } return Construct( types, Utility.RandomMinMax( minIndex, maxIndex ) ) as SpellScroll; diff --git a/Scripts/Misc/LootPack.cs b/Scripts/Misc/LootPack.cs index c369edfd6..243c01c4e 100644 --- a/Scripts/Misc/LootPack.cs +++ b/Scripts/Misc/LootPack.cs @@ -501,6 +501,21 @@ namespace Server { new LootPackEntry( false, PotionItems, 100.00, 1 ) } ); + + /* + // TODO: Uncomment once added + #region Mondain's Legacy + public static readonly LootPackItem[] ParrotItem = new LootPackItem[] + { + new LootPackItem( typeof( ParrotItem ), 1 ) + }; + + public static readonly LootPack Parrot = new LootPack( new LootPackEntry[] + { + new LootPackEntry( false, ParrotItem, 10.00, 1 ) + } ); + #endregion + */ } public class LootPackEntry @@ -561,6 +576,37 @@ namespace Server return ( m.Map == Map.Tokuno ); } + #region Mondain's Legacy + private static bool IsMondain( Mobile m ) + { + if ( m.Region.IsPartOf( "Twisted Weald" ) ) + return true; + + if ( m.Region.IsPartOf( "Sanctuary" ) ) + return true; + + if ( m.Region.IsPartOf( "Prism of Light" ) ) + return true; + + if ( m.Region.IsPartOf( "Citadel" ) ) + return true; + + if ( m.Region.IsPartOf( "Bedlam" ) ) + return true; + + if ( m.Region.IsPartOf( "Blighted Grove" ) ) + return true; + + if ( m.Region.IsPartOf( "Painted Caves" ) ) + return true; + + if ( m.Region.IsPartOf( "Palace of Paroxysmus" ) ) + return true; + + return false; + } + #endregion + public Item Construct( Mobile from, int luckChance, bool spawning ) { if ( m_AtSpawnTime != spawning ) @@ -578,7 +624,7 @@ namespace Server LootPackItem item = m_Items[i]; if ( rnd < item.Chance ) - return Mutate( from, luckChance, item.Construct( IsInTokuno( from ) ) ); + return Mutate( from, luckChance, item.Construct( IsInTokuno( from ), IsMondain( from ) ) ); rnd -= item.Chance; } @@ -850,18 +896,18 @@ namespace Server return Loot.RandomScroll( minCircle * 8, (maxCircle * 8) + 7, SpellbookType.Regular ); } - public Item Construct( bool inTokuno ) + public Item Construct( bool inTokuno, bool isMondain ) { try { Item item; if ( m_Type == typeof( BaseRanged ) ) - item = Loot.RandomRangedWeapon( inTokuno ); + item = Loot.RandomRangedWeapon( inTokuno, isMondain ); else if ( m_Type == typeof( BaseWeapon ) ) - item = Loot.RandomWeapon( inTokuno ); + item = Loot.RandomWeapon( inTokuno, isMondain ); else if ( m_Type == typeof( BaseArmor ) ) - item = Loot.RandomArmorOrHat( inTokuno ); + item = Loot.RandomArmorOrHat( inTokuno, isMondain ); else if ( m_Type == typeof( BaseShield ) ) item = Loot.RandomShield(); else if ( m_Type == typeof( BaseJewel ) ) diff --git a/Scripts/Misc/MondainsLegacy.cs b/Scripts/Misc/MondainsLegacy.cs index fecd5d8ce..8a08e7b2b 100644 --- a/Scripts/Misc/MondainsLegacy.cs +++ b/Scripts/Misc/MondainsLegacy.cs @@ -1,10 +1,56 @@ using System; using Server; +using Server.Items; +using Server.Mobiles; namespace Server { public static class MondainsLegacy { + public static Type[] Artifacts { get { return m_Artifacts; } } + + private static Type[] m_Artifacts = new Type[] + { + typeof( AegisOfGrace ), typeof( BladeDance ), typeof( BloodwoodSpirit ), typeof( Bonesmasher ), + typeof( Boomstick ), typeof( BrightsightLenses ), typeof( FeyLeggings ), typeof( FleshRipper ), + typeof( HelmOfSwiftness ), typeof( PadsOfTheCuSidhe ), typeof( QuiverOfRage ), typeof( QuiverOfElements ), + typeof( RaedsGlory ), typeof( RighteousAnger ), typeof( RobeOfTheEclipse ), typeof( RobeOfTheEquinox ), + typeof( SoulSeeker ), typeof( TalonBite ), typeof( TotemOfVoid ), typeof( WildfireBow ), + typeof( Windsong ) + }; + + public static bool CheckArtifactChance( Mobile m, BaseCreature bc ) + { + if ( !Core.ML ) + return false; + + return Paragon.CheckArtifactChance( m, bc ); + } + + public static void GiveArtifactTo( Mobile m ) + { + Item item = Activator.CreateInstance( m_Artifacts[Utility.Random( m_Artifacts.Length )] ) as Item; + + if ( item == null ) + return; + + if ( m.AddToBackpack( item ) ) + { + m.SendLocalizedMessage( 1062317 ); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + m.SendLocalizedMessage( 1072223 ); // An item has been placed in your backpack. + } + else if ( m.BankBox.TryDropItem( m, item, false ) ) + { + m.SendLocalizedMessage( 1062317 ); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + m.SendLocalizedMessage( 1072224 ); // An item has been placed in your bank box. + } + else + { + // Item was placed at feet by m.AddToBackpack + m.SendLocalizedMessage( 1072523 ); // You find an artifact, but your backpack and bank are too full to hold it. + } + } + public static bool CheckML( Mobile from ) { return CheckML( from, true ); diff --git a/Scripts/Mobiles/AI/MageAI.cs b/Scripts/Mobiles/AI/MageAI.cs index 751476006..936f2db1a 100644 --- a/Scripts/Mobiles/AI/MageAI.cs +++ b/Scripts/Mobiles/AI/MageAI.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using Server.Spells; using Server.Spells.Fifth; @@ -37,24 +36,28 @@ namespace Server.Mobiles public virtual bool SmartAI { - get { return ( m_Mobile is BaseVendor || m_Mobile is BaseEscortable ); } + get { return ( m_Mobile is BaseVendor || m_Mobile is BaseEscortable/* || m_Mobile is Changeling*/ ); } // TODO: Uncomment once added + } + + public virtual bool IsNecromancer + { + get { return ( m_Mobile.Skills[ SkillName.Necromancy ].Value > 50 ); } } private const double HealChance = 0.10; // 10% chance to heal at gm magery private const double TeleportChance = 0.05; // 5% chance to teleport at gm magery private const double DispelChance = 0.75; // 75% chance to dispel at gm magery - public virtual double ScaleByMagery( double v ) + public virtual double ScaleBySkill( double v, SkillName skill ) { - return m_Mobile.Skills[ SkillName.Magery ].Value * v * 0.01; + return v * m_Mobile.Skills[ skill ].Value / 100; } public override bool DoActionWander() { if( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) { - if( m_Mobile.Debug ) - m_Mobile.DebugSay( "I am going to attack {0}", m_Mobile.FocusMob.Name ); + m_Mobile.DebugSay( "I am going to attack {0}", m_Mobile.FocusMob.Name ); m_Mobile.Combatant = m_Mobile.FocusMob; Action = ActionType.Combat; @@ -74,7 +77,7 @@ namespace Server.Mobiles base.DoActionWander(); - if( ( Utility.RandomDouble() < .05 ) ) + if( Utility.RandomDouble() < 0.05 ) { Spell spell = CheckCastHealingSpell(); @@ -104,7 +107,7 @@ namespace Server.Mobiles if( !SmartAI ) { - if( ScaleByMagery( HealChance ) < Utility.RandomDouble() ) + if( ScaleBySkill( HealChance, SkillName.Magery ) < Utility.RandomDouble() ) return null; } else @@ -117,13 +120,22 @@ namespace Server.Mobiles if( m_Mobile.Hits < ( m_Mobile.HitsMax - 50 ) ) { - spell = new GreaterHealSpell( m_Mobile, null ); + if ( UseNecromancy() ) + { + m_Mobile.UseSkill( SkillName.SpiritSpeak ); + } + else + { + spell = new GreaterHealSpell( m_Mobile, null ); - if( spell == null ) - spell = new HealSpell( m_Mobile, null ); + if( spell == null ) + spell = new HealSpell( m_Mobile, null ); + } } else if( m_Mobile.Hits < ( m_Mobile.HitsMax - 10 ) ) + { spell = new HealSpell( m_Mobile, null ); + } double delay; @@ -175,7 +187,7 @@ namespace Server.Mobiles public void OnFailedMove() { - if( !m_Mobile.DisallowAllMoves && ( SmartAI ? Utility.Random( 4 ) == 0 : ScaleByMagery( TeleportChance ) > Utility.RandomDouble() ) ) + if( !m_Mobile.DisallowAllMoves && ( SmartAI ? Utility.Random( 4 ) == 0 : ScaleBySkill( TeleportChance, SkillName.Magery ) > Utility.RandomDouble() ) ) { if( m_Mobile.Target != null ) m_Mobile.Target.Cancel( m_Mobile, TargetCancelType.Canceled ); @@ -186,8 +198,7 @@ namespace Server.Mobiles } else if( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) { - if( m_Mobile.Debug ) - m_Mobile.DebugSay( "My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name ); + m_Mobile.DebugSay( "My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name ); m_Mobile.Combatant = m_Mobile.FocusMob; Action = ActionType.Combat; @@ -209,46 +220,41 @@ namespace Server.Mobiles OnFailedMove(); } - public virtual bool CanCastNecro() + public virtual bool UseNecromancy() { - return ( Utility.RandomBool() && ( m_Mobile is BaseCreature ) && ( (BaseCreature)m_Mobile ).IsNecromancer ); - } + if ( IsNecromancer ) + return ( Utility.Random( m_Mobile.Skills[ SkillName.Necromancy ].BaseFixedPoint ) > Utility.Random( m_Mobile.Skills[ SkillName.Magery ].BaseFixedPoint ) ); - public virtual bool CanCastNecroBias( int bias ) - { - return ( CanCastNecro() && Utility.Random( bias ) == 0 ); - } - - public virtual Spell GetRandomDamage() - { - return ( CanCastNecroBias( 2 ) ) ? GetRandomDamageNecroSpell() : GetRandomDamageSpell(); - } - - public virtual Spell GetRandomDamageNecroSpell() - { - int possibles = 3; - - if( myNecro >= 100 ) - { - possibles = 5; - } - switch( Utility.Random( possibles ) ) - { - default: m_Mobile.DebugSay( "Vengeful Spirit" ); return new VengefulSpiritSpell( m_Mobile, null ); - - case 0: m_Mobile.DebugSay( "Pain Spike" ); return new PainSpikeSpell( m_Mobile, null ); - case 1: m_Mobile.DebugSay( "Poison Strike" ); return new PoisonStrikeSpell( m_Mobile, null ); - case 2: m_Mobile.DebugSay( "Strangle" ); return new StrangleSpell( m_Mobile, null ); - case 3: m_Mobile.DebugSay( "Wither" ); return new WitherSpell( m_Mobile, null ); - } + return false; } public virtual Spell GetRandomDamageSpell() { - int maxCircle = (int)( ( myMagery + 20.0 ) / ( 100.0 / 7.0 ) ); + return UseNecromancy() ? GetRandomDamageSpellNecro() : GetRandomDamageSpellMage(); + } + + public virtual Spell GetRandomDamageSpellNecro() + { + int bound = ( m_Mobile.Skills[ SkillName.Necromancy ].Value >= 100 ) ? 5 : 3; + + switch( Utility.Random( bound ) ) + { + case 0: m_Mobile.DebugSay( "Pain Spike" ); return new PainSpikeSpell( m_Mobile, null ); + case 1: m_Mobile.DebugSay( "Poison Strike" ); return new PoisonStrikeSpell( m_Mobile, null ); + case 2: m_Mobile.DebugSay( "Strangle" ); return new StrangleSpell( m_Mobile, null ); + case 3: m_Mobile.DebugSay( "Wither" ); return new WitherSpell( m_Mobile, null ); + default: m_Mobile.DebugSay( "Vengeful Spirit" ); return new VengefulSpiritSpell( m_Mobile, null ); + } + } + + public virtual Spell GetRandomDamageSpellMage() + { + int maxCircle = (int)( ( m_Mobile.Skills[ SkillName.Magery ].Value + 20.0 ) / ( 100.0 / 7.0 ) ); if( maxCircle < 1 ) maxCircle = 1; + else if( maxCircle > 8 ) + maxCircle = 8; switch( Utility.Random( maxCircle * 2 ) ) { @@ -268,49 +274,39 @@ namespace Server.Mobiles } } - public virtual Spell GetRandomCurse() + public virtual Spell GetRandomCurseSpell() { - return ( CanCastNecro() ) ? GetRandomNecroCurseSpell() : GetRandomCurseSpell(); + return UseNecromancy() ? GetRandomCurseSpellNecro() : GetRandomCurseSpellMage(); } - public virtual Spell GetRandomNecroCurseSpell() + public virtual Spell GetRandomCurseSpellNecro() { switch( Utility.Random( 4 ) ) { - default: case 0: m_Mobile.DebugSay( "Blood Oath" ); return new BloodOathSpell( m_Mobile, null ); case 1: m_Mobile.DebugSay( "Corpse Skin" ); return new CorpseSkinSpell( m_Mobile, null ); case 2: m_Mobile.DebugSay( "Evil Omen" ); return new EvilOmenSpell( m_Mobile, null ); - case 3: m_Mobile.DebugSay( "Mind Rot" ); return new MindRotSpell( m_Mobile, null ); + default: m_Mobile.DebugSay( "Mind Rot" ); return new MindRotSpell( m_Mobile, null ); } } - public virtual Spell GetRandomCurseSpell() + public virtual Spell GetRandomCurseSpellMage() { - if( Utility.Random( 4 ) == 3 ) - { - if( myMagery >= 40.0 ) - { - return new CurseSpell( m_Mobile, null ); - } - } + if( m_Mobile.Skills[ SkillName.Magery ].Value >= 40.0 && Utility.Random( 4 ) == 0 ) + return new CurseSpell( m_Mobile, null ); switch( Utility.Random( 3 ) ) { - default: case 0: return new WeakenSpell( m_Mobile, null ); case 1: return new ClumsySpell( m_Mobile, null ); - case 2: return new FeeblemindSpell( m_Mobile, null ); + default: return new FeeblemindSpell( m_Mobile, null ); } } public virtual Spell GetRandomManaDrainSpell() { - if( Utility.RandomBool() ) - { - if( myMagery >= 80.0 ) - return new ManaVampireSpell( m_Mobile, null ); - } + if( m_Mobile.Skills[ SkillName.Magery ].Value >= 80.0 && Utility.RandomBool() ) + return new ManaVampireSpell( m_Mobile, null ); return new ManaDrainSpell( m_Mobile, null ); } @@ -319,7 +315,7 @@ namespace Server.Mobiles { if( !SmartAI ) { - if( ScaleByMagery( DispelChance ) > Utility.RandomDouble() ) + if( ScaleBySkill( DispelChance, SkillName.Magery ) > Utility.RandomDouble() ) return new DispelSpell( m_Mobile, null ); return ChooseSpell( toDispel ); @@ -340,12 +336,6 @@ namespace Server.Mobiles return spell; } - public virtual double myNecro { get { return m_Mobile.Skills[ SkillName.Magery ].Value; } } - - public virtual double myMagery { get { return m_Mobile.Skills[ SkillName.Magery ].Value; } } - - public virtual double mySpiritSpeak { get { return m_Mobile.Skills[ SkillName.SpiritSpeak ].Value; } } - public virtual Spell ChooseSpell( Mobile c ) { Spell spell = null; @@ -357,64 +347,74 @@ namespace Server.Mobiles if( spell != null ) return spell; + if( IsNecromancer ) + { + double psDamage = ( ( m_Mobile.Skills[ SkillName.SpiritSpeak ].Value - c.Skills[ SkillName.MagicResist ].Value ) / 10 ) + ( c.Player ? 18 : 30 ); + + if( psDamage > c.Hits ) + return new PainSpikeSpell( m_Mobile, null ); + } + switch (Utility.Random(16)) { case 0: case 1: // Poison them { - //m_Mobile.DebugSay( "Attempting to poison" ); + if (c.Poisoned) + goto default; - if (!c.Poisoned) - spell = new PoisonSpell(m_Mobile, null); + m_Mobile.DebugSay( "Attempting to poison" ); + spell = new PoisonSpell(m_Mobile, null); break; } - case 2: // Bless ourselves. + case 2: // Bless ourselves { - //m_Mobile.DebugSay( "Blessing myself" ); + m_Mobile.DebugSay( "Blessing myself" ); spell = new BlessSpell(m_Mobile, null); break; } case 3: - case 4: // Curse them. + case 4: // Curse them { - //m_Mobile.DebugSay( "Attempting to curse" ); + m_Mobile.DebugSay( "Attempting to curse" ); - spell = GetRandomCurse(); + spell = GetRandomCurseSpell(); break; } - case 5: // Paralyze them. + case 5: // Paralyze them { - //m_Mobile.DebugSay( "Attempting to paralyze" ); + if (m_Mobile.Skills[ SkillName.Magery ].Value <= 50.0) + goto default; - if (m_Mobile.Skills[SkillName.Magery].Value > 50.0) - spell = new ParalyzeSpell(m_Mobile, null); + m_Mobile.DebugSay( "Attempting to paralyze" ); + spell = new ParalyzeSpell(m_Mobile, null); break; } case 6: // Drain mana { - //m_Mobile.DebugSay( "Attempting to drain mana" ); + m_Mobile.DebugSay( "Attempting to drain mana" ); spell = GetRandomManaDrainSpell(); break; } - case 7: + case 7: // Invis ourselves { - //m_Mobile.DebugSay( "Attempting to Invis" ); - if (Utility.RandomBool()) - spell = new InvisibilitySpell(m_Mobile, null); + goto default; + m_Mobile.DebugSay( "Attempting to invis myself" ); + + spell = new InvisibilitySpell(m_Mobile, null); break; } - - default: // Damage them. + default: // Damage them { - //m_Mobile.DebugSay( "Just doing damage" ); + m_Mobile.DebugSay( "Just doing damage" ); - spell = GetRandomDamage(); + spell = GetRandomDamageSpell(); break; } } @@ -429,12 +429,12 @@ namespace Server.Mobiles switch( Utility.Random( 3 ) ) { - default: case 0: // Poison them { - if( !c.Poisoned ) - spell = new PoisonSpell( m_Mobile, null ); + if( c.Poisoned ) + goto case 1; + spell = new PoisonSpell( m_Mobile, null ); break; } case 1: // Deal some damage @@ -443,9 +443,9 @@ namespace Server.Mobiles break; } - case 2: // Set up a combo + default: // Set up a combo { - if( m_Mobile.Mana < 40 && m_Mobile.Mana > 15 ) + if( m_Mobile.Mana > 15 && m_Mobile.Mana < 40 ) { if( c.Paralyzed && !c.Poisoned ) { @@ -460,7 +460,7 @@ namespace Server.Mobiles } else if( m_Mobile.Mana > 60 ) { - if( Utility.Random( 2 ) == 0 && !c.Paralyzed && !c.Frozen && !c.Poisoned ) + if( Utility.RandomBool() && !c.Paralyzed && !c.Frozen && !c.Poisoned ) { m_Combo = 0; spell = new ParalyzeSpell( m_Mobile, null ); @@ -499,15 +499,16 @@ namespace Server.Mobiles { if( !c.Poisoned ) spell = new PoisonSpell( m_Mobile, null ); + else if ( IsNecromancer ) + spell = new StrangleSpell( m_Mobile, null ); ++m_Combo; // Move to next spell } if( m_Combo == 3 && spell == null ) { - switch( Utility.Random( 3 ) ) + switch( Utility.Random( IsNecromancer ? 4 : 3 ) ) { - default: case 0: { if( c.Int < c.Dex ) @@ -531,6 +532,12 @@ namespace Server.Mobiles m_Combo = -1; // Reset combo state break; } + default: + { + spell = new PainSpikeSpell( m_Mobile, null ); + m_Combo = -1; // Reset combo state + break; + } } } else if( m_Combo == 4 && spell == null ) @@ -550,7 +557,7 @@ namespace Server.Mobiles } else { - double del = ScaleByMagery( 3.0 ); + double del = ScaleBySkill( 3.0, SkillName.Magery ); double min = 6.0 - ( del * 0.75 ); double max = 6.0 - ( del * 1.25 ); @@ -573,8 +580,7 @@ namespace Server.Mobiles if( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) { - if( m_Mobile.Debug ) - m_Mobile.DebugSay( "Something happened to my combatant, so I am going to fight {0}", m_Mobile.FocusMob.Name ); + m_Mobile.DebugSay( "Something happened to my combatant, so I am going to fight {0}", m_Mobile.FocusMob.Name ); m_Mobile.Combatant = c = m_Mobile.FocusMob; m_Mobile.FocusMob = null; @@ -650,8 +656,7 @@ namespace Server.Mobiles if( flee ) { - if( m_Mobile.Debug ) - m_Mobile.DebugSay( "I am going to flee from {0}", c.Name ); + m_Mobile.DebugSay( "I am going to flee from {0}", c.Name ); Action = ActionType.Flee; return true; @@ -784,8 +789,7 @@ namespace Server.Mobiles } else if( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) { - if( m_Mobile.Debug ) - m_Mobile.DebugSay( "I am scared of {0}", m_Mobile.FocusMob.Name ); + m_Mobile.DebugSay( "I am scared of {0}", m_Mobile.FocusMob.Name ); RunFrom( m_Mobile.FocusMob ); m_Mobile.FocusMob = null; diff --git a/Scripts/Mobiles/AI/OppositionGroup.cs b/Scripts/Mobiles/AI/OppositionGroup.cs index dd095eb60..b5c1730f9 100644 --- a/Scripts/Mobiles/AI/OppositionGroup.cs +++ b/Scripts/Mobiles/AI/OppositionGroup.cs @@ -35,7 +35,7 @@ namespace Server bool contains = false; for ( int j = 0; !contains && j < group.Length; ++j ) - contains = ( type == group[j] ); + contains = group[j].IsAssignableFrom( type ); if ( contains ) return i; @@ -107,7 +107,8 @@ namespace Server typeof( Unicorn ), typeof( Wisp ), typeof( Treefellow ), - typeof( MLDryad ) + typeof( MLDryad ), + typeof( Satyr ) }, new Type[] { diff --git a/Scripts/Mobiles/BaseCreature.cs b/Scripts/Mobiles/BaseCreature.cs index 95de92752..ec230a2c0 100644 --- a/Scripts/Mobiles/BaseCreature.cs +++ b/Scripts/Mobiles/BaseCreature.cs @@ -286,8 +286,6 @@ namespace Server.Mobiles #region Bonding public const bool BondingEnabled = true; - public virtual bool IsNecromancer { get { return ( Skills[ SkillName.Necromancy ].Value > 50 ); } } - public virtual bool IsBondable{ get{ return ( BondingEnabled && !Summoned ); } } public virtual TimeSpan BondingDelay{ get{ return TimeSpan.FromDays( 7.0 ); } } public virtual TimeSpan BondingAbandonDelay{ get{ return TimeSpan.FromDays( 1.0 ); } } @@ -525,7 +523,7 @@ namespace Server.Mobiles public virtual int BreathRange{ get{ return RangePerception; } } // Damage types - public virtual int BreathChaosDamage { get { return 0; } } + public virtual int BreathChaosDamage{ get { return 0; } } public virtual int BreathPhysicalDamage{ get{ return 0; } } public virtual int BreathFireDamage{ get{ return 100; } } public virtual int BreathColdDamage{ get{ return 0; } } @@ -648,7 +646,7 @@ namespace Server.Mobiles } } } - + public virtual int BreathComputeDamage() { int damage = (int)(Hits * BreathDamageScalar); @@ -683,7 +681,7 @@ namespace Server.Mobiles { loc = target.Location; map = target.Map; - } + } else { bool validLocation = false; @@ -869,6 +867,9 @@ namespace Server.Mobiles BaseCreature c = (BaseCreature)m; + if ( ( FightMode == FightMode.Evil && m.Karma < 0 ) || ( c.FightMode == FightMode.Evil && Karma < 0 ) ) + return true; + return ( m_iTeam != c.m_iTeam || ( (m_bSummoned || m_bControlled) != (c.m_bSummoned || c.m_bControlled) )/* || c.Combatant == this*/ ); } @@ -1351,6 +1352,20 @@ namespace Server.Mobiles public virtual void AlterMeleeDamageFrom( Mobile from, ref int damage ) { + #region Mondain's Legacy + if ( from != null && from.Talisman is BaseTalisman ) + { + BaseTalisman talisman = (BaseTalisman)from.Talisman; + + if ( talisman.Killer != null && talisman.Killer.Type != null ) + { + Type type = talisman.Killer.Type; + + if ( type.IsAssignableFrom( GetType() ) ) + damage = (int)( damage * ( 1 + (double)talisman.Killer.Amount / 100 ) ); + } + } + #endregion } public virtual void AlterMeleeDamageTo( Mobile to, ref int damage ) @@ -1371,19 +1386,17 @@ namespace Server.Mobiles int hides = Hides; int scales = Scales; - if ( (feathers == 0 && wool == 0 && meat == 0 && hides == 0 && scales == 0) || Summoned || IsBonded || corpse.Animated ) + if ( ( feathers == 0 && wool == 0 && meat == 0 && hides == 0 && scales == 0 ) || Summoned || IsBonded || corpse.Animated ) { - if ( corpse.Animated ) - corpse.SendLocalizedMessageTo( from, 500464 ); // Use this on corpses to carve away meat and hide + if ( corpse.Animated ) + corpse.SendLocalizedMessageTo( from, 500464 ); // Use this on corpses to carve away meat and hide else - from.SendLocalizedMessage( 500485 ); // You see nothing useful to carve from the corpse. + from.SendLocalizedMessage( 500485 ); // You see nothing useful to carve from the corpse. } else { - if( Core.ML && from.Race == Race.Human ) - { - hides = (int)Math.Ceiling( hides * 1.1 ); //10% Bonus Only applies to Hides, Ore & Logs - } + if ( Core.ML && from.Race == Race.Human ) + hides = (int)Math.Ceiling( hides * 1.1 ); // 10% bonus only applies to hides, ore & logs if ( corpse.Map == Map.Felucca ) { @@ -1427,6 +1440,7 @@ namespace Server.Mobiles if ( hides != 0 ) { Item holding = from.Weapon as Item; + if ( Core.AOS && ( holding is SkinningKnife /* TODO: || holding is ButcherWarCleaver || with is ButcherWarCleaver */ ) ) { Item leather = null; @@ -1447,7 +1461,9 @@ namespace Server.Mobiles from.SendLocalizedMessage( 500471 ); // You skin it, and the hides are now in the corpse. } else + { from.SendLocalizedMessage( 1073555 ); // You skin it and place the cut-up hides in your backpack. + } } } else @@ -3684,6 +3700,27 @@ namespace Server.Mobiles #region Pack & Loot + #region Mondain's Legacy + public void PackArcaneScroll( int min, int max ) + { + PackArcaneScroll( Utility.RandomMinMax( min, max ) ); + } + + public void PackArcaneScroll( int amount ) + { + for ( int i = 0; i < amount; ++i ) + PackArcaneScroll(); + } + + public void PackArcaneScroll() + { + if ( !Core.ML ) + return; + + PackItem( Loot.Construct( Loot.ArcanistScrollTypes ) ); + } + #endregion + public void PackPotion() { PackItem( Loot.RandomPotion() ); @@ -3694,7 +3731,7 @@ namespace Server.Mobiles if ( !Core.ML || chance <= Utility.RandomDouble() ) return; - PackItem( Loot.Construct( Loot.ArcaneScrollTypes ) ); + PackItem( Loot.Construct( Loot.ArcanistScrollTypes ) ); } public void PackNecroScroll( int index ) @@ -4445,10 +4482,19 @@ namespace Server.Mobiles return rights; } + #region Mondain's Legacy + public virtual bool GivesMLMinorArtifact{ get{ return false; } } + #endregion + public virtual void OnKilledBy( Mobile mob ) { if ( m_Paragon && Paragon.CheckArtifactChance( mob, this ) ) Paragon.GiveArtifactTo( mob ); + + #region Mondain's Legacy + if ( GivesMLMinorArtifact && MondainsLegacy.CheckArtifactChance( mob, this ) ) + MondainsLegacy.GiveArtifactTo( mob ); + #endregion } public override void OnDeath( Container c ) @@ -4814,22 +4860,6 @@ namespace Server.Mobiles return true; } - private static Type[] m_MinorArtifactsMl = new Type[] - { - typeof( AegisOfGrace ), typeof( BladeDance ), typeof( Bonesmasher ), - typeof( Boomstick ), typeof( FeyLeggings ), typeof( FleshRipper ), - typeof( HelmOfSwiftness ), typeof( PadsOfTheCuSidhe ), typeof( QuiverOfRage ), - typeof( QuiverOfElements ), typeof( RaedsGlory ), typeof( RighteousAnger ), - typeof( RobeOfTheEclipse ), typeof( RobeOfTheEquinox ), typeof( SoulSeeker ), - typeof( TalonBite ), typeof( WildfireBow ), typeof( Windsong ), - // TODO: Brightsight lenses, Bloodwood spirit, Totem of the void - }; - - public static Type[] MinorArtifactsMl - { - get { return m_MinorArtifactsMl; } - } - private static bool EnableRummaging = true; private const double ChanceToRummage = 0.5; // 50% @@ -5004,10 +5034,10 @@ namespace Server.Mobiles if ( CanBreath && DateTime.Now >= m_NextBreathTime ) // tested: controlled dragons do breath fire, what about summoned skeletal dragons? { Mobile target = this.Combatant; - + if( target != null && target.Alive && !target.IsDeadBondedPet && CanBeHarmful( target ) && target.Map == this.Map && !IsDeadBondedPet && target.InRange( this, BreathRange ) && InLOS( target ) && !BardPacified ) { - if( ( DateTime.Now - m_NextBreathTime ) < TimeSpan.FromSeconds( 30 ) ) + if( ( DateTime.Now - m_NextBreathTime ) < TimeSpan.FromSeconds( 30 ) ) { BreathStart( target ); } diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs index 7e203e787..b7382e036 100644 --- a/Scripts/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs @@ -40,7 +40,7 @@ namespace Server.Mobiles Karma = -3000; VirtualArmor = 40; - + switch ( Utility.Random( 6 ) ) { case 0: PackItem( new PlateArms() ); break; diff --git a/Scripts/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs new file mode 100644 index 000000000..21d6d40f9 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Lady Jennifyr corpse" )] + public class LadyJennifyr : SkeletalKnight + { + [Constructable] + public LadyJennifyr() + { + Name = "Lady Jennifyr"; + Hue = 0x76D; + + SetStr( 208, 309 ); + SetDex( 91, 118 ); + SetInt( 44, 101 ); + + SetHits( 1113, 1285 ); + + SetDamage( 15, 25 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 56, 65 ); + SetResistance( ResistanceType.Fire, 41, 49 ); + SetResistance( ResistanceType.Cold, 71, 80 ); + SetResistance( ResistanceType.Poison, 41, 50 ); + SetResistance( ResistanceType.Energy, 50, 58 ); + + SetSkill( SkillName.Wrestling, 127.9, 137.1 ); + SetSkill( SkillName.Tactics, 128.4, 141.9 ); + SetSkill( SkillName.MagicResist, 102.1, 119.5 ); + SetSkill( SkillName.Anatomy, 129.0, 137.5 ); + + Fame = 18000; + Karma = -18000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosUltraRich, 4 ); + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( Utility.RandomDouble() < 0.1 ) + { + ExpireTimer timer; + + if ( m_Table.TryGetValue( defender, out timer ) ) + timer.DoExpire(); + + defender.FixedParticles( 0x3709, 10, 30, 5052, EffectLayer.LeftFoot ); + defender.PlaySound( 0x208 ); + defender.SendLocalizedMessage( 1070833 ); // The creature fans you with fire, reducing your resistance to fire attacks. + + ResistanceMod mod = new ResistanceMod( ResistanceType.Fire, -10 ); + defender.AddResistanceMod( mod ); + + m_Table[defender] = timer = new ExpireTimer( defender, mod ); + timer.Start(); + } + } + + private static Dictionary m_Table = new Dictionary(); + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private ResistanceMod m_Mod; + + public ExpireTimer( Mobile m, ResistanceMod mod ) + : base( TimeSpan.FromSeconds( 10 ) ) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod( m_Mod ); + + Stop(); + m_Table.Remove( m_Mobile ); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage( 1070834 ); // Your resistance to fire attacks has returned. + DoExpire(); + } + } + + /* + // TODO: Uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.15 ) + c.DropItem( new DisintegratingThesisNotes() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public LadyJennifyr( 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/Bedlam/LadyMarai.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/LadyMarai.cs new file mode 100644 index 000000000..69ed44ae5 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/LadyMarai.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Lady Marai corpse" )] + public class LadyMarai : SkeletalKnight + { + [Constructable] + public LadyMarai() + { + Name = "Lady Marai"; + Hue = 0x21; + + SetStr( 221, 304 ); + SetDex( 98, 138 ); + SetInt( 54, 99 ); + + SetHits( 694, 846 ); + + SetDamage( 15, 25 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 70, 80 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.Wrestling, 126.6, 137.2 ); + SetSkill( SkillName.Tactics, 128.7, 134.5 ); + SetSkill( SkillName.MagicResist, 102.1, 119.1 ); + SetSkill( SkillName.Anatomy, 126.2, 136.5 ); + + Fame = 18000; + Karma = -18000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosUltraRich, 4 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.CrushingBlow; + } + + /* + // TODO: Uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.15 ) + c.DropItem( new DisintegratingThesisNotes() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public LadyMarai( 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/Bedlam/MasterJonath.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterJonath.cs new file mode 100644 index 000000000..2708ef2a7 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterJonath.cs @@ -0,0 +1,96 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Master Jonath corpse" )] + public class MasterJonath : BoneMagi + { + [Constructable] + public MasterJonath() + { + Name = "Master Jonath"; + Hue = 0x455; + + SetStr( 109, 131 ); + SetDex( 98, 110 ); + SetInt( 232, 259 ); + + SetHits( 766, 920 ); + + SetDamage( 10, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 60 ); + SetResistance( ResistanceType.Fire, 43, 49 ); + SetResistance( ResistanceType.Cold, 45, 80 ); + SetResistance( ResistanceType.Poison, 41, 45 ); + SetResistance( ResistanceType.Energy, 54, 55 ); + + SetSkill( SkillName.Wrestling, 80.5, 88.6 ); + SetSkill( SkillName.Tactics, 88.5, 95.1 ); + SetSkill( SkillName.MagicResist, 102.7, 102.9 ); + SetSkill( SkillName.Magery, 100.0, 106.6 ); + SetSkill( SkillName.EvalInt, 99.6, 106.9 ); + SetSkill( SkillName.Necromancy, 100.0, 106.6 ); + SetSkill( SkillName.SpiritSpeak, 99.6, 106.9 ); + + Fame = 18000; + Karma = -18000; + + if ( Utility.RandomBool() ) + PackNecroScroll( Utility.RandomMinMax( 5, 9 ) ); + else + PackScroll( 4, 7 ); + + PackReg( 7 ); + PackReg( 7 ); + PackReg( 8 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosUltraRich, 4 ); + } + + // TODO: Special move? + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.05 ) + c.DropItem( new ParrotItem() ); + + if ( Utility.RandomDouble() < 0.15 ) + c.DropItem( new DisintegratingThesisNotes() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public MasterJonath( 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/Bedlam/MasterMikael.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterMikael.cs new file mode 100644 index 000000000..893421310 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterMikael.cs @@ -0,0 +1,94 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Master Mikael corpse" )] + public class MasterMikael : BoneMagi + { + [Constructable] + public MasterMikael() + { + Name = "Master Mikael"; + Hue = 0x8FD; + + SetStr( 93, 122 ); + SetDex( 91, 100 ); + SetInt( 252, 271 ); + + SetHits( 789, 1014 ); + + SetDamage( 11, 19 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 59 ); + SetResistance( ResistanceType.Fire, 40, 46 ); + SetResistance( ResistanceType.Cold, 72, 80 ); + SetResistance( ResistanceType.Poison, 44, 49 ); + SetResistance( ResistanceType.Energy, 50, 57 ); + + SetSkill( SkillName.Wrestling, 80.1, 87.2 ); + SetSkill( SkillName.Tactics, 79.0, 90.9 ); + SetSkill( SkillName.MagicResist, 90.3, 106.9 ); + SetSkill( SkillName.Magery, 103.8, 108.0 ); + SetSkill( SkillName.EvalInt, 96.1, 105.3 ); + SetSkill( SkillName.Necromancy, 103.8, 108.0 ); + SetSkill( SkillName.SpiritSpeak, 96.1, 105.3 ); + + Fame = 18000; + Karma = -18000; + + if ( Utility.RandomBool() ) + PackNecroScroll( Utility.RandomMinMax( 5, 9 ) ); + else + PackScroll( 4, 7 ); + + PackReg( 3 ); + PackNecroReg( 1, 10 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosUltraRich, 3 ); + } + + // TODO: Special move? + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.15 ) + c.DropItem( new DisintegratingThesisNotes() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public MasterMikael( 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/Bedlam/MasterTheophilus.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterTheophilus.cs new file mode 100644 index 000000000..3a2e9f8f6 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterTheophilus.cs @@ -0,0 +1,104 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Master Theophilus corpse" )] + public class MasterTheophilus : EvilMageLord + { + [Constructable] + public MasterTheophilus() + { + Name = "Master Theophilus"; + Title = "the necromancer"; + + SetStr( 137, 187 ); + SetDex( 253, 301 ); + SetInt( 393, 444 ); + + SetHits( 663, 876 ); + + SetDamage( 15, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 60 ); + SetResistance( ResistanceType.Fire, 50, 58 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.Wrestling, 69.9, 105.3 ); + SetSkill( SkillName.Tactics, 113.0, 117.9 ); + SetSkill( SkillName.MagicResist, 127.0, 132.8 ); + SetSkill( SkillName.Magery, 138.1, 143.7 ); + SetSkill( SkillName.EvalInt, 125.6, 133.8 ); + SetSkill( SkillName.Necromancy, 125.6, 133.8 ); + SetSkill( SkillName.SpiritSpeak, 125.6, 133.8 ); + SetSkill( SkillName.Meditation, 128.8, 132.9 ); + + Fame = 18000; + Karma = -18000; + + AddItem( new Shoes( 0x537 ) ); + AddItem( new Robe( 0x452 ) ); + + for ( int i = 0; i < 2; ++i ) + { + if ( Utility.RandomBool() ) + PackNecroScroll( Utility.RandomMinMax( 5, 9 ) ); + else + PackScroll( 4, 7 ); + } + + PackReg( 7 ); + PackReg( 7 ); + PackReg( 8 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosUltraRich, 4 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ParalyzingBlow; + } + + /* + // TODO: Needs verification + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Paragon.ChestChance > Utility.RandomDouble() ) + c.DropItem( new ParagonChest( Name, TreasureMapLevel ) ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override bool AlwaysMurderer{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public MasterTheophilus( 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/Bedlam/RedDeath.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/RedDeath.cs new file mode 100644 index 000000000..b4761618f --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/RedDeath.cs @@ -0,0 +1,91 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Red Death corpse" )] + public class RedDeath : SkeletalMount + { + [Constructable] + public RedDeath() + : base( "Red Death" ) + { + Hue = 0x21; + BaseSoundID = 0x1C3; + + SetStr( 319, 324 ); + SetDex( 241, 244 ); + SetInt( 242, 255 ); + + SetHits( 1540, 1605 ); + + SetDamage( 25, 29 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Fire, 75 ); + SetDamageType( ResistanceType.Cold, 0 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 90 ); + SetResistance( ResistanceType.Cold, 0 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 0 ); + + SetSkill( SkillName.Wrestling, 121.4, 143.7 ); + SetSkill( SkillName.Tactics, 120.9, 142.2 ); + SetSkill( SkillName.MagicResist, 120.1, 142.3 ); + SetSkill( SkillName.Anatomy, 120.2, 144.0 ); + + Fame = 28000; + Karma = -28000; + + if ( Utility.RandomBool() ) + PackNecroScroll( Utility.RandomMinMax( 5, 9 ) ); + else + PackScroll( 4, 7 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosUltraRich, 4 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.WhirlwindAttack; + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.DropItem( new ResolvesBridle() ); + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override bool AlwaysMurderer{ get{ return true; } } + public override bool HasBreath{ get{ return true; } } + public override int BreathChaosDamage{ get { return 100; } } + public override int BreathFireDamage{ get{ return 0; } } + + public RedDeath( 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/Bedlam/SirPatrick.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/SirPatrick.cs new file mode 100644 index 000000000..dfe48cdd3 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/SirPatrick.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Sir Patrick corpse" )] + public class SirPatrick : SkeletalKnight + { + [Constructable] + public SirPatrick() + { + Name = "Sir Patrick"; + Hue = 0x47E; + + SetStr( 208, 319 ); + SetDex( 98, 132 ); + SetInt( 45, 91 ); + + SetHits( 616, 884 ); + + SetDamage( 15, 25 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 55, 62 ); + SetResistance( ResistanceType.Fire, 40, 48 ); + SetResistance( ResistanceType.Cold, 71, 80 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.Wrestling, 126.3, 136.5 ); + SetSkill( SkillName.Tactics, 128.5, 143.8 ); + SetSkill( SkillName.MagicResist, 102.8, 117.9 ); + SetSkill( SkillName.Anatomy, 127.5, 137.2 ); + + Fame = 18000; + Karma = -18000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosUltraRich, 3 ); + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( Utility.RandomDouble() < 0.1 ) + DrainLife(); + } + + public virtual void DrainLife() + { + List list = new List(); + + foreach ( Mobile m in GetMobilesInRange( 2 ) ) + { + if ( m == this || !CanBeHarmful( m ) ) + continue; + + if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + if ( bc.Controlled || bc.Summoned || bc.Team != Team ) + list.Add( m ); + } + else if ( m.Player ) + { + list.Add( m ); + } + } + + foreach ( Mobile m in list ) + { + DoHarmful( m ); + + m.FixedParticles( 0x374A, 10, 15, 5013, 0x455, 0, EffectLayer.Waist ); + m.PlaySound( 0x1EA ); + + int drain = Utility.RandomMinMax( 14, 30 ); + + Hits += drain; + m.Damage( drain, this ); + } + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.15 ) + c.DropItem( new DisintegratingThesisNotes() ); + + if ( Utility.RandomDouble() < 0.05 ) + c.DropItem( new AssassinChest() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public SirPatrick( 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/Magic/FetidEssence.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/FetidEssence.cs index a405c61d2..1d4b5f560 100644 --- a/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/FetidEssence.cs +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/FetidEssence.cs @@ -19,7 +19,7 @@ namespace Server.Mobiles SetInt( 451, 550 ); SetHits( 551, 650 ); - + SetDamage( 21, 25 ); SetDamageType( ResistanceType.Physical, 30 ); @@ -48,7 +48,10 @@ namespace Server.Mobiles { AddLoot( LootPack.FilthyRich ); } - + + public override Poison HitPoison{ get{ return Poison.Deadly; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override int GetAngerSound() { return 0x56d; diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs index 33a73d2bd..41ef4c82f 100644 --- a/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs @@ -41,6 +41,11 @@ namespace Server.Mobiles PackArcanceScroll( 0.05 ); } + public override OppositionGroup OppositionGroup + { + get { return OppositionGroup.FeyAndUndead; } + } + public override void GenerateLoot() { AddLoot( LootPack.MlRich ); diff --git a/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs b/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs index eb177619f..406b7da74 100644 --- a/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs +++ b/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs @@ -121,9 +121,9 @@ namespace Server.Mobiles c.DropItem( new GrizzledBones() ); - /* if (Utility.RandomDouble() < 0.6) - c.DropItem(new ParrotItem()); */ - //TODO Add parrots + // TODO: Parrots + /*if ( Utility.RandomDouble() < 0.6 ) + c.DropItem( new ParrotItem() ); */ if( Utility.RandomDouble() < 0.05 ) c.DropItem( new GrizzledMareStatuette() ); @@ -131,23 +131,24 @@ namespace Server.Mobiles if( Utility.RandomDouble() < 0.025 ) c.DropItem( new CrimsonCincture() ); - /* if (Utility.RandomDouble() < 0.05) //TODO Add armor sets - { - switch (Utility.Random(5)) - { - case 0: c.DropItem(new GrizzleGauntlets()); break; - case 1: c.DropItem(new GrizzleGreaves()); break; - case 2: c.DropItem(new GrizzleHelm()); break; - case 3: c.DropItem(new GrizzleTunic()); break; - case 4: c.DropItem(new GrizzleVambraces()); break; - } - } */ + // TODO: Armor sets + /*if ( Utility.RandomDouble() < 0.05 ) + { + switch ( Utility.Random(5) ) + { + case 0: c.DropItem( new GrizzleGauntlets() ); break; + case 1: c.DropItem( new GrizzleGreaves() ); break; + case 2: c.DropItem( new GrizzleHelm() ); break; + case 3: c.DropItem( new GrizzleTunic() ); break; + case 4: c.DropItem( new GrizzleVambraces() ); break; + } + }*/ } public override bool Unprovokable { get { return true; } } public override bool Uncalmable { get { return true; } } public override Poison PoisonImmune { get { return Poison.Lethal; } } - // public override bool GivesMinorArtifact { get { return true; } } //TODO add ML minor artifacts + //public override bool GivesMLMinorArtifact { get { return true; } } // TODO: Needs verification public override int TreasureMapLevel { get { return 5; } } public override void OnGaveMeleeAttack( Mobile defender ) diff --git a/Scripts/Spells/Necromancy/AnimateDeadSpell.cs b/Scripts/Spells/Necromancy/AnimateDeadSpell.cs index 6d3e7a7cc..f1b3a901a 100644 --- a/Scripts/Spells/Necromancy/AnimateDeadSpell.cs +++ b/Scripts/Spells/Necromancy/AnimateDeadSpell.cs @@ -197,6 +197,7 @@ namespace Server.Spells.Necromancy { type = c.Owner.GetType(); } + if( c.ItemID != 0x2006 || c.Animated || type == typeof( PlayerMobile ) || type == null || ( c.Owner != null && c.Owner.Fame < 100 ) || ( ( c.Owner != null ) && ( c.Owner is BaseCreature ) && ( ( ( BaseCreature )c.Owner ).Summoned || ( ( BaseCreature )c.Owner ).IsBonded ) ) ) { Caster.SendLocalizedMessage( 1061085 ); // There's not enough life force there to animate. @@ -300,7 +301,7 @@ namespace Server.Spells.Necromancy Map map = (Map)states[3]; CreatureGroup group = (CreatureGroup)states[4]; - if ( corpse.ItemID != 0x2006 ) + if ( corpse.Animated ) return; Mobile owner = corpse.Owner; @@ -377,13 +378,12 @@ namespace Server.Spells.Necromancy summoned.MoveToWorld( loc, map ); corpse.Hue = 1109; - corpse.Animated = true; Register( caster, summoned ); } - private static void Scale( BaseCreature bc, int scalar ) + public static void Scale( BaseCreature bc, int scalar ) { int toScale;