- 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:
parent
37043076e0
commit
cd7c2becf7
14 changed files with 511 additions and 98 deletions
|
|
@ -190,6 +190,8 @@ namespace Server.Gumps
|
|||
660, 666, 672, 898, 970,
|
||||
974, 982
|
||||
};
|
||||
|
||||
private static List<int> _HouseSigns = new List<int>();
|
||||
|
||||
public HouseGumpAOS( HouseGumpPageAOS page, Mobile from, BaseHouse house ) : base( 50, 40 )
|
||||
{
|
||||
|
|
@ -486,20 +488,37 @@ namespace Server.Gumps
|
|||
case HouseGumpPageAOS.ChangeSign:
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
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 < 3; ++i )
|
||||
for ( int i = 0; i < pages; ++i )
|
||||
{
|
||||
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 y = 130 + ((j / 6) * 60);
|
||||
|
||||
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:
|
||||
{
|
||||
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 ) );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1011,6 +1011,13 @@ namespace Server.Items
|
|||
|
||||
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 ) )
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ namespace Server.Items
|
|||
|
||||
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 int m_Velocity;
|
||||
|
||||
|
|
@ -120,7 +121,33 @@ namespace Server.Items
|
|||
public override void OnMiss( Mobile attacker, Mobile defender )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
base.OnMiss( attacker, defender );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,10 +224,19 @@ namespace Server
|
|||
|
||||
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[] NecromancyScrollTypes{ get{ return m_NecromancyScrollTypes; } }
|
||||
public static Type[] SENecromancyScrollTypes{ get{ return m_SENecromancyScrollTypes; } }
|
||||
public static Type[] PaladinScrollTypes{ get{ return m_PaladinScrollTypes; } }
|
||||
public static Type[] ArcaneScrollTypes{ get{ return m_ArcaneScrollTypes; } }
|
||||
|
||||
private static Type[] m_GrimmochJournalTypes = new Type[]
|
||||
{
|
||||
|
|
@ -589,6 +598,7 @@ namespace Server
|
|||
case SpellbookType.Regular: types = m_RegularScrollTypes; break;
|
||||
case SpellbookType.Necromancer: types = (Core.SE ? m_SENecromancyScrollTypes : m_NecromancyScrollTypes ); break;
|
||||
case SpellbookType.Paladin: types = m_PaladinScrollTypes; break;
|
||||
case SpellbookType.Arcanist: types = m_ArcaneScrollTypes; break;
|
||||
}
|
||||
|
||||
return Construct( types, Utility.RandomMinMax( minIndex, maxIndex ) ) as SpellScroll;
|
||||
|
|
|
|||
|
|
@ -239,6 +239,17 @@ namespace Server
|
|||
};
|
||||
#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
|
||||
public static readonly LootPack SePoor = new LootPack( new LootPackEntry[]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1222,6 +1222,9 @@ namespace Server.Mobiles
|
|||
if ( m_ReceivedHonorContext != null )
|
||||
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 );
|
||||
}
|
||||
|
||||
|
|
@ -3507,6 +3510,14 @@ namespace Server.Mobiles
|
|||
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 )
|
||||
{
|
||||
if ( !Core.AOS || 0.05 <= Utility.RandomDouble() )
|
||||
|
|
|
|||
|
|
@ -106,7 +106,8 @@ namespace Server
|
|||
typeof( Silvani ),
|
||||
typeof( Unicorn ),
|
||||
typeof( Wisp ),
|
||||
typeof( Treefellow )
|
||||
typeof( Treefellow ),
|
||||
typeof( MLDryad )
|
||||
},
|
||||
new Type[]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,86 +1,160 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using Server.Items;
|
||||
using Server.Targeting;
|
||||
using Server.Misc;
|
||||
using Server.Engines.Plants;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a dryad corpse")]
|
||||
[CorpseName( "a dryad's corpse" )]
|
||||
public class MLDryad : BaseCreature
|
||||
{
|
||||
public override bool InitialInnocent { get { return true; } }
|
||||
|
||||
/* VULNERABLE TO FEY SLAYER!
|
||||
* These creatures should be able to cast Area Peace as
|
||||
* well as cause Players' armor to drop into their backpack*/
|
||||
|
||||
public override WeaponAbility GetWeaponAbility()
|
||||
public override OppositionGroup OppositionGroup
|
||||
{
|
||||
return WeaponAbility.Disrobe;
|
||||
get { return OppositionGroup.FeyAndUndead; }
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public MLDryad()
|
||||
: base(AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4) // NEED TO CHECK
|
||||
public MLDryad() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 )
|
||||
{
|
||||
Name = "a dryad";
|
||||
Body = 266;
|
||||
BaseSoundID = 0x57B;
|
||||
|
||||
SetStr(132, 149);
|
||||
SetDex(152, 168);
|
||||
SetInt(251, 280);
|
||||
SetStr( 132, 149 );
|
||||
SetDex( 152, 168 );
|
||||
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.Fire, 15, 25);
|
||||
SetResistance(ResistanceType.Cold, 40, 45);
|
||||
SetResistance(ResistanceType.Poison, 30, 40);
|
||||
SetResistance(ResistanceType.Energy, 25, 35);
|
||||
SetResistance( ResistanceType.Physical, 40, 50 );
|
||||
SetResistance( ResistanceType.Fire, 15, 25 );
|
||||
SetResistance( ResistanceType.Cold, 40, 45 );
|
||||
SetResistance( ResistanceType.Poison, 30, 40 );
|
||||
SetResistance( ResistanceType.Energy, 25, 35 );
|
||||
|
||||
SetSkill(SkillName.Meditation, 80.9, 89.9);
|
||||
SetSkill(SkillName.EvalInt, 70.3, 78.7);
|
||||
SetSkill(SkillName.Magery, 70.7, 75.7);
|
||||
SetSkill(SkillName.Anatomy, 0);
|
||||
SetSkill(SkillName.MagicResist, 101.7, 117.1);
|
||||
SetSkill(SkillName.Tactics, 71.7, 79.8);
|
||||
SetSkill(SkillName.Wrestling, 72.5, 79.5);
|
||||
SetSkill( SkillName.Meditation, 80.0, 90.0 );
|
||||
SetSkill( SkillName.EvalInt, 70.0, 80.0 );
|
||||
SetSkill( SkillName.Magery, 70.0, 80.0 );
|
||||
SetSkill( SkillName.Anatomy, 0 );
|
||||
SetSkill( SkillName.MagicResist, 100.0, 120.0 );
|
||||
SetSkill( SkillName.Tactics, 70.0, 80.0 );
|
||||
SetSkill( SkillName.Wrestling, 70.0, 80.0 );
|
||||
|
||||
Fame = 5000;
|
||||
Karma = 5000;
|
||||
|
||||
VirtualArmor = 28; // Don't know what it should be
|
||||
|
||||
if ( Core.ML && Utility.RandomDouble() < .33 )
|
||||
PackItem( Engines.Plants.Seed.RandomPeculiarSeed(1) );
|
||||
if ( Core.ML && Utility.RandomDouble() < .60 )
|
||||
PackItem( Seed.RandomPeculiarSeed( 1 ) );
|
||||
|
||||
PackArcanceScroll( 0.05 );
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.Rich); // Need to verify
|
||||
AddLoot( LootPack.MlRich );
|
||||
}
|
||||
|
||||
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);
|
||||
writer.Write((int)0);
|
||||
base.Serialize( writer );
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,83 +1,233 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using Server.Items;
|
||||
using Server.Targeting;
|
||||
using Server.Misc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a satyr corpse")]
|
||||
[CorpseName( "a satyr's corpse" )]
|
||||
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]
|
||||
public Satyr()
|
||||
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) // NEED TO CHECK
|
||||
public Satyr() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 )
|
||||
{
|
||||
Name = "a satyr";
|
||||
Body = 271;
|
||||
BaseSoundID = 0x586;
|
||||
BaseSoundID = 0x586;
|
||||
|
||||
SetStr(177, 195);
|
||||
SetDex(251, 269);
|
||||
SetInt(153, 170);
|
||||
SetStr( 177, 195 );
|
||||
SetDex( 251, 269 );
|
||||
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.Fire, 26, 35);
|
||||
SetResistance(ResistanceType.Cold, 30, 40);
|
||||
SetResistance(ResistanceType.Poison, 30, 40);
|
||||
SetResistance(ResistanceType.Energy, 30, 40);
|
||||
SetResistance( ResistanceType.Physical, 55, 60 );
|
||||
SetResistance( ResistanceType.Fire, 25, 35 );
|
||||
SetResistance( ResistanceType.Cold, 30, 40 );
|
||||
SetResistance( ResistanceType.Poison, 30, 40 );
|
||||
SetResistance( ResistanceType.Energy, 30, 40 );
|
||||
|
||||
SetSkill(SkillName.Poisoning, 0);
|
||||
SetSkill(SkillName.Meditation, 0);
|
||||
SetSkill(SkillName.EvalInt, 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);
|
||||
SetSkill( SkillName.MagicResist, 55.0, 65.0 );
|
||||
SetSkill( SkillName.Tactics, 80.0, 100.0 );
|
||||
SetSkill( SkillName.Wrestling, 80.0, 100.0 );
|
||||
|
||||
Fame = 5000;
|
||||
Karma = -5000;
|
||||
Karma = 0;
|
||||
|
||||
VirtualArmor = 28; // Don't know what it should be
|
||||
}
|
||||
|
||||
PackArcanceScroll( 0.05 );
|
||||
}
|
||||
|
||||
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 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);
|
||||
writer.Write((int)0);
|
||||
base.Serialize( writer );
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Server.Mobiles
|
|||
public SummonedDaemon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 )
|
||||
{
|
||||
Name = NameList.RandomName( "daemon" );
|
||||
Body = 9;
|
||||
Body = Core.AOS ? 10 : 9;
|
||||
BaseSoundID = 357;
|
||||
|
||||
SetStr( 200 );
|
||||
|
|
|
|||
|
|
@ -313,6 +313,62 @@ namespace Server.Mobiles
|
|||
}
|
||||
#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;
|
||||
|
||||
[CommandProperty( AccessLevel.GameMaster )]
|
||||
|
|
@ -322,6 +378,15 @@ namespace Server.Mobiles
|
|||
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
|
||||
private DateTime m_AcceleratedStart;
|
||||
|
||||
|
|
@ -342,7 +407,6 @@ namespace Server.Mobiles
|
|||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public static Direction GetDirection4( Point3D from, Point3D to )
|
||||
{
|
||||
int dx = from.X - to.X;
|
||||
|
|
@ -1833,6 +1897,9 @@ namespace Server.Mobiles
|
|||
if ( m_SentHonorContext != null )
|
||||
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 );
|
||||
}
|
||||
|
||||
|
|
@ -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 int m_InsuranceCost;
|
||||
private int m_InsuranceBonus;
|
||||
|
|
@ -1890,6 +1963,8 @@ namespace Server.Mobiles
|
|||
if ( m_SentHonorContext != null )
|
||||
m_SentHonorContext.OnSourceKilled();
|
||||
|
||||
RecoverAmmo();
|
||||
|
||||
return base.OnBeforeDeath();
|
||||
}
|
||||
|
||||
|
|
@ -2417,6 +2492,12 @@ namespace Server.Mobiles
|
|||
|
||||
switch ( version )
|
||||
{
|
||||
case 28:
|
||||
{
|
||||
m_PeacedUntil = reader.ReadDateTime();
|
||||
|
||||
goto case 27;
|
||||
}
|
||||
case 27:
|
||||
{
|
||||
m_AnkhNextUse = reader.ReadDateTime();
|
||||
|
|
@ -2710,8 +2791,9 @@ namespace Server.Mobiles
|
|||
|
||||
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( m_AutoStabled, true );
|
||||
|
||||
|
|
|
|||
|
|
@ -498,6 +498,10 @@ namespace Server.Spells
|
|||
{
|
||||
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() ) )
|
||||
{
|
||||
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.
|
||||
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() )
|
||||
{
|
||||
m_Caster.Mana -= mana;
|
||||
|
|
|
|||
|
|
@ -987,6 +987,11 @@ namespace Server.Spells
|
|||
//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 )
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using Server.Misc;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
|
|
@ -7,6 +9,8 @@ namespace Server.Spells.Eighth
|
|||
{
|
||||
public class SummonDaemonSpell : MagerySpell
|
||||
{
|
||||
private BaseCreature m_Daemon = new SummonedDaemon();
|
||||
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Summon Daemon", "Kal Vas Xen Corp",
|
||||
269,
|
||||
|
|
@ -41,11 +45,14 @@ namespace Server.Spells.Eighth
|
|||
public override void OnCast()
|
||||
{
|
||||
if ( CheckSequence() )
|
||||
{
|
||||
{
|
||||
TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 );
|
||||
|
||||
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
|
||||
SpellHelper.Summon( new Daemon(), Caster, 0x216, duration, false, false );
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue