diff --git a/Scripts/Engines/CannedEvil/ChampionSpawn.cs b/Scripts/Engines/CannedEvil/ChampionSpawn.cs index 5959cd4d2..83150d005 100644 --- a/Scripts/Engines/CannedEvil/ChampionSpawn.cs +++ b/Scripts/Engines/CannedEvil/ChampionSpawn.cs @@ -387,6 +387,137 @@ namespace Server.Engines.CannedEvil Start(); } + #region Scroll of Transcendence + private ScrollofTranscendence CreateRandomTramSoT() + { + int level; + double random = Utility.RandomDouble(); + + if (0.2 >= random) + level = 5; + else if (0.4 >= random) + level = 4; + else if (0.6 >= random) + level = 3; + else if (0.8 >= random) + level = 2; + else + level = 1; + + return ScrollofTranscendence.CreateRandom(level, level); + } + + private ScrollofTranscendence CreateRandomFelSoT() + { + int level; + double random = Utility.RandomDouble(); + + if (0.2 >= random) + level = 10; + else if (0.4 >= random) + level = 9; + else if (0.6 >= random) + level = 8; + else if (0.8 >= random) + level = 7; + else + level = 6; + + return ScrollofTranscendence.CreateRandom(level, level); + } + + private PowerScroll CreateRandomFelPS() + { + return PowerScroll.CreateRandomNoCraft(5, 5); + } + + public static void GiveScrollOfTranscendenceFelTo ( Mobile killer, ScrollofTranscendence SoTF ) + { + if( SoTF == null || killer == null ) //sanity + return; + + killer.SendLocalizedMessage( 1094936 ); // You have received a Scroll of Transcendence! + + if ( killer.Alive ) + killer.AddToBackpack( SoTF ); + else + { + if( killer.Corpse != null && !killer.Corpse.Deleted ) + killer.Corpse.DropItem( SoTF ); + else + killer.AddToBackpack( SoTF ); + } + + + // Justice reward + PlayerMobile pm = (PlayerMobile)killer; + for (int j = 0; j < pm.JusticeProtectors.Count; ++j) + { + Mobile prot = (Mobile)pm.JusticeProtectors[j]; + if (prot.Map != killer.Map || prot.Kills >= 5 || prot.Criminal || !JusticeVirtue.CheckMapRegion(killer, prot)) + continue; + + int chance = 0; + + switch (VirtueHelper.GetLevel(prot, VirtueName.Justice)) + { + case VirtueLevel.Seeker: chance = 60; break; + case VirtueLevel.Follower: chance = 80; break; + case VirtueLevel.Knight: chance = 100; break; + } + + if (chance > Utility.Random(100)) + { + prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice! + ScrollofTranscendence SoTFduplicate = new ScrollofTranscendence ( SoTF.Skill, SoTF.Value ); + prot.AddToBackpack( SoTFduplicate ); + } + } + } + public static void GivePowerScrollFelTo ( Mobile killer, PowerScroll PS ) + { + if( PS == null || killer == null ) //sanity + return; + + killer.SendLocalizedMessage(1049524); // You have received a scroll of power! + + if ( killer.Alive ) + killer.AddToBackpack( PS ); + else + { + if( killer.Corpse != null && !killer.Corpse.Deleted ) + killer.Corpse.DropItem( PS ); + else + killer.AddToBackpack( PS ); + } + + // Justice reward + PlayerMobile pm = (PlayerMobile)killer; + for (int j = 0; j < pm.JusticeProtectors.Count; ++j) + { + Mobile prot = (Mobile)pm.JusticeProtectors[j]; + if (prot.Map != killer.Map || prot.Kills >= 5 || prot.Criminal || !JusticeVirtue.CheckMapRegion(killer, prot)) + continue; + + int chance = 0; + + switch (VirtueHelper.GetLevel(prot, VirtueName.Justice)) + { + case VirtueLevel.Seeker: chance = 60; break; + case VirtueLevel.Follower: chance = 80; break; + case VirtueLevel.Knight: chance = 100; break; + } + + if (chance > Utility.Random(100)) + { + prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice! + PowerScroll PSduplicate = new PowerScroll ( PS.Skill, PS.Value ); + prot.AddToBackpack( PSduplicate ); + } + } + } + #endregion + public void OnSlice() { if( !m_Active || Deleted ) @@ -445,6 +576,41 @@ namespace Server.Engines.CannedEvil if( killer is PlayerMobile ) { + #region Scroll of Transcendence + if ( Core.ML ) + { + if ( Map == Map.Felucca ) + { + if ( Utility.RandomDouble() < 0.001 ) + { + PlayerMobile pm = (PlayerMobile)killer; + double random = Utility.Random ( 49 ); + + if ( random <= 24 ) + { + ScrollofTranscendence SoTF = CreateRandomFelSoT(); + GiveScrollOfTranscendenceFelTo ( pm, SoTF ); + } + else + { + PowerScroll PS = CreateRandomFelPS(); + GivePowerScrollFelTo ( pm, PS ); + } + } + } + + if ( Map == Map.Ilshenar || Map == Map.Tokuno ) + { + if ( Utility.RandomDouble() < 0.0015 ) + { + killer.SendLocalizedMessage( 1094936 ); // You have received a Scroll of Transcendence! + ScrollofTranscendence SoTT = CreateRandomTramSoT(); + killer.AddToBackpack( SoTT ); + } + } + } + #endregion + int mobSubLevel = GetSubLevelFor( m ) + 1; if( mobSubLevel >= 0 ) diff --git a/Scripts/Engines/Harvest/Fishing.cs b/Scripts/Engines/Harvest/Fishing.cs index 0a6044380..8a8da738d 100644 --- a/Scripts/Engines/Harvest/Fishing.cs +++ b/Scripts/Engines/Harvest/Fishing.cs @@ -251,7 +251,7 @@ namespace Server.Engines.Harvest { SOS sos = messages[i]; - if ( from.Map == sos.TargetMap && from.InRange( sos.TargetLocation, 60 ) ) + if ( ( from.Map == Map.Felucca || from.Map == Map.Trammel ) && from.InRange( sos.TargetLocation, 60 ) ) { Item preLoot = null; diff --git a/Scripts/Items/Misc/Firebomb.cs b/Scripts/Items/Misc/Firebomb.cs new file mode 100644 index 000000000..ef7b9a34c --- /dev/null +++ b/Scripts/Items/Misc/Firebomb.cs @@ -0,0 +1,270 @@ +using Server.Network; +using Server.Spells; +using Server.Targeting; +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + public class Firebomb : Item + { + private Timer m_Timer; + private int m_Ticks = 0; + private Mobile m_LitBy; + + [Constructable] + public Firebomb() : this( 0x99B ) + { + } + + [Constructable] + public Firebomb( int itemID ) : base( itemID ) + { + //Name = "a firebomb"; + Weight = 2.0; + Hue = 1260; + } + + public Firebomb( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + return; + } + + if ( Core.AOS && (from.Paralyzed || from.Frozen || (from.Spell != null && from.Spell.IsCasting)) ) + { + //to prevent exploiting for pvp + from.SendLocalizedMessage( 1075857 ); // You can not use that while paralyzed. + return; + } + + if ( m_Timer == null ) + { + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 1 ), TimeSpan.FromSeconds( 1 ), new TimerCallback( OnFirebombTimerTick ) ); + m_LitBy = from; + from.SendLocalizedMessage( 1060581 ); //You light the firebomb! Throw it now! + } + else + from.SendLocalizedMessage( 1060582 ); //You've already lit it! Better throw it now! + + from.BeginTarget( 12, true, TargetFlags.None, new TargetCallback( OnFirebombTarget ) ); + } + + private void OnFirebombTimerTick() + { + if ( Deleted ) + { + m_Timer.Stop(); + return; + } + + if ( Map == Map.Internal && HeldBy == null ) + return; + + switch ( m_Ticks ) + { + case 0: + case 1: + case 2: + { + ++m_Ticks; + + if ( HeldBy != null ) + HeldBy.PublicOverheadMessage( MessageType.Regular, 957, false, m_Ticks.ToString() ); + else if ( RootParent == null ) + PublicOverheadMessage( MessageType.Regular, 957, false, m_Ticks.ToString() ); + else if ( RootParent is Mobile ) + ((Mobile)RootParent).PublicOverheadMessage( MessageType.Regular, 957, false, m_Ticks.ToString() ); + + break; + } + default: + { + if ( HeldBy != null ) + HeldBy.DropHolding(); + + if ( RootParent is Mobile ) + { + Mobile parent = (Mobile)RootParent; + parent.SendLocalizedMessage( 1060583 ); //The firebomb explodes in your hand! + AOS.Damage( parent, Utility.Random( 3 ) + 4, 0, 100, 0, 0, 0 ); + } + else if ( RootParent == null ) + { + List toDamage = new List(); + IPooledEnumerable eable = Map.GetMobilesInRange( Location, 1 ); + + foreach ( Mobile m in eable ) + { + toDamage.Add( m ); + } + eable.Free(); + + Mobile victim; + for ( int i = 0; i < toDamage.Count; ++i ) + { + victim = toDamage[i]; + + if ( m_LitBy == null || (SpellHelper.ValidIndirectTarget( m_LitBy, victim ) && m_LitBy.CanBeHarmful( victim, false )) ) + { + if ( m_LitBy != null ) + m_LitBy.DoHarmful( victim ); + + AOS.Damage( victim, m_LitBy, Utility.Random( 3 ) + 4, 0, 100, 0, 0, 0 ); + } + } + (new FirebombField( m_LitBy, toDamage )).MoveToWorld( Location, Map ); + } + + m_Timer.Stop(); + Delete(); + break; + } + } + } + + private void OnFirebombTarget( Mobile from, object obj ) + { + if ( Deleted || Map == Map.Internal || !IsChildOf( from.Backpack ) ) + return; + + IPoint3D p = obj as IPoint3D; + + if ( p == null ) + return; + + SpellHelper.GetSurfaceTop( ref p ); + + from.RevealingAction(); + + IEntity to; + + if ( p is Mobile ) + to = (Mobile)p; + else + to = new Entity( Serial.Zero, new Point3D( p ), Map ); + + Effects.SendMovingEffect( from, to, ItemID & 0x3FFF, 7, 0, false, false, Hue, 0 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( FirebombReposition_OnTick ), new object[]{ p, Map } ); + Internalize(); + } + + private void FirebombReposition_OnTick( object state ) + { + if ( Deleted ) + return; + + object[] states = (object[])state; + IPoint3D p = (IPoint3D)states[0]; + Map map = (Map)states[1]; + + MoveToWorld( new Point3D( p ), map ); + } + } + + public class FirebombField : Item + { + private List m_Burning; + private Timer m_Timer; + private Mobile m_LitBy; + private DateTime m_Expire; + + public FirebombField( Mobile litBy, List toDamage ) : base( 0x376A ) + { + Movable = false; + m_LitBy = litBy; + m_Expire = DateTime.Now + TimeSpan.FromSeconds( 10 ); + m_Burning = toDamage; + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ), new TimerCallback( OnFirebombFieldTimerTick ) ); + } + + public FirebombField( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + //Don't serialize these... + } + + public override void Deserialize( GenericReader reader ) + { + } + + public override bool OnMoveOver( Mobile m ) + { + if ( ItemID == 0x398C && m_LitBy == null || (SpellHelper.ValidIndirectTarget( m_LitBy, m ) && m_LitBy.CanBeHarmful( m, false )) ) + { + if ( m_LitBy != null ) + m_LitBy.DoHarmful( m ); + + AOS.Damage( m, m_LitBy, 2, 0, 100, 0, 0, 0 ); + m.PlaySound( 0x208 ); + + if ( !m_Burning.Contains( m ) ) + m_Burning.Add( m ); + } + + return true; + } + + private void OnFirebombFieldTimerTick() + { + if ( Deleted ) + { + m_Timer.Stop(); + return; + } + + if ( ItemID == 0x376A ) + { + ItemID = 0x398C; + return; + } + + Mobile victim; + for ( int i = 0; i < m_Burning.Count; ) + { + victim = m_Burning[i]; + + if ( victim.Location == Location && victim.Map == Map && (m_LitBy == null || ( SpellHelper.ValidIndirectTarget( m_LitBy, victim ) && m_LitBy.CanBeHarmful( victim, false ) )) ) + { + if ( m_LitBy != null ) + m_LitBy.DoHarmful( victim ); + + AOS.Damage( victim, m_LitBy, Utility.Random( 3 ) + 4, 0, 100, 0, 0, 0 ); + ++i; + } + else + m_Burning.RemoveAt( i ); + } + + if ( DateTime.Now >= m_Expire ) + { + m_Timer.Stop(); + Delete(); + } + } + } +} diff --git a/Scripts/Items/Misc/OilCloth.cs b/Scripts/Items/Misc/OilCloth.cs index b54813a3b..8f091bcab 100644 --- a/Scripts/Items/Misc/OilCloth.cs +++ b/Scripts/Items/Misc/OilCloth.cs @@ -106,6 +106,29 @@ namespace Server.Items from.LocalOverheadMessage( Network.MessageType.Regular, 0x3B2, 1005422 ); // Hmmmm... this does not need to be cleaned. } } +//Added for Firebomb + else if ( obj is BaseBeverage ) + { + BaseBeverage beverage = (BaseBeverage) obj; + + if ( beverage.Content == BeverageType.Liquor ) + { + Firebomb bomb = new Firebomb( beverage.ItemID ); + bomb.Name = beverage.Name; + Point3D loc = beverage.Location; + beverage.Delete(); + + from.AddToBackpack( bomb ); + bomb.Location = loc; + from.SendLocalizedMessage( 1060580 ); // You prepare a firebomb. + Consume(); + } + } + else if ( obj is Firebomb ) + { + from.SendLocalizedMessage( 1060579 ); // That is already a firebomb! + } +//Firebomb end else { from.SendLocalizedMessage( 1005426 ); // The cloth will not work on that. diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs index 07c2b3c4a..2d98fe40b 100644 --- a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs @@ -251,7 +251,7 @@ namespace Server.Items from.PlaySound( 0x23E ); } } - else if ( (item is BaseArmor && (((BaseArmor)item).MaterialType == ArmorMaterialType.Leather || ((BaseArmor)item).MaterialType == ArmorMaterialType.Studded) || item is ElvenBoots) && m_Tub.AllowLeather ) + else if ( (item is BaseArmor && (((BaseArmor)item).MaterialType == ArmorMaterialType.Leather || ((BaseArmor)item).MaterialType == ArmorMaterialType.Studded) || item is ElvenBoots || item is WoodlandBelt) && m_Tub.AllowLeather ) { if ( !from.InRange( m_Tub.GetWorldLocation(), 1 ) || !from.InRange( item.GetWorldLocation(), 1 ) ) { diff --git a/Scripts/Items/Special/SoulStone.cs b/Scripts/Items/Special/SoulStone.cs index 93ac749c8..5b0d941d1 100644 --- a/Scripts/Items/Special/SoulStone.cs +++ b/Scripts/Items/Special/SoulStone.cs @@ -5,6 +5,7 @@ using Server.Network; using Server.Accounting; using Server.Engines.VeteranRewards; using Server.Multis; +using Server.Mobiles; namespace Server.Items { @@ -49,7 +50,7 @@ namespace Server.Items this.ItemID = m_InactiveItemID; } } - + public static readonly TimeSpan UseDelay = TimeSpan.FromDays( 1.0 ); private string m_Account; @@ -157,6 +158,8 @@ namespace Server.Items { DateTime now = DateTime.Now; + PlayerMobile pm = from as PlayerMobile; + if ( this.Deleted || !this.IsAccessibleTo( from ) ) { return false; @@ -224,6 +227,15 @@ namespace Server.Items return false; } + + #region Scroll of Alacrity + if ( pm.AcceleratedStart > DateTime.Now ) + { + from.SendLocalizedMessage(1078115); // You may not use a soulstone while your character is under the effects of a Scroll of Alacrity. + return false; + } + #endregion + else { return true; @@ -591,6 +603,21 @@ namespace Server.Items return; } + #region Scroll of ALacrity + PlayerMobile pm = from as PlayerMobile; + if (pm.AcceleratedStart > DateTime.Now) + { + //
Unable to Absorb Selected Skill from Soulstone
+ + /*You may not use a soulstone while your character is under the effects of a Scroll of Alacrity.*/ + + // Wrong message?! + + from.SendGump(new ErrorGump(m_Stone, 1070717, 1078115)); + return; + } + #endregion + if ( requiredAmount > 0 ) { for ( int i = 0; i < from.Skills.Length; ++i ) diff --git a/Scripts/Items/Special/Special Scrolls/PowerScroll.cs b/Scripts/Items/Special/Special Scrolls/PowerScroll.cs index a73421d9e..26162cc10 100644 --- a/Scripts/Items/Special/Special Scrolls/PowerScroll.cs +++ b/Scripts/Items/Special/Special Scrolls/PowerScroll.cs @@ -270,9 +270,12 @@ namespace Server.Items { if ( firstStage ) { - from.CloseGump( typeof( StatCapScroll.InternalGump ) ); - from.CloseGump( typeof( PowerScroll.InternalGump ) ); - from.SendGump( new InternalGump( from, this ) ); + from.CloseGump(typeof(StatCapScroll.InternalGump)); + from.CloseGump(typeof(PowerScroll.InternalGump)); + #region Scroll of Alacrity + from.CloseGump(typeof(ScrollofAlacrity.InternalGump)); + #endregion + from.SendGump(new InternalGump(from, this)); } else { diff --git a/Scripts/Items/Special/Special Scrolls/ScrollofAlacrity.cs b/Scripts/Items/Special/Special Scrolls/ScrollofAlacrity.cs new file mode 100644 index 000000000..fe7e1ce8a --- /dev/null +++ b/Scripts/Items/Special/Special Scrolls/ScrollofAlacrity.cs @@ -0,0 +1,324 @@ +/*************************************************************************** +* ScrollofAlacrity.cs +* ------------------- +* begin : June 1, 2009 +* copyright : (C) Shai'Tan Malkier aka Callandor2k +* email : ShaiTanMalkier@gmail.com +* +* $Id: ScrollofAlacrity.cs 1 2009-06-1 04:28:39Z Callandor2k $ +* +***************************************************************************/ + +/*************************************************************************** +* +* This Script/File is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +***************************************************************************/ + +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using System.Collections; +using Server.Engines.Quests; +using System.Collections.Generic; + +namespace Server.Items +{ + public class ScrollofAlacrity : Item + { + public override int LabelNumber { get { return 1078604; } } // Scroll of Alacrity + + private SkillName m_Skill; + + private static SkillName[] m_Skills = new SkillName[] + { + SkillName.Alchemy, + SkillName.Anatomy, + SkillName.AnimalLore, + SkillName.ItemID, + SkillName.ArmsLore, + SkillName.Parry, + SkillName.Begging, + SkillName.Blacksmith, + SkillName.Fletching, + SkillName.Peacemaking, + SkillName.Camping, + SkillName.Carpentry, + SkillName.Cartography, + SkillName.Cooking, + SkillName.DetectHidden, + SkillName.Discordance, + SkillName.EvalInt, + SkillName.Healing, + SkillName.Fishing, + SkillName.Forensics, + SkillName.Herding, + SkillName.Hiding, + SkillName.Provocation, + SkillName.Inscribe, + SkillName.Lockpicking, + SkillName.Magery, + SkillName.MagicResist, + SkillName.Tactics, + SkillName.Snooping, + SkillName.Musicianship, + SkillName.Poisoning, + SkillName.Archery, + SkillName.SpiritSpeak, + SkillName.Stealing, + SkillName.Tailoring, + SkillName.AnimalTaming, + SkillName.TasteID, + SkillName.Tinkering, + SkillName.Tracking, + SkillName.Veterinary, + SkillName.Swords, + SkillName.Macing, + SkillName.Fencing, + SkillName.Wrestling, + SkillName.Lumberjacking, + SkillName.Mining, + SkillName.Meditation, + SkillName.Stealth, + SkillName.RemoveTrap, + SkillName.Necromancy, + SkillName.Focus, + SkillName.Chivalry, + SkillName.Bushido, + SkillName.Ninjitsu, + SkillName.Spellweaving + }; + + public static SkillName[] Skills { get { return (m_Skills); } } + + [Constructable] + public ScrollofAlacrity(SkillName skill) + : base(0x14EF) + { + base.Hue = 0x4AB; + base.Weight = 1.0; + + LootType = LootType.Cursed; + + m_Skill = skill; + } + + public ScrollofAlacrity(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill + { + get + { + return m_Skill; + } + set + { + m_Skill = value; + } + } + + private string GetNameLocalized() + { + return String.Concat("#", (1044060 + (int)m_Skill).ToString()); + } + + private string GetName() + { + int index = (int)m_Skill; + SkillInfo[] table = SkillInfo.Table; + + if (index >= 0 && index < table.Length) + return table[index].Name.ToLower(); + else + return "???"; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1071345, "{0} 15 Minutes", GetName());// Skill: ~1_val~ + } + + public void Use(Mobile from, bool firstStage) + { + PlayerMobile pm = from as PlayerMobile; + + if (Deleted) + return; + + /* to add when skillgain quests will be implemented + + #region Mondain's Legacy + for (int i = pm.Quests.Count - 1; i >= 0; i--) + { + BaseQuest quest = pm.Quests[i]; + + for (int j = quest.Objectives.Count - 1; j >= 0; j--) + { + BaseObjective objective = quest.Objectives[j]; + + if (objective is ApprenticeObjective) + { + from.SendMessage("You are already under the effect of an enhanced skillgain quest."); + return; + } + } + } + #endregion + */ + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + else if (pm.AcceleratedStart > DateTime.Now) + { + from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll. + return; + } + + else + { + if (firstStage) + { + from.CloseGump(typeof(StatCapScroll.InternalGump)); + from.CloseGump(typeof(PowerScroll.InternalGump)); + from.CloseGump(typeof(ScrollofTranscendence.InternalGump)); + from.CloseGump(typeof(ScrollofAlacrity.InternalGump)); + from.SendGump(new InternalGump(from, this)); + } + else + { + double tskill = from.Skills[m_Skill].Base; + double tcap = from.Skills[m_Skill].Cap; + + if (tskill >= tcap || from.Skills[m_Skill].Lock == SkillLock.Locked || from.Skills[m_Skill].Lock == SkillLock.Down) + { + from.SendLocalizedMessage(1094935); /*You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. + *If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap.*/ + return; + } + else + { + Effects.PlaySound(from.Location, from.Map, 0x1E9); + + Effects.SendTargetParticles(from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); + + from.SendLocalizedMessage(1077956); // You are infused with intense energy. You are under the effects of an accelerated skillgain scroll. + + pm.AcceleratedStart = DateTime.Now + TimeSpan.FromMinutes(15); + + Timer t = (Timer)m_Table[from]; + + m_Table[from] = Timer.DelayCall(TimeSpan.FromMinutes(15), new TimerStateCallback(Expire_Callback), from); + + pm.AcceleratedSkill = m_Skill; + + Delete(); + } + } + } + } + + private static Hashtable m_Table = new Hashtable(); + + private static void Expire_Callback(object state) + { + Mobile m = (Mobile)state; + + m_Table.Remove(m); + + m.PlaySound(0x1F8); + + m.SendLocalizedMessage(1077957);// The intense energy dissipates. You are no longer under the effects of an accelerated skillgain scroll. + } + + public override void OnDoubleClick(Mobile from) + { + Use(from, true); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write((int)m_Skill); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Skill = (SkillName)reader.ReadInt(); + break; + } + } + + LootType = LootType.Cursed; + + if (Insured) + Insured = false; + } + + public class InternalGump : Gump + { + private Mobile m_Mobile; + private ScrollofAlacrity m_Scroll; + + public InternalGump(Mobile mobile, ScrollofAlacrity scroll) + : base(25, 50) + { + m_Mobile = mobile; + m_Scroll = scroll; + + AddPage(0); + + AddBackground(25, 10, 420, 200, 5054); + + AddImageTiled(33, 20, 401, 181, 2624); + AddAlphaRegion(33, 20, 401, 181); + + AddHtmlLocalized(40, 48, 387, 100, 1078602, true, true); /* Using a Scroll of Alacrity for a given skill will increase the amount of skillgain + * you receive for that skill. Once the Scroll of Alacrity duration has expired, + * skillgain will return to normal for that skill. */ + + AddHtmlLocalized(125, 148, 200, 20, 1049478, 0xFFFFFF, false, false); // Do you wish to use this scroll? + + AddButton(100, 172, 4005, 4007, 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(135, 172, 120, 20, 1046362, 0xFFFFFF, false, false); // Yes + + AddButton(275, 172, 4005, 4007, 0, GumpButtonType.Reply, 0); + AddHtmlLocalized(310, 172, 120, 20, 1046363, 0xFFFFFF, false, false); // No + + AddHtml(40, 20, 260, 20, String.Format("Scroll of Alacrity:"), false, false); + + AddHtmlLocalized(310, 20, 120, 20, 1044060 + (int)scroll.m_Skill, 0xFFFFFF, false, false); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info.ButtonID == 1) + m_Scroll.Use(m_Mobile, false); + } + } + } +} diff --git a/Scripts/Items/Special/Special Scrolls/ScrollofTranscendence.cs b/Scripts/Items/Special/Special Scrolls/ScrollofTranscendence.cs new file mode 100644 index 000000000..bfc121c9d --- /dev/null +++ b/Scripts/Items/Special/Special Scrolls/ScrollofTranscendence.cs @@ -0,0 +1,352 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Items +{ + public class ScrollofTranscendence : Item + { + public override int LabelNumber { get { return 1094934; } } // Scroll of Transcendence + + private SkillName m_Skill; + private double m_Value; + + private static SkillName[] m_Skills = new SkillName[] + { + SkillName.Alchemy, + SkillName.Anatomy, + SkillName.AnimalLore, + SkillName.ItemID, + SkillName.ArmsLore, + SkillName.Parry, + SkillName.Begging, + SkillName.Blacksmith, + SkillName.Fletching, + SkillName.Peacemaking, + SkillName.Camping, + SkillName.Carpentry, + SkillName.Cartography, + SkillName.Cooking, + SkillName.DetectHidden, + SkillName.Discordance, + SkillName.EvalInt, + SkillName.Healing, + SkillName.Fishing, + SkillName.Forensics, + SkillName.Herding, + SkillName.Hiding, + SkillName.Provocation, + SkillName.Inscribe, + SkillName.Lockpicking, + SkillName.Magery, + SkillName.MagicResist, + SkillName.Tactics, + SkillName.Snooping, + SkillName.Musicianship, + SkillName.Poisoning, + SkillName.Archery, + SkillName.SpiritSpeak, + SkillName.Stealing, + SkillName.Tailoring, + SkillName.AnimalTaming, + SkillName.TasteID, + SkillName.Tinkering, + SkillName.Tracking, + SkillName.Veterinary, + SkillName.Swords, + SkillName.Macing, + SkillName.Fencing, + SkillName.Wrestling, + SkillName.Lumberjacking, + SkillName.Mining, + SkillName.Meditation, + SkillName.Stealth, + SkillName.RemoveTrap, + SkillName.Necromancy, + SkillName.Focus, + SkillName.Chivalry, + SkillName.Bushido, + SkillName.Ninjitsu, + SkillName.Spellweaving + }; + + public static SkillName[] Skills { get { return (m_Skills); } } + + public static ScrollofTranscendence CreateRandom(int min, int max) + { + min /= 1; + max /= 1; + + SkillName[] skills = ScrollofTranscendence.Skills; + + return new ScrollofTranscendence(skills[Utility.Random(skills.Length)], Utility.RandomMinMax(min, max) * 0.1); + } + + [Constructable] + public ScrollofTranscendence(SkillName skill, double value) + : base(0x14EF) + { + Hue = 0x490; + Weight = 1.0; + + m_Skill = skill; + m_Value = value; + if (m_Value > 0.0) + LootType = LootType.Cursed; + } + + public ScrollofTranscendence(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill + { + get + { + return m_Skill; + } + set + { + m_Skill = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double Value + { + get + { + return m_Value; + } + set + { + m_Value = value; + } + } + + private string GetNameLocalized() + { + return String.Concat("#", (1044060 + (int)m_Skill).ToString()); + } + + private string GetName() + { + int index = (int)m_Skill; + SkillInfo[] table = SkillInfo.Table; + + if (index >= 0 && index < table.Length) + return table[index].Name.ToLower(); + else + return "???"; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Value == 1) + list.Add(1076759, "{0}\t{1}.0 Skill Points", GetName(), m_Value); + else + list.Add(1076759, "{0}\t{1} Skill Points", GetName(), m_Value); + } + + public void Use(Mobile from, bool firstStage) + { + PlayerMobile pm = from as PlayerMobile; + + if (Deleted) + return; + + /* to uncomment when skillgain quests will be implementes + + #region Mondain's Legacy + for (int i = pm.Quests.Count - 1; i >= 0; i--) + { + BaseQuest quest = pm.Quests[i]; + + for (int j = quest.Objectives.Count - 1; j >= 0; j--) + { + BaseObjective objective = quest.Objectives[j]; + + if (objective is ApprenticeObjective) + { + from.SendMessage("You are already under the effect of an enhanced skillgain quest."); + return; + } + } + } + #endregion + */ + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + #region Scroll of Alacrity + else if (pm.AcceleratedStart > DateTime.Now) + { + from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll. + return; + } + #endregion + else + { + if (firstStage) + { + from.CloseGump(typeof(StatCapScroll.InternalGump)); + from.CloseGump(typeof(PowerScroll.InternalGump)); + from.CloseGump(typeof(ScrollofTranscendence.InternalGump)); + from.CloseGump(typeof(ScrollofAlacrity.InternalGump)); + from.SendGump(new InternalGump(from, this)); + } + else + { + double tskill = from.Skills[m_Skill].Base; + double tcap = from.Skills[m_Skill].Cap; + bool canGain = true; + + if (tskill >= tcap || from.Skills[m_Skill].Lock == SkillLock.Locked || from.Skills[m_Skill].Lock == SkillLock.Down) + { + from.SendLocalizedMessage(1094935); /*You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. + *If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap.*/ + return; + } + + if ((tskill + m_Value) > tcap) + m_Value = tcap - tskill; + + if ((from.SkillsTotal + m_Value * 10) > from.SkillsCap) + { + canGain = false; + for (int i = 0; i <= 54; i++) + { + if (from.Skills[i].Lock == SkillLock.Down && from.Skills[i].Base >= m_Value) + { + from.Skills[i].Base = from.Skills[i].Base - m_Value; + canGain = true; + break; + } + } + + if (!canGain) + { + from.SendLocalizedMessage(1094935); /*You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. + *If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap.*/ + return; + } + } + + if (tskill + m_Value > tcap) + { + from.Skills[m_Skill].Base = tcap; + } + else + { + from.Skills[m_Skill].Base = tskill + m_Value; + } + + from.SendLocalizedMessage(1049513, GetNameLocalized()); // You feel a surge of magic as the scroll enhances your ~1_type~! + + Effects.PlaySound(from.Location, from.Map, 0x1F7); + + Effects.SendTargetParticles(from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); + Effects.SendTargetParticles(from, 0x376A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100); + + Delete(); + } + } + } + + public override void OnDoubleClick(Mobile from) + { + Use(from, true); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write((int)m_Skill); + writer.Write((double)m_Value); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Skill = (SkillName)reader.ReadInt(); + m_Value = reader.ReadDouble(); + break; + } + } + + if (m_Value >= 0.1) + { + LootType = LootType.Cursed; + + if (Insured) + Insured = false; + } + + if (Hue == 0x7E) + Hue = 0x490; + } + + public class InternalGump : Gump + { + private Mobile m_Mobile; + private ScrollofTranscendence m_Scroll; + + public InternalGump(Mobile mobile, ScrollofTranscendence scroll) + : base(25, 50) + { + m_Mobile = mobile; + m_Scroll = scroll; + + AddPage(0); + + AddBackground(25, 10, 420, 200, 5054); + + AddImageTiled(33, 20, 401, 181, 2624); + AddAlphaRegion(33, 20, 401, 181); + + AddHtmlLocalized(40, 48, 387, 100, 1094933, true, true); /*Using a Scroll of Transcendence for a given skill will permanently increase your current + *level in that skill by the amount of points displayed on the scroll. + *As you may not gain skills beyond your maximum skill cap, any excess points will be lost.*/ + + AddHtmlLocalized(125, 148, 200, 20, 1049478, 0xFFFFFF, false, false); // Do you wish to use this scroll? + + AddButton(100, 172, 4005, 4007, 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(135, 172, 120, 20, 1046362, 0xFFFFFF, false, false); // Yes + + AddButton(275, 172, 4005, 4007, 0, GumpButtonType.Reply, 0); + AddHtmlLocalized(310, 172, 120, 20, 1046363, 0xFFFFFF, false, false); // No + + double value = scroll.m_Value; + + AddHtml(40, 20, 260, 20, String.Format("Scroll of Transcendence ({0} Skill):", value), false, false); + + AddHtmlLocalized(310, 20, 120, 20, 1044060 + (int)scroll.m_Skill, 0xFFFFFF, false, false); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info.ButtonID == 1) + m_Scroll.Use(m_Mobile, false); + } + } + } +} diff --git a/Scripts/Items/Special/Special Scrolls/StatScroll.cs b/Scripts/Items/Special/Special Scrolls/StatScroll.cs index 7b86c3fbb..fa7af7dca 100644 --- a/Scripts/Items/Special/Special Scrolls/StatScroll.cs +++ b/Scripts/Items/Special/Special Scrolls/StatScroll.cs @@ -89,6 +89,9 @@ namespace Server.Items { from.CloseGump( typeof( StatCapScroll.InternalGump ) ); from.CloseGump( typeof( PowerScroll.InternalGump ) ); + #region Scroll of Alacrity + from.CloseGump(typeof( ScrollofAlacrity.InternalGump ) ); + #endregion from.SendGump( new InternalGump( from, this ) ); } else diff --git a/Scripts/Items/Weapons/SlayerGroup.cs b/Scripts/Items/Weapons/SlayerGroup.cs index d4cc6d39b..17253c256 100644 --- a/Scripts/Items/Weapons/SlayerGroup.cs +++ b/Scripts/Items/Weapons/SlayerGroup.cs @@ -85,7 +85,7 @@ namespace Server.Items elemental.Opposition = new SlayerGroup[]{ abyss }; elemental.FoundOn = new Type[]{ typeof( Balron ), typeof( Daemon ) }; - elemental.Super = new SlayerEntry( SlayerName.ElementalBan,/* typeof( AcidElemental ),*/ typeof( AgapiteElemental ), typeof( AirElemental ), typeof( SummonedAirElemental ), typeof( BloodElemental ), typeof( BronzeElemental ), typeof( CopperElemental ), typeof( CrystalElemental ), typeof( DullCopperElemental ), typeof( EarthElemental ), typeof( SummonedEarthElemental ), typeof( Efreet ), typeof( FireElemental ), typeof( SummonedFireElemental ), typeof( GoldenElemental ), typeof( IceElemental ), typeof( KazeKemono ), typeof( PoisonElemental ), typeof( RaiJu ), typeof( SandVortex ), typeof( ShadowIronElemental ), typeof( SnowElemental ), typeof( ValoriteElemental ), typeof( VeriteElemental ), typeof( WaterElemental ), typeof( SummonedWaterElemental ) ); + elemental.Super = new SlayerEntry( SlayerName.ElementalBan, typeof( ToxicElemental ), typeof( AgapiteElemental ), typeof( AirElemental ), typeof( SummonedAirElemental ), typeof( BloodElemental ), typeof( BronzeElemental ), typeof( CopperElemental ), typeof( CrystalElemental ), typeof( DullCopperElemental ), typeof( EarthElemental ), typeof( SummonedEarthElemental ), typeof( Efreet ), typeof( FireElemental ), typeof( SummonedFireElemental ), typeof( GoldenElemental ), typeof( IceElemental ), typeof( KazeKemono ), typeof( PoisonElemental ), typeof( RaiJu ), typeof( SandVortex ), typeof( ShadowIronElemental ), typeof( SnowElemental ), typeof( ValoriteElemental ), typeof( VeriteElemental ), typeof( WaterElemental ), typeof( SummonedWaterElemental ) ); elemental.Entries = new SlayerEntry[] { new SlayerEntry( SlayerName.BloodDrinking, typeof( BloodElemental ) ), diff --git a/Scripts/Misc/SkillCheck.cs b/Scripts/Misc/SkillCheck.cs index db655bc7f..2b95a60a6 100644 --- a/Scripts/Misc/SkillCheck.cs +++ b/Scripts/Misc/SkillCheck.cs @@ -221,6 +221,14 @@ namespace Server.Misc } } + #region Scroll of Alacrity + PlayerMobile pm = from as PlayerMobile; + + if ( from is PlayerMobile ) + if (pm != null && skill.SkillName == pm.AcceleratedSkill && pm.AcceleratedStart > DateTime.Now) + toGain *= Utility.RandomMinMax(2, 5); + #endregion + if ( !from.Player || (skills.Total + toGain) <= skills.Cap ) { skill.BaseFixedPoint += toGain; diff --git a/Scripts/Mobiles/AI/AI/BaseAI.cs b/Scripts/Mobiles/AI/AI/BaseAI.cs index 8138a1330..3cda39ec9 100644 --- a/Scripts/Mobiles/AI/AI/BaseAI.cs +++ b/Scripts/Mobiles/AI/AI/BaseAI.cs @@ -2494,6 +2494,10 @@ namespace Server.Mobiles if( TransformationSpellHelper.UnderTransformation( m, typeof( EtherealVoyageSpell ) ) ) continue; + // Ignore players with activated honor + if ( m is PlayerMobile && ( (PlayerMobile)m ).HonorActive ) + continue; + if( acqType == FightMode.Aggressor || acqType == FightMode.Evil ) { // Only acquire this mobile if it attacked us, or if it's evil. diff --git a/Scripts/Mobiles/AI/Creature/BaseCreature.cs b/Scripts/Mobiles/AI/Creature/BaseCreature.cs index 64237a8b6..6f9cb7ecb 100644 --- a/Scripts/Mobiles/AI/Creature/BaseCreature.cs +++ b/Scripts/Mobiles/AI/Creature/BaseCreature.cs @@ -769,6 +769,9 @@ namespace Server.Mobiles if( TransformationSpellHelper.UnderTransformation( m, typeof( EtherealVoyageSpell ) ) ) return false; + if ( m is PlayerMobile && ( (PlayerMobile)m ).HonorActive ) + return false; + BaseCreature c = (BaseCreature)m; return ( m_iTeam != c.m_iTeam || ( (m_bSummoned || m_bControlled) != (c.m_bSummoned || c.m_bControlled) )/* || c.Combatant == this*/ ); diff --git a/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs b/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs index 16031f1b9..2bf4fd75b 100644 --- a/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs +++ b/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs @@ -134,19 +134,19 @@ namespace Server.Mobiles if ( Core.ML ) { if ( defender.PhysicalResistance > 0 ) - mods.Add( new ResistanceMod( ResistanceType.Physical, defender.PhysicalResistance / 2 ) ); + mods.Add( new ResistanceMod( ResistanceType.Physical, -(defender.PhysicalResistance / 2) ) ); if ( defender.FireResistance > 0 ) - mods.Add( new ResistanceMod( ResistanceType.Fire, defender.FireResistance / 2 ) ); + mods.Add( new ResistanceMod( ResistanceType.Fire, -(defender.FireResistance / 2) ) ); if ( defender.ColdResistance > 0 ) - mods.Add( new ResistanceMod( ResistanceType.Cold, defender.ColdResistance / 2 ) ); + mods.Add( new ResistanceMod( ResistanceType.Cold, -(defender.ColdResistance / 2) ) ); if ( defender.PoisonResistance > 0 ) - mods.Add( new ResistanceMod( ResistanceType.Poison, defender.PoisonResistance / 2 ) ); + mods.Add( new ResistanceMod( ResistanceType.Poison, -(defender.PoisonResistance / 2) ) ); if ( defender.EnergyResistance > 0 ) - mods.Add( new ResistanceMod( ResistanceType.Energy, defender.EnergyResistance / 2 ) ); + mods.Add( new ResistanceMod( ResistanceType.Energy, -(defender.EnergyResistance / 2) ) ); } else { diff --git a/Scripts/Mobiles/PlayerMobile.cs b/Scripts/Mobiles/PlayerMobile.cs index 88da78bcc..52306ddff 100644 --- a/Scripts/Mobiles/PlayerMobile.cs +++ b/Scripts/Mobiles/PlayerMobile.cs @@ -45,7 +45,11 @@ namespace Server.Mobiles Young = 0x00000400, AcceptGuildInvites = 0x00000800, DisplayChampionTitle = 0x00001000, - HasStatReward = 0x00002000 + HasStatReward = 0x00002000, + + #region Scroll of Alacrity + AcceleratedSkill = 0x00080000, + #endregion } public enum NpcGuild @@ -318,6 +322,27 @@ namespace Server.Mobiles set{ m_AnkhNextUse = value; } } + #region Scroll of Alacrity + private DateTime m_AcceleratedStart; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime AcceleratedStart + { + get { return m_AcceleratedStart; } + set { m_AcceleratedStart = value; } + } + + private SkillName m_AcceleratedSkill; + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName AcceleratedSkill + { + get { return m_AcceleratedSkill; } + set { m_AcceleratedSkill = value; } + } + #endregion + + public static Direction GetDirection4( Point3D from, Point3D to ) { int dx = from.X - to.X; @@ -345,6 +370,16 @@ namespace Server.Mobiles if ( !base.OnDroppedItemToWorld( item, location ) ) return false; + IPooledEnumerable mobiles = Map.GetMobilesInRange( location, 0 ); + + if ( mobiles.GetEnumerator().MoveNext() ) + { + mobiles.Free(); + return false; + } + else + mobiles.Free(); + BounceInfo bi = item.GetBounce(); if ( bi != null ) diff --git a/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs b/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs index 79ab34e4d..8be74a837 100644 --- a/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs +++ b/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs @@ -251,7 +251,7 @@ namespace Server.Mobiles } else { - SayTo( from, 1042558 ); /* I charge 30 gold per pet for a real week's stable time. + from.SendLocalizedMessage( 1042558 ); /* I charge 30 gold per pet for a real week's stable time. * I will withdraw it from thy bank account. * Which animal wouldst thou like to stable here? */ @@ -313,7 +313,7 @@ namespace Server.Mobiles from.Stabled.Add( pet ); - SayTo( from, 502679 ); // Very well, thy pet is stabled. Thou mayst recover it by saying 'claim' to me. In one real world week, I shall sell it off if it is not claimed! + SayTo( from, Core.AOS ? 1049677 : 502679 ); // [AOS: Your pet has been stabled.] Very well, thy pet is stabled. Thou mayst recover it by saying 'claim' to me. In one real world week, I shall sell it off if it is not claimed! } else { diff --git a/Scripts/Skills/AnimalTaming.cs b/Scripts/Skills/AnimalTaming.cs index ecbbe5f9d..9ea92f71f 100644 --- a/Scripts/Skills/AnimalTaming.cs +++ b/Scripts/Skills/AnimalTaming.cs @@ -180,7 +180,8 @@ namespace Server.SkillHandlers creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 502805, from.NetState ); // You seem to anger the beast! creature.PlaySound( creature.GetAngerSound() ); creature.Direction = creature.GetDirectionTo( from ); - creature.Combatant = from; + if ( from is PlayerMobile && !( (PlayerMobile)from ).HonorActive ) + creature.Combatant = from; } else { diff --git a/Scripts/Spells/Necromancy/AnimateDeadSpell.cs b/Scripts/Spells/Necromancy/AnimateDeadSpell.cs index b9b610220..5d9ec5356 100644 --- a/Scripts/Spells/Necromancy/AnimateDeadSpell.cs +++ b/Scripts/Spells/Necromancy/AnimateDeadSpell.cs @@ -116,7 +116,7 @@ namespace Server.Spells.Necromancy typeof( ValoriteElemental ), typeof( VeriteElemental ), typeof( PoisonElemental ), typeof( FireElemental ), typeof( SummonedFireElemental ), typeof( SnowElemental ), typeof( AirElemental ), typeof( SummonedAirElemental ), typeof( WaterElemental ), - typeof( SummonedAirElemental ) + typeof( SummonedAirElemental ), typeof ( ToxicElemental ) }, new SummonEntry[] { new SummonEntry( 5000, typeof( WailingBanshee ) ),