Overwrite

Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
Unstable Kitsune
2023-11-28 23:20:26 -05:00
parent 3cd54811de
commit b918192e4e
11608 changed files with 2644205 additions and 47 deletions

View File

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

View File

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

View File

@@ -0,0 +1,420 @@
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Network;
using Server.Spells.Bushido;
using Server.Spells.Ninjitsu;
using Server.Spells.SkillMasteries;
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 int GetAccuracyBonus(Mobile attacker)
{
return 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 void SendAbilityMessage(Mobile m)
{
TextDefinition.SendMessageTo(m, AbilityMessage);
}
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[this.MoveSkill].Value < this.RequiredSkill)
{
string args = String.Format("{0}\t{1}\t ", this.RequiredSkill.ToString("F1"), this.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 (ManaPhasingOrb.IsInManaPhase(m))
{
ManaPhasingOrb.RemoveFromTable(m);
return 0;
}
if (!Server.Spells.Necromancy.MindRotSpell.GetMindRotScalar(m, ref scalar))
{
scalar = 1.0;
}
if (Server.Spells.Mysticism.PurgeMagicSpell.IsUnderCurseEffects(m))
{
scalar += .5;
}
// Lower Mana Cost = 40%
int lmc = Math.Min(AosAttributes.GetValue(m, AosAttribute.LowerManaCost), 40);
lmc += BaseArmor.GetInherentLowerManaCost(m);
scalar -= (double)lmc / 100;
int total = (int)(mana * scalar);
if (m.Skills[this.MoveSkill].Value < 50.0 && GetContext(m) != null)
total *= 2;
return total;
}
public virtual bool CheckMana(Mobile from, bool consume)
{
int mana = this.ScaleMana(from, this.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 (!this.DelayedContext)
this.SetContext(from);
from.Mana -= mana;
}
return true;
}
public virtual void SetContext(Mobile from)
{
if (GetContext(from) == null)
{
if (this.DelayedContext || from.Skills[this.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 this.CheckSkills(from) && this.CheckMana(from, false);
}
public virtual void CheckGain(Mobile m)
{
m.CheckSkill(this.MoveSkill, this.RequiredSkill, this.RequiredSkill + 37.5);
}
private static readonly Dictionary<Mobile, SpecialMove> m_Table = new Dictionary<Mobile, SpecialMove>();
public static Dictionary<Mobile, SpecialMove> Table
{
get
{
return m_Table;
}
}
public static void ClearAllMoves(Mobile m)
{
foreach (KeyValuePair<Int32, SpecialMove> kvp in SpellRegistry.SpecialMoves)
{
int moveID = kvp.Key;
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 = null;
m_Table.TryGetValue(m, out move);
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));
move.SendAbilityMessage(m);
SkillMasterySpell.CancelSpecialMove(m);
}
return true;
}
public static void ClearCurrentMove(Mobile m)
{
SpecialMove move = null;
m_Table.TryGetValue(m, out move);
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 readonly Dictionary<Mobile, SpecialMoveContext> m_PlayersTable = new Dictionary<Mobile, SpecialMoveContext>();
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.ContainsKey(m) ? m_PlayersTable[m] : null);
}
public static bool GetContext(Mobile m, Type type)
{
SpecialMoveContext context = null;
m_PlayersTable.TryGetValue(m, out context);
if (context == null)
return false;
return (context.Type == type);
}
private class SpecialMoveTimer : Timer
{
private readonly Mobile m_Mobile;
public SpecialMoveTimer(Mobile from)
: base(TimeSpan.FromSeconds(3.0))
{
this.m_Mobile = from;
this.Priority = TimerPriority.TwentyFiveMS;
}
protected override void OnTick()
{
RemoveContext(this.m_Mobile);
}
}
public class SpecialMoveContext
{
private readonly Timer m_Timer;
private readonly Type m_Type;
public Timer Timer
{
get
{
return this.m_Timer;
}
}
public Type Type
{
get
{
return this.m_Type;
}
}
public SpecialMoveContext(Timer timer, Type type)
{
this.m_Timer = timer;
this.m_Type = type;
}
}
}
}

1401
Scripts/Spells/Base/Spell.cs Normal file

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
namespace Server.Spells
{
public class SpellRegistry
{
private static readonly Type[] m_Types = new Type[745];
private static int m_Count;
public static Type[] Types
{
get
{
m_Count = -1;
return m_Types;
}
}
//What IS this used for anyways.
public static int Count
{
get
{
if (m_Count == -1)
{
m_Count = 0;
for (int i = 0; i < m_Types.Length; ++i)
if (m_Types[i] != null)
++m_Count;
}
return m_Count;
}
}
private static readonly Dictionary<Type, Int32> m_IDsFromTypes = new Dictionary<Type, Int32>(m_Types.Length);
private static readonly Dictionary<Int32, SpecialMove> m_SpecialMoves = new Dictionary<Int32, SpecialMove>();
public static Dictionary<Int32, SpecialMove> SpecialMoves
{
get
{
return m_SpecialMoves;
}
}
public static int GetRegistryNumber(ISpell s)
{
return GetRegistryNumber(s.GetType());
}
public static int GetRegistryNumber(SpecialMove s)
{
return GetRegistryNumber(s.GetType());
}
public static int GetRegistryNumber(Type type)
{
if (m_IDsFromTypes.ContainsKey(type))
return m_IDsFromTypes[type];
return -1;
}
public static void Register(int spellID, Type type)
{
if (spellID < 0 || spellID >= m_Types.Length)
return;
if (m_Types[spellID] == null)
++m_Count;
m_Types[spellID] = type;
if (!m_IDsFromTypes.ContainsKey(type))
m_IDsFromTypes.Add(type, spellID);
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)) || !m_SpecialMoves.ContainsKey(spellID))
return null;
return m_SpecialMoves[spellID];
}
private static readonly 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 readonly string[] m_CircleNames = new string[]
{
"First",
"Second",
"Third",
"Fourth",
"Fifth",
"Sixth",
"Seventh",
"Eighth",
"Necromancy",
"Chivalry",
"Bushido",
"Ninjitsu",
"Spellweaving",
#region Stygian Abyss
"Mystic",
#endregion
#region TOL
"SkillMasteries"
#endregion
};
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,199 @@
using System;
using System.Collections.Generic;
namespace Server.Spells.Bushido
{
public class Confidence : SamuraiSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Confidence", null,
-1,
9002);
private static Dictionary<Mobile, Timer> m_Table = new Dictionary<Mobile, Timer>();
private static Dictionary<Mobile, Timer> m_RegenTable = new Dictionary<Mobile, Timer>();
public Confidence(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(0.25);
}
}
public override double RequiredSkill
{
get
{
return 25.0;
}
}
public override int RequiredMana
{
get
{
return 10;
}
}
public static bool IsConfident(Mobile m)
{
return m_Table.ContainsKey(m);
}
public static void BeginConfidence(Mobile m)
{
Timer t;
if (m_Table.TryGetValue(m, out t))
t.Stop();
t = new InternalTimer(m);
m_Table[m] = t;
t.Start();
double bushido = m.Skills[SkillName.Bushido].Value;
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Confidence, 1060596, 1153809, TimeSpan.FromSeconds(4), m, String.Format("{0}\t{1}\t{2}", ((int)(bushido / 12)).ToString(), ((int)(bushido / 5)).ToString(), "100"))); // Successful parry will heal for 1-~1_HEAL~ hit points and refresh for 1-~2_STAM~ stamina points.<br>+~3_HP~ hit point regeneration (4 second duration).
int anticipateHitBonus = SkillMasteries.MasteryInfo.AnticipateHitBonus(m);
if (anticipateHitBonus > 0)
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.AnticipateHit, 1155905, 1156057, TimeSpan.FromSeconds(4), m, String.Format("{0}\t{1}", anticipateHitBonus.ToString(), "75"))); // ~1_CHANCE~% chance to reduce Confidence heal by ~2_REDUCE~% when hit.
}
public static void EndConfidence(Mobile m)
{
if (!m_Table.ContainsKey(m))
return;
Timer t = m_Table[m];
t.Stop();
m_Table.Remove(m);
OnEffectEnd(m, typeof(Confidence));
BuffInfo.RemoveBuff(m, BuffIcon.Confidence);
BuffInfo.RemoveBuff(m, BuffIcon.AnticipateHit);
}
public static bool IsRegenerating(Mobile m)
{
return m_RegenTable.ContainsKey(m);
}
public static void BeginRegenerating(Mobile m)
{
Timer t;
if (m_RegenTable.TryGetValue(m, out t))
t.Stop();
t = new RegenTimer(m);
m_RegenTable[m] = t;
t.Start();
}
public static void StopRegenerating(Mobile m)
{
Timer t;
int anticipateHitBonus = SkillMasteries.MasteryInfo.AnticipateHitBonus(m);
if (anticipateHitBonus >= Utility.Random(100) && m_RegenTable.TryGetValue(m, out t))
{
if (t is RegenTimer)
((RegenTimer)t).Hits /= 2;
return;
}
if (m_RegenTable.TryGetValue(m, out t))
t.Stop();
if (m_RegenTable.ContainsKey(m))
m_RegenTable.Remove(m);
BuffInfo.RemoveBuff(m, BuffIcon.AnticipateHit);
}
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 class InternalTimer : Timer
{
private readonly 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 class RegenTimer : Timer
{
private Mobile m_Mobile;
private int m_Ticks;
private int m_Hits;
public int Hits { get { return m_Hits; } set { m_Hits = value; } }
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,131 @@
using System;
using System.Collections;
using Server.Items;
namespace Server.Spells.Bushido
{
public class CounterAttack : SamuraiSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"CounterAttack", null,
-1,
9002);
private static readonly Hashtable m_Table = new Hashtable();
public CounterAttack(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(0.25);
}
}
public override double RequiredSkill
{
get
{
return 40.0;
}
}
public override int RequiredMana
{
get
{
return 5;
}
}
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;
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.CounterAttack, 1060598, 1063266, TimeSpan.FromSeconds(30), m));
t.Start();
}
public static void StopCountering(Mobile m)
{
Timer t = (Timer)m_Table[m];
if (t != null)
t.Stop();
m_Table.Remove(m);
BuffInfo.RemoveBuff(m, BuffIcon.CounterAttack);
OnEffectEnd(m, typeof(CounterAttack));
}
public override bool CheckCast()
{
if (!base.CheckCast())
return false;
if (this.Caster.FindItemOnLayer(Layer.TwoHanded) as BaseShield != null)
return true;
if (this.Caster.FindItemOnLayer(Layer.OneHanded) as BaseWeapon != null)
return true;
if (this.Caster.FindItemOnLayer(Layer.TwoHanded) as BaseWeapon != null)
return true;
this.Caster.SendLocalizedMessage(1062944); // You must have a weapon or a shield equipped to use this ability!
return false;
}
public override void OnBeginCast()
{
base.OnBeginCast();
this.Caster.FixedEffect(0x37C4, 10, 7, 4, 3);
}
public override void OnCast()
{
if (this.CheckSequence())
{
this.Caster.SendLocalizedMessage(1063118); // You prepare to respond immediately to the next blocked blow.
this.OnCastSuccessful(this.Caster);
StartCountering(this.Caster);
}
this.FinishSequence();
}
private class InternalTimer : Timer
{
private readonly Mobile m_Mobile;
public InternalTimer(Mobile m)
: base(TimeSpan.FromSeconds(30.0))
{
this.m_Mobile = m;
this.Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
StopCountering(this.m_Mobile);
this.m_Mobile.SendLocalizedMessage(1063119); // You return to your normal stance.
}
}
}
}

View File

@@ -0,0 +1,259 @@
using System;
using System.Collections;
using Server.Items;
namespace Server.Spells.Bushido
{
public class Evasion : SamuraiSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Evasion", null,
-1,
9002);
private static readonly Hashtable m_Table = new Hashtable();
public Evasion(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(0.25);
}
}
public override double RequiredSkill
{
get
{
return 60.0;
}
}
public override int RequiredMana
{
get
{
return 10;
}
}
public static bool VerifyCast(Mobile Caster, bool messages)
{
if (Caster == null) // Sanity
return false;
BaseWeapon weap = Caster.FindItemOnLayer(Layer.OneHanded) as BaseWeapon;
if (weap == null)
weap = Caster.FindItemOnLayer(Layer.TwoHanded) as BaseWeapon;
if (weap != null)
{
if (Core.ML && Caster.Skills[weap.Skill].Base < 50)
{
if (messages)
{
Caster.SendLocalizedMessage(1076206); // Your skill with your equipped weapon must be 50 or higher to use Evasion.
}
return false;
}
}
else if (!(Caster.FindItemOnLayer(Layer.TwoHanded) is BaseShield))
{
if (messages)
{
Caster.SendLocalizedMessage(1062944); // You must have a weapon or a shield equipped to use this ability!
}
return false;
}
if (!Caster.CanBeginAction(typeof(Evasion)))
{
if (messages)
{
Caster.SendLocalizedMessage(501789); // You must wait before trying again.
}
return false;
}
return true;
}
public static bool CheckSpellEvasion(Mobile defender)
{
BaseWeapon weap = defender.FindItemOnLayer(Layer.OneHanded) as BaseWeapon;
if (weap == null)
weap = defender.FindItemOnLayer(Layer.TwoHanded) as BaseWeapon;
if (Core.ML)
{
if (defender.Spell != null && defender.Spell.IsCasting)
{
return false;
}
if (weap != null)
{
if (defender.Skills[weap.Skill].Base < 50)
{
return false;
}
}
else if (!(defender.FindItemOnLayer(Layer.TwoHanded) is BaseShield))
{
return false;
}
}
if (IsEvading(defender) && BaseWeapon.CheckParry(defender))
{
defender.Emote("*evades*"); // Yes. Eew. Blame OSI.
defender.FixedEffect(0x37B9, 10, 16);
if (Core.SA)
{
defender.Animate(AnimationType.Block, 0);
}
return true;
}
return false;
}
public static bool IsEvading(Mobile m)
{
return m_Table.Contains(m);
}
public static TimeSpan GetEvadeDuration(Mobile m)
{
/* Evasion duration now scales with Bushido skill
*
* If the player has higher than GM Bushido, and GM Tactics and Anatomy, they get a 1 second bonus
* Evasion duration range:
* o 3-6 seconds w/o tactics/anatomy
* o 6-7 seconds w/ GM+ Bushido and GM tactics/anatomy
*/
if (!Core.ML)
return TimeSpan.FromSeconds(8.0);
double seconds = 3;
if (m.Skills.Bushido.Value > 60)
seconds += (m.Skills.Bushido.Value - 60) / 20;
if (m.Skills.Anatomy.Value >= 100.0 && m.Skills.Tactics.Value >= 100.0 && m.Skills.Bushido.Value > 100.0) //Bushido being HIGHER than 100 for bonus is intended
seconds++;
return TimeSpan.FromSeconds((int)seconds);
}
public static double GetParryScalar(Mobile m)
{
/* Evasion modifier to parry now scales with Bushido skill
*
* If the player has higher than GM Bushido, and at least GM Tactics and Anatomy, they get a bonus to their evasion modifier (10% bonus to the evasion modifier to parry NOT 10% to the final parry chance)
*
* Bonus modifier to parry range: (these are the ranges for the evasion modifier)
* o 16-40% bonus w/o tactics/anatomy
* o 42-50% bonus w/ GM+ bushido and GM tactics/anatomy
*/
if (!Core.ML)
return 1.5;
double bonus = 0;
if (m.Skills.Bushido.Value >= 60)
bonus += (((m.Skills.Bushido.Value - 60) * .004) + 0.16);
if (m.Skills.Anatomy.Value >= 100 && m.Skills.Tactics.Value >= 100 && m.Skills.Bushido.Value > 100) //Bushido being HIGHER than 100 for bonus is intended
bonus += 0.10;
return 1.0 + bonus;
}
public static void BeginEvasion(Mobile m)
{
Timer t = (Timer)m_Table[m];
if (t != null)
t.Stop();
TimeSpan duration = GetEvadeDuration(m);
t = new InternalTimer(m, duration);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Evasion, 1060597, 1153810, duration, 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);
BuffInfo.RemoveBuff(m, BuffIcon.Evasion);
OnEffectEnd(m, typeof(Evasion));
}
public override bool CheckCast()
{
if (VerifyCast(this.Caster, true))
return base.CheckCast();
return false;
}
public override void OnBeginCast()
{
base.OnBeginCast();
this.Caster.FixedEffect(0x37C4, 10, 7, 4, 3);
}
public override void OnCast()
{
if (this.CheckSequence())
{
this.Caster.SendLocalizedMessage(1063120); // You feel that you might be able to deflect any attack!
this.Caster.FixedParticles(0x376A, 1, 20, 0x7F5, 0x960, 3, EffectLayer.Waist);
this.Caster.PlaySound(0x51B);
this.OnCastSuccessful(this.Caster);
BeginEvasion(this.Caster);
this.Caster.BeginAction(typeof(Evasion));
Timer.DelayCall(TimeSpan.FromSeconds(20.0), delegate { this.Caster.EndAction(typeof(Evasion)); });
}
this.FinishSequence();
}
private class InternalTimer : Timer
{
private readonly Mobile m_Mobile;
public InternalTimer(Mobile m, TimeSpan delay)
: base(delay)
{
this.m_Mobile = m;
this.Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
EndEvasion(this.m_Mobile);
this.m_Mobile.SendLocalizedMessage(1063121); // You no longer feel that you could deflect any attack.
}
}
}
}

View File

@@ -0,0 +1,206 @@
using System;
using System.Collections;
namespace Server.Spells.Bushido
{
public class HonorableExecution : SamuraiMove
{
private static readonly Hashtable m_Table = new Hashtable();
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 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);
}
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 (!this.Validate(attacker) || !this.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);
BuffInfo.AddBuff(attacker, new BuffInfo(BuffIcon.HonorableExecution, 1060595, 1153808, TimeSpan.FromSeconds(7.0), attacker, String.Format("{0}\t40\t40\t40\t40\t40", resSpells)));
m_Table[attacker] = info;
}
attacker.Delta(MobileDelta.WeaponDamage);
this.CheckGain(attacker);
}
public void EndEffect(object state)
{
HonorableExecutionInfo info = (HonorableExecutionInfo)state;
if(info.m_Mobile != null)
info.m_Mobile.Delta(MobileDelta.WeaponDamage);
RemovePenalty(info.m_Mobile);
}
private class HonorableExecutionInfo
{
public readonly Mobile m_Mobile;
public readonly int m_SwingBonus;
public readonly ArrayList m_Mods;
public readonly 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)
{
this.m_Mobile = from;
this.m_SwingBonus = swingBonus;
this.m_Mods = mods;
this.m_Penalty = penalty;
this.Apply();
}
public void Apply()
{
if (this.m_Mods == null)
return;
for (int i = 0; i < this.m_Mods.Count; ++i)
{
object mod = this.m_Mods[i];
if (mod is ResistanceMod)
this.m_Mobile.AddResistanceMod((ResistanceMod)mod);
else if (mod is SkillMod)
this.m_Mobile.AddSkillMod((SkillMod)mod);
}
}
public void Clear()
{
if (this.m_Mods == null)
return;
for (int i = 0; i < this.m_Mods.Count; ++i)
{
object mod = this.m_Mods[i];
if (mod is ResistanceMod)
this.m_Mobile.RemoveResistanceMod((ResistanceMod)mod);
else if (mod is SkillMod)
this.m_Mobile.RemoveSkillMod((SkillMod)mod);
}
}
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using Server.Mobiles;
namespace Server.Spells.Bushido
{
public class LightningStrike : SamuraiMove
{
public LightningStrike()
{
}
public override int BaseMana
{
get
{
return Core.SA ? 10 : 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 bool ValidatesDuringHit
{
get
{
return false;
}
}
public override int GetAccuracyBonus(Mobile attacker)
{
return 50;
}
public override bool Validate(Mobile from)
{
bool isValid = base.Validate(from);
if (isValid)
{
var ThePlayer = from as PlayerMobile;
if(ThePlayer != null)
{
ThePlayer.ExecutesLightningStrike = BaseMana;
}
}
return isValid;
}
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)
{
/* no mana drain before actual hit */
bool enoughMana = CheckMana(attacker, false);
return Validate(attacker);
}
public override bool OnBeforeDamage(Mobile attacker, Mobile defender)
{
ClearCurrentMove(attacker);
if (CheckMana(attacker, true))
{
attacker.SendLocalizedMessage(1063168); // You attack with lightning precision!
defender.SendLocalizedMessage(1063169); // Your opponent's quick strike causes extra damage!
defender.FixedParticles(0x3818, 1, 11, 0x13A8, 0, 0, EffectLayer.Waist);
defender.PlaySound(0x51D);
CheckGain(attacker);
SetContext(attacker);
}
return base.OnBeforeDamage(attacker, defender);
}
public override void CheckGain(Mobile m)
{
// Lighning strike will gain to 120, albeit slow
if (Core.SA && m.Skills[MoveSkill].Value >= 87.5)
{
if (0.25 > Utility.RandomDouble())
{
m.CheckSkill(MoveSkill, 0, m.Skills[MoveSkill].Cap);
}
}
else
{
base.CheckGain(m);
}
}
public override void OnUse(Mobile m)
{
base.OnUse(m);
double bushido = m.Skills[SkillName.Bushido].Value;
int criticalChance = (int)((bushido * bushido) / 720.0);
m.Delta(MobileDelta.WeaponDamage);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.LightningStrike, 1060599, 1153811, String.Format("50\t{0}", criticalChance)));
}
public override void OnClearMove(Mobile attacker)
{
var ThePlayer = attacker as PlayerMobile; // this can be deletet if the PlayerMobile parts are moved to Server.Mobile
if(ThePlayer != null)
{
ThePlayer.ExecutesLightningStrike = 0;
}
attacker.Delta(MobileDelta.WeaponDamage);
BuffInfo.RemoveBuff(attacker, BuffIcon.LightningStrike);
}
}
}

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using Server.Items;
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 (!this.Validate(attacker) || !this.CheckMana(attacker, false))
return;
ClearCurrentMove(attacker);
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
List<Mobile> targets = new List<Mobile>();
IPooledEnumerable eable = attacker.GetMobilesInRange(weapon.MaxRange);
foreach (Mobile m in eable)
{
if (m != defender && m != attacker && m.CanBeHarmful(attacker, false) && attacker.InLOS(m) &&
Server.Spells.SpellHelper.ValidIndirectTarget(attacker, m))
{
targets.Add(m);
}
}
eable.Free();
if (targets.Count > 0)
{
if (!this.CheckMana(attacker, true))
return;
Mobile target = 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);
attacker.PlaySound(0x510);
weapon.OnSwing(attacker, target, damageBonus);
if (defender.Alive)
attacker.Combatant = defender;
this.CheckGain(attacker);
}
else
{
attacker.SendLocalizedMessage(1063123); // There are no valid targets to attack!
}
ColUtility.Free(targets);
}
public override void OnUse(Mobile m)
{
base.OnUse(m);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.MomentumStrike, 1060600, 1063268));
}
public override void OnClearMove(Mobile from)
{
base.OnClearMove(from);
BuffInfo.RemoveBuff(from, BuffIcon.MomentumStrike);
}
public override void CheckGain(Mobile m)
{
m.CheckSkill(this.MoveSkill, this.RequiredSkill, 120.0);
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
namespace Server.Spells
{
public class SamuraiMove : SpecialMove
{
public override SkillName MoveSkill
{
get
{
return SkillName.Bushido;
}
}
public override void CheckGain(Mobile m)
{
m.CheckSkill(this.MoveSkill, this.RequiredSkill - 12.5, this.RequiredSkill + 37.5); //Per five on friday 02/16/07
}
}
}

View File

@@ -0,0 +1,167 @@
using System;
using Server.Mobiles;
using Server.Network;
namespace Server.Spells.Bushido
{
public abstract class SamuraiSpell : Spell
{
public SamuraiSpell(Mobile caster, Item scroll, SpellInfo info)
: base(caster, scroll, info)
{
}
public abstract double RequiredSkill { get; }
public abstract int RequiredMana { get; }
public override SkillName CastSkill
{
get
{
return SkillName.Bushido;
}
}
public override SkillName DamageSkill
{
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 double CastDelayFastScalar
{
get
{
return 0;
}
}
public override int CastRecoveryBase
{
get
{
return 7;
}
}
public static bool CheckExpansion(Mobile from)
{
if (!Core.SE)
return false;
if (!(from is PlayerMobile))
return true;
if (from.NetState == null)
return false;
return from.NetState.SupportsExpansion(Expansion.SE);
}
public static void OnEffectEnd(Mobile caster, Type type)
{
int spellID = SpellRegistry.GetRegistryNumber(type);
if (spellID > 0)
caster.Send(new ToggleSpecialAbility(spellID + 1, false));
}
public override bool CheckCast()
{
int mana = this.ScaleMana(this.RequiredMana);
if (!base.CheckCast())
return false;
if (!CheckExpansion(this.Caster))
{
this.Caster.SendLocalizedMessage(1063456); // You must upgrade to Samurai Empire in order to use that ability.
return false;
}
if (this.Caster.Skills[this.CastSkill].Value < this.RequiredSkill)
{
string args = String.Format("{0}\t{1}\t ", this.RequiredSkill.ToString("F1"), this.CastSkill.ToString());
this.Caster.SendLocalizedMessage(1063013, args); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
return false;
}
else if (this.Caster.Mana < mana)
{
this.Caster.SendLocalizedMessage(1060174, mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
return false;
}
return true;
}
public override bool CheckFizzle()
{
int mana = this.ScaleMana(this.RequiredMana);
if (this.Caster.Skills[this.CastSkill].Value < this.RequiredSkill)
{
this.Caster.SendLocalizedMessage(1070768, this.RequiredSkill.ToString("F1")); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack!
return false;
}
else if (this.Caster.Mana < mana)
{
this.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;
this.Caster.Mana -= mana;
return true;
}
public override void GetCastSkills(out double min, out double max)
{
min = this.RequiredSkill - 12.5; //per 5 on friday, 2/16/07
max = this.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));
}
}
}

View File

@@ -0,0 +1,146 @@
using System;
using Server.Targeting;
namespace Server.Spells.Chivalry
{
public class CleanseByFireSpell : PaladinSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Cleanse By Fire", "Expor Flamus",
-1,
9002);
public CleanseByFireSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.0);
}
}
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 override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable)
{
return true;
}
public void Target(Mobile m)
{
if (!m.Poisoned)
{
this.Caster.SendLocalizedMessage(1060176); // That creature is not poisoned!
}
else if (this.CheckBSequence(m))
{
SpellHelper.Turn(this.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)(this.Caster.Skills[SkillName.Chivalry].Value * 75) - ((p.RealLevel + 1) * 2000);
chanceToCure /= 100;
if (chanceToCure > Utility.Random(100))
{
if (m.CurePoison(this.Caster))
{
if (this.Caster != m)
this.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);
this.Caster.PlaySound(0x208);
this.Caster.FixedParticles(0x3709, 1, 30, 9934, 0, 7, EffectLayer.Waist);
int damage = 50 - this.ComputePowerValue(4);
// TODO: Should caps be applied?
if (damage < 13)
damage = 13;
else if (damage > 55)
damage = 55;
AOS.Damage(this.Caster, this.Caster, damage, 0, 100, 0, 0, 0, true);
}
this.FinishSequence();
}
private class InternalTarget : Target
{
private readonly CleanseByFireSpell m_Owner;
public InternalTarget(CleanseByFireSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Beneficial)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
this.m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,141 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Chivalry
{
public class CloseWoundsSpell : PaladinSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Close Wounds", "Obsu Vulni",
-1,
9002);
public CloseWoundsSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.5);
}
}
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 override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable)
{
return true;
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (!this.Caster.InRange(m, 2))
{
this.Caster.SendLocalizedMessage(1060178); // You are too far away to perform that action!
}
else if (m is BaseCreature && ((BaseCreature)m).IsAnimatedDead)
{
this.Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive.
}
else if (m.IsDeadBondedPet)
{
this.Caster.SendLocalizedMessage(1060177); // You cannot heal a creature that is already dead!
}
else if (m.Hits >= m.HitsMax)
{
this.Caster.SendLocalizedMessage(500955); // That being is not damaged!
}
else if (m.Poisoned || Server.Items.MortalStrike.IsWounded(m))
{
this.Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, (this.Caster == m) ? 1005000 : 1010398);
}
else if (this.CheckBSequence(m))
{
SpellHelper.Turn(this.Caster, m);
/* Heals the target for 7 to 39 points of damage.
* The caster's Karma affects the amount of damage healed.
*/
int toHeal = this.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; //Was previosuly due to the message
//m.Heal( toHeal, Caster, false );
SpellHelper.Heal(toHeal, m, this.Caster, false);
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);
}
this.FinishSequence();
}
private class InternalTarget : Target
{
private readonly CloseWoundsSpell m_Owner;
public InternalTarget(CloseWoundsSpell owner)
: base(12, false, TargetFlags.Beneficial)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
this.m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,231 @@
using System;
using System.Collections.Generic;
using Server.Items;
namespace Server.Spells.Chivalry
{
public class ConsecrateWeaponSpell : PaladinSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Consecrate Weapon", "Consecrus Arma",
-1,
9002);
private static Dictionary<Mobile, ConsecratedWeaponContext> m_Table = new Dictionary<Mobile, ConsecratedWeaponContext>();
public ConsecrateWeaponSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(0.5);
}
}
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 override void OnCast()
{
BaseWeapon weapon = this.Caster.Weapon as BaseWeapon;
if (Caster.Player && (weapon == null || weapon is Fists))
{
this.Caster.SendLocalizedMessage(501078); // You must be holding a weapon.
}
else if (this.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;
}
this.Caster.PlaySound(0x20C);
this.Caster.PlaySound(soundID);
this.Caster.FixedParticles(0x3779, 1, 30, 9964, 3, 3, EffectLayer.Waist);
IEntity from = new Entity(Serial.Zero, new Point3D(this.Caster.X, this.Caster.Y, this.Caster.Z), this.Caster.Map);
IEntity to = new Entity(Serial.Zero, new Point3D(this.Caster.X, this.Caster.Y, this.Caster.Z + 50), this.Caster.Map);
Effects.SendMovingParticles(from, to, itemID, 1, 0, false, false, 33, 3, 9501, 1, 0, EffectLayer.Head, 0x100);
double seconds = this.ComputePowerValue(20);
// TODO: Should caps be applied?
int pkarma = this.Caster.Karma;
if (pkarma > 5000)
seconds = 11.0;
else if (pkarma >= 4999)
seconds = 10.0;
else if (pkarma >= 3999)
seconds = 9.00;
else if (pkarma >= 2999)
seconds = 8.0;
else if (pkarma >= 1999)
seconds = 7.0;
else if (pkarma >= 999)
seconds = 6.0;
else
seconds = 5.0;
TimeSpan duration = TimeSpan.FromSeconds(seconds);
ConsecratedWeaponContext context;
if (IsUnderEffects(Caster))
{
context = m_Table[Caster];
if (context.Timer != null)
{
context.Timer.Stop();
context.Timer = null;
}
context.Weapon = weapon;
}
else
{
context = new ConsecratedWeaponContext(Caster, weapon);
}
weapon.ConsecratedContext = context;
context.Timer = Timer.DelayCall<Mobile>(duration, RemoveEffects, Caster);
m_Table[Caster] = context;
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.ConsecrateWeapon, 1151385, 1151386, duration, Caster, String.Format("{0}\t{1}", context.ConsecrateProcChance, context.ConsecrateDamageBonus)));
}
this.FinishSequence();
}
public static bool IsUnderEffects(Mobile m)
{
return m_Table.ContainsKey(m);
}
public static void RemoveEffects(Mobile m)
{
if (m_Table.ContainsKey(m))
{
var context = m_Table[m];
context.Expire();
m_Table.Remove(m);
}
}
}
public class ConsecratedWeaponContext
{
public Mobile Owner { get; private set; }
public BaseWeapon Weapon { get; set; }
public Timer Timer { get; set; }
public int ConsecrateProcChance
{
get
{
if (!Core.SA || Owner.Skills.Chivalry.Value >= 80)
{
return 100;
}
return (int)Owner.Skills.Chivalry.Value;
}
}
public int ConsecrateDamageBonus
{
get
{
if (Core.SA)
{
double value = Owner.Skills.Chivalry.Value;
if (value >= 90)
{
return (int)Math.Truncate((value - 90) / 2);
}
}
return 0;
}
}
public ConsecratedWeaponContext(Mobile owner, BaseWeapon weapon)
{
Owner = owner;
Weapon = weapon;
}
public void Expire()
{
Weapon.ConsecratedContext = null;
Effects.PlaySound(Weapon.GetWorldLocation(), Weapon.Map, 0x1F8);
if (Timer != null)
{
Timer.Stop();
Timer = null;
}
}
}
}

