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).
}
}

View file

@ -0,0 +1,158 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
namespace Server.Spells.Bushido
{
public class Confidence : SamuraiSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Confidence", null,
SpellCircle.First, // 0 + 0.25 = 0.25s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 25.0; } }
public override int RequiredMana{ get{ return 10; } }
public Confidence( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnBeginCast()
{
base.OnBeginCast();
Caster.FixedEffect( 0x37C4, 10, 7, 4, 3 );
}
public override void OnCast()
{
if ( CheckSequence() )
{
Caster.SendLocalizedMessage( 1063115 ); // You exude confidence.
Caster.FixedParticles( 0x375A, 1, 17, 0x7DA, 0x960, 0x3, EffectLayer.Waist );
Caster.PlaySound( 0x51A );
OnCastSuccessful( Caster );
BeginConfidence( Caster );
BeginRegenerating( Caster );
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
public static bool IsConfident( Mobile m )
{
return m_Table.Contains( m );
}
public static void BeginConfidence( Mobile m )
{
Timer t = (Timer)m_Table[m];
if ( t != null )
t.Stop();
t = new InternalTimer( m );
m_Table[m] = t;
t.Start();
}
public static void EndConfidence( Mobile m )
{
Timer t = (Timer)m_Table[m];
if ( t != null )
t.Stop();
m_Table.Remove( m );
OnEffectEnd( m, typeof( Confidence ) );
}
private class InternalTimer : Timer
{
private Mobile m_Mobile;
public InternalTimer( Mobile m ) : base( TimeSpan.FromSeconds( 15.0 ) )
{
m_Mobile = m;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
EndConfidence( m_Mobile );
m_Mobile.SendLocalizedMessage( 1063116 ); // Your confidence wanes.
}
}
private static Hashtable m_RegenTable = new Hashtable();
public static bool IsRegenerating( Mobile m )
{
return m_RegenTable.Contains( m );
}
public static void BeginRegenerating( Mobile m )
{
Timer t = (Timer)m_RegenTable[m];
if ( t != null )
t.Stop();
t = new RegenTimer( m );
m_RegenTable[m] = t;
t.Start();
}
public static void StopRegenerating( Mobile m )
{
Timer t = (Timer)m_RegenTable[m];
if ( t != null )
t.Stop();
m_RegenTable.Remove( m );
}
private class RegenTimer : Timer
{
private Mobile m_Mobile;
private int m_Ticks;
private int m_Hits;
public RegenTimer( Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) )
{
m_Mobile = m;
m_Hits = 15 + (m.Skills.Bushido.Fixed * m.Skills.Bushido.Fixed / 57600);
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
++m_Ticks;
if ( m_Ticks >= 5 )
{
m_Mobile.Hits += (m_Hits - (m_Hits * 4 / 5));
StopRegenerating( m_Mobile );
}
m_Mobile.Hits += (m_Hits / 5);
}
}
}
}

View file

@ -0,0 +1,115 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Bushido
{
public class CounterAttack : SamuraiSpell
{
private static SpellInfo m_Info = new SpellInfo(
"CounterAttack", null,
SpellCircle.First, // 0 + 0.25 = 0.25s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 40.0; } }
public override int RequiredMana{ get{ return 5; } }
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( Caster.FindItemOnLayer( Layer.TwoHanded ) as BaseShield != null )
return true;
if ( Caster.FindItemOnLayer( Layer.OneHanded ) as BaseWeapon != null )
return true;
if ( Caster.FindItemOnLayer( Layer.TwoHanded ) as BaseWeapon != null )
return true;
Caster.SendLocalizedMessage( 1062944 ); // You must have a weapon or a shield equipped to use this ability!
return false;
}
public CounterAttack( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnBeginCast()
{
base.OnBeginCast();
Caster.FixedEffect( 0x37C4, 10, 7, 4, 3 );
}
public override void OnCast()
{
if ( CheckSequence() )
{
Caster.SendLocalizedMessage( 1063118 ); // You prepare to respond immediately to the next blocked blow.
OnCastSuccessful( Caster );
StartCountering( Caster );
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
public static bool IsCountering( Mobile m )
{
return m_Table.Contains( m );
}
public static void StartCountering( Mobile m )
{
Timer t = (Timer)m_Table[m];
if ( t != null )
t.Stop();
t = new InternalTimer( m );
m_Table[m] = t;
t.Start();
}
public static void StopCountering( Mobile m )
{
Timer t = (Timer)m_Table[m];
if ( t != null )
t.Stop();
m_Table.Remove( m );
OnEffectEnd( m, typeof( CounterAttack ) );
}
private class InternalTimer : Timer
{
private Mobile m_Mobile;
public InternalTimer( Mobile m ) : base( TimeSpan.FromSeconds( 30.0 ) )
{
m_Mobile = m;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
StopCountering( m_Mobile );
m_Mobile.SendLocalizedMessage( 1063119 ); // You return to your normal stance.
}
}
}
}

View file

@ -0,0 +1,115 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Bushido
{
public class Evasion : SamuraiSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Evasion", null,
SpellCircle.First, // 0 + 0.25 = 0.25s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 60.0; } }
public override int RequiredMana{ get{ return 10; } }
public override bool CheckCast()
{
if ( Caster.FindItemOnLayer( Layer.TwoHanded ) as BaseShield != null )
return base.CheckCast();
if ( Caster.FindItemOnLayer( Layer.OneHanded ) as BaseWeapon != null )
return base.CheckCast();
if ( Caster.FindItemOnLayer( Layer.TwoHanded ) as BaseWeapon != null )
return base.CheckCast();
Caster.SendLocalizedMessage( 1062944 ); // You must have a weapon or a shield equipped to use this ability!
return false;
}
public Evasion( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnBeginCast()
{
base.OnBeginCast();
Caster.FixedEffect( 0x37C4, 10, 7, 4, 3 );
}
public override void OnCast()
{
if ( CheckSequence() )
{
Caster.SendLocalizedMessage( 1063120 ); // You feel that you might be able to deflect any attack!
Caster.FixedParticles( 0x376A, 1, 20, 0x7F5, 0x960, 0x3, EffectLayer.Waist );
Caster.PlaySound( 0x51B );
OnCastSuccessful( Caster );
BeginEvasion( Caster );
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
public static bool IsEvading( Mobile m )
{
return m_Table.Contains( m );
}
public static void BeginEvasion( Mobile m )
{
Timer t = (Timer)m_Table[m];
if ( t != null )
t.Stop();
t = new InternalTimer( m );
m_Table[m] = t;
t.Start();
}
public static void EndEvasion( Mobile m )
{
Timer t = (Timer)m_Table[m];
if ( t != null )
t.Stop();
m_Table.Remove( m );
OnEffectEnd( m, typeof( Evasion ) );
}
private class InternalTimer : Timer
{
private Mobile m_Mobile;
public InternalTimer( Mobile m ) : base( TimeSpan.FromSeconds( 8.0 ) )
{
m_Mobile = m;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
EndEvasion( m_Mobile );
m_Mobile.SendLocalizedMessage( 1063121 ); // You no longer feel that you could deflect any attack.
}
}
}
}

View file

@ -0,0 +1,197 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Bushido
{
public class HonorableExecution : SamuraiMove
{
public HonorableExecution()
{
}
public override int BaseMana{ get{ return 0; } }
public override double RequiredSkill{ get{ return 25.0; } }
public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063122 ); } } // You better kill your enemy with your next hit or you'll be rather sorry...
public override double GetAccuracyScalar( Mobile attacker )
{
double bushido = attacker.Skills[SkillName.Bushido].Value;
// TODO: 4 -> Perfection / 5
return 1.0 + ( bushido / 10.0 + 4 ) / 100.0;
}
public override double GetDamageScalar( Mobile attacker, Mobile defender )
{
double bushido = attacker.Skills[SkillName.Bushido].Value;
// TODO: 20 -> Perfection
return 1.0 + (bushido * 20) / 10000;
}
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentMove( attacker );
HonorableExecutionInfo info = m_Table[attacker] as HonorableExecutionInfo;
if ( info != null )
{
info.Clear();
if ( info.m_Timer != null )
info.m_Timer.Stop();
}
if ( !defender.Alive )
{
attacker.FixedParticles( 0x373A, 1, 17, 0x7E2, EffectLayer.Waist );
double bushido = attacker.Skills[SkillName.Bushido].Value;
attacker.Hits += 20 + (int)((bushido * bushido) / 480.0);
int swingBonus = Math.Max( 1, (int)((bushido * bushido) / 720.0) );
info = new HonorableExecutionInfo( attacker, swingBonus );
info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 20.0 ), new TimerStateCallback( EndEffect ), info );
m_Table[attacker] = info;
}
else
{
ArrayList mods = new ArrayList();
mods.Add( new ResistanceMod( ResistanceType.Physical, -40 ) );
mods.Add( new ResistanceMod( ResistanceType.Fire, -40 ) );
mods.Add( new ResistanceMod( ResistanceType.Cold, -40 ) );
mods.Add( new ResistanceMod( ResistanceType.Poison, -40 ) );
mods.Add( new ResistanceMod( ResistanceType.Energy, -40 ) );
double resSpells = attacker.Skills[SkillName.MagicResist].Value;
if ( resSpells > 0.0 )
mods.Add( new DefaultSkillMod( SkillName.MagicResist, true, -resSpells ) );
info = new HonorableExecutionInfo( attacker, mods );
info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 7.0 ), new TimerStateCallback( EndEffect ), info );
m_Table[attacker] = info;
}
CheckGain( attacker );
}
private static Hashtable m_Table = new Hashtable();
public static int GetSwingBonus( Mobile target )
{
HonorableExecutionInfo info = m_Table[target] as HonorableExecutionInfo;
if ( info == null )
return 0;
return info.m_SwingBonus;
}
public static bool IsUnderPenalty( Mobile target )
{
HonorableExecutionInfo info = m_Table[target] as HonorableExecutionInfo;
if ( info == null )
return false;
return info.m_Penalty;
}
public static void RemovePenalty( Mobile target )
{
HonorableExecutionInfo info = m_Table[target] as HonorableExecutionInfo;
if ( info == null || !info.m_Penalty )
return;
info.Clear();
if ( info.m_Timer != null )
info.m_Timer.Stop();
m_Table.Remove( target );
}
private class HonorableExecutionInfo
{
public Mobile m_Mobile;
public int m_SwingBonus;
public ArrayList m_Mods;
public bool m_Penalty;
public Timer m_Timer;
public HonorableExecutionInfo( Mobile from, int swingBonus ) : this( from, swingBonus, null, false )
{
}
public HonorableExecutionInfo( Mobile from, ArrayList mods ) : this( from, 0, mods, true )
{
}
public HonorableExecutionInfo( Mobile from, int swingBonus, ArrayList mods, bool penalty )
{
m_Mobile = from;
m_SwingBonus = swingBonus;
m_Mods = mods;
m_Penalty = penalty;
Apply();
}
public void Apply()
{
if ( m_Mods == null )
return;
for ( int i = 0; i < m_Mods.Count; ++i )
{
object mod = m_Mods[i];
if ( mod is ResistanceMod )
m_Mobile.AddResistanceMod( (ResistanceMod) mod );
else if ( mod is SkillMod )
m_Mobile.AddSkillMod( (SkillMod) mod );
}
}
public void Clear()
{
if ( m_Mods == null )
return;
for ( int i = 0; i < m_Mods.Count; ++i )
{
object mod = m_Mods[i];
if ( mod is ResistanceMod )
m_Mobile.RemoveResistanceMod( (ResistanceMod) mod );
else if ( mod is SkillMod )
m_Mobile.RemoveSkillMod( (SkillMod) mod );
}
}
}
public void EndEffect( object state )
{
HonorableExecutionInfo info = (HonorableExecutionInfo)state;
RemovePenalty( info.m_Mobile );
}
}
}

View file

@ -0,0 +1,68 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Bushido
{
public class LightningStrike : SamuraiMove
{
public LightningStrike()
{
}
public override int BaseMana{ get{ return 5; } }
public override double RequiredSkill{ get{ return 50.0; } }
public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063167 ); } } // You prepare to strike quickly.
public override bool DelayedContext{ get{ return true; } }
public override double GetAccuracyScalar( Mobile attacker )
{
if ( GetContext( attacker, typeof( Bushido.LightningStrike ) ) )
return 1.1;
return 1.5;
}
public override bool IgnoreArmor( Mobile attacker )
{
double bushido = attacker.Skills[SkillName.Bushido].Value;
double criticalChance = (bushido * bushido) / 72000.0;
return ( criticalChance >= Utility.RandomDouble() );
}
public override bool OnBeforeSwing( Mobile attacker, Mobile defender )
{
return Validate( attacker ) && CheckMana( attacker, true );
}
public override bool ValidatesDuringHit { get { return false; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
//Validation in OnBeforeSwing
ClearCurrentMove( attacker );
attacker.SendLocalizedMessage( 1063168 ); // You attack with lightning precision!
defender.SendLocalizedMessage( 1063169 ); // Your opponent's quick strike causes extra damage!
CheckGain( attacker );
SetContext( attacker );
}
public override void OnMiss( Mobile attacker, Mobile defender )
{
ClearCurrentMove( attacker );
SetContext( attacker );
}
}
}

View file

@ -0,0 +1,75 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Bushido
{
public class MomentumStrike : SamuraiMove
{
public MomentumStrike()
{
}
public override int BaseMana{ get{ return 10; } }
public override double RequiredSkill{ get{ return 70.0; } }
public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1070757 ); } } // You prepare to strike two enemies with one blow.
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) || !CheckMana( attacker, false ) )
return;
ClearCurrentMove( attacker );
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
ArrayList targets = new ArrayList();
foreach ( Mobile m in attacker.GetMobilesInRange( weapon.MaxRange ) )
{
if ( m == defender )
continue;
if ( m.Combatant != attacker )
continue;
targets.Add( m );
}
if ( targets.Count > 0 )
{
if ( !CheckMana( attacker, true ) )
return;
Mobile target = (Mobile)targets[Utility.Random( targets.Count )];
double damageBonus = attacker.Skills[SkillName.Bushido].Value / 100.0;
if ( !defender.Alive )
damageBonus *= 1.5;
attacker.SendLocalizedMessage( 1063171 ); // You transfer the momentum of your weapon into another enemy!
target.SendLocalizedMessage( 1063172 ); // You were hit by the momentum of a Samurai's weapon!
target.FixedParticles( 0x37B9, 1, 4, 0x251D, 0, 0, EffectLayer.Waist );
weapon.OnSwing( attacker, target, damageBonus );
CheckGain( attacker );
}
else
{
attacker.SendLocalizedMessage( 1063123 ); // There are no valid targets to attack!
}
}
public override void CheckGain( Mobile m )
{
m.CheckSkill( MoveSkill, RequiredSkill, 120.0 );
}
}
}

View file

@ -0,0 +1,10 @@
using System;
using Server;
namespace Server.Spells
{
public class SamuraiMove : SpecialMove
{
public override SkillName MoveSkill{ get{ return SkillName.Bushido; } }
}
}

View file

@ -0,0 +1,126 @@
using System;
using Server;
using Server.Spells;
using Server.Network;
using Server.Items;
using Server.Mobiles;
namespace Server.Spells.Bushido
{
public abstract class SamuraiSpell : Spell
{
public abstract double RequiredSkill{ get; }
public abstract int RequiredMana{ get; }
public override SkillName CastSkill{ get{ return SkillName.Bushido; } }
public override bool ClearHandsOnCast{ get{ return false; } }
public override bool BlocksMovement{ get{ return false; } }
public override bool ShowHandMovement{ get{ return false; } }
public override int CastDelayBase{ get{ return 1; } }
public override int CastDelayFastScalar{ get{ return 0; } }
public override int CastRecoveryBase{ get{ return 7; } }
public SamuraiSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info )
{
}
public static bool CheckExpansion( Mobile from )
{
if ( !( from is PlayerMobile ) )
return true;
if ( from.NetState == null )
return false;
return ( (from.NetState.Flags & 0x10) != 0 );
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( !CheckExpansion( Caster ) )
{
Caster.SendLocalizedMessage( 1063456 ); // You must upgrade to Samurai Empire in order to use that ability.
return false;
}
if ( Caster.Skills[CastSkill].Value < RequiredSkill )
{
string args = String.Format( "{0}\t{1}\t ", RequiredSkill.ToString( "F1" ), CastSkill.ToString() );
Caster.SendLocalizedMessage( 1063013, args ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
return false;
}
else if ( Caster.Mana < ScaleMana( RequiredMana ) )
{
Caster.SendLocalizedMessage( 1060174, RequiredMana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
return false;
}
return true;
}
public override bool CheckFizzle()
{
int mana = ScaleMana( RequiredMana );
if ( Caster.Skills[CastSkill].Value < RequiredSkill )
{
Caster.SendLocalizedMessage( 1070768, RequiredSkill.ToString( "F1" ) ); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack!
return false;
}
else if ( Caster.Mana < mana )
{
Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
return false;
}
if ( !base.CheckFizzle() )
return false;
Caster.Mana -= mana;
return true;
}
public override void GetCastSkills( out double min, out double max )
{
min = RequiredSkill;
max = RequiredSkill + 37.5;
}
public override int GetMana()
{
return 0;
}
public virtual void OnCastSuccessful( Mobile caster )
{
if ( Evasion.IsEvading( caster ) )
Evasion.EndEvasion( caster );
if ( Confidence.IsConfident( caster ) )
Confidence.EndConfidence( caster );
if ( CounterAttack.IsCountering( caster ) )
CounterAttack.StopCountering( caster );
int spellID = SpellRegistry.GetRegistryNumber( this );
if ( spellID > 0 )
caster.Send( new ToggleSpecialAbility( spellID + 1, true ) );
}
public static void OnEffectEnd( Mobile caster, Type type )
{
int spellID = SpellRegistry.GetRegistryNumber( type );
if ( spellID > 0 )
caster.Send( new ToggleSpecialAbility( spellID + 1, false ) );
}
}
}

View file

@ -0,0 +1,115 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Chivalry
{
public class CleanseByFireSpell : PaladinSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Cleanse By Fire", "Expor Flamus",
SpellCircle.Fourth, // 0 + 1.0 = 1s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 5.0; } }
public override int RequiredMana{ get{ return 10; } }
public override int RequiredTithing{ get{ return 10; } }
public override int MantraNumber{ get{ return 1060718; } } // Expor Flamus
public CleanseByFireSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !m.Poisoned )
{
Caster.SendLocalizedMessage( 1060176 ); // That creature is not poisoned!
}
else if ( CheckBSequence( m ) )
{
SpellHelper.Turn( Caster, m );
/* Cures the target of poisons, but causes the caster to be burned by fire damage for 13-55 hit points.
* The amount of fire damage is lessened if the caster has high Karma.
*/
Poison p = m.Poison;
if ( p != null )
{
// Cleanse by fire is now difficulty based
int chanceToCure = 10000 + (int)(Caster.Skills[SkillName.Chivalry].Value * 75) - ((p.Level + 1) * 2000);
chanceToCure /= 100;
if ( chanceToCure > Utility.Random( 100 ) )
{
if ( m.CurePoison( Caster ) )
{
if ( Caster != m )
Caster.SendLocalizedMessage( 1010058 ); // You have cured the target of all poisons!
m.SendLocalizedMessage( 1010059 ); // You have been cured of all poisons.
}
}
else
{
m.SendLocalizedMessage( 1010060 ); // You have failed to cure your target!
}
}
m.PlaySound( 0x1E0 );
m.FixedParticles( 0x373A, 1, 15, 5012, 3, 2, EffectLayer.Waist );
IEntity from = new Entity( Serial.Zero, new Point3D( m.X, m.Y, m.Z - 5 ), m.Map );
IEntity to = new Entity( Serial.Zero, new Point3D( m.X, m.Y, m.Z + 45 ), m.Map );
Effects.SendMovingParticles( from, to, 0x374B, 1, 0, false, false, 63, 2, 9501, 1, 0, EffectLayer.Head, 0x100 );
Caster.PlaySound( 0x208 );
Caster.FixedParticles( 0x3709, 1, 30, 9934, 0, 7, EffectLayer.Waist );
int damage = 50 - ComputePowerValue( 4 );
// TODO: Should caps be applied?
if ( damage < 13 )
damage = 13;
else if ( damage > 55 )
damage = 55;
AOS.Damage( Caster, Caster, damage, 0, 100, 0, 0, 0, true );
}
FinishSequence();
}
private class InternalTarget : Target
{
private CleanseByFireSpell m_Owner;
public InternalTarget( CleanseByFireSpell owner ) : base( 12, false, TargetFlags.Beneficial )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,107 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Chivalry
{
public class CloseWoundsSpell : PaladinSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Close Wounds", "Obsu Vulni",
SpellCircle.Sixth, // 0 + 1.5 = 1.5s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 0.0; } }
public override int RequiredMana{ get{ return 10; } }
public override int RequiredTithing{ get{ return 10; } }
public override int MantraNumber{ get{ return 1060719; } } // Obsu Vulni
public CloseWoundsSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.InRange( m, 2 ) )
{
Caster.SendLocalizedMessage( 1060178 ); // You are too far away to perform that action!
}
else if ( m is BaseCreature && ((BaseCreature)m).IsAnimatedDead )
{
Caster.SendLocalizedMessage( 1061654 ); // You cannot heal that which is not alive.
}
else if ( m.IsDeadBondedPet )
{
Caster.SendLocalizedMessage( 1060177 ); // You cannot heal a creature that is already dead!
}
else if ( m.Hits >= m.HitsMax )
{
Caster.SendLocalizedMessage( 500955 ); // That being is not damaged!
}
else if ( m.Poisoned || Server.Items.MortalStrike.IsWounded( m ) )
{
Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, (Caster == m) ? 1005000 : 1010398 );
}
else if ( CheckBSequence( m ) )
{
SpellHelper.Turn( Caster, m );
/* Heals the target for 7 to 39 points of damage.
* The caster's Karma affects the amount of damage healed.
*/
int toHeal = ComputePowerValue( 6 ) + Utility.RandomMinMax( 0, 2 );
// TODO: Should caps be applied?
if ( toHeal < 7 )
toHeal = 7;
else if ( toHeal > 39 )
toHeal = 39;
if ( (m.Hits + toHeal) > m.HitsMax )
toHeal = m.HitsMax - m.Hits;
m.Hits += toHeal;
m.SendLocalizedMessage( 1060203, toHeal.ToString() ); // You have had ~1_HEALED_AMOUNT~ hit points of damage healed.
m.PlaySound( 0x202 );
m.FixedParticles( 0x376A, 1, 62, 9923, 3, 3, EffectLayer.Waist );
m.FixedParticles( 0x3779, 1, 46, 9502, 5, 3, EffectLayer.Waist );
}
FinishSequence();
}
private class InternalTarget : Target
{
private CloseWoundsSpell m_Owner;
public InternalTarget( CloseWoundsSpell owner ) : base( 12, false, TargetFlags.Beneficial )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,106 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Chivalry
{
public class ConsecrateWeaponSpell : PaladinSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Consecrate Weapon", "Consecrus Arma",
SpellCircle.Second, // 0 + 0.5 = 0.5s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 15.0; } }
public override int RequiredMana{ get{ return 10; } }
public override int RequiredTithing{ get{ return 10; } }
public override int MantraNumber{ get{ return 1060720; } } // Consecrus Arma
public override bool BlocksMovement{ get{ return false; } }
public ConsecrateWeaponSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
BaseWeapon weapon = Caster.Weapon as BaseWeapon;
if ( weapon == null || weapon is Fists )
{
Caster.SendLocalizedMessage( 501078 ); // You must be holding a weapon.
}
else if ( CheckSequence() )
{
/* Temporarily enchants the weapon the caster is currently wielding.
* The type of damage the weapon inflicts when hitting a target will
* be converted to the target's worst Resistance type.
* Duration of the effect is affected by the caster's Karma and lasts for 3 to 11 seconds.
*/
int itemID, soundID;
switch ( weapon.Skill )
{
case SkillName.Macing: itemID = 0xFB4; soundID = 0x232; break;
case SkillName.Archery: itemID = 0x13B1; soundID = 0x145; break;
default: itemID = 0xF5F; soundID = 0x56; break;
}
Caster.PlaySound( 0x20C );
Caster.PlaySound( soundID );
Caster.FixedParticles( 0x3779, 1, 30, 9964, 3, 3, EffectLayer.Waist );
IEntity from = new Entity( Serial.Zero, new Point3D( Caster.X, Caster.Y, Caster.Z ), Caster.Map );
IEntity to = new Entity( Serial.Zero, new Point3D( Caster.X, Caster.Y, Caster.Z + 50 ), Caster.Map );
Effects.SendMovingParticles( from, to, itemID, 1, 0, false, false, 33, 3, 9501, 1, 0, EffectLayer.Head, 0x100 );
double seconds = ComputePowerValue( 20 );
// TODO: Should caps be applied?
if ( seconds < 3.0 )
seconds = 3.0;
else if ( seconds > 11.0 )
seconds = 11.0;
TimeSpan duration = TimeSpan.FromSeconds( seconds );
Timer t = (Timer)m_Table[weapon];
if ( t != null )
t.Stop();
weapon.Consecrated = true;
m_Table[weapon] = t = new ExpireTimer( weapon, duration );
t.Start();
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
private class ExpireTimer : Timer
{
private BaseWeapon m_Weapon;
public ExpireTimer( BaseWeapon weapon, TimeSpan delay ) : base( delay )
{
m_Weapon = weapon;
Priority = TimerPriority.FiftyMS;
}
protected override void OnTick()
{
m_Weapon.Consecrated = false;
Effects.PlaySound( m_Weapon.GetWorldLocation(), m_Weapon.Map, 0x1F8 );
m_Table.Remove( this );
}
}
}
}

View file

@ -0,0 +1,116 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
using Server.Mobiles;
using Server.Spells.Necromancy;
namespace Server.Spells.Chivalry
{
public class DispelEvilSpell : PaladinSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Dispel Evil", "Dispiro Malas",
SpellCircle.First, // 0 + 0.25 = 0.25s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 35.0; } }
public override int RequiredMana{ get{ return 10; } }
public override int RequiredTithing{ get{ return 10; } }
public override int MantraNumber{ get{ return 1060721; } } // Dispiro Malas
public override bool BlocksMovement{ get{ return false; } }
public DispelEvilSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool DelayedDamage{ get{ return false; } }
public override void SendCastEffect()
{
Caster.FixedEffect( 0x37C4, 10, 7, 4, 3 ); // At player
}
public override void OnCast()
{
if ( CheckSequence() )
{
ArrayList targets = new ArrayList();
foreach ( Mobile m in Caster.GetMobilesInRange( 8 ) )
{
if ( Caster != m && SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) )
targets.Add( m );
}
Caster.PlaySound( 0x299 );
Caster.FixedParticles( 0x37C4, 1, 25, 9922, 14, 3, EffectLayer.Head );
int dispelSkill = ComputePowerValue( 2 );
double chiv = Caster.Skills.Chivalry.Value;
for ( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
BaseCreature bc = m as BaseCreature;
if ( bc != null )
{
bool dispellable = bc.Summoned && !bc.IsAnimatedDead;
if ( dispellable )
{
double dispelChance = (50.0 + ((100 * (chiv - bc.DispelDifficulty)) / (bc.DispelFocus*2))) / 100;
dispelChance *= dispelSkill / 100.0;
if ( dispelChance > Utility.RandomDouble() )
{
Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x3728, 8, 20, 5042 );
Effects.PlaySound( m, m.Map, 0x201 );
m.Delete();
continue;
}
}
bool evil = !bc.Controlled && bc.Karma < 0;
if ( evil )
{
// TODO: Is this right?
double fleeChance = (100 - Math.Sqrt( m.Fame / 2 )) * chiv * dispelSkill;
fleeChance /= 1000000;
if ( fleeChance > Utility.RandomDouble() )
{
// guide says 2 seconds, it's longer
bc.BeginFlee( TimeSpan.FromSeconds( 30.0 ) );
}
}
}
if ( TransformationSpell.GetContext( m ) != null )
{
// transformed ..
double drainChance = 0.5 * (Caster.Skills.Chivalry.Value / Math.Max( m.Skills.Necromancy.Value, 1 ));
if ( drainChance > Utility.RandomDouble() )
{
int drain = (5 * dispelSkill) / 100;
m.Stam -= drain;
m.Mana -= drain;
}
}
}
}
FinishSequence();
}
}
}

View file

@ -0,0 +1,76 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Chivalry
{
public class DivineFurySpell : PaladinSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Divine Fury", "Divinum Furis",
SpellCircle.Fourth, // 0 + 1.0 = 1s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 25.0; } }
public override int RequiredMana{ get{ return 15; } }
public override int RequiredTithing{ get{ return 10; } }
public override int MantraNumber{ get{ return 1060722; } } // Divinum Furis
public override bool BlocksMovement{ get{ return false; } }
public DivineFurySpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
if ( CheckSequence() )
{
Caster.PlaySound( 0x20F );
Caster.PlaySound( Caster.Body.IsFemale ? 0x338 : 0x44A );
Caster.FixedParticles( 0x376A, 1, 31, 9961, 1160, 0, EffectLayer.Waist );
Caster.FixedParticles( 0x37C4, 1, 31, 9502, 43, 2, EffectLayer.Waist );
Caster.Stam = Caster.StamMax;
Timer t = (Timer)m_Table[Caster];
if ( t != null )
t.Stop();
int delay = ComputePowerValue( 10 );
// TODO: Should caps be applied?
if ( delay < 7 )
delay = 7;
else if ( delay > 24 )
delay = 24;
m_Table[Caster] = t = Timer.DelayCall( TimeSpan.FromSeconds( delay ), new TimerStateCallback( Expire_Callback ), Caster );
Caster.Delta( MobileDelta.WeaponDamage );
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
public static bool UnderEffect( Mobile m )
{
return m_Table.Contains( m );
}
private static void Expire_Callback( object state )
{
Mobile m = (Mobile)state;
m_Table.Remove( m );
m.Delta( MobileDelta.WeaponDamage );
m.PlaySound( 0xF8 );
}
}
}

