From 2204d5fb861124f3be1cbda69d408b1352d843a6 Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 28 Jun 2009 03:36:42 +0000 Subject: [PATCH] --- Scripts/Commands/Handlers.cs | 28 ++- Scripts/Engines/AI/AI/BaseAI.cs | 19 +- Scripts/Engines/AI/Creature/BaseCreature.cs | 209 ++++++++++++++---- Scripts/Engines/AI/Creature/SpeedInfo.cs | 4 +- .../Engines/BulkOrders/Books/BulkOrderBook.cs | 29 +++ Scripts/Engines/Harvest/Core/HarvestBank.cs | 8 +- Scripts/Engines/Harvest/Fishing.cs | 9 + Scripts/Engines/Harvest/Mining.cs | 14 +- Scripts/Engines/Pathing/FastAStarAlgorithm.cs | 4 +- Scripts/Engines/Pathing/MovementPath.cs | 4 +- Scripts/Gumps/HouseDemolishGump.cs | 2 + .../Items/Construction/Misc/BarrelParts.cs | 2 + Scripts/Items/Containers/Container.cs | 2 +- Scripts/Items/Deeds/HolidayTreeDeed.cs | 4 +- Scripts/Items/Food/Asian.cs | 2 +- Scripts/Items/Food/Cooking.cs | 2 + Scripts/Items/Food/Food.cs | 4 +- Scripts/Items/Misc/ArcaneGem.cs | 1 + Scripts/Items/Misc/Corpses/Corpse.cs | 10 + Scripts/Items/Misc/TribalPaint.cs | 1 + Scripts/Items/Resources/Fishing/BigFish.cs | 2 +- Scripts/Items/Resources/Masonry/Granite.cs | 1 + .../Carpenter Items/TaxidermyKit.cs | 2 + .../Skill Items/Magical/Potions/BasePotion.cs | 14 +- Scripts/Items/Skill Items/Magical/Runebook.cs | 24 +- .../Magical/Scrolls/SpellweavingScrolls.cs | 16 ++ Scripts/Items/Skill Items/Ninjitsu/EggBomb.cs | 1 + .../Items/Skill Items/Ninjitsu/SmokeBomb.cs | 1 + Scripts/Items/Skill Items/Specialized/Sand.cs | 2 +- .../Items/Skill Items/Tools/BaseRunicTool.cs | 8 +- .../Special/Holiday/Christmas/HolidayTree.cs | 34 ++- .../Special/Solen Items/BallOfSummoning.cs | 167 ++++++++++++-- Scripts/Items/Wands/BaseWand.cs | 16 ++ Scripts/Items/Weapons/Abilities/Disarm.cs | 12 +- Scripts/Items/Weapons/Abilities/Dismount.cs | 16 +- .../Weapons/Abilities/InfectiousStrike.cs | 5 + Scripts/Items/Weapons/Abilities/MovingShot.cs | 2 +- .../Items/Weapons/Abilities/ParalyzingBlow.cs | 10 + .../Items/Weapons/Abilities/ShadowStrike.cs | 5 + .../Items/Weapons/Abilities/WeaponAbility.cs | 28 ++- Scripts/Items/Weapons/BaseWeapon.cs | 43 ++-- Scripts/Items/Weapons/Maces/MagicWand.cs | 3 + Scripts/Misc/AOS.cs | 2 +- Scripts/Misc/Notoriety.cs | 10 + Scripts/Misc/RegenRates.cs | 7 +- Scripts/Mobiles/Animals/Mounts/Hiryu.cs | 2 +- Scripts/Mobiles/Animals/Mounts/LesserHiryu.cs | 22 +- Scripts/Mobiles/Familiars/HordeMinion.cs | 2 +- Scripts/Mobiles/Monsters/AOS/AbysmalHorror.cs | 2 +- Scripts/Mobiles/Monsters/AOS/BoneDemon.cs | 5 +- .../Mobiles/Monsters/AOS/DarknightCreeper.cs | 2 +- Scripts/Mobiles/Monsters/AOS/DemonKnight.cs | 2 +- Scripts/Mobiles/Monsters/AOS/FleshRenderer.cs | 5 +- Scripts/Mobiles/Monsters/AOS/Impaler.cs | 2 +- Scripts/Mobiles/Monsters/AOS/ShadowKnight.cs | 4 +- Scripts/Mobiles/Monsters/Misc/Melee/Golem.cs | 4 +- Scripts/Mobiles/Monsters/SE/RuneBeetle.cs | 40 +++- Scripts/Mobiles/PlayerMobile.cs | 142 +++++++++++- Scripts/Mobiles/Townfolk/BaseEscortable.cs | 2 +- Scripts/Multis/Camps/OrcCamp.cs | 4 + Scripts/Multis/Camps/RatCamp.cs | 4 + Scripts/Skills/AnimalTaming.cs | 19 +- Scripts/Skills/Hiding.cs | 7 +- Scripts/Skills/Peacemaking.cs | 2 +- Scripts/Spells/Base/SpecialMove.cs | 4 +- Scripts/Spells/Base/Spell.cs | 3 + Scripts/Spells/Bushido/HonorableExecution.cs | 8 - Scripts/Spells/Bushido/LightningStrike.cs | 7 +- Scripts/Spells/Bushido/SamuraiSpell.cs | 6 +- Scripts/Spells/Chivalry/DivineFury.cs | 2 + Scripts/Spells/Chivalry/EnemyOfOne.cs | 2 + Scripts/Spells/Chivalry/PaladinSpell.cs | 8 +- Scripts/Spells/Chivalry/RemoveCurse.cs | 4 + Scripts/Spells/First/ReactiveArmor.cs | 7 + Scripts/Spells/Fourth/Curse.cs | 7 + Scripts/Spells/Necromancy/BloodOathSpell.cs | 48 +++- Scripts/Spells/Necromancy/MindRot.cs | 98 +++++--- Scripts/Spells/Necromancy/PainSpike.cs | 4 +- Scripts/Spells/Necromancy/PoisonStrike.cs | 11 +- Scripts/Spells/Ninjitsu/DeathStrike.cs | 3 + Scripts/Spells/Ninjitsu/NinjaSpell.cs | 6 +- Scripts/Spells/Second/Protection.cs | 11 +- Scripts/Spells/Spellweaving/ArcanistSpell.cs | 2 +- Scripts/Spells/Spellweaving/NatureFury.cs | 7 + Scripts/Spells/Spellweaving/Thunderstorm.cs | 18 +- Scripts/Spells/Third/Bless.cs | 7 + 86 files changed, 1077 insertions(+), 257 deletions(-) diff --git a/Scripts/Commands/Handlers.cs b/Scripts/Commands/Handlers.cs index 21ecfc5a4..edbcfd89c 100644 --- a/Scripts/Commands/Handlers.cs +++ b/Scripts/Commands/Handlers.cs @@ -272,7 +272,33 @@ namespace Server.Commands public static void GetFollowers_OnTarget( Mobile from, object obj ) { - if ( obj is Mobile && ((Mobile)obj).Player ) + if ( obj is PlayerMobile ) + { + PlayerMobile master = (PlayerMobile)obj; + List pets = master.AllFollowers; + + if ( pets.Count > 0 ) + { + CommandLogging.WriteLine( from, "{0} {1} getting all followers of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( master ) ); + + from.SendMessage( "That player has {0} pet{1}.", pets.Count, pets.Count != 1 ? "s" : "" ); + + for ( int i = 0; i < pets.Count; ++i ) + { + Mobile pet = (Mobile)pets[i]; + + if ( pet is IMount ) + ((IMount)pet).Rider = null; // make sure it's dismounted + + pet.MoveToWorld( from.Location, from.Map ); + } + } + else + { + from.SendMessage( "There were no pets found for that player." ); + } + } + else if ( obj is Mobile && ((Mobile)obj).Player ) { Mobile master = (Mobile)obj; ArrayList pets = new ArrayList(); diff --git a/Scripts/Engines/AI/AI/BaseAI.cs b/Scripts/Engines/AI/AI/BaseAI.cs index 97adff4d2..a8bd640a6 100644 --- a/Scripts/Engines/AI/AI/BaseAI.cs +++ b/Scripts/Engines/AI/AI/BaseAI.cs @@ -1096,6 +1096,7 @@ namespace Server.Mobiles case OrderType.Stop: m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.Home = m_Mobile.Location; m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = false; @@ -1476,13 +1477,9 @@ namespace Server.Mobiles Mobile newCombatant = null; double newScore = 0.0; - List list = m_Mobile.Aggressors; - - for( int i = 0; i < list.Count; ++i ) + foreach( Mobile aggr in m_Mobile.GetMobilesInRange( m_Mobile.RangePerception ) ) { - Mobile aggr = list[i].Attacker; - - if( aggr.Map != m_Mobile.Map || !aggr.InRange( m_Mobile.Location, m_Mobile.RangePerception ) || !m_Mobile.CanSee( aggr ) ) + if( !m_Mobile.CanSee( aggr ) || aggr.Combatant != m_Mobile ) continue; if( aggr.IsDeadBondedPet || !aggr.Alive ) @@ -1571,7 +1568,15 @@ namespace Server.Mobiles m_Mobile.Home = m_Mobile.Location; m_Mobile.ControlTarget = null; - m_Mobile.ControlOrder = OrderType.None; + + if( Core.ML ) + { + WalkRandomInHome( 3, 2, 1 ); + } + else + { + m_Mobile.ControlOrder = OrderType.None; + } return true; } diff --git a/Scripts/Engines/AI/Creature/BaseCreature.cs b/Scripts/Engines/AI/Creature/BaseCreature.cs index 6332e41e6..7726db526 100644 --- a/Scripts/Engines/AI/Creature/BaseCreature.cs +++ b/Scripts/Engines/AI/Creature/BaseCreature.cs @@ -55,9 +55,10 @@ namespace Server.Mobiles [Flags] public enum FoodType { + None = 0x0000, Meat = 0x0001, - FruitsAndVegies = 0x0002, - GrainsAndHay = 0x0004, + FruitsAndVegies = 0x0002, + GrainsAndHay = 0x0004, Fish = 0x0008, Eggs = 0x0010, Gold = 0x0020 @@ -170,39 +171,39 @@ namespace Server.Mobiles #region Var declarations private BaseAI m_AI; // THE AI - private AIType m_CurrentAI; // The current AI - private AIType m_DefaultAI; // The default AI + private AIType m_CurrentAI; // The current AI + private AIType m_DefaultAI; // The default AI private Mobile m_FocusMob; // Use focus mob instead of combatant, maybe we don't whan to fight - private FightMode m_FightMode; // The style the mob uses + private FightMode m_FightMode; // The style the mob uses private int m_iRangePerception; // The view area private int m_iRangeFight; // The fight distance - - private bool m_bDebugAI; // Show debug AI messages - private int m_iTeam; // Monster Team + private bool m_bDebugAI; // Show debug AI messages - private double m_dActiveSpeed; // Timer speed when active - private double m_dPassiveSpeed; // Timer speed when not active - private double m_dCurrentSpeed; // The current speed, lets say it could be changed by something; + private int m_iTeam; // Monster Team - private Point3D m_pHome; // The home position of the creature, used by some AI + private double m_dActiveSpeed; // Timer speed when active + private double m_dPassiveSpeed; // Timer speed when not active + private double m_dCurrentSpeed; // The current speed, lets say it could be changed by something; + + private Point3D m_pHome; // The home position of the creature, used by some AI private int m_iRangeHome = 10; // The home range of the creature List m_arSpellAttack; // List of attack spell/power List m_arSpellDefense; // List of defensive spell/power - private bool m_bControlled; // Is controlled - private Mobile m_ControlMaster; // My master - private Mobile m_ControlTarget; // My target mobile - private Point3D m_ControlDest; // My target destination (patrol) - private OrderType m_ControlOrder; // My order + private bool m_bControlled; // Is controlled + private Mobile m_ControlMaster; // My master + private Mobile m_ControlTarget; // My target mobile + private Point3D m_ControlDest; // My target destination (patrol) + private OrderType m_ControlOrder; // My order - private int m_Loyalty; + private int m_Loyalty; - private double m_dMinTameSkill; - private bool m_bTamable; + private double m_dMinTameSkill; + private bool m_bTamable; private bool m_bSummoned = false; private DateTime m_SummonEnd; @@ -218,20 +219,20 @@ namespace Server.Mobiles private Mobile m_SummonMaster; - private int m_HitsMax = -1; - private int m_StamMax = -1; - private int m_ManaMax = -1; - private int m_DamageMin = -1; - private int m_DamageMax = -1; + private int m_HitsMax = -1; + private int m_StamMax = -1; + private int m_ManaMax = -1; + private int m_DamageMin = -1; + private int m_DamageMax = -1; - private int m_PhysicalResistance, m_PhysicalDamage = 100; - private int m_FireResistance, m_FireDamage; - private int m_ColdResistance, m_ColdDamage; - private int m_PoisonResistance, m_PoisonDamage; - private int m_EnergyResistance, m_EnergyDamage; + private int m_PhysicalResistance, m_PhysicalDamage = 100; + private int m_FireResistance, m_FireDamage; + private int m_ColdResistance, m_ColdDamage; + private int m_PoisonResistance, m_PoisonDamage; + private int m_EnergyResistance, m_EnergyDamage; - private List m_Owners; - private List m_Friends; + private List m_Owners; + private List m_Friends; private bool m_IsStabled; @@ -239,6 +240,10 @@ namespace Server.Mobiles private bool m_Paragon; + private bool m_IsPrisoner; + + private Timer m_GhostDeletionTimer; + #endregion public virtual InhumanSpeech SpeechType{ get{ return null; } } @@ -246,9 +251,20 @@ namespace Server.Mobiles public bool IsStabled { get{ return m_IsStabled; } - set{ m_IsStabled = value; } + set + { + m_IsStabled = value; + SetGhostDeletionTimer( !m_IsStabled ); + } } + [CommandProperty( AccessLevel.GameMaster )] + public bool IsPrisoner + { + get{ return m_IsPrisoner; } + set{ m_IsPrisoner = value; } + } + protected DateTime SummonEnd { get { return m_SummonEnd; } @@ -402,6 +418,7 @@ namespace Server.Mobiles public virtual bool BardImmune{ get{ return false; } } public virtual bool Unprovokable{ get{ return BardImmune || m_IsDeadPet; } } public virtual bool Uncalmable{ get{ return BardImmune || m_IsDeadPet; } } + public virtual bool AreaPeaceImmune { get { return BardImmune || m_IsDeadPet; } } public virtual bool BleedImmune{ get{ return false; } } public virtual double BonusPetDamageScalar{ get{ return 1.0; } } @@ -824,16 +841,38 @@ namespace Server.Mobiles int taming = (int)((useBaseSkill ? m.Skills[SkillName.AnimalTaming].Base : m.Skills[SkillName.AnimalTaming].Value ) * 10); int lore = (int)((useBaseSkill ? m.Skills[SkillName.AnimalLore].Base : m.Skills[SkillName.AnimalLore].Value )* 10); + int bonus = 0, chance = 700; - int difficulty = (int)(dMinTameSkill * 10); - int weighted = ((taming * 4) + lore) / 5; - int bonus = weighted - difficulty; - int chance; + if( Core.ML ) + { + int SkillBonus = taming - (int)(dMinTameSkill * 10); + int LoreBonus = lore - (int)(dMinTameSkill * 10); - if ( bonus <= 0 ) - chance = 700 + (bonus * 14); + int SkillMod = 6, LoreMod = 6; + + if( SkillBonus < 0 ) + SkillMod = 28; + if( LoreBonus < 0 ) + LoreMod = 14; + + SkillBonus *= SkillMod; + LoreBonus *= LoreMod; + + bonus = (SkillBonus + LoreBonus ) / 2; + } else - chance = 700 + (bonus * 6); + { + int difficulty = (int)(dMinTameSkill * 10); + int weighted = ((taming * 4) + lore) / 5; + bonus = weighted - difficulty; + + if ( bonus <= 0 ) + bonus *= 14; + else + bonus *= 6; + } + + chance += bonus; if ( chance >= 0 && chance < 200 ) chance = 200; @@ -1693,6 +1732,8 @@ namespace Server.Mobiles if ( IsAnimatedDead ) Spells.Necromancy.AnimateDeadSpell.Register( m_SummonMaster, this ); + + SetGhostDeletionTimer( true ); } public virtual bool IsHumanInTown() @@ -2215,9 +2256,23 @@ namespace Server.Mobiles public void RemoveFollowers() { if ( m_ControlMaster != null ) + { m_ControlMaster.Followers -= ControlSlots; + if( m_ControlMaster is PlayerMobile ) + { + ((PlayerMobile)m_ControlMaster).AllFollowers.Remove( this ); + if( ((PlayerMobile)m_ControlMaster).AutoStabled.Contains( this ) ) + ((PlayerMobile)m_ControlMaster).AutoStabled.Remove( this ); + } + } else if ( m_SummonMaster != null ) + { m_SummonMaster.Followers -= ControlSlots; + if( m_SummonMaster is PlayerMobile ) + { + ((PlayerMobile)m_SummonMaster).AllFollowers.Remove( this ); + } + } if ( m_ControlMaster != null && m_ControlMaster.Followers < 0 ) m_ControlMaster.Followers = 0; @@ -2229,9 +2284,21 @@ namespace Server.Mobiles public void AddFollowers() { if ( m_ControlMaster != null ) + { m_ControlMaster.Followers += ControlSlots; + if( m_ControlMaster is PlayerMobile ) + { + ((PlayerMobile)m_ControlMaster).AllFollowers.Add( this ); + } + } else if ( m_SummonMaster != null ) + { m_SummonMaster.Followers += ControlSlots; + if( m_SummonMaster is PlayerMobile ) + { + ((PlayerMobile)m_SummonMaster).AllFollowers.Add( this ); + } + } } [CommandProperty( AccessLevel.GameMaster )] @@ -2833,8 +2900,22 @@ namespace Server.Mobiles { base.AggressiveAction( aggressor, criminal ); + OrderType ct = m_ControlOrder; + if ( m_AI != null ) - m_AI.OnAggressiveAction( aggressor ); + { + if( !Core.ML || ( ct != OrderType.Follow && ct != OrderType.Stop ) ) + { + m_AI.OnAggressiveAction( aggressor ); + } + else + { + DebugSay( "I'm being attacked but my master told me not to fight." ); + Warmode = false; + Combatant = null; + return; + } + } StopFlee(); @@ -2848,9 +2929,7 @@ namespace Server.Mobiles pl.FinishShield(); } - OrderType ct = m_ControlOrder; - - if ( aggressor.ChangingCombatant && (m_bControlled || m_bSummoned) && (ct == OrderType.Come || ct == OrderType.Stay || ct == OrderType.Stop || ct == OrderType.None || ct == OrderType.Follow) ) + if ( aggressor.ChangingCombatant && (m_bControlled || m_bSummoned) && (ct == OrderType.Come || ( !Core.ML && ct == OrderType.Stay ) || ct == OrderType.Stop || ct == OrderType.None || ct == OrderType.Follow) ) { ControlTarget = aggressor; ControlOrder = OrderType.Attack; @@ -2874,7 +2953,7 @@ namespace Server.Mobiles { } - public virtual bool CanDrop { get { return !Summoned; } } + public virtual bool CanDrop { get { return IsBonded; } } public override void GetContextMenuEntries( Mobile from, List list ) { @@ -4182,6 +4261,8 @@ namespace Server.Mobiles GiftOfLifeSpell.HandleDeath( this ); CheckStatTimers(); + + SetGhostDeletionTimer( true ); } else { @@ -4801,8 +4882,26 @@ namespace Server.Mobiles } CheckStatTimers(); + + SetGhostDeletionTimer( false ); } + private void SetGhostDeletionTimer( bool running ) + { + if( running && ( !IsDeadBondedPet || !Core.ML ) ) + return; + + if( m_GhostDeletionTimer != null ) + m_GhostDeletionTimer.Stop(); + + if( !running ) + return; + + m_GhostDeletionTimer = new GhostDeletionTimer( this, TimeSpan.FromMinutes( 120 + Utility.Random( 120 ) ) ); + m_GhostDeletionTimer.Start(); + } + + public override bool CanBeDamaged() { if ( IsDeadPet ) @@ -4839,6 +4938,26 @@ namespace Server.Mobiles [CommandProperty( AccessLevel.GameMaster )] public int RemoveStep { get { return m_RemoveStep; } set { m_RemoveStep = value; } } + + private class GhostDeletionTimer : Timer + { + private BaseCreature m_Creature; + + public GhostDeletionTimer( BaseCreature Creature, TimeSpan delay ) : base( delay ) + { + Priority = TimerPriority.FiveSeconds; + m_Creature = Creature; + } + + protected override void OnTick() + { + if( Core.ML && m_Creature.IsDeadBondedPet ); + { + m_Creature.Delete(); + } + Stop(); + } + } } public class LoyaltyTimer : Timer diff --git a/Scripts/Engines/AI/Creature/SpeedInfo.cs b/Scripts/Engines/AI/Creature/SpeedInfo.cs index dfddfb2c0..24d07a3c9 100644 --- a/Scripts/Engines/AI/Creature/SpeedInfo.cs +++ b/Scripts/Engines/AI/Creature/SpeedInfo.cs @@ -118,7 +118,7 @@ namespace Server typeof( SnowElemental ), typeof( WhiteWyrm ), typeof( Wisp ), typeof( DemonKnight ), typeof( GiantBlackWidow ), typeof( SummonedAirElemental ), typeof( LesserHiryu ), typeof( Hiryu ), typeof( LadyOfTheSnow ), - typeof( RaiJu ), typeof( Ronin ) + typeof( RaiJu ), typeof( Ronin ), typeof( RuneBeetle ) } ), /* Very Fast */ new SpeedInfo( 0.175, 0.350, new Type[] @@ -206,7 +206,7 @@ namespace Server typeof( Kappa ), typeof( KazeKemono ), typeof( DeathwatchBeetle ), typeof( TsukiWolf ), typeof( YomotsuElder ), typeof( YomotsuPriest ), typeof( YomotsuWarrior ), typeof( RevenantLion ), typeof( Oni ), - typeof( RuneBeetle ), typeof( Gaman ), typeof( Crane ) + typeof( Gaman ), typeof( Crane ) } ) }; } diff --git a/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs b/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs index aac2ed6f4..cf0b742b2 100644 --- a/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs +++ b/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs @@ -7,6 +7,7 @@ using Server.Multis; using Server.Prompts; using Server.Mobiles; using Server.ContextMenus; +using Server.Items; namespace Server.Engines.BulkOrders { @@ -63,6 +64,34 @@ namespace Server.Engines.BulkOrders from.SendGump( new BOBGump( (PlayerMobile)from, this ) ); } + public override void OnDoubleClickSecureTrade( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + else if ( m_Entries.Count == 0 ) + { + from.SendLocalizedMessage( 1062381 ); // The book is empty. + } + else + { + from.SendGump( new BOBGump( (PlayerMobile)from, this ) ); + + SecureTradeContainer cont = GetSecureTradeCont(); + + if ( cont != null ) + { + SecureTrade trade = cont.Trade; + + if ( trade != null && trade.From.Mobile == from ) + trade.To.Mobile.SendGump( new BOBGump( (PlayerMobile)(trade.To.Mobile), this ) ); + else if ( trade != null && trade.To.Mobile == from ) + trade.From.Mobile.SendGump( new BOBGump( (PlayerMobile)(trade.From.Mobile), this ) ); + } + } + } + public override bool OnDragDrop( Mobile from, Item dropped ) { if ( dropped is LargeBOD ) diff --git a/Scripts/Engines/Harvest/Core/HarvestBank.cs b/Scripts/Engines/Harvest/Core/HarvestBank.cs index 5ac2975b4..541ce0c0f 100644 --- a/Scripts/Engines/Harvest/Core/HarvestBank.cs +++ b/Scripts/Engines/Harvest/Core/HarvestBank.cs @@ -56,12 +56,10 @@ namespace Server.Engines.Harvest if ( m_Definition.RandomizeVeins ) { - m_Vein = m_Definition.GetVeinFrom( Utility.RandomDouble() ); - } - else - { - m_Vein = m_DefaultVein; + m_DefaultVein = m_Definition.GetVeinFrom( Utility.RandomDouble() ); } + + m_Vein = m_DefaultVein; } public void Consume( int amount, Mobile from ) diff --git a/Scripts/Engines/Harvest/Fishing.cs b/Scripts/Engines/Harvest/Fishing.cs index b082487bb..0a6044380 100644 --- a/Scripts/Engines/Harvest/Fishing.cs +++ b/Scripts/Engines/Harvest/Fishing.cs @@ -91,6 +91,15 @@ namespace Server.Engines.Harvest fish.Resources = res; fish.Veins = veins; + if ( Core.ML ) + { + fish.BonusResources = new BonusHarvestResource[] + { + new BonusHarvestResource( 0, 99.4, null, null ), //set to same chance as mining ml gems + new BonusHarvestResource( 80.0, .6, 1072597, typeof( WhitePearl ) ) + }; + } + m_Definition = fish; Definitions.Add( fish ); #endregion diff --git a/Scripts/Engines/Harvest/Mining.cs b/Scripts/Engines/Harvest/Mining.cs index 4e481e262..03ed08780 100644 --- a/Scripts/Engines/Harvest/Mining.cs +++ b/Scripts/Engines/Harvest/Mining.cs @@ -114,13 +114,13 @@ namespace Server.Engines.Harvest { oreAndStone.BonusResources = new BonusHarvestResource[] { - new BonusHarvestResource( 0, 99.8998, null, null ), //Nothing //Note: Rounded the below to .0167 instead of 1/6th of a %. Close enough - new BonusHarvestResource( 100, .0167, 1072562, typeof( BlueDiamond ) ), - new BonusHarvestResource( 100, .0167, 1072567, typeof( DarkSapphire ) ), - new BonusHarvestResource( 100, .0167, 1072570, typeof( EcruCitrine ) ), - new BonusHarvestResource( 100, .0167, 1072564, typeof( FireRuby ) ), - new BonusHarvestResource( 100, .0167, 1072566, typeof( PerfectEmerald ) ), - new BonusHarvestResource( 100, .0167, 1072568, typeof( Turquoise ) ) + new BonusHarvestResource( 0, 99.4, null, null ), //Nothing + new BonusHarvestResource( 100, .1, 1072562, typeof( BlueDiamond ) ), + new BonusHarvestResource( 100, .1, 1072567, typeof( DarkSapphire ) ), + new BonusHarvestResource( 100, .1, 1072570, typeof( EcruCitrine ) ), + new BonusHarvestResource( 100, .1, 1072564, typeof( FireRuby ) ), + new BonusHarvestResource( 100, .1, 1072566, typeof( PerfectEmerald ) ), + new BonusHarvestResource( 100, .1, 1072568, typeof( Turquoise ) ) }; } diff --git a/Scripts/Engines/Pathing/FastAStarAlgorithm.cs b/Scripts/Engines/Pathing/FastAStarAlgorithm.cs index ad8a00716..a39e8e779 100644 --- a/Scripts/Engines/Pathing/FastAStarAlgorithm.cs +++ b/Scripts/Engines/Pathing/FastAStarAlgorithm.cs @@ -166,13 +166,13 @@ namespace Server.PathAlgorithms.FastAStar int newCost = m_Nodes[bestNode].cost + 1; int newTotal = newCost + Heuristic( newNode % AreaSize, (newNode / AreaSize) % AreaSize, m_Nodes[newNode].z ); - if ( m_Nodes[newNode].total > newTotal ) + if ( !wasTouched || m_Nodes[newNode].total > newTotal ) { m_Nodes[newNode].parent = bestNode; m_Nodes[newNode].cost = newCost; m_Nodes[newNode].total = newTotal; - if ( !m_OnOpen[newNode] ) + if ( !wasTouched || !m_OnOpen[newNode] ) { AddToChain( newNode ); diff --git a/Scripts/Engines/Pathing/MovementPath.cs b/Scripts/Engines/Pathing/MovementPath.cs index 5f4bc430c..22ccdc354 100644 --- a/Scripts/Engines/Pathing/MovementPath.cs +++ b/Scripts/Engines/Pathing/MovementPath.cs @@ -149,8 +149,8 @@ namespace Server { alg = FastAStarAlgorithm.Instance; - if ( !alg.CheckCondition( m, map, start, goal ) ) - alg = SlowAStarAlgorithm.Instance; + //if ( !alg.CheckCondition( m, map, start, goal ) ) // SlowAstar is still broken + // alg = SlowAStarAlgorithm.Instance; // TODO: Fix SlowAstar } if ( alg != null && alg.CheckCondition( m, map, start, goal ) ) diff --git a/Scripts/Gumps/HouseDemolishGump.cs b/Scripts/Gumps/HouseDemolishGump.cs index 83bc0604c..fc459a0f1 100644 --- a/Scripts/Gumps/HouseDemolishGump.cs +++ b/Scripts/Gumps/HouseDemolishGump.cs @@ -92,6 +92,8 @@ namespace Server.Gumps if ( m_Mobile.AccessLevel >= AccessLevel.GameMaster ) { m_Mobile.SendMessage( "You do not get a refund for your house as you are not a player" ); + m_House.RemoveKeys(m_Mobile); + m_House.Delete(); } else { diff --git a/Scripts/Items/Construction/Misc/BarrelParts.cs b/Scripts/Items/Construction/Misc/BarrelParts.cs index 823a0b16d..f61401a2a 100644 --- a/Scripts/Items/Construction/Misc/BarrelParts.cs +++ b/Scripts/Items/Construction/Misc/BarrelParts.cs @@ -59,6 +59,8 @@ namespace Server.Items public class BarrelHoops : Item { + public override int LabelNumber { get { return 1011228; } } // Barrel hoops + [Constructable] public BarrelHoops() : base(0x1DB7) { diff --git a/Scripts/Items/Containers/Container.cs b/Scripts/Items/Containers/Container.cs index 5cf8feb6d..f83e4a803 100644 --- a/Scripts/Items/Containers/Container.cs +++ b/Scripts/Items/Containers/Container.cs @@ -194,7 +194,7 @@ namespace Server.Items get { if ( Core.ML ) { Mobile m = ParentEntity as Mobile; - if ( m != null && m.Backpack == this ) { + if ( m != null && m.Player && m.Backpack == this ) { return 550; } else { return base.DefaultMaxWeight; diff --git a/Scripts/Items/Deeds/HolidayTreeDeed.cs b/Scripts/Items/Deeds/HolidayTreeDeed.cs index f3b8352ce..2b9522f87 100644 --- a/Scripts/Items/Deeds/HolidayTreeDeed.cs +++ b/Scripts/Items/Deeds/HolidayTreeDeed.cs @@ -106,7 +106,9 @@ namespace Server.Items public void EndPlace( Mobile from, HolidayTreeType type, Point3D loc ) { this.Delete(); - new HolidayTree( from, type, loc ); + HolidayTree tree = new HolidayTree( from, type, loc ); + BaseHouse house = BaseHouse.FindHouseAt( tree ); + house.Addons.Add( tree ); } public override void OnDoubleClick( Mobile from ) diff --git a/Scripts/Items/Food/Asian.cs b/Scripts/Items/Food/Asian.cs index 19ed5cfd4..5d8b50b22 100644 --- a/Scripts/Items/Food/Asian.cs +++ b/Scripts/Items/Food/Asian.cs @@ -157,7 +157,7 @@ namespace Server.Items [Constructable] public SushiPlatter() : base( 0x2840 ) { - Stackable = false; + Stackable = Core.ML; Weight = 3.0; FillFactor = 2; } diff --git a/Scripts/Items/Food/Cooking.cs b/Scripts/Items/Food/Cooking.cs index f1fc7ceed..772688811 100644 --- a/Scripts/Items/Food/Cooking.cs +++ b/Scripts/Items/Food/Cooking.cs @@ -26,6 +26,7 @@ namespace Server.Items [Constructable] public Dough() : base( 0x103d ) { + Stackable = Core.ML; Weight = 1.0; } @@ -124,6 +125,7 @@ namespace Server.Items [Constructable] public SweetDough() : base( 0x103d ) { + Stackable = Core.ML; Weight = 1.0; Hue = 150; } diff --git a/Scripts/Items/Food/Food.cs b/Scripts/Items/Food/Food.cs index 9e3b9cb2d..5c12e3b0e 100644 --- a/Scripts/Items/Food/Food.cs +++ b/Scripts/Items/Food/Food.cs @@ -688,7 +688,7 @@ namespace Server.Items [Constructable] public Cookies() : base( 0x160b ) { - Stackable = false; + Stackable = Core.ML; this.Weight = 1.0; this.FillFactor = 4; } @@ -997,7 +997,7 @@ namespace Server.Items [Constructable] public Quiche() : base( 0x1041 ) { - Stackable = false; + Stackable = Core.ML; this.Weight = 1.0; this.FillFactor = 5; } diff --git a/Scripts/Items/Misc/ArcaneGem.cs b/Scripts/Items/Misc/ArcaneGem.cs index 5a8b0bb09..58fcbd61f 100644 --- a/Scripts/Items/Misc/ArcaneGem.cs +++ b/Scripts/Items/Misc/ArcaneGem.cs @@ -16,6 +16,7 @@ namespace Server.Items [Constructable] public ArcaneGem() : base( 0x1EA7 ) { + Stackable = Core.ML; Weight = 1.0; } diff --git a/Scripts/Items/Misc/Corpses/Corpse.cs b/Scripts/Items/Misc/Corpses/Corpse.cs index 541ebe1aa..71d1c39f1 100644 --- a/Scripts/Items/Misc/Corpses/Corpse.cs +++ b/Scripts/Items/Misc/Corpses/Corpse.cs @@ -929,6 +929,16 @@ namespace Server.Items public void Carve( Mobile from, Item item ) { + if ( IsCriminalAction( from ) && this.Map != null && (this.Map.Rules & MapRules.HarmfulRestrictions) != 0 ) + { + if ( m_Owner == null || !m_Owner.Player ) + from.SendLocalizedMessage( 1005035 ); // You did not earn the right to loot this creature! + else + from.SendLocalizedMessage( 1010049 ); // You may not loot this corpse. + + return; + } + Mobile dead = m_Owner; if ( m_Carved || dead == null ) diff --git a/Scripts/Items/Misc/TribalPaint.cs b/Scripts/Items/Misc/TribalPaint.cs index 3f3275bbe..638634cbf 100644 --- a/Scripts/Items/Misc/TribalPaint.cs +++ b/Scripts/Items/Misc/TribalPaint.cs @@ -14,6 +14,7 @@ namespace Server.Items { Hue = 2101; Weight = 2.0; + Stackable = Core.ML; } public TribalPaint( Serial serial ) : base( serial ) diff --git a/Scripts/Items/Resources/Fishing/BigFish.cs b/Scripts/Items/Resources/Fishing/BigFish.cs index 6e0578f29..5ee957382 100644 --- a/Scripts/Items/Resources/Fishing/BigFish.cs +++ b/Scripts/Items/Resources/Fishing/BigFish.cs @@ -26,7 +26,7 @@ namespace Server.Items public BigFish() : base( 0x09CC ) { Weight = Utility.RandomMinMax( 3, 200 ); //TODO: Find correct formula. max on OSI currently 200, OSI dev says it's not 200 as max, and ~ 1/1,000,000 chance to get highest - Hue = 0x847; + Hue = Utility.RandomBool() ? 0x847 : 0x58C; } public override void GetProperties( ObjectPropertyList list ) diff --git a/Scripts/Items/Resources/Masonry/Granite.cs b/Scripts/Items/Resources/Masonry/Granite.cs index 8963a6465..142938ad5 100644 --- a/Scripts/Items/Resources/Masonry/Granite.cs +++ b/Scripts/Items/Resources/Masonry/Granite.cs @@ -71,6 +71,7 @@ namespace Server.Items else list.Add( CraftResources.GetName( m_Resource ) ); } + Stackable = Core.ML; } } diff --git a/Scripts/Items/Skill Items/Carpenter Items/TaxidermyKit.cs b/Scripts/Items/Skill Items/Carpenter Items/TaxidermyKit.cs index 309252fd7..e48ccc31e 100644 --- a/Scripts/Items/Skill Items/Carpenter Items/TaxidermyKit.cs +++ b/Scripts/Items/Skill Items/Carpenter Items/TaxidermyKit.cs @@ -146,6 +146,8 @@ namespace Server.Items public class TrophyAddon : Item, IAddon { + public override bool ForceShowProperties { get { return ObjectPropertyList.Enabled; } } + private int m_WestID; private int m_NorthID; private int m_DeedNumber; diff --git a/Scripts/Items/Skill Items/Magical/Potions/BasePotion.cs b/Scripts/Items/Skill Items/Magical/Potions/BasePotion.cs index b6fdf469d..d2dae6f6a 100644 --- a/Scripts/Items/Skill Items/Magical/Potions/BasePotion.cs +++ b/Scripts/Items/Skill Items/Magical/Potions/BasePotion.cs @@ -134,12 +134,20 @@ namespace Server.Items m.Animate( 34, 5, 1, true, false, 0 ); } + public static int EnhancePotions( Mobile m ) + { + int EP = AosAttributes.GetValue( m, AosAttribute.EnhancePotions ); + if ( Core.ML && EP > 50 ) + EP = 50; + return EP; + } + public static TimeSpan Scale( Mobile m, TimeSpan v ) { if ( !Core.AOS ) return v; - double scalar = 1.0 + (0.01 * AosAttributes.GetValue( m, AosAttribute.EnhancePotions )); + double scalar = 1.0 + ( 0.01 * EnhancePotions( m ) ); return TimeSpan.FromSeconds( v.TotalSeconds * scalar ); } @@ -149,7 +157,7 @@ namespace Server.Items if ( !Core.AOS ) return v; - double scalar = 1.0 + (0.01 * AosAttributes.GetValue( m, AosAttribute.EnhancePotions )); + double scalar = 1.0 + ( 0.01 * EnhancePotions( m ) ); return v * scalar; } @@ -159,7 +167,7 @@ namespace Server.Items if ( !Core.AOS ) return v; - return AOS.Scale( v, 100 + AosAttributes.GetValue( m, AosAttribute.EnhancePotions ) ); + return AOS.Scale( v, 100 + EnhancePotions( m ) ); } public override bool StackWith( Mobile from, Item dropped, bool playSound ) diff --git a/Scripts/Items/Skill Items/Magical/Runebook.cs b/Scripts/Items/Skill Items/Magical/Runebook.cs index 2849dacd3..7f24c98fb 100644 --- a/Scripts/Items/Skill Items/Magical/Runebook.cs +++ b/Scripts/Items/Skill Items/Magical/Runebook.cs @@ -276,7 +276,7 @@ namespace Server.Items public override void OnDoubleClick( Mobile from ) { - if ( from.InRange( GetWorldLocation(), 1 ) ) + if ( from.InRange( GetWorldLocation(), (Core.ML ? 3 : 1) ) ) { if ( DateTime.Now < NextUse ) { @@ -294,22 +294,22 @@ namespace Server.Items NextUse = DateTime.Now + UseDelay; } - public override void OnAfterDuped( Item newItem ) - { - Runebook book = newItem as Runebook; + public override void OnAfterDuped( Item newItem ) + { + Runebook book = newItem as Runebook; - if ( book == null ) - return; + if ( book == null ) + return; book.m_Entries = new List(); - for ( int i = 0; i < m_Entries.Count; i++ ) - { - RunebookEntry entry = m_Entries[i]; + for ( int i = 0; i < m_Entries.Count; i++ ) + { + RunebookEntry entry = m_Entries[i]; - book.m_Entries.Add( new RunebookEntry( entry.Location, entry.Map, entry.Description, entry.House ) ); - } - } + book.m_Entries.Add( new RunebookEntry( entry.Location, entry.Map, entry.Description, entry.House ) ); + } + } public bool CheckAccess( Mobile m ) { diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs b/Scripts/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs index 70a8c90fb..657aad189 100644 --- a/Scripts/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs +++ b/Scripts/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs @@ -16,6 +16,7 @@ namespace Server.Items public ArcaneCircleScroll( int amount ) : base( 600, 0x2D51, amount ) { + Hue = 0x8FD; } public ArcaneCircleScroll( Serial serial ) @@ -50,6 +51,7 @@ namespace Server.Items public GiftOfRenewalScroll( int amount ) : base( 601, 0x2D52, amount ) { + Hue = 0x8FD; } public GiftOfRenewalScroll( Serial serial ) @@ -84,6 +86,7 @@ namespace Server.Items public ImmolatingWeaponScroll( int amount ) : base( 602, 0x2D53, amount ) { + Hue = 0x8FD; } public ImmolatingWeaponScroll( Serial serial ) @@ -118,6 +121,7 @@ namespace Server.Items public AttuneWeaponScroll( int amount ) : base( 603, 0x2D54, amount ) { + Hue = 0x8FD; } public AttuneWeaponScroll( Serial serial ) @@ -152,6 +156,7 @@ namespace Server.Items public ThunderstormScroll( int amount ) : base( 604, 0x2D55, amount ) { + Hue = 0x8FD; } public ThunderstormScroll( Serial serial ) @@ -186,6 +191,7 @@ namespace Server.Items public NatureFuryScroll( int amount ) : base( 605, 0x2D56, amount ) { + Hue = 0x8FD; } public NatureFuryScroll( Serial serial ) @@ -220,6 +226,7 @@ namespace Server.Items public SummonFeyScroll( int amount ) : base( 606, 0x2D57, amount ) { + Hue = 0x8FD; } public SummonFeyScroll( Serial serial ) @@ -254,6 +261,7 @@ namespace Server.Items public SummonFiendScroll( int amount ) : base( 607, 0x2D58, amount ) { + Hue = 0x8FD; } public SummonFiendScroll( Serial serial ) @@ -288,6 +296,7 @@ namespace Server.Items public ReaperFormScroll( int amount ) : base( 608, 0x2D59, amount ) { + Hue = 0x8FD; } public ReaperFormScroll( Serial serial ) @@ -322,6 +331,7 @@ namespace Server.Items public WildfireScroll( int amount ) : base( 609, 0x2D5A, amount ) { + Hue = 0x8FD; } public WildfireScroll( Serial serial ) @@ -356,6 +366,7 @@ namespace Server.Items public EssenceOfWindScroll( int amount ) : base( 610, 0x2D5B, amount ) { + Hue = 0x8FD; } public EssenceOfWindScroll( Serial serial ) @@ -390,6 +401,7 @@ namespace Server.Items public DryadAllureScroll( int amount ) : base( 611, 0x2D5C, amount ) { + Hue = 0x8FD; } public DryadAllureScroll( Serial serial ) @@ -424,6 +436,7 @@ namespace Server.Items public EtherealVoyageScroll( int amount ) : base( 612, 0x2D5D, amount ) { + Hue = 0x8FD; } public EtherealVoyageScroll( Serial serial ) @@ -458,6 +471,7 @@ namespace Server.Items public WordOfDeathScroll( int amount ) : base( 613, 0x2D5E, amount ) { + Hue = 0x8FD; } public WordOfDeathScroll( Serial serial ) @@ -492,6 +506,7 @@ namespace Server.Items public GiftOfLifeScroll( int amount ) : base( 614, 0x2D5F, amount ) { + Hue = 0x8FD; } public GiftOfLifeScroll( Serial serial ) @@ -526,6 +541,7 @@ namespace Server.Items public ArcaneEmpowermentScroll( int amount ) : base( 615, 0x2D60, amount ) { + Hue = 0x8FD; } public ArcaneEmpowermentScroll( Serial serial ) diff --git a/Scripts/Items/Skill Items/Ninjitsu/EggBomb.cs b/Scripts/Items/Skill Items/Ninjitsu/EggBomb.cs index 9a33d39cd..051c5e781 100644 --- a/Scripts/Items/Skill Items/Ninjitsu/EggBomb.cs +++ b/Scripts/Items/Skill Items/Ninjitsu/EggBomb.cs @@ -8,6 +8,7 @@ namespace Server.Items [Constructable] public EggBomb() : base( 0x2809 ) { + Stackable = Core.ML; Weight = 1.0; } diff --git a/Scripts/Items/Skill Items/Ninjitsu/SmokeBomb.cs b/Scripts/Items/Skill Items/Ninjitsu/SmokeBomb.cs index 582359abc..ca44a25fa 100644 --- a/Scripts/Items/Skill Items/Ninjitsu/SmokeBomb.cs +++ b/Scripts/Items/Skill Items/Ninjitsu/SmokeBomb.cs @@ -8,6 +8,7 @@ namespace Server.Items [Constructable] public SmokeBomb() : base( 0x2808 ) { + Stackable = Core.ML; Weight = 1.0; } diff --git a/Scripts/Items/Skill Items/Specialized/Sand.cs b/Scripts/Items/Skill Items/Specialized/Sand.cs index 4d95fab53..f0493ef30 100644 --- a/Scripts/Items/Skill Items/Specialized/Sand.cs +++ b/Scripts/Items/Skill Items/Specialized/Sand.cs @@ -26,7 +26,7 @@ namespace Server.Items [Constructable] public Sand( int amount ) : base( 0x11EA ) { - Stackable = false; + Stackable = Core.ML; Weight = 1.0; } diff --git a/Scripts/Items/Skill Items/Tools/BaseRunicTool.cs b/Scripts/Items/Skill Items/Tools/BaseRunicTool.cs index 21f1d46aa..755ab714c 100644 --- a/Scripts/Items/Skill Items/Tools/BaseRunicTool.cs +++ b/Scripts/Items/Skill Items/Tools/BaseRunicTool.cs @@ -492,7 +492,13 @@ namespace Server.Items /* Begin Sheilds */ case 0: ApplyAttribute( primary, min, max, AosAttribute.SpellChanneling, 1, 1 ); break; case 1: ApplyAttribute( primary, min, max, AosAttribute.DefendChance, 1, 15 ); break; - case 2: ApplyAttribute( primary, min, max, AosAttribute.AttackChance, 1, 15 ); break; + case 2: + if (Core.ML) { + ApplyAttribute( primary, min, max, AosAttribute.ReflectPhysical, 1, 15 ); + } else { + ApplyAttribute( primary, min, max, AosAttribute.AttackChance, 1, 15 ); + } + break; case 3: ApplyAttribute( primary, min, max, AosAttribute.CastSpeed, 1, 1 ); break; /* Begin Armor */ case 4: ApplyAttribute( secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10 ); break; diff --git a/Scripts/Items/Special/Holiday/Christmas/HolidayTree.cs b/Scripts/Items/Special/Holiday/Christmas/HolidayTree.cs index ba7bbf906..8d6f850a0 100644 --- a/Scripts/Items/Special/Holiday/Christmas/HolidayTree.cs +++ b/Scripts/Items/Special/Holiday/Christmas/HolidayTree.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using Server.Network; using Server.Items; +using Server.Multis; namespace Server.Items { @@ -11,7 +12,7 @@ namespace Server.Items Modern } - public class HolidayTree : Item + public class HolidayTree : Item, IAddon { private ArrayList m_Components; private Mobile m_Placer; @@ -208,6 +209,16 @@ namespace Server.Items { } + public bool CouldFit( IPoint3D p, Map map ) + { + return map.CanFit( (Point3D)p, 20 ); + } + + Item IAddon.Deed + { + get{ return new HolidayTreeDeed(); } + } + public override void Serialize( GenericWriter writer ) { base.Serialize( writer ); @@ -253,8 +264,22 @@ namespace Server.Items break; } } + ValidatePlacement(); } + public void ValidatePlacement() + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house == null ) + { + HolidayTreeDeed deed = new HolidayTreeDeed(); + deed.MoveToWorld( Location, Map ); + Delete(); + } + } + + public override void OnDoubleClick( Mobile from ) { if ( from.InRange( this.GetWorldLocation(), 1 ) ) @@ -265,6 +290,13 @@ namespace Server.Items this.Delete(); + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.Addons.Contains( this ) ) + { + house.Addons.Remove( this ); + } + from.SendLocalizedMessage( 503393 ); // A deed for the tree has been placed in your backpack. } else diff --git a/Scripts/Items/Special/Solen Items/BallOfSummoning.cs b/Scripts/Items/Special/Solen Items/BallOfSummoning.cs index 2f08d187c..ca9a8e447 100644 --- a/Scripts/Items/Special/Solen Items/BallOfSummoning.cs +++ b/Scripts/Items/Special/Solen Items/BallOfSummoning.cs @@ -7,6 +7,8 @@ using Server.Targeting; using Server.ContextMenus; using Server.Network; using Server.Regions; +using Server.Spells; +using Server.Spells.Ninjitsu; namespace Server.Items { @@ -144,20 +146,27 @@ namespace Server.Items public override void OnDoubleClick( Mobile from ) { - if ( this.RootParent == from ) // TODO: Previous implementation allowed use on ground, without house protection checks. What is the correct behavior? + if ( this.RootParent != from ) // TODO: Previous implementation allowed use on ground, without house protection checks. What is the correct behavior? { - if ( Pet == null ) - { - LinkPet( from ); - } - else - { - SummonPet( from ); - } + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1042001 ); // That must be in your pack for you to use it. + return; + } + + AnimalFormContext animalContext = AnimalForm.GetContext( from ); + + if( Core.ML && animalContext != null ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1080073 ); // You cannot use a Crystal Ball of Pet Summoning while in animal form. + return; + } + + if ( Pet == null ) + { + LinkPet( from ); } else { - from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1042001 ); // That must be in your pack for you to use it. + CastSummonPet( from ); } } @@ -220,7 +229,7 @@ namespace Server.Items } } - public void SummonPet( Mobile from ) + public void CastSummonPet( Mobile from ) { BaseCreature pet = this.Pet; @@ -251,27 +260,48 @@ namespace Server.Items { from.Send( new AsciiMessage( this.Serial, this.ItemID, MessageType.Regular, 0x22, 3, "", "You cannot summon your pet to this location." ) ); } + else if ( Core.ML && from is PlayerMobile && DateTime.Now < ((PlayerMobile)from).LastPetBallTime.AddSeconds( 15.0 ) ) + { + MessageHelper.SendLocalizedMessageTo( this, from, 1080072, 0x22 ); // You must wait a few seconds before you can summon your pet. + } else { - Charges--; + if( Core.ML ) + new PetSummoningSpell( this, from ).Cast(); + else + SummonPet( from ); + } - if ( pet.IsStabled ) - { - pet.SetControlMaster( from ); + } - if ( pet.Summoned ) - pet.SummonMaster = from; + + public void SummonPet( Mobile from ) + { + BaseCreature pet = this.Pet; - pet.ControlTarget = from; - pet.ControlOrder = OrderType.Follow; + Charges--; - pet.IsStabled = false; - from.Stabled.Remove( pet ); - } + if ( pet.IsStabled ) + { + pet.SetControlMaster( from ); - pet.MoveToWorld( from.Location, from.Map ); + if ( pet.Summoned ) + pet.SummonMaster = from; - MessageHelper.SendLocalizedMessageTo( this, from, 1054128, 0x43 ); // The Crystal Ball fills with a green mist. Your pet has been summoned. + pet.ControlTarget = from; + pet.ControlOrder = OrderType.Follow; + + pet.IsStabled = false; + from.Stabled.Remove( pet ); + } + + pet.MoveToWorld( from.Location, from.Map ); + + MessageHelper.SendLocalizedMessageTo( this, from, 1054128, 0x43 ); // The Crystal Ball fills with a green mist. Your pet has been summoned. + + if ( from is PlayerMobile ) + { + ((PlayerMobile)from).LastPetBallTime = DateTime.Now; } } @@ -341,5 +371,94 @@ namespace Server.Items } } } + + private class PetSummoningSpell : Spell + { + private static SpellInfo m_Info = new SpellInfo( "Ball Of Summoning", "", 230 ); + + private BallOfSummoning m_Ball; + private Mobile m_Caster; + + public PetSummoningSpell( BallOfSummoning ball, Mobile caster ) + : base( caster, null, m_Info ) + { + m_Caster = caster; + m_Ball = ball; + } + + public override bool ClearHandsOnCast { get { return false; } } + public override bool RevealOnCast { get { return true; } } + + public override TimeSpan GetCastRecovery() + { + return TimeSpan.Zero; + } + + public override double CastDelayFastScalar { get { return 0; } } + + public override TimeSpan CastDelayBase + { + get + { + return TimeSpan.FromSeconds( 2.0 ); + } + } + + public override int GetMana() + { + return 0; + } + + public override bool ConsumeReagents() + { + return true; + } + + public override bool CheckFizzle() + { + return true; + } + + private bool m_Stop; + + public void Stop() + { + m_Stop = true; + Disturb( DisturbType.Hurt, false, false ); + } + + public override bool CheckDisturb( DisturbType type, bool checkFirst, bool resistable ) + { + if( type == DisturbType.EquipRequest || type == DisturbType.UseRequest/* || type == DisturbType.Hurt*/ ) + return false; + + return true; + } + + public override void DoHurtFizzle() + { + if( !m_Stop ) + base.DoHurtFizzle(); + } + + public override void DoFizzle() + { + if( !m_Stop ) + base.DoFizzle(); + } + + public override void OnDisturb( DisturbType type, bool message ) + { + if( message && !m_Stop ) + Caster.SendLocalizedMessage( 1080074 ); // You have been disrupted while attempting to summon your pet! + } + + public override void OnCast() + { + m_Ball.SummonPet( m_Caster ); + + FinishSequence(); + } + } } } diff --git a/Scripts/Items/Wands/BaseWand.cs b/Scripts/Items/Wands/BaseWand.cs index 7a50fc18b..694db2b7f 100644 --- a/Scripts/Items/Wands/BaseWand.cs +++ b/Scripts/Items/Wands/BaseWand.cs @@ -24,6 +24,22 @@ namespace Server.Items public abstract class BaseWand : BaseBashing { + public override WeaponAbility PrimaryAbility { get { return WeaponAbility.Dismount; } } + public override WeaponAbility SecondaryAbility { get { return WeaponAbility.Disarm; } } + + public override int AosStrengthReq { get { return 5; } } + public override int AosMinDamage { get { return 9; } } + public override int AosMaxDamage { get { return 11; } } + public override int AosSpeed { get { return 40; } } + + public override int OldStrengthReq { get { return 0; } } + public override int OldMinDamage { get { return 2; } } + public override int OldMaxDamage { get { return 6; } } + public override int OldSpeed { get { return 35; } } + + public override int InitMinHits { get { return 31; } } + public override int InitMaxHits { get { return 110; } } + private WandEffect m_WandEffect; private int m_Charges; diff --git a/Scripts/Items/Weapons/Abilities/Disarm.cs b/Scripts/Items/Weapons/Abilities/Disarm.cs index 220816167..44554af55 100644 --- a/Scripts/Items/Weapons/Abilities/Disarm.cs +++ b/Scripts/Items/Weapons/Abilities/Disarm.cs @@ -33,6 +33,16 @@ namespace Server.Items return false; }*/ + public override bool RequiresTactics( Mobile from ) + { + BaseWeapon weapon = from.Weapon as BaseWeapon; + + if ( weapon == null ) + return false; + + return weapon.Skill != SkillName.Wrestling; + } + public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds( 5.0 ); public override void OnHit( Mobile attacker, Mobile defender, int damage ) @@ -53,7 +63,7 @@ namespace Server.Items { attacker.SendLocalizedMessage( 1004001 ); // You cannot disarm your opponent. } - else if ( toDisarm == null || toDisarm is BaseShield || toDisarm is Spellbook ) + else if (toDisarm == null || toDisarm is BaseShield || toDisarm is Spellbook && !Core.ML ) { attacker.SendLocalizedMessage( 1060849 ); // Your target is already unarmed! } diff --git a/Scripts/Items/Weapons/Abilities/Dismount.cs b/Scripts/Items/Weapons/Abilities/Dismount.cs index d3e8d81c3..e20a47d95 100644 --- a/Scripts/Items/Weapons/Abilities/Dismount.cs +++ b/Scripts/Items/Weapons/Abilities/Dismount.cs @@ -58,6 +58,11 @@ namespace Server.Items if ( !CheckMana( attacker, true ) ) return; + if ( Core.ML && attacker is LesserHiryu && 0.8 >= Utility.RandomDouble() ) + { + return; //Lesser Hiryu have an 80% chance of missing this attack + } + attacker.SendLocalizedMessage( 1060082 ); // The force of your attack has dislodged them from their mount! if ( attacker.Mounted ) @@ -71,8 +76,15 @@ namespace Server.Items mount.Rider = null; BaseMount.SetMountPrevention( defender, BlockMountType.Dazed, DefenderRemountDelay ); - BaseMount.SetMountPrevention( attacker, BlockMountType.DismountRecovery, AttackerRemountDelay ); - + if( Core.ML && attacker is BaseCreature && ((BaseCreature)attacker).ControlMaster != null ) + { + BaseMount.SetMountPrevention( ((BaseCreature)attacker).ControlMaster, BlockMountType.DismountRecovery, AttackerRemountDelay ); + } + else + { + BaseMount.SetMountPrevention( attacker, BlockMountType.DismountRecovery, AttackerRemountDelay ); + } + if ( !attacker.Mounted ) AOS.Damage( defender, attacker, Utility.RandomMinMax( 15, 25 ), 100, 0, 0, 0, 0 ); } diff --git a/Scripts/Items/Weapons/Abilities/InfectiousStrike.cs b/Scripts/Items/Weapons/Abilities/InfectiousStrike.cs index 40e879f2a..e705f89b8 100644 --- a/Scripts/Items/Weapons/Abilities/InfectiousStrike.cs +++ b/Scripts/Items/Weapons/Abilities/InfectiousStrike.cs @@ -20,6 +20,11 @@ namespace Server.Items public override int BaseMana{ get{ return 15; } } + public override bool RequiresTactics( Mobile from ) + { + return false; + } + public override void OnHit( Mobile attacker, Mobile defender, int damage ) { if ( !Validate( attacker ) ) diff --git a/Scripts/Items/Weapons/Abilities/MovingShot.cs b/Scripts/Items/Weapons/Abilities/MovingShot.cs index 0f736f101..b64d7de6e 100644 --- a/Scripts/Items/Weapons/Abilities/MovingShot.cs +++ b/Scripts/Items/Weapons/Abilities/MovingShot.cs @@ -13,7 +13,7 @@ namespace Server.Items } public override int BaseMana{ get{ return 15; } } - public override double AccuracyScalar{ get{ return 0.75; } } + public override int AccuracyBonus{ get{ return -25; } } public override bool OnBeforeSwing( Mobile attacker, Mobile defender ) { diff --git a/Scripts/Items/Weapons/Abilities/ParalyzingBlow.cs b/Scripts/Items/Weapons/Abilities/ParalyzingBlow.cs index e8740762c..c29584ab4 100644 --- a/Scripts/Items/Weapons/Abilities/ParalyzingBlow.cs +++ b/Scripts/Items/Weapons/Abilities/ParalyzingBlow.cs @@ -38,6 +38,16 @@ namespace Server.Items return false; }*/ + public override bool RequiresTactics( Mobile from ) + { + BaseWeapon weapon = from.Weapon as BaseWeapon; + + if ( weapon == null ) + return true; + + return weapon.Skill != SkillName.Wrestling; + } + public override bool OnBeforeSwing( Mobile attacker, Mobile defender ) { if( defender.Paralyzed ) diff --git a/Scripts/Items/Weapons/Abilities/ShadowStrike.cs b/Scripts/Items/Weapons/Abilities/ShadowStrike.cs index a4236b000..2c64521bf 100644 --- a/Scripts/Items/Weapons/Abilities/ShadowStrike.cs +++ b/Scripts/Items/Weapons/Abilities/ShadowStrike.cs @@ -16,6 +16,11 @@ namespace Server.Items public override int BaseMana{ get{ return 20; } } public override double DamageScalar{ get{ return 1.25; } } + public override bool RequiresTactics( Mobile from ) + { + return false; + } + public override bool CheckSkills( Mobile from ) { if ( !base.CheckSkills( from ) ) diff --git a/Scripts/Items/Weapons/Abilities/WeaponAbility.cs b/Scripts/Items/Weapons/Abilities/WeaponAbility.cs index addf9086d..5c19b6fdf 100644 --- a/Scripts/Items/Weapons/Abilities/WeaponAbility.cs +++ b/Scripts/Items/Weapons/Abilities/WeaponAbility.cs @@ -11,7 +11,7 @@ namespace Server.Items { public virtual int BaseMana{ get{ return 0; } } - public virtual double AccuracyScalar{ get{ return 1.0; } } + public virtual int AccuracyBonus{ get{ return 0; } } public virtual double DamageScalar{ get{ return 1.0; } } public virtual bool RequiresSE { get { return false; } } @@ -35,6 +35,11 @@ namespace Server.Items return true; } + public virtual bool RequiresTactics( Mobile from ) + { + return true; + } + public virtual double GetRequiredSkill( Mobile from ) { BaseWeapon weapon = from.Weapon as BaseWeapon; @@ -87,6 +92,13 @@ namespace Server.Items Skill skill = from.Skills[weapon.Skill]; double reqSkill = GetRequiredSkill( from ); + bool reqTactics = Core.ML && RequiresTactics( from ); + + if ( Core.ML && reqTactics && from.Skills[SkillName.Tactics].Base < reqSkill ) + { + from.SendLocalizedMessage( 1079308, reqSkill.ToString() ); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack + return false; + } if ( skill != null && skill.Base >= reqSkill ) return true; @@ -96,7 +108,14 @@ namespace Server.Items return true; /* */ - from.SendLocalizedMessage( 1060182, reqSkill.ToString() ); // You need ~1_SKILL_REQUIREMENT~ weapon skill to perform that attack + if ( reqTactics ) + { + from.SendLocalizedMessage( 1079308, reqSkill.ToString() ); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack + } + else + { + from.SendLocalizedMessage( 1060182, reqSkill.ToString() ); // You need ~1_SKILL_REQUIREMENT~ weapon skill to perform that attack + } return false; } @@ -160,6 +179,11 @@ namespace Server.Items from.SendLocalizedMessage( 1063024 ); // You cannot perform this special move right now. return false; } + if ( Core.ML && from.Spell != null ) + { + from.SendLocalizedMessage( 1063024 ); // You cannot perform this special move right now. + return false; + } return CheckSkills( from ) && CheckMana( from, false ); } diff --git a/Scripts/Items/Weapons/BaseWeapon.cs b/Scripts/Items/Weapons/BaseWeapon.cs index 56bf97c21..21a802ca2 100644 --- a/Scripts/Items/Weapons/BaseWeapon.cs +++ b/Scripts/Items/Weapons/BaseWeapon.cs @@ -750,9 +750,6 @@ namespace Server.Items double atkValue = atkWeapon.GetAttackSkillValue( attacker, defender ); double defValue = defWeapon.GetDefendSkillValue( attacker, defender ); - //attacker.CheckSkill( atkSkill.SkillName, defValue - 20.0, 120.0 ); - //defender.CheckSkill( defSkill.SkillName, atkValue - 20.0, 120.0 ); - double ourValue, theirValue; int bonus = GetHitChanceBonus(); @@ -765,12 +762,7 @@ namespace Server.Items if ( defValue <= -20.0 ) defValue = -19.9; - // Hit Chance Increase = 45% - int atkChance = AosAttributes.GetValue( attacker, AosAttribute.AttackChance ); - if ( atkChance > 45 ) - atkChance = 45; - - bonus += atkChance; + bonus += AosAttributes.GetValue( attacker, AosAttribute.AttackChance ); if ( Spells.Chivalry.DivineFurySpell.UnderEffect( attacker ) ) bonus += 10; // attacker gets 10% bonus when they're under divine fury @@ -781,13 +773,24 @@ namespace Server.Items if ( HitLower.IsUnderAttackEffect( attacker ) ) bonus -= 25; // Under Hit Lower Attack effect -> 25% malus - ourValue = (atkValue + 20.0) * (100 + bonus); + WeaponAbility ability = WeaponAbility.GetCurrentAbility( attacker ); - // Defense Chance Increase = 45% - bonus = AosAttributes.GetValue( defender, AosAttribute.DefendChance ); + if ( ability != null ) + bonus += ability.AccuracyBonus; + + SpecialMove move = SpecialMove.GetCurrentMove( attacker ); + + if ( move != null ) + bonus += move.GetAccuracyBonus( attacker ); + + // Max Hit Chance Increase = 45% if ( bonus > 45 ) bonus = 45; + ourValue = (atkValue + 20.0) * (100 + bonus); + + bonus = AosAttributes.GetValue( defender, AosAttribute.DefendChance ); + if ( Spells.Chivalry.DivineFurySpell.UnderEffect( defender ) ) bonus -= 20; // defender loses 20% bonus when they're under divine fury @@ -810,6 +813,10 @@ namespace Server.Items if ( SkillHandlers.Discordance.GetEffect( attacker, ref discordanceEffect ) ) bonus -= discordanceEffect; + // Defense Chance Increase = 45% + if ( bonus > 45 ) + bonus = 45; + theirValue = (defValue + 20.0) * (100 + bonus); bonus = 0; @@ -833,19 +840,7 @@ namespace Server.Items if ( Core.AOS && chance < 0.02 ) chance = 0.02; - WeaponAbility ability = WeaponAbility.GetCurrentAbility( attacker ); - - if ( ability != null ) - chance *= ability.AccuracyScalar; - - SpecialMove move = SpecialMove.GetCurrentMove( attacker ); - - if ( move != null ) - chance *= move.GetAccuracyScalar( attacker ); - return attacker.CheckSkill( atkSkill.SkillName, chance ); - - //return ( chance >= Utility.RandomDouble() ); } public virtual TimeSpan GetDelay( Mobile m ) diff --git a/Scripts/Items/Weapons/Maces/MagicWand.cs b/Scripts/Items/Weapons/Maces/MagicWand.cs index c3dc66748..42d75b980 100644 --- a/Scripts/Items/Weapons/Maces/MagicWand.cs +++ b/Scripts/Items/Weapons/Maces/MagicWand.cs @@ -6,6 +6,9 @@ namespace Server.Items { public class MagicWand : BaseBashing { + public override WeaponAbility PrimaryAbility { get { return WeaponAbility.Dismount; } } + public override WeaponAbility SecondaryAbility { get { return WeaponAbility.Disarm; } } + public override int AosStrengthReq{ get{ return 5; } } public override int AosMinDamage{ get{ return 9; } } public override int AosMaxDamage{ get{ return 11; } } diff --git a/Scripts/Misc/AOS.cs b/Scripts/Misc/AOS.cs index 83484a009..a3e5bd2dd 100644 --- a/Scripts/Misc/AOS.cs +++ b/Scripts/Misc/AOS.cs @@ -100,7 +100,7 @@ namespace Server } #region Dragon Barding - if( (!Core.AOS || from == null || !from.Player) && m.Player && m.Mount is SwampDragon ) + if( (from == null || !from.Player) && m.Player && m.Mount is SwampDragon ) { SwampDragon pet = m.Mount as SwampDragon; diff --git a/Scripts/Misc/Notoriety.cs b/Scripts/Misc/Notoriety.cs index 2697ce746..12e43f6c1 100644 --- a/Scripts/Misc/Notoriety.cs +++ b/Scripts/Misc/Notoriety.cs @@ -281,6 +281,16 @@ namespace Server.Misc if ( master != null && master.AccessLevel > AccessLevel.Player ) return Notoriety.CanBeAttacked; + master = bc.ControlMaster; + + if ( Core.ML && master != null ) + { + if( source == master && CheckAggressor( target.Aggressors, source ) ) + return Notoriety.CanBeAttacked; + else + return MobileNotoriety( source, master ); + } + if( !bc.Summoned && !bc.Controlled && ((PlayerMobile)source).EnemyOfOneType == target.GetType() ) return Notoriety.Enemy; } diff --git a/Scripts/Misc/RegenRates.cs b/Scripts/Misc/RegenRates.cs index 26025b7d6..637d3114f 100644 --- a/Scripts/Misc/RegenRates.cs +++ b/Scripts/Misc/RegenRates.cs @@ -129,7 +129,7 @@ namespace Server.Misc CheckBonusSkill( from, from.Mana, from.ManaMax, SkillName.Focus ); - double focusPoints = (int)(from.Skills[SkillName.Focus].Value * 0.05); + double focusPoints = (from.Skills[SkillName.Focus].Value * 0.05); if ( armorPenalty > 0 ) medPoints = 0; // In AOS, wearing any meditation-blocking armor completely removes meditation bonus @@ -154,7 +154,10 @@ namespace Server.Misc if ( totalPoints < -1 ) totalPoints = -1; - rate = 1.0 / (0.1 * (2 + (int)totalPoints)); + if ( Core.ML ) + totalPoints = Math.Floor( totalPoints ); + + rate = 1.0 / (0.1 * (2 + totalPoints)); } else { diff --git a/Scripts/Mobiles/Animals/Mounts/Hiryu.cs b/Scripts/Mobiles/Animals/Mounts/Hiryu.cs index a84ea3ae4..6f9af3798 100644 --- a/Scripts/Mobiles/Animals/Mounts/Hiryu.cs +++ b/Scripts/Mobiles/Animals/Mounts/Hiryu.cs @@ -235,7 +235,7 @@ namespace Server.Mobiles Timer.DelayCall( TimeSpan.Zero, delegate { Hue = GetHue(); } ); if( version <= 1 ) - Timer.DelayCall( TimeSpan.Zero, delegate { InternalItem.Hue = this.Hue; } ); + Timer.DelayCall( TimeSpan.Zero, delegate { if( InternalItem != null ) { InternalItem.Hue = this.Hue; } } ); } } } diff --git a/Scripts/Mobiles/Animals/Mounts/LesserHiryu.cs b/Scripts/Mobiles/Animals/Mounts/LesserHiryu.cs index 4c3be4f16..7a521ee31 100644 --- a/Scripts/Mobiles/Animals/Mounts/LesserHiryu.cs +++ b/Scripts/Mobiles/Animals/Mounts/LesserHiryu.cs @@ -118,12 +118,26 @@ namespace Server.Mobiles public override double GetControlChance( Mobile m, bool useBaseSkill ) { + double tamingChance = base.GetControlChance( m, useBaseSkill ); + + if( tamingChance >= 0.95 ) + { + return tamingChance; + } + double skill = (useBaseSkill? m.Skills.Bushido.Base : m.Skills.Bushido.Value); - if( skill >= 90.0 ) - return 1.0; + if( skill < 90.0 ) + { + return tamingChance; + } - return base.GetControlChance( m, useBaseSkill ); + double bushidoChance = ( skill - 30.0 ) / 100; + + if( m.Skills.Bushido.Base >= 120 ) + bushidoChance += 0.05; + + return bushidoChance > tamingChance ? bushidoChance : tamingChance; } public override int TreasureMapLevel { get { return 3; } } @@ -217,7 +231,7 @@ namespace Server.Mobiles Timer.DelayCall( TimeSpan.Zero, delegate { Hue = GetHue(); } ); if( version <= 1 ) - Timer.DelayCall( TimeSpan.Zero, delegate { InternalItem.Hue = this.Hue; } ); + Timer.DelayCall( TimeSpan.Zero, delegate { if( InternalItem != null ) { InternalItem.Hue = this.Hue; } } ); } } } diff --git a/Scripts/Mobiles/Familiars/HordeMinion.cs b/Scripts/Mobiles/Familiars/HordeMinion.cs index a5c4d9610..6effd3f59 100644 --- a/Scripts/Mobiles/Familiars/HordeMinion.cs +++ b/Scripts/Mobiles/Familiars/HordeMinion.cs @@ -45,7 +45,7 @@ namespace Server.Mobiles if ( pack != null ) pack.Delete(); - pack = new StrongBackpack(); + pack = new Backpack(); pack.Movable = false; AddItem( pack ); diff --git a/Scripts/Mobiles/Monsters/AOS/AbysmalHorror.cs b/Scripts/Mobiles/Monsters/AOS/AbysmalHorror.cs index 2fa68ccbd..dd73d81b9 100644 --- a/Scripts/Mobiles/Monsters/AOS/AbysmalHorror.cs +++ b/Scripts/Mobiles/Monsters/AOS/AbysmalHorror.cs @@ -66,7 +66,7 @@ namespace Server.Mobiles public override bool BardImmune{ get{ return !Core.SE; } } public override bool Unprovokable{ get{ return Core.SE; } } - public override bool Uncalmable{ get{ return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } public override Poison PoisonImmune{ get{ return Poison.Lethal; } } public override int TreasureMapLevel{ get{ return 1; } } diff --git a/Scripts/Mobiles/Monsters/AOS/BoneDemon.cs b/Scripts/Mobiles/Monsters/AOS/BoneDemon.cs index 09e16959e..ce2a88f2a 100644 --- a/Scripts/Mobiles/Monsters/AOS/BoneDemon.cs +++ b/Scripts/Mobiles/Monsters/AOS/BoneDemon.cs @@ -50,8 +50,9 @@ namespace Server.Mobiles AddLoot( LootPack.FilthyRich, 8 ); } - public override bool Unprovokable{ get{ return true; } } - public override bool Uncalmable{ get{ return true; } } + public override bool BardImmune { get { return !Core.SE; } } + public override bool Unprovokable { get { return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } public override Poison PoisonImmune{ get{ return Poison.Lethal; } } public override int TreasureMapLevel{ get{ return 1; } } diff --git a/Scripts/Mobiles/Monsters/AOS/DarknightCreeper.cs b/Scripts/Mobiles/Monsters/AOS/DarknightCreeper.cs index 8bc64bc81..5c70f19c7 100644 --- a/Scripts/Mobiles/Monsters/AOS/DarknightCreeper.cs +++ b/Scripts/Mobiles/Monsters/AOS/DarknightCreeper.cs @@ -63,7 +63,7 @@ namespace Server.Mobiles public override bool BardImmune{ get{ return !Core.SE; } } public override bool Unprovokable{ get{ return Core.SE; } } - public override bool Uncalmable{ get{ return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } public override bool BleedImmune{ get{ return true; } } public override Poison PoisonImmune{ get{ return Poison.Lethal; } } public override Poison HitPoison{ get{ return Poison.Lethal; } } diff --git a/Scripts/Mobiles/Monsters/AOS/DemonKnight.cs b/Scripts/Mobiles/Monsters/AOS/DemonKnight.cs index 9b334b313..9ab57c6fd 100644 --- a/Scripts/Mobiles/Monsters/AOS/DemonKnight.cs +++ b/Scripts/Mobiles/Monsters/AOS/DemonKnight.cs @@ -213,7 +213,7 @@ namespace Server.Mobiles public override bool BardImmune{ get{ return !Core.SE; } } public override bool Unprovokable{ get{ return Core.SE; } } - public override bool Uncalmable{ get{ return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } public override Poison PoisonImmune{ get{ return Poison.Lethal; } } public override int TreasureMapLevel{ get{ return 1; } } diff --git a/Scripts/Mobiles/Monsters/AOS/FleshRenderer.cs b/Scripts/Mobiles/Monsters/AOS/FleshRenderer.cs index 86d7b6764..eb6d2c54a 100644 --- a/Scripts/Mobiles/Monsters/AOS/FleshRenderer.cs +++ b/Scripts/Mobiles/Monsters/AOS/FleshRenderer.cs @@ -63,8 +63,9 @@ namespace Server.Mobiles } public override bool AutoDispel{ get{ return true; } } - public override bool Unprovokable{ get{ return true; } } - public override bool Uncalmable{ get{ return true; } } + public override bool BardImmune { get { return !Core.SE; } } + public override bool Unprovokable { get { return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } public override Poison PoisonImmune{ get{ return Poison.Lethal; } } public override int TreasureMapLevel{ get{ return 1; } } diff --git a/Scripts/Mobiles/Monsters/AOS/Impaler.cs b/Scripts/Mobiles/Monsters/AOS/Impaler.cs index 5796a12f8..85f6733f3 100644 --- a/Scripts/Mobiles/Monsters/AOS/Impaler.cs +++ b/Scripts/Mobiles/Monsters/AOS/Impaler.cs @@ -66,7 +66,7 @@ namespace Server.Mobiles public override bool AutoDispel{ get{ return true; } } public override bool BardImmune{ get{ return !Core.SE; } } public override bool Unprovokable{ get{ return Core.SE; } } - public override bool Uncalmable{ get{ return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } public override Poison PoisonImmune{ get{ return Poison.Lethal; } } public override Poison HitPoison{ get{ return (0.8 >= Utility.RandomDouble() ? Poison.Greater : Poison.Deadly); } } diff --git a/Scripts/Mobiles/Monsters/AOS/ShadowKnight.cs b/Scripts/Mobiles/Monsters/AOS/ShadowKnight.cs index a7273a20f..f685573af 100644 --- a/Scripts/Mobiles/Monsters/AOS/ShadowKnight.cs +++ b/Scripts/Mobiles/Monsters/AOS/ShadowKnight.cs @@ -167,7 +167,9 @@ namespace Server.Mobiles base.OnThink(); } - public override bool BardImmune{ get{ return true; } } + public override bool BardImmune{ get{ return !Core.SE; } } + public override bool Unprovokable{ get{ return Core.SE; } } + public override bool AreaPeaceImmune{ get{ return Core.SE; } } public override Poison PoisonImmune{ get{ return Poison.Lethal; } } public override int TreasureMapLevel{ get{ return 1; } } diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/Golem.cs b/Scripts/Mobiles/Monsters/Misc/Melee/Golem.cs index 3dc9b2860..85ea63031 100644 --- a/Scripts/Mobiles/Monsters/Misc/Melee/Golem.cs +++ b/Scripts/Mobiles/Monsters/Misc/Melee/Golem.cs @@ -14,6 +14,8 @@ namespace Server.Mobiles public override bool IsBondable{ get{ return false; } } + public override FoodType FavoriteFood { get { return FoodType.None; } } + [Constructable] public Golem() : this( false, 1.0 ) { @@ -81,7 +83,7 @@ namespace Server.Mobiles PackItem( new Gears() ); } - ControlSlots = 4; + ControlSlots = 3; } public override bool DeleteOnRelease{ get{ return true; } } diff --git a/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs b/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs index ab4fe35f1..68a0819c4 100644 --- a/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs +++ b/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs @@ -131,20 +131,40 @@ namespace Server.Mobiles List mods = new List(); - if ( defender.PhysicalResistance > 0 ) - mods.Add( new ResistanceMod( ResistanceType.Physical, (defender.PhysicalResistance > 70) ? -70 : -defender.PhysicalResistance ) ); + if ( Core.ML ) + { + if ( defender.PhysicalResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Physical, defender.PhysicalResistance / 2 ) ); - if ( defender.FireResistance > 0 ) - mods.Add( new ResistanceMod( ResistanceType.Fire, (defender.FireResistance > 70) ? -70 : -defender.FireResistance ) ); + if ( defender.FireResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Fire, defender.FireResistance / 2 ) ); - if ( defender.ColdResistance > 0 ) - mods.Add( new ResistanceMod( ResistanceType.Cold, (defender.ColdResistance > 70) ? -70 : -defender.ColdResistance ) ); + if ( defender.ColdResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Cold, defender.ColdResistance / 2 ) ); - if ( defender.PoisonResistance > 0 ) - mods.Add( new ResistanceMod( ResistanceType.Poison, (defender.PoisonResistance > 70) ? -70 : -defender.PoisonResistance ) ); + if ( defender.PoisonResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Poison, defender.PoisonResistance / 2 ) ); - if ( defender.EnergyResistance > 0 ) - mods.Add( new ResistanceMod( ResistanceType.Energy, (defender.EnergyResistance > 70) ? -70 : -defender.EnergyResistance ) ); + if ( defender.EnergyResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Energy, defender.EnergyResistance / 2 ) ); + } + else + { + if ( defender.PhysicalResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Physical, (defender.PhysicalResistance > 70) ? -70 : -defender.PhysicalResistance ) ); + + if ( defender.FireResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Fire, (defender.FireResistance > 70) ? -70 : -defender.FireResistance ) ); + + if ( defender.ColdResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Cold, (defender.ColdResistance > 70) ? -70 : -defender.ColdResistance ) ); + + if ( defender.PoisonResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Poison, (defender.PoisonResistance > 70) ? -70 : -defender.PoisonResistance ) ); + + if ( defender.EnergyResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Energy, (defender.EnergyResistance > 70) ? -70 : -defender.EnergyResistance ) ); + } for ( int i = 0; i < mods.Count; ++i ) defender.AddResistanceMod( mods[i] ); diff --git a/Scripts/Mobiles/PlayerMobile.cs b/Scripts/Mobiles/PlayerMobile.cs index d358970be..d32285919 100644 --- a/Scripts/Mobiles/PlayerMobile.cs +++ b/Scripts/Mobiles/PlayerMobile.cs @@ -105,7 +105,22 @@ namespace Server.Mobiles private int m_GuildMessageHue, m_AllianceMessageHue; + private List m_AutoStabled; + private List m_AllFollowers; + #region Getters & Setters + public List AutoStabled { get { return m_AutoStabled; } } + + public List AllFollowers + { + get + { + if( m_AllFollowers == null ) + m_AllFollowers = new List();; + return m_AllFollowers; + } + } + public Server.Guilds.RankDefinition GuildRank { get @@ -516,7 +531,11 @@ namespace Server.Mobiles } from.SendGump( new NoticeGump( 1060637, 30720, notice, 0xFFC000, 300, 140, null, null ) ); + return; } + + if( from is PlayerMobile ) + ((PlayerMobile)from).ClaimAutoStabledPets(); } private bool m_NoDeltaRecursion; @@ -768,6 +787,8 @@ namespace Server.Mobiles private static void OnLogout( LogoutEventArgs e ) { + if( e.Mobile is PlayerMobile ) + ((PlayerMobile)e.Mobile).AutoStablePets(); } private static void EventSink_Connected( ConnectedEventArgs e ) @@ -989,6 +1010,9 @@ namespace Server.Mobiles strBase = this.Str; //this.Str already includes GetStatOffset/str strOffs = AosAttributes.GetValue( this, AosAttribute.BonusHits ); + if ( Core.ML && strOffs > 25 ) + strOffs = 25; + if ( AnimalForm.UnderTransformation( this, typeof( BakeKitsune ) ) || AnimalForm.UnderTransformation( this, typeof( GreyWolf ) ) ) strOffs += 20; } @@ -1998,6 +2022,7 @@ namespace Server.Mobiles private TimeSpan m_LongTermElapse; private DateTime m_SessionStart; private DateTime m_LastEscortTime; + private DateTime m_LastPetBallTime; private DateTime m_NextSmithBulkOrder; private DateTime m_NextTailorBulkOrder; private DateTime m_SavagePaintExpiration; @@ -2072,8 +2097,17 @@ namespace Server.Mobiles set{ m_LastEscortTime = value; } } + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastPetBallTime + { + get{ return m_LastPetBallTime; } + set{ m_LastPetBallTime = value; } + } + public PlayerMobile() { + m_AutoStabled = new List(); + m_VisList = new List(); m_PermaFlags = new List(); m_AntiMacroTable = new Hashtable(); @@ -2260,6 +2294,9 @@ namespace Server.Mobiles if ( target is BaseCreature && ((BaseCreature)target).InitialInnocent && !((BaseCreature)target).Controlled ) return false; + if ( Core.ML && target is BaseCreature && ((BaseCreature)target).Controlled && this == ((BaseCreature)target).ControlMaster ) + return false; + return base.IsHarmfulCriminal( target ); } @@ -2319,6 +2356,11 @@ namespace Server.Mobiles switch ( version ) { + case 26: + { + m_AutoStabled = reader.ReadStrongMobileList(); + goto case 25; + } case 25: { int recipeCount = reader.ReadInt(); @@ -2520,6 +2562,8 @@ namespace Server.Mobiles } case 0: { + if( version < 26 ) + m_AutoStabled = new List(); break; } } @@ -2598,7 +2642,9 @@ namespace Server.Mobiles base.Serialize( writer ); - writer.Write( (int) 25 ); // version + writer.Write( (int) 26 ); // version + + writer.Write( m_AutoStabled, true ); if( m_AcquiredRecipes == null ) { @@ -3855,5 +3901,99 @@ namespace Server.Mobiles m_BuffTable = null; } #endregion + + public void AutoStablePets() + { + if ( Core.SE && AllFollowers.Count > 0 ) + { + for ( int i = 0; i < m_AllFollowers.Count; ++i ) + { + BaseCreature pet = AllFollowers[i] as BaseCreature; + + if ( pet == null || pet.ControlMaster == null || ( pet.Summoned && !Core.ML ) ) + continue; + + if ( pet is IMount && ((IMount)pet).Rider != null ) + continue; + + if ( (pet is PackLlama || pet is PackHorse || pet is Beetle || pet is HordeMinionFamiliar) && (pet.Backpack != null && pet.Backpack.Items.Count > 0) ) + continue; + + if ( !pet.Summoned && !pet.IsBonded ) + continue; + + pet.ControlTarget = null; + pet.ControlOrder = OrderType.Stay; + pet.Internalize(); + + pet.SetControlMaster( null ); + pet.SummonMaster = null; + + pet.IsStabled = true; + + pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully happy + + Stabled.Add( pet ); + m_AutoStabled.Add( pet ); + --i; + } + } + } + + public void ClaimAutoStabledPets() + { + if( !Core.SE || m_AutoStabled.Count <= 0 ) + return; + + if( !Alive ) + { + SendLocalizedMessage( 1076251 ); // Your pet was unable to join you while you are a ghost. Please re-login once you have ressurected to claim your pets. + return; + } + + for ( int i = 0; i < m_AutoStabled.Count; ++i ) + { + BaseCreature pet = m_AutoStabled[i] as BaseCreature; + + if ( pet == null || pet.Deleted ) + { + pet.IsStabled = false; + m_AutoStabled.RemoveAt( i ); + if( Stabled.Contains( pet ) ) + Stabled.Remove( pet ); + --i; + continue; + } + + if ( (Followers + pet.ControlSlots) <= FollowersMax ) + { + m_AutoStabled.RemoveAt( i ); + --i; + + pet.SetControlMaster( this ); + + if ( pet.Summoned ) + pet.SummonMaster = this; + + pet.ControlTarget = this; + pet.ControlOrder = OrderType.Follow; + + pet.MoveToWorld( Location, Map ); + + pet.IsStabled = false; + + pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully Happy + + if( Stabled.Contains( pet ) ) + Stabled.Remove( pet ); + } + else + { + SendMessage( 1049612, pet.Name ); // ~1_NAME~ remained in the stables because you have too many followers. + } + } + + m_AutoStabled.Clear(); + } } } \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/BaseEscortable.cs b/Scripts/Mobiles/Townfolk/BaseEscortable.cs index b0eb52a17..f6991f05d 100644 --- a/Scripts/Mobiles/Townfolk/BaseEscortable.cs +++ b/Scripts/Mobiles/Townfolk/BaseEscortable.cs @@ -332,7 +332,7 @@ namespace Server.Mobiles { pm.SendLocalizedMessage( 1053004 ); // You must wait about a day before you can gain in compassion again. } - else if ( VirtueHelper.Award( pm, VirtueName.Compassion, 200, ref gainedPath ) ) + else if ( VirtueHelper.Award( pm, VirtueName.Compassion, this.IsPrisoner ? 400 : 200, ref gainedPath ) ) { if ( gainedPath ) pm.SendLocalizedMessage( 1053005 ); // You have achieved a path in compassion! diff --git a/Scripts/Multis/Camps/OrcCamp.cs b/Scripts/Multis/Camps/OrcCamp.cs index a8b54907c..affbdd919 100644 --- a/Scripts/Multis/Camps/OrcCamp.cs +++ b/Scripts/Multis/Camps/OrcCamp.cs @@ -17,6 +17,8 @@ namespace Server.Multis public override void AddComponents() { + BaseCreature bc; + IronGate gate = new IronGate( DoorFacing.EastCCW ); m_Gate = gate; @@ -46,6 +48,8 @@ namespace Server.Multis case 1: m_Prisoner = new SeekerOfAdventure(); break; } + bc = (BaseCreature)m_Prisoner; + bc.IsPrisoner = true; m_Prisoner.YellHue = Utility.RandomList( 0x57, 0x67, 0x77, 0x87, 0x117 ); AddMobile( m_Prisoner, 2, -2, 0, 0 ); diff --git a/Scripts/Multis/Camps/RatCamp.cs b/Scripts/Multis/Camps/RatCamp.cs index fc30c5e25..1dc43b4ed 100644 --- a/Scripts/Multis/Camps/RatCamp.cs +++ b/Scripts/Multis/Camps/RatCamp.cs @@ -17,6 +17,8 @@ namespace Server.Multis public override void AddComponents() { + BaseCreature bc; + IronGate gate = new IronGate( DoorFacing.EastCCW ); m_Gate = gate; @@ -46,6 +48,8 @@ namespace Server.Multis case 1: m_Prisoner = new SeekerOfAdventure(); break; } + bc = (BaseCreature)m_Prisoner; + bc.IsPrisoner = true; m_Prisoner.YellHue = Utility.RandomList( 0x57, 0x67, 0x77, 0x87, 0x117 ); AddMobile( m_Prisoner, 2, -2, 0, 0 ); diff --git a/Scripts/Skills/AnimalTaming.cs b/Scripts/Skills/AnimalTaming.cs index 78d1071d2..5a7b2aa44 100644 --- a/Scripts/Skills/AnimalTaming.cs +++ b/Scripts/Skills/AnimalTaming.cs @@ -82,7 +82,7 @@ namespace Server.SkillHandlers public static void ScaleSkills( BaseCreature bc, double scalar ) { - int totalCapIncrease = 0; + int totalCapIncrease = Core.SE ? 2000 : 0; // 2000 points for GM Anatomy and Meditation for ( int i = 0; i < bc.Skills.Length; ++i ) { @@ -246,7 +246,7 @@ namespace Server.SkillHandlers m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 502796, m_Tamer.NetState ); // You are dead, and cannot continue taming. Stop(); } - else if ( !m_Tamer.CanSee( m_Creature ) || !m_Tamer.InLOS( m_Creature ) ) + else if ( !m_Tamer.CanSee( m_Creature ) || !m_Tamer.InLOS( m_Creature ) || !CanPath() ) { m_BeingTamed.Remove( m_Creature ); m_Tamer.NextSkillTime = DateTime.Now; @@ -356,6 +356,21 @@ namespace Server.SkillHandlers } } } + + private bool CanPath() + { + IPoint3D p = m_Tamer as IPoint3D; + + if ( p == null ) + return false; + + if( m_Creature.InRange( new Point3D( p ), 1 ) ) + return true; + + MovementPath path = new MovementPath( m_Creature, new Point3D( p ) ); + + return path.Success; + } } } } diff --git a/Scripts/Skills/Hiding.cs b/Scripts/Skills/Hiding.cs index c8d32197a..b1adf5fc2 100644 --- a/Scripts/Skills/Hiding.cs +++ b/Scripts/Skills/Hiding.cs @@ -23,12 +23,17 @@ namespace Server.SkillHandlers public static TimeSpan OnUse( Mobile m ) { - if ( m.Target != null || m.Spell != null ) + if ( m.Spell != null ) { m.SendLocalizedMessage( 501238 ); // You are busy doing something else and cannot hide. return TimeSpan.FromSeconds( 1.0 ); } + if ( Core.ML && m.Target != null ) + { + Targeting.Target.Cancel( m ); + } + double bonus = 0.0; BaseHouse house = BaseHouse.FindHouseAt( m ); diff --git a/Scripts/Skills/Peacemaking.cs b/Scripts/Skills/Peacemaking.cs index f1967583b..0c62e3005 100644 --- a/Scripts/Skills/Peacemaking.cs +++ b/Scripts/Skills/Peacemaking.cs @@ -95,7 +95,7 @@ namespace Server.SkillHandlers foreach ( Mobile m in from.GetMobilesInRange( range ) ) { - if ( (m is BaseCreature && ((BaseCreature)m).Uncalmable) || m == from || !from.CanBeHarmful( m, false ) ) + if ((m is BaseCreature && ((BaseCreature)m).Uncalmable) || (m is BaseCreature && ((BaseCreature)m).AreaPeaceImmune) || m == from || !from.CanBeHarmful ( m, false )) continue; calmed = true; diff --git a/Scripts/Spells/Base/SpecialMove.cs b/Scripts/Spells/Base/SpecialMove.cs index 9a9f81837..6de975db3 100644 --- a/Scripts/Spells/Base/SpecialMove.cs +++ b/Scripts/Spells/Base/SpecialMove.cs @@ -21,9 +21,9 @@ namespace Server.Spells public virtual bool BlockedByAnimalForm{ get{ return true; } } public virtual bool DelayedContext{ get{ return false; } } - public virtual double GetAccuracyScalar( Mobile attacker ) + public virtual int GetAccuracyBonus( Mobile attacker ) { - return 1.0; + return 0; } public virtual double GetDamageScalar( Mobile attacker, Mobile defender ) diff --git a/Scripts/Spells/Base/Spell.cs b/Scripts/Spells/Base/Spell.cs index f258f2eca..8b4bcca2c 100644 --- a/Scripts/Spells/Base/Spell.cs +++ b/Scripts/Spells/Base/Spell.cs @@ -532,6 +532,9 @@ namespace Server.Spells if ( ClearHandsOnCast ) m_Caster.ClearHands(); + if ( Core.ML ) + WeaponAbility.ClearCurrentAbility( m_Caster ); + m_CastTimer = new CastTimer( this, castDelay ); m_CastTimer.Start(); diff --git a/Scripts/Spells/Bushido/HonorableExecution.cs b/Scripts/Spells/Bushido/HonorableExecution.cs index fd75974ac..09d931079 100644 --- a/Scripts/Spells/Bushido/HonorableExecution.cs +++ b/Scripts/Spells/Bushido/HonorableExecution.cs @@ -18,14 +18,6 @@ namespace Server.Spells.Bushido public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063122 ); } } // You better kill your enemy with your next hit or you'll be rather sorry... - public override double GetAccuracyScalar( Mobile attacker ) - { - double bushido = attacker.Skills[SkillName.Bushido].Value; - - // TODO: 4 -> Perfection / 5 - return 1.0 + ( bushido / 10.0 + 4 ) / 100.0; - } - public override double GetDamageScalar( Mobile attacker, Mobile defender ) { double bushido = attacker.Skills[SkillName.Bushido].Value; diff --git a/Scripts/Spells/Bushido/LightningStrike.cs b/Scripts/Spells/Bushido/LightningStrike.cs index 4649bd442..a05c23e41 100644 --- a/Scripts/Spells/Bushido/LightningStrike.cs +++ b/Scripts/Spells/Bushido/LightningStrike.cs @@ -20,12 +20,9 @@ namespace Server.Spells.Bushido public override bool DelayedContext{ get{ return true; } } - public override double GetAccuracyScalar( Mobile attacker ) + public override int GetAccuracyBonus( Mobile attacker ) { - if ( GetContext( attacker, typeof( Bushido.LightningStrike ) ) ) - return 1.1; - - return 1.5; + return 50; } public override bool IgnoreArmor( Mobile attacker ) diff --git a/Scripts/Spells/Bushido/SamuraiSpell.cs b/Scripts/Spells/Bushido/SamuraiSpell.cs index a11fb54bb..e0d6ff1ec 100644 --- a/Scripts/Spells/Bushido/SamuraiSpell.cs +++ b/Scripts/Spells/Bushido/SamuraiSpell.cs @@ -41,6 +41,8 @@ namespace Server.Spells.Bushido public override bool CheckCast() { + int mana = ScaleMana ( RequiredMana ); + if ( !base.CheckCast() ) return false; @@ -56,9 +58,9 @@ namespace Server.Spells.Bushido Caster.SendLocalizedMessage( 1063013, args ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. return false; } - else if ( Caster.Mana < ScaleMana( RequiredMana ) ) + else if ( Caster.Mana < mana ) { - Caster.SendLocalizedMessage( 1060174, RequiredMana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. return false; } diff --git a/Scripts/Spells/Chivalry/DivineFury.cs b/Scripts/Spells/Chivalry/DivineFury.cs index 530badb09..fce81ad65 100644 --- a/Scripts/Spells/Chivalry/DivineFury.cs +++ b/Scripts/Spells/Chivalry/DivineFury.cs @@ -52,6 +52,8 @@ namespace Server.Spells.Chivalry m_Table[Caster] = t = Timer.DelayCall( TimeSpan.FromSeconds( delay ), new TimerStateCallback( Expire_Callback ), Caster ); Caster.Delta( MobileDelta.WeaponDamage ); + + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.DivineFury, 1060589, 1075634, TimeSpan.FromSeconds(delay), Caster)); } FinishSequence(); diff --git a/Scripts/Spells/Chivalry/EnemyOfOne.cs b/Scripts/Spells/Chivalry/EnemyOfOne.cs index d1490c47e..f6a809ef3 100644 --- a/Scripts/Spells/Chivalry/EnemyOfOne.cs +++ b/Scripts/Spells/Chivalry/EnemyOfOne.cs @@ -56,6 +56,8 @@ namespace Server.Spells.Chivalry { ((PlayerMobile)Caster).EnemyOfOneType = null; ((PlayerMobile)Caster).WaitingForEnemy = true; + + BuffInfo.AddBuff ( Caster, new BuffInfo ( BuffIcon.EnemyOfOne, 1075653, 1044111, TimeSpan.FromMinutes ( delay ), Caster ) ); } } diff --git a/Scripts/Spells/Chivalry/PaladinSpell.cs b/Scripts/Spells/Chivalry/PaladinSpell.cs index 0d9d436fc..14cd70357 100644 --- a/Scripts/Spells/Chivalry/PaladinSpell.cs +++ b/Scripts/Spells/Chivalry/PaladinSpell.cs @@ -26,6 +26,8 @@ namespace Server.Spells.Chivalry public override bool CheckCast() { + int mana = ScaleMana( RequiredMana ); + if ( !base.CheckCast() ) return false; @@ -39,9 +41,9 @@ namespace Server.Spells.Chivalry Caster.SendLocalizedMessage( 1060173, RequiredTithing.ToString() ); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability, return false; } - else if ( Caster.Mana < ScaleMana( RequiredMana ) ) + else if ( Caster.Mana < mana ) { - Caster.SendLocalizedMessage( 1060174, RequiredMana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. return false; } @@ -69,7 +71,7 @@ namespace Server.Spells.Chivalry } else if ( Caster.Mana < mana ) { - Caster.SendLocalizedMessage( 1060174, RequiredMana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. return false; } diff --git a/Scripts/Spells/Chivalry/RemoveCurse.cs b/Scripts/Spells/Chivalry/RemoveCurse.cs index 11da615dc..fb16378dc 100644 --- a/Scripts/Spells/Chivalry/RemoveCurse.cs +++ b/Scripts/Spells/Chivalry/RemoveCurse.cs @@ -86,12 +86,16 @@ namespace Server.Spells.Chivalry CorpseSkinSpell.RemoveCurse( m ); CurseSpell.RemoveEffect( m ); MortalStrike.EndWound( m ); + if (Core.ML) { BloodOathSpell.RemoveCurse ( m ); } + MindRotSpell.ClearMindRotScalar ( m ); BuffInfo.RemoveBuff( m, BuffIcon.Clumsy ); BuffInfo.RemoveBuff( m, BuffIcon.FeebleMind ); BuffInfo.RemoveBuff( m, BuffIcon.Weaken ); + BuffInfo.RemoveBuff ( m, BuffIcon.Curse ); BuffInfo.RemoveBuff( m, BuffIcon.MassCurse ); BuffInfo.RemoveBuff( m, BuffIcon.MortalStrike ); + BuffInfo.RemoveBuff ( m, BuffIcon.Mindrot ); // TODO: Should this remove blood oath? Pain spike? } diff --git a/Scripts/Spells/First/ReactiveArmor.cs b/Scripts/Spells/First/ReactiveArmor.cs index de2ec6a08..3af807519 100644 --- a/Scripts/Spells/First/ReactiveArmor.cs +++ b/Scripts/Spells/First/ReactiveArmor.cs @@ -79,6 +79,11 @@ namespace Server.Spells.First for ( int i = 0; i < mods.Length; ++i ) targ.AddResistanceMod( mods[i] ); + + int physresist = 15 + (int)(targ.Skills[SkillName.Inscribe].Value / 20); + string args = String.Format("{0}\t{1}\t{2}\t{3}\t{4}", physresist, 5, 5, 5, 5); + + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.ReactiveArmor, 1075812, 1075813, args.ToString())); } else { @@ -89,6 +94,8 @@ namespace Server.Spells.First for ( int i = 0; i < mods.Length; ++i ) targ.RemoveResistanceMod( mods[i] ); + + BuffInfo.RemoveBuff(Caster, BuffIcon.ReactiveArmor); } } diff --git a/Scripts/Spells/Fourth/Curse.cs b/Scripts/Spells/Fourth/Curse.cs index 4153a9e08..a518c65c9 100644 --- a/Scripts/Spells/Fourth/Curse.cs +++ b/Scripts/Spells/Fourth/Curse.cs @@ -75,6 +75,13 @@ namespace Server.Spells.Fourth m.FixedParticles( 0x374A, 10, 15, 5028, EffectLayer.Waist ); m.PlaySound( 0x1EA ); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + string args = String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", percentage, percentage, percentage, 10, 10, 10, 10); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Curse, 1075835, 1075836, length, m, args.ToString())); } FinishSequence(); diff --git a/Scripts/Spells/Necromancy/BloodOathSpell.cs b/Scripts/Spells/Necromancy/BloodOathSpell.cs index e4bc63fe7..2ef77beca 100644 --- a/Scripts/Spells/Necromancy/BloodOathSpell.cs +++ b/Scripts/Spells/Necromancy/BloodOathSpell.cs @@ -58,6 +58,10 @@ namespace Server.Spells.Necromancy * ((ss-rm)/8)+8 */ + ExpireTimer timer = (ExpireTimer)m_Table[m]; + if ( timer != null ) + timer.DoExpire(); + m_OathTable[Caster] = Caster; m_OathTable[m] = Caster; @@ -72,13 +76,32 @@ namespace Server.Spells.Necromancy TimeSpan duration = TimeSpan.FromSeconds( ((GetDamageSkill( Caster ) - GetResistSkill( m )) / 8) + 8 ); m.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); //Skill check for gain - new ExpireTimer( Caster, m, duration ).Start(); + timer = new ExpireTimer ( Caster, m, duration ); + timer.Start (); + + BuffInfo.AddBuff ( Caster, new BuffInfo ( BuffIcon.BloodOathCaster, 1075659, duration, Caster, m.Name.ToString () ) ); + BuffInfo.AddBuff ( m, new BuffInfo ( BuffIcon.BloodOathCurse, 1075661, duration, m, Caster.Name.ToString () ) ); + + m_Table[m] = timer; + } FinishSequence(); } + public static bool RemoveCurse( Mobile m ) + { + ExpireTimer t = (ExpireTimer)m_Table[m]; + + if ( t == null ) + return false; + + t.DoExpire(); + return true; + } + private static Hashtable m_OathTable = new Hashtable(); + private static Hashtable m_Table = new Hashtable (); public static Mobile GetBloodOath( Mobile m ) { @@ -112,15 +135,24 @@ namespace Server.Spells.Necromancy { if ( m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive || DateTime.Now >= m_End ) { - m_Caster.SendLocalizedMessage( 1061620 ); // Your Blood Oath has been broken. - m_Target.SendLocalizedMessage( 1061620 ); // Your Blood Oath has been broken. - - m_OathTable.Remove( m_Caster ); - m_OathTable.Remove( m_Target ); - - Stop(); + DoExpire (); } } + public void DoExpire() + { + m_Caster.SendLocalizedMessage( 1061620 ); // Your Blood Oath has been broken. + m_Target.SendLocalizedMessage( 1061620 ); // Your Blood Oath has been broken. + + m_OathTable.Remove ( m_Caster ); + m_OathTable.Remove ( m_Target ); + + Stop (); + + BuffInfo.RemoveBuff ( m_Caster, BuffIcon.BloodOathCaster ); + BuffInfo.RemoveBuff ( m_Target, BuffIcon.BloodOathCurse ); + + m_Table.Remove ( m_Caster ); + } } private class InternalTarget : Target diff --git a/Scripts/Spells/Necromancy/MindRot.cs b/Scripts/Spells/Necromancy/MindRot.cs index 38c981862..49982c6de 100644 --- a/Scripts/Spells/Necromancy/MindRot.cs +++ b/Scripts/Spells/Necromancy/MindRot.cs @@ -66,56 +66,42 @@ namespace Server.Spells.Necromancy public static void ClearMindRotScalar( Mobile m ) { - m_Table.Remove( m ); + if (!m_Table.ContainsKey(m)) + return; + BuffInfo.RemoveBuff( m, BuffIcon.Mindrot ); + MRBucket tmpB = (MRBucket)m_Table[m]; + MRExpireTimer tmpT = (MRExpireTimer)tmpB.m_MRExpireTimer; + tmpT.Stop(); + m_Table.Remove(m); + m.SendLocalizedMessage(1060872); // Your mind feels normal again. } public static bool HasMindRotScalar( Mobile m ) { - return m_Table.Contains( m ); + return m_Table.ContainsKey(m); } public static bool GetMindRotScalar( Mobile m, ref double scalar ) { - object obj = m_Table[m]; - - if ( obj == null ) + if (!m_Table.ContainsKey(m)) return false; - scalar = (double)obj; + MRBucket tmpB = (MRBucket)m_Table[m]; + scalar = tmpB.m_Scalar; return true; } public static void SetMindRotScalar( Mobile caster, Mobile target, double scalar, TimeSpan duration ) { - m_Table[target] = scalar; - BuffInfo.AddBuff( target, new BuffInfo( BuffIcon.Mindrot, 1075665, duration, target ) ); - new ExpireTimer( caster, target, duration ).Start(); - } - - private class ExpireTimer : Timer - { - private Mobile m_Caster; - private Mobile m_Target; - private DateTime m_End; - - public ExpireTimer( Mobile caster, Mobile target, TimeSpan delay ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + if (!m_Table.ContainsKey(target)) { - m_Caster = caster; - m_Target = target; - m_End = DateTime.Now + delay; - - Priority = TimerPriority.TwoFiftyMS; - } - - protected override void OnTick() - { - if ( m_Target.Deleted || !m_Target.Alive || DateTime.Now >= m_End ) - { - m_Target.SendLocalizedMessage( 1060872 ); // Your mind feels normal again. - ClearMindRotScalar( m_Target ); - Stop(); - } + m_Table.Add(target, new MRBucket(scalar, new MRExpireTimer(caster, target, duration))); + BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Mindrot, 1075665, duration, target)); + MRBucket tmpB = (MRBucket)m_Table[target]; + MRExpireTimer tmpT = (MRExpireTimer)tmpB.m_MRExpireTimer; + tmpT.Start(); + target.SendLocalizedMessage(1074384); } } @@ -142,4 +128,50 @@ namespace Server.Spells.Necromancy } } } + + public class MRExpireTimer : Timer + { + private Mobile m_Caster; + private Mobile m_Target; + private DateTime m_End; + + public MRExpireTimer( Mobile caster, Mobile target, TimeSpan delay ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_Caster = caster; + m_Target = target; + m_End = DateTime.Now + delay; + Priority = TimerPriority.TwoFiftyMS; + } + + public void RenewDelay(TimeSpan delay) + { + m_End = DateTime.Now + delay; + } + + public void Halt() + { + Stop(); + } + + protected override void OnTick() + { + if ( m_Target.Deleted || !m_Target.Alive || DateTime.Now >= m_End ) + { + MindRotSpell.ClearMindRotScalar( m_Target ); + Stop(); + } + } + } + + public class MRBucket + { + public MRBucket(double theScalar, MRExpireTimer theTimer) + { + m_Scalar = theScalar; + m_MRExpireTimer = theTimer; + } + + public double m_Scalar; + public MRExpireTimer m_MRExpireTimer; + } } \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/PainSpike.cs b/Scripts/Spells/Necromancy/PainSpike.cs index 239069ac7..7807ef2d4 100644 --- a/Scripts/Spells/Necromancy/PainSpike.cs +++ b/Scripts/Spells/Necromancy/PainSpike.cs @@ -74,9 +74,7 @@ namespace Server.Spells.Necromancy new InternalTimer( m, damage ).Start(); } - BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.PainSpike, 1075667, buffTime, m, (int)damage ) ); - - + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.PainSpike, 1075667, buffTime, m, Convert.ToString( (int)damage ) ) ); Misc.WeightOverloading.DFA = Misc.DFAlgorithm.PainSpike; m.Damage( (int) damage, Caster ); diff --git a/Scripts/Spells/Necromancy/PoisonStrike.cs b/Scripts/Spells/Necromancy/PoisonStrike.cs index c34b61746..55305b4d4 100644 --- a/Scripts/Spells/Necromancy/PoisonStrike.cs +++ b/Scripts/Spells/Necromancy/PoisonStrike.cs @@ -49,6 +49,13 @@ namespace Server.Spells.Necromancy Effects.PlaySound( m.Location, m.Map, 0x229 ); double damage = Utility.RandomMinMax( (Core.ML ? 32 : 36), 40 ) * ((300 + (GetDamageSkill( Caster ) * 9)) / 1000); + + double sdiBonus = (double)AosAttributes.GetValue( Caster, AosAttribute.SpellDamage )/100; + double pvmDamage = damage * (1 + sdiBonus); + + if ( Core.ML && sdiBonus > 0.15 ) + sdiBonus = 0.15; + double pvpDamage = damage * (1 + sdiBonus); Map map = m.Map; @@ -57,7 +64,7 @@ namespace Server.Spells.Necromancy List targets = new List(); foreach( Mobile targ in m.GetMobilesInRange( 2 ) ) - if( (Caster == targ || SpellHelper.ValidIndirectTarget( Caster, targ )) && Caster.CanBeHarmful( targ, false ) ) + if( (Caster == targ || m == targ || SpellHelper.ValidIndirectTarget( Caster, targ )) && Caster.CanBeHarmful( targ, false ) ) targets.Add( targ ); for( int i = 0; i < targets.Count; ++i ) @@ -74,7 +81,7 @@ namespace Server.Spells.Necromancy num = 3; Caster.DoHarmful( targ ); - SpellHelper.Damage( this, targ, damage / num, 0, 0, 0, 100, 0 ); + SpellHelper.Damage( this, targ, ((m.Player && Caster.Player) ? pvpDamage : pvmDamage) / num, 0, 0, 0, 100, 0 ); } } } diff --git a/Scripts/Spells/Ninjitsu/DeathStrike.cs b/Scripts/Spells/Ninjitsu/DeathStrike.cs index 6fc16be90..d0f74319c 100644 --- a/Scripts/Spells/Ninjitsu/DeathStrike.cs +++ b/Scripts/Spells/Ninjitsu/DeathStrike.cs @@ -135,6 +135,9 @@ namespace Server.Spells.Ninjitsu // This bonus is 8 at most. That brings the cap up to 70/30. damage += info.m_DamageBonus; + if ( info.m_Attacker.Weapon is BaseWeapon && ((BaseWeapon)info.m_Attacker.Weapon).MaxRange > 1 ) + damage /= 2; + // Damage is direct. //info.m_Target.Damage( damage, info.m_Attacker ); diff --git a/Scripts/Spells/Ninjitsu/NinjaSpell.cs b/Scripts/Spells/Ninjitsu/NinjaSpell.cs index 6a985e254..6886ea699 100644 --- a/Scripts/Spells/Ninjitsu/NinjaSpell.cs +++ b/Scripts/Spells/Ninjitsu/NinjaSpell.cs @@ -43,6 +43,8 @@ namespace Server.Spells.Ninjitsu public override bool CheckCast() { + int mana = ScaleMana( RequiredMana ); + if ( !base.CheckCast() ) return false; @@ -58,9 +60,9 @@ namespace Server.Spells.Ninjitsu Caster.SendLocalizedMessage( 1063013, args ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. return false; } - else if ( Caster.Mana < ScaleMana( RequiredMana ) ) + else if ( Caster.Mana < mana ) { - Caster.SendLocalizedMessage( 1060174, RequiredMana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. return false; } diff --git a/Scripts/Spells/Second/Protection.cs b/Scripts/Spells/Second/Protection.cs index efbf204df..c6dacd7f8 100644 --- a/Scripts/Spells/Second/Protection.cs +++ b/Scripts/Spells/Second/Protection.cs @@ -49,8 +49,8 @@ namespace Server.Spells.Second public static void Toggle( Mobile caster, Mobile target ) { /* Players under the protection spell effect can no longer have their spells "disrupted" when hit. - * Players under the protection spell have decreased physical resistance stat value, - * a decreased "resisting spells" skill value by -35, + * Players under the protection spell have decreased physical resistance stat value (-15 + (Inscription/20), + * a decreased "resisting spells" skill value by -35 + (Inscription/20), * and a slower casting speed modifier (technically, a negative "faster cast speed") of 2 points. * The protection spell has an indefinite duration, becoming active when cast, and deactivated when re-cast. * Reactive Armor, Protection, and Magic Reflection will stay on—even after logging out, @@ -75,6 +75,11 @@ namespace Server.Spells.Second target.AddResistanceMod( (ResistanceMod)mods[0] ); target.AddSkillMod( (SkillMod)mods[1] ); + + int physloss = -15 + (int) (caster.Skills[SkillName.Inscribe].Value / 20); + int resistloss = -35 + (int) (caster.Skills[SkillName.Inscribe].Value / 20); + string args = String.Format("{0}\t{1}", physloss, resistloss); + BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Protection, 1075814, 1075815, args.ToString())); } else { @@ -86,6 +91,8 @@ namespace Server.Spells.Second target.RemoveResistanceMod( (ResistanceMod)mods[0] ); target.RemoveSkillMod( (SkillMod)mods[1] ); + + BuffInfo.RemoveBuff(target, BuffIcon.Protection); } } diff --git a/Scripts/Spells/Spellweaving/ArcanistSpell.cs b/Scripts/Spells/Spellweaving/ArcanistSpell.cs index 50504c69b..820069bdd 100644 --- a/Scripts/Spells/Spellweaving/ArcanistSpell.cs +++ b/Scripts/Spells/Spellweaving/ArcanistSpell.cs @@ -130,7 +130,7 @@ namespace Server.Spells.Spellweaving public virtual bool CheckResisted( Mobile m ) { - double percent = (50 + 2*(GetResistSkill( m ) - GetDamageSkill( m )))/100; //TODO: According to the guide this is it.. but.. is it correct per OSI? + double percent = (50 + 2*(GetResistSkill( m ) - GetDamageSkill( Caster )))/100; //TODO: According to the guide this is it.. but.. is it correct per OSI? if( percent <= 0 ) return false; diff --git a/Scripts/Spells/Spellweaving/NatureFury.cs b/Scripts/Spells/Spellweaving/NatureFury.cs index 189797e97..f635eb60f 100644 --- a/Scripts/Spells/Spellweaving/NatureFury.cs +++ b/Scripts/Spells/Spellweaving/NatureFury.cs @@ -70,6 +70,13 @@ namespace Server.Spells.Spellweaving { Caster.SendLocalizedMessage( 501942 ); // That location is blocked. } + + //say "Target can not be seen" if you target directly a mobile, like in OSI + if (m != null) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if( SpellHelper.CheckTown( p, Caster ) && (m_MobileTarg ? CheckHSequence( m ) : CheckSequence()) ) { TimeSpan duration = TimeSpan.FromSeconds( Caster.Skills.Spellweaving.Value/24 + 25 + FocusLevel*2 ); diff --git a/Scripts/Spells/Spellweaving/Thunderstorm.cs b/Scripts/Spells/Spellweaving/Thunderstorm.cs index 2eed57bd0..a26bd8635 100644 --- a/Scripts/Spells/Spellweaving/Thunderstorm.cs +++ b/Scripts/Spells/Spellweaving/Thunderstorm.cs @@ -27,8 +27,22 @@ namespace Server.Spells.Spellweaving { Caster.PlaySound( 0x5CE ); + double skill = Caster.Skills[SkillName.Spellweaving].Value; + + int damage = Math.Max( 11, 10 + (int)(skill / 24) ) + FocusLevel; + + int sdiBonus = AosAttributes.GetValue( Caster, AosAttribute.SpellDamage ); + + int pvmDamage = damage * ( 100 + sdiBonus ); + pvmDamage /= 100; + + if ( sdiBonus > 15 ) + sdiBonus = 15; + + int pvpDamage = damage * ( 100 + sdiBonus ); + pvpDamage /= 100; + int range = 2 + FocusLevel; - int damage = 15 + FocusLevel; TimeSpan duration = TimeSpan.FromSeconds( 5 + FocusLevel ); List targets = new List(); @@ -47,7 +61,7 @@ namespace Server.Spells.Spellweaving Spell oldSpell = m.Spell as Spell; - SpellHelper.Damage( this, m, damage, 0, 0, 0, 0, 100 ); + SpellHelper.Damage( this, m, ( m.Player && Caster.Player ) ? pvpDamage : pvmDamage, 0, 0, 0, 0, 100 ); if( oldSpell != null && oldSpell != m.Spell ) { diff --git a/Scripts/Spells/Third/Bless.cs b/Scripts/Spells/Third/Bless.cs index 55f57ebf0..970d44a56 100644 --- a/Scripts/Spells/Third/Bless.cs +++ b/Scripts/Spells/Third/Bless.cs @@ -41,6 +41,13 @@ namespace Server.Spells.Third m.FixedParticles( 0x373A, 10, 15, 5018, EffectLayer.Waist ); m.PlaySound( 0x1EA ); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + string args = String.Format("{0}\t{1}\t{2}", percentage, percentage, percentage); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Bless, 1075847, 1075848, length, m, args.ToString())); } FinishSequence();