- Hit Life Leech now works in PvP

(http://www.uodemise.com/discussion/showthread.php?t=121298)

- Summoned Daemon now has the proper bodyvalue (AoS+) and effect
(http://www.uodemise.com/discussion/showthread.php?t=127404)

- Two new house signs are added
(http://www.uodemise.com/discussion/showthread.php?t=125409)

- Changes to Satyrs and Dryads:
--> Dryads:
----> they do area peace
----> can partially undress males
----> have chance to drop peculiar or fragrant (not yet implemented) seeds
--> Satyrs:
----> their karma is neutral
----> can peace combatants
----> can provoke nearby creatures to the combatant
----> can undress females
----> can discord combatants
--> Both: can drop spellweaving scrolls
(http://www.uodemise.com/discussion/showthread.php?t=125444)

- Added Auto Arrow Recovery feature (SE+)
(http://www.uodemise.com/discussion/showthread.php?t=114807)
This commit is contained in:
daedalus 2009-12-14 19:01:59 +00:00
parent 37043076e0
commit cd7c2becf7
14 changed files with 511 additions and 98 deletions

View file

@ -191,6 +191,8 @@ namespace Server.Gumps
974, 982 974, 982
}; };
private static List<int> _HouseSigns = new List<int>();
public HouseGumpAOS( HouseGumpPageAOS page, Mobile from, BaseHouse house ) : base( 50, 40 ) public HouseGumpAOS( HouseGumpPageAOS page, Mobile from, BaseHouse house ) : base( 50, 40 )
{ {
m_House = house; m_House = house;
@ -487,19 +489,36 @@ namespace Server.Gumps
{ {
int index = 0; int index = 0;
for ( int i = 0; i < 3; ++i ) if ( _HouseSigns.Count == 0 )
{
// Add standard signs
for ( int i = 0; i < 54; ++i )
{
_HouseSigns.Add( 2980 + ( i * 2 ) );
}
// Add library and beekeeper signs ( ML )
_HouseSigns.Add( 2966 );
_HouseSigns.Add( 3140 );
}
int signsPerPage = Core.ML ? 24 : 18;
int totalSigns = Core.ML ? 56 : 54;
int pages = (int) Math.Ceiling( (double) totalSigns / signsPerPage );
for ( int i = 0; i < pages; ++i )
{ {
AddPage( i + 1 ); AddPage( i + 1 );
AddButton( 10, 360, 4005, 4007, 0, GumpButtonType.Page, ((i + 1) % 3) + 1 ); AddButton( 10, 360, 4005, 4007, 0, GumpButtonType.Page, ((i + 1) % pages ) + 1 );
for ( int j = 0; j < 18; ++j ) for ( int j = 0; j < signsPerPage && totalSigns - ( signsPerPage * i ) - j > 0; ++j )
{ {
int x = 30 + ((j % 6) * 60); int x = 30 + ((j % 6) * 60);
int y = 130 + ((j / 6) * 60); int y = 130 + ((j / 6) * 60);
AddButton( x, y, 4005, 4007, GetButtonID( 9, index ), GumpButtonType.Reply, 0 ); AddButton( x, y, 4005, 4007, GetButtonID( 9, index ), GumpButtonType.Reply, 0 );
AddItem( x + 20, y, 2980 + (index++ * 2) ); AddItem( x + 20, y, _HouseSigns[index++] );
} }
} }
@ -1305,9 +1324,9 @@ namespace Server.Gumps
} }
case 9: case 9:
{ {
if ( isOwner && m_House.Public && index >= 0 && index < 54 ) if ( isOwner && m_House.Public && index >= 0 && index < _HouseSigns.Count )
{ {
m_House.ChangeSignType( 2980 + (index * 2) ); m_House.ChangeSignType( _HouseSigns[index] );
from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Customize, from, m_House ) ); from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Customize, from, m_House ) );
} }

View file

@ -1011,6 +1011,13 @@ namespace Server.Items
canSwing = ( sp == null || !sp.IsCasting || !sp.BlocksMovement ); canSwing = ( sp == null || !sp.IsCasting || !sp.BlocksMovement );
} }
if ( canSwing )
{
PlayerMobile p = attacker as PlayerMobile;
canSwing = ( p == null || p.PeacedUntil <= DateTime.Now );
}
} }
if ( canSwing && attacker.HarmfulCheck( defender ) ) if ( canSwing && attacker.HarmfulCheck( defender ) )

View file