View File

@@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Items;
using Server.Mobiles;
using Server.Spells.Necromancy;
namespace Server.Spells.Chivalry
{
public class DispelEvilSpell : PaladinSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Dispel Evil", "Dispiro Malas",
-1,
9002);
public DispelEvilSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(0.25);
}
}
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 override bool DelayedDamage
{
get
{
return false;
}
}
public override void SendCastEffect()
{
Caster.FixedEffect(0x37C4, 10, 7, 4, 3); // At player
}
public override void OnCast()
{
if (this.CheckSequence())
{
Caster.PlaySound(0xF5);
Caster.PlaySound(0x299);
Caster.FixedParticles(0x37C4, 1, 25, 9922, 14, 3, EffectLayer.Head);
int dispelSkill = ComputePowerValue(2);
double chiv = Caster.Skills.Chivalry.Value;
foreach (var m in AcquireIndirectTargets(Caster.Location, 8).OfType<Mobile>())
{
BaseCreature bc = m as BaseCreature;
if (bc != null)
{
bool dispellable = bc.Summoned && !bc.IsAnimatedDead;
if (dispellable)
{
double dispelChance = (50.0 + ((100 * (chiv - bc.GetDispelDifficulty())) / (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));
}
}
}
TransformContext context = TransformationSpellHelper.GetContext(m);
if (context != null && context.Spell is NecromancerSpell) //Trees are not evil! TODO: OSI confirm?
{
// transformed ..
double drainChance = 0.5 * (this.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,158 @@
using System;
using System.Collections.Generic;
namespace Server.Spells.Chivalry
{
public class DivineFurySpell : PaladinSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Divine Fury", "Divinum Furis",
-1,
9002);
private static readonly Dictionary<Mobile, Timer> m_Table = new Dictionary<Mobile, Timer>();
public DivineFurySpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.0);
}
}
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 static bool UnderEffect(Mobile m)
{
return m_Table.ContainsKey(m);
}
public override void OnCast()
{
if (CheckSequence())
{
Caster.PlaySound(0x20F);
Caster.PlaySound(Caster.Female ? 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;
if (m_Table.ContainsKey(Caster))
{
t = 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);
string args = String.Format("{0}\t{1}\t{2}\t{3}", GetAttackBonus(Caster).ToString(), GetDamageBonus(Caster).ToString(), GetWeaponSpeedBonus(Caster).ToString(), GetDefendMalus(Caster).ToString());
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.DivineFury, 1060589, 1150218, TimeSpan.FromSeconds(delay), Caster, args));
// ~1_HCI~% hit chance<br> ~2_DI~% damage<br>~3_SSI~% swing speed increase<br>-~4_DCI~% defense chance
}
FinishSequence();
}
public static int GetDamageBonus(Mobile m)
{
if (m_Table.ContainsKey(m))
{
return m.Skills[SkillName.Chivalry].Value >= 120.0 && m.Karma >= 10000 ? 20 : 10;
}
return 0;
}
public static int GetWeaponSpeedBonus(Mobile m)
{
if (m_Table.ContainsKey(m))
{
return m.Skills[SkillName.Chivalry].Value >= 120.0 && m.Karma >= 10000 ? 15 : 10;
}
return 0;
}
public static int GetAttackBonus(Mobile m)
{
if (m_Table.ContainsKey(m))
{
return m.Skills[SkillName.Chivalry].Value >= 120.0 && m.Karma >= 10000 ? 15 : 10;
}
return 0;
}
public static int GetDefendMalus(Mobile m)
{
if (m_Table.ContainsKey(m))
{
return m.Skills[SkillName.Chivalry].Value >= 120.0 && m.Karma >= 10000 ? 10 : 20;
}
return 0;
}
private static void Expire_Callback(object state)
{
Mobile m = (Mobile)state;
if(m_Table.ContainsKey(m))
m_Table.Remove(m);
m.Delta(MobileDelta.WeaponDamage);
m.PlaySound(0xF8);
}
}
}

View File

@@ -0,0 +1,317 @@
using System;
using Server.Mobiles;
using System.Collections.Generic;
namespace Server.Spells.Chivalry
{
public class EnemyOfOneSpell : PaladinSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Enemy of One", "Forul Solum",
-1,
9002);
public EnemyOfOneSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(0.5); } }
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 override TimeSpan GetCastDelay()
{
TimeSpan delay = base.GetCastDelay();
if (Core.SA && UnderEffect(Caster))
{
double milliseconds = delay.TotalMilliseconds / 2;
delay = TimeSpan.FromMilliseconds(milliseconds);
}
return delay;
}
public override void OnCast()
{
if (Core.SA && UnderEffect(Caster))
{
PlayEffects();
// As per Pub 71, Enemy of one has now been changed to a Spell Toggle. You can remove the effect
// before the duration expires by recasting the spell.
RemoveEffect(Caster);
}
else if (CheckSequence())
{
PlayEffects();
// TODO: validate formula
var seconds = ComputePowerValue(1);
Utility.FixMinMax(ref seconds, 67, 228);
var delay = TimeSpan.FromSeconds(seconds);
var timer = Timer.DelayCall(delay, RemoveEffect, Caster);
var expire = DateTime.UtcNow + delay;
var context = new EnemyOfOneContext(Caster, timer, expire);
context.OnCast();
m_Table[Caster] = context;
}
FinishSequence();
}
private void PlayEffects()
{
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);
}
private static readonly Dictionary<Mobile, EnemyOfOneContext> m_Table = new Dictionary<Mobile, EnemyOfOneContext>();
public static EnemyOfOneContext GetContext(Mobile m)
{
if (!m_Table.ContainsKey(m))
return null;
return m_Table[m];
}
public static bool UnderEffect(Mobile m)
{
return m_Table.ContainsKey(m);
}
public static void RemoveEffect(Mobile m)
{
if (m_Table.ContainsKey(m))
{
var context = m_Table[m];
m_Table.Remove(m);
context.OnRemoved();
m.PlaySound(0x1F8);
}
}
public static Dictionary<Type, string> NameCache { get; set; }
public static void Configure()
{
if (NameCache == null)
NameCache = new Dictionary<Type, string>();
}
public static string GetTypeName(Mobile defender)
{
if (defender is PlayerMobile || (defender is BaseCreature && ((BaseCreature)defender).GetMaster() is PlayerMobile))
{
return defender.Name;
}
Type t = defender.GetType();
if (NameCache.ContainsKey(t))
{
return NameCache[t];
}
return AddNameToCache(t);
}
public static string AddNameToCache(Type t)
{
string name = t.Name;
if (name != null)
{
for (int i = 0; i < name.Length; i++)
{
if (i > 0 && Char.IsUpper(name[i]))
{
name = name.Insert(i, " ");
i++;
}
}
if (name.EndsWith("y"))
{
name = name.Substring(0, name.Length - 1);
name = name + "ies";
}
else if (!name.EndsWith("s"))
{
name = name + "s";
}
NameCache[t] = name.ToLower();
}
return name;
}
}
public class EnemyOfOneContext
{
private Mobile m_Owner;
private Timer m_Timer;
private DateTime m_Expire;
private Type m_TargetType;
private int m_DamageScalar;
private string m_TypeName;
private Mobile m_PlayerOrPet;
public Mobile Owner { get { return m_Owner; } }
public Timer Timer { get { return m_Timer; } }
public Type TargetType { get { return m_TargetType; } }
public int DamageScalar { get { return m_DamageScalar; } }
public string TypeName { get { return m_TypeName; } }
public EnemyOfOneContext(Mobile owner, Timer timer, DateTime expire)
{
m_Owner = owner;
m_Timer = timer;
m_Expire = expire;
m_TargetType = null;
m_DamageScalar = 50;
}
public bool IsWaitingForEnemy { get { return m_TargetType == null; } }
public bool IsEnemy(Mobile m)
{
if (m is BaseCreature && ((BaseCreature)m).GetMaster() == Owner)
{
return false;
}
if (m_PlayerOrPet != null)
{
if (m_PlayerOrPet == m)
{
return true;
}
}
else if (m_TargetType == m.GetType())
{
return true;
}
return false;
}
public void OnCast()
{
UpdateBuffInfo();
}
private void UpdateDamage()
{
var chivalry = (int)m_Owner.Skills.Chivalry.Value;
m_DamageScalar = 10 + ((chivalry - 40) * 9) / 10;
if (m_PlayerOrPet != null)
m_DamageScalar /= 2;
}
private void UpdateBuffInfo()
{
if (m_TypeName == null)
{
BuffInfo.AddBuff(m_Owner, new BuffInfo(BuffIcon.EnemyOfOne, 1075653, 1075902, m_Expire - DateTime.UtcNow, m_Owner, string.Format("{0}\t{1}", m_DamageScalar, "100"), true));
}
else
{
BuffInfo.AddBuff(m_Owner, new BuffInfo(BuffIcon.EnemyOfOne, 1075653, 1075654, m_Expire - DateTime.UtcNow, m_Owner, string.Format("{0}\t{1}\t{2}\t{3}", m_DamageScalar, TypeName, ".", "100"), true));
}
}
public void OnHit(Mobile defender)
{
if (m_TargetType == null)
{
m_TypeName = EnemyOfOneSpell.GetTypeName(defender);
if (defender is PlayerMobile || (defender is BaseCreature && ((BaseCreature)defender).GetMaster() is PlayerMobile))
{
m_PlayerOrPet = defender;
TimeSpan duration = TimeSpan.FromSeconds(8);
if (DateTime.UtcNow + duration < m_Expire)
{
m_Expire = DateTime.UtcNow + duration;
}
if (m_Timer != null)
{
m_Timer.Stop();
m_Timer = null;
}
m_Timer = Timer.DelayCall(duration, EnemyOfOneSpell.RemoveEffect, m_Owner);
}
else
{
m_TargetType = defender.GetType();
}
UpdateDamage();
DeltaEnemies();
UpdateBuffInfo();
}
else if (Core.SA)
{
// Odd but OSI recalculates when the target changes...
UpdateDamage();
}
}
public void OnRemoved()
{
if (m_Timer != null)
m_Timer.Stop();
DeltaEnemies();
BuffInfo.RemoveBuff(m_Owner, BuffIcon.EnemyOfOne);
}
private void DeltaEnemies()
{
IPooledEnumerable eable = m_Owner.GetMobilesInRange(18);
foreach (Mobile m in eable)
{
if (m_PlayerOrPet != null)
{
if (m == m_PlayerOrPet)
{
m.Delta(MobileDelta.Noto);
}
}
else if (m.GetType() == m_TargetType)
{
m.Delta(MobileDelta.Noto);
}
}
eable.Free();
}
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using Server.Items;
namespace Server.Spells.Chivalry
{
public class HolyLightSpell : PaladinSpell
{
public override DamageType SpellDamageType { get { return DamageType.SpellAOE; } }
private static readonly SpellInfo m_Info = new SpellInfo(
"Holy Light", "Augus Luminos",
-1,
9002);
public HolyLightSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.75);
}
}
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 override bool DelayedDamage
{
get
{
return false;
}
}
public override void OnCast()
{
if (CheckSequence())
{
foreach (var id in AcquireIndirectTargets(Caster.Location, 3))
{
Mobile m = id as Mobile;
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);
}
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);
}
FinishSequence();
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Collections.Generic;
using Server.Gumps;
using Server.Mobiles;
using Server.Spells.Necromancy;
namespace Server.Spells.Chivalry
{
public class NobleSacrificeSpell : PaladinSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Noble Sacrifice", "Dium Prostra",
-1,
9002);
public NobleSacrificeSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.5);
}
}
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 override void OnCast()
{
if (CheckSequence())
{
List<Mobile> targets = new List<Mobile>();
IPooledEnumerable eable = Caster.GetMobilesInRange(6);
foreach (Mobile m in eable)
{
if (m is BaseCreature || (m.Player && (m.Criminal || m.Murderer)))
continue;
if (Caster != m && m.InLOS(Caster) && Caster.CanBeBeneficial(m, false, true) && !(m is IRepairableMobile))
targets.Add(m);
}
eable.Free();
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 = 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 (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, Caster);
sendEffect = true;
}
if(m.RemoveStatMod("[Magic] Str Offset"))
sendEffect = true;
if(m.RemoveStatMod("[Magic] Dex Offset"))
sendEffect = true;
if(m.RemoveStatMod("[Magic] Int Offset"))
sendEffect = true;
if (m.Paralyzed)
{
m.Paralyzed = false;
sendEffect = true;
}
if (EvilOmenSpell.TryEndEffect(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(Caster.Body.IsFemale ? 0x150 : 0x423);
Caster.Hits = 1;
Caster.Stam = 1;
Caster.Mana = 1;
}
}
FinishSequence();
}
}
}

View File

@@ -0,0 +1,142 @@
#region References
using System;
using Server.Network;
#endregion
namespace Server.Spells.Chivalry
{
public abstract class PaladinSpell : Spell
{
public PaladinSpell(Mobile caster, Item scroll, SpellInfo info)
: base(caster, scroll, info)
{ }
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 SkillName DamageSkill { get { return SkillName.Chivalry; } }
public override bool ClearHandsOnCast { get { return false; } }
public override int CastRecoveryBase { get { return 7; } }
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;
}
public override bool CheckCast()
{
int mana = ScaleMana(RequiredMana);
if (!base.CheckCast())
{
return false;
}
if (Caster.Player && 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, mana.ToString());
// You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
return false;
}
return true;
}
public override bool CheckFizzle()
{
int requiredTithing = Caster.Player ? RequiredTithing : 0;
if (AosAttributes.GetValue(Caster, AosAttribute.LowerRegCost) > Utility.Random(100))
{
requiredTithing = 0;
}
int mana = ScaleMana(RequiredMana);
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, mana.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()
{
if (Caster.Player)
Caster.PublicOverheadMessage( MessageType.Regular, 0x3B2, MantraNumber, "", false );
}
public override void DoFizzle()
{
Caster.PlaySound(0x1D6);
Caster.NextSpellTime = Core.TickCount;
}
public override void DoHurtFizzle()
{
Caster.PlaySound(0x1D6);
}
public override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable)
{
// Cannot disturb Chivalry spells
return false;
}
public override void SendCastEffect()
{
if(Caster.Player)
Caster.FixedEffect(0x37C4, 87, (int)(GetCastDelay().TotalSeconds * 28), 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);
}
}
}

View File

@@ -0,0 +1,152 @@
using System;
using Server.Items;
using Server.Spells.First;
using Server.Spells.Fourth;
using Server.Spells.Necromancy;
using Server.Targeting;
using Server.Spells.Mysticism;
namespace Server.Spells.Chivalry
{
public class RemoveCurseSpell : PaladinSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Remove Curse", "Extermo Vomica",
-1,
9002);
public RemoveCurseSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.5);
}
}
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 override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable)
{
return true;
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (this.CheckBSequence(m))
{
SpellHelper.Turn(this.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 (this.Caster.Karma < -5000)
chance = 0;
else if (this.Caster.Karma < 0)
chance = (int)Math.Sqrt(20000 + this.Caster.Karma) - 122;
else if (this.Caster.Karma < 5625)
chance = (int)Math.Sqrt(this.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), this.Caster.Map);
IEntity to = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z + 50), this.Caster.Map);
Effects.SendMovingParticles(from, to, 0x2255, 1, 0, false, false, 13, 3, 9501, 1, 0, EffectLayer.Head, 0x100);
m.Paralyzed = false;
EvilOmenSpell.TryEndEffect(m);
StrangleSpell.RemoveCurse(m);
CorpseSkinSpell.RemoveCurse(m);
CurseSpell.RemoveEffect(m);
MortalStrike.EndWound(m);
WeakenSpell.RemoveEffects(m);
FeeblemindSpell.RemoveEffects(m);
ClumsySpell.RemoveEffects(m);
if (Core.ML)
{
BloodOathSpell.RemoveCurse(m);
}
MindRotSpell.ClearMindRotScalar(m);
SpellPlagueSpell.RemoveFromList(m);
BuffInfo.RemoveBuff(m, BuffIcon.MassCurse);
}
else
{
m.PlaySound(0x1DF);
}
}
this.FinishSequence();
}
private class InternalTarget : Target
{
private readonly RemoveCurseSpell m_Owner;
public InternalTarget(RemoveCurseSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Beneficial)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
this.m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,304 @@
using System;
using Server.Items;
using Server.Mobiles;
using Server.Multis;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Chivalry
{
public class SacredJourneySpell : PaladinSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Sacred Journey", "Sanctum Viatas",
-1,
9002);
private readonly RunebookEntry m_Entry;
private readonly 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 TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.5);
}
}
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;
}
}
public override void OnCast()
{
if (m_Entry == null)
{
Caster.SendLocalizedMessage(501029); // Select Marked item.
Caster.Target = new InternalTarget(this);
}
else
{
if (m_Entry.Type == RecallRuneType.Ship)
{
Effect(m_Entry.Galleon);
}
else
{
Effect(m_Entry.Location, m_Entry.Map, true, false);
}
}
}
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 (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(BaseGalleon galleon)
{
if (galleon == null)
{
Caster.SendLocalizedMessage(1116767); // The ship could not be located.
}
else if (galleon.Map == Map.Internal)
{
Caster.SendLocalizedMessage(1149569); // That ship is in dry dock.
}
else if (!galleon.HasAccess(Caster))
{
Caster.SendLocalizedMessage(1116617); // You do not have permission to board this ship.
}
else
{
Effect(galleon.GetMarkedLocation(), galleon.Map, false, true);
}
}
public void Effect(Point3D loc, Map map, bool checkMulti, bool isboatkey = false)
{
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 (SpellHelper.RestrictRedTravel && Caster.Murderer && map.Rules != MapRules.FeluccaRules)
{
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 (Misc.WeightOverloading.IsOverloaded(Caster))
{
Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move.
}
else if (!map.CanSpawnMobile(loc.X, loc.Y, loc.Z) && !isboatkey)
{
Caster.SendLocalizedMessage(501942); // That location is blocked.
}
else if ((checkMulti && SpellHelper.CheckMulti(loc, map)) && !isboatkey)
{
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 (Engines.CityLoyalty.CityTradeSystem.HasTrade(Caster))
{
Caster.SendLocalizedMessage(1151733); // You cannot do that while carrying a Trade Order.
}
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.PlaySound(0x1FC);
Caster.MoveToWorld(loc, map);
Caster.PlaySound(0x1FC);
}
FinishSequence();
}
private class InternalTarget : Target
{
private readonly SacredJourneySpell m_Owner;
public InternalTarget(SacredJourneySpell owner)
: base(Core.ML ? 10 : 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)
{
if (rune.Type == RecallRuneType.Ship)
{
m_Owner.Effect(rune.Galleon);
}
else
{
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)
{
if (e.Type == RecallRuneType.Ship)
{
m_Owner.Effect(e.Galleon);
}
else
{
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 if (o is HouseRaffleDeed && ((HouseRaffleDeed)o).ValidLocation())
{
HouseRaffleDeed deed = (HouseRaffleDeed)o;
m_Owner.Effect(deed.PlotLocation, deed.PlotFacet, true);
}
else if (o is Engines.NewMagincia.WritOfLease)
{
Engines.NewMagincia.WritOfLease lease = (Engines.NewMagincia.WritOfLease)o;
if (lease.RecallLoc != Point3D.Zero && lease.Facet != null && lease.Facet != Map.Internal)
m_Owner.Effect(lease.RecallLoc, lease.Facet, 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 OnNonlocalTarget(Mobile from, object o)
{
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
namespace Server.Spells.Eighth
{
public class EarthquakeSpell : MagerySpell
{
public override DamageType SpellDamageType { get { return DamageType.SpellAOE; } }
private static readonly SpellInfo m_Info = new SpellInfo(
"Earthquake", "In Vas Por",
233,
9012,
false,
Reagent.Bloodmoss,
Reagent.Ginseng,
Reagent.MandrakeRoot,
Reagent.SulfurousAsh);
public EarthquakeSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Eighth;
}
}
public override bool DelayedDamage
{
get
{
return !Core.AOS;
}
}
public override void OnCast()
{
if (SpellHelper.CheckTown(Caster, Caster) && CheckSequence())
{
foreach (var id in AcquireIndirectTargets(Caster.Location, 1 + (int)(Caster.Skills[SkillName.Magery].Value / 15.0)))
{
Mobile m = id as Mobile;
int damage;
if (Core.AOS)
{
damage = id.Hits / 2;
if (m == null || !m.Player)
damage = Math.Max(Math.Min(damage, 100), 15);
damage += Utility.RandomMinMax(0, 15);
}
else
{
damage = (id.Hits * 6) / 10;
if ((m == null || !m.Player) && damage < 10)
damage = 10;
else if (damage > 75)
damage = 75;
}
Caster.DoHarmful(id);
SpellHelper.Damage(this, id, damage, 100, 0, 0, 0, 0);
}
}
FinishSequence();
}
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,62 @@
using System;
using Server.Mobiles;
namespace Server.Spells.Eighth
{
public class SummonDaemonSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Summon Daemon", "Kal Vas Xen Corp",
269,
9050,
false,
Reagent.Bloodmoss,
Reagent.MandrakeRoot,
Reagent.SpidersSilk,
Reagent.SulfurousAsh);
public SummonDaemonSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Eighth;
}
}
public override bool CheckCast()
{
if (!base.CheckCast())
return false;
if ((this.Caster.Followers + (Core.SE ? 4 : 5)) > this.Caster.FollowersMax)
{
this.Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
if (this.CheckSequence())
{
TimeSpan duration = TimeSpan.FromSeconds((2 * this.Caster.Skills.Magery.Fixed) / 5);
if (Core.AOS) /* Why two diff daemons? TODO: solve this */
{
BaseCreature m_Daemon = new SummonedDaemon();
SpellHelper.Summon(m_Daemon, this.Caster, 0x216, duration, false, false);
m_Daemon.FixedParticles(0x3728, 8, 20, 5042, EffectLayer.Head);
}
else
SpellHelper.Summon(new Daemon(), this.Caster, 0x216, duration, false, false);
}
this.FinishSequence();
}
}
}

View File

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

View File

@@ -0,0 +1,111 @@
using System;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Fifth
{
public class BladeSpiritsSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Blade Spirits", "In Jux Hur Ylem",
266,
9040,
false,
Reagent.BlackPearl,
Reagent.MandrakeRoot,
Reagent.Nightshade);
public BladeSpiritsSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fifth;
}
}
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 ((this.Caster.Followers + (Core.SE ? 2 : 1)) > this.Caster.FollowersMax)
{
this.Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(IPoint3D p)
{
Map map = this.Caster.Map;
SpellHelper.GetSurfaceTop(ref p);
if (map == null || !map.CanSpawnMobile(p.X, p.Y, p.Z))
{
this.Caster.SendLocalizedMessage(501942); // That location is blocked.
}
else if (SpellHelper.CheckTown(p, this.Caster) && this.CheckSequence())
{
TimeSpan duration;
if (Core.AOS)
duration = TimeSpan.FromSeconds(120);
else
duration = TimeSpan.FromSeconds(Utility.Random(80, 40));
BaseCreature.Summon(new BladeSpirits(true), false, this.Caster, new Point3D(p), 0x212, duration);
}
this.FinishSequence();
}
public class InternalTarget : Target
{
private BladeSpiritsSpell m_Owner;
public InternalTarget(BladeSpiritsSpell owner)
: base(Core.ML ? 10 : 12, true, TargetFlags.None)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is IPoint3D)
this.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(this.m_Owner);
from.Target.BeginTimeout(from, this.TimeoutTime - DateTime.UtcNow);
this.m_Owner = null;
}
protected override void OnTargetFinish(Mobile from)
{
if (this.m_Owner != null)
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,91 @@
using System;
using Server.Items;
using Server.Misc;
using Server.Targeting;
namespace Server.Spells.Fifth
{
public class DispelFieldSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Dispel Field", "An Grav",
206,
9002,
Reagent.BlackPearl,
Reagent.SpidersSilk,
Reagent.SulfurousAsh,
Reagent.Garlic);
public DispelFieldSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fifth;
}
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(Item item)
{
Type t = item.GetType();
if (!this.Caster.CanSee(item))
{
this.Caster.SendLocalizedMessage(500237); // Target can not be seen.
}
else if (!t.IsDefined(typeof(DispellableFieldAttribute), false))
{
this.Caster.SendLocalizedMessage(1005049); // That cannot be dispelled.
}
else if (item is Moongate && !((Moongate)item).Dispellable)
{
this.Caster.SendLocalizedMessage(1005047); // That magic is too chaotic
}
else if (this.CheckSequence())
{
SpellHelper.Turn(this.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();
}
this.FinishSequence();
}
public class InternalTarget : Target
{
private readonly DispelFieldSpell m_Owner;
public InternalTarget(DispelFieldSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.None)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Item)
{
this.m_Owner.Target((Item)o);
}
else
{
this.m_Owner.Caster.SendLocalizedMessage(1005049); // That cannot be dispelled.
}
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

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

View File

@@ -0,0 +1,161 @@
using System;
using System.Collections;
namespace Server.Spells.Fifth
{
public class MagicReflectSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Magic Reflection", "In Jux Sanct",
242,
9012,
Reagent.Garlic,
Reagent.MandrakeRoot,
Reagent.SpidersSilk);
private static readonly Hashtable m_Table = new Hashtable();
public MagicReflectSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fifth;
}
}
public static void EndReflect(Mobile m)
{
if (m_Table.Contains(m))
{
ResistanceMod[] mods = (ResistanceMod[])m_Table[m];
if (mods != null)
{
for (int i = 0; i < mods.Length; ++i)
m.RemoveResistanceMod(mods[i]);
}
m_Table.Remove(m);
BuffInfo.RemoveBuff(m, BuffIcon.MagicReflection);
}
}
public override bool CheckCast()
{
if (Core.AOS)
return true;
if (this.Caster.MagicDamageAbsorb > 0)
{
this.Caster.SendLocalizedMessage(1005559); // This spell is already in effect.
return false;
}
else if (!this.Caster.CanBeginAction(typeof(DefensiveSpell)))
{
this.Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time.
return false;
}
return true;
}
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 on<6F>even after logging out, even after dying<6E>until you <20>turn them off<66> by casting them again.
*/
if (this.CheckSequence())
{
Mobile targ = this.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);
}
}
this.FinishSequence();
}
else
{
if (this.Caster.MagicDamageAbsorb > 0)
{
this.Caster.SendLocalizedMessage(1005559); // This spell is already in effect.
}
else if (!this.Caster.CanBeginAction(typeof(DefensiveSpell)))
{
this.Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time.
}
else if (this.CheckSequence())
{
if (this.Caster.BeginAction(typeof(DefensiveSpell)))
{
int value = (int)(this.Caster.Skills[SkillName.Magery].Value + this.Caster.Skills[SkillName.Inscribe].Value);
value = (int)(8 + (value / 200) * 7.0);//absorb from 8 to 15 "circles"
this.Caster.MagicDamageAbsorb = value;
this.Caster.FixedParticles(0x375A, 10, 15, 5037, EffectLayer.Waist);
this.Caster.PlaySound(0x1E9);
}
else
{
this.Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time.
}
}
this.FinishSequence();
}
}
#region SA
public static bool HasReflect(Mobile m)
{
return m_Table.ContainsKey(m);
}
#endregion
}
}

View File

@@ -0,0 +1,171 @@
using System;
using Server.Targeting;
namespace Server.Spells.Fifth
{
public class MindBlastSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Mind Blast", "Por Corp Wis",
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 SpellCircle Circle
{
get
{
return SpellCircle.Fifth;
}
}
public override bool DelayedDamage
{
get
{
return !Core.AOS;
}
}
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)
{
if (Caster.CanBeHarmful(m) && CheckSequence())
{
Mobile from = Caster, target = m;
SpellHelper.Turn(from, target);
SpellHelper.CheckReflect((int)Circle, ref from, ref target);
int intel = Math.Min(200, Caster.Int);
int damage = (int)((Caster.Skills[SkillName.Magery].Value + intel) / 5) + Utility.RandomMinMax(2, 6);
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);
if(target != null)
SpellHelper.CheckReflect((int)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;
double damage;
if (Core.AOS)
{
damage = GetDamageScalar(m)*(highestStat - lowestStat)/4; //less damage
}
else
{
damage = GetDamageScalar(m) * (highestStat - lowestStat) / 2; //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 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))
{
target.FixedParticles(0x374A, 10, 15, 5038, 1181, 2, EffectLayer.Head);
target.PlaySound(0x213);
SpellHelper.Damage(this, target, Utility.RandomMinMax(damage, damage + 4), 0, 0, 100, 0, 0);
}
}
private class InternalTarget : Target
{
private readonly MindBlastSpell m_Owner;
public InternalTarget(MindBlastSpell owner)
: base(Core.ML ? 10 : 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,114 @@
using System;
using Server.Mobiles;
using Server.Spells.Chivalry;
using Server.Targeting;
namespace Server.Spells.Fifth
{
public class ParalyzeSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Paralyze", "An Ex Por",
218,
9012,
Reagent.Garlic,
Reagent.MandrakeRoot,
Reagent.SpidersSilk);
public ParalyzeSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fifth;
}
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (!this.Caster.CanSee(m))
{
this.Caster.SendLocalizedMessage(500237); // Target can not be seen.
}
else if (Core.AOS && (m.Frozen || m.Paralyzed || (m.Spell != null && m.Spell.IsCasting && !(m.Spell is PaladinSpell))))
{
this.Caster.SendLocalizedMessage(1061923); // The target is already frozen.
}
else if (this.CheckHSequence(m))
{
SpellHelper.Turn(this.Caster, m);
SpellHelper.CheckReflect((int)this.Circle, this.Caster, ref m);
double duration;
if (Core.AOS)
{
int secs = (int)((this.GetDamageSkill(this.Caster) / 10) - (this.GetResistSkill(m) / 10));
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 + (this.Caster.Skills[SkillName.Magery].Value * 0.2);
if (this.CheckResisted(m))
duration *= 0.75;
}
if (m is PlagueBeastLord)
{
((PlagueBeastLord)m).OnParalyzed(this.Caster);
duration = 120;
}
m.Paralyze(TimeSpan.FromSeconds(duration));
m.PlaySound(0x204);
m.FixedEffect(0x376A, 6, 1);
this.HarmfulSpell(m);
}
this.FinishSequence();
}
public class InternalTarget : Target
{
private readonly ParalyzeSpell m_Owner;
public InternalTarget(ParalyzeSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
this.m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,314 @@
using System;
using System.Collections;
using Server.Items;
using Server.Misc;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Fifth
{
public class PoisonFieldSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Poison Field", "In Nox Grav",
230,
9052,
false,
Reagent.BlackPearl,
Reagent.Nightshade,
Reagent.SpidersSilk);
public PoisonFieldSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fifth;
}
}
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) && SpellHelper.CheckWater(new Point3D(p), Caster.Map) && 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;
Point3D pnt = new Point3D(p);
TimeSpan duration = TimeSpan.FromSeconds(3 + (Caster.Skills.Magery.Fixed / 25));
if (SpellHelper.CheckField(pnt, Caster.Map))
new InternalItem(itemID, pnt, Caster, Caster.Map, duration);
for (int i = 1; i <= 2; ++i)
{
Timer.DelayCall<int>(TimeSpan.FromMilliseconds(i * 300), index =>
{
Point3D point = new Point3D(eastToWest ? pnt.X + index : pnt.X, eastToWest ? pnt.Y : pnt.Y + index, pnt.Z);
SpellHelper.AdjustField(ref point, Caster.Map, 16, false);
if (SpellHelper.CheckField(point, Caster.Map))
new InternalItem(itemID, point, Caster, Caster.Map, duration);
point = new Point3D(eastToWest ? pnt.X + -index : pnt.X, eastToWest ? pnt.Y : pnt.Y + -index, pnt.Z);
SpellHelper.AdjustField(ref point, Caster.Map, 16, false);
if (SpellHelper.CheckField(point, Caster.Map))
new InternalItem(itemID, point, Caster, Caster.Map, duration);
}, i);
}
}
FinishSequence();
}
[DispellableField]
public class InternalItem : Item
{
private Timer m_Timer;
private DateTime m_End;
private Mobile m_Caster;
public Mobile Caster { get { return m_Caster; } }
public InternalItem(int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration)
: base(itemID)
{
bool canFit = SpellHelper.AdjustField(ref loc, map, 12, false);
Movable = false;
Light = LightType.Circle300;
MoveToWorld(loc, map);
Effects.SendLocationParticles(EffectItem.Create(loc, map, EffectItem.DefaultDuration), 0x376A, 9, 10, 5029);
m_Caster = caster;
m_End = DateTime.UtcNow + duration;
m_Timer = new InternalTimer(this, caster.InLOS(this), canFit);
m_Timer.Start();
}
public InternalItem(Serial serial)
: base(serial)
{
}
public override bool BlocksFit
{
get
{
return true;
}
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if (m_Timer != null)
m_Timer.Stop();
}
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, 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;
}
if (m.ApplyPoison(m_Caster, p) == ApplyPoisonResult.Poisoned)
if (SpellHelper.CanRevealCaster(m))
m_Caster.RevealingAction();
if (m is BaseCreature)
((BaseCreature)m).OnHarmfulSpell(m_Caster);
}
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 static readonly Queue m_Queue = new Queue();
private readonly InternalItem m_Item;
private readonly bool m_InLOS;
private readonly bool m_CanFit;
public InternalTimer(InternalItem item, bool inLOS, bool canFit)
: base(TimeSpan.FromMilliseconds(500), 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 (DateTime.UtcNow > 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);
}
}
}
}
}
}
public class InternalTarget : Target
{
private readonly PoisonFieldSpell m_Owner;
public InternalTarget(PoisonFieldSpell owner)
: base(Core.TOL ? 15 : Core.ML ? 10 : 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,98 @@
using System;
using Server.Mobiles;
namespace Server.Spells.Fifth
{
public class SummonCreatureSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Summon Creature", "Kal Xen",
16,
false,
Reagent.Bloodmoss,
Reagent.MandrakeRoot,
Reagent.SpidersSilk);
// NOTE: Creature list based on 1hr of summon/release on OSI.
private static readonly Type[] m_Types = new Type[]
{
typeof(PolarBear),
typeof(GrizzlyBear),
typeof(BlackBear),
typeof(Horse),
typeof(Walrus),
typeof(Chicken),
typeof(Scorpion),
typeof(GiantSerpent),
typeof(Llama),
typeof(Alligator),
typeof(GreyWolf),
typeof(Slime),
typeof(Eagle),
typeof(Gorilla),
typeof(SnowLeopard),
typeof(Pig),
typeof(Hind),
typeof(Rabbit)
};
public SummonCreatureSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fifth;
}
}
public override bool CheckCast()
{
if (!base.CheckCast())
return false;
if ((this.Caster.Followers + 2) > this.Caster.FollowersMax)
{
this.Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature.
return false;
}
return true;
}
public override void OnCast()
{
if (this.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 * this.Caster.Skills.Magery.Fixed) / 5);
else
duration = TimeSpan.FromSeconds(4.0 * this.Caster.Skills[SkillName.Magery].Value);
SpellHelper.Summon(creature, this.Caster, 0x215, duration, false, false);
}
catch
{
}
}
this.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,140 @@
using System;
using Server.Targeting;
using System.Collections.Generic;
namespace Server.Spells.First
{
public class ClumsySpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Clumsy", "Uus Jux",
212,
9031,
Reagent.Bloodmoss,
Reagent.Nightshade);
public ClumsySpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public static Dictionary<Mobile, Timer> m_Table = new Dictionary<Mobile, Timer>();
public static bool IsUnderEffects(Mobile m)
{
return m_Table.ContainsKey(m);
}
public static void RemoveEffects(Mobile m, bool removeMod = true)
{
if (m_Table.ContainsKey(m))
{
Timer t = m_Table[m];
if (t != null && t.Running)
{
t.Stop();
}
BuffInfo.RemoveBuff(m, BuffIcon.Clumsy);
if (removeMod)
m.RemoveStatMod("[Magic] Dex Curse");
m_Table.Remove(m);
}
}
public override SpellCircle Circle
{
get
{
return SpellCircle.First;
}
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (!this.Caster.CanSee(m))
{
this.Caster.SendLocalizedMessage(500237); // Target can not be seen.
}
else if (this.CheckHSequence(m))
{
SpellHelper.Turn(this.Caster, m);
SpellHelper.CheckReflect((int)this.Circle, this.Caster, ref m);
if (Mysticism.StoneFormSpell.CheckImmunity(m))
{
Caster.SendLocalizedMessage(1080192); // Your target resists your ability reduction magic.
return;
}
int oldOffset = SpellHelper.GetCurseOffset(m, StatType.Dex);
int newOffset = SpellHelper.GetOffset(Caster, m, StatType.Dex, true, false);
if (-newOffset > oldOffset || newOffset == 0)
{
DoHurtFizzle();
}
else
{
if (m.Spell != null)
m.Spell.OnCasterHurt();
m.Paralyzed = false;
m.FixedParticles(0x3779, 10, 15, 5002, EffectLayer.Head);
m.PlaySound(0x1DF);
HarmfulSpell(m);
if (-newOffset < oldOffset)
{
SpellHelper.AddStatCurse(this.Caster, m, StatType.Dex, false, newOffset);
int percentage = (int)(SpellHelper.GetOffsetScalar(this.Caster, m, true) * 100);
TimeSpan length = SpellHelper.GetDuration(this.Caster, m);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Clumsy, 1075831, length, m, percentage.ToString()));
if (m_Table.ContainsKey(m))
m_Table[m].Stop();
m_Table[m] = Timer.DelayCall(length, () =>
{
RemoveEffects(m);
});
}
}
}
this.FinishSequence();
}
private class InternalTarget : Target
{
private readonly ClumsySpell m_Owner;
public InternalTarget(ClumsySpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
{
this.m_Owner.Target((Mobile)o);
}
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,111 @@
using System;
using Server.Items;
namespace Server.Spells.First
{
public class CreateFoodSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Create Food", "In Mani Ylem",
224,
9011,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.MandrakeRoot);
private static readonly 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 CreateFoodSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.First;
}
}
public override void OnCast()
{
if (this.CheckSequence())
{
FoodInfo foodInfo = m_Food[Utility.Random(m_Food.Length)];
Item food = foodInfo.Create();
if (food != null)
{
this.Caster.AddToBackpack(food);
// You magically create food in your backpack:
this.Caster.SendLocalizedMessage(1042695, true, " " + foodInfo.Name);
this.Caster.FixedParticles(0, 10, 5, 2003, EffectLayer.RightHand);
this.Caster.PlaySound(0x1E2);
}
}
this.FinishSequence();
}
}
public class FoodInfo
{
private Type m_Type;
private string m_Name;
public FoodInfo(Type type, string name)
{
this.m_Type = type;
this.m_Name = name;
}
public Type Type
{
get
{
return this.m_Type;
}
set
{
this.m_Type = value;
}
}
public string Name
{
get
{
return this.m_Name;
}
set
{
this.m_Name = value;
}
}
public Item Create()
{
Item item;
try
{
item = (Item)Activator.CreateInstance(this.m_Type);
}
catch
{
item = null;
}
return item;
}
}
}

View File

@@ -0,0 +1,140 @@
using System;
using Server.Targeting;
using System.Collections.Generic;
namespace Server.Spells.First
{
public class FeeblemindSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Feeblemind", "Rel Wis",
212,
9031,
Reagent.Ginseng,
Reagent.Nightshade);
public FeeblemindSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public static Dictionary<Mobile, Timer> m_Table = new Dictionary<Mobile, Timer>();
public static bool IsUnderEffects(Mobile m)
{
return m_Table.ContainsKey(m);
}
public static void RemoveEffects(Mobile m, bool removeMod = true)
{
if (m_Table.ContainsKey(m))
{
Timer t = m_Table[m];
if (t != null && t.Running)
{
t.Stop();
}
BuffInfo.RemoveBuff(m, BuffIcon.FeebleMind);
if (removeMod)
m.RemoveStatMod("[Magic] Int Curse");
m_Table.Remove(m);
}
}
public override SpellCircle Circle
{
get
{
return SpellCircle.First;
}
}
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)Circle, Caster, ref m);
if (Mysticism.StoneFormSpell.CheckImmunity(m))
{
Caster.SendLocalizedMessage(1080192); // Your target resists your ability reduction magic.
return;
}
int oldOffset = SpellHelper.GetCurseOffset(m, StatType.Int);
int newOffset = SpellHelper.GetOffset(Caster, m, StatType.Int, true, false);
if (-newOffset > oldOffset || newOffset == 0)
{
DoHurtFizzle();
}
else
{
if (m.Spell != null)
m.Spell.OnCasterHurt();
m.Paralyzed = false;
m.FixedParticles(0x3779, 10, 15, 5002, EffectLayer.Head);
m.PlaySound(0x1DF);
HarmfulSpell(m);
if (-newOffset < oldOffset)
{
SpellHelper.AddStatCurse(this.Caster, m, StatType.Int, false, newOffset);
int percentage = (int)(SpellHelper.GetOffsetScalar(this.Caster, m, true) * 100);
TimeSpan length = SpellHelper.GetDuration(this.Caster, m);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.FeebleMind, 1075833, length, m, percentage.ToString()));
if (m_Table.ContainsKey(m))
m_Table[m].Stop();
m_Table[m] = Timer.DelayCall(length, () =>
{
RemoveEffects(m);
});
}
}
}
FinishSequence();
}
private class InternalTarget : Target
{
private readonly FeeblemindSpell m_Owner;
public InternalTarget(FeeblemindSpell owner)
: base(Core.ML ? 10 : 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,110 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.First
{
public class HealSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Heal", "In Mani",
224,
9061,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.SpidersSilk);
public HealSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.First;
}
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (!this.Caster.CanSee(m))
{
this.Caster.SendLocalizedMessage(500237); // Target can not be seen.
}
else if (m.IsDeadBondedPet)
{
this.Caster.SendLocalizedMessage(1060177); // You cannot heal a creature that is already dead!
}
else if (m is BaseCreature && ((BaseCreature)m).IsAnimatedDead)
{
this.Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive.
}
else if (m is IRepairableMobile)
{
this.Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500951); // You cannot heal that.
}
else if (m.Poisoned || Server.Items.MortalStrike.IsWounded(m))
{
this.Caster.LocalOverheadMessage(MessageType.Regular, 0x22, (this.Caster == m) ? 1005000 : 1010398);
}
else if (this.CheckBSequence(m))
{
SpellHelper.Turn(this.Caster, m);
int toHeal;
if (Core.AOS)
{
toHeal = this.Caster.Skills.Magery.Fixed / 120;
toHeal += Utility.RandomMinMax(1, 4);
if (Core.SE && this.Caster != m)
toHeal = (int)(toHeal * 1.5);
}
else
{
toHeal = (int)(this.Caster.Skills[SkillName.Magery].Value * 0.1);
toHeal += Utility.Random(1, 5);
}
//m.Heal( toHeal, Caster );
SpellHelper.Heal(toHeal, m, this.Caster);
m.FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist);
m.PlaySound(0x1F2);
}
this.FinishSequence();
}
public class InternalTarget : Target
{
private readonly HealSpell m_Owner;
public InternalTarget(HealSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Beneficial)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
{
this.m_Owner.Target((Mobile)o);
}
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,128 @@
using System;
using Server.Targeting;
namespace Server.Spells.First
{
public class MagicArrowSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Magic Arrow", "In Por Ylem",
212,
9041,
Reagent.SulfurousAsh);
public MagicArrowSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.First;
}
}
public override bool DelayedDamageStacking
{
get
{
return !Core.AOS;
}
}
public override bool DelayedDamage
{
get
{
return true;
}
}
public override Type[] DelayDamageFamily { get { return new Type[] { typeof(Server.Spells.Mysticism.NetherBoltSpell) }; } }
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void Target(IDamageable d)
{
if (!Caster.CanSee(d))
{
Caster.SendLocalizedMessage(500237); // Target can not be seen.
}
else if (CheckHSequence(d))
{
IDamageable source = Caster;
IDamageable target = d;
SpellHelper.Turn(Caster, d);
if (Core.SA && HasDelayContext(d))
{
DoHurtFizzle();
return;
}
if (SpellHelper.CheckReflect((int)Circle, ref source, ref target))
{
Timer.DelayCall(TimeSpan.FromSeconds(.5), () =>
{
source.MovingParticles(target, 0x36E4, 5, 0, false, true, 3043, 4043, 0x211);
source.PlaySound(0x1E5);
});
}
double damage = 0;
if (Core.AOS)
{
damage = GetNewAosDamage(10, 1, 4, d);
}
else if (target is Mobile)
{
damage = Utility.Random(4, 4);
if (CheckResisted((Mobile)target))
{
damage *= 0.75;
((Mobile)target).SendLocalizedMessage(501783); // You feel yourself resisting magical energy.
}
damage *= GetDamageScalar((Mobile)target);
}
if (damage > 0)
{
Caster.MovingParticles(d, 0x36E4, 5, 0, false, false, 3006, 0, 0);
Caster.PlaySound(0x1E5);
SpellHelper.Damage(this, target, damage, 0, 100, 0, 0, 0);
}
}
FinishSequence();
}
private class InternalTarget : Target
{
private readonly MagicArrowSpell m_Owner;
public InternalTarget(MagicArrowSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is IDamageable)
{
m_Owner.Target((IDamageable)o);
}
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,83 @@
using System;
using Server.Targeting;
namespace Server.Spells.First
{
public class NightSightSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Night Sight", "In Lor",
236,
9031,
Reagent.SulfurousAsh,
Reagent.SpidersSilk);
public NightSightSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.First;
}
}
public override void OnCast()
{
Caster.Target = new NightSightTarget(this);
}
public void Target(Mobile targ)
{
SpellHelper.Turn(Caster, targ);
if (targ.BeginAction(typeof(LightCycle)))
{
new LightCycle.NightSightTimer(targ).Start();
int level = (int)(LightCycle.DungeonLevel * ((Core.AOS ? targ.Skills[SkillName.Magery].Value : Caster.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
{
Caster.SendMessage("{0} already have nightsight.", Caster == targ ? "You" : "They");
}
}
private class NightSightTarget : Target
{
private readonly NightSightSpell m_Spell;
public NightSightTarget(NightSightSpell 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))
{
m_Spell.Target((Mobile)targeted);
}
m_Spell.FinishSequence();
}
protected override void OnTargetFinish(Mobile from)
{
m_Spell.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,165 @@
using System;
using System.Collections;
namespace Server.Spells.First
{
public class ReactiveArmorSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Reactive Armor", "Flam Sanct",
236,
9011,
Reagent.Garlic,
Reagent.SpidersSilk,
Reagent.SulfurousAsh);
private static readonly Hashtable m_Table = new Hashtable();
public ReactiveArmorSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.First;
}
}
public static void EndArmor(Mobile m)
{
if (m_Table.Contains(m))
{
ResistanceMod[] mods = (ResistanceMod[])m_Table[m];
if (mods != null)
{
for (int i = 0; i < mods.Length; ++i)
m.RemoveResistanceMod(mods[i]);
}
m_Table.Remove(m);
BuffInfo.RemoveBuff(m, BuffIcon.ReactiveArmor);
}
}
public override bool CheckCast()
{
if (Core.AOS)
return true;
if (this.Caster.MeleeDamageAbsorb > 0)
{
this.Caster.SendLocalizedMessage(1005559); // This spell is already in effect.
return false;
}
else if (!this.Caster.CanBeginAction(typeof(DefensiveSpell)))
{
this.Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time.
return false;
}
return true;
}
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 on<6F>even after logging out, even after dying<6E>until you <20>turn them off<66> by casting them again.
* (+20 physical -5 elemental at 100 Inscription)
*/
if (this.CheckSequence())
{
Mobile targ = this.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]);
int physresist = 15 + (int)(targ.Skills[SkillName.Inscribe].Value / 20);
string args = String.Format("{0}\t{1}\t{2}\t{3}\t{4}", physresist, 5, 5, 5, 5);
BuffInfo.AddBuff(this.Caster, new BuffInfo(BuffIcon.ReactiveArmor, 1075812, 1075813, args.ToString()));
}
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]);
BuffInfo.RemoveBuff(this.Caster, BuffIcon.ReactiveArmor);
}
}
this.FinishSequence();
}
else
{
if (this.Caster.MeleeDamageAbsorb > 0)
{
this.Caster.SendLocalizedMessage(1005559); // This spell is already in effect.
}
else if (!this.Caster.CanBeginAction(typeof(DefensiveSpell)))
{
this.Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time.
}
else if (this.CheckSequence())
{
if (this.Caster.BeginAction(typeof(DefensiveSpell)))
{
int value = (int)(this.Caster.Skills[SkillName.Magery].Value + this.Caster.Skills[SkillName.Meditation].Value + this.Caster.Skills[SkillName.Inscribe].Value);
value /= 3;
if (value < 0)
value = 1;
else if (value > 75)
value = 75;
this.Caster.MeleeDamageAbsorb = value;
this.Caster.FixedParticles(0x376A, 9, 32, 5008, EffectLayer.Waist);
this.Caster.PlaySound(0x1F2);
}
else
{
this.Caster.SendLocalizedMessage(1005385); // The spell will not adhere to you at this time.
}
}
this.FinishSequence();
}
}
#region SA
public static bool HasArmor(Mobile m)
{
return m_Table.ContainsKey(m);
}
#endregion
}
}

View File

@@ -0,0 +1,141 @@
using System;
using Server.Targeting;
using System.Collections.Generic;
namespace Server.Spells.First
{
public class WeakenSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Weaken", "Des Mani",
212,
9031,
Reagent.Garlic,
Reagent.Nightshade);
public static Dictionary<Mobile, Timer> m_Table = new Dictionary<Mobile, Timer>();
public static bool IsUnderEffects(Mobile m)
{
return m_Table.ContainsKey(m);
}
public static void RemoveEffects(Mobile m, bool removeMod = true)
{
if (m_Table.ContainsKey(m))
{
Timer t = m_Table[m];
if (t != null && t.Running)
{
t.Stop();
}
BuffInfo.RemoveBuff(m, BuffIcon.Weaken);
if(removeMod)
m.RemoveStatMod("[Magic] Str Curse");
m_Table.Remove(m);
}
}
public WeakenSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.First;
}
}
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)Circle, Caster, ref m);
if (Mysticism.StoneFormSpell.CheckImmunity(m))
{
Caster.SendLocalizedMessage(1080192); // Your target resists your ability reduction magic.
return;
}
int oldOffset = SpellHelper.GetCurseOffset(m, StatType.Str);
int newOffset = SpellHelper.GetOffset(Caster, m, StatType.Str, true, false);
if (-newOffset > oldOffset || newOffset == 0)
{
DoHurtFizzle();
}
else
{
if (m.Spell != null)
m.Spell.OnCasterHurt();
m.Paralyzed = false;
m.FixedParticles(0x3779, 10, 15, 5002, EffectLayer.Head);
m.PlaySound(0x1DF);
HarmfulSpell(m);
if (-newOffset < oldOffset)
{
SpellHelper.AddStatCurse(this.Caster, m, StatType.Str, false, newOffset);
int percentage = (int)(SpellHelper.GetOffsetScalar(this.Caster, m, true) * 100);
TimeSpan length = SpellHelper.GetDuration(this.Caster, m);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Weaken, 1075837, length, m, percentage.ToString()));
if (m_Table.ContainsKey(m))
m_Table[m].Stop();
m_Table[m] = Timer.DelayCall(length, () =>
{
RemoveEffects(m);
});
}
}
}
FinishSequence();
}
public class InternalTarget : Target
{
private readonly WeakenSpell m_Owner;
public InternalTarget(WeakenSpell owner)
: base(Core.ML ? 10 : 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 System.Collections.Generic;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Fourth
{
public class ArchCureSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Arch Cure", "Vas An Nox",
215,
9061,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.MandrakeRoot);
public ArchCureSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fourth;
}
}
// Arch cure is now 1/4th of a second faster
public override TimeSpan CastDelayBase
{
get
{
return base.CastDelayBase - TimeSpan.FromSeconds(0.25);
}
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(IPoint3D p)
{
if (!this.Caster.CanSee(p))
{
this.Caster.SendLocalizedMessage(500237); // Target can not be seen.
}
else if (this.CheckSequence())
{
SpellHelper.Turn(this.Caster, p);
SpellHelper.GetSurfaceTop(ref p);
List<Mobile> targets = new List<Mobile>();
Map map = this.Caster.Map;
Mobile directTarget = p as Mobile;
if (map != null)
{
bool feluccaRules = (map.Rules == MapRules.FeluccaRules);
// You can target any living mobile directly, beneficial checks apply
if (directTarget != null && this.Caster.CanBeBeneficial(directTarget, false))
targets.Add(directTarget);
IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 2);
foreach (Mobile m in eable)
{
if (m == directTarget)
continue;
if (this.AreaCanTarget(m, feluccaRules))
targets.Add(m);
}
eable.Free();
}
Effects.PlaySound(p, this.Caster.Map, 0x299);
if (targets.Count > 0)
{
int cured = 0;
for (int i = 0; i < targets.Count; ++i)
{
Mobile m = targets[i];
this.Caster.DoBeneficial(m);
Poison poison = m.Poison;
if (poison != null)
{
int chanceToCure = 10000 + (int)(this.Caster.Skills[SkillName.Magery].Value * 75) - ((poison.RealLevel + 1) * 1750);
chanceToCure /= 100;
chanceToCure -= 1;
if (chanceToCure > Utility.Random(100) && m.CurePoison(this.Caster))
++cured;
}
m.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist);
m.PlaySound(0x1E0);
}
if (cured > 0)
this.Caster.SendLocalizedMessage(1010058); // You have cured the target of all poisons!
}
}
this.FinishSequence();
}
private static bool IsInnocentTo(Mobile from, Mobile to)
{
return (Notoriety.Compute(from, (Mobile)to) == Notoriety.Innocent);
}
private static bool IsAllyTo(Mobile from, Mobile to)
{
return (Notoriety.Compute(from, (Mobile)to) == Notoriety.Ally);
}
private bool AreaCanTarget(Mobile target, bool feluccaRules)
{
/* Arch cure area effect won't cure aggressors, victims, murderers, criminals or monsters.
* In Felucca, it will also not cure summons and pets.
* For red players it will only cure themselves and guild members.
*/
if (!this.Caster.CanBeBeneficial(target, false))
return false;
if (Core.AOS && target != this.Caster)
{
if (this.IsAggressor(target) || this.IsAggressed(target))
return false;
if ((!IsInnocentTo(this.Caster, target) || !IsInnocentTo(target, this.Caster)) && !IsAllyTo(this.Caster, target))
return false;
if (feluccaRules && !(target is PlayerMobile))
return false;
}
return true;
}
private bool IsAggressor(Mobile m)
{
foreach (AggressorInfo info in this.Caster.Aggressors)
{
if (m == info.Attacker && !info.Expired)
return true;
}
return false;
}
private bool IsAggressed(Mobile m)
{
foreach (AggressorInfo info in this.Caster.Aggressed)
{
if (m == info.Defender && !info.Expired)
return true;
}
return false;
}
public class InternalTarget : Target
{
private readonly ArchCureSpell m_Owner;
public InternalTarget(ArchCureSpell owner)
: base(Core.ML ? 10 : 12, true, TargetFlags.None)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
IPoint3D p = o as IPoint3D;
if (p != null)
this.m_Owner.Target(p);
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

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

View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using Server.Targeting;
using Server.Spells.First;
namespace Server.Spells.Fourth
{
public class CurseSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Curse", "Des Sanct",
227,
9031,
Reagent.Nightshade,
Reagent.Garlic,
Reagent.SulfurousAsh);
private static readonly Dictionary<Mobile, Timer> m_UnderEffect = new Dictionary<Mobile, Timer>();
public CurseSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fourth;
}
}
public static void AddEffect(Mobile m, TimeSpan duration, int strOffset, int dexOffset, int intOffset)
{
if (m == null)
return;
if (m_UnderEffect.ContainsKey(m))
{
m_UnderEffect[m].Stop();
m_UnderEffect[m] = null;
}
// my spell is stronger, so lets remove the lesser spell
if (WeakenSpell.IsUnderEffects(m) && SpellHelper.GetCurseOffset(m, StatType.Str) <= strOffset)
{
WeakenSpell.RemoveEffects(m, false);
}
if (ClumsySpell.IsUnderEffects(m) && SpellHelper.GetCurseOffset(m, StatType.Dex) <= dexOffset)
{
ClumsySpell.RemoveEffects(m, false);
}
if (FeeblemindSpell.IsUnderEffects(m) && SpellHelper.GetCurseOffset(m, StatType.Int) <= intOffset)
{
FeeblemindSpell.RemoveEffects(m, false);
}
m_UnderEffect[m] = Timer.DelayCall<Mobile>(duration, RemoveEffect, m); //= new CurseTimer(m, duration, strOffset, dexOffset, intOffset);
m.UpdateResistances();
}
public static void RemoveEffect(Mobile m)
{
if(!WeakenSpell.IsUnderEffects(m))
m.RemoveStatMod("[Magic] Str Curse");
if(!ClumsySpell.IsUnderEffects(m))
m.RemoveStatMod("[Magic] Dex Curse");
if(!FeeblemindSpell.IsUnderEffects(m))
m.RemoveStatMod("[Magic] Int Curse");
BuffInfo.RemoveBuff(m, BuffIcon.Curse);
if(m_UnderEffect.ContainsKey(m))
{
Timer t = m_UnderEffect[m];
if(t != null)
t.Stop();
m_UnderEffect.Remove(m);
}
m.UpdateResistances();
}
public static bool UnderEffect(Mobile m)
{
return m_UnderEffect.ContainsKey(m);
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public static bool DoCurse(Mobile caster, Mobile m, bool masscurse)
{
if (Mysticism.StoneFormSpell.CheckImmunity(m))
{
caster.SendLocalizedMessage(1080192); // Your target resists your ability reduction magic.
return true;
}
int oldStr = SpellHelper.GetCurseOffset(m, StatType.Str);
int oldDex = SpellHelper.GetCurseOffset(m, StatType.Dex);
int oldInt = SpellHelper.GetCurseOffset(m, StatType.Int);
int newStr = SpellHelper.GetOffset(caster, m, StatType.Str, true, true);
int newDex = SpellHelper.GetOffset(caster, m, StatType.Dex, true, true);
int newInt = SpellHelper.GetOffset(caster, m, StatType.Int, true, true);
if ((-newStr > oldStr && -newDex > oldDex && -newInt > oldInt) ||
(newStr == 0 && newDex == 0 && newInt == 0))
{
return false;
}
SpellHelper.AddStatCurse(caster, m, StatType.Str, false);
SpellHelper.AddStatCurse(caster, m, StatType.Dex, true);
SpellHelper.AddStatCurse(caster, m, StatType.Int, true);
int percentage = (int)(SpellHelper.GetOffsetScalar(caster, m, true) * 100);
TimeSpan length = SpellHelper.GetDuration(caster, m);
string args;
if (masscurse)
{
args = String.Format("{0}\t{0}\t{0}", percentage);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.MassCurse, 1075839, length, m, args));
}
else
{
args = String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", percentage, percentage, percentage, 10, 10, 10, 10);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Curse, 1075835, 1075836, length, m, args.ToString()));
}
AddEffect(m, SpellHelper.GetDuration(caster, m), oldStr, oldDex, oldInt);
if (m.Spell != null)
m.Spell.OnCasterHurt();
m.Paralyzed = false;
m.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist);
m.PlaySound(0x1E1);
return true;
}
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)Circle, Caster, ref m);
if (DoCurse(Caster, m, false))
{
HarmfulSpell(m);
}
else
{
DoHurtFizzle();
}
}
FinishSequence();
}
private class InternalTarget : Target
{
private readonly CurseSpell m_Owner;
public InternalTarget(CurseSpell owner)
: base(Core.ML ? 10 : 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,334 @@
using System;
using System.Collections;
using Server.Items;
using Server.Misc;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Fourth
{
public class FireFieldSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Fire Field", "In Flam Grav",
215,
9041,
false,
Reagent.BlackPearl,
Reagent.SpidersSilk,
Reagent.SulfurousAsh);
public FireFieldSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fourth;
}
}
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) && SpellHelper.CheckWater(new Point3D(p), Caster.Map) && 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));
Point3D pnt = new Point3D(p);
if (SpellHelper.CheckField(pnt, Caster.Map))
new FireFieldItem(itemID, pnt, Caster, Caster.Map, duration);
for (int i = 1; i <= 2; ++i)
{
Timer.DelayCall<int>(TimeSpan.FromMilliseconds(i * 300), index =>
{
Point3D point = new Point3D(eastToWest ? pnt.X + index : pnt.X, eastToWest ? pnt.Y : pnt.Y + index, pnt.Z);
SpellHelper.AdjustField(ref point, Caster.Map, 16, false);
if (SpellHelper.CheckField(point, Caster.Map))
new FireFieldItem(itemID, point, Caster, Caster.Map, duration);
point = new Point3D(eastToWest ? pnt.X + -index : pnt.X, eastToWest ? pnt.Y : pnt.Y + -index, pnt.Z);
SpellHelper.AdjustField(ref point, Caster.Map, 16, false);
if (SpellHelper.CheckField(point, Caster.Map))
new FireFieldItem(itemID, point, Caster, Caster.Map, duration);
}, i);
}
}
FinishSequence();
}
[DispellableField]
public class FireFieldItem : Item
{
private Timer m_Timer;
private DateTime m_End;
private Mobile m_Caster;
private int m_Damage;
public Mobile Caster { get { return m_Caster; } }
public FireFieldItem(int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration)
: this(itemID, loc, caster, map, duration, 2)
{
}
public FireFieldItem(int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int damage)
: base(itemID)
{
bool canFit = SpellHelper.AdjustField(ref loc, map, 12, false);
Movable = false;
Light = LightType.Circle300;
MoveToWorld(loc, map);
Effects.SendLocationParticles(EffectItem.Create(loc, map, EffectItem.DefaultDuration), 0x376A, 9, 10, 5029);
m_Caster = caster;
m_Damage = damage;
m_End = DateTime.UtcNow + duration;
m_Timer = new InternalTimer(this, caster.InLOS(this), canFit);
m_Timer.Start();
}
public FireFieldItem(Serial serial)
: base(serial)
{
}
public override bool BlocksFit
{
get
{
return true;
}
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
if (m_Timer != null)
m_Timer.Stop();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)2); // version
writer.Write(m_Damage);
writer.Write(m_Caster);
writer.WriteDeltaTime(m_End);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch ( version )
{
case 2:
{
m_Damage = reader.ReadInt();
goto case 1;
}
case 1:
{
m_Caster = reader.ReadMobile();
goto case 0;
}
case 0:
{
m_End = reader.ReadDeltaTime();
m_Timer = new InternalTimer(this, true, true);
m_Timer.Start();
break;
}
}
if (version < 2)
m_Damage = 2;
}
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))
{
if (SpellHelper.CanRevealCaster(m))
m_Caster.RevealingAction();
m_Caster.DoHarmful(m);
int damage = m_Damage;
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);
if (m is BaseCreature)
((BaseCreature)m).OnHarmfulSpell(m_Caster);
}
return true;
}
private class InternalTimer : Timer
{
private static readonly Queue m_Queue = new Queue();
private readonly FireFieldItem m_Item;
private readonly bool m_InLOS;
private readonly bool m_CanFit;
public InternalTimer(FireFieldItem item, bool inLOS, bool canFit)
: base(TimeSpan.FromMilliseconds(500), 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 (DateTime.UtcNow > 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)
{
IPooledEnumerable eable = m_Item.GetMobilesInRange(0);
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();
if (SpellHelper.CanRevealCaster(m))
caster.RevealingAction();
caster.DoHarmful(m);
int damage = m_Item.m_Damage;
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);
if (m is BaseCreature)
((BaseCreature)m).OnHarmfulSpell(caster);
}
}
}
}
}
}
public class InternalTarget : Target
{
private readonly FireFieldSpell m_Owner;
public InternalTarget(FireFieldSpell owner)
: base(Core.TOL ? 15 : Core.ML ? 10 : 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,100 @@
using System;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
namespace Server.Spells.Fourth
{
public class GreaterHealSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Greater Heal", "In Vas Mani",
204,
9061,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.MandrakeRoot,
Reagent.SpidersSilk);
public GreaterHealSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fourth;
}
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (!this.Caster.CanSee(m))
{
this.Caster.SendLocalizedMessage(500237); // Target can not be seen.
}
else if (m is BaseCreature && ((BaseCreature)m).IsAnimatedDead)
{
this.Caster.SendLocalizedMessage(1061654); // You cannot heal that which is not alive.
}
else if (m.IsDeadBondedPet)
{
this.Caster.SendLocalizedMessage(1060177); // You cannot heal a creature that is already dead!
}
else if (m is IRepairableMobile)
{
this.Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500951); // You cannot heal that.
}
else if (m.Poisoned || Server.Items.MortalStrike.IsWounded(m))
{
this.Caster.LocalOverheadMessage(MessageType.Regular, 0x22, (this.Caster == m) ? 1005000 : 1010398);
}
else if (this.CheckBSequence(m))
{
SpellHelper.Turn(this.Caster, m);
// Algorithm: (40% of magery) + (1-10)
int toHeal = (int)(this.Caster.Skills[SkillName.Magery].Value * 0.4);
toHeal += Utility.Random(1, 10);
//m.Heal( toHeal, Caster );
SpellHelper.Heal(toHeal, m, this.Caster);
m.FixedParticles(0x376A, 9, 32, 5030, EffectLayer.Waist);
m.PlaySound(0x202);
}
this.FinishSequence();
}
public class InternalTarget : Target
{
private readonly GreaterHealSpell m_Owner;
public InternalTarget(GreaterHealSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Beneficial)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
{
this.m_Owner.Target((Mobile)o);
}
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

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

View File

@@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using Server.Targeting;
namespace Server.Spells.Fourth
{
public class ManaDrainSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Mana Drain", "Ort Rel",
215,
9031,
Reagent.BlackPearl,
Reagent.MandrakeRoot,
Reagent.SpidersSilk);
private static readonly Dictionary<Mobile, Timer> m_Table = new Dictionary<Mobile, Timer>();
public ManaDrainSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fourth;
}
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (!this.Caster.CanSee(m))
{
this.Caster.SendLocalizedMessage(500237); // Target can not be seen.
}
else if (this.CheckHSequence(m))
{
SpellHelper.Turn(this.Caster, m);
SpellHelper.CheckReflect((int)this.Circle, this.Caster, ref m);
if (m.Spell != null)
m.Spell.OnCasterHurt();
m.Paralyzed = false;
if (Core.AOS)
{
int toDrain = 40 + (int)(this.GetDamageSkill(this.Caster) - this.GetResistSkill(m));
if (toDrain < 0)
toDrain = 0;
else if (toDrain > m.Mana)
toDrain = m.Mana;
if (m_Table.ContainsKey(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 (this.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);
}
this.HarmfulSpell(m);
}
this.FinishSequence();
}
public override double GetResistPercent(Mobile target)
{
return 99.0;
}
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);
}
private class InternalTarget : Target
{
private readonly ManaDrainSpell m_Owner;
public InternalTarget(ManaDrainSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
this.m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,318 @@
using System;
using Server.Items;
using Server.Mobiles;
using Server.Multis;
using Server.Network;
using Server.Spells.Necromancy;
using Server.Targeting;
namespace Server.Spells.Fourth
{
public class RecallSpell : MagerySpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Recall", "Kal Ort Por",
239,
9031,
Reagent.BlackPearl,
Reagent.Bloodmoss,
Reagent.MandrakeRoot);
private readonly RunebookEntry m_Entry;
private readonly Runebook m_Book;
private readonly VendorSearchMap m_SearchMap;
private readonly AuctionMap m_AuctionMap;
public bool NoSkillRequirement { get { return (Core.SE && (m_Book != null || m_AuctionMap != null || m_SearchMap != null)) || TransformationSpellHelper.UnderTransformation(Caster, typeof(WraithFormSpell)); } }
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 RecallSpell(Mobile caster, Item scroll, VendorSearchMap map)
: base(caster, scroll, m_Info)
{
m_SearchMap = map;
}
public RecallSpell(Mobile caster, Item scroll, AuctionMap map)
: base(caster, scroll, m_Info)
{
m_AuctionMap = map;
}
public override SpellCircle Circle
{
get
{
return SpellCircle.Fourth;
}
}
public override void GetCastSkills(out double min, out double max)
{
if (NoSkillRequirement) //recall using Runebook charge, wraith form or using vendor search map
min = max = 0;
else
base.GetCastSkills(out min, out max);
}
public override void OnCast()
{
if (m_Entry == null && m_SearchMap == null && m_AuctionMap == null)
{
Caster.Target = new InternalTarget(this);
}
else
{
Point3D loc;
Map map;
if (m_Entry != null)
{
if (m_Entry.Type != RecallRuneType.Ship)
{
loc = m_Entry.Location;
map = m_Entry.Map;
}
else
{
Effect(m_Entry.Galleon);
return;
}
}
else if (m_SearchMap != null)
{
loc = m_SearchMap.GetLocation(Caster);
map = m_SearchMap.GetMap();
}
else
{
loc = m_AuctionMap.GetLocation(Caster);
map = m_AuctionMap.GetMap();
}
Effect(loc, map, true, false);
}
}
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 (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(BaseGalleon galleon)
{
if (galleon == null)
{
Caster.SendLocalizedMessage(1116767); // The ship could not be located.
}
else if (galleon.Map == Map.Internal)
{
Caster.SendLocalizedMessage(1149569); // That ship is in dry dock.
}
else if (!galleon.HasAccess(Caster))
{
Caster.SendLocalizedMessage(1116617); // You do not have permission to board this ship.
}
else
{
Effect(galleon.GetMarkedLocation(), galleon.Map, false, true);
}
}
public void Effect(Point3D loc, Map map, bool checkMulti, bool isboatkey = false)
{
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 (SpellHelper.RestrictRedTravel && Caster.Murderer && map.Rules != MapRules.FeluccaRules)
{
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 (Misc.WeightOverloading.IsOverloaded(Caster))
{
Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move.
}
else if (!map.CanSpawnMobile(loc.X, loc.Y, loc.Z) && !isboatkey)
{
Caster.SendLocalizedMessage(501025); // Something is blocking the location.
}
else if (checkMulti && SpellHelper.CheckMulti(loc, map) && !isboatkey)
{
Caster.SendLocalizedMessage(501025); // Something is blocking the location.
}
else if (m_Book != null && m_Book.CurCharges <= 0)
{
Caster.SendLocalizedMessage(502412); // There are no charges left on that item.
}
else if (Caster.Holding != null)
{
Caster.SendLocalizedMessage(1071955); // You cannot teleport while dragging an object.
}
else if (Engines.CityLoyalty.CityTradeSystem.HasTrade(Caster))
{
Caster.SendLocalizedMessage(1151733); // You cannot do that while carrying a Trade Order.
}
else if (CheckSequence())
{
BaseCreature.TeleportPets(Caster, loc, map, true);
if (m_Book != null)
--m_Book.CurCharges;
if (m_SearchMap != null)
m_SearchMap.OnBeforeTravel(Caster);
if (m_AuctionMap != null)
m_AuctionMap.OnBeforeTravel(Caster);
Caster.PlaySound(0x1FC);
Caster.MoveToWorld(loc, map);
Caster.PlaySound(0x1FC);
}
FinishSequence();
}
private class InternalTarget : Target
{
private readonly RecallSpell m_Owner;
public InternalTarget(RecallSpell owner)
: base(Core.ML ? 10 : 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)
{
if (rune.Type == RecallRuneType.Ship)
{
m_Owner.Effect(rune.Galleon);
}
else
{
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)
{
if (e.Type == RecallRuneType.Ship)
{
m_Owner.Effect(e.Galleon);
}
else
{
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, true);
else
from.Send(new MessageLocalized(from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "")); // I can not recall from that object.
}
else if (o is Engines.NewMagincia.WritOfLease)
{
Engines.NewMagincia.WritOfLease lease = (Engines.NewMagincia.WritOfLease)o;
if (lease.RecallLoc != Point3D.Zero && lease.Facet != null && lease.Facet != Map.Internal)
m_Owner.Effect(lease.RecallLoc, lease.Facet, 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 OnNonlocalTarget(Mobile from, object o)
{
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,98 @@
using System;
using Server.Mobiles;
using Server.Network;
namespace Server.Spells
{
public class FlySpell : Spell
{
private static readonly SpellInfo m_Info = new SpellInfo("Gargoyle Flight", null, -1, 9002);
public FlySpell(Mobile caster)
: base(caster, null, m_Info)
{
}
public override bool ClearHandsOnCast { get { return false; } }
public override bool RevealOnCast { get { return false; } }
public override double CastDelayFastScalar { get { return 0; } }
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(2.0); } }
public override TimeSpan GetCastRecovery() { return TimeSpan.Zero; }
public override int GetMana() { return 0; }
public override bool ConsumeReagents() { return true; }
public override bool CheckFizzle() { return true; }
public override bool CheckNextSpellTime { get { return false; } }
public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable)
{
if (type == DisturbType.EquipRequest || type == DisturbType.UseRequest)
return false;
return true;
}
public override void SayMantra()
{
}
public override void OnDisturb(DisturbType type, bool message)
{
Caster.Flying = false;
BuffInfo.RemoveBuff(this.Caster, BuffIcon.Fly);
if (message)
Caster.SendLocalizedMessage(1113192); // You have been disrupted while attempting to fly!
}
public static bool CheckFlyingAllowed(Mobile mob, bool message)
{
if (mob.Region != null && !mob.Region.AllowFlying(mob))
{
mob.SendMessage("You may not fly here.");
return false;
}
return true;
}
public override bool CheckCast()
{
if (!CheckFlyingAllowed(Caster, true))
{
return false;
}
else if (!Caster.Alive)
{
Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1113082); // You may not fly while dead.
}
else if (Factions.Sigil.ExistsOn(Caster))
{
Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil.
}
else if (!Caster.CanBeginAction(typeof(Seventh.PolymorphSpell)))
{
Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1112453); // You can't fly in your current form!
}
else if (Ninjitsu.AnimalForm.UnderTransformation(Caster) || Mysticism.StoneFormSpell.IsEffected(Caster) || (TransformationSpellHelper.UnderTransformation(Caster)
&& !TransformationSpellHelper.UnderTransformation(Caster, typeof(Spells.Necromancy.VampiricEmbraceSpell))) || (Caster.IsBodyMod && !Caster.Body.IsHuman))
{
Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1112453); // You can't fly in your current form!
}
else if (Caster.Region.OnBeginSpellCast(Caster, this) && Server.Mobiles.BaseMount.CheckMountAllowed(Caster, true, true))
{
Caster.Flying = true;
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Fly, 1112193, 1112567)); // Flying & You are flying.
Caster.Animate(AnimationType.TakeOff, 0);
return true;
}
return false;
}
public override void OnCast()
{
FinishSequence();
}
}
}

View File

@@ -0,0 +1,241 @@
using System;
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));
}
if (Core.ML)
{
Register(600, typeof(Spellweaving.ArcaneCircleSpell));
Register(601, typeof(Spellweaving.GiftOfRenewalSpell));
Register(602, typeof(Spellweaving.ImmolatingWeaponSpell));
Register(603, typeof(Spellweaving.AttuneWeaponSpell));
Register(604, typeof(Spellweaving.ThunderstormSpell));
Register(605, typeof(Spellweaving.NatureFurySpell));
Register(606, typeof(Spellweaving.SummonFeySpell));
Register(607, typeof(Spellweaving.SummonFiendSpell));
Register(608, typeof(Spellweaving.ReaperFormSpell));
Register( 609, typeof( Spellweaving.WildfireSpell ) );
Register(610, typeof(Spellweaving.EssenceOfWindSpell));
Register( 611, typeof( Spellweaving.DryadAllureSpell ) );
Register(612, typeof(Spellweaving.EtherealVoyageSpell));
Register(613, typeof(Spellweaving.WordOfDeathSpell));
Register(614, typeof(Spellweaving.GiftOfLifeSpell));
Register( 615, typeof( Spellweaving.ArcaneEmpowermentSpell ) );
}
if (Core.SA)
{
Register(677, typeof(Mysticism.NetherBoltSpell));
Register(678, typeof(Mysticism.HealingStoneSpell));
Register(679, typeof(Mysticism.PurgeMagicSpell));
Register(680, typeof(Mysticism.EnchantSpell));
Register(681, typeof(Mysticism.SleepSpell));
Register(682, typeof(Mysticism.EagleStrikeSpell));
Register(683, typeof(Mysticism.AnimatedWeaponSpell));
Register(684, typeof(Mysticism.StoneFormSpell));
Register(685, typeof(Mysticism.SpellTriggerSpell));
Register(686, typeof(Mysticism.MassSleepSpell));
Register(687, typeof(Mysticism.CleansingWindsSpell));
Register(688, typeof(Mysticism.BombardSpell));
Register(689, typeof(Mysticism.SpellPlagueSpell));
Register(690, typeof(Mysticism.HailStormSpell));
Register(691, typeof(Mysticism.NetherCycloneSpell));
Register(692, typeof(Mysticism.RisingColossusSpell));
Register(700, typeof(SkillMasteries.InspireSpell));
Register(701, typeof(SkillMasteries.InvigorateSpell));
Register(702, typeof(SkillMasteries.ResilienceSpell));
Register(703, typeof(SkillMasteries.PerseveranceSpell));
Register(704, typeof(SkillMasteries.TribulationSpell));
Register(705, typeof(SkillMasteries.DespairSpell));
}
if (Core.TOL)
{
Register(706, typeof(SkillMasteries.DeathRaySpell));
Register(707, typeof(SkillMasteries.EtherealBurstSpell));
Register(708, typeof(SkillMasteries.NetherBlastSpell));
Register(709, typeof(SkillMasteries.MysticWeaponSpell));
Register(710, typeof(SkillMasteries.CommandUndeadSpell));
Register(711, typeof(SkillMasteries.ConduitSpell));
Register(712, typeof(SkillMasteries.ManaShieldSpell));
Register(713, typeof(SkillMasteries.SummonReaperSpell));
Register(714, typeof(SkillMasteries.PassiveMasterySpell));
Register(715, typeof(SkillMasteries.PassiveMasterySpell));
Register(716, typeof(SkillMasteries.WarcrySpell));
Register(717, typeof(SkillMasteries.PassiveMasterySpell));
Register(718, typeof(SkillMasteries.RejuvinateSpell));
Register(719, typeof(SkillMasteries.HolyFistSpell));
Register(720, typeof(SkillMasteries.ShadowSpell));
Register(721, typeof(SkillMasteries.WhiteTigerFormSpell));
Register(722, typeof(SkillMasteries.FlamingShotSpell));
Register(723, typeof(SkillMasteries.PlayingTheOddsSpell));
Register(724, typeof(SkillMasteries.ThrustSpell));
Register(725, typeof(SkillMasteries.PierceSpell));
Register(726, typeof(SkillMasteries.StaggerSpell));
Register(727, typeof(SkillMasteries.ToughnessSpell));
Register(728, typeof(SkillMasteries.OnslaughtSpell));
Register(729, typeof(SkillMasteries.FocusedEyeSpell));
Register(730, typeof(SkillMasteries.ElementalFurySpell));
Register(731, typeof(SkillMasteries.CalledShotSpell));
Register(732, typeof(SkillMasteries.PassiveMasterySpell));
Register(733, typeof(SkillMasteries.ShieldBashSpell));
Register(734, typeof(SkillMasteries.BodyGuardSpell));
Register(735, typeof(SkillMasteries.HeightenedSensesSpell));
Register(736, typeof(SkillMasteries.ToleranceSpell));
Register(737, typeof(SkillMasteries.InjectedStrikeSpell));
Register(738, typeof(SkillMasteries.PassiveMasterySpell));
Register(739, typeof(SkillMasteries.RampageSpell));
Register(740, typeof(SkillMasteries.FistsOfFurySpell));
Register(741, typeof(SkillMasteries.PassiveMasterySpell));
Register(742, typeof(SkillMasteries.WhisperingSpell));
Register(743, typeof(SkillMasteries.CombatTrainingSpell));
}
}
}
public static void Register(int spellID, Type type)
{
SpellRegistry.Register(spellID, type);
}
}
}

View File

@@ -0,0 +1,134 @@
using System;
using Server;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public abstract class MysticSpell : Spell
{
public MysticSpell(Mobile caster, Item scroll, SpellInfo info)
: base(caster, scroll, info)
{
}
public abstract SpellCircle Circle { get; }
private static int[] m_ManaTable = new int[] { 4, 6, 9, 11, 14, 20, 40, 50 };
public override TimeSpan CastDelayBase { get { return TimeSpan.FromMilliseconds(((4 + (int)Circle) * CastDelaySecondsPerTick) * 1000); } }
public override double CastDelayFastScalar { get { return 1.0; } }
public double ChanceOffset { get { return Caster is Server.Mobiles.PlayerMobile ? 20.0 : 30.0; } }
private const double ChanceLength = 100.0 / 7.0;
public override void GetCastSkills(out double min, out double max)
{
int circle = (int)Circle;
if (Scroll != null)
circle -= 2;
double avg = ChanceLength * circle;
min = avg - ChanceOffset;
max = avg + ChanceOffset;
}
public override SkillName CastSkill { get { return SkillName.Mysticism; } }
public override SkillName DamageSkill
{
get
{
if (Caster.Skills[SkillName.Imbuing].Value >= Caster.Skills[SkillName.Focus].Value)
return SkillName.Imbuing;
return SkillName.Focus;
}
}
public override void SendCastEffect()
{
if(Caster.Player)
Caster.FixedEffect(0x37C4, 87, (int)(GetCastDelay().TotalSeconds * 28), 0x66C, 3);
}
public override int GetMana()
{
if (Core.TOL && this is HailStormSpell)
return 50;
return m_ManaTable[(int)Circle];
}
public override TimeSpan GetCastRecovery()
{
if (Scroll is SpellStone)
return TimeSpan.Zero;
return base.GetCastRecovery();
}
public override TimeSpan GetCastDelay()
{
if (Scroll is SpellStone)
return TimeSpan.Zero;
return base.GetCastDelay();
}
public override bool CheckCast()
{
if (!base.CheckCast())
return false;
return true;
}
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 circle = Math.Max(5, 1 + (int)Circle);
int maxSkill = circle * 10;
maxSkill += (circle / 6) * 25;
if (target.Skills[SkillName.MagicResist].Value < maxSkill)
target.CheckSkill(SkillName.MagicResist, 0.0, target.Skills[SkillName.MagicResist].Cap);
return (n >= Utility.RandomDouble());
}
public virtual double GetResistPercentForCircle(Mobile target, SpellCircle circle)
{
double value = GetResistSkill(target);
double firstPercent = value / 5.0;
double secondPercent = value - (((Caster.Skills[CastSkill].Value - 20.0) / 5.0) + (Math.Max(5, 1 + (int)circle)) * 5.0);
return (firstPercent > secondPercent ? firstPercent : secondPercent) / 2.0; // Seems should be about half of what stratics says.
}
public virtual double GetResistPercent(Mobile target)
{
return GetResistPercentForCircle(target, Circle);
}
public static double GetBaseSkill(Mobile m)
{
return m.Skills[SkillName.Mysticism].Value;
}
public static double GetBoostSkill(Mobile m)
{
return Math.Max(m.Skills[SkillName.Imbuing].Value, m.Skills[SkillName.Focus].Value);
}
}
}

View File

@@ -0,0 +1,85 @@
using System;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public class AnimatedWeaponSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Fourth; } }
private static SpellInfo m_Info = new SpellInfo(
"Animated Weapon", "In Jux Por Ylem",
230,
9022,
Reagent.BlackPearl,
Reagent.MandrakeRoot,
Reagent.Nightshade,
Reagent.Bone
);
public AnimatedWeaponSpell(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.Followers + 4) > Caster.FollowersMax)
{
Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature.
return;
}
Map map = Caster.Map;
SpellHelper.GetSurfaceTop(ref p);
if (map == null || (Caster.IsPlayer() && !map.CanSpawnMobile(p.X, p.Y, p.Z)))
{
Caster.SendLocalizedMessage(501942); // That location is blocked.
}
else if (SpellHelper.CheckTown(p, Caster) && CheckSequence())
{
int level = (int)((GetBaseSkill(Caster) + GetBoostSkill(Caster)) / 2.0);
TimeSpan duration = TimeSpan.FromSeconds(10 + level);
BaseCreature summon = new AnimatedWeapon(Caster, level);
BaseCreature.Summon(summon, false, Caster, new Point3D(p), 0x212, duration);
summon.PlaySound(0x64A);
Effects.SendTargetParticles(summon, 0x3728, 10, 10, 0x13AA, (EffectLayer)255);
}
FinishSequence();
}
public class InternalTarget : Target
{
private AnimatedWeaponSpell m_Owner;
public InternalTarget(AnimatedWeaponSpell 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,120 @@
using System;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public class BombardSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Sixth; } }
public override bool DelayedDamage { get { return true; } }
public override bool DelayedDamageStacking { get { return false; } }
private static SpellInfo m_Info = new SpellInfo(
"Bombard", "Corp Por Ylem",
230,
9022,
Reagent.Bloodmoss,
Reagent.Garlic,
Reagent.SulfurousAsh,
Reagent.DragonBlood
);
public BombardSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void OnTarget(IDamageable d)
{
if (d == null)
{
return;
}
else if (CheckHSequence(d))
{
IDamageable target = d;
IDamageable source = Caster;
SpellHelper.Turn(Caster, target);
if (Core.SA && HasDelayContext(target))
{
DoHurtFizzle();
return;
}
if (SpellHelper.CheckReflect((int)Circle, ref source, ref target))
{
Server.Timer.DelayCall(TimeSpan.FromSeconds(.5), () =>
{
source.MovingEffect(target, 0x1363, 12, 1, false, true, 0, 0);
source.PlaySound(0x64B);
});
}
Caster.MovingEffect(d, 0x1363, 12, 1, false, true, 0, 0);
Caster.PlaySound(0x64B);
SpellHelper.Damage(this, target, (int)GetNewAosDamage(40, 1, 5, target), 100, 0, 0, 0, 0);
if (target is Mobile)
{
Timer.DelayCall(TimeSpan.FromMilliseconds(1200), () =>
{
if (!CheckResisted((Mobile)target))
{
int secs = (int)((GetDamageSkill(this.Caster) / 10) - (GetResistSkill((Mobile)target) / 10));
if (secs < 0)
secs = 0;
((Mobile)target).Paralyze(TimeSpan.FromSeconds(secs));
}
});
}
}
FinishSequence();
}
public class InternalTarget : Target
{
public BombardSpell Owner { get; set; }
public InternalTarget(BombardSpell owner)
: this(owner, false)
{
}
public InternalTarget(BombardSpell owner, bool allowland)
: base(12, allowland, TargetFlags.Harmful)
{
Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o == null)
return;
if (!from.CanSee(o))
from.SendLocalizedMessage(500237); // Target can not be seen.
else if (o is IDamageable)
{
SpellHelper.Turn(from, o);
Owner.OnTarget((IDamageable)o);
}
}
protected override void OnTargetFinish(Mobile from)
{
Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,264 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Engines.PartySystem;
using Server.Items;
using Server.Spells.First;
using Server.Spells.Fourth;
using Server.Spells.Necromancy;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public class CleansingWindsSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Sixth; } }
private static SpellInfo m_Info = new SpellInfo(
"Cleansing Winds", "In Vas Mani Hur",
230,
9022,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.MandrakeRoot,
Reagent.DragonBlood
);
public CleansingWindsSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void OnTarget(object o)
{
var targeted = o as Mobile;
if (targeted == null)
return;
if (CheckBSequence(targeted))
{
/* Soothing winds attempt to neutralize poisons, lift curses, and heal a valid
* Target. The Caster's Mysticism and either Focus or Imbuing (whichever is
* greater) skills determine the effectiveness of the Cleansing Winds.
*/
Caster.PlaySound(0x64C);
var targets = new List<Mobile> { targeted };
targets.AddRange(FindAdditionalTargets(targeted).Take(3)); // This effect can hit up to 3 additional players beyond the primary target.
double primarySkill = Caster.Skills[CastSkill].Value;
double secondarySkill = Caster.Skills[DamageSkill].Value;
var toHeal = (int)((primarySkill + secondarySkill) / 4.0) + Utility.RandomMinMax(-3, 3);
toHeal /= targets.Count; // The effectiveness of the spell is reduced by the number of targets affected.
foreach (var target in targets)
{
// WARNING: This spell will flag the caster as a criminal if a criminal or murderer party member is close enough
// to the target to receive the benefits from the area of effect.
Caster.DoBeneficial(target);
PlayEffect(target);
int toHealMod = toHeal;
if (target.Poisoned)
{
int poisonLevel = target.Poison.RealLevel + 1;
int chanceToCure = (10000 + (int)((primarySkill + secondarySkill) / 2 * 75) - (poisonLevel * 1750)) / 100;
if (chanceToCure > Utility.Random(100) && target.CurePoison(Caster))
{
// Poison reduces healing factor by 15% per level of poison.
toHealMod -= (int)(toHeal * poisonLevel * 0.15);
}
else
{
// If the cure fails, the target will not be healed.
toHealMod = 0;
}
}
// Cleansing Winds will not heal the target after removing mortal wound.
if (MortalStrike.IsWounded(target))
{
toHealMod = 0;
}
var curseLevel = RemoveCurses(target);
if (toHealMod > 0 && curseLevel > 0)
{
// Each Curse reduces healing by 3 points + 1% per curse level.
toHealMod = toHealMod - (curseLevel * 3);
toHealMod = toHealMod - (int)((double)toHealMod * ((double)curseLevel / 100.0));
}
if (toHealMod > 0)
SpellHelper.Heal(toHealMod, target, Caster);
}
}
FinishSequence();
}
private static void PlayEffect(Mobile m)
{
m.FixedParticles(0x3709, 1, 30, 9963, 13, 3, EffectLayer.Head);
var from = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z - 10), m.Map);
var to = new Entity(Serial.Zero, new Point3D(m.X, m.Y, m.Z + 50), m.Map);
Effects.SendMovingParticles(from, to, 0x2255, 1, 0, false, false, 13, 3, 9501, 1, 0, EffectLayer.Head, 0x100);
}
private IEnumerable<Mobile> FindAdditionalTargets(Mobile targeted)
{
var casterParty = Party.Get(Caster);
if (casterParty == null)
yield break;
IPooledEnumerable eable = Caster.Map.GetMobilesInRange(new Point3D(targeted), 2);
foreach (Mobile m in eable)
{
if (m == null || m == targeted)
continue;
// Players in the area must be in the casters party in order to receive the beneficial effects of the spell.
if (Caster.CanBeBeneficial(m, false) && casterParty.Contains(m))
yield return m;
}
eable.Free();
}
public static int RemoveCurses(Mobile m)
{
int curseLevel = 0;
if (SleepSpell.IsUnderSleepEffects(m))
{
SleepSpell.EndSleep(m);
curseLevel += 2;
}
if (EvilOmenSpell.TryEndEffect(m))
{
curseLevel += 1;
}
if (StrangleSpell.RemoveCurse(m))
{
curseLevel += 2;
}
if (CorpseSkinSpell.RemoveCurse(m))
{
curseLevel += 3;
}
if (CurseSpell.UnderEffect(m))
{
CurseSpell.RemoveEffect(m);
curseLevel += 4;
}
if (BloodOathSpell.RemoveCurse(m))
{
curseLevel += 3;
}
if (MindRotSpell.HasMindRotScalar(m))
{
MindRotSpell.ClearMindRotScalar(m);
curseLevel += 2;
}
if (SpellPlagueSpell.HasSpellPlague(m))
{
SpellPlagueSpell.RemoveFromList(m);
curseLevel += 4;
}
if (FeeblemindSpell.IsUnderEffects(m))
{
FeeblemindSpell.RemoveEffects(m);
curseLevel += 1;
}
if (ClumsySpell.IsUnderEffects(m))
{
ClumsySpell.RemoveEffects(m);
curseLevel += 1;
}
if (WeakenSpell.IsUnderEffects(m))
{
WeakenSpell.RemoveEffects(m);
curseLevel += 1;
}
if (MortalStrike.IsWounded(m))
{
MortalStrike.EndWound(m);
curseLevel += 2;
}
BuffInfo.RemoveBuff(m, BuffIcon.Clumsy);
BuffInfo.RemoveBuff(m, BuffIcon.FeebleMind);
BuffInfo.RemoveBuff(m, BuffIcon.Weaken);
BuffInfo.RemoveBuff(m, BuffIcon.Curse);
BuffInfo.RemoveBuff(m, BuffIcon.MassCurse);
BuffInfo.RemoveBuff(m, BuffIcon.MortalStrike);
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot);
BuffInfo.RemoveBuff(m, BuffIcon.CorpseSkin);
BuffInfo.RemoveBuff(m, BuffIcon.Strangle);
BuffInfo.RemoveBuff(m, BuffIcon.EvilOmen);
return curseLevel;
}
public class InternalTarget : Target
{
public CleansingWindsSpell Owner { get; set; }
public InternalTarget(CleansingWindsSpell owner)
: this(owner, false)
{
}
public InternalTarget(CleansingWindsSpell owner, bool allowland)
: base(12, allowland, TargetFlags.Beneficial)
{
Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o == null)
return;
if (!from.CanSee(o))
from.SendLocalizedMessage(500237); // Target can not be seen.
else
{
SpellHelper.Turn(from, o);
Owner.OnTarget(o);
}
}
protected override void OnTargetFinish(Mobile from)
{
Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,112 @@
using System;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public class EagleStrikeSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Third; } }
public override bool DelayedDamage { get { return true; } }
public override bool DelayedDamageStacking { get { return false; } }
private static SpellInfo m_Info = new SpellInfo(
"Eagle Strike", "Kal Por Xen",
230,
9022,
Reagent.Bloodmoss,
Reagent.Bone,
Reagent.MandrakeRoot,
Reagent.SpidersSilk
);
public EagleStrikeSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void OnTarget(IDamageable d)
{
if (d == null)
{
return;
}
else if (CheckHSequence(d))
{
IDamageable target = d;
IDamageable source = Caster;
SpellHelper.Turn(Caster, target);
if (Core.SA && HasDelayContext(target))
{
DoHurtFizzle();
return;
}
if (SpellHelper.CheckReflect((int)Circle, ref source, ref target))
{
Timer.DelayCall(TimeSpan.FromSeconds(.5), () =>
{
source.MovingEffect(target, 0x407A, 8, 1, false, true, 0, 0);
source.PlaySound(0x2EE);
});
}
Caster.MovingEffect(d, 0x407A, 8, 1, false, true, 0, 0);
Caster.PlaySound(0x2EE);
Timer.DelayCall(TimeSpan.FromSeconds(.5), () =>
{
Caster.PlaySound(0x64D);
});
SpellHelper.Damage(this, target, (int)GetNewAosDamage(19, 1, 5, target), 0, 0, 0, 0, 100);
}
FinishSequence();
}
public class InternalTarget : Target
{
public EagleStrikeSpell Owner { get; set; }
public InternalTarget(EagleStrikeSpell owner)
: this(owner, false)
{
}
public InternalTarget(EagleStrikeSpell owner, bool allowland)
: base(12, allowland, TargetFlags.Harmful)
{
Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o == null)
return;
if (!from.CanSee(o))
from.SendLocalizedMessage(500237); // Target can not be seen.
else if (o is IDamageable)
{
SpellHelper.Turn(from, o);
Owner.OnTarget((IDamageable)o);
}
}
protected override void OnTargetFinish(Mobile from)
{
Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections;
using Server.Items;
using Server.Network;
using System.Collections.Generic;
using Server.Spells.Mysticism;
using Server.Spells;
namespace Server.Gumps
{
public class EnchantSpellGump : Gump
{
private Mobile m_Caster;
private Item m_Scroll;
private BaseWeapon m_Weapon;
public EnchantSpellGump(Mobile caster, Item scroll, BaseWeapon weapon)
: base(20, 20)
{
m_Caster = caster;
m_Scroll = scroll;
m_Weapon = weapon;
int font = 0x07FF;
AddBackground(0, 0, 260, 187, 3600);
AddAlphaRegion(5, 15, 242, 170);
AddImageTiled(220, 15, 30, 162, 10464);
AddItem(0, 3, 6882);
AddItem(-8, 170, 6880);
AddItem(185, 3, 6883);
AddItem(192, 170, 6881);
AddHtmlLocalized(20, 22, 150, 16, 1080133, font, false, false); //Select Enchant
AddButton(20, 50, 9702, 9703, 1, GumpButtonType.Reply, 0);
AddHtmlLocalized(45, 50, 200, 16, 1079705, font, false, false); //Hit Lighting
AddButton(20, 75, 9702, 9703, 2, GumpButtonType.Reply, 0);
AddHtmlLocalized(45, 75, 200, 16, 1079703, font, false, false); //Hit Fireball
AddButton(20, 100, 9702, 9703, 3, GumpButtonType.Reply, 0);
AddHtmlLocalized(45, 100, 200, 16, 1079704, font, false, false); //Hit Harm
AddButton(20, 125, 9702, 9703, 4, GumpButtonType.Reply, 0);
AddHtmlLocalized(45, 125, 200, 16, 1079706, font, false, false); //Hit Magic Arrow
AddButton(20, 150, 9702, 9703, 5, GumpButtonType.Reply, 0);
AddHtmlLocalized(45, 150, 200, 16, 1079702, font, false, false); //Hit Dispel
}
public override void OnResponse(NetState sender, RelayInfo info)
{
AosWeaponAttribute attr = AosWeaponAttribute.HitLightning;
switch (info.ButtonID)
{
default:
m_Caster.SendLocalizedMessage(1080132); //You decide not to enchant your weapon.
return;
case 1: //Hit Lightning
{
attr = AosWeaponAttribute.HitLightning;
break;
}
case 2: //Hit Fireball
{
attr = AosWeaponAttribute.HitFireball;
break;
}
case 3: //Hit Harm
{
attr = AosWeaponAttribute.HitHarm;
break;
}
case 4: //Hit Magic Arrow
{
attr = AosWeaponAttribute.HitMagicArrow;
break;
}
case 5: //Hit Dispel
{
attr = AosWeaponAttribute.HitDispel;
break;
}
}
Spell spell = new EnchantSpell(m_Caster, m_Scroll, m_Weapon, attr);
spell.Cast();
}
}
}

View File

@@ -0,0 +1,259 @@
using System;
using Server.Gumps;
using Server.Items;
using System.Collections.Generic;
using Server;
using Server.Mobiles;
using Server.Spells;
using Server.Network;
using Server.Spells.Spellweaving;
namespace Server.Spells.Mysticism
{
public class EnchantSpell : MysticSpell
{
private static readonly string ModName = "EnchantAttribute";
public override SpellCircle Circle { get { return SpellCircle.Second; } }
public override bool ClearHandsOnCast { get { return false; } }
public BaseWeapon Weapon { get; set; }
public AosWeaponAttribute Attribute { get; set; }
private static SpellInfo m_Info = new SpellInfo(
"Enchant", "In Ort Ylem",
230,
9022,
Reagent.SpidersSilk,
Reagent.MandrakeRoot,
Reagent.SulfurousAsh
);
public EnchantSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public EnchantSpell( Mobile caster, Item scroll, BaseWeapon weapon, AosWeaponAttribute attribute ) : base( caster, scroll, m_Info )
{
Weapon = weapon;
this.Attribute = attribute;
}
public override bool CheckCast()
{
if (Weapon == null)
{
BaseWeapon wep = Caster.Weapon as BaseWeapon;
if (wep == null)
{
Caster.SendLocalizedMessage(501078); // You must be holding a weapon.
}
else
{
if (Caster.HasGump(typeof(EnchantSpellGump)))
{
Caster.CloseGump(typeof(EnchantSpellGump));
}
var gump = new EnchantSpellGump(Caster, Scroll, wep);
int serial = gump.Serial;
Caster.SendGump(gump);
Timer.DelayCall(TimeSpan.FromSeconds(30), () =>
{
var current = Caster.FindGump(typeof(EnchantSpellGump));
if (current != null && current.Serial == serial)
{
Caster.CloseGump(typeof(EnchantSpellGump));
FinishSequence();
}
});
}
return false;
}
else if (IsUnderSpellEffects(Caster, Weapon))
{
Caster.SendLocalizedMessage(501775); // This spell is already in effect.
return false;
}
else if (ImmolatingWeaponSpell.IsImmolating(Caster, Weapon) || Weapon.ConsecratedContext != null)
{
Caster.SendLocalizedMessage(1080128); //You cannot use this ability while your weapon is enchanted.
return false;
}
else if (Weapon.FocusWeilder != null)
{
Caster.SendLocalizedMessage(1080446); // You cannot enchant an item that is under the effects of the ninjitsu focus attack ability.
return false;
}
else if (Weapon.WeaponAttributes.HitLightning > 0 || Weapon.WeaponAttributes.HitFireball > 0 || Weapon.WeaponAttributes.HitHarm > 0 || Weapon.WeaponAttributes.HitMagicArrow > 0 || Weapon.WeaponAttributes.HitDispel > 0)
{
Caster.SendLocalizedMessage(1080127); // This weapon already has a hit spell effect and cannot be enchanted.
return false;
}
return true;
}
public override void OnCast()
{
BaseWeapon wep = Caster.Weapon as BaseWeapon;
if (wep == null || wep != Weapon)
{
Caster.SendLocalizedMessage(501078); // You must be holding a weapon.
}
else if (IsUnderSpellEffects(Caster, Weapon))
{
Caster.SendLocalizedMessage(501775); // This spell is already in effect.
}
else if (ImmolatingWeaponSpell.IsImmolating(Caster, Weapon) || Weapon.ConsecratedContext != null)
{
Caster.SendLocalizedMessage(1080128); //You cannot use this ability while your weapon is enchanted.
}
else if (Weapon.FocusWeilder != null)
{
Caster.SendLocalizedMessage(1080446); // You cannot enchant an item that is under the effects of the ninjitsu focus attack ability.
}
else if (Weapon.WeaponAttributes.HitLightning > 0 || Weapon.WeaponAttributes.HitFireball > 0 || Weapon.WeaponAttributes.HitHarm > 0 || Weapon.WeaponAttributes.HitMagicArrow > 0 || Weapon.WeaponAttributes.HitDispel > 0)
{
Caster.SendLocalizedMessage(1080127); // This weapon already has a hit spell effect and cannot be enchanted.
}
else if (CheckSequence() && Caster.Weapon == Weapon)
{
Caster.PlaySound(0x64E);
Caster.FixedEffect(0x36CB, 1, 9, 1915, 0);
int prim = (int)Caster.Skills[CastSkill].Value;
int sec = (int)Caster.Skills[DamageSkill].Value;
int value = (60 * (prim + sec)) / 240;
double duration = ((double)(prim + sec) / 2.0) + 30.0;
int malus = 0;
if (Table == null)
Table = new Dictionary<Mobile, EnchantmentTimer>();
Enhancement.SetValue(Caster, this.Attribute, value, ModName);
if (prim >= 80 && sec >= 80 && Weapon.Attributes.SpellChanneling == 0)
{
Enhancement.SetValue(Caster, AosAttribute.SpellChanneling, 1, ModName);
Enhancement.SetValue(Caster, AosAttribute.CastSpeed, -1, ModName);
malus = 1;
}
Table[Caster] = new EnchantmentTimer(Caster, Weapon, this.Attribute, value, malus, duration);
int loc;
switch (this.Attribute)
{
default:
case AosWeaponAttribute.HitLightning: loc = 1060423; break;
case AosWeaponAttribute.HitFireball: loc = 1060420; break;
case AosWeaponAttribute.HitHarm: loc = 1060421; break;
case AosWeaponAttribute.HitMagicArrow: loc = 1060426; break;
case AosWeaponAttribute.HitDispel: loc = 1060417; break;
}
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Enchant, 1080126, loc, TimeSpan.FromSeconds(duration), Caster, value.ToString()));
Weapon.EnchantedWeilder = Caster;
Weapon.InvalidateProperties();
}
FinishSequence();
}
public static Dictionary<Mobile, EnchantmentTimer> Table { get; set; }
public static bool IsUnderSpellEffects(Mobile Caster, BaseWeapon wep)
{
if (Table == null)
return false;
return Table.ContainsKey(Caster) && Table[Caster].Weapon == wep;
}
public static AosWeaponAttribute BonusAttribute(Mobile from)
{
if (Table.ContainsKey(from))
return Table[from].WeaponAttribute;
return AosWeaponAttribute.HitColdArea;
}
public static int BonusValue(Mobile from)
{
if (Table.ContainsKey(from))
return Table[from].AttributeValue;
return 0;
}
public static bool CastingMalus(Mobile from, BaseWeapon weapon)
{
if (Table.ContainsKey(from))
return Table[from].CastingMalus > 0;
return false;
}
public static void RemoveEnchantment(Mobile caster)
{
if(Table != null && Table.ContainsKey(caster))
{
Table[caster].Stop();
Table[caster] = null;
Table.Remove(caster);
caster.SendLocalizedMessage(1115273); // The enchantment on your weapon has expired.
caster.PlaySound(0x1E6);
Enhancement.RemoveMobile(caster);
}
}
public static void OnWeaponRemoved(BaseWeapon wep, Mobile from)
{
if(IsUnderSpellEffects(from, wep))
RemoveEnchantment(from);
if (wep.EnchantedWeilder != null)
wep.EnchantedWeilder = null;
}
}
public class EnchantmentTimer : Timer
{
public Mobile Owner { get; set; }
public BaseWeapon Weapon { get; set; }
public AosWeaponAttribute WeaponAttribute { get; set; }
public int AttributeValue { get; set; }
public int CastingMalus { get; set; }
public EnchantmentTimer(Mobile owner, BaseWeapon wep, AosWeaponAttribute attribute, int value, int malus, double duration) : base(TimeSpan.FromSeconds(duration))
{
Owner = owner;
Weapon = wep;
WeaponAttribute = attribute;
AttributeValue = value;
CastingMalus = malus;
this.Start();
}
protected override void OnTick()
{
if(Weapon != null)
Weapon.EnchantedWeilder = null;
EnchantSpell.RemoveEnchantment(Owner);
}
}
}

View File

@@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public class HailStormSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Seventh; } }
public override bool DelayedDamage { get { return true; } }
public override DamageType SpellDamageType { get { return DamageType.SpellAOE; } }
private static SpellInfo m_Info = new SpellInfo(
"Hail Storm", "Kal Des Ylem",
230,
9022,
Reagent.BlackPearl,
Reagent.Bloodmoss,
Reagent.MandrakeRoot,
Reagent.DragonBlood
);
public HailStormSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void OnTarget(IPoint3D p)
{
if (SpellHelper.CheckTown(p, Caster) && CheckSequence())
{
SpellHelper.Turn(Caster, p);
SpellHelper.GetSurfaceTop(ref p);
Map map = Caster.Map;
if (map == null)
return;
Rectangle2D effectArea = new Rectangle2D(p.X - 3, p.Y - 3, 6, 6);
Effects.PlaySound(p, map, 0x64F);
for (int x = effectArea.X; x <= effectArea.X + effectArea.Width; x++)
{
for (int y = effectArea.Y; y <= effectArea.Y + effectArea.Height; y++)
{
if (x == effectArea.X && y == effectArea.Y ||
x >= effectArea.X + effectArea.Width - 1 && y >= effectArea.Y + effectArea.Height - 1 ||
y >= effectArea.Y + effectArea.Height - 1 && x == effectArea.X ||
y == effectArea.Y && x >= effectArea.X + effectArea.Width - 1)
continue;
IPoint3D pnt = new Point3D(x, y, p.Z);
SpellHelper.GetSurfaceTop(ref pnt);
Timer.DelayCall<Point3D>(TimeSpan.FromMilliseconds(Utility.RandomMinMax(100, 300)), point =>
{
Effects.SendLocationEffect(point, map, 0x3779, 12, 11, 0x63, 0);
},
new Point3D(pnt));
}
}
var list = AcquireIndirectTargets(p, 2).ToList();
int count = list.Count;
foreach (var id in list)
{
if (id.Deleted)
continue;
int damage = GetNewAosDamage(51, 1, 5, id is PlayerMobile, id);
if (count > 2)
damage = (damage * 2) / count;
Caster.DoHarmful(id);
SpellHelper.Damage(this, id, damage, 0, 0, 100, 0, 0);
Server.Effects.SendTargetParticles(id, 0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255, 0);
}
ColUtility.Free(list);
}
FinishSequence();
}
public class InternalTarget : Target
{
private HailStormSpell m_Owner;
public InternalTarget(HailStormSpell owner)
: base(10, true, TargetFlags.None)
{
m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is IPoint3D)
m_Owner.OnTarget((IPoint3D)o);
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public class HealingStoneSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.First; } }
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(5); } }
private static SpellInfo m_Info = new SpellInfo(
"Healing Stone", "Kal In Mani",
230,
9022,
Reagent.Bone,
Reagent.Garlic,
Reagent.Ginseng,
Reagent.SpidersSilk
);
public HealingStoneSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
if ( Caster.Backpack != null && CheckSequence() )
{
Item[] stones = Caster.Backpack.FindItemsByType( typeof( HealingStone ) );
for ( int i = 0; i < stones.Length; i++ )
stones[i].Delete();
int amount = (int)((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) * 1.5);
int maxHeal = (int)((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 5);
Caster.PlaySound( 0x650 );
Caster.FixedParticles(0x3779, 1, 15, 0x251E, 0, 0, EffectLayer.Waist);
Caster.Backpack.DropItem( new HealingStone( Caster, amount, maxHeal ) );
Caster.SendLocalizedMessage( 1080115 ); // A Healing Stone appears in your backpack.
}
FinishSequence();
}
}
}

View File

@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public class MassSleepSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Fifth; } }
private static SpellInfo m_Info = new SpellInfo(
"Mass Sleep", "Vas Zu",
230,
9022,
Reagent.Ginseng,
Reagent.Nightshade,
Reagent.SpidersSilk
);
public MassSleepSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public class InternalTarget : Target
{
private MassSleepSpell m_Owner;
public InternalTarget(MassSleepSpell owner)
: base(10, 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();
}
}
public void Target(IPoint3D p)
{
if (!Caster.CanSee(p))
{
Caster.SendLocalizedMessage(500237); // Target can not be seen.
}
else if (SpellHelper.CheckTown(p, Caster) && CheckSequence())
{
Map map = Caster.Map;
if (map == null)
return;
foreach (var m in AcquireIndirectTargets(p, 3).OfType<Mobile>())
{
double duration = ((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 20) + 3;
duration -= GetResistSkill(m) / 10;
if (duration > 0)
{
Caster.DoHarmful(m);
SleepSpell.DoSleep(Caster, m, TimeSpan.FromSeconds(duration));
}
}
}
FinishSequence();
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
using Server.Spells.Fifth;
using Server.Spells.Seventh;
namespace Server.Spells.Mysticism
{
public abstract class MysticTransformationSpell : MysticSpell, ITransformationSpell
{
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 MysticTransformationSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info )
{
}
public override bool BlockedByHorrificBeast{ get{ return false; } }
public override bool CheckCast()
{
if( !TransformationSpellHelper.CheckCast( Caster, this ) )
return false;
return base.CheckCast();
}
public override void OnCast()
{
TransformationSpellHelper.OnCast( Caster, this );
FinishSequence();
}
public virtual double TickRate{ get{ return 1.0; } }
public virtual void OnTick( Mobile m )
{
}
public virtual void DoEffect( Mobile m )
{
}
public virtual void RemoveEffect( Mobile m )
{
}
}
}

View File

@@ -0,0 +1,105 @@
using System;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public class NetherBoltSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.First; } }
private static SpellInfo m_Info = new SpellInfo(
"Nether Bolt", "In Corp Ylem",
230,
9022,
Reagent.BlackPearl,
Reagent.SulfurousAsh
);
public NetherBoltSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override bool DelayedDamage { get { return true; } }
public override bool DelayedDamageStacking { get { return false; } }
public override Type[] DelayDamageFamily { get { return new Type[] { typeof(Server.Spells.First.MagicArrowSpell) }; } }
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void OnTarget(IDamageable d)
{
if (d == null)
{
return;
}
else if (CheckHSequence(d))
{
IDamageable target = d;
IDamageable source = Caster;
SpellHelper.Turn(Caster, target);
if (Core.SA && HasDelayContext(target))
{
DoHurtFizzle();
return;
}
if (SpellHelper.CheckReflect((int)Circle, ref source, ref target))
{
Timer.DelayCall(TimeSpan.FromSeconds(.5), () =>
{
source.MovingParticles(target, 0x36D4, 7, 0, false, true, 0x49A, 0, 0, 9502, 4019, 0x160);
source.PlaySound(0x211);
});
}
double damage = GetNewAosDamage(10, 1, 4, target);
SpellHelper.Damage(this, target, damage, 0, 0, 0, 0, 0, 100, 0);
Caster.MovingParticles(d, 0x36D4, 7, 0, false, true, 0x49A, 0, 0, 9502, 4019, 0x160);
Caster.PlaySound(0x211);
}
FinishSequence();
}
public class InternalTarget : Target
{
public NetherBoltSpell Owner { get; set; }
public InternalTarget(NetherBoltSpell owner)
: this(owner, false)
{
}
public InternalTarget(NetherBoltSpell owner, bool allowland)
: base(12, allowland, TargetFlags.Harmful)
{
Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o == null)
return;
if (!from.CanSee(o))
from.SendLocalizedMessage(500237); // Target can not be seen.
else if (o is IDamageable)
{
SpellHelper.Turn(from, o);
Owner.OnTarget((IDamageable)o);
}
}
protected override void OnTargetFinish(Mobile from)
{
Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public class NetherCycloneSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Eighth; } }
public override DamageType SpellDamageType { get { return DamageType.SpellAOE; } }
private static SpellInfo m_Info = new SpellInfo(
"Nether Cyclone", "Grav Hur",
230,
9022,
Reagent.MandrakeRoot,
Reagent.Nightshade,
Reagent.SulfurousAsh,
Reagent.Bloodmoss
);
public NetherCycloneSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void OnTarget(IPoint3D p)
{
if (p != null && CheckSequence())
{
SpellHelper.Turn(Caster, p);
SpellHelper.GetSurfaceTop(ref p);
Map map = Caster.Map;
if (map != null)
{
Rectangle2D effectArea = new Rectangle2D(p.X - 3, p.Y - 3, 6, 6);
Effects.PlaySound(p, map, 0x64F);
for (int x = effectArea.X; x <= effectArea.X + effectArea.Width; x++)
{
for (int y = effectArea.Y; y <= effectArea.Y + effectArea.Height; y++)
{
if (x == effectArea.X && y == effectArea.Y ||
x >= effectArea.X + effectArea.Width - 1 && y >= effectArea.Y + effectArea.Height - 1 ||
y >= effectArea.Y + effectArea.Height - 1 && x == effectArea.X ||
y == effectArea.Y && x >= effectArea.X + effectArea.Width - 1)
continue;
IPoint3D pnt = new Point3D(x, y, p.Z);
SpellHelper.GetSurfaceTop(ref pnt);
Timer.DelayCall<Point3D>(TimeSpan.FromMilliseconds(Utility.RandomMinMax(100, 300)), point =>
{
Effects.SendLocationEffect(point, map, 0x375A, 8, 11, 0x49A, 0);
},
new Point3D(pnt));
}
}
foreach(var d in AcquireIndirectTargets(p, 3))
{
Server.Effects.SendTargetParticles(d, 0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255, 0);
double damage = (((Caster.Skills[CastSkill].Value + (Caster.Skills[DamageSkill].Value / 2)) * .66) + Utility.RandomMinMax(1, 6));
SpellHelper.Damage(this, d, damage, 0, 0, 0, 0, 0, 100, 0);
if (d is Mobile)
{
Mobile m = d as Mobile;
double stamSap = (damage / 3);
double manaSap = (damage / 3);
double mod = m.Skills[SkillName.MagicResist].Value - ((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 2);
if (mod > 0)
{
mod /= 100;
stamSap *= mod;
manaSap *= mod;
}
m.Stam -= (int)stamSap;
m.Mana -= (int)manaSap;
Timer.DelayCall(TimeSpan.FromSeconds(10), () =>
{
if (m.Alive)
{
m.Stam += (int)stamSap;
m.Mana += (int)manaSap;
}
});
}
Effects.SendLocationParticles(EffectItem.Create(d.Location, map, EffectItem.DefaultDuration), 0x37CC, 1, 40, 97, 3, 9917, 0);
}
}
}
FinishSequence();
}
public class InternalTarget : Target
{
public NetherCycloneSpell Owner { get; set; }
public InternalTarget(NetherCycloneSpell owner)
: this(owner, false)
{
}
public InternalTarget(NetherCycloneSpell owner, bool allowland)
: base(12, allowland, TargetFlags.None)
{
Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o == null)
return;
if (!from.CanSee(o))
from.SendLocalizedMessage(500237); // Target can not be seen.
else if(o is IPoint3D)
{
SpellHelper.Turn(from, o);
Owner.OnTarget((IPoint3D)o);
}
}
protected override void OnTargetFinish(Mobile from)
{
Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,342 @@
using System;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
using Server.Targeting;
using System.Collections.Generic;
using Server.Spells.First;
using Server.Spells.Second;
using Server.Spells.Third;
using Server.Spells.Fourth;
using Server.Spells.Fifth;
using Server.Spells.Ninjitsu;
namespace Server.Spells.Mysticism
{
public enum BuffType
{
None,
MagicReflect,
ReactiveArmor,
Protection,
Transformation,
StrBonus,
DexBonus,
IntBonus,
BarrabHemolymph,
UraliTrance,
Bless
}
public class PurgeMagicSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Second; } }
private static SpellInfo m_Info = new SpellInfo(
"Purge", "An Ort Sanct ",
230,
9022,
Reagent.Garlic,
Reagent.MandrakeRoot,
Reagent.SulfurousAsh,
Reagent.FertileDirt
);
public PurgeMagicSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void OnTarget(object o)
{
Mobile target = o as Mobile;
if (target == null)
return;
if (m_CurseTable.ContainsKey(Caster))
{
Caster.SendLocalizedMessage(1154212); //You may not use the Purge Magic spell while you are under its curse.
}
else if (m_ImmuneTable.ContainsKey(target) || m_CurseTable.ContainsKey(target))
{
Caster.SendLocalizedMessage(1080119); // Your Purge Magic has been resisted!
}
else if (CheckHSequence(target))
{
if (CheckResisted(target))
{
target.SendLocalizedMessage(501783); // You feel yourself resisting magical energy.
Caster.SendLocalizedMessage(1080119); //Your Purge Magic has been resisted!
}
else
{
SpellHelper.CheckReflect((int)Circle, Caster, ref target);
Caster.PlaySound(0x655);
Effects.SendLocationParticles(EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 1, 13, 0x834, 0, 0x13B2, 0);
BuffType type = GetRandomBuff(target);
if (type != BuffType.None)
{
string arg = "";
switch (type)
{
case BuffType.MagicReflect:
MagicReflectSpell.EndReflect(target);
arg = "magic reflect";
break;
case BuffType.ReactiveArmor:
ReactiveArmorSpell.EndArmor(target);
arg = "reactive armor";
break;
case BuffType.Protection:
ProtectionSpell.EndProtection(target);
arg = "protection";
break;
case BuffType.Transformation:
TransformationSpellHelper.RemoveContext(target, true);
arg = "transformation spell";
break;
case BuffType.StrBonus:
arg = "strength bonus";
target.RemoveStatMod("[Magic] Str Buff");
BuffInfo.RemoveBuff(target, BuffIcon.Strength);
break;
case BuffType.DexBonus:
arg = "dexterity bonus";
target.RemoveStatMod("[Magic] Dex Buff");
BuffInfo.RemoveBuff(target, BuffIcon.Agility);
break;
case BuffType.IntBonus:
arg = "intelligence bonus";
target.RemoveStatMod("[Magic] Int Buff");
BuffInfo.RemoveBuff(target, BuffIcon.Cunning);
break;
case BuffType.BarrabHemolymph:
arg = "Barrab hemolymph";
EodonianPotion.RemoveEffects(target, PotionEffect.Barrab);
break;
case BuffType.UraliTrance:
arg = "Urali Trance";
EodonianPotion.RemoveEffects(target, PotionEffect.Urali);
break;
case BuffType.Bless:
arg = "bless";
target.RemoveStatMod("[Magic] Str Buff");
target.RemoveStatMod("[Magic] Dex Buff");
target.RemoveStatMod("[Magic] Int Buff");
BuffInfo.RemoveBuff(target, BuffIcon.Bless);
BlessSpell.RemoveBless(target);
break;
}
target.SendLocalizedMessage(1080117, arg); //Your ~1_ABILITY_NAME~ has been purged.
Caster.SendLocalizedMessage(1080118, arg); //Your target's ~1_ABILITY_NAME~ has been purged.
int duration = (int)((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 15);
if (duration <= 0)
duration = 1;
m_ImmuneTable.Add(target, new ImmuneTimer(target, TimeSpan.FromSeconds(duration)));
}
else
{
Caster.SendLocalizedMessage(1080120); //Your target has no magic that can be purged.
int duration = (int)((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 28);
if (duration <= 0)
duration = 1;
m_CurseTable.Add(target, new CurseTimer(target, Caster, TimeSpan.FromSeconds(duration)));
}
}
}
FinishSequence();
}
public BuffType GetRandomBuff(Mobile target)
{
List<BuffType> buffs = new List<BuffType>();
if (MagicReflectSpell.HasReflect(target))
buffs.Add(BuffType.MagicReflect);
if (ReactiveArmorSpell.HasArmor(target))
buffs.Add(BuffType.ReactiveArmor);
if (ProtectionSpell.HasProtection(target))
buffs.Add(BuffType.Protection);
TransformContext context = TransformationSpellHelper.GetContext(target);
if (context != null && context.Type != typeof(AnimalForm))
buffs.Add(BuffType.Transformation);
if (BlessSpell.IsBlessed(target))
{
buffs.Add(BuffType.Bless);
}
else
{
StatMod mod = target.GetStatMod("[Magic] Str Buff");
if (mod != null)
buffs.Add(BuffType.StrBonus);
mod = target.GetStatMod("[Magic] Dex Buff");
if (mod != null)
buffs.Add(BuffType.DexBonus);
mod = target.GetStatMod("[Magic] Int Buff");
if (mod != null)
buffs.Add(BuffType.IntBonus);
}
if (EodonianPotion.IsUnderEffects(target, PotionEffect.Barrab))
buffs.Add(BuffType.BarrabHemolymph);
if (EodonianPotion.IsUnderEffects(target, PotionEffect.Urali))
buffs.Add(BuffType.UraliTrance);
if (buffs.Count == 0)
return BuffType.None;
BuffType type = buffs[Utility.Random(buffs.Count)];
buffs.Clear();
return type;
}
private static Dictionary<Mobile, ImmuneTimer> m_ImmuneTable = new Dictionary<Mobile, ImmuneTimer>();
private static Dictionary<Mobile, CurseTimer> m_CurseTable = new Dictionary<Mobile, CurseTimer>();
public static void RemoveImmunity(Mobile from)
{
if (m_ImmuneTable.ContainsKey(from))
{
m_ImmuneTable[from].Stop();
m_ImmuneTable.Remove(from);
}
}
public static void RemoveCurse(Mobile from, Mobile caster)
{
if (m_CurseTable.ContainsKey(from))
{
m_CurseTable[from].Stop();
if (DateTime.UtcNow > m_CurseTable[from].StartTime)
{
TimeSpan inEffect = DateTime.UtcNow - m_CurseTable[from].StartTime;
int damage = 5 * (int)inEffect.TotalSeconds;
from.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head);
from.PlaySound(0x307);
m_CurseTable.Remove(from);
AOS.Damage(from, caster, damage, 0, 0, 0, 0, 0, 100, 0);
}
}
m_ImmuneTable[from] = new ImmuneTimer(from, TimeSpan.FromSeconds(16));
}
public static void OnMobileDoDamage(Mobile from)
{
if (from != null && m_CurseTable.ContainsKey(from))
RemoveCurse(from, m_CurseTable[from].Caster);
}
public static bool IsUnderCurseEffects(Mobile from)
{
return m_CurseTable.ContainsKey(from);
}
private class ImmuneTimer : Timer
{
private Mobile m_Mobile;
public ImmuneTimer(Mobile mob, TimeSpan duration) : base(duration)
{
m_Mobile = mob;
Start();
}
protected override void OnTick()
{
PurgeMagicSpell.RemoveImmunity(m_Mobile);
}
}
private class CurseTimer : Timer
{
private Mobile m_Mobile;
private Mobile m_Caster;
private DateTime m_StartTime;
public DateTime StartTime { get { return m_StartTime; } }
public Mobile Caster { get { return m_Caster; } }
public CurseTimer(Mobile mob, Mobile caster, TimeSpan duration)
: base(duration)
{
m_Mobile = mob;
m_Caster = caster;
m_StartTime = DateTime.UtcNow;
Start();
}
protected override void OnTick()
{
PurgeMagicSpell.RemoveCurse(m_Mobile, m_Caster);
}
}
public class InternalTarget : Target
{
public PurgeMagicSpell Owner { get; set; }
public InternalTarget(PurgeMagicSpell owner)
: this(owner, false)
{
}
public InternalTarget(PurgeMagicSpell owner, bool allowland)
: base(12, allowland, TargetFlags.Harmful)
{
Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o == null)
return;
if (!from.CanSee(o))
from.SendLocalizedMessage(500237); // Target can not be seen.
else
{
SpellHelper.Turn(from, o);
Owner.OnTarget(o);
}
}
protected override void OnTargetFinish(Mobile from)
{
Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,89 @@
using System;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
using Server.Targeting;
namespace Server.Spells.Mysticism
{
public class RisingColossusSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Eighth; } }
private static SpellInfo m_Info = new SpellInfo(
"Rising Colossus", "Kal Vas Xen Corp Ylem",
230,
9022,
Reagent.DaemonBone,
Reagent.DragonBlood,
Reagent.FertileDirt,
Reagent.Nightshade
);
public RisingColossusSpell( 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.Followers + 5) > Caster.FollowersMax)
{
Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature.
return;
}
Map map = Caster.Map;
SpellHelper.GetSurfaceTop(ref p);
if (map == null || (Caster.IsPlayer() && !map.CanSpawnMobile(p.X, p.Y, p.Z)))
{
Caster.SendLocalizedMessage(501942); // That location is blocked.
}
else if (SpellHelper.CheckTown(p, Caster) && CheckSequence())
{
double baseskill = Caster.Skills[SkillName.Mysticism].Value;
double boostskill = GetBoostSkill(Caster);
int level = (int)(baseskill + boostskill);
TimeSpan duration = TimeSpan.FromSeconds(level / 3);
BaseCreature summon = new RisingColossus(Caster, baseskill, boostskill);
BaseCreature.Summon(summon, false, Caster, new Point3D(p), 0x656, duration);
Effects.SendTargetParticles(summon, 0x3728, 10, 10, 0x13AA, (EffectLayer)255);
}
FinishSequence();
}
public class InternalTarget : Target
{
private RisingColossusSpell m_Owner;
public InternalTarget(RisingColossusSpell 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,190 @@
using System;
using Server;
using Server.Targeting;
using System.Collections.Generic;
using Server.Network;
namespace Server.Spells.Mysticism
{
public class SleepSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Third; } }
private static SpellInfo m_Info = new SpellInfo(
"Sleep", "In Zu",
230,
9022,
Reagent.Nightshade,
Reagent.SpidersSilk,
Reagent.BlackPearl
);
public SleepSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void OnTarget(object o)
{
Mobile target = o as Mobile;
if (target == null)
{
return;
}
else if (target.Paralyzed)
{
Caster.SendLocalizedMessage(1080134); //Your target is already immobilized and cannot be slept.
}
else if (m_ImmunityList.Contains(target))
{
Caster.SendLocalizedMessage(1080135); //Your target cannot be put to sleep.
}
else if (CheckHSequence(target))
{
SpellHelper.CheckReflect((int)Circle, Caster, ref target);
double duration = ((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 20) + 2;
duration -= GetResistSkill(target) / 10;
if (duration <= 0 || StoneFormSpell.CheckImmunity(target))
{
Caster.SendLocalizedMessage(1080136); //Your target resists sleep.
target.SendLocalizedMessage(1080137); //You resist sleep.
}
else
DoSleep(Caster, target, TimeSpan.FromSeconds(duration));
}
FinishSequence();
}
private static Dictionary<Mobile, SleepTimer> m_Table = new Dictionary<Mobile, SleepTimer>();
private static List<Mobile> m_ImmunityList = new List<Mobile>();
public static void DoSleep(Mobile caster, Mobile target, TimeSpan duration)
{
target.Combatant = null;
target.SendSpeedControl(SpeedControlType.WalkSpeed);
if (m_Table.ContainsKey(target))
m_Table[target].Stop();
m_Table[target] = new SleepTimer(target, duration);
BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Sleep, 1080139, 1080140, duration, target));
target.Delta(MobileDelta.WeaponDamage);
}
public static void AddToSleepTable(Mobile from, TimeSpan duration)
{
m_Table.Add(from, new SleepTimer(from, duration));
}
public static bool IsUnderSleepEffects(Mobile from)
{
return m_Table.ContainsKey(from);
}
public static void OnDamage(Mobile from)
{
if (m_Table.ContainsKey(from))
EndSleep(from);
}
public class SleepTimer : Timer
{
private Mobile m_Target;
private DateTime m_EndTime;
public SleepTimer(Mobile target, TimeSpan duration)
: base(TimeSpan.Zero, TimeSpan.FromSeconds(0.5))
{
m_EndTime = DateTime.UtcNow + duration;
m_Target = target;
Start();
}
protected override void OnTick()
{
if (m_EndTime < DateTime.UtcNow)
{
EndSleep(m_Target);
Stop();
}
else
{
Effects.SendTargetParticles(m_Target, 0x3779, 1, 32, 0x13BA, EffectLayer.Head);
}
}
}
public static void EndSleep(Mobile target)
{
if (m_Table.ContainsKey(target))
{
target.SendSpeedControl(SpeedControlType.Disable);
m_Table[target].Stop();
m_Table.Remove(target);
BuffInfo.RemoveBuff(target, BuffIcon.Sleep);
double immduration = target.Skills[SkillName.MagicResist].Value / 10;
m_ImmunityList.Add(target);
Timer.DelayCall(TimeSpan.FromSeconds(immduration), new TimerStateCallback(RemoveImmunity_Callback), target);
target.Delta(MobileDelta.WeaponDamage);
}
}
public static void RemoveImmunity_Callback(object state)
{
Mobile m = (Mobile)state;
if (m_ImmunityList.Contains(m))
m_ImmunityList.Remove(m);
}
public class InternalTarget : Target
{
public SleepSpell Owner { get; set; }
public InternalTarget(SleepSpell owner)
: this(owner, false)
{
}
public InternalTarget(SleepSpell owner, bool allowland)
: base(12, allowland, TargetFlags.Harmful)
{
Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o == null)
return;
if (!from.CanSee(o))
from.SendLocalizedMessage(500237); // Target can not be seen.
else
{
SpellHelper.Turn(from, o);
Owner.OnTarget(o);
}
}
protected override void OnTargetFinish(Mobile from)
{
Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,253 @@
using System;
using Server.Mobiles;
using Server.Targeting;
using System.Collections.Generic;
namespace Server.Spells.Mysticism
{
public class SpellPlagueSpell : MysticSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Spell Plague", "Vas Rel Jux Ort",
230,
9022,
Reagent.DaemonBone,
Reagent.DragonBlood,
Reagent.Nightshade,
Reagent.SulfurousAsh
);
public override SpellCircle Circle { get { return SpellCircle.Seventh; } }
public SpellPlagueSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void OnTarget(object o)
{
Mobile m = o as Mobile;
if (m == null)
return;
if (!(m is PlayerMobile || m is BaseCreature))
{
Caster.SendLocalizedMessage(1080194); // Your target cannot be affected by spell plague.
}
else if (CheckResisted(m))
{
m.SendLocalizedMessage(1080199); //You resist spell plague.
Caster.SendLocalizedMessage(1080200); //Your target resists spell plague.
}
else if (CheckHSequence(m))
{
SpellHelper.CheckReflect((int)Circle, Caster, ref m);
SpellHelper.Turn(Caster, m);
Caster.PlaySound(0x658);
m.FixedParticles(0x375A, 1, 17, 9919, 1161, 7, EffectLayer.Waist);
m.FixedParticles(0x3728, 1, 13, 9502, 1161, 7, (EffectLayer)255);
if (!m_Table.ContainsKey(m) || m_Table[m] == null)
m_Table.Add(m, new List<SpellPlagueTimer>());
m_Table[m].Add(new SpellPlagueTimer(Caster, m, TimeSpan.FromSeconds(8)));
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.SpellPlague, 1031690, 1080167, TimeSpan.FromSeconds(8), m));
DoExplosion(m, Caster, true, 1);
}
FinishSequence();
}
private static Dictionary<Mobile, List<SpellPlagueTimer>> m_Table = new Dictionary<Mobile, List<SpellPlagueTimer>>();
public static bool HasSpellPlague(Mobile from)
{
foreach (KeyValuePair<Mobile, List<SpellPlagueTimer>> kvp in m_Table)
{
if (kvp.Value != null)
{
foreach (SpellPlagueTimer timer in kvp.Value)
{
if (timer.Caster == from)
return true;
}
}
}
return false;
}
public static void OnMobileDamaged(Mobile from)
{
if (m_Table.ContainsKey(from) && m_Table[from].Count > 0 && m_Table[from][0].NextUse < DateTime.UtcNow)
{
int amount = m_Table[from][0].Amount;
bool doExplosion = false;
double mod = from.Skills[SkillName.MagicResist].Value >= 70.0 ? (from.Skills[SkillName.MagicResist].Value / 1000 * 3) : 0.0;
if (mod < 0)
mod = .01;
if (amount == 0 && .90 - mod > Utility.RandomDouble())
doExplosion = true;
else if (amount == 1 && .60 - mod > Utility.RandomDouble())
doExplosion = true;
else if (amount == 2 && .30 - mod > Utility.RandomDouble())
doExplosion = true;
if (doExplosion)
{
SpellPlagueTimer timer = m_Table[from][0];
timer.NextUse = DateTime.UtcNow + TimeSpan.FromSeconds(1.5);
DoExplosion(from, timer.Caster, false, amount);
timer.Amount++;
}
}
}
public static void DoExplosion(Mobile from, Mobile caster, bool initial, int amount)
{
double prim = caster.Skills[SkillName.Mysticism].Value;
double sec = caster.Skills[SkillName.Imbuing].Value;
if (caster.Skills[SkillName.Focus].Value > sec)
sec = caster.Skills[SkillName.Focus].Value;
int damage = (int)((prim + sec) / 12) + Utility.RandomMinMax(1, 6);
if (amount > 1)
damage /= amount;
from.PlaySound(0x658);
from.FixedParticles(0x375A, 1, 17, 9919, 1161, 7, EffectLayer.Waist);
from.FixedParticles(0x3728, 1, 13, 9502, 1161, 7, (EffectLayer)255);
int sdiBonus = SpellHelper.GetSpellDamageBonus(caster, from, SkillName.Mysticism, from is PlayerMobile);
damage *= (100 + sdiBonus);
damage /= 100;
SpellHelper.Damage(null, TimeSpan.Zero, from, caster, damage, 0, 0, 0, 0, 0, DFAlgorithm.Standard, 100, 0);
}
public static void RemoveFromList(Mobile from)
{
if (m_Table.ContainsKey(from) && m_Table[from].Count > 0)
{
Mobile caster = m_Table[from][0].Caster;
m_Table[from].Remove(m_Table[from][0]);
if (m_Table[from].Count == 0)
{
m_Table.Remove(from);
BuffInfo.RemoveBuff(from, BuffIcon.SpellPlague);
}
foreach (KeyValuePair<Mobile, List<SpellPlagueTimer>> kvp in m_Table)
{
foreach (SpellPlagueTimer Ttimer in kvp.Value)
{
if (Ttimer.Caster == caster)
return;
}
}
BuffInfo.RemoveBuff(caster, BuffIcon.SpellPlague);
}
}
public class InternalTarget : Target
{
public SpellPlagueSpell Owner { get; set; }
public InternalTarget(SpellPlagueSpell owner)
: this(owner, false)
{
}
public InternalTarget(SpellPlagueSpell owner, bool allowland)
: base(12, allowland, TargetFlags.Harmful)
{
Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o == null)
return;
if (!from.CanSee(o))
from.SendLocalizedMessage(500237); // Target can not be seen.
else
{
SpellHelper.Turn(from, o);
Owner.OnTarget(o);
}
}
protected override void OnTargetFinish(Mobile from)
{
Owner.FinishSequence();
}
}
}
public class SpellPlagueTimer : Timer
{
private Mobile m_Caster;
private Mobile m_Owner;
private int m_Amount;
private DateTime m_NextUse;
public Mobile Caster { get { return m_Caster; } }
public int Amount
{
get { return m_Amount; }
set
{
m_Amount = value;
if (m_Amount >= 3)
EndTimer();
}
}
public DateTime NextUse { get { return m_NextUse; } set { m_NextUse = value; } }
public SpellPlagueTimer(Mobile caster, Mobile owner, TimeSpan duration)
: base(duration)
{
m_Caster = caster;
m_Owner = owner;
m_Amount = 0;
m_NextUse = DateTime.UtcNow;
this.Start();
}
protected override void OnTick()
{
EndTimer();
}
private void EndTimer()
{
this.Stop();
SpellPlagueSpell.RemoveFromList(m_Owner);
}
}
}

View File

@@ -0,0 +1,307 @@
using System;
using Server.Gumps;
using Server.Items;
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Network;
namespace Server.Spells.Mysticism
{
public class SpellTriggerSpell : MysticSpell
{
public override SpellCircle Circle { get { return SpellCircle.Fifth; } }
private static SpellInfo m_Info = new SpellInfo(
"Spell Trigger", "In Vas Ort Ex ",
230,
9022,
Reagent.Garlic,
Reagent.MandrakeRoot,
Reagent.SpidersSilk,
Reagent.DragonBlood
);
public SpellTriggerSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
if (Caster.HasGump(typeof(SpellTriggerGump)))
Caster.CloseGump(typeof(SpellTriggerGump));
var gump = new SpellTriggerGump(this, Caster);
int serial = gump.Serial;
Caster.SendGump(gump);
Timer.DelayCall(TimeSpan.FromSeconds(30), () =>
{
var current = Caster.FindGump(typeof(SpellTriggerGump));
if (current != null && current.Serial == serial)
{
Caster.CloseGump(typeof(EnchantSpellGump));
FinishSequence();
}
});
}
private class SpellTriggerGump : Gump
{
private Spell m_Spell;
private int m_Skill;
public SpellTriggerGump(Spell spell, Mobile m)
: base(60, 36)
{
m_Spell = spell;
AddPage(0);
AddBackground(0, 0, 520, 404, 0x13BE);
AddImageTiled(10, 10, 500, 20, 0xA40);
AddImageTiled(10, 40, 500, 324, 0xA40);
AddImageTiled(10, 374, 500, 20, 0xA40);
AddAlphaRegion(10, 10, 500, 384);
AddButton(10, 374, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0);
AddHtmlLocalized(45, 376, 450, 20, 1060051, 0x7FFF, false, false); // CANCEL
AddHtmlLocalized(14, 12, 500, 20, 1080151, 0x7FFF, false, false); // <center>Spell Trigger Selection Menu</center>
AddPage(1);
m_Skill = (int)(GetBaseSkill(m) + GetBoostSkill(m));
int idx = 0;
for (int i = 0; i < m_Definitions.Length; i++)
{
SpellTriggerDef entry = m_Definitions[i];
if (m_Skill >= (entry.Rank * 40))
{
idx++;
if (idx == 11)
{
AddButton(400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, 2);
AddHtmlLocalized(440, 376, 60, 20, 1043353, 0x7FFF, false, false); // Next
AddPage(2);
AddButton(300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 1);
AddHtmlLocalized(340, 376, 60, 20, 1011393, 0x7FFF, false, false); // Back
idx = 1;
}
if ((idx % 2) != 0)
{
AddImageTiledButton(14, 44 + (64 * (idx - 1) / 2), 0x918, 0x919, 100 + i, GumpButtonType.Reply, 0, entry.ItemId, 0, 15, 20);
AddTooltip(entry.Tooltip);
AddHtmlLocalized(98, 44 + (64 * (idx - 1) / 2), 170, 60, entry.Cliloc, 0x7FFF, false, false);
}
else
{
AddImageTiledButton(264, 44 + (64 * (idx - 2) / 2), 0x918, 0x919, 100 + i, GumpButtonType.Reply, 0, entry.ItemId, 0, 15, 20);
AddTooltip(entry.Tooltip);
AddHtmlLocalized(348, 44 + (64 * (idx - 2) / 2), 170, 60, entry.Cliloc, 0x7FFF, false, false);
}
}
else
{
break;
}
}
}
public override void OnResponse(NetState sender, RelayInfo info)
{
Mobile from = sender.Mobile;
if (from.Backpack != null && info.ButtonID >= 100 && info.ButtonID <= 110 && m_Spell.CheckSequence())
{
Item[] stones = from.Backpack.FindItemsByType(typeof(SpellStone));
for (int i = 0; i < stones.Length; i++)
stones[i].Delete();
SpellTriggerDef entry = m_Definitions[info.ButtonID - 100];
if (m_Skill >= (entry.Rank * 40))
{
from.PlaySound(0x659);
from.PlaceInBackpack(new SpellStone(entry));
from.SendLocalizedMessage(1080165); // A Spell Stone appears in your backpack
}
}
m_Spell.FinishSequence();
}
}
private static SpellTriggerDef[] m_Definitions = new SpellTriggerDef[]
{
new SpellTriggerDef( 677, "Nether Bolt", 1, 1031678, 1095193, 0x2D9E ),
new SpellTriggerDef( 678, "Healing Stone", 1, 1031679, 1095194, 0x2D9F ),
new SpellTriggerDef( 679, "Purge Magic", 2, 1031680, 1095195, 0x2DA0 ),
new SpellTriggerDef( 680, "Enchant", 2, 1031681, 1095196, 0x2DA1 ),
new SpellTriggerDef( 681, "Sleep", 3, 1031682, 1095197, 0x2DA2 ),
new SpellTriggerDef( 682, "Eagle Strike", 3, 1031683, 1095198, 0x2DA3 ),
new SpellTriggerDef( 683, "Animated Weapon", 4, 1031684, 1095199, 0x2DA4 ),
new SpellTriggerDef( 684, "Stone Form", 4, 1031685, 1095200, 0x2DA5 ),
new SpellTriggerDef( 686, "Mass Sleep", 5, 1031687, 1095202, 0x2DA7 ),
new SpellTriggerDef( 687, "Cleansing Winds", 6, 1031688, 1095203, 0x2DA8 ),
new SpellTriggerDef( 688, "Bombard", 6, 1031689, 1095204, 0x2DA9 )
};
public static SpellTriggerDef[] Definitions { get { return m_Definitions; } }
}
public class SpellTriggerDef
{
private int m_SpellId;
private string m_Name;
private int m_Rank;
private int m_Cliloc;
private int m_Tooltip;
private int m_ItemId;
public int SpellId { get { return m_SpellId; } }
public string Name { get { return m_Name; } }
public int Rank { get { return m_Rank; } }
public int Cliloc { get { return m_Cliloc; } }
public int Tooltip { get { return m_Tooltip; } }
public int ItemId { get { return m_ItemId; } }
public SpellTriggerDef(int spellId, string name, int rank, int cliloc, int tooltip, int itemId)
{
m_SpellId = spellId;
m_Name = name;
m_Rank = rank;
m_Cliloc = cliloc;
m_Tooltip = tooltip;
m_ItemId = itemId;
}
}
public class SpellStone : SpellScroll
{
private SpellTriggerDef m_SpellDef;
public override bool Nontransferable { get { return true; } }
[Constructable]
public SpellStone(SpellTriggerDef spellDef)
: base(spellDef.SpellId, 0x4079, 1)
{
this.m_SpellDef = spellDef;
this.LootType = LootType.Blessed;
}
public override bool DropToWorld(Mobile from, Point3D p)
{
this.Delete();
return false;
}
public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted)
{
return false;
}
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
{
}
private static Dictionary<Mobile, DateTime> m_CooldownTable = new Dictionary<Mobile, DateTime>();
public override void OnDoubleClick(Mobile from)
{
if (m_CooldownTable.ContainsKey(from))
{
DateTime next = m_CooldownTable[from];
int seconds = (int)(next - DateTime.UtcNow).TotalSeconds + 1;
// You must wait ~1_seconds~ seconds before you can use this item.
from.SendLocalizedMessage(1079263, seconds.ToString());
return;
}
base.OnDoubleClick(from);
}
public void Use(Mobile from)
{
m_CooldownTable[from] = DateTime.UtcNow + TimeSpan.FromSeconds(300.0);
Timer.DelayCall(TimeSpan.FromSeconds(300.0), new TimerCallback(
delegate
{
m_CooldownTable.Remove(from);
}));
Delete();
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
list.Add(1080166, m_SpellDef.Name); // Use: ~1_spellName~
}
public SpellStone(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)1);
writer.Write((int)m_SpellDef.SpellId);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 1:
{
int spellId = reader.ReadInt();
for (int i = 0; i < SpellTriggerSpell.Definitions.Length; i++)
{
SpellTriggerDef def = SpellTriggerSpell.Definitions[i];
if (def.SpellId == spellId)
{
m_SpellDef = def;
break;
}
}
if (m_SpellDef == null)
Delete();
break;
}
case 0:
{
Delete();
break;
}
}
}
}
}

View File

@@ -0,0 +1,217 @@
using System;
using System.Collections.Generic;
using Server.Network;
namespace Server.Spells.Mysticism
{
public class StoneFormSpell : MysticTransformationSpell
{
private static HashSet<Mobile> m_Effected = new HashSet<Mobile>();
public static bool IsEffected(Mobile m)
{
return m_Effected.Contains(m);
}
private static SpellInfo m_Info = new SpellInfo(
"Stone Form", "In Rel Ylem",
230,
9022,
Reagent.Bloodmoss,
Reagent.FertileDirt,
Reagent.Garlic
);
private int m_ResisMod;
public override SpellCircle Circle { get { return SpellCircle.Fourth; } }
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.0 ); } }
public override int Body{ get{ return 705; } }
public override int PhysResistOffset { get { return m_ResisMod; } }
public override int FireResistOffset { get { return m_ResisMod; } }
public override int ColdResistOffset { get { return m_ResisMod; } }
public override int PoisResistOffset { get { return m_ResisMod; } }
public override int NrgyResistOffset { get { return m_ResisMod; } }
public StoneFormSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override bool CheckCast()
{
bool doCast = base.CheckCast();
if (doCast && Caster.Flying)
{
Caster.SendLocalizedMessage(1112567); // You are flying.
doCast = false;
}
if (doCast)
m_ResisMod = GetResBonus(Caster);
return doCast;
}
public override void DoEffect( Mobile m )
{
m.PlaySound( 0x65A );
m.FixedParticles( 0x3728, 1, 13, 9918, 92, 3, EffectLayer.Head );
Timer.DelayCall(new TimerCallback(MobileDelta_Callback));
m_Effected.Add(m);
if (!Core.HS)
{
m.SendSpeedControl(SpeedControlType.WalkSpeed);
}
string args = String.Format("{0}\t{1}\t{2}\t{3}\t{4}", "-10", "-2", GetResBonus(m).ToString(), GetMaxResistance(m).ToString(), GetDamBonus(m).ToString());
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.StoneForm, 1080145, 1080146, args));
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.PoisonImmunity, 1153785, 1153814));
}
public void MobileDelta_Callback()
{
Caster.Delta(MobileDelta.WeaponDamage);
Caster.UpdateResistances();
}
public override void RemoveEffect( Mobile m )
{
if (!Core.HS)
{
m.SendSpeedControl(SpeedControlType.Disable);
}
m.Delta( MobileDelta.WeaponDamage );
m_Effected.Remove(m);
BuffInfo.RemoveBuff(m, BuffIcon.StoneForm);
BuffInfo.RemoveBuff(m, BuffIcon.PoisonImmunity);
}
public static void Initialize()
{
if (!Core.HS)
{
EventSink.Login += new LoginEventHandler(OnLogin);
}
}
public static void OnLogin(LoginEventArgs e)
{
TransformContext context = TransformationSpellHelper.GetContext(e.Mobile);
if (context != null && context.Type == typeof(StoneFormSpell))
e.Mobile.SendSpeedControl(SpeedControlType.WalkSpeed);
}
public static int GetMaxResistBonus(Mobile m)
{
if (TransformationSpellHelper.UnderTransformation(m, typeof(StoneFormSpell)))
{
return GetMaxResistance(m);
}
return 0;
}
public static int GetResistanceBonus(Mobile m)
{
if (TransformationSpellHelper.UnderTransformation(m, typeof(StoneFormSpell)))
{
return GetResBonus(m);
}
return 0;
}
public static int GetDamageBonus(Mobile m)
{
if (TransformationSpellHelper.UnderTransformation(m, typeof(StoneFormSpell)))
{
return GetDamBonus(m);
}
return 0;
}
public static double StatOffsetReduction(Mobile caster, Mobile m)
{
if (TransformationSpellHelper.UnderTransformation(m, typeof(StoneFormSpell)))
{
int prim = (int)m.Skills[SkillName.Mysticism].Value;
int sec = (int)m.Skills[SkillName.Imbuing].Value;
if (m.Skills[SkillName.Focus].Value > sec)
sec = (int)m.Skills[SkillName.Focus].Value;
caster.SendLocalizedMessage(1080192); // Your target resists your ability reduction magic.
return (double)(prim + sec) / 480;
}
return 1.0;
}
private static int GetResBonus(Mobile m)
{
int prim = (int)m.Skills[SkillName.Mysticism].Value;
int sec = (int)m.Skills[SkillName.Imbuing].Value;
if (m.Skills[SkillName.Focus].Value > sec)
sec = (int)m.Skills[SkillName.Focus].Value;
return Math.Max(2, (prim + sec) / 24);
}
private static int GetMaxResistance(Mobile m)
{
if (Server.Items.BaseArmor.HasRefinedResist(m))
return 0;
int prim = (int)m.Skills[SkillName.Mysticism].Value;
int sec = (int)m.Skills[SkillName.Imbuing].Value;
if (m.Skills[SkillName.Focus].Value > sec)
sec = (int)m.Skills[SkillName.Focus].Value;
return Math.Max(2, (prim + sec) / 48);
}
private static int GetDamBonus(Mobile m)
{
int prim = (int)m.Skills[SkillName.Mysticism].Value;
int sec = (int)m.Skills[SkillName.Imbuing].Value;
if (m.Skills[SkillName.Focus].Value > sec)
sec = (int)m.Skills[SkillName.Focus].Value;
return Math.Max(0, (prim + sec) / 12);
}
public static bool CheckImmunity(Mobile from)
{
if (TransformationSpellHelper.UnderTransformation(from, typeof(StoneFormSpell)))
{
int prim = (int)from.Skills[SkillName.Mysticism].Value;
int sec = (int)from.Skills[SkillName.Imbuing].Value;
if (from.Skills[SkillName.Focus].Value > sec)
sec = (int)from.Skills[SkillName.Focus].Value;
int immunity = (int)(((double)(prim + sec) / 480) * 100);
if (Server.Spells.Necromancy.EvilOmenSpell.TryEndEffect(from))
immunity -= 30;
return immunity > Utility.Random(100);
}
return false;
}
}
}

View File

@@ -0,0 +1,462 @@
using System;
using System.Collections.Generic;
using Server.Engines.Quests;
using Server.Engines.Quests.Necro;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class AnimateDeadSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Animate Dead", "Uus Corp",
203,
9031,
Reagent.GraveDust,
Reagent.DaemonBlood);
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.75);
}
}
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()
{
this.Caster.Target = new InternalTarget(this);
this.Caster.SendLocalizedMessage(1061083); // Animate what corpse?
}
private class CreatureGroup
{
public readonly Type[] m_Types;
public readonly SummonEntry[] m_Entries;
public CreatureGroup(Type[] types, SummonEntry[] entries)
{
this.m_Types = types;
this.m_Entries = entries;
}
}
private class SummonEntry
{
public readonly Type[] m_ToSummon;
public readonly int m_Requirement;
public SummonEntry(int requirement, params Type[] toSummon)
{
this.m_ToSummon = toSummon;
this.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].IsAssignableFrom(type);
if (contains)
return group;
}
return null;
}
private static readonly 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), typeof (ToxicElemental)
}, new SummonEntry[]
{
new SummonEntry(5000, typeof(WailingBanshee)),
new SummonEntry(0, typeof(Wraith))
}),
// Dragons
new CreatureGroup(new Type[]
{
typeof(AncientWyrm), typeof(Dragon), typeof(GreaterDragon), 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 = this.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(this.Caster);
objective.Complete();
}
}
}
return;
}
}
Corpse c = obj as Corpse;
if (c == null)
{
this.Caster.SendLocalizedMessage(1061084); // You cannot animate that.
}
else
{
Type type = null;
if (c.Owner != null)
{
type = c.Owner.GetType();
}
if (c.ItemID != 0x2006 || c.Animated || 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)))
{
this.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))
{
this.Caster.SendLocalizedMessage(1061086); // You cannot animate undead remains.
}
else if (this.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[] { this.Caster, c, p, map, group });
}
}
}
}
}
this.FinishSequence();
}
private static readonly Dictionary<Mobile, List<Mobile>> m_Table = new Dictionary<Mobile, List<Mobile>>();
public static void Unregister(Mobile master, Mobile summoned)
{
if (master == null)
return;
List<Mobile> list = null;
m_Table.TryGetValue(master, out list);
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;
List<Mobile> list = null;
m_Table.TryGetValue(master, out list);
if (list == null)
m_Table[master] = list = new List<Mobile>();
for (int i = list.Count - 1; i >= 0; --i)
{
if (i >= list.Count)
continue;
Mobile mob = list[i];
if (mob.Deleted)
list.RemoveAt(i--);
}
list.Add(summoned);
if (list.Count > 3)
Timer.DelayCall(TimeSpan.Zero, new TimerCallback(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 -= 2;
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.Animated)
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;
#region Mondain's Legacy
BaseCreature creature = caster as BaseCreature;
if (creature != null)
{
if (creature.AIObject is NecroMageAI)
toSummon = typeof(FleshGolem);
}
#endregion
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.Hue = 1109;
corpse.Animated = true;
Register(caster, summoned);
#region Mondain's Legacy
/*if (creature != null)
{
if (creature.AIObject is NecroMageAI)
((NecroMageAI)creature.AIObject).Animated = summoned;
}*/
#endregion
}
public 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
}
public class InternalTarget : Target
{
private readonly AnimateDeadSpell m_Owner;
public InternalTarget(AnimateDeadSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.None)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
this.m_Owner.Target(o);
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,211 @@
using System;
using System.Collections;
using Server.Mobiles;
using Server.Targeting;
using Server.Spells.SkillMasteries;
namespace Server.Spells.Necromancy
{
public class BloodOathSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Blood Oath", "In Jux Mani Xen",
203,
9031,
Reagent.DaemonBlood);
private static readonly Hashtable m_OathTable = new Hashtable();
private static readonly Hashtable m_Table = new Hashtable();
public BloodOathSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.75);
}
}
public override double RequiredSkill
{
get
{
return 20.0;
}
}
public override int RequiredMana
{
get
{
return 13;
}
}
public static bool RemoveCurse(Mobile m)
{
ExpireTimer t = (ExpireTimer)m_Table[m];
if (t == null)
return false;
t.DoExpire();
return true;
}
public static Mobile GetBloodOath(Mobile m)
{
if (m == null)
return null;
Mobile oath = (Mobile)m_OathTable[m];
if (oath == m)
oath = null;
return oath;
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (Caster == m)
{
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);
ApplyEffects(m);
ConduitSpell.CheckAffected(Caster, m, ApplyEffects);
}
FinishSequence();
}
public void ApplyEffects(Mobile m, double strength = 1.0)
{
/* 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
*/
ExpireTimer timer = (ExpireTimer)m_Table[m];
if (timer != null)
timer.DoExpire();
m_OathTable[Caster] = Caster;
m_OathTable[m] = Caster;
if (m.Spell != null)
m.Spell.OnCasterHurt();
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) * strength);
m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); //Skill check for gain
timer = new ExpireTimer(Caster, m, duration);
timer.Start();
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.BloodOathCaster, 1075659, duration, Caster, m.Name.ToString()));
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.BloodOathCurse, 1075661, duration, m, Caster.Name.ToString()));
m_Table[m] = timer;
HarmfulSpell(m);
}
private class ExpireTimer : Timer
{
private readonly Mobile m_Caster;
private readonly Mobile m_Target;
private readonly 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.UtcNow + delay;
Priority = TimerPriority.TwoFiftyMS;
}
public void DoExpire()
{
if (m_OathTable.Contains(m_Caster))
{
m_Caster.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
m_OathTable.Remove(m_Caster);
}
if (m_OathTable.Contains(m_Target))
{
m_Target.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
m_OathTable.Remove(m_Target);
}
Stop();
BuffInfo.RemoveBuff(m_Caster, BuffIcon.BloodOathCaster);
BuffInfo.RemoveBuff(m_Target, BuffIcon.BloodOathCurse);
m_Table.Remove(m_Caster);
}
protected override void OnTick()
{
if (m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive || DateTime.UtcNow >= m_End)
{
DoExpire();
}
}
}
private class InternalTarget : Target
{
private readonly BloodOathSpell m_Owner;
public InternalTarget(BloodOathSpell owner)
: base(Core.ML ? 10 : 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,207 @@
using System;
using System.Collections.Generic;
using Server.Targeting;
using Server.Spells.SkillMasteries;
namespace Server.Spells.Necromancy
{
public class CorpseSkinSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Corpse Skin", "In Agle Corp Ylem",
203,
9051,
Reagent.BatWing,
Reagent.GraveDust);
private static readonly Dictionary<Mobile, ExpireTimer> m_Table = new Dictionary<Mobile, ExpireTimer>();
public CorpseSkinSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.75);
}
}
public override double RequiredSkill
{
get
{
return 20.0;
}
}
public override int RequiredMana
{
get
{
return 11;
}
}
public static bool RemoveCurse(Mobile m)
{
if (m_Table.ContainsKey(m))
{
m_Table[m].DoExpire();
return true;
}
return false;
}
public static bool IsUnderEffects(Mobile m)
{
return m_Table.ContainsKey(m);
}
public static int GetResistMalus(Mobile m)
{
if (m_Table.ContainsKey(m))
{
return 70 - m_Table[m].Malus;
}
return 70;
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
ApplyEffects(m);
ConduitSpell.CheckAffected(Caster, m, ApplyEffects);
}
FinishSequence();
}
public void ApplyEffects(Mobile m, double strength = 1.0)
{
/* 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
*/
if (m_Table.ContainsKey(m))
{
m_Table[m].DoExpire(false);
}
m.SendLocalizedMessage(1061689); // Your skin turns dry and corpselike.
if (m.Spell != null)
m.Spell.OnCasterHurt();
m.FixedParticles(0x373A, 1, 15, 9913, 67, 7, EffectLayer.Head);
m.PlaySound(0x1BB);
double ss = GetDamageSkill(Caster);
double mr = GetResistSkill(m);
m.CheckSkill(SkillName.MagicResist, 0.0, m.Skills[SkillName.MagicResist].Cap); //Skill check for gain
TimeSpan duration = TimeSpan.FromSeconds((((ss - mr) / 2.5) + 40.0) * strength);
int malus = (int)Math.Min(15, (Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) * 0.075);
ResistanceMod[] mods = new ResistanceMod[4]
{
new ResistanceMod( ResistanceType.Fire, (int)(-malus * strength) ),
new ResistanceMod( ResistanceType.Poison, (int)(-malus * strength) ),
new ResistanceMod( ResistanceType.Cold, (int)(+10.0 * strength) ),
new ResistanceMod( ResistanceType.Physical, (int)(+10.0 * strength) )
};
ExpireTimer timer = new ExpireTimer(m, mods, malus, duration);
timer.Start();
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.CorpseSkin, 1075663, duration, m));
m_Table[m] = timer;
m.UpdateResistances();
for (int i = 0; i < mods.Length; ++i)
m.AddResistanceMod(mods[i]);
HarmfulSpell(m);
}
private class ExpireTimer : Timer
{
private readonly Mobile m_Mobile;
private readonly ResistanceMod[] m_Mods;
private readonly int m_Malus;
public int Malus { get { return m_Malus; } }
public ExpireTimer(Mobile m, ResistanceMod[] mods, int malus, TimeSpan delay)
: base(delay)
{
m_Mobile = m;
m_Mods = mods;
m_Malus = malus;
}
public void DoExpire(bool message = true)
{
for (int i = 0; i < m_Mods.Length; ++i)
m_Mobile.RemoveResistanceMod(m_Mods[i]);
Stop();
BuffInfo.RemoveBuff(m_Mobile, BuffIcon.CorpseSkin);
if(m_Table.ContainsKey(m_Mobile))
m_Table.Remove(m_Mobile);
m_Mobile.UpdateResistances();
if(message)
m_Mobile.SendLocalizedMessage(1061688); // Your skin returns to normal.
}
protected override void OnTick()
{
DoExpire();
}
}
private class InternalTarget : Target
{
private readonly CorpseSkinSpell m_Owner;
public InternalTarget(CorpseSkinSpell owner)
: base(Core.ML ? 10 : 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,135 @@
using System;
using System.Collections.Generic;
using Server.Items;
namespace Server.Spells.Necromancy
{
public class CurseWeaponSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Curse Weapon", "An Sanct Gra Char",
203,
9031,
Reagent.PigIron);
private static readonly Dictionary<Mobile, ExpireTimer> m_Table = new Dictionary<Mobile, ExpireTimer>();
public CurseWeaponSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.0);
}
}
public override double RequiredSkill
{
get
{
return 0.0;
}
}
public override int RequiredMana
{
get
{
return 7;
}
}
public override void OnCast()
{
BaseWeapon weapon = Caster.Weapon as BaseWeapon;
if (Caster.Player && (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);
ExpireTimer t = null;
if (m_Table.ContainsKey(Caster))
{
t = m_Table[Caster];
}
if (t != null)
t.Stop();
m_Table[Caster] = t = new ExpireTimer(weapon, Caster, duration);
t.Start();
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.CurseWeapon, 1060512, 1153780, duration, Caster));
}
FinishSequence();
}
public static bool IsCursed(Mobile attacker, BaseWeapon wep)
{
return m_Table.ContainsKey(attacker) && m_Table[attacker].Weapon == wep;
}
public class ExpireTimer : Timer
{
public BaseWeapon Weapon { get; private set; }
public Mobile Owner { get; private set; }
public ExpireTimer(BaseWeapon weapon, Mobile owner, TimeSpan delay)
: base(delay)
{
Weapon = weapon;
Owner = owner;
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
Effects.PlaySound(Weapon.GetWorldLocation(), Weapon.Map, 0xFA);
if (m_Table.ContainsKey(Owner))
{
m_Table.Remove(Owner);
}
}
}
private class SoundEffectTimer : Timer
{
private readonly 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,168 @@
using System;
using System.Collections.Generic;
using Server.Mobiles;
using Server.Targeting;
using Server.Spells.SkillMasteries;
namespace Server.Spells.Necromancy
{
public class EvilOmenSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Evil Omen", "Pas Tym An Sanct",
203,
9031,
Reagent.BatWing,
Reagent.NoxCrystal);
private static readonly Dictionary<Mobile, double> m_Table = new Dictionary<Mobile, double>();
public EvilOmenSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.0);
}
}
public override double RequiredSkill
{
get
{
return 20.0;
}
}
public override int RequiredMana
{
get
{
return 11;
}
}
/*
* The naming here was confusing. Its a 1-off effect spell.
* So, we dont actually "checkeffect"; we endeffect with bool
* return to determine external behaviors.
*
* -refactored.
*/
public static bool UnderEffects(Mobile m)
{
return m_Table.ContainsKey(m);
}
public static double GetResistMalus(Mobile m)
{
if (UnderEffects(m))
{
return m_Table[m];
}
return 0;
}
public static bool TryEndEffect(Mobile m)
{
if (m_Table.ContainsKey(m))
{
m_Table.Remove(m);
BuffInfo.RemoveBuff(m, BuffIcon.EvilOmen);
return true;
}
return false;
}
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 (UnderEffects(m))
{
DoFizzle();
}
else if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
ApplyEffects(m);
ConduitSpell.CheckAffected(Caster, m, ApplyEffects);
}
FinishSequence();
}
public void ApplyEffects(Mobile m, double strength = 1.0)
{
/* 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.
*/
if (m.Spell != null)
m.Spell.OnCasterHurt();
m.PlaySound(0xFC);
m.FixedParticles(0x3728, 1, 13, 9912, 1150, 7, EffectLayer.Head);
m.FixedParticles(0x3779, 1, 15, 9502, 67, 7, EffectLayer.Head);
HarmfulSpell(m);
double resistMalas = 0;
if(m.Skills[SkillName.MagicResist].Base > 50.0)
resistMalas = m.Skills[SkillName.MagicResist].Base / 2.0;
m_Table[m] = resistMalas;
TimeSpan duration = TimeSpan.FromSeconds(((Caster.Skills[SkillName.SpiritSpeak].Value / 12) + 1.0) * strength);
Timer.DelayCall(duration, new TimerStateCallback(EffectExpire_Callback), m);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EvilOmen, 1075647, 1075648, duration, m));
}
private static void EffectExpire_Callback(object state)
{
TryEndEffect((Mobile)state);
}
private class InternalTarget : Target
{
private readonly EvilOmenSpell m_Owner;
public InternalTarget(EvilOmenSpell owner)
: base(Core.ML ? 10 : 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,220 @@
using System;
using System.Collections.Generic;
using Server.Engines.CannedEvil;
using Server.Engines.PartySystem;
using Server.Factions;
using Server.Guilds;
using Server.Items;
using Server.Regions;
namespace Server.Spells.Necromancy
{
public class ExorcismSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Exorcism", "Ort Corp Grav",
203,
9031,
Reagent.NoxCrystal,
Reagent.GraveDust);
private static readonly int Range = (Core.ML ? 48 : 18);
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)
};
public ExorcismSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(2.0);
}
}
public override double RequiredSkill
{
get
{
return 80.0;
}
}
public override int RequiredMana
{
get
{
return 40;
}
}
public override bool DelayedDamage
{
get
{
return false;
}
}
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 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())
{
Map map = Caster.Map;
if (map != null)
{
List<Mobile> targets = new List<Mobile>();
IPooledEnumerable eable = r.ChampionSpawn.GetMobilesInRange(Range);
foreach (Mobile m in eable)
if (IsValidTarget(m))
targets.Add(m);
eable.Free();
for (int i = 0; i < targets.Count; ++i)
{
Mobile m = targets[i];
//Suprisingly, no sparkle type effects
Point3D p = GetNearestShrine(m, ref map);
m.MoveToWorld(p, map);
}
}
}
FinishSequence();
}
public static Point3D GetNearestShrine(Mobile m, ref Map 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
{
// No map, lets use trammel
locList = m_BritanniaLocs;
map = Map.Trammel;
}
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 bool IsValidTarget(Mobile m)
{
if (!m.Player || m.Alive)
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<DungeonRegion>() == Region.Find(c.Location, map).IsPartOf<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;
}
}
}

View File