View file

@ -0,0 +1,81 @@
using System;
using System.Collections;
using Server;
using Server.Mobiles;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Chivalry
{
public class EnemyOfOneSpell : PaladinSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Enemy of One", "Forul Solum",
SpellCircle.Second, // 0 + 0.5 = 0.5s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 45.0; } }
public override int RequiredMana{ get{ return 20; } }
public override int RequiredTithing{ get{ return 10; } }
public override int MantraNumber{ get{ return 1060723; } } // Forul Solum
public override bool BlocksMovement{ get{ return false; } }
public EnemyOfOneSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
if ( CheckSequence() )
{
Caster.PlaySound( 0x0F5 );
Caster.PlaySound( 0x1ED );
Caster.FixedParticles( 0x375A, 1, 30, 9966, 33, 2, EffectLayer.Head );
Caster.FixedParticles( 0x37B9, 1, 30, 9502, 43, 3, EffectLayer.Head );
Timer t = (Timer)m_Table[Caster];
if ( t != null )
t.Stop();
double delay = (double)ComputePowerValue( 1 ) / 60;
// TODO: Should caps be applied?
if ( delay < 1.5 )
delay = 1.5;
else if ( delay > 3.5 )
delay = 3.5;
m_Table[Caster] = Timer.DelayCall( TimeSpan.FromMinutes( delay ), new TimerStateCallback( Expire_Callback ), Caster );
if ( Caster is PlayerMobile )
{
((PlayerMobile)Caster).EnemyOfOneType = null;
((PlayerMobile)Caster).WaitingForEnemy = true;
}
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
private static void Expire_Callback( object state )
{
Mobile m = (Mobile)state;
m_Table.Remove( m );
m.PlaySound( 0x1F8 );
if ( m is PlayerMobile )
{
((PlayerMobile)m).EnemyOfOneType = null;
((PlayerMobile)m).WaitingForEnemy = false;
}
}
}
}

View file

@ -0,0 +1,68 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Chivalry
{
public class HolyLightSpell : PaladinSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Holy Light", "Augus Luminos",
SpellCircle.Seventh, // 0 + 1.75 = 1.75s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 55.0; } }
public override int RequiredMana{ get{ return 10; } }
public override int RequiredTithing{ get{ return 10; } }
public override int MantraNumber{ get{ return 1060724; } } // Augus Luminos
public override bool BlocksMovement{ get{ return false; } }
public HolyLightSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool DelayedDamage{ get{ return false; } }
public override void OnCast()
{
if ( CheckSequence() )
{
ArrayList targets = new ArrayList();
foreach ( Mobile m in Caster.GetMobilesInRange( 3 ) )
{
if ( Caster != m && SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) )
targets.Add( m );
}
Caster.PlaySound( 0x212 );
Caster.PlaySound( 0x206 );
Effects.SendLocationParticles( EffectItem.Create( Caster.Location, Caster.Map, EffectItem.DefaultDuration ), 0x376A, 1, 29, 0x47D, 2, 9962, 0 );
Effects.SendLocationParticles( EffectItem.Create( new Point3D( Caster.X, Caster.Y, Caster.Z - 7 ), Caster.Map, EffectItem.DefaultDuration ), 0x37C4, 1, 29, 0x47D, 2, 9502, 0 );
for ( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
int damage = ComputePowerValue( 10 ) + Utility.RandomMinMax( 0, 2 );
// TODO: Should caps be applied?
if ( damage < 8 )
damage = 8;
else if ( damage > 24 )
damage = 24;
Caster.DoHarmful( m );
SpellHelper.Damage( this, m, damage, 0, 0, 0, 0, 100 );
}
}
FinishSequence();
}
}
}

View file

@ -0,0 +1,175 @@
using System;
using System.Collections;
using Server;
using Server.Mobiles;
using Server.Network;
using Server.Items;
using Server.Targeting;
using Server.Gumps;
using Server.Spells.Necromancy;
using Server.Regions;
namespace Server.Spells.Chivalry
{
public class NobleSacrificeSpell : PaladinSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Noble Sacrifice", "Dium Prostra",
SpellCircle.Sixth, // 0 + 1.5 = 1.5s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 65.0; } }
public override int RequiredMana{ get{ return 20; } }
public override int RequiredTithing{ get{ return 30; } }
public override int MantraNumber{ get{ return 1060725; } } // Dium Prostra
public override bool BlocksMovement{ get{ return false; } }
public NobleSacrificeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
if ( CheckSequence() )
{
ArrayList targets = new ArrayList();
foreach ( Mobile m in Caster.GetMobilesInRange( 3 ) ) // TODO: Validate range
{
if ( m is BaseCreature && ((BaseCreature)m).IsAnimatedDead )
continue;
if ( Caster != m && Caster.CanBeBeneficial( m, false, true ) && !(m is Golem) )
targets.Add( m );
}
Caster.PlaySound( 0x244 );
Caster.FixedParticles( 0x3709, 1, 30, 9965, 5, 7, EffectLayer.Waist );
Caster.FixedParticles( 0x376A, 1, 30, 9502, 5, 3, EffectLayer.Waist );
/* Attempts to Resurrect, Cure and Heal all targets in a radius around the caster.
* If any target is successfully assisted, the Paladin's current
* Hit Points, Mana and Stamina are set to 1.
* Amount of damage healed is affected by the Caster's Karma, from 8 to 24 hit points.
*/
bool sacrifice = false;
// TODO: Is there really a resurrection chance?
double resChance = 0.1 + (0.9 * ((double)Caster.Karma / 10000));
for ( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
if ( !m.Alive )
{
if ( m.Region != null && m.Region.IsPartOf( "Khaldun" ) )
{
Caster.SendLocalizedMessage( 1010395 ); // The veil of death in this area is too strong and resists thy efforts to restore life.
}
else if( Core.ML && m.Region != null && m.Region.IsPartOf( typeof( HouseRegion ) ) )
{
}
else if( resChance > Utility.RandomDouble() )
{
m.FixedParticles( 0x375A, 1, 15, 5005, 5, 3, EffectLayer.Head );
m.CloseGump( typeof( ResurrectGump ) );
m.SendGump( new ResurrectGump( m, Caster ) );
sacrifice = true;
}
}
else
{
bool sendEffect = false;
if ( m.Poisoned && m.CurePoison( Caster ) )
{
Caster.DoBeneficial( m );
if ( Caster != m )
Caster.SendLocalizedMessage( 1010058 ); // You have cured the target of all poisons!
m.SendLocalizedMessage( 1010059 ); // You have been cured of all poisons.
sendEffect = true;
sacrifice = true;
}
if ( m.Hits < m.HitsMax )
{
int toHeal = ComputePowerValue( 10 ) + Utility.RandomMinMax( 0, 2 );
// TODO: Should caps be applied?
if ( toHeal < 8 )
toHeal = 8;
else if ( toHeal > 24 )
toHeal = 24;
Caster.DoBeneficial( m );
m.Heal( toHeal );
sendEffect = true;
}
StatMod mod;
mod = m.GetStatMod( "[Magic] Str Offset" );
if ( mod != null && mod.Offset < 0 )
{
m.RemoveStatMod( "[Magic] Str Offset" );
sendEffect = true;
}
mod = m.GetStatMod( "[Magic] Dex Offset" );
if ( mod != null && mod.Offset < 0 )
{
m.RemoveStatMod( "[Magic] Dex Offset" );
sendEffect = true;
}
mod = m.GetStatMod( "[Magic] Int Offset" );
if ( mod != null && mod.Offset < 0 )
{
m.RemoveStatMod( "[Magic] Int Offset" );
sendEffect = true;
}
if ( m.Paralyzed )
{
m.Paralyzed = false;
sendEffect = true;
}
if ( EvilOmenSpell.CheckEffect( m ) )
sendEffect = true;
if ( StrangleSpell.RemoveCurse( m ) )
sendEffect = true;
if ( CorpseSkinSpell.RemoveCurse( m ) )
sendEffect = true;
// TODO: Should this remove blood oath? Pain spike?
if ( sendEffect )
{
m.FixedParticles( 0x375A, 1, 15, 5005, 5, 3, EffectLayer.Head );
sacrifice = true;
}
}
}
if ( sacrifice )
{
Caster.PlaySound( 0x423 );
Caster.Hits = 1;
Caster.Stam = 1;
Caster.Mana = 1;
}
}
FinishSequence();
}
}
}

View file

@ -0,0 +1,148 @@
using System;
using Server;
using Server.Spells;
using Server.Network;
namespace Server.Spells.Chivalry
{
public abstract class PaladinSpell : Spell
{
public abstract double RequiredSkill{ get; }
public abstract int RequiredMana{ get; }
public abstract int RequiredTithing{ get; }
public abstract int MantraNumber{ get; }
public override SkillName CastSkill{ get{ return SkillName.Chivalry; } }
public override bool ClearHandsOnCast{ get{ return false; } }
public override int CastDelayBase{ get{ return 1; } }
public override int CastRecoveryBase{ get{ return 7; } }
public PaladinSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info )
{
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( Caster.Skills[SkillName.Chivalry].Value < RequiredSkill )
{
Caster.SendLocalizedMessage( 1060172, RequiredSkill.ToString( "F1" ) ); // You must have at least ~1_SKILL_REQUIREMENT~ Chivalry to use this ability,
return false;
}
else if ( Caster.TithingPoints < RequiredTithing )
{
Caster.SendLocalizedMessage( 1060173, RequiredTithing.ToString() ); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability,
return false;
}
else if ( Caster.Mana < ScaleMana( RequiredMana ) )
{
Caster.SendLocalizedMessage( 1060174, RequiredMana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
return false;
}
return true;
}
public override bool CheckFizzle()
{
int requiredTithing = this.RequiredTithing;
if ( AosAttributes.GetValue( Caster, AosAttribute.LowerRegCost ) > Utility.Random( 100 ) )
requiredTithing = 0;
int mana = ScaleMana( RequiredMana );
if ( Caster.Skills[SkillName.Chivalry].Value < RequiredSkill )
{
Caster.SendLocalizedMessage( 1060172, RequiredSkill.ToString( "F1" ) ); // You must have at least ~1_SKILL_REQUIREMENT~ Chivalry to use this ability,
return false;
}
else if ( Caster.TithingPoints < requiredTithing )
{
Caster.SendLocalizedMessage( 1060173, RequiredTithing.ToString() ); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability,
return false;
}
else if ( Caster.Mana < mana )
{
Caster.SendLocalizedMessage( 1060174, RequiredMana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
return false;
}
Caster.TithingPoints -= requiredTithing;
if ( !base.CheckFizzle() )
return false;
Caster.Mana -= mana;
return true;
}
public override void SayMantra()
{
Caster.PublicOverheadMessage( MessageType.Regular, 0x3B2, MantraNumber, "", false );
}
public override void DoFizzle()
{
Caster.PlaySound( 0x1D6 );
Caster.NextSpellTime = DateTime.Now;
}
public override void DoHurtFizzle()
{
Caster.PlaySound( 0x1D6 );
}
public override void OnDisturb( DisturbType type, bool message )
{
base.OnDisturb( type, message );
if ( message )
Caster.PlaySound( 0x1D6 );
}
public override void OnBeginCast()
{
base.OnBeginCast();
SendCastEffect();
}
public virtual void SendCastEffect()
{
Caster.FixedEffect( 0x37C4, 10, 42, 4, 3 );
}
public override void GetCastSkills( out double min, out double max )
{
min = RequiredSkill;
max = RequiredSkill + 50.0;
}
public override int GetMana()
{
return 0;
}
public int ComputePowerValue( int div )
{
return ComputePowerValue( Caster, div );
}
public static int ComputePowerValue( Mobile from, int div )
{
if ( from == null )
return 0;
int v = (int) Math.Sqrt( from.Karma + 20000 + (from.Skills.Chivalry.Fixed * 10) );
return v / div;
}
}
}

View file

@ -0,0 +1,125 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
using Server.Spells.Necromancy;
using Server.Spells.Fourth;
namespace Server.Spells.Chivalry
{
public class RemoveCurseSpell : PaladinSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Remove Curse", "Extermo Vomica",
SpellCircle.Sixth, // 0 + 1.5 = 1.5s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 5.0; } }
public override int RequiredMana{ get{ return 20; } }
public override int RequiredTithing{ get{ return 10; } }
public override int MantraNumber{ get{ return 1060726; } } // Extermo Vomica
public RemoveCurseSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( CheckBSequence( m ) )
{
SpellHelper.Turn( Caster, m );
/* Attempts to remove all Curse effects from Target.
* Curses include Mage spells such as Clumsy, Weaken, Feeblemind and Paralyze
* as well as all Necromancer curses.
* Chance of removing curse is affected by Caster's Karma.
*/
int chance = 0;
if ( Caster.Karma < -5000 )
chance = 0;
else if ( Caster.Karma < 0 )
chance = (int) Math.Sqrt( 20000 + Caster.Karma ) - 122;
else if ( Caster.Karma < 5625 )
chance = (int) Math.Sqrt( Caster.Karma ) + 25;
else
chance = 100;
if ( chance > Utility.Random( 100 ) )
{
m.PlaySound( 0xF6 );
m.PlaySound( 0x1F7 );
m.FixedParticles( 0x3709, 1, 30, 9963, 13, 3, EffectLayer.Head );
IEntity from = new Entity( Serial.Zero, new Point3D( m.X, m.Y, m.Z - 10 ), Caster.Map );
IEntity to = new Entity( Serial.Zero, new Point3D( m.X, m.Y, m.Z + 50 ), Caster.Map );
Effects.SendMovingParticles( from, to, 0x2255, 1, 0, false, false, 13, 3, 9501, 1, 0, EffectLayer.Head, 0x100 );
StatMod mod;
mod = m.GetStatMod( "[Magic] Str Offset" );
if ( mod != null && mod.Offset < 0 )
m.RemoveStatMod( "[Magic] Str Offset" );
mod = m.GetStatMod( "[Magic] Dex Offset" );
if ( mod != null && mod.Offset < 0 )
m.RemoveStatMod( "[Magic] Dex Offset" );
mod = m.GetStatMod( "[Magic] Int Offset" );
if ( mod != null && mod.Offset < 0 )
m.RemoveStatMod( "[Magic] Int Offset" );
m.Paralyzed = false;
EvilOmenSpell.CheckEffect( m );
StrangleSpell.RemoveCurse( m );
CorpseSkinSpell.RemoveCurse( m );
CurseSpell.RemoveEffect( m );
BuffInfo.RemoveBuff( m, BuffIcon.Clumsy );
BuffInfo.RemoveBuff( m, BuffIcon.FeebleMind );
BuffInfo.RemoveBuff( m, BuffIcon.Weaken );
BuffInfo.RemoveBuff( m, BuffIcon.MassCurse );
// TODO: Should this remove blood oath? Pain spike?
}
else
{
m.PlaySound( 0x1DF );
}
}
FinishSequence();
}
private class InternalTarget : Target
{
private RemoveCurseSpell m_Owner;
public InternalTarget( RemoveCurseSpell owner ) : base( 12, false, TargetFlags.Beneficial )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,189 @@
using System;
using Server;
using Server.Items;
using Server.Multis;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Chivalry
{
public class SacredJourneySpell : PaladinSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Sacred Journey", "Sanctum Viatas",
SpellCircle.Sixth, // 0 + 1.5 = 1.5s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 15.0; } }
public override int RequiredMana{ get{ return 10; } }
public override int RequiredTithing{ get{ return 15; } }
public override int MantraNumber{ get{ return 1060727; } } // Sanctum Viatas
public override bool BlocksMovement{ get{ return false; } }
private RunebookEntry m_Entry;
private Runebook m_Book;
public SacredJourneySpell( Mobile caster, Item scroll ) : this( caster, scroll, null, null )
{
}
public SacredJourneySpell( Mobile caster, Item scroll, RunebookEntry entry, Runebook book ) : base( caster, scroll, m_Info )
{
m_Entry = entry;
m_Book = book;
}
public override void OnCast()
{
if ( m_Entry == null )
Caster.Target = new InternalTarget( this );
else
Effect( m_Entry.Location, m_Entry.Map, true );
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( Factions.Sigil.ExistsOn( Caster ) )
{
Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
return false;
}
else if ( Caster.Criminal )
{
Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily.
return false;
}
else if ( SpellHelper.CheckCombat( Caster ) )
{
Caster.SendLocalizedMessage( 1061282 ); // You cannot use the Sacred Journey ability to flee from combat.
return false;
}
else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) )
{
Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move.
return false;
}
return SpellHelper.CheckTravel( Caster, TravelCheckType.RecallFrom );
}
public void Effect( Point3D loc, Map map, bool checkMulti )
{
if ( Factions.Sigil.ExistsOn( Caster ) )
{
Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
}
else if ( map == null || (!Core.AOS && Caster.Map != map) )
{
Caster.SendLocalizedMessage( 1005569 ); // You can not recall to another facet.
}
else if ( !SpellHelper.CheckTravel( Caster, TravelCheckType.RecallFrom ) )
{
}
else if ( !SpellHelper.CheckTravel( Caster, map, loc, TravelCheckType.RecallTo ) )
{
}
else if ( map == Map.Felucca && Caster is PlayerMobile && ((PlayerMobile)Caster).Young )
{
Caster.SendLocalizedMessage( 1049543 ); // You decide against traveling to Felucca while you are still young.
}
else if ( Caster.Kills >= 5 && map != Map.Felucca )
{
Caster.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there.
}
else if ( Caster.Criminal )
{
Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily.
}
else if ( SpellHelper.CheckCombat( Caster ) )
{
Caster.SendLocalizedMessage( 1061282 ); // You cannot use the Sacred Journey ability to flee from combat.
}
else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) )
{
Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move.
}
else if ( !map.CanSpawnMobile( loc.X, loc.Y, loc.Z ) )
{
Caster.SendLocalizedMessage( 501942 ); // That location is blocked.
}
else if ( (checkMulti && SpellHelper.CheckMulti( loc, map )) )
{
Caster.SendLocalizedMessage( 501942 ); // That location is blocked.
}
else if ( m_Book != null && m_Book.CurCharges <= 0 )
{
Caster.SendLocalizedMessage( 502412 ); // There are no charges left on that item.
}
else if ( CheckSequence() )
{
BaseCreature.TeleportPets( Caster, loc, map, true );
if ( m_Book != null )
--m_Book.CurCharges;
Effects.SendLocationParticles( EffectItem.Create( Caster.Location, Caster.Map, EffectItem.DefaultDuration ), 0, 0, 0, 5033 );
Caster.MoveToWorld( loc, map );
}
FinishSequence();
}
private class InternalTarget : Target
{
private SacredJourneySpell m_Owner;
public InternalTarget( SacredJourneySpell owner ) : base( 12, false, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is RecallRune )
{
RecallRune rune = (RecallRune)o;
if ( rune.Marked )
m_Owner.Effect( rune.Target, rune.TargetMap, true );
else
from.SendLocalizedMessage( 501805 ); // That rune is not yet marked.
}
else if ( o is Runebook )
{
RunebookEntry e = ((Runebook)o).Default;
if ( e != null )
m_Owner.Effect( e.Location, e.Map, true );
else
from.SendLocalizedMessage( 502354 ); // Target is not marked.
}
else if ( o is Key && ((Key)o).KeyValue != 0 && ((Key)o).Link is BaseBoat )
{
BaseBoat boat = ((Key)o).Link as BaseBoat;
if ( !boat.Deleted && boat.CheckKey( ((Key)o).KeyValue ) )
m_Owner.Effect( boat.GetMarkedLocation(), boat.Map, false );
else
from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "" ) ); // I can not recall from that object.
}
else
{
from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "" ) ); // I can not recall from that object.
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,54 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Eighth
{
public class AirElementalSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Air Elemental", "Kal Vas Xen Hur",
SpellCircle.Eighth,
269,
9010,
false,
Reagent.Bloodmoss,
Reagent.MandrakeRoot,
Reagent.SpidersSilk
);
public AirElementalSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( (Caster.Followers + 2) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
if ( CheckSequence() )
{
TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 );
if ( Core.AOS )
SpellHelper.Summon( new SummonedAirElemental(), Caster, 0x217, duration, false, false );
else
SpellHelper.Summon( new AirElemental(), Caster, 0x217, duration, false, false );
}
FinishSequence();
}
}
}

View file

@ -0,0 +1,54 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Eighth
{
public class EarthElementalSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Earth Elemental", "Kal Vas Xen Ylem",
SpellCircle.Eighth,
269,
9020,
false,
Reagent.Bloodmoss,
Reagent.MandrakeRoot,
Reagent.SpidersSilk
);
public EarthElementalSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( (Caster.Followers + 2) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
if ( CheckSequence() )
{
TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 );
if ( Core.AOS )
SpellHelper.Summon( new SummonedEarthElemental(), Caster, 0x217, duration, false, false );
else
SpellHelper.Summon( new EarthElemental(), Caster, 0x217, duration, false, false );
}
FinishSequence();
}
}
}

View file

@ -0,0 +1,81 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Eighth
{
public class EarthquakeSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Earthquake", "In Vas Por",
SpellCircle.Eighth,
233,
9012,
false,
Reagent.Bloodmoss,
Reagent.Ginseng,
Reagent.MandrakeRoot,
Reagent.SulfurousAsh
);
public EarthquakeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool DelayedDamage{ get{ return !Core.AOS; } }
public override void OnCast()
{
if ( SpellHelper.CheckTown( Caster, Caster ) && CheckSequence() )
{
ArrayList targets = new ArrayList();
Map map = Caster.Map;
if ( map != null )
{
foreach ( Mobile m in Caster.GetMobilesInRange( 1 + (int)(Caster.Skills[SkillName.Magery].Value / 15.0) ) )
{
if ( Caster != m && SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) && (!Core.AOS || Caster.InLOS( m )) )
targets.Add( m );
}
}
Caster.PlaySound( 0x2F3 );
for ( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
int damage;
if ( Core.AOS )
{
damage = m.Hits / 2;
if ( !m.Player )
damage = Math.Max( Math.Min( damage, 100 ), 15 );
damage += Utility.RandomMinMax( 0, 15 );
}
else
{
damage = (m.Hits * 6) / 10;
if ( !m.Player && damage < 10 )
damage = 10;
else if ( damage > 75 )
damage = 75;
}
Caster.DoHarmful( m );
SpellHelper.Damage( TimeSpan.Zero, m, Caster, damage, 100, 0, 0, 0, 0 );
}
}
FinishSequence();
}
}
}

View file

@ -0,0 +1,100 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Eighth
{
public class EnergyVortexSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Energy Vortex", "Vas Corp Por",
SpellCircle.Eighth,
260,
9032,
false,
Reagent.Bloodmoss,
Reagent.BlackPearl,
Reagent.MandrakeRoot,
Reagent.Nightshade
);
public EnergyVortexSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( (Caster.Followers + (Core.SE ? 2 : 1)) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( IPoint3D p )
{
Map map = Caster.Map;
SpellHelper.GetSurfaceTop( ref p );
if ( map == null || !map.CanSpawnMobile( p.X, p.Y, p.Z ) )
{
Caster.SendLocalizedMessage( 501942 ); // That location is blocked.
}
else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() )
{
TimeSpan duration;
if ( Core.AOS )
duration = TimeSpan.FromSeconds( 90.0 );
else
duration = TimeSpan.FromSeconds( Utility.Random( 80, 40 ) );
BaseCreature.Summon( new EnergyVortex(), false, Caster, new Point3D( p ), 0x212, duration );
}
FinishSequence();
}
private class InternalTarget : Target
{
private EnergyVortexSpell m_Owner;
public InternalTarget( EnergyVortexSpell owner ) : base( 12, true, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is IPoint3D )
m_Owner.Target( (IPoint3D)o );
}
protected override void OnTargetOutOfLOS( Mobile from, object o )
{
from.SendLocalizedMessage( 501943 ); // Target cannot be seen. Try again.
from.Target = new InternalTarget( m_Owner );
from.Target.BeginTimeout( from, TimeoutTime - DateTime.Now );
m_Owner = null;
}
protected override void OnTargetFinish( Mobile from )
{
if ( m_Owner != null )
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,55 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Eighth
{
public class FireElementalSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Fire Elemental", "Kal Vas Xen Flam",
SpellCircle.Eighth,
269,
9050,
false,
Reagent.Bloodmoss,
Reagent.MandrakeRoot,
Reagent.SpidersSilk,
Reagent.SulfurousAsh
);
public FireElementalSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( (Caster.Followers + 4) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
if ( CheckSequence() )
{
TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 );
if ( Core.AOS )
SpellHelper.Summon( new SummonedFireElemental(), Caster, 0x217, duration, false, false );
else
SpellHelper.Summon( new FireElemental(), Caster, 0x217, duration, false, false );
}
FinishSequence();
}
}
}

View file

@ -0,0 +1,101 @@
using System;
using Server.Targeting;
using Server.Network;
using Server.Gumps;
namespace Server.Spells.Eighth
{
public class ResurrectionSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Resurrection", "An Corp",
SpellCircle.Eighth,
245,
9062,
Reagent.Bloodmoss,
Reagent.Garlic,
Reagent.Ginseng
);
public ResurrectionSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( m == Caster )
{
Caster.SendLocalizedMessage( 501039 ); // Thou can not resurrect thyself.
}
else if ( !Caster.Alive )
{
Caster.SendLocalizedMessage( 501040 ); // The resurrecter must be alive.
}
else if ( m.Alive )
{
Caster.SendLocalizedMessage( 501041 ); // Target is not dead.
}
else if ( !Caster.InRange( m, 1 ) )
{
Caster.SendLocalizedMessage( 501042 ); // Target is not close enough.
}
else if ( !m.Player )
{
Caster.SendLocalizedMessage( 501043 ); // Target is not a being.
}
else if ( m.Map == null || !m.Map.CanFit( m.Location, 16, false, false ) )
{
Caster.SendLocalizedMessage( 501042 ); // Target can not be resurrected at that location.
m.SendLocalizedMessage( 502391 ); // Thou can not be resurrected there!
}
else if ( m.Region != null && m.Region.IsPartOf( "Khaldun" ) )
{
Caster.SendLocalizedMessage( 1010395 ); // The veil of death in this area is too strong and resists thy efforts to restore life.
}
else if ( CheckBSequence( m, true ) )
{
SpellHelper.Turn( Caster, m );
m.PlaySound( 0x214 );
m.FixedEffect( 0x376A, 10, 16 );
m.CloseGump( typeof( ResurrectGump ) );
m.SendGump( new ResurrectGump( m, Caster ) );
}
FinishSequence();
}
private class InternalTarget : Target
{
private ResurrectionSpell m_Owner;
public InternalTarget( ResurrectionSpell owner ) : base( 1, false, TargetFlags.Beneficial )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,55 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Eighth
{
public class SummonDaemonSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Summon Daemon", "Kal Vas Xen Corp",
SpellCircle.Eighth,
269,
9050,
false,
Reagent.Bloodmoss,
Reagent.MandrakeRoot,
Reagent.SpidersSilk,
Reagent.SulfurousAsh
);
public SummonDaemonSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( (Caster.Followers + (Core.SE ? 4 : 5)) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
if ( CheckSequence() )
{
TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 );
if ( Core.AOS )
SpellHelper.Summon( new SummonedDaemon(), Caster, 0x216, duration, false, false );
else
SpellHelper.Summon( new Daemon(), Caster, 0x216, duration, false, false );
}
FinishSequence();
}
}
}

View file

@ -0,0 +1,54 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Eighth
{
public class WaterElementalSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Water Elemental", "Kal Vas Xen An Flam",
SpellCircle.Eighth,
269,
9070,
false,
Reagent.Bloodmoss,
Reagent.MandrakeRoot,
Reagent.SpidersSilk
);
public WaterElementalSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( (Caster.Followers + 3) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
if ( CheckSequence() )
{
TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 );
if ( Core.AOS )
SpellHelper.Summon( new SummonedWaterElemental(), Caster, 0x217, duration, false, false );
else
SpellHelper.Summon( new WaterElemental(), Caster, 0x217, duration, false, false );
}
FinishSequence();
}
}
}

View file

