This commit is contained in:
mark 2006-06-15 04:14:30 +00:00
commit 47711d616e
2644 changed files with 479454 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,337 @@
using System;
using System.Collections;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Network;
using Server.Spells.Ninjitsu;
using Server.Spells.Bushido;
namespace Server.Spells
{
public abstract class SpecialMove
{
public virtual int BaseMana{ get{ return 0; } }
public virtual SkillName MoveSkill{ get{ return SkillName.Bushido; } }
public virtual double RequiredSkill{ get{ return 0.0; } }
public virtual TextDefinition AbilityMessage{ get{ return 0; } }
public virtual bool BlockedByAnimalForm{ get{ return true; } }
public virtual bool DelayedContext{ get{ return false; } }
public virtual double GetAccuracyScalar( Mobile attacker )
{
return 1.0;
}
public virtual double GetDamageScalar( Mobile attacker, Mobile defender )
{
return 1.0;
}
// Called before swinging, to make sure the accuracy scalar is to be computed.
public virtual bool OnBeforeSwing( Mobile attacker, Mobile defender )
{
return true;
}
// Called when a hit connects, but before damage is calculated.
public virtual bool OnBeforeDamage( Mobile attacker, Mobile defender )
{
return true;
}
// Called as soon as the ability is used.
public virtual void OnUse( Mobile from )
{
}
// Called when a hit connects, at the end of the weapon.OnHit() method.
public virtual void OnHit( Mobile attacker, Mobile defender, int damage )
{
}
// Called when a hit misses.
public virtual void OnMiss( Mobile attacker, Mobile defender )
{
}
// Called when the move is cleared.
public virtual void OnClearMove( Mobile from )
{
}
public virtual bool IgnoreArmor( Mobile attacker )
{
return false;
}
public virtual double GetPropertyBonus( Mobile attacker )
{
return 1.0;
}
public virtual bool CheckSkills( Mobile m )
{
if ( m.Skills[MoveSkill].Value < RequiredSkill )
{
string args = String.Format( "{0}\t{1}\t ", RequiredSkill.ToString( "F1" ), MoveSkill.ToString() );
m.SendLocalizedMessage( 1063013, args ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
return false;
}
return true;
}
public virtual int ScaleMana( Mobile m, int mana )
{
double scalar = 1.0;
if ( !Server.Spells.Necromancy.MindRotSpell.GetMindRotScalar( m, ref scalar ) )
scalar = 1.0;
// Lower Mana Cost = 40%
int lmc = Math.Min( AosAttributes.GetValue( m, AosAttribute.LowerManaCost ), 40 );
scalar -= (double)lmc / 100;
int total = (int)(mana * scalar);
if ( m.Skills[MoveSkill].Value < 50.0 && GetContext( m ) != null )
total *= 2;
return total;
}
public virtual bool CheckMana( Mobile from, bool consume )
{
int mana = ScaleMana( from, BaseMana );
if ( from.Mana < mana )
{
from.SendLocalizedMessage( 1060181, mana.ToString() ); // You need ~1_MANA_REQUIREMENT~ mana to perform that attack
return false;
}
if ( consume )
{
if ( !DelayedContext )
SetContext( from );
from.Mana -= mana;
}
return true;
}
public virtual void SetContext( Mobile from )
{
if ( GetContext( from ) == null )
{
if ( DelayedContext || from.Skills[MoveSkill].Value < 50.0 )
{
Timer timer = new SpecialMoveTimer( from );
timer.Start();
AddContext( from, new SpecialMoveContext( timer, this.GetType() ) );
}
}
}
public virtual bool Validate( Mobile from )
{
if ( !from.Player )
return true;
if ( Bushido.HonorableExecution.IsUnderPenalty( from ) )
{
from.SendLocalizedMessage( 1063024 ); // You cannot perform this special move right now.
return false;
}
if ( Ninjitsu.AnimalForm.UnderTransformation( from ) )
{
from.SendLocalizedMessage( 1063024 ); // You cannot perform this special move right now.
return false;
}
return CheckSkills( from ) && CheckMana( from, false );
}
public virtual void CheckGain( Mobile m )
{
m.CheckSkill( MoveSkill, RequiredSkill, RequiredSkill + 37.5 );
}
private static Hashtable m_Table = new Hashtable();
public static Hashtable Table{ get{ return m_Table; } }
public static void ClearAllMoves( Mobile m )
{
foreach ( DictionaryEntry de in SpellRegistry.SpecialMoves )
{
SpecialMove move = (SpecialMove)de.Value;
int moveID = SpellRegistry.GetRegistryNumber( move );
if ( moveID != -1 )
m.Send( new ToggleSpecialAbility( moveID + 1, false ) );
}
}
public virtual bool ValidatesDuringHit{ get { return true; } }
public static SpecialMove GetCurrentMove( Mobile m )
{
if ( m == null )
return null;
if ( !Core.SE )
{
ClearCurrentMove( m );
return null;
}
SpecialMove move = (SpecialMove)m_Table[m];
if ( move != null && move.ValidatesDuringHit && !move.Validate( m ) )
{
ClearCurrentMove( m );
return null;
}
return move;
}
public static bool SetCurrentMove( Mobile m, SpecialMove move )
{
if ( !Core.SE )
{
ClearCurrentMove( m );
return false;
}
if ( move != null && !move.Validate( m ) )
{
ClearCurrentMove( m );
return false;
}
bool sameMove = ( move == GetCurrentMove( m ) );
ClearCurrentMove( m );
if ( sameMove )
return true;
if ( move != null )
{
WeaponAbility.ClearCurrentAbility( m );
m_Table[m] = move;
move.OnUse( m );
int moveID = SpellRegistry.GetRegistryNumber( move );
if ( moveID > 0 )
m.Send( new ToggleSpecialAbility( moveID + 1, true ) );
TextDefinition.SendMessageTo( m, move.AbilityMessage );
}
return true;
}
public static void ClearCurrentMove( Mobile m )
{
SpecialMove move = (SpecialMove)m_Table[m];
if ( move != null )
{
move.OnClearMove( m );
int moveID = SpellRegistry.GetRegistryNumber( move );
if ( moveID > 0 )
m.Send( new ToggleSpecialAbility( moveID + 1, false ) );
}
m_Table.Remove( m );
}
public SpecialMove()
{
}
private static Hashtable m_PlayersTable = new Hashtable();
private static void AddContext( Mobile m, SpecialMoveContext context )
{
m_PlayersTable[m] = context;
}
private static void RemoveContext( Mobile m )
{
SpecialMoveContext context = GetContext( m );
if ( context != null )
{
m_PlayersTable.Remove( m );
context.Timer.Stop();
}
}
private static SpecialMoveContext GetContext( Mobile m )
{
return ( m_PlayersTable[m] as SpecialMoveContext );
}
public static bool GetContext( Mobile m, Type type )
{
SpecialMoveContext context = m_PlayersTable[m] as SpecialMoveContext;
if ( context == null )
return false;
return ( context.Type == type );
}
private class SpecialMoveTimer : Timer
{
private Mobile m_Mobile;
public SpecialMoveTimer( Mobile from ) : base ( TimeSpan.FromSeconds( 3.0 ) )
{
m_Mobile = from;
Priority = TimerPriority.TwentyFiveMS;
}
protected override void OnTick()
{
RemoveContext( m_Mobile );
}
}
public class SpecialMoveContext
{
private Timer m_Timer;
private Type m_Type;
public Timer Timer{ get{ return m_Timer; } }
public Type Type{ get{ return m_Type; } }
public SpecialMoveContext( Timer timer, Type type )
{
m_Timer = timer;
m_Type = type;
}
}
}
}

View file

@ -0,0 +1,942 @@
using System;
using Server.Items;
using Server.Network;
using Server.Targeting;
using Server.Mobiles;
using Server.Spells.Second;
using Server.Spells.Necromancy;
using Server.Spells.Ninjitsu;
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 SpellCircle Circle{ get{ return m_Info.Circle; } }
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.EvalInt; } }
public virtual bool RevealOnCast{ get{ return true; } }
public virtual bool ClearHandsOnCast{ get{ return true; } }
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 Post-AoS 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, Dictionary<Mobile, Timer>> m_ContextTable = new Dictionary<Type, Dictionary<Mobile, Timer>>();
public void StartDelayedDamageContext( Mobile m, Timer t )
{
if( DelayedDamageStacking )
return; //Sanity
Dictionary<Mobile, Timer> contexts;
if( !m_ContextTable.TryGetValue( GetType(), out contexts ) )
{
contexts = new Dictionary<Mobile, Timer>();
m_ContextTable.Add( GetType(), contexts );
}
if( contexts.ContainsKey( m ) )
{
contexts[m].Stop();
contexts.Remove( m );
}
contexts.Add( m, t );
}
public void RemoveDelayedDamageContext( Mobile m )
{
Dictionary<Mobile, Timer> contexts;
if( !m_ContextTable.TryGetValue( GetType(), out contexts ) )
return;
contexts.Remove( m );
}
public Spell( Mobile caster, Item scroll, SpellInfo info )
{
m_Caster = caster;
m_Scroll = scroll;
m_Info = info;
}
public virtual int GetNewAosDamage( int bonus, int dice, int sides, Mobile singleTarget )
{
if( singleTarget != null )
{
return GetNewAosDamage( bonus, dice, sides, (Caster.Player && singleTarget.Player), GetDamageScalar( singleTarget ) );
}
else
{
return GetNewAosDamage( bonus, dice, sides, false );
}
}
public virtual int GetNewAosDamage( int bonus, int dice, int sides, bool playerVsPlayer )
{
return GetNewAosDamage( bonus, dice, sides, playerVsPlayer, 1.0 );
}
public virtual int GetNewAosDamage( int bonus, int dice, int sides, bool playerVsPlayer, double scalar )
{
int damage = Utility.Dice( dice, sides, bonus ) * 100;
int damageBonus = 0;
int inscribeSkill = GetInscribeFixed( m_Caster );
int inscribeBonus = (inscribeSkill + (1000 * (inscribeSkill / 1000))) / 200;
damageBonus += inscribeBonus;
int intBonus = Caster.Int / 10;
damageBonus += intBonus;
int sdiBonus = AosAttributes.GetValue( m_Caster, AosAttribute.SpellDamage );
// PvP spell damage increase cap of 15% from an items magic property
if ( playerVsPlayer && sdiBonus > 15 )
sdiBonus = 15;
damageBonus += sdiBonus;
damage = AOS.Scale( damage, 100 + damageBonus );
int evalSkill = GetDamageFixed( m_Caster );
int evalScale = 30 + ((9 * evalSkill) / 100);
damage = AOS.Scale( damage, evalScale );
damage = AOS.Scale( damage, (int)(scalar*100) );
return damage / 100;
}
/*
public virtual double GetAosDamage( int min, int random, double div )
{
double scale = 1.0;
scale += GetInscribeSkill( m_Caster ) * 0.001;
if ( Caster.Player )
{
scale += Caster.Int * 0.001;
scale += AosAttributes.GetValue( m_Caster, AosAttribute.SpellDamage ) * 0.01;
}
int baseDamage = min + (int)(GetDamageSkill( m_Caster ) / div);
double damage = Utility.RandomMinMax( baseDamage, baseDamage + random );
return damage * scale;
}
*/
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 ( 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;
if ( AosAttributes.GetValue( m_Caster, AosAttribute.LowerRegCost ) > Utility.Random( 100 ) )
return true;
Container pack = m_Caster.Backpack;
if ( pack == null )
return false;
if ( pack.ConsumeTotal( m_Info.Reagents, m_Info.Amounts ) == -1 )
return true;
if ( GetType().BaseType == typeof( Spell ) )
{
if ( ArcaneGem.ConsumeCharges( m_Caster, ( Core.SE ? 1 : 1 + (int)Circle ) ) )
return true;
}
return false;
}
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, 120.0 );
return ( n >= Utility.RandomDouble() );
}
public virtual double GetInscribeSkill( Mobile m )
{
// There is no chance to gain
// m.CheckSkill( SkillName.Inscribe, 0.0, 120.0 );
return m.Skills[SkillName.Inscribe].Value;
}
public virtual int GetInscribeFixed( Mobile m )
{
// There is no chance to gain
// m.CheckSkill( SkillName.Inscribe, 0.0, 120.0 );
return m.Skills[SkillName.Inscribe].Fixed;
}
public virtual int GetDamageFixed( Mobile m )
{
m.CheckSkill( DamageSkill, 0.0, 120.0 );
return m.Skills[DamageSkill].Fixed;
}
public virtual double GetDamageSkill( Mobile m )
{
m.CheckSkill( DamageSkill, 0.0, 120.0 );
return m.Skills[DamageSkill].Value;
}
public virtual int GetResistFixed( 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, 120.0 );
return m.Skills[SkillName.MagicResist].Fixed;
}
public virtual 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, 120.0 );
return m.Skills[SkillName.MagicResist].Value;
}
public virtual double GetResistPercentForCircle( Mobile target, SpellCircle circle )
{
double firstPercent = target.Skills[SkillName.MagicResist].Value / 5.0;
double secondPercent = target.Skills[SkillName.MagicResist].Value - (((m_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, m_Info.Circle );
}
public virtual double GetDamageScalar( Mobile target )
{
double scalar = 1.0;
if( !Core.AOS ) //EvalInt stuff for AoS is handled elsewhere
{
double casterEI = m_Caster.Skills[DamageSkill].Value;
double targetRS = target.Skills[SkillName.MagicResist].Value;
/*
if( Core.AOS )
targetRS = 0;
*/
m_Caster.CheckSkill( DamageSkill, 0.0, 120.0 );
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( !target.Player && !target.Body.IsHuman /*&& !Core.AOS*/ )
scalar *= 2.0; // Double magery damage to monsters/animals if not AOS
}
if ( target is BaseCreature )
((BaseCreature)target).AlterDamageScalarFrom( m_Caster, ref scalar );
if ( m_Caster is BaseCreature )
((BaseCreature)m_Caster).AlterDamageScalarTo( target, ref scalar );
if( Core.SE )
scalar *= GetSlayerDamageScalar( target );
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;
}
TransformContext context = TransformationSpell.GetContext( defender );
if( (atkBook.Slayer == SlayerName.Silver || atkBook.Slayer2 == SlayerName.Silver) && context != null && context.Type != typeof( HorrificBeastSpell ) )
scalar +=.25; // Every necromancer transformation other than horrific beast take an additional 25% damage
if( scalar != 1.0 )
return scalar;
}
ISlayer defISlayer = Spellbook.FindEquippedSpellbook( defender );
if( defISlayer == null )
defISlayer = defender.Weapon as ISlayer;
if( defISlayer != null )
{
SlayerEntry defSlayer = SlayerGroup.GetEntryByName( defISlayer.Slayer );
SlayerEntry defSlayer2 = SlayerGroup.GetEntryByName( defISlayer.Slayer2 );
if( defSlayer != null && defSlayer.Group.OppositionSuperSlays( m_Caster ) || defSlayer2 != null && defSlayer2.Group.OppositionSuperSlays( m_Caster ) )
scalar = 2.0;
}
return scalar;
}
public virtual void DoFizzle()
{
m_Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502632 ); // The spell fizzles.
if ( m_Caster.Player )
{
if ( Core.AOS )
m_Caster.FixedParticles( 0x3735, 1, 30, 9503, EffectLayer.Waist );
else
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 && Circle == SpellCircle.First && !Core.AOS )
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();
if ( Core.AOS && m_Caster.Player && type == DisturbType.Hurt )
DoHurtFizzle();
m_Caster.NextSpellTime = DateTime.Now + GetDisturbRecovery();
}
else if ( m_State == SpellState.Sequencing )
{
if ( !firstCircle && Circle == SpellCircle.First && !Core.AOS )
return;
m_State = SpellState.None;
m_Caster.Spell = null;
OnDisturb( type, false );
Targeting.Target.Cancel( m_Caster );
if ( Core.AOS && m_Caster.Player && type == DisturbType.Hurt )
DoHurtFizzle();
}
}
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 BlockedByHorrificBeast{ get{ return true; } }
public virtual bool BlockedByAnimalForm{ get{ return true; } }
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 ( Core.AOS && m_Caster.Spell is Spell && ((Spell)m_Caster.Spell).State == SpellState.Sequencing )
((Spell)m_Caster.Spell).Disturb( DisturbType.NewCast );
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 ( BlockedByHorrificBeast && TransformationSpell.UnderTransformation( m_Caster, typeof( HorrificBeastSpell ) ) || ( BlockedByAnimalForm && AnimalForm.UnderTransformation( m_Caster ) ))
{
m_Caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form.
}
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.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()
{
}
private const double ChanceOffset = 20.0, ChanceLength = 100.0 / 7.0;
public virtual void GetCastSkills( out double min, out double max )
{
int circle = (int)m_Info.Circle;
if ( m_Scroll != null )
circle -= 2;
double avg = ChanceLength * circle;
min = avg - ChanceOffset;
max = avg + ChanceOffset;
}
public virtual bool CheckFizzle()
{
if ( m_Scroll is BaseWand )
return true;
double minSkill, maxSkill;
GetCastSkills( out minSkill, out maxSkill );
return Caster.CheckSkill( CastSkill, minSkill, maxSkill );
}
private static int[] m_ManaTable = new int[]{ 4, 6, 9, 11, 14, 20, 40, 50 };
public virtual int GetMana()
{
if ( m_Scroll is BaseWand )
return 0;
return m_ManaTable[(int)Circle];
}
public virtual int ScaleMana( int mana )
{
double scalar = 1.0;
if ( !Necromancy.MindRotSpell.GetMindRotScalar( Caster, ref scalar ) )
scalar = 1.0;
// Lower Mana Cost = 40%
int lmc = AosAttributes.GetValue( m_Caster, AosAttribute.LowerManaCost );
if ( lmc > 40 )
lmc = 40;
scalar -= (double)lmc / 100;
return (int)(mana * scalar);
}
public virtual TimeSpan GetDisturbRecovery()
{
if ( Core.AOS )
return TimeSpan.Zero;
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 CastRecoveryCircleScalar{ get{ return 0; } }
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()
{
if ( !Core.AOS )
return NextSpellDelay;
int fcr = AosAttributes.GetValue( m_Caster, AosAttribute.CastRecovery );
int circleDelay = CastRecoveryCircleScalar * (1 + (int)Circle); // Note: Circle is 0-based so we must offset
int fcrDelay = -(CastRecoveryFastScalar * fcr);
int delay = CastRecoveryBase + circleDelay + fcrDelay;
if ( delay < CastRecoveryMinimum )
delay = CastRecoveryMinimum;
return TimeSpan.FromSeconds( (double)delay / CastRecoveryPerSecond );
}
public virtual int CastDelayBase{ get{ return 3; } }
public virtual int CastDelayCircleScalar{ get{ return 1; } }
public virtual int CastDelayFastScalar{ get{ return 1; } }
public virtual int CastDelayPerSecond{ get{ return 4; } }
public virtual int CastDelayMinimum{ get{ return 1; } }
public virtual TimeSpan GetCastDelay()
{
if ( m_Scroll is BaseWand )
return TimeSpan.Zero;
if ( !Core.AOS )
return TimeSpan.FromSeconds( 0.5 + (0.25 * (int)Circle) );
// Faster casting cap of 2 (if not using the protection spell)
// Faster casting cap of 0 (if using the protection spell)
// Paladin spells are subject to a faster casting cap of 4
// Paladins with magery of 70.0 or above are subject to a faster casting cap of 2
int fcMax = 2;
if ( CastSkill == SkillName.Chivalry && m_Caster.Skills[SkillName.Magery].Value < 70.0 )
fcMax = 4;
int fc = AosAttributes.GetValue( m_Caster, AosAttribute.CastSpeed );
if ( fc > fcMax )
fc = fcMax;
if ( ProtectionSpell.Registry.Contains( m_Caster ) )
fc -= 2;
// Circle is 0-based but we must not offset, first circle spells are cast at base delay.
int circleDelay = CastDelayCircleScalar * (int)Circle;
int fcDelay = -(CastDelayFastScalar * fc);
int delay = CastDelayBase + circleDelay + fcDelay;
if ( delay < CastDelayMinimum )
delay = CastDelayMinimum;
return TimeSpan.FromSeconds( (double)delay / CastDelayPerSecond );
}
public virtual void FinishSequence()
{
m_State = SpellState.None;
if ( m_Caster.Spell == this )
m_Caster.Spell = null;
}
public virtual int ComputeKarmaAward()
{
return 0;
}
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 is Runebook) && (m_Scroll.Amount <= 0 || m_Scroll.Deleted || m_Scroll.RootParent != m_Caster || (m_Scroll is BaseWand && (((BaseWand)m_Scroll).Charges <= 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 ( Core.AOS && (m_Caster.Frozen || m_Caster.Paralyzed) )
{
m_Caster.SendLocalizedMessage( 502646 ); // You cannot cast a spell while frozen.
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();
}
int karma = ComputeKarmaAward();
if ( karma != 0 )
Misc.Titles.AwardKarma( Caster, karma, true );
if ( TransformationSpell.UnderTransformation( m_Caster, typeof( VampiricEmbraceSpell ) ) )
{
bool garlic = false;
for ( int i = 0; !garlic && i < m_Info.Reagents.Length; ++i )
garlic = ( m_Info.Reagents[i] == Reagent.Garlic );
if ( garlic )
{
m_Caster.SendLocalizedMessage( 1061651 ); // The garlic burns you!
AOS.Damage( m_Caster, Utility.RandomMinMax( 17, 23 ), 100, 0, 0, 0, 0 );
}
}
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,946 @@
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;
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 AosDamageDelay = TimeSpan.FromSeconds( 1.0 );
private static TimeSpan OldDamageDelay = TimeSpan.FromSeconds( 0.5 );
public static TimeSpan GetDamageDelayForSpell( Spell sp )
{
if ( !sp.DelayedDamage )
return TimeSpan.Zero;
return ( Core.AOS ? AosDamageDelay : OldDamageDelay );
}
public static bool CheckMulti( Point3D p, Map map )
{
return CheckMulti( p, map, true );
}
public static bool CheckMulti( Point3D p, Map map, bool houses )
{
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 = (BaseMulti) sector.Multis[i];
if ( multi is BaseHouse )
{
if ( houses && ( (BaseHouse) multi ).IsInside( p, 16 ) )
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;
}
if ( Core.Expansion == Expansion.AOS )
{
for ( int i = 0; i < m.Aggressors.Count; ++i )
{
AggressorInfo info = m.Aggressors[i];
if ( info.Attacker.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 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 & 0x3FFF].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 )
{
if ( Core.AOS )
return TimeSpan.FromSeconds( ( ( 6 * caster.Skills.EvalInt.Fixed ) / 50 ) + 1 );
return TimeSpan.FromSeconds( 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.EvalInt.Fixed / 100) - (target.Skills.MagicResist.Fixed / 100);
else
percent = 1 + (caster.Skills.EvalInt.Fixed / 100);
percent *= 0.01;
if( percent < 0 )
percent = 0;
return percent;
}
public static int GetOffset( Mobile caster, Mobile target, StatType type, bool curse )
{
if ( Core.AOS )
{
if ( !m_DisableSkillCheck )
{
caster.CheckSkill( SkillName.EvalInt, 0.0, 120.0 );
if ( curse )
target.CheckSkill( SkillName.MagicResist, 0.0, 120.0 );
}
double percent = GetOffsetScalar( caster, target, curse );
switch ( type )
{
case StatType.Str:
return (int) ( target.RawStr * percent );
case StatType.Dex:
return (int) ( target.RawDex * percent );
case StatType.Int:
return (int) ( target.RawInt * percent );
}
}
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;
}
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.
}
private delegate bool TravelValidator( Map map, Point3D loc );
private static TravelValidator[] m_Validators = new TravelValidator[]
{
new TravelValidator( IsFeluccaT2A ),
new TravelValidator( IsIlshenar ),
new TravelValidator( IsTrammelWind ),
new TravelValidator( IsFeluccaWind ),
new TravelValidator( IsFeluccaDungeon ),
new TravelValidator( IsTrammelSolenHive ),
new TravelValidator( IsFeluccaSolenHive ),
new TravelValidator( IsCrystalCave ),
new TravelValidator( IsDoomGauntlet ),
new TravelValidator( IsDoomFerry ),
new TravelValidator( IsFactionStronghold ),
new TravelValidator( IsChampionSpawn ),
new TravelValidator( IsTokunoDungeon )
};
private static bool[,] m_Rules = new bool[,]
{
/*T2A(Fel) Ilshenar Wind(Tram), Wind(Fel), Dungeons(Fel), Solen(Tram), Solen(Fel), CrystalCave(Malas), Gauntlet(Malas), Gauntlet(Ferry), Stronghold, ChampionSpawn, Dungeons(Tokuno[Malas]) */
/* Recall From */ { false, true, true, false, false, true, false, false, false, false, true, true, true },
/* Recall To */ { false, false, false, false, false, false, false, false, false, false, false, false, false },
/* Gate From */ { false, false, false, false, false, false, false, false, false, false, false, false, false },
/* Gate To */ { false, false, false, false, false, false, false, false, false, false, false, false, false },
/* Mark In */ { false, false, false, false, false, false, false, false, false, false, false, false, false },
/* Tele From */ { true, true, true, true, true, true, true, false, true, true, false, true, true },
/* Tele To */ { true, true, true, true, true, true, true, false, true, false, false, true, true },
};
public static bool CheckTravel( Mobile caster, TravelCheckType type )
{
if ( CheckTravel( caster, caster.Map, caster.Location, type ) )
return true;
SendInvalidMessage( caster, type );
return false;
}
public static void SendInvalidMessage( Mobile caster, TravelCheckType type )
{
if ( type == TravelCheckType.RecallTo || type == TravelCheckType.GateTo )
caster.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there.
else if ( type == TravelCheckType.TeleportTo )
caster.SendLocalizedMessage( 501035 ); // You cannot teleport from here to the destination.
else
caster.SendLocalizedMessage( 501802 ); // Thy spell doth not appear to work...
}
public static bool CheckTravel( Map map, Point3D loc, TravelCheckType type )
{
return CheckTravel( null, map, loc, type );
}
private static Mobile m_TravelCaster;
private static TravelCheckType m_TravelType;
public static bool CheckTravel( Mobile caster, Map map, Point3D loc, TravelCheckType type )
{
if ( IsInvalid( map, loc ) ) // null, internal, out of bounds
{
if ( caster != null )
SendInvalidMessage( caster, type );
return false;
}
m_TravelCaster = caster;
m_TravelType = type;
int v = (int) type;
bool isValid = true;
for ( int i = 0; isValid && i < m_Validators.Length; ++i )
isValid = ( m_Rules[v, i] || !m_Validators[i]( map, loc ) );
if ( !isValid && caster != null )
SendInvalidMessage( caster, type );
return isValid;
}
public static bool IsWindLoc( Point3D loc )
{
int x = loc.X, y = loc.Y;
return ( x >= 5120 && y >= 0 && x < 5376 && y < 256 );
}
public static bool IsFeluccaWind( Map map, Point3D loc )
{
return ( map == Map.Felucca && IsWindLoc( loc ) );
}
public static bool IsTrammelWind( Map map, Point3D loc )
{
return ( map == Map.Trammel && IsWindLoc( loc ) );
}
public static bool IsIlshenar( Map map, Point3D loc )
{
return ( map == Map.Ilshenar );
}
public static bool IsSolenHiveLoc( Point3D loc )
{
int x = loc.X, y = loc.Y;
return ( x >= 5640 && y >= 1776 && x < 5935 && y < 2039 );
}
public static bool IsTrammelSolenHive( Map map, Point3D loc )
{
return ( map == Map.Trammel && IsSolenHiveLoc( loc ) );
}
public static bool IsFeluccaSolenHive( Map map, Point3D loc )
{
return ( map == Map.Felucca && IsSolenHiveLoc( loc ) );
}
public static bool IsFeluccaT2A( Map map, Point3D loc )
{
int x = loc.X, y = loc.Y;
return ( map == Map.Felucca && x >= 5120 && y >= 2304 && x < 6144 && y < 4096 );
}
public static bool IsAnyT2A( Map map, Point3D loc )
{
int x = loc.X, y = loc.Y;
return ( ( map == Map.Trammel || map == Map.Felucca ) && x >= 5120 && y >= 2304 && x < 6144 && y < 4096 );
}
public static bool IsFeluccaDungeon( Map map, Point3D loc )
{
Region region = Region.Find( loc, map );
return ( region.IsPartOf( typeof( DungeonRegion ) ) && region.Map == Map.Felucca );
}
public static bool IsCrystalCave( Map map, Point3D loc )
{
if ( map != Map.Malas )
return false;
int x = loc.X, y = loc.Y, z = loc.Z;
bool r1 = ( x >= 1182 && y >= 437 && x < 1211 && y < 470 );
bool r2 = ( x >= 1156 && y >= 470 && x < 1211 && y < 503 );
bool r3 = ( x >= 1176 && y >= 503 && x < 1208 && y < 509 );
bool r4 = ( x >= 1188 && y >= 509 && x < 1201 && y < 513 );
return ( z < -80 && ( r1 || r2 || r3 || r4 ) );
}
public static bool IsFactionStronghold( Map map, Point3D loc )
{
/*// Teleporting is allowed, but only for faction members
if ( !Core.AOS && m_TravelCaster != null && (m_TravelType == TravelCheckType.TeleportTo || m_TravelType == TravelCheckType.TeleportFrom) )
{
if ( Factions.Faction.Find( m_TravelCaster, true, true ) != null )
return false;
}*/
return ( Region.Find( loc, map ).IsPartOf( typeof( Factions.StrongholdRegion ) ) );
}
public static bool IsChampionSpawn( Map map, Point3D loc )
{
return ( Region.Find( loc, map ).IsPartOf( typeof( Engines.CannedEvil.ChampionSpawnRegion ) ) );
}
public static bool IsDoomFerry( Map map, Point3D loc )
{
if ( map != Map.Malas )
return false;
int x = loc.X, y = loc.Y;
if ( x >= 426 && y >= 314 && x <= 430 && y <= 331 )
return true;
if ( x >= 406 && y >= 247 && x <= 410 && y <= 264 )
return true;
return false;
}
public static bool IsTokunoDungeon( Map map, Point3D loc )
{
//The tokuno dungeons are really inside malas
if ( map != Map.Malas )
return false;
int x = loc.X, y = loc.Y, z = loc.Z;
bool r1 = ( x >= 0 && y >= 0 && x <= 128 && y <= 128 );
bool r2 = ( x >= 45 && y >= 320 && x < 195 && y < 710 );
return ( r1 || r2 );
}
public static bool IsDoomGauntlet( Map map, Point3D loc )
{
if ( map != Map.Malas )
return false;
int x = loc.X - 256, y = loc.Y - 304;
return ( x >= 0 && y >= 0 && x < 256 && y < 256 );
}
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;
GuardedRegion reg = (GuardedRegion) Region.Find( loc, map ).GetRegion( typeof( GuardedRegion ) );
return ( reg != null && !reg.IsDisabled() );
}
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;
}
//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) target ).OnDamagedBySpell( from );
}
public static void Damage( Spell spell, Mobile target, double damage, int phys, int fire, int cold, int pois, int nrgy )
{
TimeSpan ts = GetDamageDelayForSpell( spell );
Damage( spell, ts, target, spell.Caster, damage, phys, fire, cold, pois, nrgy, DFAlgorithm.Standard );
}
public static void Damage( Spell spell, Mobile target, double damage, int phys, int fire, int cold, int pois, int nrgy, DFAlgorithm dfa )
{
TimeSpan ts = GetDamageDelayForSpell( spell );
Damage( spell, ts, target, spell.Caster, damage, phys, fire, cold, pois, nrgy, dfa );
}
public static void Damage( TimeSpan delay, Mobile target, double damage, int phys, int fire, int cold, int pois, int nrgy )
{
Damage( delay, target, null, damage, phys, fire, cold, pois, nrgy );
}
public static void Damage( TimeSpan delay, Mobile target, Mobile from, double damage, int phys, int fire, int cold, int pois, int nrgy )
{
Damage( delay, target, from, damage, phys, fire, cold, pois, nrgy, DFAlgorithm.Standard );
}
public static void Damage( TimeSpan delay, Mobile target, Mobile from, double damage, int phys, int fire, int cold, int pois, int nrgy, DFAlgorithm dfa )
{
Damage( null, delay, target, from, damage, phys, fire, cold, pois, nrgy, dfa );
}
public static void Damage( Spell spell, TimeSpan delay, Mobile target, Mobile from, double damage, int phys, int fire, int cold, int pois, int nrgy, DFAlgorithm dfa )
{
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 );
WeightOverloading.DFA = dfa;
AOS.Damage( target, from, iDamage, phys, fire, cold, pois, nrgy );
WeightOverloading.DFA = DFAlgorithm.Standard;
}
else
{
new SpellDamageTimerAOS( spell, target, from, iDamage, phys, fire, cold, pois, nrgy, delay, dfa ).Start();
}
if ( target is BaseCreature && from != null && delay == TimeSpan.Zero )
( (BaseCreature) target ).OnDamagedBySpell( from );
}
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( from, 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_From );
}
}
private class SpellDamageTimerAOS : Timer
{
private Mobile m_Target, m_From;
private int m_Damage;
private int m_Phys, m_Fire, m_Cold, m_Pois, m_Nrgy;
private DFAlgorithm m_DFA;
private Spell m_Spell;
public SpellDamageTimerAOS( Spell s, Mobile target, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy, TimeSpan delay, DFAlgorithm dfa )
: base( delay )
{
m_Target = target;
m_From = from;
m_Damage = damage;
m_Phys = phys;
m_Fire = fire;
m_Cold = cold;
m_Pois = pois;
m_Nrgy = nrgy;
m_DFA = dfa;
m_Spell = s;
if ( m_Spell != null && m_Spell.DelayedDamage && !m_Spell.DelayedDamageStacking )
m_Spell.StartDelayedDamageContext( from, this );
Priority = TimerPriority.TwentyFiveMS;
}
protected override void OnTick()
{
if ( m_From is BaseCreature && m_Target != null )
( (BaseCreature) m_From ).AlterSpellDamageTo( m_Target, ref m_Damage );
if ( m_Target is BaseCreature && m_From != null )
( (BaseCreature) m_Target ).AlterSpellDamageFrom( m_From, ref m_Damage );
WeightOverloading.DFA = m_DFA;
AOS.Damage( m_Target, m_From, m_Damage, m_Phys, m_Fire, m_Cold, m_Pois, m_Nrgy );
WeightOverloading.DFA = DFAlgorithm.Standard;
if ( m_Target is BaseCreature && m_From != null )
( (BaseCreature) m_Target ).OnDamagedBySpell( m_From );
if ( m_Spell != null )
m_Spell.RemoveDelayedDamageContext( m_From );
}
}
}
}

View file

@ -0,0 +1,69 @@
using System;
using Server;
namespace Server.Spells
{
public class SpellInfo
{
private string m_Name;
private string m_Mantra;
private SpellCircle m_Circle;
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, SpellCircle circle, params Type[] regs ) : this( name, mantra, circle, 16, 0, 0, true, regs )
{
}
public SpellInfo( string name, string mantra, SpellCircle circle, bool allowTown, params Type[] regs ) : this( name, mantra, circle, 16, 0, 0, allowTown, regs )
{
}
public SpellInfo( string name, string mantra, SpellCircle circle, int action, params Type[] regs ) : this( name, mantra, circle, action, 0, 0, true, regs )
{
}
public SpellInfo( string name, string mantra, SpellCircle circle, int action, bool allowTown, params Type[] regs ) : this( name, mantra, circle, action, 0, 0, allowTown, regs )
{
}
public SpellInfo( string name, string mantra, SpellCircle circle, int action, int handEffect, params Type[] regs ) : this( name, mantra, circle, action, handEffect, handEffect, true, regs )
{
}
public SpellInfo( string name, string mantra, SpellCircle circle, int action, int handEffect, bool allowTown, params Type[] regs ) : this( name, mantra, circle, action, handEffect, handEffect, allowTown, regs )
{
}
public SpellInfo( string name, string mantra, SpellCircle circle, int action, int leftHandEffect, int rightHandEffect, bool allowTown, params Type[] regs )
{
m_Name = name;
m_Mantra = mantra;
m_Circle = circle;
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 SpellCircle Circle{ get{ return m_Circle; } set{ m_Circle = 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,182 @@
using System;
using System.IO;
using Server.Items;
using System.Collections;
using Server.Spells.Necromancy;
using Server.Spells.Chivalry;
using Server.Spells.Bushido;
using Server.Spells.Ninjitsu;
namespace Server.Spells
{
public class SpellRegistry
{
private static Type[] m_Types = new Type[600];
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;
}
}
public static int GetRegistryNumber( ISpell s )
{
return GetRegistryNumber( s.GetType() );
}
public static int GetRegistryNumber( SpecialMove s )
{
return GetRegistryNumber( s.GetType() );
}
private static Hashtable m_IDsFromTypes = new Hashtable( m_Types.Length );
public static int GetRegistryNumber( Type type )
{
if( m_IDsFromTypes.Contains( type ) )
return (int)m_IDsFromTypes[type];
return -1;
}
private static Hashtable m_SpecialMoves = new Hashtable();
public static Hashtable SpecialMoves { get { return m_SpecialMoves; } }
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[type] == null )
m_IDsFromTypes.Add( type, spellID );
if( type.IsSubclassOf( typeof( SpecialMove ) ) )
{
SpecialMove spm = null;
try
{
spm = Activator.CreateInstance( type ) as SpecialMove;
}
catch
{
}
if( spm != null )
m_SpecialMoves.Add( spellID, spm );
}
}
public static SpecialMove GetSpecialMove( int spellID )
{
if ( spellID < 0 || spellID >= m_Types.Length )
return null;
Type t = m_Types[spellID];
if ( t == null || !t.IsSubclassOf( typeof( SpecialMove ) ) ) //Ensure correct registration
return null;
if( m_SpecialMoves.ContainsKey( spellID ) )
return m_SpecialMoves[spellID] as SpecialMove;
return null;
}
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 && !t.IsSubclassOf( typeof( SpecialMove ) ) )
{
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",
"Necromancy",
"Chivalry",
"Bushido",
"Ninjitsu"
};
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 && !t.IsSubclassOf( typeof( SpecialMove ) ) )
{
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).
}
}