@@ -0,0 +1,64 @@
using System;
namespace Server.Spells.Necromancy
{
public class HorrificBeastSpell : TransformationSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Horrific Beast", "Rel Xen Vas Bal",
203,
9031,
Reagent.BatWing,
Reagent.DaemonBlood);
public HorrificBeastSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(2.25);
}
}
public override double RequiredSkill
{
get
{
return 40.0;
}
}
public override int RequiredMana
{
get
{
return 11;
}
}
public override int Body
{
get
{
return 746;
}
}
public override void DoEffect(Mobile m)
{
m.PlaySound(0x165);
m.FixedParticles(0x3728, 1, 13, 9918, 92, 3, EffectLayer.Head);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.HorrificBeast, 1060514, 1153763, "20\t25"));
m.Delta(MobileDelta.WeaponDamage);
m.ResetStatTimers();
}
public override void RemoveEffect(Mobile m)
{
m.Delta(MobileDelta.WeaponDamage);
BuffInfo.RemoveBuff(m, BuffIcon.HorrificBeast);
}
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
namespace Server.Spells.Necromancy
{
public class LichFormSpell : TransformationSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Lich Form", "Rel Xen Corp Ort",
203,
9031,
Reagent.GraveDust,
Reagent.DaemonBlood,
Reagent.NoxCrystal);
public LichFormSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(2.25);
}
}
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;
}
}
public override void DoEffect(Mobile m)
{
m.PlaySound(0x19C);
m.FixedParticles(0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.LichForm, 1060515, 1153767, "5\t13\t10\t10\t10"));
m.ResetStatTimers();
}
public override void OnTick(Mobile m)
{
--m.Hits;
}
public override void RemoveEffect(Mobile m)
{
BuffInfo.RemoveBuff(m, BuffIcon.LichForm);
}
}
}

View File

@@ -0,0 +1,200 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Spells.SkillMasteries;
namespace Server.Spells.Necromancy
{
public class MindRotSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Mind Rot", "Wis An Ben",
203,
9031,
Reagent.BatWing,
Reagent.PigIron,
Reagent.DaemonBlood);
private static readonly Hashtable m_Table = new Hashtable();
public MindRotSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.75);
}
}
public override double RequiredSkill
{
get
{
return 30.0;
}
}
public override int RequiredMana
{
get
{
return 17;
}
}
public static void ClearMindRotScalar(Mobile m)
{
if (!m_Table.ContainsKey(m))
return;
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot);
MRBucket tmpB = (MRBucket)m_Table[m];
MRExpireTimer tmpT = (MRExpireTimer)tmpB.m_MRExpireTimer;
tmpT.Stop();
m_Table.Remove(m);
m.SendLocalizedMessage(1060872); // Your mind feels normal again.
}
public static bool HasMindRotScalar(Mobile m)
{
return m_Table.ContainsKey(m);
}
public static bool GetMindRotScalar(Mobile m, ref double scalar)
{
if (!m_Table.ContainsKey(m))
return false;
MRBucket tmpB = (MRBucket)m_Table[m];
scalar = tmpB.m_Scalar;
return true;
}
public static void SetMindRotScalar(Mobile caster, Mobile target, double scalar, TimeSpan duration)
{
if (!m_Table.ContainsKey(target))
{
m_Table.Add(target, new MRBucket(scalar, new MRExpireTimer(caster, target, duration)));
BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Mindrot, 1075665, duration, target));
MRBucket tmpB = (MRBucket)m_Table[target];
MRExpireTimer tmpT = (MRExpireTimer)tmpB.m_MRExpireTimer;
tmpT.Start();
target.SendLocalizedMessage(1074384);
}
}
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);
ApplyEffects(m);
ConduitSpell.CheckAffected(Caster, m, ApplyEffects);
}
FinishSequence();
}
public void ApplyEffects(Mobile m, double strength = 1.0)
{
/* 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.
*/
if (m.Spell != null)
m.Spell.OnCasterHurt();
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)) * strength);
m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); //Skill check for gain
if (m.Player)
SetMindRotScalar(Caster, m, 1.25 * strength, duration);
else
SetMindRotScalar(Caster, m, 2.00 * strength, duration);
HarmfulSpell(m);
}
private class InternalTarget : Target
{
private readonly MindRotSpell m_Owner;
public InternalTarget(MindRotSpell owner)
: base(Core.ML ? 10 : 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();
}
}
}
public class MRExpireTimer : Timer
{
private readonly Mobile m_Caster;
private readonly Mobile m_Target;
private DateTime m_End;
public MRExpireTimer(Mobile caster, Mobile target, TimeSpan delay)
: base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
{
m_Caster = caster;
m_Target = target;
m_End = DateTime.UtcNow + delay;
Priority = TimerPriority.TwoFiftyMS;
}
public void RenewDelay(TimeSpan delay)
{
m_End = DateTime.UtcNow + delay;
}
public void Halt()
{
Stop();
}
protected override void OnTick()
{
if (m_Target.Deleted || !m_Target.Alive || DateTime.UtcNow >= m_End)
{
MindRotSpell.ClearMindRotScalar(m_Target);
Stop();
}
}
}
public class MRBucket
{
public double m_Scalar;
public MRExpireTimer m_MRExpireTimer;
public MRBucket(double theScalar, MRExpireTimer theTimer)
{
m_Scalar = theScalar;
m_MRExpireTimer = theTimer;
}
}
}

View File

@@ -0,0 +1,78 @@
using System;
using Server.Items;
namespace Server.Spells.Necromancy
{
public abstract class NecromancerSpell : Spell
{
public NecromancerSpell(Mobile caster, Item scroll, SpellInfo info)
: base(caster, scroll, info)
{
}
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 int CastDelayBase{ get{ return base.CastDelayBase; } } // Reference, 3
public override bool ClearHandsOnCast
{
get
{
return false;
}
}
public override double CastDelayFastScalar
{
get
{
return (Core.SE ? base.CastDelayFastScalar : 0);
}
}// Necromancer spells are not affected by fast cast items, though they are by fast cast recovery
public override int ComputeKarmaAward()
{
//TODO: Verify this formula being that Necro spells don't HAVE a circle.
//int karma = -(70 + (10 * (int)Circle));
int karma = -(40 + (int)(10 * (this.CastDelayBase.TotalSeconds / this.CastDelaySecondsPerTick)));
if (Core.ML) // Pub 36: "Added a new property called Increased Karma Loss which grants higher karma loss for casting necromancy spells."
karma += AOS.Scale(karma, AosAttributes.GetValue(this.Caster, AosAttribute.IncreasedKarmaLoss));
return karma;
}
public override void GetCastSkills(out double min, out double max)
{
min = this.RequiredSkill;
max = this.Scroll != null ? min : this.RequiredSkill + 40.0;
}
public override bool ConsumeReagents()
{
if (base.ConsumeReagents())
return true;
if (ArcaneGem.ConsumeCharges(this.Caster, 1))
return true;
return false;
}
public override int GetMana()
{
return this.RequiredMana;
}
}
}

View File

@@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using Server;
using Server.Targeting;
using Server.Spells.SkillMasteries;
namespace Server.Spells.Necromancy
{
public class PainSpikeSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Pain Spike", "In Sar",
203,
9031,
Reagent.GraveDust,
Reagent.PigIron);
private static readonly Dictionary<Mobile, InternalTimer> m_Table = new Dictionary<Mobile, InternalTimer>();
public PainSpikeSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.25);
}
}
public override double RequiredSkill
{
get
{
return 20.0;
}
}
public override int RequiredMana
{
get
{
return 5;
}
}
public override bool DelayedDamage
{
get
{
return false;
}
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
ApplyEffects(m);
ConduitSpell.CheckAffected(Caster, m, ApplyEffects);
}
FinishSequence();
}
public void ApplyEffects(Mobile m, double strength = 1.0)
{
//SpellHelper.CheckReflect( (int)Circle, Caster, ref m ); //Irrelevent asfter AoS
/* 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)) * strength;
m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); //Skill check for gain
if (damage < 1)
damage = 1;
TimeSpan buffTime = TimeSpan.FromSeconds(10.0 * strength);
InternalTimer t;
if (m_Table.ContainsKey(m))
{
damage = Utility.RandomMinMax(3, 7);
t = m_Table[m];
if (t != null)
{
t.Expires += TimeSpan.FromSeconds(2);
}
}
else
{
t = new InternalTimer(m, damage);
t.Start();
}
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.PainSpike, 1075667, t.Expires - DateTime.UtcNow, m, Convert.ToString((int)damage)));
m.DFA = DFAlgorithm.PainSpike;
AOS.Damage(m, Caster, (int)damage, 0, 0, 0, 0, 0, 0, 100);
AOS.DoLeech((int)damage, Caster, m);
m.DFA = DFAlgorithm.Standard;
HarmfulSpell(m);
}
private class InternalTimer : Timer
{
private readonly Mobile m_Mobile;
private readonly int m_ToRestore;
public DateTime Expires { get; set; }
public InternalTimer(Mobile m, double toRestore)
: base(TimeSpan.FromMilliseconds(250), TimeSpan.FromMilliseconds(250))
{
Priority = TimerPriority.FiftyMS;
m_Mobile = m;
m_ToRestore = (int)toRestore;
Expires = DateTime.UtcNow + TimeSpan.FromSeconds(10);
m_Table[m] = this;
}
protected override void OnTick()
{
if (DateTime.UtcNow >= Expires)
{
if (m_Table.ContainsKey(m_Mobile))
m_Table.Remove(m_Mobile);
if (m_Mobile.Alive && !m_Mobile.IsDeadBondedPet)
m_Mobile.Hits += m_ToRestore;
BuffInfo.RemoveBuff(m_Mobile, BuffIcon.PainSpike);
Stop();
}
}
}
private class InternalTarget : Target
{
private readonly PainSpikeSpell m_Owner;
public InternalTarget(PainSpikeSpell owner)
: base(Core.ML ? 10 : 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,152 @@
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
using Server.Spells.SkillMasteries;
namespace Server.Spells.Necromancy
{
public class PoisonStrikeSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Poison Strike", "In Vas Nox",
203,
9031,
Reagent.NoxCrystal);
public PoisonStrikeSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override DamageType SpellDamageType { get { return DamageType.SpellAOE; } }
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds((Core.ML ? 2.0 : 1.5));
}
}
public override double RequiredSkill
{
get
{
return 50.0;
}
}
public override int RequiredMana
{
get
{
return 17;
}
}
public override bool DelayedDamage
{
get
{
return false;
}
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void Target(IDamageable m)
{
if (CheckHSequence(m))
{
Mobile mob = m as Mobile;
SpellHelper.Turn(Caster, m);
ApplyEffects(m);
ConduitSpell.CheckAffected(Caster, m, ApplyEffects);
}
FinishSequence();
}
public void ApplyEffects(IDamageable m, double strength = 1.0)
{
/* 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.
*/
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((Core.ML ? 32 : 36), 40) * ((300 + (GetDamageSkill(Caster) * 9)) / 1000);
damage *= strength;
double sdiBonus;
if (Core.SE)
{
if (Core.SA)
{
sdiBonus = (double)SpellHelper.GetSpellDamageBonus(Caster, m, CastSkill, m is PlayerMobile) / 100;
}
else
{
sdiBonus = (double)AosAttributes.GetValue(Caster, AosAttribute.SpellDamage) / 100;
// PvP spell damage increase cap of 15% from an items magic property in Publish 33(SE)
if (m is PlayerMobile && Caster.Player && sdiBonus > 15)
sdiBonus = 15;
}
}
else
{
sdiBonus = (double)AosAttributes.GetValue(Caster, AosAttribute.SpellDamage) / 100;
}
double pvmDamage = (damage * (1 + sdiBonus)) * strength;
double pvpDamage = damage * (1 + sdiBonus);
Map map = m.Map;
if (map != null)
{
foreach (var id in AcquireIndirectTargets(m.Location, 2))
{
int num;
if (Utility.InRange(id.Location, m.Location, 0))
num = 1;
else if (Utility.InRange(id.Location, m.Location, 1))
num = 2;
else
num = 3;
Caster.DoHarmful(id);
SpellHelper.Damage(this, id, ((id is PlayerMobile && Caster.Player) ? pvpDamage : pvmDamage) / num, 0, 0, 0, 100, 0);
}
}
}
private class InternalTarget : Target
{
private readonly PoisonStrikeSpell m_Owner;
public InternalTarget(PoisonStrikeSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is IDamageable)
m_Owner.Target((IDamageable)o);
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,274 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Spells.SkillMasteries;
namespace Server.Spells.Necromancy
{
public class StrangleSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Strangle", "In Bal Nox",
209,
9031,
Reagent.DaemonBlood,
Reagent.NoxCrystal);
private static readonly Hashtable m_Table = new Hashtable();
public StrangleSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(2.25);
}
}
public override double RequiredSkill
{
get
{
return 65.0;
}
}
public override int RequiredMana
{
get
{
return 29;
}
}
public static bool UnderEffects(Mobile m)
{
return m_Table.ContainsKey(m);
}
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.
BuffInfo.RemoveBuff(m, BuffIcon.Strangle);
m_Table.Remove(m);
return true;
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public void Target(Mobile m)
{
if (this.CheckHSequence(m))
{
SpellHelper.Turn(this.Caster, m);
ApplyEffects(m);
ConduitSpell.CheckAffected(Caster, m, ApplyEffects);
}
FinishSequence();
}
public void ApplyEffects(Mobile m, double strength = 1.0)
{
//SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); //Irrelevent after AoS
/* 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
*/
if (m.Spell != null)
m.Spell.OnCasterHurt();
m.PlaySound(0x22F);
m.FixedParticles(0x36CB, 1, 9, 9911, 67, 5, EffectLayer.Head);
m.FixedParticles(0x374A, 1, 17, 9502, 1108, 4, (EffectLayer)255);
if (Server.Spells.Mysticism.StoneFormSpell.CheckImmunity(m))
{
Caster.SendLocalizedMessage(1095250); // Your target resists strangle.
}
else if (!m_Table.ContainsKey(m))
{
Timer t = new InternalTimer(m, Caster, strength);
t.Start();
m_Table[m] = t;
//Calculations for the buff bar
double spiritlevel = Caster.Skills[SkillName.SpiritSpeak].Value / 10;
if (spiritlevel < 4)
spiritlevel = 4;
int d_MinDamage = (int)(4.0 * strength);
int d_MaxDamage = (int)(((spiritlevel + 1) * 3) * strength);
string args = String.Format("{0}\t{1}", d_MinDamage, d_MaxDamage);
int i_Count = (int)spiritlevel;
int i_MaxCount = i_Count;
int i_HitDelay = 5;
int i_Length = i_HitDelay;
while (i_Count > 1)
{
--i_Count;
if (i_HitDelay > 1)
{
if (i_MaxCount < 5)
{
--i_HitDelay;
}
else
{
int delay = (int)(Math.Ceiling((1.0 + (5 * i_Count)) / i_MaxCount));
if (delay <= 5)
i_HitDelay = delay;
else
i_HitDelay = 5;
}
}
i_Length += i_HitDelay;
}
TimeSpan t_Duration = TimeSpan.FromSeconds(i_Length * strength);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strangle, 1075794, 1075795, t_Duration, m, args.ToString()));
}
HarmfulSpell(m);
}
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, double strength)
: 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) * strength;
m_MaxBaseDamage = (spiritLevel + 1) * strength;
m_HitDelay = 5;
m_NextHit = DateTime.UtcNow + 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.UtcNow < 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.UtcNow + 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);
if (0.60 <= Utility.RandomDouble()) // OSI: randomly revealed between first and third damage tick, guessing 60% chance
m_Target.RevealingAction();
}
}
}
private class InternalTarget : Target
{
private readonly StrangleSpell m_Owner;
public InternalTarget(StrangleSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
this.m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,258 @@
using System;
using System.Collections;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
namespace Server.Spells.Necromancy
{
public class SummonFamiliarSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Summon Familiar", "Kal Xen Bal",
203,
9031,
Reagent.BatWing,
Reagent.GraveDust,
Reagent.DaemonBlood);
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(2.25);
}
}
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 readonly Hashtable m_Table = new Hashtable();
public static Hashtable Table
{
get
{
return m_Table;
}
}
public override bool CheckCast()
{
BaseCreature check = (BaseCreature)m_Table[this.Caster];
if (check != null && !check.Deleted)
{
this.Caster.SendLocalizedMessage(1061605); // You already have a familiar.
return false;
}
return base.CheckCast();
}
public override void OnCast()
{
if (this.CheckSequence())
{
this.Caster.CloseGump(typeof(SummonFamiliarGump));
this.Caster.SendGump(new SummonFamiliarGump(this.Caster, m_Entries, this));
}
this.FinishSequence();
}
private static readonly 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 readonly Type m_Type;
private readonly object m_Name;
private readonly double m_ReqNecromancy;
private readonly double m_ReqSpiritSpeak;
public Type Type
{
get
{
return this.m_Type;
}
}
public object Name
{
get
{
return this.m_Name;
}
}
public double ReqNecromancy
{
get
{
return this.m_ReqNecromancy;
}
}
public double ReqSpiritSpeak
{
get
{
return this.m_ReqSpiritSpeak;
}
}
public SummonFamiliarEntry(Type type, object name, double reqNecromancy, double reqSpiritSpeak)
{
this.m_Type = type;
this.m_Name = name;
this.m_ReqNecromancy = reqNecromancy;
this.m_ReqSpiritSpeak = reqSpiritSpeak;
}
}
public class SummonFamiliarGump : Gump
{
private readonly Mobile m_From;
private readonly SummonFamiliarEntry[] m_Entries;
private readonly 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)
{
this.m_From = from;
this.m_Entries = entries;
this.m_Spell = spell;
this.AddPage(0);
this.AddBackground(10, 10, 250, 178, 9270);
this.AddAlphaRegion(20, 20, 230, 158);
this.AddImage(220, 20, 10464);
this.AddImage(220, 72, 10464);
this.AddImage(220, 124, 10464);
this.AddItem(188, 16, 6883);
this.AddItem(198, 168, 6881);
this.AddItem(8, 15, 6882);
this.AddItem(2, 168, 6880);
this.AddHtmlLocalized(30, 26, 200, 20, 1060147, EnabledColor16, false, false); // Chose thy familiar...
double necro = from.Skills[SkillName.Necromancy].Value;
double spirit = from.Skills[SkillName.SpiritSpeak].Value;
for (int i = 0; i < entries.Length; ++i)
{
object name = entries[i].Name;
bool enabled = (necro >= entries[i].ReqNecromancy && spirit >= entries[i].ReqSpiritSpeak);
this.AddButton(27, 53 + (i * 21), 9702, 9703, i + 1, GumpButtonType.Reply, 0);
if (name is int)
this.AddHtmlLocalized(50, 51 + (i * 21), 150, 20, (int)name, enabled ? EnabledColor16 : DisabledColor16, false, false);
else if (name is string)
this.AddHtml(50, 51 + (i * 21), 150, 20, String.Format("<BASEFONT COLOR=#{0:X6}>{1}</BASEFONT>", enabled ? EnabledColor32 : DisabledColor32, name), false, false);
}
}
private static readonly Hashtable m_Table = new Hashtable();
public override void OnResponse(NetState sender, RelayInfo info)
{
int index = info.ButtonID - 1;
if (index >= 0 && index < this.m_Entries.Length)
{
SummonFamiliarEntry entry = this.m_Entries[index];
double necro = this.m_From.Skills[SkillName.Necromancy].Value;
double spirit = this.m_From.Skills[SkillName.SpiritSpeak].Value;
BaseCreature check = (BaseCreature)SummonFamiliarSpell.Table[this.m_From];
if (check != null && !check.Deleted)
{
this.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.
this.m_From.SendLocalizedMessage(1061606, String.Format("{0:F1}\t{1:F1}", entry.ReqNecromancy, entry.ReqSpiritSpeak));
this.m_From.CloseGump(typeof(SummonFamiliarGump));
this.m_From.SendGump(new SummonFamiliarGump(this.m_From, SummonFamiliarSpell.Entries, this.m_Spell));
}
else if (entry.Type == null)
{
this.m_From.SendMessage("That familiar has not yet been defined.");
this.m_From.CloseGump(typeof(SummonFamiliarGump));
this.m_From.SendGump(new SummonFamiliarGump(this.m_From, SummonFamiliarSpell.Entries, this.m_Spell));
}
else
{
try
{
BaseCreature bc = (BaseCreature)Activator.CreateInstance(entry.Type);
bc.Skills.MagicResist = this.m_From.Skills.MagicResist;
if (BaseCreature.Summon(bc, this.m_From, this.m_From.Location, -1, TimeSpan.FromDays(1.0)))
{
this.m_From.FixedParticles(0x3728, 1, 10, 9910, EffectLayer.Head);
bc.PlaySound(bc.GetIdleSound());
SummonFamiliarSpell.Table[this.m_From] = bc;
}
}
catch
{
}
}
}
else
{
this.m_From.SendLocalizedMessage(1061825); // You decide not to summon a familiar.
}
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
namespace Server.Spells.Necromancy
{
public abstract class TransformationSpell : NecromancerSpell, ITransformationSpell
{
public TransformationSpell(Mobile caster, Item scroll, SpellInfo info)
: base(caster, scroll, info)
{
}
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 override bool BlockedByHorrificBeast
{
get
{
return false;
}
}
public virtual double TickRate
{
get
{
return 1.0;
}
}
public override bool CheckCast()
{
if (!TransformationSpellHelper.CheckCast(this.Caster, this))
return false;
return base.CheckCast();
}
public override void OnCast()
{
TransformationSpellHelper.OnCast(this.Caster, this);
this.FinishSequence();
}
public virtual void OnTick(Mobile m)
{
}
public virtual void DoEffect(Mobile m)
{
}
public virtual void RemoveEffect(Mobile m)
{
}
}
}

View File

@@ -0,0 +1,100 @@
using System;
using Server.Items;
namespace Server.Spells.Necromancy
{
public class VampiricEmbraceSpell : TransformationSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Vampiric Embrace", "Rel Xen An Sanct",
203,
9031,
Reagent.BatWing,
Reagent.NoxCrystal,
Reagent.PigIron);
public VampiricEmbraceSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(2.25);
}
}
public override double RequiredSkill
{
get
{
return 99.0;
}
}
public override int RequiredMana
{
get
{
return 23;
}
}
public override int Body
{
get
{
if (Caster.Race == Race.Gargoyle)
{
return Caster.Female ? 667 : 666;
}
return Caster.Female ? Caster.Race.FemaleBody : Caster.Race.MaleBody;
}
}
public override int Hue
{
get
{
return 0x847E;
}
}
public override int FireResistOffset
{
get
{
return -25;
}
}
public override void GetCastSkills(out double min, out double max)
{
if (this.Caster.Skills[this.CastSkill].Value >= this.RequiredSkill)
{
min = 80.0;
max = 120.0;
}
else
{
base.GetCastSkills(out min, out max);
}
}
public override void DoEffect(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);
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.VampiricEmbrace, 1028812, 1153768, String.Format("{0}\t{1}\t{2}\t{3}", "20", "15", "3", "25")));
if (Caster.Skills.Necromancy.Value > 99.0)
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.PoisonImmunity, 1153785, 1153814));
m.ResetStatTimers();
}
public override void RemoveEffect(Mobile m)
{
BuffInfo.RemoveBuff(Caster, BuffIcon.PoisonImmunity);
BuffInfo.RemoveBuff(Caster, BuffIcon.VampiricEmbrace);
}
}
}

View File

@@ -0,0 +1,109 @@
using System;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class VengefulSpiritSpell : NecromancerSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Vengeful Spirit", "Kal Xen Bal Beh",
203,
9031,
Reagent.BatWing,
Reagent.GraveDust,
Reagent.PigIron);
public VengefulSpiritSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(2.25);
}
}
public override double RequiredSkill
{
get
{
return 80.0;
}
}
public override int RequiredMana
{
get
{
return 41;
}
}
public override void OnCast()
{
this.Caster.Target = new InternalTarget(this);
}
public override bool CheckCast()
{
if (!base.CheckCast())
return false;
if ((this.Caster.Followers + 3) > this.Caster.FollowersMax)
{
this.Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature.
return false;
}
return true;
}
public void Target(Mobile m)
{
if (this.Caster == m)
{
this.Caster.SendLocalizedMessage(1061832); // You cannot exact vengeance on yourself.
}
else if (this.CheckHSequence(m))
{
SpellHelper.Turn(this.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(((this.GetDamageSkill(this.Caster) * 80) / 120) + 10);
Revenant rev = new Revenant(this.Caster, m, duration);
if (BaseCreature.Summon(rev, false, this.Caster, m.Location, 0x81, TimeSpan.FromSeconds(duration.TotalSeconds + 2.0)))
rev.FixedParticles(0x373A, 1, 15, 9909, EffectLayer.Waist);
}
this.FinishSequence();
}
private class InternalTarget : Target
{
private readonly VengefulSpiritSpell m_Owner;
public InternalTarget(VengefulSpiritSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
this.m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
this.m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish(Mobile from)
{
this.m_Owner.FinishSequence();
}
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Items;
using Server.Mobiles;
namespace Server.Spells.Necromancy
{
public class WitherSpell : NecromancerSpell
{
public override DamageType SpellDamageType { get { return DamageType.SpellAOE; } }
private static readonly SpellInfo m_Info = new SpellInfo(
"Wither", "Kal Vas An Flam",
203,
9031,
Reagent.NoxCrystal,
Reagent.GraveDust,
Reagent.PigIron);
public WitherSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(1.5);
}
}
public override double RequiredSkill
{
get
{
return 60.0;
}
}
public override int RequiredMana
{
get
{
return 23;
}
}
public override bool DelayedDamage
{
get
{
return false;
}
}
public override void OnCast()
{
if (this.CheckSequence())
{
/* Creates a withering frost around the Caster,
* which deals Cold Damage to all valid targets in a radius of 5 tiles.
*/
Map map = this.Caster.Map;
if (map != null)
{
Effects.PlaySound(this.Caster.Location, map, 0x1FB);
Effects.PlaySound(this.Caster.Location, map, 0x10B);
Effects.SendLocationParticles(EffectItem.Create(this.Caster.Location, map, EffectItem.DefaultDuration), 0x37CC, 1, 40, 97, 3, 9917, 0);
foreach (var id in AcquireIndirectTargets(Caster.Location, Core.ML ? 4 : 5))
{
Mobile m = id as Mobile;
this.Caster.DoHarmful(id);
if (m != null)
{
m.FixedParticles(0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255);
}
else
{
Effects.SendLocationParticles(id, 0x374A, 1, 30, 97, 3, 9502, 0);
}
double damage = Utility.RandomMinMax(30, 35);
int karma = m != null ? m.Karma / 100 : 0;
damage *= 300 + karma + (this.GetDamageSkill(this.Caster) * 10);
damage /= 1000;
int sdiBonus;
if (Core.SE)
{
if (Core.SA)
{
sdiBonus = SpellHelper.GetSpellDamageBonus(Caster, m, CastSkill, m is PlayerMobile);
}
else
{
sdiBonus = AosAttributes.GetValue(this.Caster, AosAttribute.SpellDamage);
// PvP spell damage increase cap of 15% from an items magic property in Publish 33(SE)
if (id is PlayerMobile && this.Caster.Player && sdiBonus > 15)
sdiBonus = 15;
}
}
else
{
sdiBonus = AosAttributes.GetValue(this.Caster, AosAttribute.SpellDamage);
}
damage *= (100 + sdiBonus);
damage /= 100;
SpellHelper.Damage(this, id, damage, 0, 0, 100, 0, 0);
}
}
}
this.FinishSequence();
}
}
}

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using Server.Mobiles;
namespace Server.Spells.Necromancy
{
public class WraithFormSpell : TransformationSpell
{
private static readonly SpellInfo m_Info = new SpellInfo(
"Wraith Form", "Rel Xen Um",
203,
9031,
Reagent.NoxCrystal,
Reagent.PigIron);
public WraithFormSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase
{
get
{
return TimeSpan.FromSeconds(2.25);
}
}
public override double RequiredSkill
{
get
{
return 20.0;
}
}
public override int RequiredMana
{
get
{
return 17;
}
}
public override int Body
{
get
{
return this.Caster.Female ? 747 : 748;
}
}
public override int Hue
{
get
{
return this.Caster.Female ? 0 : 0x4001;
}
}
public override int PhysResistOffset
{
get
{
return +15;
}
}
public override int FireResistOffset
{
get
{
return -5;
}
}
public override int ColdResistOffset
{
get
{
return 0;
}
}
public override int PoisResistOffset
{
get
{
return 0;
}
}
public override int NrgyResistOffset
{
get
{
return -5;
}
}
public override void DoEffect(Mobile m)
{
if (m is PlayerMobile)
((PlayerMobile)m).IgnoreMobiles = true;
m.PlaySound(0x17F);
m.FixedParticles(0x374A, 1, 15, 9902, 1108, 4, EffectLayer.Waist);
int manadrain = (int)(m.Skills.SpiritSpeak.Value / 5);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.WraithForm, 1060524, 1153829, String.Format("15\t5\t5\t{0}", manadrain)));
}
public override void RemoveEffect(Mobile m)
{
if (m is PlayerMobile && m.IsPlayer())
((PlayerMobile)m).IgnoreMobiles = false;
BuffInfo.RemoveBuff(m, BuffIcon.WraithForm);
}
}
}

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