@ -21,6 +21,7 @@ namespace Server.Items
public override SkillName AccuracySkill{ get{ return SkillName.Archery; } } public override SkillName AccuracySkill{ get{ return SkillName.Archery; } }
private Timer m_RecoveryTimer; // so we don't start too many timers
private bool m_Balanced; private bool m_Balanced;
private int m_Velocity; private int m_Velocity;
@ -120,7 +121,33 @@ namespace Server.Items
public override void OnMiss( Mobile attacker, Mobile defender ) public override void OnMiss( Mobile attacker, Mobile defender )
{ {
if ( attacker.Player && 0.4 >= Utility.RandomDouble() ) if ( attacker.Player && 0.4 >= Utility.RandomDouble() )
{
if ( Core.SE )
{
PlayerMobile p = attacker as PlayerMobile;
if ( p != null )
{
Type ammo = AmmoType;
if ( p.RecoverableAmmo.ContainsKey( ammo ) )
p.RecoverableAmmo[ ammo ]++;
else
p.RecoverableAmmo.Add( ammo, 1 );
if ( !p.Warmode )
{
if ( m_RecoveryTimer == null )
m_RecoveryTimer = Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerCallback( p.RecoverAmmo ) );
if ( !m_RecoveryTimer.Running )
m_RecoveryTimer.Start();
}
}
}
else
Ammo.MoveToWorld( new Point3D( defender.X + Utility.RandomMinMax( -1, 1 ), defender.Y + Utility.RandomMinMax( -1, 1 ), defender.Z ), defender.Map ); Ammo.MoveToWorld( new Point3D( defender.X + Utility.RandomMinMax( -1, 1 ), defender.Y + Utility.RandomMinMax( -1, 1 ), defender.Z ), defender.Map );
}
base.OnMiss( attacker, defender ); base.OnMiss( attacker, defender );
} }

View file

@ -224,10 +224,19 @@ namespace Server
private static Type[] m_PaladinScrollTypes = new Type[0]; private static Type[] m_PaladinScrollTypes = new Type[0];
private static Type[] m_ArcaneScrollTypes = new Type[]
{
typeof( ArcaneCircleScroll ), typeof ( GiftOfRenewalScroll ), typeof( ImmolatingWeaponScroll ), typeof( AttuneWeaponScroll ),
typeof( ThunderstormScroll ), typeof( NatureFuryScroll ), typeof( ReaperFormScroll ), typeof( WildfireScroll ),
typeof( EssenceOfWindScroll ), typeof( DryadAllureScroll ), typeof( EtherealVoyageScroll ), typeof( WordOfDeathScroll ),
typeof( GiftOfLifeScroll ), typeof( ArcaneEmpowermentScroll )
};
public static Type[] RegularScrollTypes{ get{ return m_RegularScrollTypes; } } public static Type[] RegularScrollTypes{ get{ return m_RegularScrollTypes; } }
public static Type[] NecromancyScrollTypes{ get{ return m_NecromancyScrollTypes; } } public static Type[] NecromancyScrollTypes{ get{ return m_NecromancyScrollTypes; } }
public static Type[] SENecromancyScrollTypes{ get{ return m_SENecromancyScrollTypes; } } public static Type[] SENecromancyScrollTypes{ get{ return m_SENecromancyScrollTypes; } }
public static Type[] PaladinScrollTypes{ get{ return m_PaladinScrollTypes; } } public static Type[] PaladinScrollTypes{ get{ return m_PaladinScrollTypes; } }
public static Type[] ArcaneScrollTypes{ get{ return m_ArcaneScrollTypes; } }
private static Type[] m_GrimmochJournalTypes = new Type[] private static Type[] m_GrimmochJournalTypes = new Type[]
{ {
@ -589,6 +598,7 @@ namespace Server
case SpellbookType.Regular: types = m_RegularScrollTypes; break; case SpellbookType.Regular: types = m_RegularScrollTypes; break;
case SpellbookType.Necromancer: types = (Core.SE ? m_SENecromancyScrollTypes : m_NecromancyScrollTypes ); break; case SpellbookType.Necromancer: types = (Core.SE ? m_SENecromancyScrollTypes : m_NecromancyScrollTypes ); break;
case SpellbookType.Paladin: types = m_PaladinScrollTypes; break; case SpellbookType.Paladin: types = m_PaladinScrollTypes; break;
case SpellbookType.Arcanist: types = m_ArcaneScrollTypes; break;
} }
return Construct( types, Utility.RandomMinMax( minIndex, maxIndex ) ) as SpellScroll; return Construct( types, Utility.RandomMinMax( minIndex, maxIndex ) ) as SpellScroll;

View file

@ -239,6 +239,17 @@ namespace Server
}; };
#endregion #endregion
#region ML definitions
public static readonly LootPack MlRich = new LootPack( new LootPackEntry[]
{
new LootPackEntry( true, Gold, 100.00, "4d50+450" ),
new LootPackEntry( false, AosMagicItemsRichType1, 100.00, 1, 3, 0, 75 ),
new LootPackEntry( false, AosMagicItemsRichType1, 80.00, 1, 3, 0, 75 ),
new LootPackEntry( false, AosMagicItemsRichType1, 60.00, 1, 5, 0, 100 ),
new LootPackEntry( false, Instruments, 1.00, 1 )
} );
#endregion
#region SE definitions #region SE definitions
public static readonly LootPack SePoor = new LootPack( new LootPackEntry[] public static readonly LootPack SePoor = new LootPack( new LootPackEntry[]
{ {

View file

@ -1222,6 +1222,9 @@ namespace Server.Mobiles
if ( m_ReceivedHonorContext != null ) if ( m_ReceivedHonorContext != null )
m_ReceivedHonorContext.OnTargetDamaged( from, amount ); m_ReceivedHonorContext.OnTargetDamaged( from, amount );
if ( willKill && from is PlayerMobile )
Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerCallback( ((PlayerMobile) from).RecoverAmmo ) );
base.OnDamage( amount, from, willKill ); base.OnDamage( amount, from, willKill );
} }
@ -3507,6 +3510,14 @@ namespace Server.Mobiles
PackItem( Loot.RandomPotion() ); PackItem( Loot.RandomPotion() );
} }
public void PackArcanceScroll( double chance )
{
if ( !Core.ML || chance <= Utility.RandomDouble() )
return;
PackItem( Loot.Construct( Loot.ArcaneScrollTypes ) );
}
public void PackNecroScroll( int index ) public void PackNecroScroll( int index )
{ {
if ( !Core.AOS || 0.05 <= Utility.RandomDouble() ) if ( !Core.AOS || 0.05 <= Utility.RandomDouble() )

View file

@ -106,7 +106,8 @@ namespace Server
typeof( Silvani ), typeof( Silvani ),
typeof( Unicorn ), typeof( Unicorn ),
typeof( Wisp ), typeof( Wisp ),
typeof( Treefellow ) typeof( Treefellow ),
typeof( MLDryad )
}, },
new Type[] new Type[]
{ {

View file

@ -1,86 +1,160 @@
using System; using System;
using System.Collections; using Server.Engines.Plants;
using Server.Items;
using Server.Targeting;
using Server.Misc;
namespace Server.Mobiles namespace Server.Mobiles
{ {
[CorpseName("a dryad corpse")] [CorpseName( "a dryad's corpse" )]
public class MLDryad : BaseCreature public class MLDryad : BaseCreature
{ {
public override bool InitialInnocent { get { return true; } } public override bool InitialInnocent { get { return true; } }
/* VULNERABLE TO FEY SLAYER! public override OppositionGroup OppositionGroup
* These creatures should be able to cast Area Peace as
* well as cause Players' armor to drop into their backpack*/
public override WeaponAbility GetWeaponAbility()
{ {
return WeaponAbility.Disrobe; get { return OppositionGroup.FeyAndUndead; }
} }
[Constructable] [Constructable]
public MLDryad() public MLDryad() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 )
: base(AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4) // NEED TO CHECK
{ {
Name = "a dryad"; Name = "a dryad";
Body = 266; Body = 266;
BaseSoundID = 0x57B; BaseSoundID = 0x57B;
SetStr(132, 149); SetStr( 132, 149 );
SetDex(152, 168); SetDex( 152, 168 );
SetInt(251, 280); SetInt( 251, 280 );
SetHits(304, 321); SetHits( 304, 321 );
SetDamage(11, 20); SetDamage( 11, 20 );
SetDamageType(ResistanceType.Physical, 100); SetDamageType( ResistanceType.Physical, 100 );
SetResistance(ResistanceType.Physical, 40, 50); SetResistance( ResistanceType.Physical, 40, 50 );
SetResistance(ResistanceType.Fire, 15, 25); SetResistance( ResistanceType.Fire, 15, 25 );
SetResistance(ResistanceType.Cold, 40, 45); SetResistance( ResistanceType.Cold, 40, 45 );
SetResistance(ResistanceType.Poison, 30, 40); SetResistance( ResistanceType.Poison, 30, 40 );
SetResistance(ResistanceType.Energy, 25, 35); SetResistance( ResistanceType.Energy, 25, 35 );
SetSkill(SkillName.Meditation, 80.9, 89.9); SetSkill( SkillName.Meditation, 80.0, 90.0 );
SetSkill(SkillName.EvalInt, 70.3, 78.7); SetSkill( SkillName.EvalInt, 70.0, 80.0 );
SetSkill(SkillName.Magery, 70.7, 75.7); SetSkill( SkillName.Magery, 70.0, 80.0 );
SetSkill(SkillName.Anatomy, 0); SetSkill( SkillName.Anatomy, 0 );
SetSkill(SkillName.MagicResist, 101.7, 117.1); SetSkill( SkillName.MagicResist, 100.0, 120.0 );
SetSkill(SkillName.Tactics, 71.7, 79.8); SetSkill( SkillName.Tactics, 70.0, 80.0 );
SetSkill(SkillName.Wrestling, 72.5, 79.5); SetSkill( SkillName.Wrestling, 70.0, 80.0 );
Fame = 5000; Fame = 5000;
Karma = 5000; Karma = 5000;
VirtualArmor = 28; // Don't know what it should be VirtualArmor = 28; // Don't know what it should be
if ( Core.ML && Utility.RandomDouble() < .33 ) if ( Core.ML && Utility.RandomDouble() < .60 )
PackItem( Engines.Plants.Seed.RandomPeculiarSeed(1) ); PackItem( Seed.RandomPeculiarSeed( 1 ) );
PackArcanceScroll( 0.05 );
} }
public override void GenerateLoot() public override void GenerateLoot()
{ {
AddLoot(LootPack.Rich); // Need to verify AddLoot( LootPack.MlRich );
} }
public override int Meat { get { return 1; } } public override int Meat { get { return 1; } }
public MLDryad(Serial serial) : base(serial) public override void OnThink()
{
base.OnThink();
AreaPeace();
AreaUndress();
}
#region Area Peace
private DateTime m_NextPeace;
public void AreaPeace()
{
if ( Combatant == null || Deleted || !Alive || m_NextPeace > DateTime.Now || 0.1 < Utility.RandomDouble() )
return;
TimeSpan duration = TimeSpan.FromSeconds( Utility.RandomMinMax( 20, 80 ) );
foreach ( Mobile m in GetMobilesInRange( RangePerception ) )
{
PlayerMobile p = m as PlayerMobile;
if ( IsValidTarget( p ) )
{
p.PeacedUntil = DateTime.Now + duration;
p.SendLocalizedMessage( 1072065 ); // You gaze upon the dryad's beauty, and forget to continue battling!
p.FixedParticles( 0x376A, 1, 20, 0x7F5, EffectLayer.Waist );
p.Combatant = null;
}
}
m_NextPeace = DateTime.Now + TimeSpan.FromSeconds( 10 );
PlaySound( 0x1D3 );
}
public bool IsValidTarget( PlayerMobile m )
{
if ( m != null && m.PeacedUntil < DateTime.Now && !m.Hidden && m.AccessLevel == AccessLevel.Player && CanBeHarmful( m ) )
return true;
return false;
}
#endregion
#region Undress
private DateTime m_NextUndress;
public void AreaUndress()
{
if ( Combatant == null || Deleted || !Alive || m_NextUndress > DateTime.Now || 0.005 < Utility.RandomDouble() )
return;
foreach ( Mobile m in GetMobilesInRange( RangePerception ) )
{
if ( m != null && m.Player && !m.Female && !m.Hidden && m.AccessLevel == AccessLevel.Player && CanBeHarmful( m ) )
{
UndressItem( m, Layer.OuterTorso );
UndressItem( m, Layer.InnerTorso );
UndressItem( m, Layer.MiddleTorso );
UndressItem( m, Layer.Pants );
UndressItem( m, Layer.Shirt );
m.SendLocalizedMessage( 1072197 ); // The dryad's beauty makes your blood race. Your clothing is too confining.
}
}
m_NextUndress = DateTime.Now + TimeSpan.FromMinutes( 1 );
}
public void UndressItem( Mobile m, Layer layer )
{
Item item = m.FindItemOnLayer( layer );
if ( item != null && item.Movable )
m.PlaceInBackpack( item );
}
#endregion
public MLDryad( Serial serial ) : base( serial )
{ {
} }
public override void Serialize(GenericWriter writer) public override void Serialize( GenericWriter writer )
{ {
base.Serialize(writer); base.Serialize( writer );
writer.Write((int)0);
writer.Write( (int) 0 ); // version
} }
public override void Deserialize(GenericReader reader) public override void Deserialize( GenericReader reader )
{ {
base.Deserialize(reader); base.Deserialize( reader );
int version = reader.ReadInt(); int version = reader.ReadInt();
} }
} }

View file

@ -1,83 +1,233 @@
using System; using System;
using System.Collections; using System.Collections.Generic;
using Server.Items;
using Server.Targeting;
using Server.Misc;
namespace Server.Mobiles namespace Server.Mobiles
{ {
[CorpseName("a satyr corpse")] [CorpseName( "a satyr's corpse" )]
public class Satyr : BaseCreature public class Satyr : BaseCreature
{ {
/* These creatures should be able to cast Area Peace as
* well as cause Players' armor to drop into their backpack
*/
public override WeaponAbility GetWeaponAbility()
{
return WeaponAbility.Disrobe;
}
[Constructable] [Constructable]
public Satyr() public Satyr() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 )
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK
{ {
Name = "a satyr"; Name = "a satyr";
Body = 271; Body = 271;
BaseSoundID = 0x586; BaseSoundID = 0x586;
SetStr(177, 195); SetStr( 177, 195 );
SetDex(251, 269); SetDex( 251, 269 );
SetInt(153, 170); SetInt( 153, 170 );
SetHits(353, 399); SetHits( 350, 400 );
SetDamage(13, 24); SetDamage( 13, 24 );
SetDamageType(ResistanceType.Physical, 100); SetDamageType( ResistanceType.Physical, 100 );
SetResistance(ResistanceType.Physical, 55, 60); SetResistance( ResistanceType.Physical, 55, 60 );
SetResistance(ResistanceType.Fire, 26, 35); SetResistance( ResistanceType.Fire, 25, 35 );
SetResistance(ResistanceType.Cold, 30, 40); SetResistance( ResistanceType.Cold, 30, 40 );
SetResistance(ResistanceType.Poison, 30, 40); SetResistance( ResistanceType.Poison, 30, 40 );
SetResistance(ResistanceType.Energy, 30, 40); SetResistance( ResistanceType.Energy, 30, 40 );
SetSkill(SkillName.Poisoning, 0); SetSkill( SkillName.MagicResist, 55.0, 65.0 );
SetSkill(SkillName.Meditation, 0); SetSkill( SkillName.Tactics, 80.0, 100.0 );
SetSkill(SkillName.EvalInt, 0); SetSkill( SkillName.Wrestling, 80.0, 100.0 );
SetSkill(SkillName.Magery, 0);
SetSkill(SkillName.Anatomy, 0);
SetSkill(SkillName.MagicResist, 55.3, 64.3);
SetSkill(SkillName.Tactics, 80.1, 99.3);
SetSkill(SkillName.Wrestling, 80.6, 100.0);
Fame = 5000; Fame = 5000;
Karma = -5000; Karma = 0;
VirtualArmor = 28; // Don't know what it should be VirtualArmor = 28; // Don't know what it should be
}
PackArcanceScroll( 0.05 );
}
public override void GenerateLoot() public override void GenerateLoot()
{ {
AddLoot(LootPack.Rich); // Need to verify AddLoot( LootPack.MlRich );
} }
public override void OnThink()
{
base.OnThink();
Peace( Combatant );
Undress( Combatant );
Suppress( Combatant );
Provoke( Combatant );
}
#region Peace
private DateTime m_NextPeace;
public void Peace( Mobile target )
{
if ( target == null || Deleted || !Alive || m_NextPeace > DateTime.Now || 0.1 < Utility.RandomDouble() )
return;
PlayerMobile p = target as PlayerMobile;
if ( p != null && p.PeacedUntil < DateTime.Now && !p.Hidden && CanBeHarmful( p ) )
{
p.PeacedUntil = DateTime.Now + TimeSpan.FromMinutes( 1 );
p.SendLocalizedMessage( 500616 ); // You hear lovely music, and forget to continue battling!
p.FixedParticles( 0x376A, 1, 32, 0x15BD, EffectLayer.Waist );
p.Combatant = null;
PlaySound( 0x58D );
}
m_NextPeace = DateTime.Now + TimeSpan.FromSeconds( 10 );
}
#endregion
#region Suppress
private static Dictionary<Mobile, Timer> m_Suppressed = new Dictionary<Mobile, Timer>();
private DateTime m_NextSuppress;
public void Suppress( Mobile target )
{
if ( target == null || m_Suppressed.ContainsKey( target ) || Deleted || !Alive || m_NextSuppress > DateTime.Now || 0.1 < Utility.RandomDouble() )
return;
TimeSpan delay = TimeSpan.FromSeconds( Utility.RandomMinMax( 20, 80 ) );
if ( !target.Hidden && CanBeHarmful( target ) )
{
target.SendLocalizedMessage( 1072061 ); // You hear jarring music, suppressing your strength.
for ( int i = 0; i < target.Skills.Length; i++ )
{
Skill s = target.Skills[ i ];
target.AddSkillMod( new TimedSkillMod( s.SkillName, true, s.Base * -0.28, delay ) );
}
int count = (int) Math.Round( delay.TotalSeconds / 1.25 );
Timer timer = new AnimateTimer( target, count );
m_Suppressed.Add( target, timer );
timer.Start();
PlaySound( 0x58C );
}
m_NextSuppress = DateTime.Now + TimeSpan.FromSeconds( 10 );
}
public static void SuppressRemove( Mobile target )
{
if ( target != null && m_Suppressed.ContainsKey( target ) )
{
Timer timer = m_Suppressed[ target ];
if ( timer != null || timer.Running )
timer.Stop();
m_Suppressed.Remove( target );
}
}
private class AnimateTimer : Timer
{
private Mobile m_Owner;
private int m_Count;
public AnimateTimer( Mobile owner, int count ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.25 ) )
{
m_Owner = owner;
m_Count = count;
}
protected override void OnTick()
{
if ( m_Owner.Deleted || !m_Owner.Alive || m_Count-- < 0 )
{
SuppressRemove( m_Owner );
}
else
m_Owner.FixedParticles( 0x376A, 1, 32, 0x15BD, EffectLayer.Waist );
}
}
#endregion
#region Undress
private DateTime m_NextUndress;
public void Undress( Mobile target )
{
if ( target == null || Deleted || !Alive || m_NextUndress > DateTime.Now || 0.005 < Utility.RandomDouble() )
return;
if ( target.Player && target.Female && !target.Hidden && CanBeHarmful( target ) )
{
UndressItem( target, Layer.OuterTorso );
UndressItem( target, Layer.InnerTorso );
UndressItem( target, Layer.MiddleTorso );
UndressItem( target, Layer.Pants );
UndressItem( target, Layer.Shirt );
target.SendLocalizedMessage( 1072196 ); // The satyr's music makes your blood race. Your clothing is too confining.
}
m_NextUndress = DateTime.Now + TimeSpan.FromMinutes( 1 );
}
public void UndressItem( Mobile m, Layer layer )
{
Item item = m.FindItemOnLayer( layer );
if ( item != null && item.Movable )
m.PlaceInBackpack( item );
}
#endregion
#region Provoke
private DateTime m_NextProvoke;
public void Provoke( Mobile target )
{
if ( target == null || Deleted || !Alive || m_NextProvoke > DateTime.Now || 0.05 < Utility.RandomDouble() )
return;
foreach ( Mobile m in GetMobilesInRange( RangePerception ) )
{
if ( m is BaseCreature )
{
BaseCreature c = (BaseCreature) m;
if ( c == this || c == target || c.Unprovokable || c.IsParagon || c.BardProvoked || c.AccessLevel != AccessLevel.Player || !c.CanBeHarmful( target ) )
continue;
c.Provoke( this, target, true );
if ( target.Player )
target.SendLocalizedMessage( 1072062 ); // You hear angry music, and start to fight.
PlaySound( 0x58A );
break;
}
}
m_NextProvoke = DateTime.Now + TimeSpan.FromSeconds( 10 );
}
#endregion
public override int Meat { get { return 1; } } public override int Meat { get { return 1; } }
public Satyr(Serial serial) : base(serial) public Satyr( Serial serial ) : base( serial )
{ {
} }
public override void Serialize(GenericWriter writer) public override void Serialize( GenericWriter writer )
{ {
base.Serialize(writer); base.Serialize( writer );
writer.Write((int)0);
writer.Write( (int) 0 ); // version
} }
public override void Deserialize(GenericReader reader) public override void Deserialize( GenericReader reader )
{ {
base.Deserialize(reader); base.Deserialize( reader );
int version = reader.ReadInt(); int version = reader.ReadInt();
} }
} }

View file

@ -14,7 +14,7 @@ namespace Server.Mobiles
public SummonedDaemon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) public SummonedDaemon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 )
{ {
Name = NameList.RandomName( "daemon" ); Name = NameList.RandomName( "daemon" );
Body = 9; Body = Core.AOS ? 10 : 9;
BaseSoundID = 357; BaseSoundID = 357;
SetStr( 200 ); SetStr( 200 );

View file

@ -313,6 +313,62 @@ namespace Server.Mobiles
} }
#endregion #endregion
#region Auto Arrow Recovery
private Dictionary<Type, int> m_RecoverableAmmo = new Dictionary<Type,int>();
public Dictionary<Type, int> RecoverableAmmo
{
get { return m_RecoverableAmmo; }
}
public void RecoverAmmo()
{
if ( Core.SE && Alive )
{
foreach ( KeyValuePair<Type, int> kvp in m_RecoverableAmmo )
{
if ( kvp.Value > 0 )
{
Item ammo = null;
try
{
ammo = Activator.CreateInstance( kvp.Key ) as Item;
}
catch
{
}
if ( ammo != null )
{
string name = ammo.Name;
ammo.Amount = kvp.Value;
if ( name == null )
{
if ( ammo is Arrow )
name = "arrow";
else if ( ammo is Bolt )
name = "bolt";
}
if ( name != null && ammo.Amount > 1 )
name = String.Format( "{0}s", name );
if ( name == null )
name = String.Format( "#{0}", ammo.LabelNumber );
PlaceInBackpack( ammo );
SendLocalizedMessage( 1073504, String.Format( "{0}\t{1}", ammo.Amount, name ) ); // You recover ~1_NUM~ ~2_AMMO~.
}
}
}
m_RecoverableAmmo.Clear();
}
}
#endregion
private DateTime m_AnkhNextUse; private DateTime m_AnkhNextUse;
[CommandProperty( AccessLevel.GameMaster )] [CommandProperty( AccessLevel.GameMaster )]
@ -322,6 +378,15 @@ namespace Server.Mobiles
set{ m_AnkhNextUse = value; } set{ m_AnkhNextUse = value; }
} }
private DateTime m_PeacedUntil;
[CommandProperty( AccessLevel.GameMaster )]
public DateTime PeacedUntil
{
get { return m_PeacedUntil; }
set { m_PeacedUntil = value; }
}
#region Scroll of Alacrity #region Scroll of Alacrity
private DateTime m_AcceleratedStart; private DateTime m_AcceleratedStart;
@ -342,7 +407,6 @@ namespace Server.Mobiles
} }
#endregion #endregion
public static Direction GetDirection4( Point3D from, Point3D to ) public static Direction GetDirection4( Point3D from, Point3D to )
{ {
int dx = from.X - to.X; int dx = from.X - to.X;
@ -1833,6 +1897,9 @@ namespace Server.Mobiles
if ( m_SentHonorContext != null ) if ( m_SentHonorContext != null )
m_SentHonorContext.OnSourceDamaged( from, amount ); m_SentHonorContext.OnSourceDamaged( from, amount );
if ( willKill && from is PlayerMobile )
Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerCallback( ((PlayerMobile) from).RecoverAmmo ) );
base.OnDamage( amount, from, willKill ); base.OnDamage( amount, from, willKill );
} }
@ -1862,6 +1929,12 @@ namespace Server.Mobiles
} }
} }
public override void OnWarmodeChanged()
{
if ( !Warmode )
Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerCallback( RecoverAmmo ) );
}
private Mobile m_InsuranceAward; private Mobile m_InsuranceAward;
private int m_InsuranceCost; private int m_InsuranceCost;
private int m_InsuranceBonus; private int m_InsuranceBonus;
@ -1890,6 +1963,8 @@ namespace Server.Mobiles
if ( m_SentHonorContext != null ) if ( m_SentHonorContext != null )
m_SentHonorContext.OnSourceKilled(); m_SentHonorContext.OnSourceKilled();
RecoverAmmo();
return base.OnBeforeDeath(); return base.OnBeforeDeath();
} }
@ -2417,6 +2492,12 @@ namespace Server.Mobiles
switch ( version ) switch ( version )
{ {
case 28:
{
m_PeacedUntil = reader.ReadDateTime();
goto case 27;
}
case 27: case 27:
{ {
m_AnkhNextUse = reader.ReadDateTime(); m_AnkhNextUse = reader.ReadDateTime();
@ -2710,8 +2791,9 @@ namespace Server.Mobiles
base.Serialize( writer ); base.Serialize( writer );
writer.Write( (int) 27 ); // version writer.Write( (int) 28 ); // version
writer.Write( (DateTime) m_PeacedUntil );
writer.Write( (DateTime) m_AnkhNextUse ); writer.Write( (DateTime) m_AnkhNextUse );
writer.Write( m_AutoStabled, true ); writer.Write( m_AutoStabled, true );

View file

@ -498,6 +498,10 @@ namespace Server.Spells
{ {
m_Caster.SendLocalizedMessage( 502644 ); // You have not yet recovered from casting a spell. m_Caster.SendLocalizedMessage( 502644 ); // You have not yet recovered from casting a spell.
} }
else if ( m_Caster is PlayerMobile && ( (PlayerMobile) m_Caster ).PeacedUntil > DateTime.Now )
{
m_Caster.SendLocalizedMessage( 1072060 ); // You cannot cast a spell while calmed.
}
else if ( m_Caster.Mana >= ScaleMana( GetMana() ) ) else if ( m_Caster.Mana >= ScaleMana( GetMana() ) )
{ {
if ( m_Caster.Spell == null && m_Caster.CheckSpellCast( this ) && CheckCast() && m_Caster.Region.OnBeginSpellCast( m_Caster, this ) ) if ( m_Caster.Spell == null && m_Caster.CheckSpellCast( this ) && CheckCast() && m_Caster.Region.OnBeginSpellCast( m_Caster, this ) )
@ -727,6 +731,11 @@ namespace Server.Spells
m_Caster.SendLocalizedMessage( 502646 ); // You cannot cast a spell while frozen. m_Caster.SendLocalizedMessage( 502646 ); // You cannot cast a spell while frozen.
DoFizzle(); DoFizzle();
} }
else if ( m_Caster is PlayerMobile && ((PlayerMobile) m_Caster).PeacedUntil > DateTime.Now )
{
m_Caster.SendLocalizedMessage( 1072060 ); // You cannot cast a spell while calmed.
DoFizzle();
}
else if ( CheckFizzle() ) else if ( CheckFizzle() )
{ {
m_Caster.Mana -= mana; m_Caster.Mana -= mana;

View file

@ -987,6 +987,11 @@ namespace Server.Spells
//from.SendMessage(String.Format("You Leeched {0} Mana", manaLeech)); //from.SendMessage(String.Format("You Leeched {0} Mana", manaLeech));
} }
} }
if ( context != null && context.Type == typeof( VampiricEmbraceSpell ) )
{
from.Hits += AOS.Scale( damageGiven, 20 );
from.PlaySound( 0x44D );
}
} }
public static void Heal( int amount, Mobile target, Mobile from ) public static void Heal( int amount, Mobile target, Mobile from )