@ -0,0 +1,107 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Fifth
{
public class BladeSpiritsSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Blade Spirits", "In Jux Hur Ylem",
SpellCircle.Fifth,
266,
9040,
false,
Reagent.BlackPearl,
Reagent.MandrakeRoot,
Reagent.Nightshade
);
public BladeSpiritsSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override TimeSpan GetCastDelay()
{
if ( Core.AOS )
return TimeSpan.FromTicks( base.GetCastDelay().Ticks * ((Core.SE) ? 3 : 5) );
return base.GetCastDelay() + TimeSpan.FromSeconds( 6.0 );
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if( (Caster.Followers + (Core.SE ? 2 : 1)) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( IPoint3D p )
{
Map map = Caster.Map;
SpellHelper.GetSurfaceTop( ref p );
if ( map == null || !map.CanSpawnMobile( p.X, p.Y, p.Z ) )
{
Caster.SendLocalizedMessage( 501942 ); // That location is blocked.
}
else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() )
{
TimeSpan duration;
if ( Core.AOS )
duration = TimeSpan.FromSeconds( 120 );
else
duration = TimeSpan.FromSeconds( Utility.Random( 80, 40 ) );
BaseCreature.Summon( new BladeSpirits(), false, Caster, new Point3D( p ), 0x212, duration );
}
FinishSequence();
}
private class InternalTarget : Target
{
private BladeSpiritsSpell m_Owner;
public InternalTarget( BladeSpiritsSpell owner ) : base( 12, true, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is IPoint3D )
m_Owner.Target( (IPoint3D)o );
}
protected override void OnTargetOutOfLOS( Mobile from, object o )
{
from.SendLocalizedMessage( 501943 ); // Target cannot be seen. Try again.
from.Target = new InternalTarget( m_Owner );
from.Target.BeginTimeout( from, TimeoutTime - DateTime.Now );
m_Owner = null;
}
protected override void OnTargetFinish( Mobile from )
{
if ( m_Owner != null )
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,87 @@
using System;
using Server.Targeting;
using Server.Network;
using Server.Items;
using Server.Misc;
namespace Server.Spells.Fifth
{
public class DispelFieldSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Dispel Field", "An Grav",
SpellCircle.Fifth,
206,
9002,
Reagent.BlackPearl,
Reagent.SpidersSilk,
Reagent.SulfurousAsh,
Reagent.Garlic
);
public DispelFieldSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Item item )
{
Type t = item.GetType();
if ( !Caster.CanSee( item ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( !t.IsDefined( typeof( DispellableFieldAttribute ), false ) )
{
Caster.SendLocalizedMessage( 1005049 ); // That cannot be dispelled.
}
else if ( item is Moongate && !((Moongate)item).Dispellable )
{
Caster.SendLocalizedMessage( 1005047 ); // That magic is too chaotic
}
else if ( CheckSequence() )
{
SpellHelper.Turn( Caster, item );
Effects.SendLocationParticles( EffectItem.Create( item.Location, item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 20, 5042 );
Effects.PlaySound( item.GetWorldLocation(), item.Map, 0x201 );
item.Delete();
}
FinishSequence();
}
private class InternalTarget : Target
{
private DispelFieldSpell m_Owner;
public InternalTarget( DispelFieldSpell owner ) : base( 12, false, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Item )
{
m_Owner.Target( (Item)o );
}
else
{
m_Owner.Caster.SendLocalizedMessage( 1005049 ); // That cannot be dispelled.
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,194 @@
using System;
using System.Collections;
using Server;
using Server.Mobiles;
using Server.Misc;
using Server.Items;
using Server.Gumps;
using Server.Spells;
using Server.Spells.Seventh;
namespace Server.Spells.Fifth
{
public class IncognitoSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Incognito", "Kal In Ex",
SpellCircle.Fifth,
206,
9002,
Reagent.Bloodmoss,
Reagent.Garlic,
Reagent.Nightshade
);
public IncognitoSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( Factions.Sigil.ExistsOn( Caster ) )
{
Caster.SendLocalizedMessage( 1010445 ); // You cannot incognito if you have a sigil
return false;
}
else if ( !Caster.CanBeginAction( typeof( IncognitoSpell ) ) )
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
return false;
}
else if ( Caster.BodyMod == 183 || Caster.BodyMod == 184 )
{
Caster.SendLocalizedMessage( 1042402 ); // You cannot use incognito while wearing body paint
return false;
}
return true;
}
public override void OnCast()
{
if ( Factions.Sigil.ExistsOn( Caster ) )
{
Caster.SendLocalizedMessage( 1010445 ); // You cannot incognito if you have a sigil
}
else if ( !Caster.CanBeginAction( typeof( IncognitoSpell ) ) )
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
}
else if ( Caster.BodyMod == 183 || Caster.BodyMod == 184 )
{
Caster.SendLocalizedMessage( 1042402 ); // You cannot use incognito while wearing body paint
}
else if ( !Caster.CanBeginAction( typeof( PolymorphSpell ) ) || Caster.IsBodyMod )
{
DoFizzle();
}
else if ( CheckSequence() )
{
if ( Caster.BeginAction( typeof( IncognitoSpell ) ) )
{
DisguiseGump.StopTimer( Caster );
Caster.BodyMod = Utility.RandomList( 400, 401 );
Caster.HueMod = Utility.RandomSkinHue();
Caster.NameMod = Caster.Body.IsFemale ? NameList.RandomName( "female" ) : NameList.RandomName( "male" );
PlayerMobile pm = Caster as PlayerMobile;
if ( pm != null )
{
if ( pm.Body.IsFemale )
pm.SetHairMods( Utility.RandomList( m_HairIDs ), 0 );
else
pm.SetHairMods( Utility.RandomList( m_HairIDs ), Utility.RandomList( m_BeardIDs ) );
pm.HairHue = Utility.RandomHairHue();
pm.FacialHairHue = Utility.RandomHairHue();
}
Caster.FixedParticles( 0x373A, 10, 15, 5036, EffectLayer.Head );
Caster.PlaySound( 0x3BD );
BaseArmor.ValidateMobile( Caster );
BaseClothing.ValidateMobile( Caster );
StopTimer( Caster );
int timeVal = ((6 * Caster.Skills.Magery.Fixed) / 50) + 1;
if( timeVal > 144 )
timeVal = 144;
TimeSpan length = TimeSpan.FromSeconds( timeVal );
Timer t = new InternalTimer( Caster, length );
m_Timers[Caster] = t;
t.Start();
BuffInfo.AddBuff( Caster, new BuffInfo( BuffIcon.Incognito, 1075819, length, Caster ) );
}
else
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
}
}
FinishSequence();
}
private static Hashtable m_Timers = new Hashtable();
public static bool StopTimer( Mobile m )
{
Timer t = (Timer)m_Timers[m];
if ( t != null )
{
t.Stop();
m_Timers.Remove( m );
BuffInfo.RemoveBuff( m, BuffIcon.Incognito );
}
return ( t != null );
}
private static int[] m_HairIDs = new int[]
{
0x2044, 0x2045, 0x2046,
0x203C, 0x203B, 0x203D,
0x2047, 0x2048, 0x2049,
0x204A, 0x0000
};
private static int[] m_BeardIDs = new int[]
{
0x203E, 0x203F, 0x2040,
0x2041, 0x204B, 0x204C,
0x204D, 0x0000
};
private class InternalTimer : Timer
{
private Mobile m_Owner;
public InternalTimer( Mobile owner, TimeSpan length ) : base( length )
{
m_Owner = owner;
/*
int val = ((6 * owner.Skills.Magery.Fixed) / 50) + 1;
if ( val > 144 )
val = 144;
Delay = TimeSpan.FromSeconds( val );
* */
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
if ( !m_Owner.CanBeginAction( typeof( IncognitoSpell ) ) )
{
if ( m_Owner is PlayerMobile )
((PlayerMobile)m_Owner).SetHairMods( -1, -1 );
m_Owner.BodyMod = 0;
m_Owner.HueMod = -1;
m_Owner.NameMod = null;
m_Owner.EndAction( typeof( IncognitoSpell ) );
BaseArmor.ValidateMobile( m_Owner );
BaseClothing.ValidateMobile( m_Owner );
}
}
}
}
}

View file

@ -0,0 +1,137 @@
using System;
using System.Collections;
using Server;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Fifth
{
public class MagicReflectSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Magic Reflection", "In Jux Sanct",
SpellCircle.Fifth,
242,
9012,
Reagent.Garlic,
Reagent.MandrakeRoot,
Reagent.SpidersSilk
);
public MagicReflectSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( Core.AOS )
return true;
if ( Caster.MagicDamageAbsorb > 0 )
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
return false;
}
else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) )
{
Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time.
return false;
}
return true;
}
private static Hashtable m_Table = new Hashtable();
public override void OnCast()
{
if ( Core.AOS )
{
/* The magic reflection spell decreases the caster's physical resistance, while increasing the caster's elemental resistances.
* Physical decrease = 25 - (Inscription/20).
* Elemental resistance = +10 (-20 physical, +10 elemental at GM Inscription)
* The magic reflection spell has an indefinite duration, becoming active when cast, and deactivated when re-cast.
* Reactive Armor, Protection, and Magic Reflection will stay oneven after logging out, even after dyinguntil you turn them off by casting them again.
*/
if ( CheckSequence() )
{
Mobile targ = Caster;
ResistanceMod[] mods = (ResistanceMod[])m_Table[targ];
if ( mods == null )
{
targ.PlaySound( 0x1E9 );
targ.FixedParticles( 0x375A, 10, 15, 5037, EffectLayer.Waist );
int physiMod = -25 + (int)(targ.Skills[SkillName.Inscribe].Value / 20);
int otherMod = 10;
mods = new ResistanceMod[5]
{
new ResistanceMod( ResistanceType.Physical, physiMod ),
new ResistanceMod( ResistanceType.Fire, otherMod ),
new ResistanceMod( ResistanceType.Cold, otherMod ),
new ResistanceMod( ResistanceType.Poison, otherMod ),
new ResistanceMod( ResistanceType.Energy, otherMod )
};
m_Table[targ] = mods;
for ( int i = 0; i < mods.Length; ++i )
targ.AddResistanceMod( mods[i] );
string buffFormat = String.Format( "{0}\t+{1}\t+{1}\t+{1}\t+{1}", physiMod, otherMod );
BuffInfo.AddBuff( targ, new BuffInfo( BuffIcon.MagicReflection, 1075817, buffFormat, true ) );
}
else
{
targ.PlaySound( 0x1ED );
targ.FixedParticles( 0x375A, 10, 15, 5037, EffectLayer.Waist );
m_Table.Remove( targ );
for ( int i = 0; i < mods.Length; ++i )
targ.RemoveResistanceMod( mods[i] );
BuffInfo.RemoveBuff( targ, BuffIcon.MagicReflection );
}
}
FinishSequence();
}
else
{
if ( Caster.MagicDamageAbsorb > 0 )
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
}
else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) )
{
Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time.
}
else if ( CheckSequence() )
{
if ( Caster.BeginAction( typeof( DefensiveSpell ) ) )
{
int value = (int)(Caster.Skills[SkillName.Magery].Value + Caster.Skills[SkillName.Inscribe].Value);
value = (int)(8 + (value/200)*7.0);//absorb from 8 to 15 "circles"
Caster.MagicDamageAbsorb = value;
Caster.FixedParticles( 0x375A, 10, 15, 5037, EffectLayer.Waist );
Caster.PlaySound( 0x1E9 );
}
else
{
Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time.
}
}
FinishSequence();
}
}
}
}

View file

@ -0,0 +1,154 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Fifth
{
public class MindBlastSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Mind Blast", "Por Corp Wis",
SpellCircle.Fifth,
218,
Core.AOS ? 9002 : 9032,
Reagent.BlackPearl,
Reagent.MandrakeRoot,
Reagent.Nightshade,
Reagent.SulfurousAsh
);
public MindBlastSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
if ( Core.AOS )
m_Info.LeftHandEffect = m_Info.RightHandEffect = 9002;
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
private void AosDelay_Callback( object state )
{
object[] states = (object[])state;
Mobile caster = (Mobile)states[0];
Mobile target = (Mobile)states[1];
Mobile defender = (Mobile)states[2];
int damage = (int)states[3];
if ( caster.HarmfulCheck( defender ) )
{
SpellHelper.Damage( this, target, Utility.RandomMinMax( damage, damage + 4 ), 0, 0, 100, 0, 0 );
target.FixedParticles( 0x374A, 10, 15, 5038, 1181, 2, EffectLayer.Head );
target.PlaySound( 0x213 );
}
}
public override bool DelayedDamage{ get{ return !Core.AOS; } }
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( Core.AOS )
{
if ( Caster.CanBeHarmful( m ) && CheckSequence() )
{
Mobile from = Caster, target = m;
SpellHelper.Turn( from, target );
SpellHelper.CheckReflect( (int)this.Circle, ref from, ref target );
int damage = (int)((Caster.Skills[SkillName.Magery].Value + Caster.Int) / 5);
if ( damage > 60 )
damage = 60;
Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ),
new TimerStateCallback( AosDelay_Callback ),
new object[]{ Caster, target, m, damage } );
}
}
else if ( CheckHSequence( m ) )
{
Mobile from = Caster, target = m;
SpellHelper.Turn( from, target );
SpellHelper.CheckReflect( (int)this.Circle, ref from, ref target );
// Algorithm: (highestStat - lowestStat) / 2 [- 50% if resisted]
int highestStat = target.Str, lowestStat = target.Str;
if ( target.Dex > highestStat )
highestStat = target.Dex;
if ( target.Dex < lowestStat )
lowestStat = target.Dex;
if ( target.Int > highestStat )
highestStat = target.Int;
if ( target.Int < lowestStat )
lowestStat = target.Int;
if ( highestStat > 150 )
highestStat = 150;
if ( lowestStat > 150 )
lowestStat = 150;
int damage = (highestStat - lowestStat) / 4;//less damage
if ( damage > 45 )
damage = 45;
if ( CheckResisted( target ) )
{
damage /= 2;
target.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy.
}
from.FixedParticles( 0x374A, 10, 15, 2038, EffectLayer.Head );
target.FixedParticles( 0x374A, 10, 15, 5038, EffectLayer.Head );
target.PlaySound( 0x213 );
SpellHelper.Damage( this, target, damage, 0, 0, 100, 0, 0 );
}
FinishSequence();
}
public override double GetSlayerDamageScalar( Mobile target )
{
return 1.0; //This spell isn't affected by slayer spellbooks
}
private class InternalTarget : Target
{
private MindBlastSpell m_Owner;
public InternalTarget( MindBlastSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile)o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,101 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Fifth
{
public class ParalyzeSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Paralyze", "An Ex Por",
SpellCircle.Fifth,
218,
9012,
Reagent.Garlic,
Reagent.MandrakeRoot,
Reagent.SpidersSilk
);
public ParalyzeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( Core.AOS && (m.Frozen || m.Paralyzed || (m.Spell != null && m.Spell.IsCasting)) )
{
Caster.SendLocalizedMessage( 1061923 ); // The target is already frozen.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m );
double duration;
if ( Core.AOS )
{
int secs = (GetDamageFixed( Caster ) / 100) - (GetResistFixed( m ) / 100);
if( !Core.SE )
secs += 2;
if ( !m.Player )
secs *= 3;
if ( secs < 0 )
secs = 0;
duration = secs;
}
else
{
// Algorithm: ((20% of magery) + 7) seconds [- 50% if resisted]
duration = 7.0 + (Caster.Skills[SkillName.Magery].Value * 0.2);
if ( CheckResisted( m ) )
duration *= 0.75;
}
m.Paralyze( TimeSpan.FromSeconds( duration ) );
m.PlaySound( 0x204 );
m.FixedEffect( 0x376A, 6, 1 );
}
FinishSequence();
}
public class InternalTarget : Target
{
private ParalyzeSpell m_Owner;
public InternalTarget( ParalyzeSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile)o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,294 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
using Server.Misc;
using Server.Items;
namespace Server.Spells.Fifth
{
public class PoisonFieldSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Poison Field", "In Nox Grav",
SpellCircle.Fifth,
230,
9052,
false,
Reagent.BlackPearl,
Reagent.Nightshade,
Reagent.SpidersSilk
);
public PoisonFieldSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( IPoint3D p )
{
if ( !Caster.CanSee( p ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() )
{
SpellHelper.Turn( Caster, p );
SpellHelper.GetSurfaceTop( ref p );
int dx = Caster.Location.X - p.X;
int dy = Caster.Location.Y - p.Y;
int rx = (dx - dy) * 44;
int ry = (dx + dy) * 44;
bool eastToWest;
if ( rx >= 0 && ry >= 0 )
{
eastToWest = false;
}
else if ( rx >= 0 )
{
eastToWest = true;
}
else if ( ry >= 0 )
{
eastToWest = true;
}
else
{
eastToWest = false;
}
Effects.PlaySound( p, Caster.Map, 0x20B );
int itemID = eastToWest ? 0x3915 : 0x3922;
TimeSpan duration = TimeSpan.FromSeconds( 3 + (Caster.Skills.Magery.Fixed / 25) );
for ( int i = -2; i <= 2; ++i )
{
Point3D loc = new Point3D( eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z );
new InternalItem( itemID, loc, Caster, Caster.Map, duration, i );
}
}
FinishSequence();
}
[DispellableField]
private class InternalItem : Item
{
private Timer m_Timer;
private DateTime m_End;
private Mobile m_Caster;
public override bool BlocksFit{ get{ return true; } }
public InternalItem( int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val ) : base( itemID )
{
bool canFit = SpellHelper.AdjustField( ref loc, map, 12, false );
Visible = false;
Movable = false;
Light = LightType.Circle300;
MoveToWorld( loc, map );
m_Caster = caster;
m_End = DateTime.Now + duration;
m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( Math.Abs( val ) * 0.2 ), caster.InLOS( this ), canFit );
m_Timer.Start();
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if ( m_Timer != null )
m_Timer.Stop();
}
public InternalItem( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 1 ); // version
writer.Write( m_Caster );
writer.WriteDeltaTime( m_End );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 1:
{
m_Caster = reader.ReadMobile();
goto case 0;
}
case 0:
{
m_End = reader.ReadDeltaTime();
m_Timer = new InternalTimer( this, TimeSpan.Zero, true, true );
m_Timer.Start();
break;
}
}
}
public void ApplyPoisonTo( Mobile m )
{
if ( m_Caster == null )
return;
Poison p;
if ( Core.AOS )
{
int total = (m_Caster.Skills.Magery.Fixed + m_Caster.Skills.Poisoning.Fixed) / 2;
if ( total >= 1000 )
p = Poison.Deadly;
else if ( total > 850 )
p = Poison.Greater;
else if ( total > 650 )
p = Poison.Regular;
else
p = Poison.Lesser;
}
else
{
p = Poison.Regular;
}
m.ApplyPoison( m_Caster, p );
}
public override bool OnMoveOver( Mobile m )
{
if ( Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && SpellHelper.ValidIndirectTarget( m_Caster, m ) && m_Caster.CanBeHarmful( m, false ) )
{
m_Caster.DoHarmful( m );
ApplyPoisonTo( m );
m.PlaySound( 0x474 );
}
return true;
}
private class InternalTimer : Timer
{
private InternalItem m_Item;
private bool m_InLOS, m_CanFit;
private static Queue m_Queue = new Queue();
public InternalTimer( InternalItem item, TimeSpan delay, bool inLOS, bool canFit ) : base( delay, TimeSpan.FromSeconds( 1.5 ) )
{
m_Item = item;
m_InLOS = inLOS;
m_CanFit = canFit;
Priority = TimerPriority.FiftyMS;
}
protected override void OnTick()
{
if ( m_Item.Deleted )
return;
if ( !m_Item.Visible )
{
if ( m_InLOS && m_CanFit )
m_Item.Visible = true;
else
m_Item.Delete();
if ( !m_Item.Deleted )
{
m_Item.ProcessDelta();
Effects.SendLocationParticles( EffectItem.Create( m_Item.Location, m_Item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5040 );
}
}
else if ( DateTime.Now > m_Item.m_End )
{
m_Item.Delete();
Stop();
}
else
{
Map map = m_Item.Map;
Mobile caster = m_Item.m_Caster;
if ( map != null && caster != null )
{
bool eastToWest = ( m_Item.ItemID == 0x3915 );
IPooledEnumerable eable = map.GetMobilesInBounds( new Rectangle2D( m_Item.X - (eastToWest ? 0 : 1), m_Item.Y - (eastToWest ? 1 : 0), (eastToWest ? 1 : 2), (eastToWest ? 2 : 1) ) );
foreach ( Mobile m in eable )
{
if ( (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z && (!Core.AOS || m != caster) && SpellHelper.ValidIndirectTarget( caster, m ) && caster.CanBeHarmful( m, false ) )
m_Queue.Enqueue( m );
}
eable.Free();
while ( m_Queue.Count > 0 )
{
Mobile m = (Mobile)m_Queue.Dequeue();
caster.DoHarmful( m );
m_Item.ApplyPoisonTo( m );
m.PlaySound( 0x474 );
}
}
}
}
}
}
private class InternalTarget : Target
{
private PoisonFieldSpell m_Owner;
public InternalTarget( PoisonFieldSpell owner ) : base( 12, true, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is IPoint3D )
m_Owner.Target( (IPoint3D)o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,90 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Fifth
{
public class SummonCreatureSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Summon Creature", "Kal Xen",
SpellCircle.Fifth,
266,
9040,
Reagent.Bloodmoss,
Reagent.MandrakeRoot,
Reagent.SpidersSilk
);
public SummonCreatureSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
// TODO: Get real list
private static Type[] m_Types = new Type[]
{
typeof( PolarBear ),
typeof( GrizzlyBear ),
typeof( BlackBear ),
typeof( BrownBear ),
typeof( Horse ),
typeof( Walrus ),
typeof( GreatHart ),
typeof( Hind ),
typeof( Dog ),
typeof( Boar ),
typeof( Chicken ),
typeof( Rabbit )
};
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( (Caster.Followers + 2) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
if ( CheckSequence() )
{
try
{
BaseCreature creature = (BaseCreature)Activator.CreateInstance( m_Types[Utility.Random( m_Types.Length )] );
creature.ControlSlots = 2;
TimeSpan duration;
if ( Core.AOS )
duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 );
else
duration = TimeSpan.FromSeconds( 4.0 * Caster.Skills[SkillName.Magery].Value );
SpellHelper.Summon( creature, Caster, 0x215, duration, false, false );
}
catch
{
}
}
FinishSequence();
}
public override TimeSpan GetCastDelay()
{
if ( Core.AOS )
return TimeSpan.FromTicks( base.GetCastDelay().Ticks * 5 );
return base.GetCastDelay() + TimeSpan.FromSeconds( 6.0 );
}
}
}

View file

@ -0,0 +1,81 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.First
{
public class ClumsySpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Clumsy", "Uus Jux",
SpellCircle.First,
212,
9031,
Reagent.Bloodmoss,
Reagent.Nightshade
);
public ClumsySpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m );
SpellHelper.AddStatCurse( Caster, m, StatType.Dex );
if ( m.Spell != null )
m.Spell.OnCasterHurt();
m.Paralyzed = false;
m.FixedParticles( 0x3779, 10, 15, 5002, EffectLayer.Head );
m.PlaySound( 0x1DF );
int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, true )*100);
TimeSpan length = SpellHelper.GetDuration( Caster, m );
BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Clumsy, 1075831, length, m, percentage.ToString() ) );
}
FinishSequence();
}
private class InternalTarget : Target
{
private ClumsySpell m_Owner;
public InternalTarget( ClumsySpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,89 @@
using System;
using Server.Items;
namespace Server.Spells.First
{
public class CreateFoodSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Create Food", "In Mani Ylem",
SpellCircle.First,
224,
9011,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.MandrakeRoot
);
public CreateFoodSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
private static FoodInfo[] m_Food = new FoodInfo[]
{
new FoodInfo( typeof( Grapes ), "a grape bunch" ),
new FoodInfo( typeof( Ham ), "a ham" ),
new FoodInfo( typeof( CheeseWedge ), "a wedge of cheese" ),
new FoodInfo( typeof( Muffins ), "muffins" ),
new FoodInfo( typeof( FishSteak ), "a fish steak" ),
new FoodInfo( typeof( Ribs ), "cut of ribs" ),
new FoodInfo( typeof( CookedBird ), "a cooked bird" ),
new FoodInfo( typeof( Sausage ), "sausage" ),
new FoodInfo( typeof( Apple ), "an apple" ),
new FoodInfo( typeof( Peach ), "a peach" )
};
public override void OnCast()
{
if ( CheckSequence() )
{
FoodInfo foodInfo = m_Food[Utility.Random( m_Food.Length )];
Item food = foodInfo.Create();
if ( food != null )
{
Caster.AddToBackpack( food );
// You magically create food in your backpack:
Caster.SendLocalizedMessage( 1042695, true, " " + foodInfo.Name );
Caster.FixedParticles( 0, 10, 5, 2003, EffectLayer.RightHand );
Caster.PlaySound( 0x1E2 );
}
}
FinishSequence();
}
}
public class FoodInfo
{
private Type m_Type;
private string m_Name;
public Type Type{ get{ return m_Type; } set{ m_Type = value; } }
public string Name{ get{ return m_Name; } set{ m_Name = value; } }
public FoodInfo( Type type, string name )
{
m_Type = type;
m_Name = name;
}
public Item Create()
{
Item item;
try
{
item = (Item)Activator.CreateInstance( m_Type );
}
catch
{
item = null;
}
return item;
}
}
}

View file

@ -0,0 +1,81 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.First
{
public class FeeblemindSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Feeblemind", "Rel Wis",
SpellCircle.First,
212,
9031,
Reagent.Ginseng,
Reagent.Nightshade
);
public FeeblemindSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m );
SpellHelper.AddStatCurse( Caster, m, StatType.Int );
if ( m.Spell != null )
m.Spell.OnCasterHurt();
m.Paralyzed = false;
m.FixedParticles( 0x3779, 10, 15, 5004, EffectLayer.Head );
m.PlaySound( 0x1E4 );
int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, true )*100);
TimeSpan length = SpellHelper.GetDuration( Caster, m );
BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.FeebleMind, 1075833, length, m, percentage.ToString() ) );
}
FinishSequence();
}
private class InternalTarget : Target
{
private FeeblemindSpell m_Owner;
public InternalTarget( FeeblemindSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,104 @@
using System;
using Server;
using Server.Targeting;
using Server.Network;
using Server.Mobiles;
namespace Server.Spells.First
{
public class HealSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Heal", "In Mani",
SpellCircle.First,
224,
9061,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.SpidersSilk
);
public HealSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( m.IsDeadBondedPet )
{
Caster.SendLocalizedMessage( 1060177 ); // You cannot heal a creature that is already dead!
}
else if ( m is BaseCreature && ((BaseCreature)m).IsAnimatedDead )
{
Caster.SendLocalizedMessage( 1061654 ); // You cannot heal that which is not alive.
}
else if ( m is Golem )
{
Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500951 ); // You cannot heal that.
}
else if ( m.Poisoned || Server.Items.MortalStrike.IsWounded( m ) )
{
Caster.LocalOverheadMessage( MessageType.Regular, 0x22, (Caster == m) ? 1005000 : 1010398 );
}
else if ( CheckBSequence( m ) )
{
SpellHelper.Turn( Caster, m );
int toHeal;
if ( Core.AOS )
{
toHeal = Caster.Skills.Magery.Fixed / 120;
toHeal += Utility.RandomMinMax( 1, 4 );
if( Core.SE && Caster != m )
toHeal = (int)(toHeal * 1.5);
}
else
{
toHeal = (int)(Caster.Skills[SkillName.Magery].Value * 0.1);
toHeal += Utility.Random( 1, 5 );
}
m.Heal( toHeal );
m.FixedParticles( 0x376A, 9, 32, 5005, EffectLayer.Waist );
m.PlaySound( 0x1F2 );
}
FinishSequence();
}
public class InternalTarget : Target
{
private HealSpell m_Owner;
public InternalTarget( HealSpell owner ) : base( 12, false, TargetFlags.Beneficial )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,96 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.First
{
public class MagicArrowSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Magic Arrow", "In Por Ylem",
SpellCircle.First,
212,
9041,
Reagent.SulfurousAsh
);
public MagicArrowSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool DelayedDamageStacking { get { return !Core.AOS; } }
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override bool DelayedDamage{ get{ return true; } }
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckHSequence( m ) )
{
Mobile source = Caster;
SpellHelper.Turn( source, m );
SpellHelper.CheckReflect( (int)this.Circle, ref source, ref m );
double damage;
if ( Core.AOS )
{
damage = GetNewAosDamage( 10, 1, 4, m );
}
else
{
damage = Utility.Random( 4, 4 );
if ( CheckResisted( m ) )
{
damage *= 0.75;
m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy.
}
damage *= GetDamageScalar( m );
}
source.MovingParticles( m, 0x36E4, 5, 0, false, true, 3006, 4006, 0 );
source.PlaySound( 0x1E5 );
SpellHelper.Damage( this, m, damage, 0, 100, 0, 0, 0 );
}
FinishSequence();
}
private class InternalTarget : Target
{
private MagicArrowSpell m_Owner;
public InternalTarget( MagicArrowSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,75 @@
using System;
using Server.Targeting;
using Server.Network;
using Server;
namespace Server.Spells.First
{
public class NightSightSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Night Sight", "In Lor",
SpellCircle.First,
236,
9031,
Reagent.SulfurousAsh,
Reagent.SpidersSilk
);
public NightSightSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new NightSightTarget( this );
}
private class NightSightTarget : Target
{
private Spell m_Spell;
public NightSightTarget( Spell spell ) : base( 12, false, TargetFlags.Beneficial )
{
m_Spell = spell;
}
protected override void OnTarget( Mobile from, object targeted )
{
if ( targeted is Mobile && m_Spell.CheckBSequence( (Mobile) targeted ) )
{
Mobile targ = (Mobile)targeted;
SpellHelper.Turn( m_Spell.Caster, targ );
if ( targ.BeginAction( typeof( LightCycle ) ) )
{
new LightCycle.NightSightTimer( targ ).Start();
int level = (int)( LightCycle.DungeonLevel * ( (Core.AOS ? targ.Skills[SkillName.Magery].Value : from.Skills[SkillName.Magery].Value )/ 100 ) );
if ( level < 0 )
level = 0;
targ.LightLevel = level;
targ.FixedParticles( 0x376A, 9, 32, 5007, EffectLayer.Waist );
targ.PlaySound( 0x1E3 );
BuffInfo.AddBuff( targ, new BuffInfo( BuffIcon.NightSight, 1075643 ) ); //Night Sight/You ignore lighting effects
}
else
{
from.SendMessage( "{0} already have nightsight.", from == targ ? "You" : "They" );
}
}
m_Spell.FinishSequence();
}
protected override void OnTargetFinish( Mobile from )
{
m_Spell.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,133 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.First
{
public class ReactiveArmorSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Reactive Armor", "Flam Sanct",
SpellCircle.First,
236,
9011,
Reagent.Garlic,
Reagent.SpidersSilk,
Reagent.SulfurousAsh
);
public ReactiveArmorSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( Core.AOS )
return true;
if ( Caster.MeleeDamageAbsorb > 0 )
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
return false;
}
else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) )
{
Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time.
return false;
}
return true;
}
private static Hashtable m_Table = new Hashtable();
public override void OnCast()
{
if ( Core.AOS )
{
/* The reactive armor spell increases the caster's physical resistance, while lowering the caster's elemental resistances.
* 15 + (Inscription/20) Physcial bonus
* -5 Elemental
* The reactive armor spell has an indefinite duration, becoming active when cast, and deactivated when re-cast.
* Reactive Armor, Protection, and Magic Reflection will stay oneven after logging out, even after dyinguntil you turn them off by casting them again.
* (+20 physical -5 elemental at 100 Inscription)
*/
if ( CheckSequence() )
{
Mobile targ = Caster;
ResistanceMod[] mods = (ResistanceMod[])m_Table[targ];
if ( mods == null )
{
targ.PlaySound( 0x1E9 );
targ.FixedParticles( 0x376A, 9, 32, 5008, EffectLayer.Waist );
mods = new ResistanceMod[5]
{
new ResistanceMod( ResistanceType.Physical, 15 + (int)(targ.Skills[SkillName.Inscribe].Value / 20) ),
new ResistanceMod( ResistanceType.Fire, -5 ),
new ResistanceMod( ResistanceType.Cold, -5 ),
new ResistanceMod( ResistanceType.Poison, -5 ),
new ResistanceMod( ResistanceType.Energy, -5 )
};
m_Table[targ] = mods;
for ( int i = 0; i < mods.Length; ++i )
targ.AddResistanceMod( mods[i] );
}
else
{
targ.PlaySound( 0x1ED );
targ.FixedParticles( 0x376A, 9, 32, 5008, EffectLayer.Waist );
m_Table.Remove( targ );
for ( int i = 0; i < mods.Length; ++i )
targ.RemoveResistanceMod( mods[i] );
}
}
FinishSequence();
}
else
{
if ( Caster.MeleeDamageAbsorb > 0 )
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
}
else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) )
{
Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time.
}
else if ( CheckSequence() )
{
if ( Caster.BeginAction( typeof( DefensiveSpell ) ) )
{
int value = (int)(Caster.Skills[SkillName.Magery].Value + Caster.Skills[SkillName.Meditation].Value + Caster.Skills[SkillName.Inscribe].Value);
value /= 3;
if ( value < 0 )
value = 1;
else if ( value > 75 )
value = 75;
Caster.MeleeDamageAbsorb = value;
Caster.FixedParticles( 0x376A, 9, 32, 5008, EffectLayer.Waist );
Caster.PlaySound( 0x1F2 );
}
else
{
Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time.
}
}
FinishSequence();
}
}
}
}

