#W# Initial Commit: Avatars Conquest

This commit is contained in:
WarrentyExpired 2026-07-04 10:35:30 -04:00
commit 5df497787a
7510 changed files with 416048 additions and 0 deletions

View file

@ -0,0 +1,15 @@
using System;
using Server;
namespace Server.Spells
{
public enum DisturbType
{
Unspecified,
EquipRequest,
UseRequest,
Hurt,
Kill,
NewCast
}
}

View file

@ -0,0 +1,96 @@
using System;
using Server;
namespace Server.Spells
{
public class Initializer
{
public static void Initialize()
{
// First circle
Register( 00, typeof( First.ClumsySpell ) );
Register( 01, typeof( First.CreateFoodSpell ) );
Register( 02, typeof( First.FeeblemindSpell ) );
Register( 03, typeof( First.HealSpell ) );
Register( 04, typeof( First.MagicArrowSpell ) );
Register( 05, typeof( First.NightSightSpell ) );
Register( 06, typeof( First.ReactiveArmorSpell ) );
Register( 07, typeof( First.WeakenSpell ) );
// Second circle
Register( 08, typeof( Second.AgilitySpell ) );
Register( 09, typeof( Second.CunningSpell ) );
Register( 10, typeof( Second.CureSpell ) );
Register( 11, typeof( Second.HarmSpell ) );
Register( 12, typeof( Second.MagicTrapSpell ) );
Register( 13, typeof( Second.RemoveTrapSpell ) );
Register( 14, typeof( Second.ProtectionSpell ) );
Register( 15, typeof( Second.StrengthSpell ) );
// Third circle
Register( 16, typeof( Third.BlessSpell ) );
Register( 17, typeof( Third.FireballSpell ) );
Register( 18, typeof( Third.MagicLockSpell ) );
Register( 19, typeof( Third.PoisonSpell ) );
Register( 20, typeof( Third.TelekinesisSpell ) );
Register( 21, typeof( Third.TeleportSpell ) );
Register( 22, typeof( Third.UnlockSpell ) );
Register( 23, typeof( Third.WallOfStoneSpell ) );
// Fourth circle
Register( 24, typeof( Fourth.ArchCureSpell ) );
Register( 25, typeof( Fourth.ArchProtectionSpell ) );
Register( 26, typeof( Fourth.CurseSpell ) );
Register( 27, typeof( Fourth.FireFieldSpell ) );
Register( 28, typeof( Fourth.GreaterHealSpell ) );
Register( 29, typeof( Fourth.LightningSpell ) );
Register( 30, typeof( Fourth.ManaDrainSpell ) );
Register( 31, typeof( Fourth.RecallSpell ) );
// Fifth circle
Register( 32, typeof( Fifth.BladeSpiritsSpell ) );
Register( 33, typeof( Fifth.DispelFieldSpell ) );
Register( 34, typeof( Fifth.IncognitoSpell ) );
Register( 35, typeof( Fifth.MagicReflectSpell ) );
Register( 36, typeof( Fifth.MindBlastSpell ) );
Register( 37, typeof( Fifth.ParalyzeSpell ) );
Register( 38, typeof( Fifth.PoisonFieldSpell ) );
Register( 39, typeof( Fifth.SummonCreatureSpell ) );
// Sixth circle
Register( 40, typeof( Sixth.DispelSpell ) );
Register( 41, typeof( Sixth.EnergyBoltSpell ) );
Register( 42, typeof( Sixth.ExplosionSpell ) );
Register( 43, typeof( Sixth.InvisibilitySpell ) );
Register( 44, typeof( Sixth.MarkSpell ) );
Register( 45, typeof( Sixth.MassCurseSpell ) );
Register( 46, typeof( Sixth.ParalyzeFieldSpell ) );
Register( 47, typeof( Sixth.RevealSpell ) );
// Seventh circle
Register( 48, typeof( Seventh.ChainLightningSpell ) );
Register( 49, typeof( Seventh.EnergyFieldSpell ) );
Register( 50, typeof( Seventh.FlameStrikeSpell ) );
Register( 51, typeof( Seventh.GateTravelSpell ) );
Register( 52, typeof( Seventh.ManaVampireSpell ) );
Register( 53, typeof( Seventh.MassDispelSpell ) );
Register( 54, typeof( Seventh.MeteorSwarmSpell ) );
Register( 55, typeof( Seventh.PolymorphSpell ) );
// Eighth circle
Register( 56, typeof( Eighth.EarthquakeSpell ) );
Register( 57, typeof( Eighth.EnergyVortexSpell ) );
Register( 58, typeof( Eighth.ResurrectionSpell ) );
Register( 59, typeof( Eighth.AirElementalSpell ) );
Register( 60, typeof( Eighth.SummonDaemonSpell ) );
Register( 61, typeof( Eighth.EarthElementalSpell ) );
Register( 62, typeof( Eighth.FireElementalSpell ) );
Register( 63, typeof( Eighth.WaterElementalSpell ) );
}
public static void Register( int spellID, Type type )
{
SpellRegistry.Register( spellID, type );
}
}
}

View file

@ -0,0 +1,113 @@
using System;
using Server;
using Server.Items;
namespace Server.Spells
{
public abstract class MagerySpell : Spell
{
public MagerySpell( Mobile caster, Item scroll, SpellInfo info )
: base( caster, scroll, info )
{
}
public abstract SpellCircle Circle { get; }
public override bool ConsumeReagents()
{
if( base.ConsumeReagents() )
return true;
if( ArcaneGem.ConsumeCharges( Caster, 1+(int)Circle ) )
return true;
return false;
}
private const double ChanceOffset = 20.0, ChanceLength = 100.0 / 7.0;
public override void GetCastSkills( out double min, out double max )
{
int circle = (int)Circle;
if( Scroll != null )
circle -= 2;
double avg = ChanceLength * circle;
min = avg - ChanceOffset;
max = avg + ChanceOffset;
}
private static int[] m_ManaTable = new int[] { 4, 6, 9, 11, 14, 20, 40, 50 };
public override int GetMana()
{
if( Scroll is BaseWand )
return 0;
return m_ManaTable[(int)Circle];
}
public override double GetResistSkill( Mobile m )
{
int maxSkill = (1 + (int)Circle) * 10;
maxSkill += (1 + ((int)Circle / 6)) * 25;
if( m.Skills[SkillName.MagicResist].Value < maxSkill )
m.CheckSkill( SkillName.MagicResist, 0.0, m.Skills[SkillName.MagicResist].Cap );
return m.Skills[SkillName.MagicResist].Value;
}
public virtual bool CheckResisted( Mobile target )
{
double n = GetResistPercent( target );
n /= 100.0;
if( n <= 0.0 )
return false;
if( n >= 1.0 )
return true;
int maxSkill = (1 + (int)Circle) * 10;
maxSkill += (1 + ((int)Circle / 6)) * 25;
if( target.Skills[SkillName.MagicResist].Value < maxSkill )
target.CheckSkill( SkillName.MagicResist, 0.0, target.Skills[SkillName.MagicResist].Cap );
return (n >= Utility.RandomDouble());
}
public virtual double GetResistPercentForCircle( Mobile target, SpellCircle circle )
{
double firstPercent = target.Skills[SkillName.MagicResist].Value / 5.0;
double secondPercent = target.Skills[SkillName.MagicResist].Value - (((Caster.Skills[CastSkill].Value - 20.0) / 5.0) + (1 + (int)circle) * 5.0);
return (firstPercent > secondPercent ? firstPercent : secondPercent) / 2.0; // Seems should be about half of what stratics says.
}
public virtual double GetResistPercent( Mobile target )
{
return GetResistPercentForCircle( target, Circle );
}
public override TimeSpan GetCastDelay()
{
if( Scroll is BaseWand )
return TimeSpan.Zero;
return TimeSpan.FromSeconds( 0.5 + (0.25 * (int)Circle) );
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds( (3 + (int)Circle) * CastDelaySecondsPerTick );
}
}
}
}

View file

@ -0,0 +1,732 @@
using System;
using Server.Items;
using Server.Misc;
using Server.Network;
using Server.Targeting;
using Server.Mobiles;
using Server.Spells.Second;
using System.Collections.Generic;
namespace Server.Spells
{
public abstract class Spell : ISpell
{
private Mobile m_Caster;
private Item m_Scroll;
private SpellInfo m_Info;
private SpellState m_State;
private DateTime m_StartCastTime;
public SpellState State{ get{ return m_State; } set{ m_State = value; } }
public Mobile Caster{ get{ return m_Caster; } }
public SpellInfo Info{ get{ return m_Info; } }
public string Name{ get{ return m_Info.Name; } }
public string Mantra{ get{ return m_Info.Mantra; } }
public Type[] Reagents{ get{ return m_Info.Reagents; } }
public Item Scroll{ get{ return m_Scroll; } }
public DateTime StartCastTime { get { return m_StartCastTime; } }
private static TimeSpan NextSpellDelay = TimeSpan.FromSeconds( 0.75 );
private static TimeSpan AnimateDelay = TimeSpan.FromSeconds( 1.5 );
public virtual SkillName CastSkill{ get{ return SkillName.Magery; } }
public virtual SkillName DamageSkill{ get{ return SkillName.Concentration; } }
public virtual bool RevealOnCast{ get{ return true; } }
public virtual bool ClearHandsOnCast{ get{ return Server.Misc.Settings.CastSpellsHoldingThings(); } }
public virtual bool ShowHandMovement{ get{ return true; } }
public virtual bool DelayedDamage{ get{ return false; } }
public virtual bool DelayedDamageStacking { get { return true; } }
//In reality, it's ANY delayed Damage spell that can't stack, but, only
//Expo & Magic Arrow have enough delay and a short enough cast time to bring up
//the possibility of stacking 'em. Note that a MA & an Explosion will stack, but
//of course, two MA's won't.
private static Dictionary<Type, DelayedDamageContextWrapper> m_ContextTable = new Dictionary<Type, DelayedDamageContextWrapper>();
private class DelayedDamageContextWrapper
{
private Dictionary<Mobile, Timer> m_Contexts = new Dictionary<Mobile, Timer>();
public void Add( Mobile m, Timer t )
{
Timer oldTimer;
if( m_Contexts.TryGetValue( m, out oldTimer ) )
{
oldTimer.Stop();
m_Contexts.Remove( m );
}
m_Contexts.Add( m, t );
}
public void Remove( Mobile m )
{
m_Contexts.Remove( m );
}
}
public void StartDelayedDamageContext( Mobile m, Timer t )
{
if( DelayedDamageStacking )
return; //Sanity
DelayedDamageContextWrapper contexts;
if( !m_ContextTable.TryGetValue( GetType(), out contexts ) )
{
contexts = new DelayedDamageContextWrapper();
m_ContextTable.Add( GetType(), contexts );
}
contexts.Add( m, t );
}
public void RemoveDelayedDamageContext( Mobile m )
{
DelayedDamageContextWrapper contexts;
if( !m_ContextTable.TryGetValue( GetType(), out contexts ) )
return;
contexts.Remove( m );
}
public void HarmfulSpell( Mobile m )
{
if ( m is BaseCreature )
((BaseCreature)m).OnHarmfulSpell( m_Caster );
}
public Spell( Mobile caster, Item scroll, SpellInfo info )
{
m_Caster = caster;
m_Scroll = scroll;
m_Info = info;
}
public virtual bool IsCasting{ get{ return m_State == SpellState.Casting; } }
public virtual void OnCasterHurt()
{
//Confirm: Monsters and pets cannot be disturbed.
if ( !Caster.Player )
return;
if ( CheckHandToHand( Caster ) )
return;
if ( IsCasting )
{
object o = ProtectionSpell.Registry[m_Caster];
bool disturb = true;
if ( o != null && o is double )
{
if ( ((double)o) > Utility.RandomDouble()*100.0 )
disturb = false;
}
if ( disturb )
Disturb( DisturbType.Hurt, false, true );
}
}
public virtual void OnCasterKilled()
{
Disturb( DisturbType.Kill );
}
public virtual void OnConnectionChanged()
{
FinishSequence();
}
public virtual bool OnCasterMoving( Direction d )
{
if ( IsCasting && BlocksMovement )
{
m_Caster.SendLocalizedMessage( 500111 ); // You are frozen and can not move.
return false;
}
return true;
}
public virtual bool OnCasterEquiping( Item item )
{
if ( IsCasting )
Disturb( DisturbType.EquipRequest );
return true;
}
public virtual bool OnCasterUsingObject( object o )
{
if ( m_State == SpellState.Sequencing )
Disturb( DisturbType.UseRequest );
return true;
}
public virtual bool OnCastInTown( Region r )
{
return m_Info.AllowTown;
}
public virtual bool ConsumeReagents()
{
if ( m_Scroll != null || !m_Caster.Player )
return true;
Container pack = m_Caster.Backpack;
if ( pack == null )
return false;
if ( pack.ConsumeTotal( m_Info.Reagents, m_Info.Amounts ) == -1 )
return true;
return false;
}
public virtual int GetDamageFixed( Mobile m )
{
return m.Skills[DamageSkill].Fixed;
}
public virtual double GetDamageSkill( Mobile m )
{
return m.Skills[DamageSkill].Value;
}
public virtual double GetResistSkill( Mobile m )
{
return m.Skills[SkillName.MagicResist].Value;
}
public virtual bool CheckHandToHand( Mobile m )
{
return m.CheckSkill( SkillName.HandToHand, 0.0, 100.0 );
}
public virtual double GetDamageScalar( Mobile target )
{
double scalar = 1.0;
double casterEI = m_Caster.Skills[DamageSkill].Value;
double targetRS = target.Skills[SkillName.MagicResist].Value;
if( casterEI > targetRS )
scalar = (1.0 + ((casterEI - targetRS) / 500.0));
else
scalar = (1.0 + ((casterEI - targetRS) / 200.0));
// magery damage bonus, -25% at 0 skill, +0% at 100 skill, +5% at 120 skill
scalar += (m_Caster.Skills[CastSkill].Value - 100.0) / 400.0;
if ( m_Caster.CheckSkill( SkillName.Concentration, 0.0, 100.0 ) )
scalar *= ( m_Caster.Skills[SkillName.Concentration].Value / 50 );
if ( target is BaseCreature )
((BaseCreature)target).AlterDamageScalarFrom( m_Caster, ref scalar );
if ( m_Caster is BaseCreature )
((BaseCreature)m_Caster).AlterDamageScalarTo( target, ref scalar );
target.Region.SpellDamageScalar( m_Caster, target, ref scalar );
return scalar;
}
public virtual double GetSlayerDamageScalar( Mobile defender )
{
Spellbook atkBook = Spellbook.FindEquippedSpellbook( m_Caster );
double scalar = 1.0;
if( atkBook != null )
{
SlayerEntry atkSlayer = SlayerGroup.GetEntryByName( atkBook.Slayer );
SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName( atkBook.Slayer2 );
if( atkSlayer != null && atkSlayer.Slays( defender ) || atkSlayer2 != null && atkSlayer2.Slays( defender ) )
{
defender.FixedEffect( 0x37B9, 10, 5 ); //TODO: Confirm this displays on OSIs
scalar = 2.0;
}
if( scalar != 1.0 )
return scalar;
}
return scalar;
}
public virtual void DoFizzle()
{
m_Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502632 ); // The spell fizzles.
if ( m_Caster.Player )
{
m_Caster.FixedEffect( 0x3735, 6, 30 );
m_Caster.PlaySound( 0x5C );
}
}
private CastTimer m_CastTimer;
private AnimTimer m_AnimTimer;
public void Disturb( DisturbType type )
{
Disturb( type, true, false );
}
public virtual bool CheckDisturb( DisturbType type, bool firstCircle, bool resistable )
{
if ( resistable && m_Scroll is BaseWand )
return false;
return true;
}
public void Disturb( DisturbType type, bool firstCircle, bool resistable )
{
if ( !CheckDisturb( type, firstCircle, resistable ) )
return;
if ( m_State == SpellState.Casting )
{
if( !firstCircle && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First )
return;
if ( CheckHandToHand( m_Caster ) )
return;
m_State = SpellState.None;
m_Caster.Spell = null;
OnDisturb( type, true );
if ( m_CastTimer != null )
m_CastTimer.Stop();
if ( m_AnimTimer != null )
m_AnimTimer.Stop();
m_Caster.NextSpellTime = DateTime.Now + GetDisturbRecovery();
}
else if ( m_State == SpellState.Sequencing )
{
if( !firstCircle && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First )
return;
if ( CheckHandToHand( m_Caster ) )
return;
m_State = SpellState.None;
m_Caster.Spell = null;
OnDisturb( type, false );
Targeting.Target.Cancel( m_Caster );
}
}
public virtual void DoHurtFizzle()
{
m_Caster.FixedEffect( 0x3735, 6, 30 );
m_Caster.PlaySound( 0x5C );
}
public virtual void OnDisturb( DisturbType type, bool message )
{
if ( message )
m_Caster.SendLocalizedMessage( 500641 ); // Your concentration is disturbed, thus ruining thy spell.
}
public virtual bool CheckCast()
{
return true;
}
public virtual void SayMantra()
{
if ( m_Scroll is BaseWand )
return;
if ( m_Info.Mantra != null && m_Info.Mantra.Length > 0 && m_Caster.Player )
m_Caster.PublicOverheadMessage( MessageType.Spell, m_Caster.SpeechHue, true, m_Info.Mantra, false );
}
public virtual bool BlocksMovement{ get{ return true; } }
public virtual bool CheckNextSpellTime{ get{ return !(m_Scroll is BaseWand); } }
public bool Cast()
{
m_StartCastTime = DateTime.Now;
if ( !m_Caster.CheckAlive() )
{
return false;
}
else if ( m_Caster.Spell != null && m_Caster.Spell.IsCasting )
{
m_Caster.SendLocalizedMessage( 502642 ); // You are already casting a spell.
}
else if ( !(m_Scroll is BaseWand) && (m_Caster.Paralyzed || m_Caster.Frozen) )
{
m_Caster.SendLocalizedMessage( 502643 ); // You can not cast a spell while frozen.
}
else if ( CheckNextSpellTime && DateTime.Now < m_Caster.NextSpellTime )
{
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 ) )
{
m_State = SpellState.Casting;
m_Caster.Spell = this;
if ( RevealOnCast )
m_Caster.RevealingAction();
SayMantra();
TimeSpan castDelay = this.GetCastDelay();
if ( ShowHandMovement && m_Caster.Body.IsHuman )
{
int count = (int)Math.Ceiling( castDelay.TotalSeconds / AnimateDelay.TotalSeconds );
if ( count != 0 )
{
m_AnimTimer = new AnimTimer( this, count );
m_AnimTimer.Start();
}
if ( m_Info.LeftHandEffect > 0 )
Caster.FixedParticles( 0, 10, 5, m_Info.LeftHandEffect, EffectLayer.LeftHand );
if ( m_Info.RightHandEffect > 0 )
Caster.FixedParticles( 0, 10, 5, m_Info.RightHandEffect, EffectLayer.RightHand );
}
if ( ClearHandsOnCast )
m_Caster.ClearHands();
m_CastTimer = new CastTimer( this, castDelay );
m_CastTimer.Start();
OnBeginCast();
return true;
}
else
{
return false;
}
}
else
{
m_Caster.LocalOverheadMessage( MessageType.Regular, 0x22, 502625 ); // Insufficient mana
}
return false;
}
public abstract void OnCast();
public virtual void OnBeginCast()
{
}
public virtual void GetCastSkills( out double min, out double max )
{
min = max = 0; //Intended but not required for overriding.
}
public virtual bool CheckFizzle()
{
if ( m_Scroll is BaseWand )
return true;
double minSkill, maxSkill;
GetCastSkills( out minSkill, out maxSkill );
if ( DamageSkill != CastSkill )
Caster.CheckSkill( DamageSkill, 0.0, Caster.Skills[ DamageSkill ].Cap );
return Caster.CheckSkill( CastSkill, minSkill, maxSkill );
}
public abstract int GetMana();
public virtual int ScaleMana( int mana )
{
double scalar = 1.0;
// Lower Mana Needed for Concentration is capped at 50%
int lmc = (int)(m_Caster.Skills[SkillName.Concentration].Value/2);
if ( lmc > 50 )
lmc = 50;
scalar -= (double)lmc / 100;
return (int)(mana * scalar);
}
public virtual TimeSpan GetDisturbRecovery()
{
double delay = 1.0 - Math.Sqrt( (DateTime.Now - m_StartCastTime).TotalSeconds / GetCastDelay().TotalSeconds );
if ( delay < 0.2 )
delay = 0.2;
return TimeSpan.FromSeconds( delay );
}
public virtual int CastRecoveryBase{ get{ return 6; } }
public virtual int CastRecoveryFastScalar{ get{ return 1; } }
public virtual int CastRecoveryPerSecond{ get{ return 4; } }
public virtual int CastRecoveryMinimum{ get{ return 0; } }
public virtual TimeSpan GetCastRecovery()
{
int fcr = 0;
if ( m_Caster.CheckSkill( SkillName.HandToHand, 0.0, 100.0 ) )
{
fcr = (int)(m_Caster.Skills[SkillName.HandToHand].Value / 20);
}
int fcrDelay = -(CastRecoveryFastScalar * fcr);
int delay = CastRecoveryBase + fcrDelay;
if ( delay < CastRecoveryMinimum )
delay = CastRecoveryMinimum;
return TimeSpan.FromSeconds( (double)delay / CastRecoveryPerSecond );
}
public abstract TimeSpan CastDelayBase { get; }
public virtual double CastDelayFastScalar { get { return 1; } }
public virtual double CastDelaySecondsPerTick { get { return 0.25; } }
public virtual TimeSpan CastDelayMinimum { get { return TimeSpan.FromSeconds( 0.25 ); } }
public virtual TimeSpan GetCastDelay()
{
if ( m_Scroll is BaseWand )
return TimeSpan.Zero;
// Faster casting cap of 2 (if not using the protection spell)
// Faster casting cap of 0 (if using the protection spell)
int fc = 0;
if ( m_Caster.CheckSkill( SkillName.HandToHand, 0.0, 100.0 ) )
{
if ( m_Caster.Skills[SkillName.HandToHand].Value > 50.0 )
fc = 1;
else
fc = 2;
}
if ( ProtectionSpell.Registry.Contains( m_Caster ) )
fc -= 2;
TimeSpan baseDelay = CastDelayBase;
TimeSpan fcDelay = TimeSpan.FromSeconds( -(CastDelayFastScalar * fc * CastDelaySecondsPerTick) );
//int delay = CastDelayBase + circleDelay + fcDelay;
TimeSpan delay = baseDelay + fcDelay;
if ( delay < CastDelayMinimum )
delay = CastDelayMinimum;
//return TimeSpan.FromSeconds( (double)delay / CastDelayPerSecond );
return delay;
}
public virtual void FinishSequence()
{
m_State = SpellState.None;
if ( m_Caster.Spell == this )
m_Caster.Spell = null;
}
public virtual bool CheckSequence()
{
int mana = ScaleMana( GetMana() );
if ( m_Caster.Deleted || !m_Caster.Alive || m_Caster.Spell != this || m_State != SpellState.Sequencing )
{
DoFizzle();
}
else if ( m_Scroll != null && (m_Scroll.Amount <= 0 || m_Scroll.Deleted || m_Scroll.RootParent != m_Caster || (m_Scroll is BaseWand && (((BaseWand)m_Scroll).Uses <= 0 || m_Scroll.Parent != m_Caster))) )
{
DoFizzle();
}
else if ( !ConsumeReagents() )
{
m_Caster.LocalOverheadMessage( MessageType.Regular, 0x22, 502630 ); // More reagents are needed for this spell.
}
else if ( m_Caster.Mana < mana )
{
m_Caster.LocalOverheadMessage( MessageType.Regular, 0x22, 502625 ); // Insufficient mana for this spell.
}
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;
if ( m_Scroll is SpellScroll )
m_Scroll.Consume();
else if ( m_Scroll is BaseWand )
((BaseWand)m_Scroll).ConsumeCharge( m_Caster );
if ( m_Scroll is BaseWand )
{
bool m = m_Scroll.Movable;
m_Scroll.Movable = false;
if ( ClearHandsOnCast )
m_Caster.ClearHands();
m_Scroll.Movable = m;
}
else
{
if ( ClearHandsOnCast )
m_Caster.ClearHands();
}
return true;
}
else
{
DoFizzle();
}
return false;
}
public bool CheckBSequence( Mobile target )
{
return CheckBSequence( target, false );
}
public bool CheckBSequence( Mobile target, bool allowDead )
{
if ( !target.Alive && !allowDead )
{
m_Caster.SendLocalizedMessage( 501857 ); // This spell won't work on that!
return false;
}
else if ( Caster.CanBeBeneficial( target, true, allowDead ) && CheckSequence() )
{
Caster.DoBeneficial( target );
return true;
}
else
{
return false;
}
}
public bool CheckHSequence( Mobile target )
{
if ( !target.Alive )
{
m_Caster.SendLocalizedMessage( 501857 ); // This spell won't work on that!
return false;
}
else if ( Caster.CanBeHarmful( target ) && CheckSequence() )
{
Caster.DoHarmful( target );
return true;
}
else
{
return false;
}
}
private class AnimTimer : Timer
{
private Spell m_Spell;
public AnimTimer( Spell spell, int count ) : base( TimeSpan.Zero, AnimateDelay, count )
{
m_Spell = spell;
Priority = TimerPriority.FiftyMS;
}
protected override void OnTick()
{
if ( m_Spell.State != SpellState.Casting || m_Spell.m_Caster.Spell != m_Spell )
{
Stop();
return;
}
if ( !m_Spell.Caster.Mounted && m_Spell.Caster.Body.IsHuman && m_Spell.m_Info.Action >= 0 )
m_Spell.Caster.Animate( m_Spell.m_Info.Action, 7, 1, true, false, 0 );
if ( !Running )
m_Spell.m_AnimTimer = null;
}
}
private class CastTimer : Timer
{
private Spell m_Spell;
public CastTimer( Spell spell, TimeSpan castDelay ) : base( castDelay )
{
m_Spell = spell;
Priority = TimerPriority.TwentyFiveMS;
}
protected override void OnTick()
{
if ( m_Spell.m_State == SpellState.Casting && m_Spell.m_Caster.Spell == m_Spell )
{
m_Spell.m_State = SpellState.Sequencing;
m_Spell.m_CastTimer = null;
m_Spell.m_Caster.OnSpellCast( m_Spell );
m_Spell.m_Caster.Region.OnSpellCast( m_Spell.m_Caster, m_Spell );
m_Spell.m_Caster.NextSpellTime = DateTime.Now + m_Spell.GetCastRecovery();// Spell.NextSpellDelay;
Target originalTarget = m_Spell.m_Caster.Target;
m_Spell.OnCast();
if ( m_Spell.m_Caster.Player && m_Spell.m_Caster.Target != originalTarget && m_Spell.Caster.Target != null )
m_Spell.m_Caster.Target.BeginTimeout( m_Spell.m_Caster, TimeSpan.FromSeconds( 30.0 ) );
m_Spell.m_CastTimer = null;
}
}
}
}
}