View file

@ -1,4 +1,6 @@
using System; using System;
using Server.Misc;
using Server.Items;
using Server.Mobiles; using Server.Mobiles;
using Server.Network; using Server.Network;
using Server.Targeting; using Server.Targeting;
@ -7,6 +9,8 @@ namespace Server.Spells.Eighth
{ {
public class SummonDaemonSpell : MagerySpell public class SummonDaemonSpell : MagerySpell
{ {
private BaseCreature m_Daemon = new SummonedDaemon();
private static SpellInfo m_Info = new SpellInfo( private static SpellInfo m_Info = new SpellInfo(
"Summon Daemon", "Kal Vas Xen Corp", "Summon Daemon", "Kal Vas Xen Corp",
269, 269,
@ -45,7 +49,10 @@ namespace Server.Spells.Eighth
TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 ); TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 );
if ( Core.AOS ) if ( Core.AOS )
SpellHelper.Summon( new SummonedDaemon(), Caster, 0x216, duration, false, false ); {
SpellHelper.Summon( m_Daemon, Caster, 0x216, duration, false, false );
m_Daemon.FixedParticles(0x3728, 8, 20, 5042, EffectLayer.Head );
}
else else
SpellHelper.Summon( new Daemon(), Caster, 0x216, duration, false, false ); SpellHelper.Summon( new Daemon(), Caster, 0x216, duration, false, false );
} }