View file

@ -0,0 +1,81 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.First
{
public class WeakenSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Weaken", "Des Mani",
SpellCircle.First,
212,
9031,
Reagent.Garlic,
Reagent.Nightshade
);
public WeakenSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m );
SpellHelper.AddStatCurse( Caster, m, StatType.Str );
if ( m.Spell != null )
m.Spell.OnCasterHurt();
m.Paralyzed = false;
m.FixedParticles( 0x3779, 10, 15, 5009, EffectLayer.Waist );
m.PlaySound( 0x1E6 );
int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, true )*100);
TimeSpan length = SpellHelper.GetDuration( Caster, m );
BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Weaken, 1075837, length, m, percentage.ToString() ) );
}
FinishSequence();
}
public class InternalTarget : Target
{
private WeakenSpell m_Owner;
public InternalTarget( WeakenSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,144 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Fourth
{
public class ArchCureSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Arch Cure", "Vas An Nox",
SpellCircle.Fourth,
215,
9061,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.MandrakeRoot
);
public ArchCureSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
// Archcure is now 1/4th of a second faster
public override int CastDelayBase{ get{ return base.CastDelayBase - 1; } }
public void Target( IPoint3D p )
{
if ( !Caster.CanSee( p ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckSequence() )
{
SpellHelper.Turn( Caster, p );
SpellHelper.GetSurfaceTop( ref p );
ArrayList targets = new ArrayList();
Map map = Caster.Map;
if ( map != null )
{
IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( p ), 2 );
foreach ( Mobile m in eable )
{
// Archcure doesn't cure aggressors or victims
if ( Caster.CanBeBeneficial( m, false ) && (!Core.AOS || !IsAggressor( m ) && !IsAggressed( m )) )
targets.Add( m );
}
eable.Free();
}
Effects.PlaySound( p, Caster.Map, 0x299 );
if ( targets.Count > 0 )
{
int cured = 0;
for ( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
Caster.DoBeneficial( m );
Poison poison = m.Poison;
if ( poison != null )
{
int chanceToCure = 10000 + (int)(Caster.Skills[SkillName.Magery].Value * 75) - ((poison.Level + 1) * 1750);
chanceToCure /= 100;
chanceToCure -= 1;
if ( chanceToCure > Utility.Random( 100 ) && m.CurePoison( Caster ) )
++cured;
}
m.FixedParticles( 0x373A, 10, 15, 5012, EffectLayer.Waist );
m.PlaySound( 0x1E0 );
}
if ( cured > 0 )
Caster.SendLocalizedMessage( 1010058 ); // You have cured the target of all poisons!
}
}
FinishSequence();
}
private bool IsAggressor( Mobile m )
{
foreach ( AggressorInfo info in Caster.Aggressors )
{
if ( m == info.Attacker && !info.Expired )
return true;
}
return false;
}
private bool IsAggressed( Mobile m )
{
foreach ( AggressorInfo info in Caster.Aggressed )
{
if ( m == info.Defender && !info.Expired )
return true;
}
return false;
}
private class InternalTarget : Target
{
private ArchCureSpell m_Owner;
public InternalTarget( ArchCureSpell owner ) : base( 12, true, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
IPoint3D p = o as IPoint3D;
if ( p != null )
m_Owner.Target( p );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,154 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
using Server.Engines.PartySystem;
namespace Server.Spells.Fourth
{
public class ArchProtectionSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Arch Protection", "Vas Uus Sanct",
SpellCircle.Fourth,
Core.AOS ? 239 : 215,
9011,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.MandrakeRoot,
Reagent.SulfurousAsh
);
public ArchProtectionSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( IPoint3D p )
{
if ( !Caster.CanSee( p ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckSequence() )
{
SpellHelper.Turn( Caster, p );
SpellHelper.GetSurfaceTop( ref p );
ArrayList targets = new ArrayList();
Map map = Caster.Map;
if ( map != null )
{
IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( p ), Core.AOS ? 2 : 3 );
foreach ( Mobile m in eable )
{
if ( Caster.CanBeBeneficial( m, false ) )
targets.Add( m );
}
eable.Free();
}
if ( Core.AOS )
{
Party party = Party.Get( Caster );
for ( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
if ( m == Caster || (party != null && party.Contains( m )) )
{
Caster.DoBeneficial( m );
Spells.Second.ProtectionSpell.Toggle( Caster, m );
}
}
}
else
{
Effects.PlaySound( p, Caster.Map, 0x299 );
int val = (int)(Caster.Skills[SkillName.Magery].Value/10.0 + 1);
if ( targets.Count > 0 )
{
for ( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
if ( m.BeginAction( typeof( ArchProtectionSpell ) ) )
{
Caster.DoBeneficial( m );
m.VirtualArmorMod += val;
new InternalTimer( m, Caster, val ).Start();
m.FixedParticles( 0x375A, 9, 20, 5027, EffectLayer.Waist );
m.PlaySound( 0x1F7 );
}
}
}
}
}
FinishSequence();
}
private class InternalTimer : Timer
{
private Mobile m_Owner;
private int m_Val;
public InternalTimer( Mobile target, Mobile caster, int val ) : base( TimeSpan.FromSeconds( 0 ) )
{
double time = caster.Skills[SkillName.Magery].Value * 1.2;
if ( time > 144 )
time = 144;
Delay = TimeSpan.FromSeconds( time );
Priority = TimerPriority.OneSecond;
m_Owner = target;
m_Val = val;
}
protected override void OnTick()
{
m_Owner.EndAction( typeof( ArchProtectionSpell ) );
m_Owner.VirtualArmorMod -= m_Val;
if ( m_Owner.VirtualArmorMod < 0 )
m_Owner.VirtualArmorMod = 0;
}
}
private class InternalTarget : Target
{
private ArchProtectionSpell m_Owner;
public InternalTarget( ArchProtectionSpell owner ) : base( 12, true, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
IPoint3D p = o as IPoint3D;
if ( p != null )
m_Owner.Target( p );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,103 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Fourth
{
public class CurseSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Curse", "Des Sanct",
SpellCircle.Fourth,
227,
9031,
Reagent.Nightshade,
Reagent.Garlic,
Reagent.SulfurousAsh
);
public CurseSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
private static Hashtable m_UnderEffect = new Hashtable();
public static void RemoveEffect( object state )
{
Mobile m = (Mobile)state;
m_UnderEffect.Remove( m );
m.UpdateResistances();
}
public static bool UnderEffect( Mobile m )
{
return m_UnderEffect.Contains( m );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m );
SpellHelper.AddStatCurse( Caster, m, StatType.Str ); SpellHelper.DisableSkillCheck = true;
SpellHelper.AddStatCurse( Caster, m, StatType.Dex );
SpellHelper.AddStatCurse( Caster, m, StatType.Int ); SpellHelper.DisableSkillCheck = false;
Timer t = (Timer)m_UnderEffect[m];
if ( Caster.Player && m.Player /*&& Caster != m */ && t == null ) //On OSI you CAN curse yourself and get this effect.
{
TimeSpan duration = SpellHelper.GetDuration( Caster, m );
m_UnderEffect[m] = t = Timer.DelayCall( duration, new TimerStateCallback( RemoveEffect ), m );
m.UpdateResistances();
}
if ( m.Spell != null )
m.Spell.OnCasterHurt();
m.Paralyzed = false;
m.FixedParticles( 0x374A, 10, 15, 5028, EffectLayer.Waist );
m.PlaySound( 0x1EA );
}
FinishSequence();
}
private class InternalTarget : Target
{
private CurseSpell m_Owner;
public InternalTarget( CurseSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile)o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,284 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
using Server.Misc;
using Server.Items;
namespace Server.Spells.Fourth
{
public class FireFieldSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Fire Field", "In Flam Grav",
SpellCircle.Fourth,
215,
9041,
false,
Reagent.BlackPearl,
Reagent.SpidersSilk,
Reagent.SulfurousAsh
);
public FireFieldSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( IPoint3D p )
{
if ( !Caster.CanSee( p ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() )
{
SpellHelper.Turn( Caster, p );
SpellHelper.GetSurfaceTop( ref p );
int dx = Caster.Location.X - p.X;
int dy = Caster.Location.Y - p.Y;
int rx = (dx - dy) * 44;
int ry = (dx + dy) * 44;
bool eastToWest;
if ( rx >= 0 && ry >= 0 )
{
eastToWest = false;
}
else if ( rx >= 0 )
{
eastToWest = true;
}
else if ( ry >= 0 )
{
eastToWest = true;
}
else
{
eastToWest = false;
}
Effects.PlaySound( p, Caster.Map, 0x20C );
int itemID = eastToWest ? 0x398C : 0x3996;
TimeSpan duration;
if ( Core.AOS )
duration = TimeSpan.FromSeconds( (15 + (Caster.Skills.Magery.Fixed / 5)) / 4 );
else
duration = TimeSpan.FromSeconds( 4.0 + (Caster.Skills[SkillName.Magery].Value * 0.5) );
for ( int i = -2; i <= 2; ++i )
{
Point3D loc = new Point3D( eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z );
new InternalItem( itemID, loc, Caster, Caster.Map, duration, i );
}
}
FinishSequence();
}
[DispellableField]
private class InternalItem : Item
{
private Timer m_Timer;
private DateTime m_End;
private Mobile m_Caster;
public override bool BlocksFit{ get{ return true; } }
public InternalItem( int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val ) : base( itemID )
{
bool canFit = SpellHelper.AdjustField( ref loc, map, 12, false );
Visible = false;
Movable = false;
Light = LightType.Circle300;
MoveToWorld( loc, map );
m_Caster = caster;
m_End = DateTime.Now + duration;
m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( Math.Abs( val ) * 0.2 ), caster.InLOS( this ), canFit );
m_Timer.Start();
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if ( m_Timer != null )
m_Timer.Stop();
}
public InternalItem( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 1 ); // version
writer.Write( m_Caster );
writer.WriteDeltaTime( m_End );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch ( version )
{
case 1:
{
m_Caster = reader.ReadMobile();
goto case 0;
}
case 0:
{
m_End = reader.ReadDeltaTime();
m_Timer = new InternalTimer( this, TimeSpan.Zero, true, true );
m_Timer.Start();
break;
}
}
}
public override bool OnMoveOver( Mobile m )
{
if ( Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && SpellHelper.ValidIndirectTarget( m_Caster, m ) && m_Caster.CanBeHarmful( m, false ) )
{
m_Caster.DoHarmful( m );
int damage = 2;
if ( !Core.AOS && m.CheckSkill( SkillName.MagicResist, 0.0, 30.0 ) )
{
damage = 1;
m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy.
}
AOS.Damage( m, m_Caster, damage, 0, 100, 0, 0, 0 );
m.PlaySound( 0x208 );
}
return true;
}
private class InternalTimer : Timer
{
private InternalItem m_Item;
private bool m_InLOS, m_CanFit;
private static Queue m_Queue = new Queue();
public InternalTimer( InternalItem item, TimeSpan delay, bool inLOS, bool canFit ) : base( delay, TimeSpan.FromSeconds( 1.0 ) )
{
m_Item = item;
m_InLOS = inLOS;
m_CanFit = canFit;
Priority = TimerPriority.FiftyMS;
}
protected override void OnTick()
{
if ( m_Item.Deleted )
return;
if ( !m_Item.Visible )
{
if ( m_InLOS && m_CanFit )
m_Item.Visible = true;
else
m_Item.Delete();
if ( !m_Item.Deleted )
{
m_Item.ProcessDelta();
Effects.SendLocationParticles( EffectItem.Create( m_Item.Location, m_Item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5029 );
}
}
else if ( DateTime.Now > m_Item.m_End )
{
m_Item.Delete();
Stop();
}
else
{
Map map = m_Item.Map;
Mobile caster = m_Item.m_Caster;
if ( map != null && caster != null )
{
foreach ( Mobile m in m_Item.GetMobilesInRange( 0 ) )
{
if ( (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z && (!Core.AOS || m != caster) && SpellHelper.ValidIndirectTarget( caster, m ) && caster.CanBeHarmful( m, false ) )
m_Queue.Enqueue( m );
}
while ( m_Queue.Count > 0 )
{
Mobile m = (Mobile)m_Queue.Dequeue();
caster.DoHarmful( m );
int damage = 2;
if ( !Core.AOS && m.CheckSkill( SkillName.MagicResist, 0.0, 30.0 ) )
{
damage = 1;
m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy.
}
AOS.Damage( m, caster, damage, 0, 100, 0, 0, 0 );
m.PlaySound( 0x208 );
}
}
}
}
}
}
private class InternalTarget : Target
{
private FireFieldSpell m_Owner;
public InternalTarget( FireFieldSpell owner ) : base( 12, true, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is IPoint3D )
m_Owner.Target( (IPoint3D)o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,94 @@
using System;
using Server;
using Server.Targeting;
using Server.Network;
using Server.Mobiles;
namespace Server.Spells.Fourth
{
public class GreaterHealSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Greater Heal", "In Vas Mani",
SpellCircle.Fourth,
204,
9061,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.MandrakeRoot,
Reagent.SpidersSilk
);
public GreaterHealSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( m is BaseCreature && ((BaseCreature)m).IsAnimatedDead )
{
Caster.SendLocalizedMessage( 1061654 ); // You cannot heal that which is not alive.
}
else if ( m.IsDeadBondedPet )
{
Caster.SendLocalizedMessage( 1060177 ); // You cannot heal a creature that is already dead!
}
else if ( m is Golem )
{
Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500951 ); // You cannot heal that.
}
else if ( m.Poisoned || Server.Items.MortalStrike.IsWounded( m ) )
{
Caster.LocalOverheadMessage( MessageType.Regular, 0x22, (Caster == m) ? 1005000 : 1010398 );
}
else if ( CheckBSequence( m ) )
{
SpellHelper.Turn( Caster, m );
// Algorithm: (40% of magery) + (1-10)
int toHeal = (int)(Caster.Skills[SkillName.Magery].Value * 0.4);
toHeal += Utility.Random( 1, 10 );
m.Heal( toHeal );
m.FixedParticles( 0x376A, 9, 32, 5030, EffectLayer.Waist );
m.PlaySound( 0x202 );
}
FinishSequence();
}
public class InternalTarget : Target
{
private GreaterHealSpell m_Owner;
public InternalTarget( GreaterHealSpell owner ) : base( 12, false, TargetFlags.Beneficial )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,90 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Fourth
{
public class LightningSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Lightning", "Por Ort Grav",
SpellCircle.Fourth,
239,
9021,
Reagent.MandrakeRoot,
Reagent.SulfurousAsh
);
public LightningSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override bool DelayedDamage{ get{ return false; } }
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m );
double damage;
if ( Core.AOS )
{
damage = GetNewAosDamage( 23, 1, 4, m );
}
else
{
damage = Utility.Random( 12, 9 );
if ( CheckResisted( m ) )
{
damage *= 0.75;
m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy.
}
damage *= GetDamageScalar( m );
}
m.BoltEffect( 0 );
SpellHelper.Damage( this, m, damage, 0, 0, 0, 0, 100 );
}
FinishSequence();
}
private class InternalTarget : Target
{
private LightningSpell m_Owner;
public InternalTarget( LightningSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile)o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,131 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Fourth
{
public class ManaDrainSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Mana Drain", "Ort Rel",
SpellCircle.Fourth,
215,
9031,
Reagent.BlackPearl,
Reagent.MandrakeRoot,
Reagent.SpidersSilk
);
public ManaDrainSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
private Hashtable m_Table = new Hashtable();
private void AosDelay_Callback( object state )
{
object[] states = (object[])state;
Mobile m = (Mobile)states[0];
int mana = (int)states[1];
if ( m.Alive && !m.IsDeadBondedPet )
{
m.Mana += mana;
m.FixedEffect( 0x3779, 10, 25 );
m.PlaySound( 0x28E );
}
m_Table.Remove( m );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m );
if ( m.Spell != null )
m.Spell.OnCasterHurt();
m.Paralyzed = false;
if ( Core.AOS )
{
int toDrain = 40 + (int)(GetDamageSkill( Caster ) - GetResistSkill( m ));
if ( toDrain < 0 )
toDrain = 0;
else if ( toDrain > m.Mana )
toDrain = m.Mana;
if ( m_Table.Contains( m ) )
toDrain = 0;
m.FixedParticles( 0x3789, 10, 25, 5032, EffectLayer.Head );
m.PlaySound( 0x1F8 );
if ( toDrain > 0 )
{
m.Mana -= toDrain;
m_Table[m] = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( AosDelay_Callback ), new object[]{ m, toDrain } );
}
}
else
{
if ( CheckResisted( m ) )
m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy.
else if ( m.Mana >= 100 )
m.Mana -= Utility.Random( 1, 100 );
else
m.Mana -= Utility.Random( 1, m.Mana );
m.FixedParticles( 0x374A, 10, 15, 5032, EffectLayer.Head );
m.PlaySound( 0x1F8 );
}
}
FinishSequence();
}
public override double GetResistPercent( Mobile target )
{
return 99.0;
}
private class InternalTarget : Target
{
private ManaDrainSpell m_Owner;
public InternalTarget( ManaDrainSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile)o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,196 @@
using System;
using Server.Items;
using Server.Multis;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
using Server.Regions;
using Server.Spells.Necromancy;
namespace Server.Spells.Fourth
{
public class RecallSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Recall", "Kal Ort Por",
SpellCircle.Fourth,
239,
9031,
Reagent.BlackPearl,
Reagent.Bloodmoss,
Reagent.MandrakeRoot
);
private RunebookEntry m_Entry;
private Runebook m_Book;
public RecallSpell( Mobile caster, Item scroll ) : this( caster, scroll, null, null )
{
}
public RecallSpell( Mobile caster, Item scroll, RunebookEntry entry, Runebook book ) : base( caster, scroll, m_Info )
{
m_Entry = entry;
m_Book = book;
}
public override void GetCastSkills( out double min, out double max )
{
if ( TransformationSpell.UnderTransformation( Caster, typeof( WraithFormSpell ) ) )
min = max = 0;
else if( Core.SE && m_Book != null ) //recall using Runebook charge
min = max = 0;
else
base.GetCastSkills( out min, out max );
}
public override void OnCast()
{
if ( m_Entry == null )
Caster.Target = new InternalTarget( this );
else
Effect( m_Entry.Location, m_Entry.Map, true );
}
public override bool CheckCast()
{
if ( Factions.Sigil.ExistsOn( Caster ) )
{
Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
return false;
}
else if ( Caster.Criminal )
{
Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily.
return false;
}
else if ( SpellHelper.CheckCombat( Caster ) )
{
Caster.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle??
return false;
}
else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) )
{
Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move.
return false;
}
return SpellHelper.CheckTravel( Caster, TravelCheckType.RecallFrom );
}
public void Effect( Point3D loc, Map map, bool checkMulti )
{
if ( Factions.Sigil.ExistsOn( Caster ) )
{
Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
}
else if ( map == null || (!Core.AOS && Caster.Map != map) )
{
Caster.SendLocalizedMessage( 1005569 ); // You can not recall to another facet.
}
else if ( !SpellHelper.CheckTravel( Caster, TravelCheckType.RecallFrom ) )
{
}
else if ( !SpellHelper.CheckTravel( Caster, map, loc, TravelCheckType.RecallTo ) )
{
}
else if ( map == Map.Felucca && Caster is PlayerMobile && ((PlayerMobile)Caster).Young )
{
Caster.SendLocalizedMessage( 1049543 ); // You decide against traveling to Felucca while you are still young.
}
else if ( Caster.Kills >= 5 && map != Map.Felucca )
{
Caster.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there.
}
else if ( Caster.Criminal )
{
Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily.
}
else if ( SpellHelper.CheckCombat( Caster ) )
{
Caster.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle??
}
else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) )
{
Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move.
}
else if ( !map.CanSpawnMobile( loc.X, loc.Y, loc.Z ) )
{
Caster.SendLocalizedMessage( 501942 ); // That location is blocked.
}
else if ( (checkMulti && SpellHelper.CheckMulti( loc, map )) )
{
Caster.SendLocalizedMessage( 501942 ); // That location is blocked.
}
else if ( m_Book != null && m_Book.CurCharges <= 0 )
{
Caster.SendLocalizedMessage( 502412 ); // There are no charges left on that item.
}
else if ( CheckSequence() )
{
BaseCreature.TeleportPets( Caster, loc, map, true );
if ( m_Book != null )
--m_Book.CurCharges;
Caster.PlaySound( 0x1FC );
Caster.MoveToWorld( loc, map );
Caster.PlaySound( 0x1FC );
}
FinishSequence();
}
private class InternalTarget : Target
{
private RecallSpell m_Owner;
public InternalTarget( RecallSpell owner ) : base( 12, false, TargetFlags.None )
{
m_Owner = owner;
owner.Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501029 ); // Select Marked item.
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is RecallRune )
{
RecallRune rune = (RecallRune)o;
if ( rune.Marked )
m_Owner.Effect( rune.Target, rune.TargetMap, true );
else
from.SendLocalizedMessage( 501805 ); // That rune is not yet marked.
}
else if ( o is Runebook )
{
RunebookEntry e = ((Runebook)o).Default;
if ( e != null )
m_Owner.Effect( e.Location, e.Map, true );
else
from.SendLocalizedMessage( 502354 ); // Target is not marked.
}
else if ( o is Key && ((Key)o).KeyValue != 0 && ((Key)o).Link is BaseBoat )
{
BaseBoat boat = ((Key)o).Link as BaseBoat;
if ( !boat.Deleted && boat.CheckKey( ((Key)o).KeyValue ) )
m_Owner.Effect( boat.GetMarkedLocation(), boat.Map, false );
else
from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "" ) ); // I can not recall from that object.
}
else
{
from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "" ) ); // I can not recall from that object.
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,153 @@
using System;
using Server;
namespace Server.Spells
{
public class Initializer
{
public static void Initialize()
{
// First circle
Register( 00, typeof( First.ClumsySpell ) );
Register( 01, typeof( First.CreateFoodSpell ) );
Register( 02, typeof( First.FeeblemindSpell ) );
Register( 03, typeof( First.HealSpell ) );
Register( 04, typeof( First.MagicArrowSpell ) );
Register( 05, typeof( First.NightSightSpell ) );
Register( 06, typeof( First.ReactiveArmorSpell ) );
Register( 07, typeof( First.WeakenSpell ) );
// Second circle
Register( 08, typeof( Second.AgilitySpell ) );
Register( 09, typeof( Second.CunningSpell ) );
Register( 10, typeof( Second.CureSpell ) );
Register( 11, typeof( Second.HarmSpell ) );
Register( 12, typeof( Second.MagicTrapSpell ) );
Register( 13, typeof( Second.RemoveTrapSpell ) );
Register( 14, typeof( Second.ProtectionSpell ) );
Register( 15, typeof( Second.StrengthSpell ) );
// Third circle
Register( 16, typeof( Third.BlessSpell ) );
Register( 17, typeof( Third.FireballSpell ) );
Register( 18, typeof( Third.MagicLockSpell ) );
Register( 19, typeof( Third.PoisonSpell ) );
Register( 20, typeof( Third.TelekinesisSpell ) );
Register( 21, typeof( Third.TeleportSpell ) );
Register( 22, typeof( Third.UnlockSpell ) );
Register( 23, typeof( Third.WallOfStoneSpell ) );
// Fourth circle
Register( 24, typeof( Fourth.ArchCureSpell ) );
Register( 25, typeof( Fourth.ArchProtectionSpell ) );
Register( 26, typeof( Fourth.CurseSpell ) );
Register( 27, typeof( Fourth.FireFieldSpell ) );
Register( 28, typeof( Fourth.GreaterHealSpell ) );
Register( 29, typeof( Fourth.LightningSpell ) );
Register( 30, typeof( Fourth.ManaDrainSpell ) );
Register( 31, typeof( Fourth.RecallSpell ) );
// Fifth circle
Register( 32, typeof( Fifth.BladeSpiritsSpell ) );
Register( 33, typeof( Fifth.DispelFieldSpell ) );
Register( 34, typeof( Fifth.IncognitoSpell ) );
Register( 35, typeof( Fifth.MagicReflectSpell ) );
Register( 36, typeof( Fifth.MindBlastSpell ) );
Register( 37, typeof( Fifth.ParalyzeSpell ) );
Register( 38, typeof( Fifth.PoisonFieldSpell ) );
Register( 39, typeof( Fifth.SummonCreatureSpell ) );
// Sixth circle
Register( 40, typeof( Sixth.DispelSpell ) );
Register( 41, typeof( Sixth.EnergyBoltSpell ) );
Register( 42, typeof( Sixth.ExplosionSpell ) );
Register( 43, typeof( Sixth.InvisibilitySpell ) );
Register( 44, typeof( Sixth.MarkSpell ) );
Register( 45, typeof( Sixth.MassCurseSpell ) );
Register( 46, typeof( Sixth.ParalyzeFieldSpell ) );
Register( 47, typeof( Sixth.RevealSpell ) );
// Seventh circle
Register( 48, typeof( Seventh.ChainLightningSpell ) );
Register( 49, typeof( Seventh.EnergyFieldSpell ) );
Register( 50, typeof( Seventh.FlameStrikeSpell ) );
Register( 51, typeof( Seventh.GateTravelSpell ) );
Register( 52, typeof( Seventh.ManaVampireSpell ) );
Register( 53, typeof( Seventh.MassDispelSpell ) );
Register( 54, typeof( Seventh.MeteorSwarmSpell ) );
Register( 55, typeof( Seventh.PolymorphSpell ) );
// Eighth circle
Register( 56, typeof( Eighth.EarthquakeSpell ) );
Register( 57, typeof( Eighth.EnergyVortexSpell ) );
Register( 58, typeof( Eighth.ResurrectionSpell ) );
Register( 59, typeof( Eighth.AirElementalSpell ) );
Register( 60, typeof( Eighth.SummonDaemonSpell ) );
Register( 61, typeof( Eighth.EarthElementalSpell ) );
Register( 62, typeof( Eighth.FireElementalSpell ) );
Register( 63, typeof( Eighth.WaterElementalSpell ) );
if ( Core.AOS )
{
// Necromancy spells
Register( 100, typeof( Necromancy.AnimateDeadSpell ) );
Register( 101, typeof( Necromancy.BloodOathSpell ) );
Register( 102, typeof( Necromancy.CorpseSkinSpell ) );
Register( 103, typeof( Necromancy.CurseWeaponSpell ) );
Register( 104, typeof( Necromancy.EvilOmenSpell ) );
Register( 105, typeof( Necromancy.HorrificBeastSpell ) );
Register( 106, typeof( Necromancy.LichFormSpell ) );
Register( 107, typeof( Necromancy.MindRotSpell ) );
Register( 108, typeof( Necromancy.PainSpikeSpell ) );
Register( 109, typeof( Necromancy.PoisonStrikeSpell ) );
Register( 110, typeof( Necromancy.StrangleSpell ) );
Register( 111, typeof( Necromancy.SummonFamiliarSpell ) );
Register( 112, typeof( Necromancy.VampiricEmbraceSpell ) );
Register( 113, typeof( Necromancy.VengefulSpiritSpell ) );
Register( 114, typeof( Necromancy.WitherSpell ) );
Register( 115, typeof( Necromancy.WraithFormSpell ) );
if( Core.SE )
Register( 116, typeof( Necromancy.ExorcismSpell ) );
// Paladin abilities
Register( 200, typeof( Chivalry.CleanseByFireSpell ) );
Register( 201, typeof( Chivalry.CloseWoundsSpell ) );
Register( 202, typeof( Chivalry.ConsecrateWeaponSpell ) );
Register( 203, typeof( Chivalry.DispelEvilSpell ) );
Register( 204, typeof( Chivalry.DivineFurySpell ) );
Register( 205, typeof( Chivalry.EnemyOfOneSpell ) );
Register( 206, typeof( Chivalry.HolyLightSpell ) );
Register( 207, typeof( Chivalry.NobleSacrificeSpell ) );
Register( 208, typeof( Chivalry.RemoveCurseSpell ) );
Register( 209, typeof( Chivalry.SacredJourneySpell ) );
if ( Core.SE )
{
// Samurai abilities
Register( 400, typeof( Bushido.HonorableExecution ) );
Register( 401, typeof( Bushido.Confidence ) );
Register( 402, typeof( Bushido.Evasion ) );
Register( 403, typeof( Bushido.CounterAttack ) );
Register( 404, typeof( Bushido.LightningStrike ) );
Register( 405, typeof( Bushido.MomentumStrike ) );
// Ninja abilities
Register( 500, typeof( Ninjitsu.FocusAttack ) );
Register( 501, typeof( Ninjitsu.DeathStrike ) );
Register( 502, typeof( Ninjitsu.AnimalForm ) );
Register( 503, typeof( Ninjitsu.KiAttack ) );
Register( 504, typeof( Ninjitsu.SurpriseAttack ) );
Register( 505, typeof( Ninjitsu.Backstab ) );
Register( 506, typeof( Ninjitsu.Shadowjump ) );
Register( 507, typeof( Ninjitsu.MirrorImage ) );
}
}
}
public static void Register( int spellID, Type type )
{
SpellRegistry.Register( spellID, type );
}
}
}

View file

@ -0,0 +1,419 @@
using System;
using System.Collections;
using Server.Network;
using Server.Mobiles;
using Server.Targeting;
using Server.Items;
using Server.Engines.Quests;
using Server.Engines.Quests.Necro;
namespace Server.Spells.Necromancy
{
public class AnimateDeadSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Animate Dead", "Uus Corp",
SpellCircle.Fourth, // 0.5 + 1.0 = 1.5s base cast delay
203,
9031,
Reagent.GraveDust,
Reagent.DaemonBlood
);
public override double RequiredSkill{ get{ return 40.0; } }
public override int RequiredMana{ get{ return 23; } }
public AnimateDeadSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
Caster.SendLocalizedMessage( 1061083 ); // Animate what corpse?
}
private class CreatureGroup
{
public Type[] m_Types;
public SummonEntry[] m_Entries;
public CreatureGroup( Type[] types, SummonEntry[] entries )
{
m_Types = types;
m_Entries = entries;
}
}
private class SummonEntry
{
public Type[] m_ToSummon;
public int m_Requirement;
public SummonEntry( int requirement, params Type[] toSummon )
{
m_ToSummon = toSummon;
m_Requirement = requirement;
}
}
private static CreatureGroup FindGroup( Type type )
{
for ( int i = 0; i < m_Groups.Length; ++i )
{
CreatureGroup group = m_Groups[i];
Type[] types = group.m_Types;
bool contains = ( types.Length == 0 );
for ( int j = 0; !contains && j < types.Length; ++j )
contains = ( types[j] == type );
if ( contains )
return group;
}
return null;
}
private static CreatureGroup[] m_Groups = new CreatureGroup[]
{
// Undead group--empty
new CreatureGroup( SlayerGroup.GetEntryByName( SlayerName.Silver ).Types, new SummonEntry[0] ),
// Insects
new CreatureGroup( new Type[]
{
typeof( DreadSpider ), typeof( FrostSpider ), typeof( GiantSpider ), typeof( GiantBlackWidow ),
typeof( BlackSolenInfiltratorQueen ), typeof( BlackSolenInfiltratorWarrior ),
typeof( BlackSolenQueen ), typeof( BlackSolenWarrior ), typeof( BlackSolenWorker ),
typeof( RedSolenInfiltratorQueen ), typeof( RedSolenInfiltratorWarrior ),
typeof( RedSolenQueen ), typeof( RedSolenWarrior ), typeof( RedSolenWorker ),
typeof( TerathanAvenger ), typeof( TerathanDrone ), typeof( TerathanMatriarch ),
typeof( TerathanWarrior )
// TODO: Giant beetle? Ant lion? Ophidians?
},
new SummonEntry[]
{
new SummonEntry( 0, typeof( MoundOfMaggots ) )
} ),
// Mounts
new CreatureGroup( new Type[]
{
typeof( Horse ), typeof( Nightmare ), typeof( FireSteed ),
typeof( Kirin ), typeof( Unicorn )
}, new SummonEntry[]
{
new SummonEntry( 10000, typeof( HellSteed ) ),
new SummonEntry( 0, typeof( SkeletalMount ) )
} ),
// Elementals
new CreatureGroup( new Type[]
{
typeof( BloodElemental ), typeof( EarthElemental ), typeof( SummonedEarthElemental ),
typeof( AgapiteElemental ), typeof( BronzeElemental ), typeof( CopperElemental ),
typeof( DullCopperElemental ), typeof( GoldenElemental ), typeof( ShadowIronElemental ),
typeof( ValoriteElemental ), typeof( VeriteElemental ), typeof( PoisonElemental ),
typeof( FireElemental ), typeof( SummonedFireElemental ), typeof( SnowElemental ),
typeof( AirElemental ), typeof( SummonedAirElemental ), typeof( WaterElemental ),
typeof( SummonedAirElemental )
}, new SummonEntry[]
{
new SummonEntry( 5000, typeof( WailingBanshee ) ),
new SummonEntry( 0, typeof( Wraith ) )
} ),
// Dragons
new CreatureGroup( new Type[]
{
typeof( AncientWyrm ), typeof( Dragon ), typeof( SerpentineDragon ),
typeof( ShadowWyrm ), typeof( SkeletalDragon ), typeof( WhiteWyrm ),
typeof( Drake ), typeof( Wyvern ), typeof( LesserHiryu ), typeof( Hiryu )
}, new SummonEntry[]
{
new SummonEntry( 18000, typeof( SkeletalDragon ) ),
new SummonEntry( 10000, typeof( FleshGolem ) ),
new SummonEntry( 5000, typeof( Lich ) ),
new SummonEntry( 3000, typeof( SkeletalKnight ), typeof( BoneKnight ) ),
new SummonEntry( 2000, typeof( Mummy ) ),
new SummonEntry( 1000, typeof( SkeletalMage ), typeof( BoneMagi ) ),
new SummonEntry( 0, typeof( PatchworkSkeleton ) )
} ),
// Default group
new CreatureGroup( new Type[0], new SummonEntry[]
{
new SummonEntry( 18000, typeof( LichLord ) ),
new SummonEntry( 10000, typeof( FleshGolem ) ),
new SummonEntry( 5000, typeof( Lich ) ),
new SummonEntry( 3000, typeof( SkeletalKnight ), typeof( BoneKnight ) ),
new SummonEntry( 2000, typeof( Mummy ) ),
new SummonEntry( 1000, typeof( SkeletalMage ), typeof( BoneMagi ) ),
new SummonEntry( 0, typeof( PatchworkSkeleton ) )
} ),
};
public void Target( object obj )
{
MaabusCoffinComponent comp = obj as MaabusCoffinComponent;
if ( comp != null )
{
MaabusCoffin addon = comp.Addon as MaabusCoffin;
if ( addon != null )
{
PlayerMobile pm = Caster as PlayerMobile;
if ( pm != null )
{
QuestSystem qs = pm.Quest;
if ( qs is DarkTidesQuest )
{
QuestObjective objective = qs.FindObjective( typeof( AnimateMaabusCorpseObjective ) );
if ( objective != null && !objective.Completed )
{
addon.Awake( Caster );
objective.Complete();
}
}
}
return;
}
}
Corpse c = obj as Corpse;
if ( c == null )
{
Caster.SendLocalizedMessage( 1061084 ); // You cannot animate that.
}
else
{
Type type = null;
if ( c.Owner != null )
type = c.Owner.GetType();
if ( c.ItemID != 0x2006 || c.Channeled || type == typeof( PlayerMobile ) || type == null || (c.Owner != null && c.Owner.Fame < 100) || ((c.Owner != null) && (c.Owner is BaseCreature) && (((BaseCreature)c.Owner).Summoned || ((BaseCreature)c.Owner).IsBonded)) )
{
Caster.SendLocalizedMessage( 1061085 ); // There's not enough life force there to animate.
}
else
{
CreatureGroup group = FindGroup( type );
if ( group != null )
{
if ( group.m_Entries.Length == 0 || type == typeof( DemonKnight ) )
{
Caster.SendLocalizedMessage( 1061086 ); // You cannot animate undead remains.
}
else if ( CheckSequence() )
{
Point3D p = c.GetWorldLocation();
Map map = c.Map;
if ( map != null )
{
Effects.PlaySound( p, map, 0x1FB );
Effects.SendLocationParticles( EffectItem.Create( p, map, EffectItem.DefaultDuration ), 0x3789, 1, 40, 0x3F, 3, 9907, 0 );
Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( SummonDelay_Callback ), new object[]{ Caster, c, p, map, group } );
}
}
}
}
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
public static void Unregister( Mobile master, Mobile summoned )
{
if ( master == null )
return;
ArrayList list = (ArrayList)m_Table[master];
if ( list == null )
return;
list.Remove( summoned );
if ( list.Count == 0 )
m_Table.Remove( master );
}
public static void Register( Mobile master, Mobile summoned )
{
if ( master == null )
return;
ArrayList list = (ArrayList)m_Table[master];
if ( list == null )
m_Table[master] = list = new ArrayList();
for ( int i = list.Count - 1; i >= 0; --i )
{
if ( i >= list.Count )
continue;
Mobile mob = (Mobile)list[i];
if ( mob.Deleted )
list.RemoveAt( i-- );
}
list.Add( summoned );
if ( list.Count > 3 )
Timer.DelayCall( TimeSpan.Zero, new TimerCallback( ((Mobile)list[0]).Kill ) );
Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( Summoned_Damage ), summoned );
}
private static void Summoned_Damage( object state )
{
Mobile mob = (Mobile)state;
if ( mob.Hits > 0 )
--mob.Hits;
else
mob.Kill();
}
private static void SummonDelay_Callback( object state )
{
object[] states = (object[])state;
Mobile caster = (Mobile)states[0];
Corpse corpse = (Corpse)states[1];
Point3D loc = (Point3D)states[2];
Map map = (Map)states[3];
CreatureGroup group = (CreatureGroup)states[4];
if ( corpse.ItemID != 0x2006 )
return;
Mobile owner = corpse.Owner;
if ( owner == null )
return;
double necromancy = caster.Skills[SkillName.Necromancy].Value;
double spiritSpeak = caster.Skills[SkillName.SpiritSpeak].Value;
int casterAbility = 0;
casterAbility += (int)(necromancy * 30);
casterAbility += (int)(spiritSpeak * 70);
casterAbility /= 10;
casterAbility *= 18;
if ( casterAbility > owner.Fame )
casterAbility = owner.Fame;
if ( casterAbility < 0 )
casterAbility = 0;
Type toSummon = null;
SummonEntry[] entries = group.m_Entries;
for ( int i = 0; toSummon == null && i < entries.Length; ++i )
{
SummonEntry entry = entries[i];
if ( casterAbility < entry.m_Requirement )
continue;
Type[] animates = entry.m_ToSummon;
if ( animates.Length >= 0 )
toSummon = animates[Utility.Random( animates.Length )];
}
if ( toSummon == null )
return;
Mobile summoned = null;
try{ summoned = Activator.CreateInstance( toSummon ) as Mobile; }
catch{}
if ( summoned == null )
return;
if ( summoned is BaseCreature )
{
BaseCreature bc = (BaseCreature)summoned;
// to be sure
bc.Tamable = false;
if ( bc is BaseMount )
bc.ControlSlots = 1;
else
bc.ControlSlots = 0;
Effects.PlaySound( loc, map, bc.GetAngerSound() );
BaseCreature.Summon( (BaseCreature)summoned, false, caster, loc, 0x28, TimeSpan.FromDays( 1.0 ) );
}
if ( summoned is SkeletalDragon )
Scale( (SkeletalDragon)summoned, 50 ); // lose 50% hp and strength
summoned.Fame = 0;
summoned.Karma = -1500;
summoned.MoveToWorld( loc, map );
corpse.ProcessDelta();
corpse.SendRemovePacket();
corpse.ItemID = Utility.Random( 0xECA, 9 ); // bone graphic
corpse.Hue = 0;
corpse.ProcessDelta();
Register( caster, summoned );
}
private static void Scale( BaseCreature bc, int scalar )
{
int toScale;
toScale = bc.RawStr;
bc.RawStr = AOS.Scale( toScale, scalar );
toScale = bc.HitsMaxSeed;
if ( toScale > 0 )
bc.HitsMaxSeed = AOS.Scale( toScale, scalar );
bc.Hits = bc.Hits; // refresh hits
}
private class InternalTarget : Target
{
private AnimateDeadSpell m_Owner;
public InternalTarget( AnimateDeadSpell owner ) : base( 12, false, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
m_Owner.Target( o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,147 @@
using System;
using System.Collections;
using Server.Network;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class BloodOathSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Blood Oath", "In Jux Mani Xen",
SpellCircle.Fourth, // 0.5 + 1.0 = 1.5s base cast delay
203,
9031,
Reagent.DaemonBlood
);
public override double RequiredSkill{ get{ return 20.0; } }
public override int RequiredMana{ get{ return 13; } }
public BloodOathSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( Caster == m || !(m is PlayerMobile || m is BaseCreature) ) // only PlayerMobile and BaseCreature implement blood oath checking
{
Caster.SendLocalizedMessage( 1060508 ); // You can't curse that.
}
else if ( m_OathTable.Contains( Caster ) )
{
Caster.SendLocalizedMessage( 1061607 ); // You are already bonded in a Blood Oath.
}
else if ( m_OathTable.Contains( m ) )
{
if ( m.Player )
Caster.SendLocalizedMessage( 1061608 ); // That player is already bonded in a Blood Oath.
else
Caster.SendLocalizedMessage( 1061609 ); // That creature is already bonded in a Blood Oath.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
/* Temporarily creates a dark pact between the caster and the target.
* Any damage dealt by the target to the caster is increased, but the target receives the same amount of damage.
* The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 80 ) + 8 seconds.
*
* NOTE: The above algorithm must be fixed point, it should be:
* ((ss-rm)/8)+8
*/
m_OathTable[Caster] = Caster;
m_OathTable[m] = Caster;
Caster.PlaySound( 0x175 );
Caster.FixedParticles( 0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist );
Caster.FixedParticles( 0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255 );
m.FixedParticles( 0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist );
m.FixedParticles( 0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255 );
TimeSpan duration = TimeSpan.FromSeconds( ((GetDamageSkill( Caster ) - GetResistSkill( m )) / 8) + 8 );
new ExpireTimer( Caster, m, duration ).Start();
}
FinishSequence();
}
private static Hashtable m_OathTable = new Hashtable();
public static Mobile GetBloodOath( Mobile m )
{
if ( m == null )
return null;
Mobile oath = (Mobile)m_OathTable[m];
if ( oath == m )
oath = null;
return oath;
}
private class ExpireTimer : Timer
{
private Mobile m_Caster;
private Mobile m_Target;
private DateTime m_End;
public ExpireTimer( Mobile caster, Mobile target, TimeSpan delay ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) )
{
m_Caster = caster;
m_Target = target;
m_End = DateTime.Now + delay;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
if ( m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive || DateTime.Now >= m_End )
{
m_Caster.SendLocalizedMessage( 1061620 ); // Your Blood Oath has been broken.
m_Target.SendLocalizedMessage( 1061620 ); // Your Blood Oath has been broken.
m_OathTable.Remove( m_Caster );
m_OathTable.Remove( m_Target );
Stop();
}
}
}
private class InternalTarget : Target
{
private BloodOathSpell m_Owner;
public InternalTarget( BloodOathSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
else
from.SendLocalizedMessage( 1060508 ); // You can't curse that.
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,150 @@
using System;
using System.Collections;
using Server.Network;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class CorpseSkinSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Corpse Skin", "In Agle Corp Ylem",
SpellCircle.Fourth, // 0.5 + 1.0 = 1.5s base cast delay
203,
9051,
Reagent.BatWing,
Reagent.GraveDust
);
public override double RequiredSkill{ get{ return 20.0; } }
public override int RequiredMana{ get{ return 11; } }
public CorpseSkinSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
/* Transmogrifies the flesh of the target creature or player to resemble rotted corpse flesh,
* making them more vulnerable to Fire and Poison damage,
* but increasing their resistance to Physical and Cold damage.
*
* The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 25 ) + 40 seconds.
*
* NOTE: Algorithm above is fixed point, should be:
* ((ss-mr)/2.5) + 40
*
* NOTE: Resistance is not checked if targeting yourself
*/
ExpireTimer timer = (ExpireTimer)m_Table[m];
if ( timer != null )
timer.DoExpire();
else
m.SendLocalizedMessage( 1061689 ); // Your skin turns dry and corpselike.
m.FixedParticles( 0x373A, 1, 15, 9913, 67, 7, EffectLayer.Head );
m.PlaySound( 0x1BB );
double ss = GetDamageSkill( Caster );
double mr = ( Caster == m ? 0.0 : GetResistSkill( m ) );
TimeSpan duration = TimeSpan.FromSeconds( ((ss - mr) / 2.5) + 40.0 );
ResistanceMod[] mods = new ResistanceMod[4]
{
new ResistanceMod( ResistanceType.Fire, -15 ),
new ResistanceMod( ResistanceType.Poison, -15 ),
new ResistanceMod( ResistanceType.Cold, +10 ),
new ResistanceMod( ResistanceType.Physical, +10 )
};
timer = new ExpireTimer( m, mods, duration );
timer.Start();
BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.CorpseSkin, 1075663, duration, m ) );
m_Table[m] = timer;
for ( int i = 0; i < mods.Length; ++i )
m.AddResistanceMod( mods[i] );
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
public static bool RemoveCurse( Mobile m )
{
ExpireTimer t = (ExpireTimer)m_Table[m];
if ( t == null )
return false;
m.SendLocalizedMessage( 1061688 ); // Your skin returns to normal.
t.DoExpire();
return true;
}
private class ExpireTimer : Timer
{
private Mobile m_Mobile;
private ResistanceMod[] m_Mods;
public ExpireTimer( Mobile m, ResistanceMod[] mods, TimeSpan delay ) : base( delay )
{
m_Mobile = m;
m_Mods = mods;
}
public void DoExpire()
{
for ( int i = 0; i < m_Mods.Length; ++i )
m_Mobile.RemoveResistanceMod( m_Mods[i] );
Stop();
BuffInfo.RemoveBuff( m_Mobile, BuffIcon.CorpseSkin );
m_Table.Remove( m_Mobile );
}
protected override void OnTick()
{
m_Mobile.SendLocalizedMessage( 1061688 ); // Your skin returns to normal.
DoExpire();
}
}
private class InternalTarget : Target
{
private CorpseSkinSpell m_Owner;
public InternalTarget( CorpseSkinSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,105 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class CurseWeaponSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Curse Weapon", "An Sanct Gra Char",
SpellCircle.First, // 0.5 + 0.25 = 0.75s base cast delay
203,
9031,
Reagent.PigIron
);
public override double RequiredSkill{ get{ return 0.0; } }
public override int RequiredMana{ get{ return 7; } }
public CurseWeaponSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
BaseWeapon weapon = Caster.Weapon as BaseWeapon;
if ( weapon == null || weapon is Fists )
{
Caster.SendLocalizedMessage( 501078 ); // You must be holding a weapon.
}
else if ( CheckSequence() )
{
/* Temporarily imbues a weapon with a life draining effect.
* Half the damage that the weapon inflicts is added to the necromancer's health.
* The effects lasts for (Spirit Speak skill level / 34) + 1 seconds.
*
* NOTE: Above algorithm is fixed point, should be :
* (Spirit Speak skill level / 3.4) + 1
*
* TODO: What happens if you curse a weapon then give it to someone else? Should they get the drain effect?
*/
Caster.PlaySound( 0x387 );
Caster.FixedParticles( 0x3779, 1, 15, 9905, 32, 2, EffectLayer.Head );
Caster.FixedParticles( 0x37B9, 1, 14, 9502, 32, 5, (EffectLayer)255 );
new SoundEffectTimer( Caster ).Start();
TimeSpan duration = TimeSpan.FromSeconds( (Caster.Skills[SkillName.SpiritSpeak].Value / 3.4) + 1.0 );
Timer t = (Timer)m_Table[weapon];
if ( t != null )
t.Stop();
weapon.Cursed = true;
m_Table[weapon] = t = new ExpireTimer( weapon, duration );
t.Start();
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
private class ExpireTimer : Timer
{
private BaseWeapon m_Weapon;
public ExpireTimer( BaseWeapon weapon, TimeSpan delay ) : base( delay )
{
m_Weapon = weapon;
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
m_Weapon.Cursed = false;
Effects.PlaySound( m_Weapon.GetWorldLocation(), m_Weapon.Map, 0xFA );
m_Table.Remove( this );
}
}
private class SoundEffectTimer : Timer
{
private Mobile m_Mobile;
public SoundEffectTimer( Mobile m ) : base( TimeSpan.FromSeconds( 0.75 ) )
{
m_Mobile = m;
Priority = TimerPriority.FiftyMS;
}
protected override void OnTick()
{
m_Mobile.PlaySound( 0xFA );
}
}
}
}

View file

@ -0,0 +1,116 @@
using System;
using System.Collections;
using Server.Mobiles;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class EvilOmenSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Evil Omen", "Pas Tym An Sanct",
SpellCircle.First, // 0.5 + 0.25 = 0.75s base cast delay
203,
9031,
Reagent.BatWing,
Reagent.NoxCrystal
);
public override double RequiredSkill{ get{ return 20.0; } }
public override int RequiredMana{ get{ return 11; } }
public EvilOmenSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !(m is BaseCreature || m is PlayerMobile) )
{
Caster.SendLocalizedMessage( 1060508 ); // You can't curse that.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
/* Curses the target so that the next harmful event that affects them is magnified.
* Damage to the target's hit points is increased 25%,
* the poison level of the attack will be 1 higher
* and the Resist Magic skill of the target will be fixed on 50.
*
* The effect lasts for one harmful event only.
*/
m.PlaySound( 0xFC );
m.FixedParticles( 0x3728, 1, 13, 9912, 1150, 7, EffectLayer.Head );
m.FixedParticles( 0x3779, 1, 15, 9502, 67, 7, EffectLayer.Head );
if ( !m_Table.Contains( m ) )
{
SkillMod mod = new DefaultSkillMod( SkillName.MagicResist, false, 50.0 );
if ( m.Skills[SkillName.MagicResist].Base > 50.0 )
m.AddSkillMod( mod );
m_Table[m] = mod;
}
TimeSpan duration = TimeSpan.FromSeconds( (Caster.Skills[SkillName.SpiritSpeak].Value / 12) + 1.0 );
Timer.DelayCall( duration, new TimerStateCallback( EffectExpire_Callback ), m );
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
private static void EffectExpire_Callback( object state )
{
CheckEffect( (Mobile)state );
}
public static bool CheckEffect( Mobile m )
{
SkillMod mod = (SkillMod)m_Table[m];
if ( mod == null )
return false;
m_Table.Remove( m );
mod.Remove();
return true;
}
private class InternalTarget : Target
{
private EvilOmenSpell m_Owner;
public InternalTarget( EvilOmenSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
else
from.SendLocalizedMessage( 1060508 ); // You can't curse that.
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,216 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Engines.CannedEvil;
using Server.Guilds;
using Server.Factions;
using Server.Engines.PartySystem;
using Server.Regions;
namespace Server.Spells.Necromancy
{
public class ExorcismSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Exorcism", "Ort Corp Grav",
SpellCircle.Sixth, // 0.5 + 1.5 = 2s base cast delay
203,
9031,
Reagent.NoxCrystal,
Reagent.GraveDust
);
public override double RequiredSkill { get { return 80.0; } }
public override int RequiredMana { get { return 40; } }
public ExorcismSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if( Caster.Skills.SpiritSpeak.Value < 100.0 )
{
Caster.SendLocalizedMessage( 1072112 ); // You must have GM Spirit Speak to use this spell
return false;
}
return base.CheckCast();
}
public override bool DelayedDamage { get { return false; } }
private const int Range = 18;
public override int ComputeKarmaAward()
{
return 0; //no karma lost from this spell!
}
public override void OnCast()
{
ChampionSpawnRegion r = Caster.Region.GetRegion( typeof( ChampionSpawnRegion ) ) as ChampionSpawnRegion;
if( r == null || !Caster.InRange( r.ChampionSpawn, Range ) )
{
Caster.SendLocalizedMessage( 1072111 ); // You are not in a valid exorcism region.
}
else if( CheckSequence() )
{
/* Creates a withering frost around the Caster,
* which deals Cold Damage to all valid targets in a radius of 5 tiles.
*/
Map map = Caster.Map;
if( map != null )
{
ArrayList targets = new ArrayList();
foreach( Mobile m in r.ChampionSpawn.GetMobilesInRange( Range ) )
{
if( IsValidTarget( m ) )
targets.Add( m );
}
//Effects.PlaySound( Caster.Location, map, 0x1FB );
//Effects.PlaySound( Caster.Location, map, 0x10B );
//Effects.SendLocationParticles( EffectItem.Create( Caster.Location, map, EffectItem.DefaultDuration ), 0x37CC, 1, 40, 97, 3, 9917, 0 );
for( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
//m.FixedParticles( 0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255 );
//Suprisingly, no effects
m.Location = GetNearestShrine( m );
}
}
}
FinishSequence();
}
private bool IsValidTarget( Mobile m )
{
if( !m.Player || m.Alive )
return false;
/*
if( m.Corpse != null && m.Corpse.Map == m.Map )
return false;
* */
Corpse c = m.Corpse as Corpse;
Map map = m.Map;
if( c != null && !c.Deleted && map != null && c.Map == map )
{
if( SpellHelper.IsAnyT2A( map, c.Location ) && SpellHelper.IsAnyT2A( map, m.Location ) )
return false; //Same Map, both in T2A, ie, same 'sub server'.
if( m.Region.IsPartOf( typeof( DungeonRegion ) ) == Region.Find( c.Location, map ).IsPartOf( typeof( DungeonRegion ) ) )
return false; //Same Map, both in Dungeon region OR They're both NOT in a dungeon region.
//Just an approximation cause RunUO doens't divide up the world the same way OSI does ;p
}
Party p = Party.Get( m );
if( p != null && p.Contains( Caster ) )
return false;
if( m.Guild != null && Caster.Guild != null )
{
Guild mGuild = m.Guild as Guild;
Guild cGuild = Caster.Guild as Guild;
if( mGuild.IsAlly( cGuild ) )
return false;
if( mGuild == cGuild )
return false;
}
Faction f = Faction.Find( m );
if( Faction.Facet == m.Map && f != null && f == Faction.Find( Caster ) )
return false;
return true;
}
private static Point3D GetNearestShrine( Mobile m )
{
Map map = m.Map;
Point3D[] locList;
if( map == Map.Felucca || map == Map.Trammel )
locList = m_BritanniaLocs;
else if( map == Map.Ilshenar )
locList = m_IllshLocs;
else if( map == Map.Tokuno )
locList = m_TokunoLocs;
else if( map == Map.Malas )
locList = m_MalasLocs;
else
locList = new Point3D[0];
Point3D closest = Point3D.Zero;
double minDist = double.MaxValue;
for( int i = 0; i < locList.Length; i++ )
{
Point3D p = locList[i];
double dist = m.GetDistanceToSqrt( p );
if( minDist > dist )
{
closest = p;
minDist = dist;
}
}
return closest;
}
private static readonly Point3D[] m_BritanniaLocs = new Point3D[]
{
new Point3D( 1470, 843, 0 ),
new Point3D( 1857, 865, -1 ),
new Point3D( 4220, 563, 36 ),
new Point3D( 1732, 3528, 0 ),
new Point3D( 1300, 644, 8 ),
new Point3D( 3355, 302, 9 ),
new Point3D( 1606, 2490, 5 ),
new Point3D( 2500, 3931, 3 ),
new Point3D( 4264, 3707, 0 )
};
private static readonly Point3D[] m_IllshLocs = new Point3D[]
{
new Point3D( 1222, 474, -17 ),
new Point3D( 718, 1360, -60),
new Point3D( 297, 1014, -19 ),
new Point3D( 986, 1006, -36 ),
new Point3D( 1180, 1288, -30 ),
new Point3D( 1538, 1341, -3 ),
new Point3D( 528, 223, -38 )
};
private static readonly Point3D[] m_MalasLocs = new Point3D[]
{
new Point3D ( 976, 517, -30 )
};
private static readonly Point3D[] m_TokunoLocs = new Point3D[]
{
new Point3D( 710, 1162, 25 ),
new Point3D( 1034, 515, 18 ),
new Point3D( 295, 712, 55 )
};
}
}

View file

@ -0,0 +1,35 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class HorrificBeastSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Horrific Beast", "Rel Xen Vas Bal",
SpellCircle.Sixth, // 0.5 + 1.5 = 2s base cast delay
203,
9031,
Reagent.BatWing,
Reagent.DaemonBlood
);
public override double RequiredSkill{ get{ return 40.0; } }
public override int RequiredMana{ get{ return 11; } }
public override int Body{ get{ return 746; } }
public HorrificBeastSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void PlayEffect( Mobile m )
{
m.PlaySound( 0x165 );
m.FixedParticles( 0x3728, 1, 13, 9918, 92, 3, EffectLayer.Head );
}
}
}

View file

@ -0,0 +1,47 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class LichFormSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Lich Form", "Rel Xen Corp Ort",
SpellCircle.Sixth, // 0.5 + 1.5 = 2s base cast delay
203,
9031,
Reagent.GraveDust,
Reagent.DaemonBlood,
Reagent.NoxCrystal
);
public override double RequiredSkill{ get{ return 70.0; } }
public override int RequiredMana{ get{ return 23; } }
public override int Body{ get{ return 749; } }
public override int FireResistOffset{ get{ return -10; } }
public override int ColdResistOffset{ get{ return +10; } }
public override int PoisResistOffset{ get{ return +10; } }
public override double TickRate{ get{ return 2.5; } }
public LichFormSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void PlayEffect( Mobile m )
{
m.PlaySound( 0x19C );
m.FixedParticles( 0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot );
}
public override void OnTick( Mobile m )
{
--m.Hits;
}
}
}

View file

@ -0,0 +1,143 @@
using System;
using System.Collections;
using Server.Network;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class MindRotSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Mind Rot", "Wis An Ben",
SpellCircle.Fourth, // 0.5 + 1.0 = 1.5s base cast delay
203,
9031,
Reagent.BatWing,
Reagent.PigIron,
Reagent.DaemonBlood
);
public override double RequiredSkill{ get{ return 30.0; } }
public override int RequiredMana{ get{ return 17; } }
public MindRotSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( HasMindRotScalar( m ) )
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
/* Attempts to place a curse on the Target that increases the mana cost of any spells they cast,
* for a duration based off a comparison between the Caster's Spirit Speak skill and the Target's Resisting Spells skill.
* The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 50 ) + 20 seconds.
*/
m.PlaySound( 0x1FB );
m.PlaySound( 0x258 );
m.FixedParticles( 0x373A, 1, 17, 9903, 15, 4, EffectLayer.Head );
TimeSpan duration = TimeSpan.FromSeconds( (((GetDamageSkill( Caster ) - GetResistSkill( m )) / 5.0) + 20.0) * (m.Player ? 1.0 : 2.0 ) );
if ( m.Player )
SetMindRotScalar( Caster, m, 1.25, duration );
else
SetMindRotScalar( Caster, m, 2.00, duration );
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
public static void ClearMindRotScalar( Mobile m )
{
m_Table.Remove( m );
BuffInfo.RemoveBuff( m, BuffIcon.Mindrot );
}
public static bool HasMindRotScalar( Mobile m )
{
return m_Table.Contains( m );
}
public static bool GetMindRotScalar( Mobile m, ref double scalar )
{
object obj = m_Table[m];
if ( obj == null )
return false;
scalar = (double)obj;
return true;
}
public static void SetMindRotScalar( Mobile caster, Mobile target, double scalar, TimeSpan duration )
{
m_Table[target] = scalar;
BuffInfo.AddBuff( target, new BuffInfo( BuffIcon.Mindrot, 1075665, duration, target ) );
new ExpireTimer( caster, target, duration ).Start();
}
private class ExpireTimer : Timer
{
private Mobile m_Caster;
private Mobile m_Target;
private DateTime m_End;
public ExpireTimer( Mobile caster, Mobile target, TimeSpan delay ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) )
{
m_Caster = caster;
m_Target = target;
m_End = DateTime.Now + delay;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
if ( m_Target.Deleted || !m_Target.Alive || DateTime.Now >= m_End )
{
m_Target.SendLocalizedMessage( 1060872 ); // Your mind feels normal again.
ClearMindRotScalar( m_Target );
Stop();
}
}
}
private class InternalTarget : Target
{
private MindRotSpell m_Owner;
public InternalTarget( MindRotSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
else
from.SendLocalizedMessage( 1060508 ); // You can't curse that.
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using Server;
namespace Server.Spells.Necromancy
{
public abstract class NecromancerSpell : Spell
{
public abstract double RequiredSkill{ get; }
public abstract int RequiredMana{ get; }
public override SkillName CastSkill{ get{ return SkillName.Necromancy; } }
public override SkillName DamageSkill{ get{ return SkillName.SpiritSpeak; } }
public override bool ClearHandsOnCast{ get{ return false; } }
public override int CastDelayFastScalar{ get{ return 0; } } // Necromancer spells are not effected by fast cast items, though they are by fast cast recovery
public NecromancerSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info )
{
}
public override int ComputeKarmaAward()
{
return -(70 + (10 * (int)Circle));
}
public override void GetCastSkills( out double min, out double max )
{
min = RequiredSkill;
max = RequiredSkill + 40.0;
}
public override int GetMana()
{
return RequiredMana;
}
}
}

View file

@ -0,0 +1,138 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class PainSpikeSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Pain Spike", "In Sar",
SpellCircle.Second, // 0.5 + 0.5 = 1s base cast delay
203,
9031,
Reagent.GraveDust,
Reagent.PigIron
);
public override double RequiredSkill{ get{ return 20.0; } }
public override int RequiredMana{ get{ return 5; } }
public PainSpikeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override bool DelayedDamage{ get{ return false; } }
public void Target( Mobile m )
{
if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m );
/* Temporarily causes intense physical pain to the target, dealing direct damage.
* After 10 seconds the spell wears off, and if the target is still alive,
* some of the Hit Points lost through Pain Spike are restored.
*/
m.FixedParticles( 0x37C4, 1, 8, 9916, 39, 3, EffectLayer.Head );
m.FixedParticles( 0x37C4, 1, 8, 9502, 39, 4, EffectLayer.Head );
m.PlaySound( 0x210 );
double damage = ((GetDamageSkill( Caster ) - GetResistSkill( m )) / 10) + (m.Player ? 18 : 30);
if ( damage < 1 )
damage = 1;
TimeSpan buffTime = TimeSpan.FromSeconds( 10.0 );
if( m_Table.Contains( m ) )
{
damage = Utility.RandomMinMax( 3, 7 );
Timer t = m_Table[m] as Timer;
if( t != null )
{
t.Delay += TimeSpan.FromSeconds( 2.0 );
buffTime = t.Next - DateTime.Now;
}
}
else
{
new InternalTimer( m, damage ).Start();
}
BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.PainSpike, 1075667, buffTime, m, (int)damage ) );
Misc.WeightOverloading.DFA = Misc.DFAlgorithm.PainSpike;
m.Damage( (int) damage, Caster );
Misc.WeightOverloading.DFA = Misc.DFAlgorithm.Standard;
//SpellHelper.Damage( this, m, damage, 100, 0, 0, 0, 0, Misc.DFAlgorithm.PainSpike );
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
private class InternalTimer : Timer
{
private Mobile m_Mobile;
private int m_ToRestore;
public InternalTimer( Mobile m, double toRestore ) : base( TimeSpan.FromSeconds( 10.0 ) )
{
Priority = TimerPriority.OneSecond;
m_Mobile = m;
m_ToRestore = (int)toRestore;
m_Table[m] = this;
}
protected override void OnTick()
{
m_Table.Remove( m_Mobile );
if ( m_Mobile.Alive && !m_Mobile.IsDeadBondedPet )
m_Mobile.Hits += m_ToRestore;
BuffInfo.RemoveBuff( m_Mobile, BuffIcon.PainSpike );
}
}
private class InternalTarget : Target
{
private PainSpikeSpell m_Owner;
public InternalTarget( PainSpikeSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,106 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class PoisonStrikeSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Poison Strike", "In Vas Nox",
SpellCircle.Fourth, // 0.5 + 1.0 = 1.5s base cast delay
203,
9031,
Reagent.NoxCrystal
);
public override double RequiredSkill{ get{ return 50.0; } }
public override int RequiredMana{ get{ return 17; } }
public PoisonStrikeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override bool DelayedDamage{ get{ return false; } }
public void Target( Mobile m )
{
if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
/* Creates a blast of poisonous energy centered on the target.
* The main target is inflicted with a large amount of Poison damage, and all valid targets in a radius of 2 tiles around the main target are inflicted with a lesser effect.
* One tile from main target receives 50% damage, two tiles from target receives 33% damage.
*/
CheckResisted( m ); // Check magic resist for skill, but do not use return value
Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x36B0, 1, 14, 63, 7, 9915, 0 );
Effects.PlaySound( m.Location, m.Map, 0x229 );
double damage = Utility.RandomMinMax( 36, 40 ) * ((300 + (GetDamageSkill( Caster ) * 9)) / 1000);
Map map = m.Map;
if ( map != null )
{
ArrayList targets = new ArrayList();
foreach ( Mobile targ in m.GetMobilesInRange( 2 ) )
{
if ( (Caster == targ || SpellHelper.ValidIndirectTarget( Caster, targ )) && Caster.CanBeHarmful( targ, false ) )
targets.Add( targ );
}
for ( int i = 0; i < targets.Count; ++i )
{
Mobile targ = (Mobile)targets[i];
int num;
if ( targ.InRange( m.Location, 0 ) )
num = 1;
else if ( targ.InRange( m.Location, 1 ) )
num = 2;
else
num = 3;
Caster.DoHarmful( targ );
SpellHelper.Damage( this, targ, damage / num, 0, 0, 0, 100, 0 );
}
}
}
FinishSequence();
}
private class InternalTarget : Target
{
private PoisonStrikeSpell m_Owner;
public InternalTarget( PoisonStrikeSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,195 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class StrangleSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Strangle", "In Bal Nox",
SpellCircle.Sixth, // 0.5 + 1.5 = 2s base cast delay
209,
9031,
Reagent.DaemonBlood,
Reagent.NoxCrystal
);
public override double RequiredSkill{ get{ return 65.0; } }
public override int RequiredMana{ get{ return 29; } }
public StrangleSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m );
/* Temporarily chokes off the air suply of the target with poisonous fumes.
* The target is inflicted with poison damage over time.
* The amount of damage dealt each "hit" is based off of the caster's Spirit Speak skill and the Target's current Stamina.
* The less Stamina the target has, the more damage is done by Strangle.
* Duration of the effect is Spirit Speak skill level / 10 rounds, with a minimum number of 4 rounds.
* The first round of damage is dealt after 5 seconds, and every next round after that comes 1 second sooner than the one before, until there is only 1 second between rounds.
* The base damage of the effect lies between (Spirit Speak skill level / 10) - 2 and (Spirit Speak skill level / 10) + 1.
* Base damage is multiplied by the following formula: (3 - (target's current Stamina / target's maximum Stamina) * 2).
* Example:
* For a target at full Stamina the damage multiplier is 1,
* for a target at 50% Stamina the damage multiplier is 2 and
* for a target at 20% Stamina the damage multiplier is 2.6
*/
m.PlaySound( 0x22F );
m.FixedParticles( 0x36CB, 1, 9, 9911, 67, 5, EffectLayer.Head );
m.FixedParticles( 0x374A, 1, 17, 9502, 1108, 4, (EffectLayer)255 );
if ( !m_Table.Contains( m ) )
{
Timer t = new InternalTimer( m, Caster );
t.Start();
m_Table[m] = t;
}
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
public static bool RemoveCurse( Mobile m )
{
Timer t = (Timer)m_Table[m];
if ( t == null )
return false;
t.Stop();
m.SendLocalizedMessage( 1061687 ); // You can breath normally again.
m_Table.Remove( m );
return true;
}
private class InternalTimer : Timer
{
private Mobile m_Target, m_From;
private double m_MinBaseDamage, m_MaxBaseDamage;
private DateTime m_NextHit;
private int m_HitDelay;
private int m_Count, m_MaxCount;
public InternalTimer( Mobile target, Mobile from ) : base( TimeSpan.FromSeconds( 0.1 ), TimeSpan.FromSeconds( 0.1 ) )
{
Priority = TimerPriority.FiftyMS;
m_Target = target;
m_From = from;
double spiritLevel = from.Skills[SkillName.SpiritSpeak].Value / 10;
m_MinBaseDamage = spiritLevel - 2;
m_MaxBaseDamage = spiritLevel + 1;
m_HitDelay = 5;
m_NextHit = DateTime.Now + TimeSpan.FromSeconds( m_HitDelay );
m_Count = (int)spiritLevel;
if ( m_Count < 4 )
m_Count = 4;
m_MaxCount = m_Count;
}
protected override void OnTick()
{
if ( !m_Target.Alive )
{
m_Table.Remove( m_Target );
Stop();
}
if ( !m_Target.Alive || DateTime.Now < m_NextHit )
return;
--m_Count;
if ( m_HitDelay > 1 )
{
if ( m_MaxCount < 5 )
{
--m_HitDelay;
}
else
{
int delay = (int)(Math.Ceiling( (1.0 + (5 * m_Count)) / m_MaxCount ) );
if ( delay <= 5 )
m_HitDelay = delay;
else
m_HitDelay = 5;
}
}
if ( m_Count == 0 )
{
m_Target.SendLocalizedMessage( 1061687 ); // You can breath normally again.
m_Table.Remove( m_Target );
Stop();
}
else
{
m_NextHit = DateTime.Now + TimeSpan.FromSeconds( m_HitDelay );
double damage = m_MinBaseDamage + (Utility.RandomDouble() * (m_MaxBaseDamage - m_MinBaseDamage));
damage *= (3 - (((double)m_Target.Stam / m_Target.StamMax) * 2));
if ( damage < 1 )
damage = 1;
if ( !m_Target.Player )
damage *= 1.75;
AOS.Damage( m_Target, m_From, (int)damage, 0, 0, 0, 100, 0 );
}
}
}
private class InternalTarget : Target
{
private StrangleSpell m_Owner;
public InternalTarget( StrangleSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,204 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
using Server.Gumps;
using Server.Mobiles;
namespace Server.Spells.Necromancy
{
public class SummonFamiliarSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Summon Familiar", "Kal Xen Bal",
SpellCircle.Sixth, // 0.5 + 1.5 = 2s base cast delay
203,
9031,
Reagent.BatWing,
Reagent.GraveDust,
Reagent.DaemonBlood
);
public override double RequiredSkill{ get{ return 30.0; } }
public override int RequiredMana{ get{ return 17; } }
public SummonFamiliarSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
private static Hashtable m_Table = new Hashtable();
public static Hashtable Table{ get{ return m_Table; } }
public override bool CheckCast()
{
BaseCreature check = (BaseCreature)m_Table[Caster];
if ( check != null && !check.Deleted )
{
Caster.SendLocalizedMessage( 1061605 ); // You already have a familiar.
return false;
}
return base.CheckCast();
}
public override void OnCast()
{
if ( CheckSequence() )
{
Caster.CloseGump( typeof( SummonFamiliarGump ) );
Caster.SendGump( new SummonFamiliarGump( Caster, m_Entries, this ) );
}
FinishSequence();
}
private static SummonFamiliarEntry[] m_Entries = new SummonFamiliarEntry[]
{
new SummonFamiliarEntry( typeof( HordeMinionFamiliar ), 1060146, 30.0, 30.0 ), // Horde Minion
new SummonFamiliarEntry( typeof( ShadowWispFamiliar ), 1060142, 50.0, 50.0 ), // Shadow Wisp
new SummonFamiliarEntry( typeof( DarkWolfFamiliar ), 1060143, 60.0, 60.0 ), // Dark Wolf
new SummonFamiliarEntry( typeof( DeathAdder ), 1060145, 80.0, 80.0 ), // Death Adder
new SummonFamiliarEntry( typeof( VampireBatFamiliar ), 1060144, 100.0, 100.0 ) // Vampire Bat
};
public static SummonFamiliarEntry[] Entries{ get{ return m_Entries; } }
}
public class SummonFamiliarEntry
{
private Type m_Type;
private object m_Name;
private double m_ReqNecromancy;
private double m_ReqSpiritSpeak;
public Type Type{ get{ return m_Type; } }
public object Name{ get{ return m_Name; } }
public double ReqNecromancy{ get{ return m_ReqNecromancy; } }
public double ReqSpiritSpeak{ get{ return m_ReqSpiritSpeak; } }
public SummonFamiliarEntry( Type type, object name, double reqNecromancy, double reqSpiritSpeak )
{
m_Type = type;
m_Name = name;
m_ReqNecromancy = reqNecromancy;
m_ReqSpiritSpeak = reqSpiritSpeak;
}
}
public class SummonFamiliarGump : Gump
{
private Mobile m_From;
private SummonFamiliarEntry[] m_Entries;
private SummonFamiliarSpell m_Spell;
private const int EnabledColor16 = 0x0F20;
private const int DisabledColor16 = 0x262A;
private const int EnabledColor32 = 0x18CD00;
private const int DisabledColor32 = 0x4A8B52;
public SummonFamiliarGump( Mobile from, SummonFamiliarEntry[] entries, SummonFamiliarSpell spell ) : base( 200, 100 )
{
m_From = from;
m_Entries = entries;
m_Spell = spell;
AddPage( 0 );
AddBackground( 10, 10, 250, 178, 9270 );
AddAlphaRegion( 20, 20, 230, 158 );
AddImage( 220, 20, 10464 );
AddImage( 220, 72, 10464 );
AddImage( 220, 124, 10464 );
AddItem( 188, 16, 6883 );
AddItem( 198, 168, 6881 );
AddItem( 8, 15, 6882 );
AddItem( 2, 168, 6880 );
AddHtmlLocalized( 30, 26, 200, 20, 1060147, EnabledColor16, false, false ); // Chose thy familiar...
double necro = from.Skills[SkillName.Necromancy].Base;
double spirit = from.Skills[SkillName.SpiritSpeak].Base;
for ( int i = 0; i < entries.Length; ++i )
{
object name = entries[i].Name;
bool enabled = ( necro >= entries[i].ReqNecromancy && spirit >= entries[i].ReqSpiritSpeak );
AddButton( 27, 53 + (i * 21), 9702, 9703, i + 1, GumpButtonType.Reply, 0 );
if ( name is int )
AddHtmlLocalized( 50, 51 + (i * 21), 150, 20, (int)name, enabled ? EnabledColor16 : DisabledColor16, false, false );
else if ( name is string )
AddHtml( 50, 51 + (i * 21), 150, 20, String.Format( "<BASEFONT COLOR=#{0:X6}>{1}</BASEFONT>", enabled ? EnabledColor32 : DisabledColor32, name ), false, false );
}
}
private static Hashtable m_Table = new Hashtable();
public override void OnResponse( NetState sender, RelayInfo info )
{
int index = info.ButtonID - 1;
if ( index >= 0 && index < m_Entries.Length )
{
SummonFamiliarEntry entry = m_Entries[index];
double necro = m_From.Skills[SkillName.Necromancy].Base;
double spirit = m_From.Skills[SkillName.SpiritSpeak].Base;
BaseCreature check = (BaseCreature)SummonFamiliarSpell.Table[m_From];
if ( check != null && !check.Deleted )
{
m_From.SendLocalizedMessage( 1061605 ); // You already have a familiar.
}
else if ( necro < entry.ReqNecromancy || spirit < entry.ReqSpiritSpeak )
{
// That familiar requires ~1_NECROMANCY~ Necromancy and ~2_SPIRIT~ Spirit Speak.
m_From.SendLocalizedMessage( 1061606, String.Format( "{0:F1}\t{1:F1}", entry.ReqNecromancy, entry.ReqSpiritSpeak ) );
m_From.CloseGump( typeof( SummonFamiliarGump ) );
m_From.SendGump( new SummonFamiliarGump( m_From, SummonFamiliarSpell.Entries, m_Spell ) );
}
else if ( entry.Type == null )
{
m_From.SendMessage( "That familiar has not yet been defined." );
m_From.CloseGump( typeof( SummonFamiliarGump ) );
m_From.SendGump( new SummonFamiliarGump( m_From, SummonFamiliarSpell.Entries, m_Spell ) );
}
else
{
try
{
BaseCreature bc = (BaseCreature)Activator.CreateInstance( entry.Type );
bc.Skills.MagicResist = m_From.Skills.MagicResist;
if ( BaseCreature.Summon( bc, m_From, m_From.Location, -1, TimeSpan.FromDays( 1.0 ) ) )
{
m_From.FixedParticles( 0x3728, 1, 10, 9910, EffectLayer.Head );
bc.PlaySound( bc.GetIdleSound() );
SummonFamiliarSpell.Table[m_From] = bc;
}
}
catch
{
}
}
}
else
{
m_From.SendLocalizedMessage( 1061825 ); // You decide not to summon a familiar.
}
}
}
}

View file

@ -0,0 +1,254 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
using Server.Spells.Fifth;
using Server.Spells.Seventh;
namespace Server.Spells.Necromancy
{
public abstract class TransformationSpell : NecromancerSpell
{
public abstract int Body{ get; }
public virtual int Hue{ get{ return 0; } }
public virtual int PhysResistOffset{ get{ return 0; } }
public virtual int FireResistOffset{ get{ return 0; } }
public virtual int ColdResistOffset{ get{ return 0; } }
public virtual int PoisResistOffset{ get{ return 0; } }
public virtual int NrgyResistOffset{ get{ return 0; } }
public TransformationSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info )
{
}
public override bool BlockedByHorrificBeast{ get{ return false; } }
public override bool CheckCast()
{
/*if ( Caster.Mounted )
{
Caster.SendLocalizedMessage( 1042561 ); // Please dismount first.
return false;
}
else */
if ( Factions.Sigil.ExistsOn( Caster ) )
{
Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
return false;
}
else if ( !Caster.CanBeginAction( typeof( PolymorphSpell ) ) )
{
Caster.SendLocalizedMessage( 1061628 ); // You can't do that while polymorphed.
return false;
}
else if ( Spells.Ninjitsu.AnimalForm.UnderTransformation( Caster ) )
{
Caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form.
return false;
}
return base.CheckCast();
}
public override void OnCast()
{
Mobile caster = this.Caster;
/*if ( caster.Mounted )
{
caster.SendLocalizedMessage( 1042561 ); // Please dismount first.
}
else */
if ( Factions.Sigil.ExistsOn( Caster ) )
{
Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
}
else if ( !caster.CanBeginAction( typeof( PolymorphSpell ) ) )
{
Caster.SendLocalizedMessage( 1061628 ); // You can't do that while polymorphed.
}
else if ( Spells.Ninjitsu.AnimalForm.UnderTransformation( Caster ) )
{
Caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form.
}
else if ( !caster.CanBeginAction( typeof( IncognitoSpell ) ) || (caster.IsBodyMod && GetContext( caster ) == null) )
{
DoFizzle();
}
else if ( CheckSequence() )
{
TransformContext context = GetContext( caster );
Type ourType = this.GetType();
bool wasTransformed = ( context != null );
bool ourTransform = ( wasTransformed && context.Type == ourType );
if ( wasTransformed )
{
RemoveContext( caster, context, ourTransform );
if ( ourTransform )
{
caster.PlaySound( 0xFA );
caster.FixedParticles( 0x3728, 1, 13, 5042, EffectLayer.Waist );
}
}
if ( !ourTransform )
{
List<ResistanceMod> mods = new List<ResistanceMod>();
if ( PhysResistOffset != 0 )
mods.Add( new ResistanceMod( ResistanceType.Physical, PhysResistOffset ) );
if ( FireResistOffset != 0 )
mods.Add( new ResistanceMod( ResistanceType.Fire, FireResistOffset ) );
if ( ColdResistOffset != 0 )
mods.Add( new ResistanceMod( ResistanceType.Cold, ColdResistOffset ) );
if ( PoisResistOffset != 0 )
mods.Add( new ResistanceMod( ResistanceType.Poison, PoisResistOffset ) );
if ( NrgyResistOffset != 0 )
mods.Add( new ResistanceMod( ResistanceType.Energy, NrgyResistOffset ) );
if ( !((Body)this.Body).IsHuman )
{
Mobiles.IMount mt = Caster.Mount;
if ( mt != null )
mt.Rider = null;
}
caster.BodyMod = this.Body;
caster.HueMod = this.Hue;
for ( int i = 0; i < mods.Count; ++i )
caster.AddResistanceMod( mods[i] );
PlayEffect( caster );
Timer timer = new TransformTimer( caster, this );
timer.Start();
AddContext( caster, new TransformContext( timer, mods, ourType ) );
}
}
FinishSequence();
}
public virtual double TickRate{ get{ return 1.0; } }
public virtual void OnTick( Mobile m )
{
}
public virtual void PlayEffect( Mobile m )
{
}
private static Hashtable m_Table = new Hashtable();
public static void AddContext( Mobile m, TransformContext context )
{
m_Table[m] = context;
if ( context.Type == typeof( HorrificBeastSpell ) )
m.Delta( MobileDelta.WeaponDamage );
}
public static void RemoveContext( Mobile m, bool resetGraphics )
{
TransformContext context = GetContext( m );
if ( context != null )
RemoveContext( m, context, resetGraphics );
}
public static void RemoveContext( Mobile m, TransformContext context, bool resetGraphics )
{
m_Table.Remove( m );
List<ResistanceMod> mods = context.Mods;
for ( int i = 0; i < mods.Count; ++i )
m.RemoveResistanceMod( mods[i] );
if ( resetGraphics )
{
m.HueMod = -1;
m.BodyMod = 0;
}
context.Timer.Stop();
if ( context.Type == typeof( HorrificBeastSpell ) )
m.Delta( MobileDelta.WeaponDamage );
}
public static TransformContext GetContext( Mobile m )
{
return ( m_Table[m] as TransformContext );
}
public static bool UnderTransformation( Mobile m )
{
return ( GetContext( m ) != null );
}
public static bool UnderTransformation( Mobile m, Type type )
{
TransformContext context = GetContext( m );
return ( context != null && context.Type == type );
}
}
public class TransformContext
{
private Timer m_Timer;
private List<ResistanceMod> m_Mods;
private Type m_Type;
public Timer Timer{ get{ return m_Timer; } }
public List<ResistanceMod> Mods{ get{ return m_Mods; } }
public Type Type{ get{ return m_Type; } }
public TransformContext( Timer timer, List<ResistanceMod> mods, Type type )
{
m_Timer = timer;
m_Mods = mods;
m_Type = type;
}
}
public class TransformTimer : Timer
{
private Mobile m_Mobile;
private TransformationSpell m_Spell;
public TransformTimer( Mobile from, TransformationSpell spell ) : base( TimeSpan.FromSeconds( spell.TickRate ), TimeSpan.FromSeconds( spell.TickRate ) )
{
m_Mobile = from;
m_Spell = spell;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
if ( m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Body != m_Spell.Body || m_Mobile.Hue != m_Spell.Hue )
{
TransformationSpell.RemoveContext( m_Mobile, true );
Stop();
}
else
{
m_Spell.OnTick( m_Mobile );
}
}
}
}

View file

@ -0,0 +1,53 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class VampiricEmbraceSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Vampiric Embrace", "Rel Xen An Sanct",
SpellCircle.Sixth, // 0.5 + 1.5 = 2s base cast delay
203,
9031,
Reagent.BatWing,
Reagent.NoxCrystal,
Reagent.PigIron
);
public override double RequiredSkill{ get{ return 99.0; } }
public override int RequiredMana{ get{ return 23; } }
public override int Body{ get{ return Caster.Female ? 745 : 744; } }
public override int Hue{ get{ return 0x847E; } }
public override int FireResistOffset{ get{ return -25; } }
public VampiricEmbraceSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void GetCastSkills( out double min, out double max )
{
if ( Caster.Skills[CastSkill].Value >= RequiredSkill )
{
min = 80.0;
max = 120.0;
}
else
{
base.GetCastSkills( out min, out max );
}
}
public override void PlayEffect( Mobile m )
{
Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x373A, 1, 17, 1108, 7, 9914, 0 );
Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x376A, 1, 22, 67, 7, 9502, 0 );
Effects.PlaySound( m.Location, m.Map, 0x4B1 );
}
}
}

View file

@ -0,0 +1,96 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
using Server.Mobiles;
namespace Server.Spells.Necromancy
{
public class VengefulSpiritSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Vengeful Spirit", "Kal Xen Bal Beh",
SpellCircle.Sixth, // 0.5 + 1.5 = 2s base cast delay
203,
9031,
Reagent.BatWing,
Reagent.GraveDust,
Reagent.PigIron
);
public override double RequiredSkill{ get{ return 80.0; } }
public override int RequiredMana{ get{ return 41; } }
public VengefulSpiritSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( (Caster.Followers + 3) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
}
return true;
}
public void Target( Mobile m )
{
if ( Caster == m )
{
Caster.SendLocalizedMessage( 1061832 ); // You cannot exact vengeance on yourself.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
/* Summons a Revenant which haunts the target until either the target or the Revenant is dead.
* Revenants have the ability to track down their targets wherever they may travel.
* A Revenant's strength is determined by the Necromancy and Spirit Speak skills of the Caster.
* The effect lasts for ((Spirit Speak skill level * 80) / 120) + 10 seconds.
*/
TimeSpan duration = TimeSpan.FromSeconds( ((GetDamageSkill( Caster ) * 80) / 120) + 10 );
Revenant rev = new Revenant( Caster, m, duration );
if ( BaseCreature.Summon( rev, false, Caster, m.Location, 0x81, TimeSpan.FromSeconds( duration.TotalSeconds + 2.0 ) ) )
rev.FixedParticles( 0x373A, 1, 15, 9909, EffectLayer.Waist );
}
FinishSequence();
}
private class InternalTarget : Target
{
private VengefulSpiritSpell m_Owner;
public InternalTarget( VengefulSpiritSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,78 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class WitherSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Wither", "Kal Vas An Flam",
SpellCircle.Third, // 0.5 + 0.75 = 1.25s base cast delay
203,
9031,
Reagent.NoxCrystal,
Reagent.GraveDust,
Reagent.PigIron
);
public override double RequiredSkill{ get{ return 60.0; } }
public override int RequiredMana{ get{ return 23; } }
public WitherSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool DelayedDamage{ get{ return false; } }
public override void OnCast()
{
if ( CheckSequence() )
{
/* Creates a withering frost around the Caster,
* which deals Cold Damage to all valid targets in a radius of 5 tiles.
*/
Map map = Caster.Map;
if ( map != null )
{
ArrayList targets = new ArrayList();
foreach ( Mobile m in Caster.GetMobilesInRange( 5 ) )
{
if ( Caster != m && Caster.InLOS( m ) && SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) )
targets.Add( m );
}
Effects.PlaySound( Caster.Location, map, 0x1FB );
Effects.PlaySound( Caster.Location, map, 0x10B );
Effects.SendLocationParticles( EffectItem.Create( Caster.Location, map, EffectItem.DefaultDuration ), 0x37CC, 1, 40, 97, 3, 9917, 0 );
for ( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
Caster.DoHarmful( m );
m.FixedParticles( 0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255 );
double damage = Utility.RandomMinMax( 30, 35 );
damage *= (300 + (m.Karma / 100) + (GetDamageSkill( Caster ) * 10));
damage /= 1000;
// TODO: cap?
//if ( damage > 40 )
// damage = 40;
SpellHelper.Damage( this, m, damage, 0, 0, 100, 0, 0 );
}
}
}
FinishSequence();
}
}
}

View file

@ -0,0 +1,42 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class WraithFormSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Wraith Form", "Rel Xen Um",
SpellCircle.Sixth, // 0.5 + 1.5 = 2s base cast delay
203,
9031,
Reagent.NoxCrystal,
Reagent.PigIron
);
public override double RequiredSkill{ get{ return 20.0; } }
public override int RequiredMana{ get{ return 17; } }
public override int Body{ get{ return Caster.Female ? 747 : 748; } }
public override int Hue{ get{ return Caster.Female ? 0 : 0x4001; } }
public override int PhysResistOffset{ get{ return +10; } }
public override int FireResistOffset{ get{ return -25; } }
public override int ColdResistOffset{ get{ return -05; } }
public override int PoisResistOffset{ get{ return -05; } }
public override int NrgyResistOffset{ get{ return -05; } }
public WraithFormSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void PlayEffect( Mobile m )
{
m.PlaySound( 0x17F );
m.FixedParticles( 0x374A, 1, 15, 9902, 1108, 4, EffectLayer.Waist );
}
}
}

View file

@ -0,0 +1,433 @@
using System;
using System.Collections;
using Server;
using Server.Gumps;
using Server.Network;
using Server.Mobiles;
using Server.Spells.Fifth;
using Server.Spells.Seventh;
namespace Server.Spells.Ninjitsu
{
public class AnimalForm : NinjaSpell
{
public static void Initialize()
{
EventSink.Login += new LoginEventHandler( OnLogin );
}
public static void OnLogin( LoginEventArgs e )
{
AnimalFormContext context = AnimalForm.GetContext( e.Mobile );
if( context != null && context.SpeedBoost )
e.Mobile.Send( SpeedBoost.Enabled );
}
private static SpellInfo m_Info = new SpellInfo(
"Animal Form", null,
SpellCircle.Fourth, // 1.0s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 0.0; } }
public override int RequiredMana{ get{ return (Core.ML ? 10 : 0); } }
public override int CastRecoveryBase{ get { return (Core.ML ? 10 : base.CastRecoveryBase); } }
public override bool BlockedByAnimalForm{ get{ return false; } }
public AnimalForm( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( !Caster.CanBeginAction( typeof( PolymorphSpell ) ) )
{
Caster.SendLocalizedMessage( 1061628 ); // You can't do that while polymorphed.
return false;
}
else if ( Necromancy.TransformationSpell.UnderTransformation( Caster ) )
{
Caster.SendLocalizedMessage( 1063219 ); // You cannot mimic an animal while in that form.
return false;
}
return base.CheckCast();
}
public override bool CheckDisturb( DisturbType type, bool firstCircle, bool resistable )
{
return false;
}
public override void OnBeginCast()
{
base.OnBeginCast();
Caster.FixedEffect( 0x37C4, 10, 14, 4, 3 );
}
public override bool CheckFizzle()
{
// Spell is initially always successful, and with no skill gain.
return true;
}
public override void OnCast()
{
if ( !Caster.CanBeginAction( typeof( PolymorphSpell ) ) )
{
Caster.SendLocalizedMessage( 1061628 ); // You can't do that while polymorphed.
}
else if ( Necromancy.TransformationSpell.UnderTransformation( Caster ) )
{
Caster.SendLocalizedMessage( 1063219 ); // You cannot mimic an animal while in that form.
}
else if ( !Caster.CanBeginAction( typeof( IncognitoSpell ) ) || (Caster.IsBodyMod && GetContext( Caster ) == null) )
{
DoFizzle();
}
else if ( CheckSequence() )
{
AnimalFormContext context = GetContext( Caster );
if ( context != null )
{
RemoveContext( Caster, context, true );
}
else if ( Caster is PlayerMobile )
{
if ( GetLastAnimalForm( Caster ) == -1 || DateTime.Now - Caster.LastMoveTime > Caster.ComputeMovementSpeed( Caster.Direction ) )
{
Caster.CloseGump( typeof( AnimalFormGump ) );
Caster.SendGump( new AnimalFormGump( Caster, m_Entries, this ) );
}
else
{
if ( Morph( Caster, GetLastAnimalForm( Caster ) ) == MorphResult.Fail )
DoFizzle();
}
}
else
{
if ( Morph( Caster, GetLastAnimalForm( Caster ) ) == MorphResult.Fail )
DoFizzle();
}
}
FinishSequence();
}
private static Hashtable m_LastAnimalForms = new Hashtable();
public int GetLastAnimalForm( Mobile m )
{
if ( m_LastAnimalForms.Contains( m ) )
return (int)m_LastAnimalForms[m];
return -1;
}
public enum MorphResult
{
Success,
Fail,
NoSkill
}
public static MorphResult Morph( Mobile m, int entryID )
{
if ( entryID < 0 || entryID >= m_Entries.Length )
return MorphResult.Fail;
AnimalFormEntry entry = m_Entries[entryID];
m_LastAnimalForms[m] = entryID; //On OSI, it's the last /attempted/ one not the last succeeded one
if ( m.Skills.Ninjitsu.Value < entry.ReqSkill )
{
string args = String.Format( "{0}\t{1}\t ", entry.ReqSkill.ToString( "F1" ), SkillName.Ninjitsu );
m.SendLocalizedMessage( 1063013, args ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
return MorphResult.NoSkill;
}
double ninjitsu = m.Skills.Ninjitsu.Value;
if ( ninjitsu < entry.ReqSkill + 37.5 )
{
double chance = (ninjitsu - entry.ReqSkill) / 37.5;
if ( chance < Utility.RandomDouble() )
return MorphResult.Fail;
}
m.CheckSkill( SkillName.Ninjitsu, 0.0, 37.5 );
BaseMount.Dismount( m );
m.BodyMod = entry.BodyMod;
if ( entry.HueMod > 0 )
m.HueMod = entry.HueMod;
if ( entry.SpeedBoost )
m.Send( SpeedBoost.Instantiate( true ) );
SkillMod mod = null;
if ( entry.StealthBonus )
{
mod = new DefaultSkillMod( SkillName.Stealth, true, 20.0 );
mod.ObeyCap = true;
m.AddSkillMod( mod );
}
Timer timer = new AnimalFormTimer( m, entry.BodyMod, entry.HueMod );
timer.Start();
AddContext( m, new AnimalFormContext( timer, mod, entry.SpeedBoost, entry.Type ) );
return MorphResult.Success;
}
private static Hashtable m_Table = new Hashtable();
public static void AddContext( Mobile m, AnimalFormContext context )
{
m_Table[m] = context;
if ( context.Type == typeof( BakeKitsune ) || context.Type == typeof( GreyWolf ) )
m.Hits += 20;
}
public static void RemoveContext( Mobile m, bool resetGraphics )
{
AnimalFormContext context = GetContext( m );
if ( context != null )
RemoveContext( m, context, resetGraphics );
}
public static void RemoveContext( Mobile m, AnimalFormContext context, bool resetGraphics )
{
m_Table.Remove( m );
if ( context.SpeedBoost )
m.Send( SpeedBoost.Instantiate( false ) );
SkillMod mod = context.Mod;
if ( mod != null )
m.RemoveSkillMod( mod );
if ( resetGraphics )
{
m.HueMod = -1;
m.BodyMod = 0;
}
context.Timer.Stop();
}
public static AnimalFormContext GetContext( Mobile m )
{
return ( m_Table[m] as AnimalFormContext );
}
public static bool UnderTransformation( Mobile m )
{
return ( GetContext( m ) != null );
}
public static bool UnderTransformation( Mobile m, Type type )
{
AnimalFormContext context = GetContext( m );
return ( context != null && context.Type == type );
}
/*
private delegate void AnimalFormCallback( Mobile from );
private delegate bool AnimalFormRequirementCallback( Mobile from );
* */
public class AnimalFormEntry
{
private Type m_Type;
private TextDefinition m_Name;
private int m_ItemID;
private int m_Hue;
private int m_Tooltip;
private double m_ReqSkill;
private int m_BodyMod;
private int m_HueMod;
private bool m_StealthBonus;
private bool m_SpeedBoost;
public Type Type{ get{ return m_Type; } }
public TextDefinition Name{ get{ return m_Name; } }
public int ItemID{ get{ return m_ItemID; } }
public int Hue{ get{ return m_Hue; } }
public int Tooltip{ get{ return m_Tooltip; } }
public double ReqSkill{ get{ return m_ReqSkill; } }
public int BodyMod{ get{ return m_BodyMod; } }
public int HueMod{ get{ return m_HueMod; } }
public bool StealthBonus{ get{ return m_StealthBonus; } }
public bool SpeedBoost{ get{ return m_SpeedBoost; } }
/*
private AnimalFormCallback m_TransformCallback;
private AnimalFormCallback m_UntransformCallback;
private AnimalFormRequirementCallback m_RequirementCallback;
* */
public AnimalFormEntry( Type type, TextDefinition name, int itemID, int hue, int tooltip, double reqSkill, int bodyMod, bool stealthBonus, bool speedBoost )
: this( type, name, itemID, hue, tooltip, reqSkill, bodyMod, 0, stealthBonus, speedBoost )
{
}
public AnimalFormEntry( Type type, TextDefinition name, int itemID, int hue, int tooltip, double reqSkill, int bodyMod, int hueMod, bool stealthBonus, bool speedBoost )
{
m_Type = type;
m_Name = name;
m_ItemID = itemID;
m_Hue = hue;
m_Tooltip = tooltip;
m_ReqSkill = reqSkill;
m_BodyMod = bodyMod;
m_HueMod = hueMod;
m_StealthBonus = stealthBonus;
m_SpeedBoost = speedBoost;
}
}
private static AnimalFormEntry[] m_Entries = new AnimalFormEntry[]
{
new AnimalFormEntry( typeof( Kirin ), 1029632, 9632, 0, 1070811, 100.0, 0x84, false, true ),
new AnimalFormEntry( typeof( Unicorn ), 1018214, 9678, 0, 1070812, 100.0, 0x7A, false, true ),
new AnimalFormEntry( typeof( BakeKitsune ), 1030083, 10083, 0, 1070810, 82.5, 0xF6, false, true ),
new AnimalFormEntry( typeof( GreyWolf ), 1028482, 9681, 2309, 1070810, 82.5, 0x19, false, true ),
new AnimalFormEntry( typeof( Llama ), 1028438, 8438, 0, 1070809, 70.0, 0xDC, false, true ),
new AnimalFormEntry( typeof( ForestOstard ), 1018273, 8503, 2212, 1070809, 70.0, 0xDA, false, true ),
new AnimalFormEntry( typeof( BullFrog ), 1028496, 8496, 2003, 1070807, 50.0, 0x51, 0x5A3, false, false ),
new AnimalFormEntry( typeof( GiantSerpent ), 1018114, 9663, 2009, 1070808, 50.0, 0x15, false, false ),
new AnimalFormEntry( typeof( Dog ), 1018280, 8476, 2309, 1070806, 40.0, 0xD9, false, false ),
new AnimalFormEntry( typeof( Cat ), 1018264, 8475, 2309, 1070806, 40.0, 0xC9, false, false ),
new AnimalFormEntry( typeof( Rat ), 1018294, 8483, 2309, 1070805, 20.0, 0xEE, true, false ),
new AnimalFormEntry( typeof( Rabbit ), 1028485, 8485, 2309, 1070805, 20.0, 0xCD, true, false )
};
public static AnimalFormEntry[] Entries{ get{ return m_Entries; } }
public class AnimalFormGump : Gump
{
//TODO: Convert this for ML to the BaseImageTileButtonsgump
private Mobile m_Caster;
private AnimalForm m_Spell;
public AnimalFormGump( Mobile caster, AnimalFormEntry[] entries, AnimalForm spell ) : base( 50, 50 )
{
m_Caster = caster;
m_Spell = spell;
AddPage( 0 );
AddBackground( 0, 0, 408, 298, 0x13BE );
AddBackground( 4, 28, 400, 240, 0xBB8 );
AddHtmlLocalized( 4, 4, 400, 20, 1063394, 0x0, false, false ); // <center>Animal Form Selection Menu</center>
AddButton( 25, 272, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 60, 274, 150, 20, 1011036, 0x0, false, false ); // OKAY
AddButton( 285, 272, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 );
AddHtmlLocalized( 320, 274, 150, 20, 1011012, 0x0, false, false ); // CANCEL
double ninjitsu = caster.Skills.Ninjitsu.Value;
for ( int i = 0; i < entries.Length; ++i )
{
bool enabled = ( ninjitsu >= entries[i].ReqSkill );
int x = 100 * ( i % 4 );
int y = 80 * ( i / 4 );
TextDefinition.AddHtmlText( this, 10 + x, 30 + y, 100, 18, entries[i].Name, false, false );
if ( enabled )
{
AddRadio( 10 + x, 50 + y, 0xD2, 0xD3, false, 100 + i );
AddItem( 30 + x, 50 + y, entries[i].ItemID, entries[i].Hue );
}
else
AddItem( 10 + x, 50 + y, entries[i].ItemID, 0x3E3 );
AddTooltip( enabled ? entries[i].Tooltip : 1070708 );
}
}
public override void OnResponse( NetState sender, RelayInfo info )
{
if ( info.ButtonID == 1 && info.Switches.Length > 0 )
{
int entryID = info.Switches[0] - 100;
if ( AnimalForm.Morph( m_Caster, entryID ) == MorphResult.Fail )
{
m_Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502632 ); // The spell fizzles.
m_Caster.FixedParticles( 0x3735, 1, 30, 9503, EffectLayer.Waist );
m_Caster.PlaySound( 0x5C );
}
}
}
}
}
public class AnimalFormContext
{
private Timer m_Timer;
private SkillMod m_Mod;
private bool m_SpeedBoost;
private Type m_Type;
public Timer Timer{ get{ return m_Timer; } }
public SkillMod Mod{ get{ return m_Mod; } }
public bool SpeedBoost{ get{ return m_SpeedBoost; } }
public Type Type{ get{ return m_Type; } }
public AnimalFormContext( Timer timer, SkillMod mod, bool speedBoost, Type type )
{
m_Timer = timer;
m_Mod = mod;
m_SpeedBoost = speedBoost;
m_Type = type;
}
}
public class AnimalFormTimer : Timer
{
private Mobile m_Mobile;
private int m_Body;
private int m_Hue;
public AnimalFormTimer( Mobile from, int body, int hue ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) )
{
m_Mobile = from;
m_Body = body;
m_Hue = hue;
Priority = TimerPriority.FiftyMS;
}
protected override void OnTick()
{
if ( m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Body != m_Body || (m_Hue != 0 && m_Mobile.Hue != m_Hue) )
{
AnimalForm.RemoveContext( m_Mobile, true );
Stop();
}
}
}
}

View file

@ -0,0 +1,73 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
using Server.SkillHandlers;
namespace Server.Spells.Ninjitsu
{
public class Backstab : NinjaMove
{
// TODO: Cannot hide for 5s
public Backstab()
{
}
public override int BaseMana{ get{ return 30; } }
public override double RequiredSkill{ get{ return 20.0; } }
public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063089 ); } } // You prepare to Backstab your opponent.
public override double GetDamageScalar( Mobile attacker, Mobile defender )
{
double ninjitsu = attacker.Skills[SkillName.Ninjitsu].Value;
return 1.0 + (ninjitsu / 360) + Tracking.GetStalkingBonus( attacker, defender ) / 100;
}
public override bool Validate( Mobile from )
{
if( !from.Hidden || from.AllowedStealthSteps <= 0 )
{
from.SendLocalizedMessage( 1063087 ); // You must be in stealth mode to use this ability.
return false;
}
return base.Validate( from );
}
public override bool OnBeforeSwing( Mobile attacker, Mobile defender )
{
return Validate( attacker ) && CheckMana( attacker, true );
}
public override bool ValidatesDuringHit { get { return false; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
//Validates before swing
ClearCurrentMove( attacker );
attacker.SendLocalizedMessage( 1063090 ); // You quickly stab your opponent as you come out of hiding!
defender.FixedParticles( 0x37B9, 1, 5, 0x251D, 0x651, 0, EffectLayer.Waist );
attacker.RevealingAction();
CheckGain( attacker );
}
public override void OnMiss( Mobile attacker, Mobile defender )
{
ClearCurrentMove( attacker );
attacker.SendLocalizedMessage( 1063161 ); // You failed to properly use the element of surprise.
attacker.RevealingAction();
}
}
}

View file

@ -0,0 +1,138 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
using Server.SkillHandlers;
namespace Server.Spells.Ninjitsu
{
public class DeathStrike : NinjaMove
{
public DeathStrike()
{
}
public override int BaseMana { get { return 30; } }
public override double RequiredSkill { get { return 85.0; } }
public override TextDefinition AbilityMessage { get { return new TextDefinition( 1063091 ); } } // You prepare to hit your opponent with a Death Strike.
public override double GetDamageScalar( Mobile attacker, Mobile defender )
{
return 0.5;
}
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentMove( attacker );
double ninjitsu = attacker.Skills[SkillName.Ninjitsu].Value;
double chance;
if( ninjitsu < 100 ) //This formula is an approximation from OSI data. TODO: find correct formula
chance = 30 + (ninjitsu - 85) * 2.2;
else
chance = 63 + (ninjitsu - 100) * 1.1;
if( (chance / 100) < Utility.RandomDouble() )
{
attacker.SendLocalizedMessage( 1070779 ); // You missed your opponent with a Death Strike.
return;
}
DeathStrikeInfo info;
int damageBonus = 0;
if( m_Table.Contains( defender ) )
{
attacker.SendLocalizedMessage( 1063092 ); // Your opponent lands another Death Strike!
info = (DeathStrikeInfo)m_Table[defender];
if( info.m_Steps > 0 )
damageBonus = info.m_Attacker.Skills[SkillName.Ninjitsu].Fixed / 150;
if( info.m_Timer != null )
info.m_Timer.Stop();
m_Table.Remove( defender );
}
else
{
attacker.SendLocalizedMessage( 1063094 ); // You inflict a Death Strike upon your opponent!
defender.SendLocalizedMessage( 1063093 ); // You have been hit by a Death Strike! Move with caution!
}
defender.FixedParticles( 0x374A, 1, 17, 0x26BC, EffectLayer.Waist );
attacker.PlaySound( 0x50D );
info = new DeathStrikeInfo( defender, attacker, damageBonus );
info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( ProcessDeathStrike ), info );
m_Table[defender] = info;
CheckGain( attacker );
}
private static Hashtable m_Table = new Hashtable();
private class DeathStrikeInfo
{
public Mobile m_Target;
public Mobile m_Attacker;
public int m_Steps;
public int m_DamageBonus;
public Timer m_Timer;
public DeathStrikeInfo( Mobile target, Mobile attacker, int damageBonus )
{
m_Target = target;
m_Attacker = attacker;
m_DamageBonus = damageBonus;
}
}
public static void AddStep( Mobile m )
{
DeathStrikeInfo info = m_Table[m] as DeathStrikeInfo;
if( info == null )
return;
info.m_Steps++;
}
private static void ProcessDeathStrike( object state )
{
DeathStrikeInfo info = (DeathStrikeInfo)state;
double ninjitsu = info.m_Attacker.Skills[SkillName.Ninjitsu].Fixed;
int divisor = (info.m_Steps >= 5) ? 30 : 80;
double baseDamage = ninjitsu / divisor;
double stalkingBonus = Tracking.GetStalkingBonus( info.m_Attacker, info.m_Target );
int maxDamage = (info.m_Steps >= 5) ? 62 : 22;
int damage = Math.Max( 0, Math.Min( maxDamage, (int)(baseDamage + stalkingBonus) ) );
// This bonus is 8 at most. That brings the cap up to 70/30.
damage += info.m_DamageBonus;
// Damage is direct.
//info.m_Target.Damage( damage, info.m_Attacker );
AOS.Damage( info.m_Target, info.m_Attacker, damage, true, 100, 0, 0, 0, 0 );
m_Table.Remove( info.m_Target );
}
}
}

View file

@ -0,0 +1,75 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Ninjitsu
{
public class FocusAttack : NinjaMove
{
// TODO: Display property bonus on equipped weapons.
public FocusAttack()
{
}
public override int BaseMana{ get{ return 20; } }
public override double RequiredSkill{ get{ return 60.0; } }
public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063095 ); } } // You prepare to focus all of your abilities into your next strike.
public override bool Validate( Mobile from )
{
if ( from.FindItemOnLayer( Layer.TwoHanded ) as BaseShield != null )
{
from.SendLocalizedMessage( 1063096 ); // You cannot use this ability while holding a shield.
return false;
}
Item handOne = from.FindItemOnLayer( Layer.OneHanded ) as BaseWeapon;
if ( handOne != null && !(handOne is BaseRanged) )
return base.Validate( from );
Item handTwo = from.FindItemOnLayer( Layer.TwoHanded ) as BaseWeapon;
if ( handTwo != null && !(handTwo is BaseRanged) )
return base.Validate( from );
from.SendLocalizedMessage( 1063097 ); // You must be wielding a melee weapon without a shield to use this ability.
return false;
}
public override double GetDamageScalar( Mobile attacker, Mobile defender )
{
double ninjitsu = attacker.Skills[SkillName.Ninjitsu].Value;
return 1.0 + (ninjitsu * ninjitsu) / 43636;
}
public override double GetPropertyBonus( Mobile attacker )
{
double ninjitsu = attacker.Skills[SkillName.Ninjitsu].Value;
double bonus = (ninjitsu * ninjitsu) / 43636;
return 1.0 + (bonus * 3 + 0.01);
}
public override bool OnBeforeDamage( Mobile attacker, Mobile defender )
{
return Validate( attacker ) && CheckMana( attacker, true );
}
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
ClearCurrentMove( attacker );
attacker.SendLocalizedMessage( 1063098 ); // You focus all of your abilities and strike with deadly force!
CheckGain( attacker );
}
}
}

View file

@ -0,0 +1,128 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Ninjitsu
{
public class KiAttack : NinjaMove
{
public KiAttack()
{
}
public override int BaseMana{ get{ return 25; } }
public override double RequiredSkill{ get{ return 80.0; } }
public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063099 ); } } // Your Ki Attack must be complete within 2 seconds for the damage bonus!
public override void OnUse( Mobile from )
{
if ( !Validate( from ) )
return;
KiAttackInfo info = new KiAttackInfo( from );
info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( EndKiAttack ), info );
m_Table[from] = info;
}
public override bool Validate( Mobile from )
{
if ( from.Hidden && from.AllowedStealthSteps > 0 )
{
from.SendLocalizedMessage( 1063127 ); // You cannot use this ability while in stealth mode.
return false;
}
return base.Validate( from );
}
public override double GetDamageScalar( Mobile attacker, Mobile defender )
{
if ( attacker.Hidden )
return 1.0;
return 1.0 + GetBonus( attacker ) / 10;
}
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
if ( GetBonus( attacker ) == 0.0 )
{
attacker.SendLocalizedMessage( 1063101 ); // You were too close to your target to cause any additional damage.
}
else
{
attacker.SendLocalizedMessage( 1063100 ); // Your quick flight to your target causes extra damage as you strike!
defender.FixedParticles( 0x37BE, 1, 5, 0x26BD, 0, 0x1, EffectLayer.Waist );
}
ClearCurrentMove( attacker );
}
public override void OnClearMove( Mobile from )
{
KiAttackInfo info = m_Table[from] as KiAttackInfo;
if ( info != null )
{
if ( info.m_Timer != null )
info.m_Timer.Stop();
m_Table.Remove( info.m_Mobile );
}
}
private static Hashtable m_Table = new Hashtable();
public static double GetBonus( Mobile from )
{
KiAttackInfo info = m_Table[from] as KiAttackInfo;
if ( info == null )
return 0.0;
int xDelta = info.m_Location.X - from.X;
int yDelta = info.m_Location.Y - from.Y;
double bonus = Math.Sqrt( (xDelta * xDelta) + (yDelta * yDelta) );
if ( bonus > 20.0 )
bonus = 20.0;
return bonus;
}
private class KiAttackInfo
{
public Mobile m_Mobile;
public Point3D m_Location;
public Timer m_Timer;
public KiAttackInfo( Mobile m )
{
m_Mobile = m;
m_Location = m.Location;
}
}
private static void EndKiAttack( object state )
{
KiAttackInfo info = (KiAttackInfo)state;
if ( info.m_Timer != null )
info.m_Timer.Stop();
ClearCurrentMove( info.m_Mobile );
info.m_Mobile.SendLocalizedMessage( 1063102 ); // You failed to complete your Ki Attack in time.
m_Table.Remove( info.m_Mobile );
}
}
}

View file