View file

@ -0,0 +1,16 @@
using System;
namespace Server.Spells
{
public enum SpellCircle
{
First,
Second,
Third,
Fourth,
Fifth,
Sixth,
Seventh,
Eighth
}
}

View file

@ -0,0 +1,991 @@
using System;
using Server;
using Server.Items;
using Server.Guilds;
using Server.Multis;
using Server.Regions;
using Server.Mobiles;
using Server.Targeting;
using Server.Engines.PartySystem;
using Server.Misc;
using System.Collections.Generic;
using Server.Spells.Seventh;
using Server.Spells.Fifth;
namespace Server
{
public class DefensiveSpell
{
public static void Nullify( Mobile from )
{
if( !from.CanBeginAction( typeof( DefensiveSpell ) ) )
new InternalTimer( from ).Start();
}
private class InternalTimer : Timer
{
private Mobile m_Mobile;
public InternalTimer( Mobile m )
: base( TimeSpan.FromMinutes( 1.0 ) )
{
m_Mobile = m;
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
m_Mobile.EndAction( typeof( DefensiveSpell ) );
}
}
}
}
namespace Server.Spells
{
public enum TravelCheckType
{
RecallFrom,
RecallTo,
GateFrom,
GateTo,
Mark,
TeleportFrom,
TeleportTo
}
public class SpellHelper
{
private static TimeSpan OldDamageDelay = TimeSpan.FromSeconds( 0.5 );
public static TimeSpan GetDamageDelayForSpell( Spell sp )
{
if( !sp.DelayedDamage )
return TimeSpan.Zero;
return (OldDamageDelay);
}
public static bool CheckMulti( Point3D p, Map map )
{
return CheckMulti( p, map, true, 0);
}
public static bool CheckMulti(Point3D p, Map map, bool houses)
{
return CheckMulti(p, map, houses, 0);
}
public static bool CheckMulti( Point3D p, Map map, bool houses, int housingrange )
{
if( map == null || map == Map.Internal )
return false;
Sector sector = map.GetSector( p.X, p.Y );
for( int i = 0; i < sector.Multis.Count; ++i )
{
BaseMulti multi = sector.Multis[i];
if( multi is BaseHouse )
{
BaseHouse bh = (BaseHouse)multi;
if( ( houses && bh.IsInside( p, 16 ) ) || ( housingrange > 0 && bh.InRange( p, housingrange ) ) )
return true;
}
else if( multi.Contains( p ))
{
return true;
}
}
return false;
}
public static void Turn( Mobile from, object to )
{
IPoint3D target = to as IPoint3D;
if( target == null )
return;
if( target is Item )
{
Item item = (Item)target;
if( item.RootParent != from )
from.Direction = from.GetDirectionTo( item.GetWorldLocation() );
}
else if( from != target )
{
from.Direction = from.GetDirectionTo( target );
}
}
private static TimeSpan CombatHeatDelay = TimeSpan.FromSeconds( 30.0 );
private static bool RestrictTravelCombat = true;
public static bool CheckCombat( Mobile m )
{
if( !RestrictTravelCombat )
return false;
for( int i = 0; i < m.Aggressed.Count; ++i )
{
AggressorInfo info = m.Aggressed[i];
if( info.Defender.Player && (DateTime.Now - info.LastCombatTime) < CombatHeatDelay )
return true;
}
return false;
}
public static bool AdjustField( ref Point3D p, Map map, int height, bool mobsBlock )
{
if( map == null )
return false;
for( int offset = 0; offset < 10; ++offset )
{
Point3D loc = new Point3D( p.X, p.Y, p.Z - offset );
if( map.CanFit( loc, height, true, mobsBlock ) )
{
p = loc;
return true;
}
}
return false;
}
public static bool CanRevealCaster( Mobile m )
{
if ( m is BaseCreature )
{
BaseCreature c = (BaseCreature)m;
if ( !c.Controlled )
return true;
}
return false;
}
public static void GetSurfaceTop( ref IPoint3D p )
{
if( p is Item )
{
p = ((Item)p).GetSurfaceTop();
}
else if( p is StaticTarget )
{
StaticTarget t = (StaticTarget)p;
int z = t.Z;
if( (t.Flags & TileFlag.Surface) == 0 )
z -= TileData.ItemTable[t.ItemID & TileData.MaxItemValue].CalcHeight;
p = new Point3D( t.X, t.Y, z );
}
}
public static bool AddStatOffset( Mobile m, StatType type, int offset, TimeSpan duration )
{
if( offset > 0 )
return AddStatBonus( m, m, type, offset, duration );
else if( offset < 0 )
return AddStatCurse( m, m, type, -offset, duration );
return true;
}
public static bool AddStatBonus( Mobile caster, Mobile target, StatType type )
{
return AddStatBonus( caster, target, type, GetOffset( caster, target, type, false ), GetDuration( caster, target ) );
}
public static bool AddStatBonus( Mobile caster, Mobile target, StatType type, int bonus, TimeSpan duration )
{
int offset = bonus;
string name = String.Format( "[Magic] {0} Offset", type );
StatMod mod = target.GetStatMod( name );
if( mod != null && mod.Offset < 0 )
{
target.AddStatMod( new StatMod( type, name, mod.Offset + offset, duration ) );
return true;
}
else if( mod == null || mod.Offset < offset )
{
target.AddStatMod( new StatMod( type, name, offset, duration ) );
return true;
}
return false;
}
public static bool AddStatCurse( Mobile caster, Mobile target, StatType type )
{
return AddStatCurse( caster, target, type, GetOffset( caster, target, type, true ), GetDuration( caster, target ) );
}
public static bool AddStatCurse( Mobile caster, Mobile target, StatType type, int curse, TimeSpan duration )
{
int offset = -curse;
string name = String.Format( "[Magic] {0} Offset", type );
StatMod mod = target.GetStatMod( name );
if( mod != null && mod.Offset > 0 )
{
target.AddStatMod( new StatMod( type, name, mod.Offset + offset, duration ) );
return true;
}
else if( mod == null || mod.Offset > offset )
{
target.AddStatMod( new StatMod( type, name, offset, duration ) );
return true;
}
return false;
}
public static TimeSpan GetDuration( Mobile caster, Mobile target )
{
double time = 0.0;
if ( caster.CheckSkill( SkillName.Concentration, 0.0, 100.0 ) )
time = caster.Skills[SkillName.Concentration].Value / 2;
return TimeSpan.FromSeconds( time + (caster.Skills[SkillName.Magery].Value * 1.2) );
}
private static bool m_DisableSkillCheck;
public static bool DisableSkillCheck
{
get { return m_DisableSkillCheck; }
set { m_DisableSkillCheck = value; }
}
public static double GetOffsetScalar( Mobile caster, Mobile target, bool curse )
{
double percent;
if( curse )
percent = 8 + (caster.Skills.Concentration.Fixed / 100) - (target.Skills.MagicResist.Fixed / 100);
else
percent = 1 + (caster.Skills.Concentration.Fixed / 100);
percent *= 0.01;
if( percent < 0 )
percent = 0;
return percent;
}
public static int GetOffset( Mobile caster, Mobile target, StatType type, bool curse )
{
return 1 + (int)(caster.Skills[SkillName.Magery].Value * 0.1);
}
public static Guild GetGuildFor( Mobile m )
{
Guild g = m.Guild as Guild;
if( g == null && m is BaseCreature )
{
BaseCreature c = (BaseCreature)m;
m = c.ControlMaster;
if( m != null )
g = m.Guild as Guild;
if( g == null )
{
m = c.SummonMaster;
if( m != null )
g = m.Guild as Guild;
}
}
return g;
}
public static bool ValidIndirectTarget( Mobile from, Mobile to )
{
if( from == to )
return true;
if( to.Hidden && to.AccessLevel > from.AccessLevel )
return false;
Guild fromGuild = GetGuildFor( from );
Guild toGuild = GetGuildFor( to );
if( fromGuild != null && toGuild != null && (fromGuild == toGuild || fromGuild.IsAlly( toGuild )) )
return false;
Party p = Party.Get( from );
if( p != null && p.Contains( to ) )
return false;
if( to is BaseCreature )
{
BaseCreature c = (BaseCreature)to;
if( c.Controlled || c.Summoned )
{
if( c.ControlMaster == from || c.SummonMaster == from )
return false;
if( p != null && (p.Contains( c.ControlMaster ) || p.Contains( c.SummonMaster )) )
return false;
}
}
if( from is BaseCreature )
{
BaseCreature c = (BaseCreature)from;
if( c.Controlled || c.Summoned )
{
if( c.ControlMaster == to || c.SummonMaster == to )
return false;
p = Party.Get( to );
if( p != null && (p.Contains( c.ControlMaster ) || p.Contains( c.SummonMaster )) )
return false;
}
}
if( to is BaseCreature && !((BaseCreature)to).Controlled && ((BaseCreature)to).InitialInnocent )
return true;
int noto = Notoriety.Compute( from, to );
return (noto != Notoriety.Innocent || from.Kills >= 5);
}
private static int[] m_Offsets = new int[]
{
-1, -1,
-1, 0,
-1, 1,
0, -1,
0, 1,
1, -1,
1, 0,
1, 1
};
public static void Summon( BaseCreature creature, Mobile caster, int sound, TimeSpan duration, bool scaleDuration, bool scaleStats )
{
Map map = caster.Map;
if( map == null )
return;
double scale = 1.0 + ((caster.Skills[SkillName.Magery].Value - 100.0) / 200.0);
if( scaleDuration )
duration = TimeSpan.FromSeconds( duration.TotalSeconds * scale );
if( scaleStats )
{
creature.RawStr = (int)(creature.RawStr * scale);
creature.Hits = creature.HitsMax;
creature.RawDex = (int)(creature.RawDex * scale);
creature.Stam = creature.StamMax;
creature.RawInt = (int)(creature.RawInt * scale);
creature.Mana = creature.ManaMax;
}
Point3D p = new Point3D( caster );
if( SpellHelper.FindValidSpawnLocation( map, ref p, true ) )
{
BaseCreature.Summon( creature, caster, p, sound, duration );
return;
}
/*
int offset = Utility.Random( 8 ) * 2;
for( int i = 0; i < m_Offsets.Length; i += 2 )
{
int x = caster.X + m_Offsets[(offset + i) % m_Offsets.Length];
int y = caster.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length];
if( map.CanSpawnMobile( x, y, caster.Z ) )
{
BaseCreature.Summon( creature, caster, new Point3D( x, y, caster.Z ), sound, duration );
return;
}
else
{
int z = map.GetAverageZ( x, y );
if( map.CanSpawnMobile( x, y, z ) )
{
BaseCreature.Summon( creature, caster, new Point3D( x, y, z ), sound, duration );
return;
}
}
}
* */
creature.Delete();
caster.SendLocalizedMessage( 501942 ); // That location is blocked.
}
public static bool FindValidSpawnLocation( Map map, ref Point3D p, bool surroundingsOnly )
{
if( map == null ) //sanity
return false;
if( !surroundingsOnly )
{
if( map.CanSpawnMobile( p ) ) //p's fine.
{
p = new Point3D( p );
return true;
}
int z = map.GetAverageZ( p.X, p.Y );
if( map.CanSpawnMobile( p.X, p.Y, z ) )
{
p = new Point3D( p.X, p.Y, z );
return true;
}
}
int offset = Utility.Random( 8 ) * 2;
for( int i = 0; i < m_Offsets.Length; i += 2 )
{
int x = p.X + m_Offsets[(offset + i) % m_Offsets.Length];
int y = p.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length];
if( map.CanSpawnMobile( x, y, p.Z ) )
{
p = new Point3D( x, y, p.Z );
return true;
}
else
{
int z = map.GetAverageZ( x, y );
if( map.CanSpawnMobile( x, y, z ) )
{
p = new Point3D( x, y, z );
return true;
}
}
}
return false;
}
public static bool IsInvalid( Map map, Point3D loc )
{
if( map == null || map == Map.Internal )
return true;
int x = loc.X, y = loc.Y;
return (x < 0 || y < 0 || x >= map.Width || y >= map.Height);
}
//towns
public static bool IsTown( IPoint3D loc, Mobile caster )
{
if( loc is Item )
loc = ((Item)loc).GetWorldLocation();
return IsTown( new Point3D( loc ), caster );
}
public static bool IsTown( Point3D loc, Mobile caster )
{
Map map = caster.Map;
if( map == null )
return false;
Region reg = Region.Find( loc, map );
if ( reg is TownRegion )
return true;
else if ( reg is HouseRegion )
return true;
else if ( reg is GardenRegion )
return true;
else if ( reg is ShrineRegion )
return true;
return false;
}
public static bool CheckTown( IPoint3D loc, Mobile caster )
{
if( loc is Item )
loc = ((Item)loc).GetWorldLocation();
return CheckTown( new Point3D( loc ), caster );
}
public static bool CheckTown( Point3D loc, Mobile caster )
{
if( IsTown( loc, caster ) )
{
caster.SendLocalizedMessage( 500946 ); // You cannot cast this in town!
return false;
}
return true;
}
//Misc Spell Blockers
public static bool NoRecall( Point3D loc, Mobile caster )
{
Map map = caster.Map;
if( map == null )
return false;
Region reg = Region.Find( loc, map );
if ( reg is InnRegion )
return true;
else if ( reg is GateRegion )
return true;
else if ( reg is GardenRegion )
return true;
else if ( reg is ShrineRegion )
return true;
else if ( reg is BuildingRegion )
return true;
else if ( reg is CaveRegion )
return true;
else if ( reg is DungeonRegion )
return true;
else if ( reg is GraveRegion )
return true;
else if ( reg is PirateRegion )
return true;
else if ( reg is DangerRegion )
return true;
else if ( reg is HouseRegion )
return true;
return false;
}
//magic reflection
public static void CheckReflect( int circle, Mobile caster, ref Mobile target )
{
CheckReflect( circle, ref caster, ref target );
}
public static void CheckReflect( int circle, ref Mobile caster, ref Mobile target )
{
if( target.MagicDamageAbsorb > 0 )
{
++circle;
target.MagicDamageAbsorb -= circle;
// This order isn't very intuitive, but you have to nullify reflect before target gets switched
bool reflect = (target.MagicDamageAbsorb >= 0);
if( target is BaseCreature )
((BaseCreature)target).CheckReflect( caster, ref reflect );
if( target.MagicDamageAbsorb <= 0 )
{
target.MagicDamageAbsorb = 0;
DefensiveSpell.Nullify( target );
}
if( reflect )
{
target.FixedEffect( 0x37B9, 10, 5 );
Mobile temp = caster;
caster = target;
target = temp;
}
}
else if( target is BaseCreature )
{
bool reflect = false;
((BaseCreature)target).CheckReflect( caster, ref reflect );
if( reflect )
{
target.FixedEffect( 0x37B9, 10, 5 );
Mobile temp = caster;
caster = target;
target = temp;
}
}
}
public static void Damage( Spell spell, Mobile target, double damage )
{
TimeSpan ts = GetDamageDelayForSpell( spell );
Damage( spell, ts, target, spell.Caster, damage );
}
public static void Damage( TimeSpan delay, Mobile target, double damage )
{
Damage( delay, target, null, damage );
}
public static void Damage( TimeSpan delay, Mobile target, Mobile from, double damage )
{
Damage( null, delay, target, from, damage );
}
public static void Damage( Spell spell, TimeSpan delay, Mobile target, Mobile from, double damage )
{
int iDamage = (int)damage;
if( delay == TimeSpan.Zero )
{
if( from is BaseCreature )
((BaseCreature)from).AlterSpellDamageTo( target, ref iDamage );
if( target is BaseCreature )
((BaseCreature)target).AlterSpellDamageFrom( from, ref iDamage );
target.Damage( iDamage, from );
}
else
{
new SpellDamageTimer( spell, target, from, iDamage, delay ).Start();
}
if( target is BaseCreature && from != null && delay == TimeSpan.Zero )
{
BaseCreature c = (BaseCreature) target;
c.OnHarmfulSpell( from );
c.OnDamagedBySpell( from );
}
}
/*
public static void Damage( Spell spell, Mobile target, double damage )
{
TimeSpan ts = GetDamageDelayForSpell( spell );
Damage( spell, ts, target, spell.Caster, damage, DFAlgorithm.Standard );
}
*/
public static void Damage( Spell spell, Mobile target, double damage, DFAlgorithm dfa )
{
TimeSpan ts = GetDamageDelayForSpell( spell );
Damage( spell, ts, target, spell.Caster, damage, dfa );
}
/*
public static void Damage( TimeSpan delay, Mobile target, double damage )
{
Damage( delay, target, null, damage );
}
public static void Damage( TimeSpan delay, Mobile target, Mobile from, double damage )
{
Damage( delay, target, from, damage, DFAlgorithm.Standard );
}
*/
public static void Damage( TimeSpan delay, Mobile target, Mobile from, double damage, DFAlgorithm dfa )
{
Damage( null, delay, target, from, damage, dfa );
}
public static void Damage( Spell spell, TimeSpan delay, Mobile target, Mobile from, double damage, DFAlgorithm dfa )
{
int iDamage = (int)damage;
if( from is BaseCreature )
((BaseCreature)from).AlterSpellDamageTo( target, ref iDamage );
if( target is BaseCreature )
((BaseCreature)target).AlterSpellDamageFrom( from, ref iDamage );
WeightOverloading.DFA = dfa;
int damageGiven = Ultima.Damage( target, from, iDamage );
WeightOverloading.DFA = DFAlgorithm.Standard;
if( target is BaseCreature && from != null && delay == TimeSpan.Zero )
{
BaseCreature c = (BaseCreature) target;
c.OnHarmfulSpell( from );
c.OnDamagedBySpell( from );
}
}
public static void Heal( int amount, Mobile target, Mobile from )
{
Heal( amount, target, from, true );
}
public static void Heal( int amount, Mobile target, Mobile from, bool message )
{
if ( from.CheckSkill( SkillName.Concentration, 0.0, 100.0 ) )
amount = amount + (int)( amount * (from.Skills[SkillName.Concentration].Value / 100) );
if ( target is PlayerMobile ){ amount = (int)(amount * Server.Misc.Settings.HitPoints()); }
target.Heal( amount, from, message );
}
private class SpellDamageTimer : Timer
{
private Mobile m_Target, m_From;
private int m_Damage;
private Spell m_Spell;
public SpellDamageTimer( Spell s, Mobile target, Mobile from, int damage, TimeSpan delay )
: base( delay )
{
m_Target = target;
m_From = from;
m_Damage = damage;
m_Spell = s;
if( m_Spell != null && m_Spell.DelayedDamage && !m_Spell.DelayedDamageStacking )
m_Spell.StartDelayedDamageContext( target, this );
Priority = TimerPriority.TwentyFiveMS;
}
protected override void OnTick()
{
if( m_From is BaseCreature )
((BaseCreature)m_From).AlterSpellDamageTo( m_Target, ref m_Damage );
if( m_Target is BaseCreature )
((BaseCreature)m_Target).AlterSpellDamageFrom( m_From, ref m_Damage );
m_Target.Damage( m_Damage );
if( m_Spell != null )
m_Spell.RemoveDelayedDamageContext( m_Target );
}
}
}
public class TransformationSpellHelper
{
#region Context Stuff
private static Dictionary<Mobile, TransformContext> m_Table = new Dictionary<Mobile, TransformContext>();
public static void AddContext( Mobile m, TransformContext context )
{
m_Table[m] = context;
}
public static void RemoveContext( Mobile m, bool resetGraphics )
{
TransformContext context = GetContext( m );
if( context != null )
RemoveContext( m, context, resetGraphics );
}
public static void RemoveContext( Mobile m, TransformContext context, bool resetGraphics )
{
if( m_Table.ContainsKey( m ) )
{
m_Table.Remove( m );
if( resetGraphics )
{
m.HueMod = -1;
m.BodyMod = 0;
}
context.Timer.Stop();
context.Spell.RemoveEffect( m );
}
}
public static TransformContext GetContext( Mobile m )
{
TransformContext context = null;
m_Table.TryGetValue( m, out context );
return context;
}
public static bool UnderTransformation( Mobile m )
{
return (GetContext( m ) != null);
}
public static bool UnderTransformation( Mobile m, Type type )
{
TransformContext context = GetContext( m );
return (context != null && context.Type == type);
}
#endregion
public static bool CheckCast( Mobile caster, Spell spell )
{
if( !caster.CanBeginAction( typeof( PolymorphSpell ) ) )
{
caster.SendLocalizedMessage( 1061628 ); // You can't do that while polymorphed.
return false;
}
return true;
}
public static bool OnCast( Mobile caster, Spell spell )
{
ITransformationSpell transformSpell = spell as ITransformationSpell;
if( transformSpell == null )
return false;
if( !caster.CanBeginAction( typeof( PolymorphSpell ) ) )
{
caster.SendLocalizedMessage( 1061628 ); // You can't do that while polymorphed.
}
else if ( DisguiseTimers.IsDisguised( caster ) )
{
caster.SendLocalizedMessage( 1061631 ); // You can't do that while disguised.
return false;
}
else if( !caster.CanBeginAction( typeof( IncognitoSpell ) ) || (caster.IsBodyMod && GetContext( caster ) == null) )
{
spell.DoFizzle();
}
else if( spell.CheckSequence() )
{
TransformContext context = GetContext( caster );
Type ourType = spell.GetType();
bool wasTransformed = (context != null);
bool ourTransform = (wasTransformed && context.Type == ourType);
if( wasTransformed )
{
RemoveContext( caster, context, ourTransform );
if( ourTransform )
{
caster.PlaySound( 0xFA );
caster.FixedParticles( 0x3728, 1, 13, 5042, EffectLayer.Waist );
}
}
if( !ourTransform )
{
if( !((Body)transformSpell.Body).IsHuman )
{
Mobiles.IMount mt = caster.Mount;
if( mt != null )
mt.Rider = null;
}
caster.BodyMod = transformSpell.Body;
caster.HueMod = transformSpell.Hue;
transformSpell.DoEffect( caster );
Timer timer = new TransformTimer( caster, transformSpell );
timer.Start();
AddContext( caster, new TransformContext( timer, ourType, transformSpell ) );
return true;
}
}
return false;
}
}
public interface ITransformationSpell
{
int Body { get; }
int Hue { get; }
double TickRate { get; }
void OnTick( Mobile m );
void DoEffect( Mobile m );
void RemoveEffect( Mobile m );
}
public class TransformContext
{
private Timer m_Timer;
private Type m_Type;
private ITransformationSpell m_Spell;
public Timer Timer { get { return m_Timer; } }
public Type Type { get { return m_Type; } }
public ITransformationSpell Spell { get { return m_Spell; } }
public TransformContext( Timer timer, Type type, ITransformationSpell spell )
{
m_Timer = timer;
m_Type = type;
m_Spell = spell;
}
}
public class TransformTimer : Timer
{
private Mobile m_Mobile;
private ITransformationSpell m_Spell;
public TransformTimer( Mobile from, ITransformationSpell spell )
: base( TimeSpan.FromSeconds( spell.TickRate ), TimeSpan.FromSeconds( spell.TickRate ) )
{
m_Mobile = from;
m_Spell = spell;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
if( m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Body != m_Spell.Body || m_Mobile.Hue != m_Spell.Hue )
{
TransformationSpellHelper.RemoveContext( m_Mobile, true );
Stop();
}
else
{
m_Spell.OnTick( m_Mobile );
}
}
}
}

View file

@ -0,0 +1,66 @@
using System;
using Server;
namespace Server.Spells
{
public class SpellInfo
{
private string m_Name;
private string m_Mantra;
private Type[] m_Reagents;
private int[] m_Amounts;
private int m_Action;
private bool m_AllowTown;
private int m_LeftHandEffect, m_RightHandEffect;
public SpellInfo( string name, string mantra, params Type[] regs ) : this( name, mantra, 16, 0, 0, true, regs )
{
}
public SpellInfo( string name, string mantra, bool allowTown, params Type[] regs ) : this( name, mantra, 16, 0, 0, allowTown, regs )
{
}
public SpellInfo( string name, string mantra, int action, params Type[] regs ) : this( name, mantra, action, 0, 0, true, regs )
{
}
public SpellInfo( string name, string mantra, int action, bool allowTown, params Type[] regs ) : this( name, mantra, action, 0, 0, allowTown, regs )
{
}
public SpellInfo( string name, string mantra, int action, int handEffect, params Type[] regs ) : this( name, mantra, action, handEffect, handEffect, true, regs )
{
}
public SpellInfo( string name, string mantra, int action, int handEffect, bool allowTown, params Type[] regs ) : this( name, mantra, action, handEffect, handEffect, allowTown, regs )
{
}
public SpellInfo( string name, string mantra, int action, int leftHandEffect, int rightHandEffect, bool allowTown, params Type[] regs )
{
m_Name = name;
m_Mantra = mantra;
m_Action = action;
m_Reagents = regs;
m_AllowTown = allowTown;
m_LeftHandEffect = leftHandEffect;
m_RightHandEffect = rightHandEffect;
m_Amounts = new int[regs.Length];
for ( int i = 0; i < regs.Length; ++i )
m_Amounts[i] = 1;
}
public int Action{ get{ return m_Action; } set{ m_Action = value; } }
public bool AllowTown{ get{ return m_AllowTown; } set{ m_AllowTown = value; } }
public int[] Amounts{ get{ return m_Amounts; } set{ m_Amounts = value; } }
public string Mantra{ get{ return m_Mantra; } set{ m_Mantra = value; } }
public string Name{ get{ return m_Name; } set{ m_Name = value; } }
public Type[] Reagents{ get{ return m_Reagents; } set{ m_Reagents = value; } }
public int LeftHandEffect{ get{ return m_LeftHandEffect; } set{ m_LeftHandEffect = value; } }
public int RightHandEffect{ get{ return m_RightHandEffect; } set{ m_RightHandEffect = value; } }
}
}

View file

@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.IO;
using Server.Items;
namespace Server.Spells
{
public class SpellRegistry
{
private static Type[] m_Types = new Type[700];
private static int m_Count;
public static Type[] Types
{
get
{
m_Count = -1;
return m_Types;
}
}
//What IS this used for anyways.
public static int Count
{
get
{
if ( m_Count == -1 )
{
m_Count = 0;
for ( int i = 0; i < m_Types.Length; ++i )
if ( m_Types[i] != null )
++m_Count;
}
return m_Count;
}
}
private static Dictionary<Type, Int32> m_IDsFromTypes = new Dictionary<Type, Int32>( m_Types.Length );
public static int GetRegistryNumber( ISpell s )
{
return GetRegistryNumber( s.GetType() );
}
public static int GetRegistryNumber( Type type )
{
if( m_IDsFromTypes.ContainsKey( type ) )
return m_IDsFromTypes[type];
return -1;
}
public static void Register( int spellID, Type type )
{
if ( spellID < 0 || spellID >= m_Types.Length )
return;
if ( m_Types[spellID] == null )
++m_Count;
m_Types[spellID] = type;
if( !m_IDsFromTypes.ContainsKey( type ) )
m_IDsFromTypes.Add( type, spellID );
}
private static object[] m_Params = new object[2];
public static Spell NewSpell( int spellID, Mobile caster, Item scroll )
{
if ( spellID < 0 || spellID >= m_Types.Length )
return null;
Type t = m_Types[spellID];
if( t != null )
{
m_Params[0] = caster;
m_Params[1] = scroll;
try
{
return (Spell)Activator.CreateInstance( t, m_Params );
}
catch
{
}
}
return null;
}
private static string[] m_CircleNames = new string[]
{
"First",
"Second",
"Third",
"Fourth",
"Fifth",
"Sixth",
"Seventh",
"Eighth"
};
public static Spell NewSpell( string name, Mobile caster, Item scroll )
{
for ( int i = 0; i < m_CircleNames.Length; ++i )
{
Type t = ScriptCompiler.FindTypeByFullName( String.Format( "Server.Spells.{0}.{1}", m_CircleNames[i], name ) );
if ( t != null )
{
m_Params[0] = caster;
m_Params[1] = scroll;
try
{
return (Spell)Activator.CreateInstance( t, m_Params );
}
catch
{
}
}
}
return null;
}
}
}

View file

@ -0,0 +1,11 @@
using System;
namespace Server.Spells
{
public enum SpellState
{
None = 0,
Casting = 1, // We are in the process of casting (that is, waiting GetCastTime() and doing animations). Spell casting may be interupted in this state.
Sequencing = 2 // Casting completed, but the full spell sequence isn't. Usually waiting for a target response. Some actions are restricted in this state (using skills for example).
}
}

View file

@ -0,0 +1,24 @@
using System;
using Server.Mobiles;
namespace Server.Spells
{
class UnsummonTimer : Timer
{
private BaseCreature m_Creature;
private Mobile m_Caster;
public UnsummonTimer( Mobile caster, BaseCreature creature, TimeSpan delay ) : base( delay )
{
m_Caster = caster;
m_Creature = creature;
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
if ( !m_Creature.Deleted )
m_Creature.Delete();
}
}
}