This commit is contained in:
commit
47711d616e
2644 changed files with 479454 additions and 0 deletions
15
Scripts/Spells/Base/DisturbType.cs
Normal file
15
Scripts/Spells/Base/DisturbType.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using Server;
|
||||
|
||||
namespace Server.Spells
|
||||
{
|
||||
public enum DisturbType
|
||||
{
|
||||
Unspecified,
|
||||
EquipRequest,
|
||||
UseRequest,
|
||||
Hurt,
|
||||
Kill,
|
||||
NewCast
|
||||
}
|
||||
}
|
||||
337
Scripts/Spells/Base/SpecialMove.cs
Normal file
337
Scripts/Spells/Base/SpecialMove.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
942
Scripts/Spells/Base/Spell.cs
Normal file
942
Scripts/Spells/Base/Spell.cs
Normal 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 item’s 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Scripts/Spells/Base/SpellCircle.cs
Normal file
16
Scripts/Spells/Base/SpellCircle.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Spells
|
||||
{
|
||||
public enum SpellCircle
|
||||
{
|
||||
First,
|
||||
Second,
|
||||
Third,
|
||||
Fourth,
|
||||
Fifth,
|
||||
Sixth,
|
||||
Seventh,
|
||||
Eighth
|
||||
}
|
||||
}
|
||||
946
Scripts/Spells/Base/SpellHelper.cs
Normal file
946
Scripts/Spells/Base/SpellHelper.cs
Normal 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 );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
69
Scripts/Spells/Base/SpellInfo.cs
Normal file
69
Scripts/Spells/Base/SpellInfo.cs
Normal 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; } }
|
||||
}
|
||||
}
|
||||
182
Scripts/Spells/Base/SpellRegistry.cs
Normal file
182
Scripts/Spells/Base/SpellRegistry.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/Spells/Base/SpellState.cs
Normal file
11
Scripts/Spells/Base/SpellState.cs
Normal 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).
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue