From a0e13d50074c69924b37ea63f0ca9a5d1806c20e Mon Sep 17 00:00:00 2001 From: eos Date: Wed, 7 Mar 2012 18:59:52 +0000 Subject: [PATCH] - Future ML craftables added to the special repair list until the craft system is updated. - Items can now be repaired while wearing them. - Items can now be fortified while wearing them. - Fixed repair deed messages not sending. - Sound effect added to powder of fortifying. - Map issue for fishing and SOSs fixed, where it would not allow fishing in empty resource banks when not on the target SOS map. - Added proximity spawner. - Improved spawner mouseover menu, now also shows types set on the spawner which are not yet spawned. - Fixed spawners only deleting half of their spawned objects when deleted. - Added the ability to set TextDefinition objects in the props gump. - WaitTeleporters now round delays to nearest in the remaining time messages. - Updated TextDefinition to be more usable; made it parsable from string and added safe serialization/deserialization methods. - Improved checking whether a mobile can flee. - Monsters that give ML minor artifacts will no longer flee when low on hits (like paragons). - Monsters that give ML minor artifacts will no longer spawn as paragon. - Fixed issue with pets not eating certain foods. - AI and targeting fixes for Red Death, Pyre and Swoop. - Fame and karma added to Rend. - Swoop corrected to have 0 karma. - Stat and skill tweaks for Putrefier. - Changelings will no longer show their fame title when morphed. - Added travel restrictions for ML dungeons. - Fixed issue of travel restriction message displaying twice. - Monster teleporting is no longer affected by region travel restrictions. --- Scripts/Engines/Craft/Core/Repair.cs | 51 ++++- Scripts/Engines/Harvest/Fishing.cs | 2 +- Scripts/Engines/Spawner/ProximitySpawner.cs | 176 ++++++++++++++++++ Scripts/Engines/Spawner/Spawner.cs | 50 ++++- Scripts/Gumps/Properties/PropsGump.cs | 3 +- Scripts/Items/Misc/Teleporter.cs | 6 +- .../Blacksmithy/PowderOfTemperament.cs | 7 +- Scripts/Items/Talismans/TalismanAttribute.cs | 4 +- Scripts/Misc/LootPack.cs | 28 +-- Scripts/Misc/MondainsLegacy.cs | 12 ++ Scripts/Misc/TextDefinition.cs | 121 ++++++++---- Scripts/Mobiles/AI/AnimalAI.cs | 6 +- Scripts/Mobiles/AI/ArcherAI.cs | 2 +- Scripts/Mobiles/AI/MageAI.cs | 2 +- Scripts/Mobiles/AI/MeleeAI.cs | 2 +- Scripts/Mobiles/AI/ThiefAI.cs | 2 +- Scripts/Mobiles/BaseCreature.cs | 6 +- .../Mobiles/Monsters/ML/Bedlam/RedDeath.cs | 3 + Scripts/Mobiles/Monsters/ML/Labyrinth/Pyre.cs | 2 + Scripts/Mobiles/Monsters/ML/Labyrinth/Rend.cs | 3 + .../ML/Palace of Paroxysmus/Putrefier.cs | 17 +- .../Monsters/ML/Twisted Weald/Changeling.cs | 2 + .../Monsters/ML/Twisted Weald/Swoop.cs | 4 +- Scripts/Mobiles/Special/Paragon.cs | 2 +- Scripts/Spells/Base/SpellHelper.cs | 59 +++--- 25 files changed, 432 insertions(+), 140 deletions(-) create mode 100644 Scripts/Engines/Spawner/ProximitySpawner.cs diff --git a/Scripts/Engines/Craft/Core/Repair.cs b/Scripts/Engines/Craft/Core/Repair.cs index d15599c69..fc960ec2a 100644 --- a/Scripts/Engines/Craft/Core/Repair.cs +++ b/Scripts/Engines/Craft/Core/Repair.cs @@ -101,7 +101,7 @@ namespace Server.Engines.Craft private bool IsSpecialClothing( BaseClothing clothing ) { - // Armor repairable but not craftable + // Clothing repairable but not craftable if( m_CraftSystem is DefTailoring ) { @@ -132,12 +132,41 @@ namespace Server.Engines.Craft } else if ( m_CraftSystem is DefBlacksmithy ) { - return ( weapon is Pitchfork ); + return ( weapon is Pitchfork ) + #region Temporary + // TODO: Make these items craftable + || ( weapon is RadiantScimitar ) + || ( weapon is WarCleaver ) + || ( weapon is ElvenSpellblade ) + || ( weapon is AssassinSpike ) + || ( weapon is Leafblade ) + || ( weapon is RuneBlade ) + || ( weapon is ElvenMachete ) + || ( weapon is OrnateAxe ) + || ( weapon is DiamondMace ); + #endregion } return false; } + private bool IsSpecialArmor( BaseArmor armor ) + { + // Armor repairable but not craftable + + #region Temporary + // TODO: Make these items craftable + if ( m_CraftSystem is DefBlacksmithy ) + { + return ( armor is Circlet ) + || ( armor is RoyalCirclet ) + || ( armor is GemmedCirclet ); + } + #endregion + + return false; + } + protected override void OnTarget( Mobile from, object targeted ) { int number; @@ -149,8 +178,8 @@ namespace Server.Engines.Craft bool usingDeed = (m_Deed != null); bool toDelete = false; - //TODO: Make a IRepairable - + // TODO: Make an IRepairable + if ( m_CraftSystem.CanCraft( from, m_Tool, targeted.GetType() ) == 1044267 ) { number = 1044282; // You must be near a forge and and anvil to repair items. * Yes, there are two and's * @@ -244,7 +273,7 @@ namespace Server.Engines.Craft { number = (usingDeed)? 1061136 : 1044277; // That item cannot be repaired. // You cannot repair that item with this type of repair contract. } - else if ( !weapon.IsChildOf( from.Backpack ) ) + else if ( !weapon.IsChildOf( from.Backpack ) && ( !Core.ML || weapon.Parent != from ) ) { number = 1044275; // The item must be in your backpack to repair it. } @@ -301,11 +330,11 @@ namespace Server.Engines.Craft toWeaken = 3; } - if ( m_CraftSystem.CraftItems.SearchForSubclass( armor.GetType() ) == null ) + if ( m_CraftSystem.CraftItems.SearchForSubclass( armor.GetType() ) == null && !IsSpecialArmor( armor ) ) { number = (usingDeed)? 1061136 : 1044277; // That item cannot be repaired. // You cannot repair that item with this type of repair contract. } - else if ( !armor.IsChildOf( from.Backpack ) ) + else if ( !armor.IsChildOf( from.Backpack ) && ( !Core.ML || armor.Parent != from ) ) { number = 1044275; // The item must be in your backpack to repair it. } @@ -366,7 +395,7 @@ namespace Server.Engines.Craft { number = (usingDeed) ? 1061136 : 1044277; // That item cannot be repaired. // You cannot repair that item with this type of repair contract. } - else if ( !clothing.IsChildOf( from.Backpack ) ) + else if ( !clothing.IsChildOf( from.Backpack ) && ( !Core.ML || clothing.Parent != from ) ) { number = 1044275; // The item must be in your backpack to repair it. } @@ -430,10 +459,12 @@ namespace Server.Engines.Craft CraftContext context = m_CraftSystem.GetContext( from ); from.SendGump( new CraftGump( from, m_CraftSystem, m_Tool, number ) ); } - else if( toDelete ) + else { from.SendLocalizedMessage( number ); - m_Deed.Delete(); + + if( toDelete ) + m_Deed.Delete(); } } } diff --git a/Scripts/Engines/Harvest/Fishing.cs b/Scripts/Engines/Harvest/Fishing.cs index d8ab5086c..85664253f 100644 --- a/Scripts/Engines/Harvest/Fishing.cs +++ b/Scripts/Engines/Harvest/Fishing.cs @@ -217,7 +217,7 @@ namespace Server.Engines.Harvest { SOS sos = messages[i]; - if ( from.Map == sos.TargetMap && from.InRange( sos.TargetLocation, 60 ) ) + if ( ( from.Map == Map.Felucca || from.Map == Map.Trammel ) && from.InRange( sos.TargetLocation, 60 ) ) return true; } } diff --git a/Scripts/Engines/Spawner/ProximitySpawner.cs b/Scripts/Engines/Spawner/ProximitySpawner.cs new file mode 100644 index 000000000..10c567e9d --- /dev/null +++ b/Scripts/Engines/Spawner/ProximitySpawner.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class ProximitySpawner : Spawner + { + private int m_TriggerRange; + private TextDefinition m_SpawnMessage; + private bool m_InstantFlag; + + [CommandProperty( AccessLevel.GameMaster )] + public int TriggerRange + { + get { return m_TriggerRange; } + set { m_TriggerRange = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TextDefinition SpawnMessage + { + get { return m_SpawnMessage; } + set { m_SpawnMessage = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool InstantFlag + { + get { return m_InstantFlag; } + set { m_InstantFlag = value; } + } + + [Constructable] + public ProximitySpawner() + { + } + + [Constructable] + public ProximitySpawner( string spawnName ) + : base( spawnName ) + { + } + + [Constructable] + public ProximitySpawner( int amount, int minDelay, int maxDelay, int team, int homeRange, string spawnName ) + : base( amount, minDelay, maxDelay, team, homeRange, spawnName ) + { + } + + [Constructable] + public ProximitySpawner( int amount, int minDelay, int maxDelay, int team, int homeRange, string spawnName, int triggerRange, string spawnMessage, bool instantFlag ) + : base( amount, minDelay, maxDelay, team, homeRange, spawnName ) + { + m_TriggerRange = triggerRange; + m_SpawnMessage = TextDefinition.Parse( spawnMessage ); + m_InstantFlag = instantFlag; + } + + public ProximitySpawner( int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, List spawnNames ) + : base( amount, minDelay, maxDelay, team, homeRange, spawnNames ) + { + } + + public ProximitySpawner( int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, List spawnNames, int triggerRange, TextDefinition spawnMessage, bool instantFlag ) + : base( amount, minDelay, maxDelay, team, homeRange, spawnNames ) + { + m_TriggerRange = triggerRange; + m_SpawnMessage = spawnMessage; + m_InstantFlag = instantFlag; + } + + public override string DefaultName + { + get { return "Proximity Spawner"; } + } + + public override void DoTimer( TimeSpan delay ) + { + if ( !Running ) + return; + + End = DateTime.Now + delay; + } + + public override void Respawn() + { + RemoveSpawned(); + + End = DateTime.Now; + } + + public override void Spawn() + { + for ( int i = 0; i < SpawnNamesCount; ++i ) + { + for ( int j = 0; j < Count; ++j ) + Spawn( i ); + } + } + + public override bool CheckSpawnCount() + { + return true; + } + + public override bool HandlesOnMovement { get { return true; } } + + public virtual bool ValidTrigger( Mobile m ) + { + if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + if ( !bc.Controlled && !bc.Summoned ) + return false; + } + else if ( !m.Player ) + { + return false; + } + + return ( m.Alive && !m.IsDeadBondedPet && m.CanBeDamaged() && !m.Hidden ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( !Running ) + return; + + if ( IsEmpty && End <= DateTime.Now && m.InRange( GetWorldLocation(), m_TriggerRange ) && m.Location != oldLocation && ValidTrigger( m ) ) + { + TextDefinition.SendMessageTo( m, m_SpawnMessage ); + + DoTimer(); + Spawn(); + + if ( m_InstantFlag ) + { + foreach ( ISpawnable spawned in Spawned ) + { + if ( spawned is Mobile ) + ((Mobile)spawned).Combatant = m; + } + } + } + } + + public ProximitySpawner( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_TriggerRange ); + TextDefinition.Serialize( writer, m_SpawnMessage ); + writer.Write( m_InstantFlag ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_TriggerRange = reader.ReadInt(); + m_SpawnMessage = TextDefinition.Deserialize( reader ); + m_InstantFlag = reader.ReadBool(); + } + } +} diff --git a/Scripts/Engines/Spawner/Spawner.cs b/Scripts/Engines/Spawner/Spawner.cs index bc7b7d4ac..426efd2a0 100644 --- a/Scripts/Engines/Spawner/Spawner.cs +++ b/Scripts/Engines/Spawner/Spawner.cs @@ -28,7 +28,8 @@ namespace Server.Mobiles private bool m_Group; private WayPoint m_WayPoint; - public bool IsFull{ get{ return ( m_Spawned != null && m_Spawned.Count >= m_Count ); } } + public bool IsFull{ get{ return ( m_Spawned.Count >= m_Count ); } } + public bool IsEmpty{ get{ return ( m_Spawned.Count == 0 ); } } public List SpawnNames { @@ -43,6 +44,11 @@ namespace Server.Mobiles } } + public List Spawned + { + get { return m_Spawned; } + } + public virtual int SpawnNamesCount { get { return m_SpawnNames.Count; } } public override void OnAfterDuped( Item newItem ) @@ -126,6 +132,12 @@ namespace Server.Mobiles set { m_MaxDelay = value; InvalidateProperties(); } } + public DateTime End + { + get { return m_End; } + set { m_End = value; } + } + [CommandProperty( AccessLevel.GameMaster )] public TimeSpan NextSpawn { @@ -231,7 +243,7 @@ namespace Server.Mobiles list.Add( 1060660, "team\t{0}", m_Team ); // ~1_val~: ~2_val~ list.Add( 1060661, "speed\t{0} to {1}", m_MinDelay, m_MaxDelay ); // ~1_val~: ~2_val~ - if ( m_Spawned.Count != 0 ) + if ( m_SpawnNames.Count != 0 ) list.Add( SpawnedStats() ); } else @@ -266,7 +278,9 @@ namespace Server.Mobiles { if ( m_Running ) { - m_Timer.Stop(); + if ( m_Timer != null ) + m_Timer.Stop(); + m_Running = false; } } @@ -356,7 +370,7 @@ namespace Server.Mobiles } } - public void Respawn() + public virtual void Respawn() { RemoveSpawned(); @@ -364,7 +378,7 @@ namespace Server.Mobiles Spawn(); } - public void Spawn() + public virtual void Spawn() { if ( SpawnNamesCount > 0 ) Spawn( Utility.Random( SpawnNamesCount ) ); @@ -511,6 +525,11 @@ namespace Server.Mobiles public Point3D HomeLocation { get { return this.Location; } } + public virtual bool CheckSpawnCount() + { + return ( m_Spawned.Count >= m_Count ); + } + public void Spawn( int index ) { Map map = Map; @@ -520,7 +539,7 @@ namespace Server.Mobiles Defrag(); - if ( m_Spawned.Count >= m_Count ) + if ( !CheckSpawnCount() ) return; ISpawnable spawned = CreateSpawnedObject( index ); @@ -555,7 +574,7 @@ namespace Server.Mobiles bc.Home = this.HomeLocation; } - } + } public Point3D GetSpawnPosition() { @@ -600,7 +619,7 @@ namespace Server.Mobiles DoTimer( delay ); } - public void DoTimer( TimeSpan delay ) + public virtual void DoTimer( TimeSpan delay ) { if ( !m_Running ) return; @@ -640,7 +659,18 @@ namespace Server.Mobiles { Defrag(); - Dictionary counts = new Dictionary(); + Dictionary counts = new Dictionary( StringComparer.OrdinalIgnoreCase ); + + foreach ( string entry in m_SpawnNames ) + { + string name = ParseType( entry ); + Type type = ScriptCompiler.FindTypeByName( name ); + + if ( type == null ) + counts[name] = 0; + else + counts[type.Name] = 0; + } foreach ( ISpawnable spawned in m_Spawned ) { @@ -695,7 +725,7 @@ namespace Server.Mobiles { Defrag(); - for ( int i = 0; i < m_Spawned.Count; ++i ) + for ( int i = m_Spawned.Count - 1; i >= 0; --i ) m_Spawned[i].Delete(); InvalidateProperties(); diff --git a/Scripts/Gumps/Properties/PropsGump.cs b/Scripts/Gumps/Properties/PropsGump.cs index 1e0fcc52b..514d3460f 100644 --- a/Scripts/Gumps/Properties/PropsGump.cs +++ b/Scripts/Gumps/Properties/PropsGump.cs @@ -314,7 +314,7 @@ namespace Server.Gumps from.SendGump( new SetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, Enum.GetNames( type ), GetObjects( Enum.GetValues( type ) ) ) ); else if ( IsType( type, typeofBool ) ) from.SendGump( new SetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, m_BoolNames, m_BoolValues ) ); - else if ( IsType( type, typeofString ) || IsType( type, typeofReal ) || IsType( type, typeofNumeric ) ) + else if ( IsType( type, typeofString ) || IsType( type, typeofReal ) || IsType( type, typeofNumeric ) || IsType( type, typeofText ) ) from.SendGump( new SetGump( prop, from, m_Object, m_Stack, m_Page, m_List ) ); else if ( IsType( type, typeofPoison ) ) from.SendGump( new SetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, m_PoisonNames, m_PoisonValues ) ); @@ -416,6 +416,7 @@ namespace Server.Gumps private static Type typeofEnum = typeof( Enum ); private static Type typeofBool = typeof( Boolean ); private static Type typeofString = typeof( String ); + private static Type typeofText = typeof( TextDefinition ); private static Type typeofPoison = typeof( Poison ); private static Type typeofMap = typeof( Map ); private static Type typeofSkills = typeof( Skills ); diff --git a/Scripts/Items/Misc/Teleporter.cs b/Scripts/Items/Misc/Teleporter.cs index aebb7782a..fccf6b462 100644 --- a/Scripts/Items/Misc/Teleporter.cs +++ b/Scripts/Items/Misc/Teleporter.cs @@ -592,16 +592,16 @@ namespace Server.Items { if ( ts.TotalHours >= 1 ) { - int h = (int)ts.TotalHours; + int h = (int)Math.Round( ts.TotalHours ); return String.Format( "{0} hour{1}", h, ( h == 1 ) ? "" : "s" ); } else if ( ts.TotalMinutes >= 1 ) { - int m = (int)ts.TotalMinutes; + int m = (int)Math.Round( ts.TotalMinutes ); return String.Format( "{0} minute{1}", m, ( m == 1 ) ? "" : "s" ); } - int s = Math.Max( (int)ts.TotalSeconds, 0 ); + int s = Math.Max( (int)Math.Round( ts.TotalSeconds ), 0 ); return String.Format( "{0} second{1}", s, ( s == 1 ) ? "" : "s" ); } diff --git a/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs b/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs index 8e996e886..3a621fde3 100644 --- a/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs +++ b/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs @@ -19,7 +19,7 @@ namespace Server.Items public bool ShowUsesRemaining{ get{ return true; } set{} } - public override int LabelNumber{ get{ return 1049082; } } // powder of temperament + public override int LabelNumber{ get{ return 1049082; } } // powder of fortifying [Constructable] public PowderOfTemperament() : this( 10 ) @@ -117,7 +117,7 @@ namespace Server.Items return; } - if ( item.IsChildOf( from.Backpack ) && m_Powder.IsChildOf( from.Backpack ) ) + if ( ( item.IsChildOf( from.Backpack ) || ( Core.ML && item.Parent == from ) ) && m_Powder.IsChildOf( from.Backpack ) ) { int origMaxHP = wearable.MaxHitPoints; int origCurHP = wearable.HitPoints; @@ -146,12 +146,13 @@ namespace Server.Items if ( wearable.MaxHitPoints > origMaxHP ) { from.SendLocalizedMessage( 1049084 ); // You successfully use the powder on the item. + from.PlaySound( 0x247 ); --m_Powder.UsesRemaining; if ( m_Powder.UsesRemaining <= 0 ) { - from.SendLocalizedMessage( 1049086 ); // You have used up your powder of temperament. + from.SendLocalizedMessage( 1049086 ); // You have used up your powder of fortifying. m_Powder.Delete(); } } diff --git a/Scripts/Items/Talismans/TalismanAttribute.cs b/Scripts/Items/Talismans/TalismanAttribute.cs index 08fc82c4d..d90f34a8e 100644 --- a/Scripts/Items/Talismans/TalismanAttribute.cs +++ b/Scripts/Items/Talismans/TalismanAttribute.cs @@ -78,7 +78,7 @@ namespace Server.Items m_Type = ScriptCompiler.FindTypeByFullName( reader.ReadString(), false ); if ( GetSaveFlag( flags, SaveFlag.Name ) ) - m_Name = new TextDefinition( reader ); + m_Name = TextDefinition.Deserialize( reader ); if ( GetSaveFlag( flags, SaveFlag.Amount ) ) m_Amount = reader.ReadEncodedInt(); @@ -128,7 +128,7 @@ namespace Server.Items writer.Write( m_Type.FullName ); if ( GetSaveFlag( flags, SaveFlag.Name ) ) - m_Name.Serialize( writer ); + TextDefinition.Serialize( writer, m_Name ); if ( GetSaveFlag( flags, SaveFlag.Amount ) ) writer.WriteEncodedInt( m_Amount ); diff --git a/Scripts/Misc/LootPack.cs b/Scripts/Misc/LootPack.cs index 243c01c4e..ea3f8783c 100644 --- a/Scripts/Misc/LootPack.cs +++ b/Scripts/Misc/LootPack.cs @@ -579,31 +579,7 @@ namespace Server #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; + return MondainsLegacy.IsMLRegion( m.Region ); } #endregion @@ -861,7 +837,7 @@ namespace Server new Type[] // high { typeof( VengefulSpiritScroll ), typeof( VampiricEmbraceScroll ), typeof( ExorcismScroll ) - } : + } : new Type[] // high { typeof( VengefulSpiritScroll ), typeof( VampiricEmbraceScroll ) diff --git a/Scripts/Misc/MondainsLegacy.cs b/Scripts/Misc/MondainsLegacy.cs index c805f731b..6be0eb44c 100644 --- a/Scripts/Misc/MondainsLegacy.cs +++ b/Scripts/Misc/MondainsLegacy.cs @@ -69,5 +69,17 @@ namespace Server return false; } + + public static bool IsMLRegion( Region region ) + { + return region.IsPartOf( "Twisted Weald" ) + || region.IsPartOf( "Sanctuary" ) + || region.IsPartOf( "Prism of Light" ) + || region.IsPartOf( "Citadel" ) + || region.IsPartOf( "Bedlam" ) + || region.IsPartOf( "Blighted Grove" ) + || region.IsPartOf( "Painted Caves" ) + || region.IsPartOf( "Palace of Paroxysmus" ); + } } } \ No newline at end of file diff --git a/Scripts/Misc/TextDefinition.cs b/Scripts/Misc/TextDefinition.cs index 6a41ff56b..91bb1585b 100644 --- a/Scripts/Misc/TextDefinition.cs +++ b/Scripts/Misc/TextDefinition.cs @@ -1,14 +1,21 @@ using System; +using Server; +using Server.Gumps; namespace Server { + [Parsable] public class TextDefinition { private int m_Number; private string m_String; - public int Number{ get{ return m_Number; } } - public string String{ get{ return m_String; } } + public int Number { get { return m_Number; } } + public string String { get { return m_String; } } + + public TextDefinition() : this( 0, null ) + { + } public TextDefinition( int number ) : this( number, null ) { @@ -24,18 +31,6 @@ namespace Server m_String = text; } - public TextDefinition( GenericReader reader ) - { - int type = reader.ReadEncodedInt(); - - switch ( type ) - { - case 1: m_Number = reader.ReadEncodedInt(); m_String = null; break; - case 2: m_Number = 0; m_String = reader.ReadString(); break; - default: m_Number = 0; m_String = null; break; - } - } - public override string ToString() { if ( m_Number > 0 ) @@ -46,41 +41,64 @@ namespace Server return "(empty)"; } - public virtual void Serialize( GenericWriter writer ) + public static void Serialize( GenericWriter writer, TextDefinition def ) { - if ( m_Number > 0 ) + if ( def == null ) + { + writer.WriteEncodedInt( 3 ); + } + else if ( def.m_Number > 0 ) { writer.WriteEncodedInt( 1 ); - writer.WriteEncodedInt( m_Number ); + writer.WriteEncodedInt( def.m_Number ); } - else if ( m_String != null ) + else if ( def.m_String != null ) { writer.WriteEncodedInt( 2 ); - writer.Write( m_String ); + writer.Write( def.m_String ); } else + { writer.WriteEncodedInt( 0 ); + } + } + + public static TextDefinition Deserialize( GenericReader reader ) + { + int type = reader.ReadEncodedInt(); + + switch ( type ) + { + case 0: return new TextDefinition(); + case 1: return new TextDefinition( reader.ReadEncodedInt() ); + case 2: return new TextDefinition( reader.ReadString() ); + } + + return null; } public static void AddTo( ObjectPropertyList list, TextDefinition def ) { - if ( def != null && def.m_Number > 0 ) + if ( def == null ) + return; + + if ( def.m_Number > 0 ) list.Add( def.m_Number ); - else if ( def != null && def.m_String != null ) + else if ( def.m_String != null ) list.Add( def.m_String ); } - public static implicit operator TextDefinition ( int v ) + public static implicit operator TextDefinition( int v ) { return new TextDefinition( v ); } - public static implicit operator TextDefinition ( string s ) + public static implicit operator TextDefinition( string s ) { return new TextDefinition( s ); } - public static implicit operator int ( TextDefinition m ) + public static implicit operator int( TextDefinition m ) { if ( m == null ) return 0; @@ -88,7 +106,7 @@ namespace Server return m.m_Number; } - public static implicit operator string ( TextDefinition m ) + public static implicit operator string( TextDefinition m ) { if ( m == null ) return null; @@ -96,30 +114,51 @@ namespace Server return m.m_String; } - public static void AddHtmlText( Server.Gumps.Gump g, int x, int y, int width, int height, TextDefinition text, bool back, bool scroll, int numberColor, int stringColor ) + public static void AddHtmlText( Gump g, int x, int y, int width, int height, TextDefinition def, bool back, bool scroll, int numberColor, int stringColor ) { - if( text != null && text.Number > 0 ) - if( numberColor >= 0 ) - g.AddHtmlLocalized( x, y, width, height, text.Number, numberColor, back, scroll ); + if ( def == null ) + return; + + if ( def.m_Number > 0 ) + { + if ( numberColor >= 0 ) + g.AddHtmlLocalized( x, y, width, height, def.m_Number, numberColor, back, scroll ); else - g.AddHtmlLocalized( x, y, width, height, text.Number, back, scroll ); - else if( text != null && text.String != null ) - if( stringColor >= 0 ) - g.AddHtml( x, y, width, height, String.Format( "{1}", stringColor, text.String ), back, scroll ); - else - g.AddHtml( x, y, width, height, text.String, back, scroll ); + g.AddHtmlLocalized( x, y, width, height, def.m_Number, back, scroll ); + } + else if ( def.m_String != null ) + { + if ( stringColor >= 0 ) + 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 ); + } } - public static void AddHtmlText( Server.Gumps.Gump g, int x, int y, int width, int height, TextDefinition text, bool back, bool scroll ) + + public static void AddHtmlText( Gump g, int x, int y, int width, int height, TextDefinition def, bool back, bool scroll ) { - AddHtmlText( g, x, y, width, height, text, back, scroll, -1, -1 ); + AddHtmlText( g, x, y, width, height, def, back, scroll, -1, -1 ); } public static void SendMessageTo( Mobile m, TextDefinition def ) { - if( def.Number > 0 ) - m.SendLocalizedMessage( def.Number ); - else if( def.String != null ) - m.SendMessage( def.String ); + if ( def == null ) + return; + + if ( def.m_Number > 0 ) + m.SendLocalizedMessage( def.m_Number ); + else if ( def.m_String != null ) + m.SendMessage( def.m_String ); + } + + public static TextDefinition Parse( string value ) + { + if ( value == null ) + return null; + else if ( value.StartsWith( "#" ) ) + return new TextDefinition( Utility.ToInt32( value.Substring( 1 ) ) ); + else + return new TextDefinition( value ); } } } \ No newline at end of file diff --git a/Scripts/Mobiles/AI/AnimalAI.cs b/Scripts/Mobiles/AI/AnimalAI.cs index 87ec9b5b9..fcc51c941 100644 --- a/Scripts/Mobiles/AI/AnimalAI.cs +++ b/Scripts/Mobiles/AI/AnimalAI.cs @@ -46,7 +46,7 @@ namespace Server.Mobiles double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; - if ( !m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 ) // Less than 10% health + if ( !m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee ) // Less than 10% health { m_Mobile.DebugSay( "I am low on health!" ); Action = ActionType.Flee; @@ -102,7 +102,7 @@ namespace Server.Mobiles } } - if ( !m_Mobile.Controlled && !m_Mobile.Summoned ) + if ( !m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee ) { double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; @@ -120,7 +120,7 @@ namespace Server.Mobiles { double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; - if ( !m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 ) // Less than 10% health + if ( !m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee ) // Less than 10% health { Action = ActionType.Flee; } diff --git a/Scripts/Mobiles/AI/ArcherAI.cs b/Scripts/Mobiles/AI/ArcherAI.cs index fbf770418..849706f1c 100644 --- a/Scripts/Mobiles/AI/ArcherAI.cs +++ b/Scripts/Mobiles/AI/ArcherAI.cs @@ -80,7 +80,7 @@ namespace Server.Mobiles // At 20% we should check if we must leave - if ( m_Mobile.Hits < m_Mobile.HitsMax*20/100 ) + if ( m_Mobile.Hits < m_Mobile.HitsMax*20/100 && m_Mobile.CanFlee ) { bool bFlee = false; // if my current hits are more than my opponent, i don't care diff --git a/Scripts/Mobiles/AI/MageAI.cs b/Scripts/Mobiles/AI/MageAI.cs index c5325947a..524bbc062 100644 --- a/Scripts/Mobiles/AI/MageAI.cs +++ b/Scripts/Mobiles/AI/MageAI.cs @@ -633,7 +633,7 @@ namespace Server.Mobiles } } - if( !m_Mobile.Controlled && !m_Mobile.Summoned && !m_Mobile.IsParagon ) + if( !m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee ) { if( m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100 ) { diff --git a/Scripts/Mobiles/AI/MeleeAI.cs b/Scripts/Mobiles/AI/MeleeAI.cs index 5e7c276e2..bf93ce875 100644 --- a/Scripts/Mobiles/AI/MeleeAI.cs +++ b/Scripts/Mobiles/AI/MeleeAI.cs @@ -112,7 +112,7 @@ namespace Server.Mobiles m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name ); } - if ( !m_Mobile.Controlled && !m_Mobile.Summoned && !m_Mobile.IsParagon ) + if ( !m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee ) { if ( m_Mobile.Hits < m_Mobile.HitsMax * 20/100 ) { diff --git a/Scripts/Mobiles/AI/ThiefAI.cs b/Scripts/Mobiles/AI/ThiefAI.cs index f6375c009..4296a54e3 100644 --- a/Scripts/Mobiles/AI/ThiefAI.cs +++ b/Scripts/Mobiles/AI/ThiefAI.cs @@ -128,7 +128,7 @@ namespace Server.Mobiles m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name ); } - if ( m_Mobile.Hits < m_Mobile.HitsMax * 20/100 && !m_Mobile.IsParagon ) + if ( m_Mobile.Hits < m_Mobile.HitsMax * 20/100 && m_Mobile.CanFlee ) { // We are low on health, should we flee? diff --git a/Scripts/Mobiles/BaseCreature.cs b/Scripts/Mobiles/BaseCreature.cs index e047ee0a2..a9e0c8f77 100644 --- a/Scripts/Mobiles/BaseCreature.cs +++ b/Scripts/Mobiles/BaseCreature.cs @@ -715,6 +715,8 @@ namespace Server.Mobiles #endregion #region Flee!!! + public virtual bool CanFlee{ get{ return ( !m_Paragon && !GivesMLMinorArtifact ); } } + private DateTime m_EndFlee; public DateTime EndFleeTime @@ -2083,7 +2085,7 @@ namespace Server.Mobiles public virtual bool CheckFeed( Mobile from, Item dropped ) { - if ( !IsDeadPet && Controlled && (ControlMaster == from || IsPetFriend( from )) && (dropped is Food || dropped is Gold || dropped is CookableFood || dropped is Head || dropped is LeftArm || dropped is LeftLeg || dropped is Torso || dropped is RightArm || dropped is RightLeg) ) + if ( !IsDeadPet && Controlled && ( ControlMaster == from || IsPetFriend( from ) ) ) { Item f = dropped; @@ -2114,7 +2116,7 @@ namespace Server.Mobiles { for ( int i = 0; i < amount; ++i ) { - if ( m_Loyalty < MaxLoyalty && 0.5 >= Utility.RandomDouble() ) + if ( m_Loyalty < MaxLoyalty && 0.5 >= Utility.RandomDouble() ) { m_Loyalty += 10; } diff --git a/Scripts/Mobiles/Monsters/ML/Bedlam/RedDeath.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/RedDeath.cs index b4761618f..52f89795c 100644 --- a/Scripts/Mobiles/Monsters/ML/Bedlam/RedDeath.cs +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/RedDeath.cs @@ -14,6 +14,9 @@ namespace Server.Mobiles Hue = 0x21; BaseSoundID = 0x1C3; + AI = AIType.AI_Melee; + FightMode = FightMode.Closest; + SetStr( 319, 324 ); SetDex( 241, 244 ); SetInt( 242, 255 ); diff --git a/Scripts/Mobiles/Monsters/ML/Labyrinth/Pyre.cs b/Scripts/Mobiles/Monsters/ML/Labyrinth/Pyre.cs index 2b27f7732..e0327fe95 100644 --- a/Scripts/Mobiles/Monsters/ML/Labyrinth/Pyre.cs +++ b/Scripts/Mobiles/Monsters/ML/Labyrinth/Pyre.cs @@ -16,6 +16,8 @@ namespace Server.Mobiles Name = "Pyre"; Hue = 0x489; + FightMode = FightMode.Closest; + SetStr( 605, 611 ); SetDex( 391, 519 ); SetInt( 669, 818 ); diff --git a/Scripts/Mobiles/Monsters/ML/Labyrinth/Rend.cs b/Scripts/Mobiles/Monsters/ML/Labyrinth/Rend.cs index a7a4195ca..9f7a16240 100644 --- a/Scripts/Mobiles/Monsters/ML/Labyrinth/Rend.cs +++ b/Scripts/Mobiles/Monsters/ML/Labyrinth/Rend.cs @@ -36,6 +36,9 @@ namespace Server.Mobiles SetSkill( SkillName.MagicResist, 90.9, 110.0 ); SetSkill( SkillName.Anatomy, 66.6, 72.0 ); + Fame = 21000; + Karma = -21000; + Tamable = false; /* diff --git a/Scripts/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs b/Scripts/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs index 745431acd..32093eec0 100644 --- a/Scripts/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs +++ b/Scripts/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs @@ -13,11 +13,13 @@ namespace Server.Mobiles Name = "Putrefier"; Hue = 63; - SetStr( 1057, 1330 ); - SetDex( 232, 450 ); - SetInt( 201, 415 ); + SetStr( 1057, 1400 ); + SetDex( 232, 560 ); + SetInt( 201, 440 ); - SetHits( 3010, 3778 ); + SetHits( 3010, 4092 ); + + SetDamage( 27, 34 ); SetDamageType( ResistanceType.Physical, 50 ); SetDamageType( ResistanceType.Fire, 0 ); @@ -31,12 +33,13 @@ namespace Server.Mobiles SetResistance( ResistanceType.Energy, 40, 50 ); SetSkill( SkillName.Wrestling, 111.2, 128.0 ); - SetSkill( SkillName.Tactics, 115.6, 125.2 ); - SetSkill( SkillName.MagicResist, 143.4, 163.0 ); + SetSkill( SkillName.Tactics, 115.2, 125.2 ); + SetSkill( SkillName.MagicResist, 143.4, 170.0 ); SetSkill( SkillName.Anatomy, 44.6, 67.0 ); SetSkill( SkillName.Magery, 117.6, 118.8 ); SetSkill( SkillName.EvalInt, 113.0, 128.8 ); - SetSkill( SkillName.Meditation, 41.4, 80.5 ); + SetSkill( SkillName.Meditation, 41.4, 85.0 ); + SetSkill( SkillName.Poisoning, 45.0, 50.0 ); PackScroll( 4, 7 ); PackScroll( 4, 7 ); diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs index aba898e42..8330a674e 100644 --- a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs @@ -62,6 +62,8 @@ namespace Server.Mobiles PackArcaneScroll( 0, 1 ); } + public override bool ShowFameTitle{ get{ return false; } } + public override void GenerateLoot() { AddLoot( LootPack.AosRich, 3 ); diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs index b3f159834..1971001e5 100644 --- a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs @@ -14,6 +14,8 @@ namespace Server.Mobiles Name = "Swoop"; Hue = 0xE0; + AI = AIType.AI_Melee; + SetStr( 100, 150 ); SetDex( 400, 500 ); SetInt( 80, 90 ); @@ -35,7 +37,7 @@ namespace Server.Mobiles SetSkill( SkillName.MagicResist, 95.0, 105.0 ); Fame = 18000; - Karma = -18000; + Karma = 0; Tamable = false; diff --git a/Scripts/Mobiles/Special/Paragon.cs b/Scripts/Mobiles/Special/Paragon.cs index a699c6f89..46c05dd88 100644 --- a/Scripts/Mobiles/Special/Paragon.cs +++ b/Scripts/Mobiles/Special/Paragon.cs @@ -141,7 +141,7 @@ namespace Server.Mobiles if ( Array.IndexOf( Maps, m ) == -1 ) return false; - if ( bc is BaseChampion || bc is Harrower || bc is BaseVendor || bc is BaseEscortable || bc is Clone ) + if ( bc is BaseChampion || bc is Harrower || bc is BaseVendor || bc is BaseEscortable || bc is Clone || bc.GivesMLMinorArtifact ) return false; int fame = bc.Fame; diff --git a/Scripts/Spells/Base/SpellHelper.cs b/Scripts/Spells/Base/SpellHelper.cs index bb8aefd7f..751b3e185 100644 --- a/Scripts/Spells/Base/SpellHelper.cs +++ b/Scripts/Spells/Base/SpellHelper.cs @@ -556,29 +556,21 @@ namespace Server.Spells new TravelValidator( IsLampRoom ), new TravelValidator( IsGuardianRoom ), new TravelValidator( IsHeartwood ), + new TravelValidator( IsMLDungeon ) }; private static bool[,] m_Rules = new bool[,] { - /*T2A(Fel) Ilshenar Wind(Tram), Wind(Fel), Dungeons(Fel), Solen(Tram), Solen(Fel), CrystalCave(Malas), Gauntlet(Malas), Gauntlet(Ferry), Stronghold, ChampionSpawn, Dungeons(Tokuno[Malas]), LampRoom(Doom), GuardianRoom(Doom), Heartwood */ -/* Recall From */ { false, true, true, false, false, true, false, false, false, false, true, false, true, false, false, false }, -/* Recall To */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, -/* Gate From */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, -/* Gate To */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, -/* Mark In */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, -/* Tele From */ { true, true, true, true, true, true, true, false, true, true, false, true, true, true, true, false }, -/* Tele To */ { true, true, true, true, true, true, true, false, true, false, false, true, true, true, true, false }, + /*T2A(Fel) Ilshenar Wind(Tram), Wind(Fel), Dungeons(Fel), Solen(Tram), Solen(Fel), CrystalCave(Malas), Gauntlet(Malas), Gauntlet(Ferry), Stronghold, ChampionSpawn, Dungeons(Tokuno[Malas]), LampRoom(Doom), GuardianRoom(Doom), Heartwood, MLDungeons */ +/* Recall From */ { false, true, true, false, false, true, false, false, false, false, true, false, true, false, false, false, false }, +/* Recall To */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, +/* Gate From */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, +/* Gate To */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, +/* Mark In */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, +/* Tele From */ { true, true, true, true, true, true, true, false, true, true, false, true, true, true, true, false, true }, +/* Tele To */ { true, true, true, true, true, true, true, false, true, false, false, true, true, true, true, false, false }, }; - public static bool CheckTravel( Mobile caster, TravelCheckType type ) - { - if( CheckTravel( caster, caster.Map, caster.Location, type ) ) - return true; - - SendInvalidMessage( caster, type ); - return false; - } - public static void SendInvalidMessage( Mobile caster, TravelCheckType type ) { if( type == TravelCheckType.RecallTo || type == TravelCheckType.GateTo ) @@ -589,6 +581,11 @@ namespace Server.Spells caster.SendLocalizedMessage( 501802 ); // Thy spell doth not appear to work... } + public static bool CheckTravel( Mobile caster, TravelCheckType type ) + { + return CheckTravel( caster, caster.Map, caster.Location, type ); + } + public static bool CheckTravel( Map map, Point3D loc, TravelCheckType type ) { return CheckTravel( null, map, loc, type ); @@ -613,6 +610,15 @@ namespace Server.Spells return false; } + // Always allow monsters to teleport + if ( caster is BaseCreature && ( type == TravelCheckType.TeleportTo || type == TravelCheckType.TeleportFrom ) ) + { + BaseCreature bc = (BaseCreature)caster; + + if ( !bc.Controlled && !bc.Summoned ) + return true; + } + m_TravelCaster = caster; m_TravelType = type; @@ -689,17 +695,15 @@ namespace Server.Spells public static bool IsCrystalCave( Map map, Point3D loc ) { - if( map != Map.Malas ) + if( map != Map.Malas || loc.Z >= -80 ) return false; - int x = loc.X, y = loc.Y, z = loc.Z; + int x = loc.X, y = loc.Y; - bool r1 = (x >= 1182 && y >= 437 && x < 1211 && y < 470); - bool r2 = (x >= 1156 && y >= 470 && x < 1211 && y < 503); - bool r3 = (x >= 1176 && y >= 503 && x < 1208 && y < 509); - bool r4 = (x >= 1188 && y >= 509 && x < 1201 && y < 513); - - return (z < -80 && (r1 || r2 || r3 || r4)); + return ( x >= 1182 && y >= 437 && x < 1211 && y < 470 ) + || ( x >= 1156 && y >= 470 && x < 1211 && y < 503 ) + || ( x >= 1176 && y >= 503 && x < 1208 && y < 509 ) + || ( x >= 1188 && y >= 509 && x < 1201 && y < 513 ); } public static bool IsFactionStronghold( Map map, Point3D loc ) @@ -786,6 +790,11 @@ namespace Server.Spells return (map == Map.Trammel || map == Map.Felucca) && (x >= 6911 && y >= 254 && x < 7167 && y < 511); } + public static bool IsMLDungeon( Map map, Point3D loc ) + { + return MondainsLegacy.IsMLRegion( Region.Find( loc, map ) ); + } + public static bool IsInvalid( Map map, Point3D loc ) { if( map == null || map == Map.Internal )