@ -0,0 +1,266 @@
using System;
using System.Collections;
using Server;
using Server.Spells;
using Server.Spells.Necromancy;
using Server.Mobiles;
using Server.Items;
using Server.Spells.Ninjitsu;
namespace Server.Spells.Ninjitsu
{
public class MirrorImage : NinjaSpell
{
private static Hashtable m_CloneCount = new Hashtable();
public static bool HasClone( Mobile m )
{
return (m_CloneCount.Contains( m ) && ((int)m_CloneCount[m]) > 0);
}
public static void AddClone( Mobile m )
{
if( m == null )
return;
if( m_CloneCount.Contains( m ) )
m_CloneCount[m] = ((int)m_CloneCount[m] +1);
else
m_CloneCount.Add( m, 1 );
}
public static void RemoveClone( Mobile m )
{
if( m == null )
return;
if( m_CloneCount.Contains( m ) )
{
m_CloneCount[m] = ((int)m_CloneCount[m] -1);
if( ((int)m_CloneCount[m]) <= 0 )
m_CloneCount.Remove( m );
}
}
private static SpellInfo m_Info = new SpellInfo(
"Mirror Image", null,
SpellCircle.Sixth, // 1.5s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 40.0; } }
public override int RequiredMana{ get{ return 10; } }
public override bool BlockedByAnimalForm{ get{ return false; } }
public MirrorImage( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( Caster.Mounted )
{
Caster.SendLocalizedMessage( 1063132 ); // You cannot use this ability while mounted.
return false;
}
else if ( (Caster.Followers + 1) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1063133 ); // You cannot summon a mirror image because you have too many followers.
return false;
}
else if ( Necromancy.TransformationSpell.UnderTransformation( Caster, typeof( HorrificBeastSpell ) ) )
{
Caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form.
return false;
}
return base.CheckCast();
}
public override bool CheckDisturb( DisturbType type, bool firstCircle, bool resistable )
{
return false;
}
public override void OnBeginCast()
{
base.OnBeginCast();
Caster.SendLocalizedMessage( 1063134 ); // You begin to summon a mirror image of yourself.
}
public override void OnCast()
{
if ( Caster.Mounted )
{
Caster.SendLocalizedMessage( 1063132 ); // You cannot use this ability while mounted.
}
else if ( (Caster.Followers + 1) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1063133 ); // You cannot summon a mirror image because you have too many followers.
}
else if ( Necromancy.TransformationSpell.UnderTransformation( Caster, typeof( HorrificBeastSpell ) ) )
{
Caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form.
}
else if ( CheckSequence() )
{
Caster.FixedParticles( 0x376A, 1, 14, 0x13B5, EffectLayer.Waist );
Caster.PlaySound( 0x511 );
new Clone( Caster ).MoveToWorld( Caster.Location, Caster.Map );
}
FinishSequence();
}
}
}
namespace Server.Mobiles
{
public class Clone : BaseCreature
{
private Mobile m_Caster;
public Clone( Mobile caster ) : base( AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4 )
{
m_Caster = caster;
Body = caster.Body;
Hue = caster.Hue;
Female = caster.Female;
Name = caster.Name;
NameHue = caster.NameHue;
Title = caster.Title;
Kills = caster.Kills;
HairItemID = caster.HairItemID;
HairHue = caster.HairHue;
FacialHairItemID = caster.FacialHairItemID;
FacialHairHue = caster.FacialHairHue;
for ( int i = 0; i < caster.Skills.Length; ++i )
{
Skills[i].Base = caster.Skills[i].Base;
Skills[i].Cap = caster.Skills[i].Cap;
}
for( int i = 0; i < caster.Items.Count; i++ )
{
AddItem( CloneItem( caster.Items[i] ) );
}
Warmode = true;
Summoned = true;
SummonMaster = caster;
ControlOrder = OrderType.Follow;
ControlTarget = caster;
TimeSpan duration = TimeSpan.FromSeconds( 30 + caster.Skills.Ninjitsu.Fixed / 40 );
new UnsummonTimer( caster, this, duration ).Start();
SummonEnd = DateTime.Now + duration;
MirrorImage.AddClone( m_Caster );
}
protected override BaseAI ForcedAI { get { return new CloneAI( this ); } }
public override bool IsHumanInTown() { return false; }
private Item CloneItem( Item item )
{
Item newItem = new Item( item.ItemID );
newItem.Hue = item.Hue;
newItem.Layer = item.Layer;
return newItem;
}
public override void OnDamage( int amount, Mobile from, bool willKill )
{
Delete();
}
public override bool DeleteCorpseOnDeath { get { return true; } }
public override void OnDelete()
{
Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3728, 10, 15, 5042 );
base.OnDelete();
}
public override void OnAfterDelete()
{
MirrorImage.RemoveClone( m_Caster );
base.OnAfterDelete();
}
public override bool IsDispellable { get { return false; } }
public override bool Commandable { get { return false; } }
public Clone( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.WriteEncodedInt( 0 ); // version
writer.Write( m_Caster );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadEncodedInt();
m_Caster = reader.ReadMobile();
MirrorImage.AddClone( m_Caster );
}
}
}
namespace Server.Mobiles
{
public class CloneAI : BaseAI
{
public CloneAI( Clone m ) : base ( m )
{
m.CurrentSpeed = m.ActiveSpeed;
}
public override bool Think()
{
// Clones only follow their owners
Mobile master = m_Mobile.SummonMaster;
if ( master != null && master.Map == m_Mobile.Map && master.InRange( m_Mobile, m_Mobile.RangePerception ) )
{
int iCurrDist = (int)m_Mobile.GetDistanceToSqrt( master );
bool bRun = (iCurrDist > 5);
WalkMobileRange( master, 2, bRun, 0, 1 );
}
else
WalkRandom( 2, 2, 1 );
return true;
}
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Spells
{
public class NinjaMove : SpecialMove
{
public override SkillName MoveSkill{ get{ return SkillName.Ninjitsu; } }
}
}

View file

@ -0,0 +1,102 @@
using System;
using Server;
using Server.Spells;
using Server.Network;
using Server.Items;
using Server.Mobiles;
namespace Server.Spells.Ninjitsu
{
public abstract class NinjaSpell : Spell
{
public abstract double RequiredSkill{ get; }
public abstract int RequiredMana{ get; }
public override SkillName CastSkill{ get{ return SkillName.Ninjitsu; } }
public override bool RevealOnCast{ get{ return false; } }
public override bool ClearHandsOnCast{ get{ return false; } }
public override bool ShowHandMovement{ get{ return false; } }
public override bool BlocksMovement{ get{ return false; } }
public override int CastDelayBase{ get{ return 1; } }
public override int CastRecoveryBase{ get{ return 7; } }
public NinjaSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info )
{
}
public static bool CheckExpansion( Mobile from )
{
if ( !( from is PlayerMobile ) )
return true;
if ( from.NetState == null )
return false;
return ( (from.NetState.Flags & 0x10) != 0 );
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
if ( !CheckExpansion( Caster ) )
{
Caster.SendLocalizedMessage( 1063456 ); // You must upgrade to Samurai Empire in order to use that ability.
return false;
}
if ( Caster.Skills[CastSkill].Value < RequiredSkill )
{
string args = String.Format( "{0}\t{1}\t ", RequiredSkill.ToString( "F1" ), CastSkill.ToString() );
Caster.SendLocalizedMessage( 1063013, args ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
return false;
}
else if ( Caster.Mana < ScaleMana( RequiredMana ) )
{
Caster.SendLocalizedMessage( 1060174, RequiredMana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
return false;
}
return true;
}
public override bool CheckFizzle()
{
int mana = ScaleMana( RequiredMana );
if ( Caster.Skills[CastSkill].Value < RequiredSkill )
{
Caster.SendLocalizedMessage( 1063352, RequiredSkill.ToString( "F1" ) ); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack!
return false;
}
else if ( Caster.Mana < mana )
{
Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
return false;
}
if ( !base.CheckFizzle() )
return false;
Caster.Mana -= mana;
return true;
}
public override void GetCastSkills( out double min, out double max )
{
min = RequiredSkill;
max = RequiredSkill + 37.5;
}
public override int GetMana()
{
return 0;
}
}
}

View file

@ -0,0 +1,127 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Ninjitsu
{
public class Shadowjump : NinjaSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Shadowjump", null,
SpellCircle.Fourth, // 1.0s base cast delay
-1,
9002
);
public override double RequiredSkill{ get{ return 50.0; } }
public override int RequiredMana{ get{ return 15; } }
public override bool BlockedByAnimalForm{ get{ return false; } }
public Shadowjump( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( !Caster.Hidden || Caster.AllowedStealthSteps <= 0 )
{
Caster.SendLocalizedMessage( 1063087 ); // You must be in stealth mode to use this ability.
return false;
}
return base.CheckCast();
}
public override bool CheckDisturb( DisturbType type, bool firstCircle, bool resistable )
{
return false;
}
public override void OnCast()
{
Caster.SendLocalizedMessage( 1063088 ); // You prepare to perform a Shadowjump.
Caster.Target = new InternalTarget( this );
}
public void Target( IPoint3D p )
{
IPoint3D orig = p;
Map map = Caster.Map;
SpellHelper.GetSurfaceTop( ref p );
if ( !Caster.Hidden || Caster.AllowedStealthSteps <= 0 )
{
Caster.SendLocalizedMessage( 1063087 ); // You must be in stealth mode to use this ability.
}
else if ( Factions.Sigil.ExistsOn( Caster ) )
{
Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
}
else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) )
{
Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move.
}
else if ( !SpellHelper.CheckTravel( Caster, TravelCheckType.TeleportFrom ) || !SpellHelper.CheckTravel( Caster, map, new Point3D( p ), TravelCheckType.TeleportTo ))
{
}
else if ( map == null || !map.CanSpawnMobile( p.X, p.Y, p.Z ) )
{
Caster.SendLocalizedMessage( 502831 ); // Cannot teleport to that spot.
}
else if ( SpellHelper.CheckMulti( new Point3D( p ), map ) )
{
// TODO: Cannot shadowjump within 5 tiles from any house.
Caster.SendLocalizedMessage( 502831 ); // Cannot teleport to that spot.
}
else if ( CheckSequence() )
{
SpellHelper.Turn( Caster, orig );
Mobile m = Caster;
Point3D from = m.Location;
Point3D to = new Point3D( p );
m.Location = to;
m.ProcessDelta();
Effects.SendLocationParticles( EffectItem.Create( from, m.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 );
m.PlaySound( 0x512 );
}
FinishSequence();
}
public class InternalTarget : Target
{
private Shadowjump m_Owner;
public InternalTarget( Shadowjump owner ) : base( 11, true, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
IPoint3D p = o as IPoint3D;
if ( p != null )
m_Owner.Target( p );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
if ( !from.CheckSkill( SkillName.Hiding, 0.0, 100.0 ) ) //TODO: Hiding check or stealth check?
from.RevealingAction();
}
}
}
}

View file

@ -0,0 +1,127 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
using Server.SkillHandlers;
namespace Server.Spells.Ninjitsu
{
public class SurpriseAttack : NinjaMove
{
// TODO: Cannot hide for 5s
public SurpriseAttack()
{
}
public override int BaseMana{ get{ return 20; } }
public override double RequiredSkill{ get{ return 30.0; } }
public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063128 ); } } // You prepare to surprise your prey.
public override bool Validate( Mobile from )
{
if( !from.Hidden || from.AllowedStealthSteps <= 0 )
{
from.SendLocalizedMessage( 1063087 ); // You must be in stealth mode to use this ability.
return false;
}
return base.Validate( from );
}
public override bool OnBeforeSwing( Mobile attacker, Mobile defender )
{
return Validate( attacker ) && CheckMana( attacker, true );
}
public override bool ValidatesDuringHit { get { return false; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
//Validates before swing
ClearCurrentMove( attacker );
attacker.SendLocalizedMessage( 1063129 ); // You catch your opponent off guard with your Surprise Attack!
defender.SendLocalizedMessage( 1063130 ); // Your defenses are lowered as your opponent surprises you!
defender.FixedParticles( 0x37B9, 1, 5, 0x26DA, 0, 3, EffectLayer.Head );
attacker.RevealingAction();
SurpriseAttackInfo info;
if ( m_Table.Contains( defender ) )
{
info = (SurpriseAttackInfo)m_Table[defender];
if ( info.m_Timer != null )
info.m_Timer.Stop();
m_Table.Remove( defender );
}
int ninjitsu = attacker.Skills[SkillName.Ninjitsu].Fixed;
int malus = ninjitsu / 60 + (int)Tracking.GetStalkingBonus( attacker, defender );
info = new SurpriseAttackInfo( defender, malus );
info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 8.0 ), new TimerStateCallback( EndSurprise ), info );
m_Table[defender] = info;
CheckGain( attacker );
}
public override void OnMiss( Mobile attacker, Mobile defender )
{
ClearCurrentMove( attacker );
attacker.SendLocalizedMessage( 1063161 ); // You failed to properly use the element of surprise.
attacker.RevealingAction();
}
private static Hashtable m_Table = new Hashtable();
public static bool GetMalus( Mobile target, ref int malus )
{
SurpriseAttackInfo info = m_Table[target] as SurpriseAttackInfo;
if ( info == null )
return false;
malus = info.m_Malus;
return true;
}
private class SurpriseAttackInfo
{
public Mobile m_Target;
public int m_Malus;
public Timer m_Timer;
public SurpriseAttackInfo( Mobile target, int effect )
{
m_Target = target;
m_Malus = effect;
}
}
private static void EndSurprise( object state )
{
SurpriseAttackInfo info = (SurpriseAttackInfo)state;
if ( info.m_Timer != null )
info.m_Timer.Stop();
info.m_Target.SendLocalizedMessage( 1063131 ); // Your defenses have returned to normal.
m_Table.Remove( info.m_Target );
}
}
}

108
Scripts/Spells/Reagent.cs Normal file
View file

@ -0,0 +1,108 @@
using System;
using Server.Items;
namespace Server.Spells
{
public class Reagent
{
private static Type[] m_Types = new Type[13]
{
typeof( BlackPearl ),
typeof( Bloodmoss ),
typeof( Garlic ),
typeof( Ginseng ),
typeof( MandrakeRoot ),
typeof( Nightshade ),
typeof( SulfurousAsh ),
typeof( SpidersSilk ),
typeof( BatWing ),
typeof( GraveDust ),
typeof( DaemonBlood ),
typeof( NoxCrystal ),
typeof( PigIron )
};
public Type[] Types
{
get{ return m_Types; }
}
public static Type BlackPearl
{
get{ return m_Types[0]; }
set{ m_Types[0] = value; }
}
public static Type Bloodmoss
{
get{ return m_Types[1]; }
set{ m_Types[1] = value; }
}
public static Type Garlic
{
get{ return m_Types[2]; }
set{ m_Types[2] = value; }
}
public static Type Ginseng
{
get{ return m_Types[3]; }
set{ m_Types[3] = value; }
}
public static Type MandrakeRoot
{
get{ return m_Types[4]; }
set{ m_Types[4] = value; }
}
public static Type Nightshade
{
get{ return m_Types[5]; }
set{ m_Types[5] = value; }
}
public static Type SulfurousAsh
{
get{ return m_Types[6]; }
set{ m_Types[6] = value; }
}
public static Type SpidersSilk
{
get{ return m_Types[7]; }
set{ m_Types[7] = value; }
}
public static Type BatWing
{
get{ return m_Types[8]; }
set{ m_Types[8] = value; }
}
public static Type GraveDust
{
get{ return m_Types[9]; }
set{ m_Types[9] = value; }
}
public static Type DaemonBlood
{
get{ return m_Types[10]; }
set{ m_Types[10] = value; }
}
public static Type NoxCrystal
{
get{ return m_Types[11]; }
set{ m_Types[11] = value; }
}
public static Type PigIron
{
get{ return m_Types[12]; }
set{ m_Types[12] = value; }
}
}
}

View file

@ -0,0 +1,74 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Second
{
public class AgilitySpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Agility", "Ex Uus",
SpellCircle.Second,
212,
9061,
Reagent.Bloodmoss,
Reagent.MandrakeRoot
);
public AgilitySpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckBSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.AddStatBonus( Caster, m, StatType.Dex );
m.FixedParticles( 0x375A, 10, 15, 5010, EffectLayer.Waist );
m.PlaySound( 0x28E );
int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, false )*100);
TimeSpan length = SpellHelper.GetDuration( Caster, m );
BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Agility, 1075841, length, m, percentage.ToString() ) );
}
FinishSequence();
}
private class InternalTarget : Target
{
private AgilitySpell m_Owner;
public InternalTarget( AgilitySpell owner ) : base( 12, false, TargetFlags.Beneficial )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,74 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Second
{
public class CunningSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Cunning", "Uus Wis",
SpellCircle.Second,
212,
9061,
Reagent.MandrakeRoot,
Reagent.Nightshade
);
public CunningSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckBSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.AddStatBonus( Caster, m, StatType.Int );
m.FixedParticles( 0x375A, 10, 15, 5011, EffectLayer.Head );
m.PlaySound( 0x1EB );
int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, false )*100);
TimeSpan length = SpellHelper.GetDuration( Caster, m );
BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Cunning, 1075843, length, m, percentage.ToString() ) );
}
FinishSequence();
}
private class InternalTarget : Target
{
private CunningSpell m_Owner;
public InternalTarget( CunningSpell owner ) : base( 12, false, TargetFlags.Beneficial )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,90 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Second
{
public class CureSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Cure", "An Nox",
SpellCircle.Second,
212,
9061,
Reagent.Garlic,
Reagent.Ginseng
);
public CureSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckBSequence( m ) )
{
SpellHelper.Turn( Caster, m );
Poison p = m.Poison;
if ( p != null )
{
int chanceToCure = 10000 + (int)(Caster.Skills[SkillName.Magery].Value * 75) - ((p.Level + 1) * (Core.AOS ? (p.Level < 4 ? 3300 : 3100) : 1750));
chanceToCure /= 100;
if ( chanceToCure > Utility.Random( 100 ) )
{
if ( m.CurePoison( Caster ) )
{
if ( Caster != m )
Caster.SendLocalizedMessage( 1010058 ); // You have cured the target of all poisons!
m.SendLocalizedMessage( 1010059 ); // You have been cured of all poisons.
}
}
else
{
m.SendLocalizedMessage( 1010060 ); // You have failed to cure your target!
}
}
m.FixedParticles( 0x373A, 10, 15, 5012, EffectLayer.Waist );
m.PlaySound( 0x1E0 );
}
FinishSequence();
}
public class InternalTarget : Target
{
private CureSpell m_Owner;
public InternalTarget( CureSpell owner ) : base( 12, false, TargetFlags.Beneficial )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,113 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Second
{
public class HarmSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Harm", "An Mani",
SpellCircle.Second,
212,
Core.AOS ? 9001 : 9041,
Reagent.Nightshade,
Reagent.SpidersSilk
);
public HarmSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override bool DelayedDamage{ get{ return false; } }
public override double GetSlayerDamageScalar( Mobile target )
{
return 1.0; //This spell isn't affected by slayer spellbooks
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m );
double damage;
if ( Core.AOS )
{
damage = GetNewAosDamage( 17, 1, 5, m );
}
else
{
damage = Utility.Random( 1, 15 );
if ( CheckResisted( m ) )
{
damage *= 0.75;
m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy.
}
damage *= GetDamageScalar( m );
}
if ( !m.InRange( Caster, 2 ) )
damage *= 0.25; // 1/4 damage at > 2 tile range
else if ( !m.InRange( Caster, 1 ) )
damage *= 0.50; // 1/2 damage at 2 tile range
if ( Core.AOS )
{
m.FixedParticles( 0x374A, 10, 30, 5013, 1153, 2, EffectLayer.Waist );
m.PlaySound( 0x0FC );
}
else
{
m.FixedParticles( 0x374A, 10, 15, 5013, EffectLayer.Waist );
m.PlaySound( 0x1F1 );
}
SpellHelper.Damage( this, m, damage, 0, 0, 100, 0, 0 );
}
FinishSequence();
}
private class InternalTarget : Target
{
private HarmSpell m_Owner;
public InternalTarget( HarmSpell owner ) : base( 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,88 @@
using System;
using Server.Targeting;
using Server.Network;
using Server.Items;
namespace Server.Spells.Second
{
public class MagicTrapSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Magic Trap", "In Jux",
SpellCircle.Second,
212,
9001,
Reagent.Garlic,
Reagent.SpidersSilk,
Reagent.SulfurousAsh
);
public MagicTrapSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( TrapableContainer item )
{
if ( !Caster.CanSee( item ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( item.TrapType != TrapType.None && item.TrapType != TrapType.MagicTrap )
{
base.DoFizzle();
}
else if ( CheckSequence() )
{
SpellHelper.Turn( Caster, item );
item.TrapType = TrapType.MagicTrap;
item.TrapPower = Core.AOS ? Utility.RandomMinMax( 10, 50 ) : 1;
item.TrapLevel = 0;
Point3D loc = item.GetWorldLocation();
Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc.X + 1, loc.Y, loc.Z ), item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 9502 );
Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc.X, loc.Y - 1, loc.Z ), item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 9502 );
Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc.X - 1, loc.Y, loc.Z ), item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 9502 );
Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc.X, loc.Y + 1, loc.Z ), item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 9502 );
Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc.X, loc.Y, loc.Z ), item.Map, EffectItem.DefaultDuration ), 0, 0, 0, 5014 );
Effects.PlaySound( loc, item.Map, 0x1EF );
}
FinishSequence();
}
private class InternalTarget : Target
{
private MagicTrapSpell m_Owner;
public InternalTarget( MagicTrapSpell owner ) : base( 12, false, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is TrapableContainer )
{
m_Owner.Target( (TrapableContainer)o );
}
else
{
from.SendMessage( "You can't trap that" );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,162 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Second
{
public class ProtectionSpell : Spell
{
private static Hashtable m_Registry = new Hashtable();
public static Hashtable Registry { get { return m_Registry; } }
private static SpellInfo m_Info = new SpellInfo(
"Protection", "Uus Sanct",
SpellCircle.Second,
236,
9011,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.SulfurousAsh
);
public ProtectionSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
if ( Core.AOS )
return true;
if ( m_Registry.ContainsKey( Caster ) )
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
return false;
}
else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) )
{
Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time.
return false;
}
return true;
}
private static Hashtable m_Table = new Hashtable();
public static void Toggle( Mobile caster, Mobile target )
{
/* Players under the protection spell effect can no longer have their spells "disrupted" when hit.
* Players under the protection spell have decreased physical resistance stat value,
* a decreased "resisting spells" skill value by -35,
* and a slower casting speed modifier (technically, a negative "faster cast speed") of 2 points.
* The protection spell has an indefinite duration, becoming active when cast, and deactivated when re-cast.
* Reactive Armor, Protection, and Magic Reflection will stay oneven after logging out,
* even after dyinguntil you turn them off by casting them again.
*/
object[] mods = (object[])m_Table[target];
if ( mods == null )
{
target.PlaySound( 0x1E9 );
target.FixedParticles( 0x375A, 9, 20, 5016, EffectLayer.Waist );
mods = new object[2]
{
new ResistanceMod( ResistanceType.Physical, -15 + (int)(caster.Skills[SkillName.Inscribe].Value / 20) ),
new DefaultSkillMod( SkillName.MagicResist, true, -35 + (int)(caster.Skills[SkillName.Inscribe].Value / 20) )
};
m_Table[target] = mods;
Registry[target] = 100.0;
target.AddResistanceMod( (ResistanceMod)mods[0] );
target.AddSkillMod( (SkillMod)mods[1] );
}
else
{
target.PlaySound( 0x1ED );
target.FixedParticles( 0x375A, 9, 20, 5016, EffectLayer.Waist );
m_Table.Remove( target );
Registry.Remove( target );
target.RemoveResistanceMod( (ResistanceMod)mods[0] );
target.RemoveSkillMod( (SkillMod)mods[1] );
}
}
public override void OnCast()
{
if ( Core.AOS )
{
if ( CheckSequence() )
Toggle( Caster, Caster );
FinishSequence();
}
else
{
if ( m_Registry.ContainsKey( Caster ) )
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
}
else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) )
{
Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time.
}
else if ( CheckSequence() )
{
if ( Caster.BeginAction( typeof( DefensiveSpell ) ) )
{
double value = (int)(Caster.Skills[SkillName.EvalInt].Value + Caster.Skills[SkillName.Meditation].Value + Caster.Skills[SkillName.Inscribe].Value);
value /= 4;
if ( value < 0 )
value = 0;
else if ( value > 75 )
value = 75.0;
Registry.Add( Caster, value );
new InternalTimer( Caster ).Start();
Caster.FixedParticles( 0x375A, 9, 20, 5016, EffectLayer.Waist );
Caster.PlaySound( 0x1ED );
}
else
{
Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time.
}
}
FinishSequence();
}
}
private class InternalTimer : Timer
{
private Mobile m_Caster;
public InternalTimer( Mobile caster ) : base( TimeSpan.FromSeconds( 0 ) )
{
double val = caster.Skills[SkillName.Magery].Value * 2.0;
if ( val < 15 )
val = 15;
else if ( val > 240 )
val = 240;
m_Caster = caster;
Delay = TimeSpan.FromSeconds( val );
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
ProtectionSpell.Registry.Remove( m_Caster );
DefensiveSpell.Nullify( m_Caster );
}
}
}
}

View file

@ -0,0 +1,83 @@
using System;
using Server.Targeting;
using Server.Network;
using Server.Items;
namespace Server.Spells.Second
{
public class RemoveTrapSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Remove Trap", "An Jux",
SpellCircle.Second,
212,
9001,
Reagent.Bloodmoss,
Reagent.SulfurousAsh
);
public RemoveTrapSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
Caster.SendMessage( "What do you wish to untrap?" );
}
public void Target( TrapableContainer item )
{
if ( !Caster.CanSee( item ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( item.TrapType != TrapType.None && item.TrapType != TrapType.MagicTrap )
{
base.DoFizzle();
}
else if ( CheckSequence() )
{
SpellHelper.Turn( Caster, item );
Point3D loc = item.GetWorldLocation();
Effects.SendLocationParticles( EffectItem.Create( loc, item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 32, 5015 );
Effects.PlaySound( loc, item.Map, 0x1F0 );
item.TrapType = TrapType.None;
item.TrapPower = 0;
item.TrapLevel = 0;
}
FinishSequence();
}
private class InternalTarget : Target
{
private RemoveTrapSpell m_Owner;
public InternalTarget( RemoveTrapSpell owner ) : base( 12, false, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is TrapableContainer )
{
m_Owner.Target( (TrapableContainer)o );
}
else
{
from.SendMessage( "You can't disarm that" );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,74 @@
using System;
using Server.Targeting;
using Server.Network;
namespace Server.Spells.Second
{
public class StrengthSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Strength", "Uus Mani",
SpellCircle.Second,
212,
9061,
Reagent.MandrakeRoot,
Reagent.Nightshade
);
public StrengthSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( Mobile m )
{
if ( !Caster.CanSee( m ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( CheckBSequence( m ) )
{
SpellHelper.Turn( Caster, m );
SpellHelper.AddStatBonus( Caster, m, StatType.Str );
m.FixedParticles( 0x375A, 10, 15, 5017, EffectLayer.Waist );
m.PlaySound( 0x1EE );
int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, false )*100);
TimeSpan length = SpellHelper.GetDuration( Caster, m );
BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Strength, 1075845, length, m, percentage.ToString() ) );
}
FinishSequence();
}
private class InternalTarget : Target
{
private StrengthSpell m_Owner;
public InternalTarget( StrengthSpell owner ) : base( 12, false, TargetFlags.Beneficial )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
{
m_Owner.Target( (Mobile)o );
}
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,138 @@
using System;
using System.Collections;
using Server.Network;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Seventh
{
public class ChainLightningSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Chain Lightning", "Vas Ort Grav",
SpellCircle.Seventh,
209,
9022,
false,
Reagent.BlackPearl,
Reagent.Bloodmoss,
Reagent.MandrakeRoot,
Reagent.SulfurousAsh
);
public ChainLightningSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override bool DelayedDamage{ get{ return true; } }
public void Target( IPoint3D p )
{
if ( !Caster.CanSee( p ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() )
{
SpellHelper.Turn( Caster, p );
if ( p is Item )
p = ((Item)p).GetWorldLocation();
ArrayList targets = new ArrayList();
Map map = Caster.Map;
bool playerVsPlayer = false;
if ( map != null )
{
IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( p ), 2 );
foreach ( Mobile m in eable )
{
if ( Core.AOS && m == Caster )
continue;
if ( SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) )
{
if ( Core.AOS && !Caster.InLOS( m ) )
continue;
targets.Add( m );
if ( m.Player )
playerVsPlayer = true;
}
}
eable.Free();
}
double damage;
if ( Core.AOS )
damage = GetNewAosDamage( 51, 1, 5, playerVsPlayer );
else
damage = Utility.Random( 27, 22 );
if ( targets.Count > 0 )
{
if ( Core.AOS && targets.Count > 2 )
damage = (damage * 2) / targets.Count;
else if ( !Core.AOS )
damage /= targets.Count;
for ( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
double toDeal = damage;
if ( !Core.AOS && CheckResisted( m ) )
{
toDeal *= 0.5;
m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy.
}
Caster.DoHarmful( m );
SpellHelper.Damage( this, m, toDeal, 0, 0, 0, 0, 100 );
m.BoltEffect( 0 );
}
}
}
FinishSequence();
}
private class InternalTarget : Target
{
private ChainLightningSpell m_Owner;
public InternalTarget( ChainLightningSpell owner ) : base( 12, true, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
IPoint3D p = o as IPoint3D;
if ( p != null )
m_Owner.Target( p );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -0,0 +1,190 @@
using System;
using Server.Targeting;
using Server.Network;
using Server.Misc;
using Server.Items;
namespace Server.Spells.Seventh
{
public class EnergyFieldSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo(
"Energy Field", "In Sanct Grav",
SpellCircle.Seventh,
221,
9022,
false,
Reagent.BlackPearl,
Reagent.MandrakeRoot,
Reagent.SpidersSilk,
Reagent.SulfurousAsh
);
public EnergyFieldSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public void Target( IPoint3D p )
{
if ( !Caster.CanSee( p ) )
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() )
{
SpellHelper.Turn( Caster, p );
SpellHelper.GetSurfaceTop( ref p );
int dx = Caster.Location.X - p.X;
int dy = Caster.Location.Y - p.Y;
int rx = (dx - dy) * 44;
int ry = (dx + dy) * 44;
bool eastToWest;
if ( rx >= 0 && ry >= 0 )
{
eastToWest = false;
}
else if ( rx >= 0 )
{
eastToWest = true;
}
else if ( ry >= 0 )
{
eastToWest = true;
}
else
{
eastToWest = false;
}
Effects.PlaySound( p, Caster.Map, 0x20B );
TimeSpan duration;
if ( Core.AOS )
duration = TimeSpan.FromSeconds( (15 + (Caster.Skills.Magery.Fixed / 5)) / 7 );
else
duration = TimeSpan.FromSeconds( Caster.Skills[SkillName.Magery].Value * 0.28 + 2.0 ); // (28% of magery) + 2.0 seconds
int itemID = eastToWest ? 0x3946 : 0x3956;
for ( int i = -2; i <= 2; ++i )
{
Point3D loc = new Point3D( eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z );
bool canFit = SpellHelper.AdjustField( ref loc, Caster.Map, 12, false );
if ( !canFit )
continue;
Item item = new InternalItem( loc, Caster.Map, duration, itemID, Caster );
item.ProcessDelta();
Effects.SendLocationParticles( EffectItem.Create( loc, Caster.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5051 );
}
}
FinishSequence();
}
[DispellableField]
private class InternalItem : Item
{
private Timer m_Timer;
public override bool BlocksFit{ get{ return true; } }
public InternalItem( Point3D loc, Map map, TimeSpan duration, int itemID, Mobile caster ) : base( itemID )
{
Visible = false;
Movable = false;
Light = LightType.Circle300;
MoveToWorld( loc, map );
if ( caster.InLOS( this ) )
Visible = true;
else
Delete();
if ( Deleted )
return;
m_Timer = new InternalTimer( this, duration );
m_Timer.Start();
}
public InternalItem( Serial serial ) : base( serial )
{
m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 5.0 ) );
m_Timer.Start();
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if ( m_Timer != null )
m_Timer.Stop();
}
private class InternalTimer : Timer
{
private InternalItem m_Item;
public InternalTimer( InternalItem item, TimeSpan duration ) : base( duration )
{
Priority = TimerPriority.OneSecond;
m_Item = item;
}
protected override void OnTick()
{
m_Item.Delete();
}
}
}
private class InternalTarget : Target
{
private EnergyFieldSpell m_Owner;
public InternalTarget( EnergyFieldSpell owner ) : base( 12, true, TargetFlags.None )
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is IPoint3D )
m_Owner.Target( (IPoint3D)o );
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more