Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
14
Scripts/Spells/Base/DisturbType.cs
Normal file
14
Scripts/Spells/Base/DisturbType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Spells
|
||||
{
|
||||
public enum DisturbType
|
||||
{
|
||||
Unspecified,
|
||||
EquipRequest,
|
||||
UseRequest,
|
||||
Hurt,
|
||||
Kill,
|
||||
NewCast
|
||||
}
|
||||
}
|
||||
101
Scripts/Spells/Base/MagerySpell.cs
Normal file
101
Scripts/Spells/Base/MagerySpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
420
Scripts/Spells/Base/SpecialMove.cs
Normal file
420
Scripts/Spells/Base/SpecialMove.cs
Normal 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
1401
Scripts/Spells/Base/Spell.cs
Normal file
File diff suppressed because it is too large
Load Diff
16
Scripts/Spells/Base/SpellCircle.cs
Normal file
16
Scripts/Spells/Base/SpellCircle.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Spells
|
||||
{
|
||||
public enum SpellCircle
|
||||
{
|
||||
First,
|
||||
Second,
|
||||
Third,
|
||||
Fourth,
|
||||
Fifth,
|
||||
Sixth,
|
||||
Seventh,
|
||||
Eighth
|
||||
}
|
||||
}
|
||||
1944
Scripts/Spells/Base/SpellHelper.cs
Normal file
1944
Scripts/Spells/Base/SpellHelper.cs
Normal file
File diff suppressed because it is too large
Load Diff
150
Scripts/Spells/Base/SpellInfo.cs
Normal file
150
Scripts/Spells/Base/SpellInfo.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
183
Scripts/Spells/Base/SpellRegistry.cs
Normal file
183
Scripts/Spells/Base/SpellRegistry.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Scripts/Spells/Base/SpellState.cs
Normal file
11
Scripts/Spells/Base/SpellState.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Spells
|
||||
{
|
||||
public enum SpellState
|
||||
{
|
||||
None = 0,
|
||||
Casting = 1, // We are in the process of casting (that is, waiting GetCastTime() and doing animations). Spell casting may be interupted in this state.
|
||||
Sequencing = 2 // Casting completed, but the full spell sequence isn't. Usually waiting for a target response. Some actions are restricted in this state (using skills for example).
|
||||
}
|
||||
}
|
||||
199
Scripts/Spells/Bushido/Confidence.cs
Normal file
199
Scripts/Spells/Bushido/Confidence.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
131
Scripts/Spells/Bushido/CounterAttack.cs
Normal file
131
Scripts/Spells/Bushido/CounterAttack.cs
Normal 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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
259
Scripts/Spells/Bushido/Evasion.cs
Normal file
259
Scripts/Spells/Bushido/Evasion.cs
Normal 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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
206
Scripts/Spells/Bushido/HonorableExecution.cs
Normal file
206
Scripts/Spells/Bushido/HonorableExecution.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
139
Scripts/Spells/Bushido/LightningStrike.cs
Normal file
139
Scripts/Spells/Bushido/LightningStrike.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
109
Scripts/Spells/Bushido/MomentumStrike.cs
Normal file
109
Scripts/Spells/Bushido/MomentumStrike.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Scripts/Spells/Bushido/SamuraiMove.cs
Normal file
19
Scripts/Spells/Bushido/SamuraiMove.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
167
Scripts/Spells/Bushido/SamuraiSpell.cs
Normal file
167
Scripts/Spells/Bushido/SamuraiSpell.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
146
Scripts/Spells/Chivalry/CleanseByFire.cs
Normal file
146
Scripts/Spells/Chivalry/CleanseByFire.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
141
Scripts/Spells/Chivalry/CloseWounds.cs
Normal file
141
Scripts/Spells/Chivalry/CloseWounds.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
231
Scripts/Spells/Chivalry/ConsecrateWeapon.cs
Normal file
231
Scripts/Spells/Chivalry/ConsecrateWeapon.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
146
Scripts/Spells/Chivalry/DispelEvil.cs
Normal file
146
Scripts/Spells/Chivalry/DispelEvil.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
158
Scripts/Spells/Chivalry/DivineFury.cs
Normal file
158
Scripts/Spells/Chivalry/DivineFury.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
317
Scripts/Spells/Chivalry/EnemyOfOne.cs
Normal file
317
Scripts/Spells/Chivalry/EnemyOfOne.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Scripts/Spells/Chivalry/HolyLight.cs
Normal file
100
Scripts/Spells/Chivalry/HolyLight.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
189
Scripts/Spells/Chivalry/NobleSacrifice.cs
Normal file
189
Scripts/Spells/Chivalry/NobleSacrifice.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
142
Scripts/Spells/Chivalry/PaladinSpell.cs
Normal file
142
Scripts/Spells/Chivalry/PaladinSpell.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
152
Scripts/Spells/Chivalry/RemoveCurse.cs
Normal file
152
Scripts/Spells/Chivalry/RemoveCurse.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
304
Scripts/Spells/Chivalry/SacredJourney.cs
Normal file
304
Scripts/Spells/Chivalry/SacredJourney.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Scripts/Spells/Eighth/AirElemental.cs
Normal file
57
Scripts/Spells/Eighth/AirElemental.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Scripts/Spells/Eighth/EarthElemental.cs
Normal file
57
Scripts/Spells/Eighth/EarthElemental.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
75
Scripts/Spells/Eighth/Earthquake.cs
Normal file
75
Scripts/Spells/Eighth/Earthquake.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
104
Scripts/Spells/Eighth/EnergyVortex.cs
Normal file
104
Scripts/Spells/Eighth/EnergyVortex.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
Scripts/Spells/Eighth/FireElemental.cs
Normal file
58
Scripts/Spells/Eighth/FireElemental.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Scripts/Spells/Eighth/Resurrection.cs
Normal file
106
Scripts/Spells/Eighth/Resurrection.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Scripts/Spells/Eighth/SummonDaemon.cs
Normal file
62
Scripts/Spells/Eighth/SummonDaemon.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Scripts/Spells/Eighth/WaterElemental.cs
Normal file
57
Scripts/Spells/Eighth/WaterElemental.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
111
Scripts/Spells/Fifth/BladeSpirits.cs
Normal file
111
Scripts/Spells/Fifth/BladeSpirits.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Scripts/Spells/Fifth/DispelField.cs
Normal file
91
Scripts/Spells/Fifth/DispelField.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
188
Scripts/Spells/Fifth/Incognito.cs
Normal file
188
Scripts/Spells/Fifth/Incognito.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
161
Scripts/Spells/Fifth/MagicReflect.cs
Normal file
161
Scripts/Spells/Fifth/MagicReflect.cs
Normal 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
|
||||
}
|
||||
}
|
||||
171
Scripts/Spells/Fifth/MindBlast.cs
Normal file
171
Scripts/Spells/Fifth/MindBlast.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
114
Scripts/Spells/Fifth/Paralyze.cs
Normal file
114
Scripts/Spells/Fifth/Paralyze.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
314
Scripts/Spells/Fifth/PoisonField.cs
Normal file
314
Scripts/Spells/Fifth/PoisonField.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Scripts/Spells/Fifth/SummonCreature.cs
Normal file
98
Scripts/Spells/Fifth/SummonCreature.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
140
Scripts/Spells/First/Clumsy.cs
Normal file
140
Scripts/Spells/First/Clumsy.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
111
Scripts/Spells/First/CreateFood.cs
Normal file
111
Scripts/Spells/First/CreateFood.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
140
Scripts/Spells/First/Feeblemind.cs
Normal file
140
Scripts/Spells/First/Feeblemind.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Scripts/Spells/First/Heal.cs
Normal file
110
Scripts/Spells/First/Heal.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
128
Scripts/Spells/First/MagicArrow.cs
Normal file
128
Scripts/Spells/First/MagicArrow.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
83
Scripts/Spells/First/NightSight.cs
Normal file
83
Scripts/Spells/First/NightSight.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
165
Scripts/Spells/First/ReactiveArmor.cs
Normal file
165
Scripts/Spells/First/ReactiveArmor.cs
Normal 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
|
||||
}
|
||||
}
|
||||
141
Scripts/Spells/First/Weaken.cs
Normal file
141
Scripts/Spells/First/Weaken.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
196
Scripts/Spells/Fourth/ArchCure.cs
Normal file
196
Scripts/Spells/Fourth/ArchCure.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
175
Scripts/Spells/Fourth/ArchProtection.cs
Normal file
175
Scripts/Spells/Fourth/ArchProtection.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
200
Scripts/Spells/Fourth/Curse.cs
Normal file
200
Scripts/Spells/Fourth/Curse.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
334
Scripts/Spells/Fourth/FireField.cs
Normal file
334
Scripts/Spells/Fourth/FireField.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Scripts/Spells/Fourth/GreaterHeal.cs
Normal file
100
Scripts/Spells/Fourth/GreaterHeal.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
Scripts/Spells/Fourth/Lightning.cs
Normal file
113
Scripts/Spells/Fourth/Lightning.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
136
Scripts/Spells/Fourth/ManaDrain.cs
Normal file
136
Scripts/Spells/Fourth/ManaDrain.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
318
Scripts/Spells/Fourth/Recall.cs
Normal file
318
Scripts/Spells/Fourth/Recall.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Scripts/Spells/Gargoyle/SpellDefinitions/FlySpell.cs
Normal file
98
Scripts/Spells/Gargoyle/SpellDefinitions/FlySpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
241
Scripts/Spells/Initializer.cs
Normal file
241
Scripts/Spells/Initializer.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
134
Scripts/Spells/Mysticism/MysticSpell.cs
Normal file
134
Scripts/Spells/Mysticism/MysticSpell.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
120
Scripts/Spells/Mysticism/SpellDefinitions/BombardSpell.cs
Normal file
120
Scripts/Spells/Mysticism/SpellDefinitions/BombardSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
264
Scripts/Spells/Mysticism/SpellDefinitions/CleansingWindsSpell.cs
Normal file
264
Scripts/Spells/Mysticism/SpellDefinitions/CleansingWindsSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
112
Scripts/Spells/Mysticism/SpellDefinitions/EagleStrikeSpell.cs
Normal file
112
Scripts/Spells/Mysticism/SpellDefinitions/EagleStrikeSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
94
Scripts/Spells/Mysticism/SpellDefinitions/EnchantGump.cs
Normal file
94
Scripts/Spells/Mysticism/SpellDefinitions/EnchantGump.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
259
Scripts/Spells/Mysticism/SpellDefinitions/EnchantSpell .cs
Normal file
259
Scripts/Spells/Mysticism/SpellDefinitions/EnchantSpell .cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
122
Scripts/Spells/Mysticism/SpellDefinitions/HailStormSpell.cs
Normal file
122
Scripts/Spells/Mysticism/SpellDefinitions/HailStormSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
84
Scripts/Spells/Mysticism/SpellDefinitions/MassSleepSpell.cs
Normal file
84
Scripts/Spells/Mysticism/SpellDefinitions/MassSleepSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
105
Scripts/Spells/Mysticism/SpellDefinitions/NetherBoltSpell.cs
Normal file
105
Scripts/Spells/Mysticism/SpellDefinitions/NetherBoltSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
146
Scripts/Spells/Mysticism/SpellDefinitions/NetherCycloneSpell.cs
Normal file
146
Scripts/Spells/Mysticism/SpellDefinitions/NetherCycloneSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
342
Scripts/Spells/Mysticism/SpellDefinitions/PurgeMagicSpell.cs
Normal file
342
Scripts/Spells/Mysticism/SpellDefinitions/PurgeMagicSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
190
Scripts/Spells/Mysticism/SpellDefinitions/SleepSpell.cs
Normal file
190
Scripts/Spells/Mysticism/SpellDefinitions/SleepSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
253
Scripts/Spells/Mysticism/SpellDefinitions/SpellPlague.cs
Normal file
253
Scripts/Spells/Mysticism/SpellDefinitions/SpellPlague.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
307
Scripts/Spells/Mysticism/SpellDefinitions/SpellTriggerSpell.cs
Normal file
307
Scripts/Spells/Mysticism/SpellDefinitions/SpellTriggerSpell.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
217
Scripts/Spells/Mysticism/SpellDefinitions/StoneForm.cs
Normal file
217
Scripts/Spells/Mysticism/SpellDefinitions/StoneForm.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
462
Scripts/Spells/Necromancy/AnimateDeadSpell.cs
Normal file
462
Scripts/Spells/Necromancy/AnimateDeadSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
211
Scripts/Spells/Necromancy/BloodOathSpell.cs
Normal file
211
Scripts/Spells/Necromancy/BloodOathSpell.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
207
Scripts/Spells/Necromancy/CorpseSkin.cs
Normal file
207
Scripts/Spells/Necromancy/CorpseSkin.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
135
Scripts/Spells/Necromancy/CurseWeapon.cs
Normal file
135
Scripts/Spells/Necromancy/CurseWeapon.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
168
Scripts/Spells/Necromancy/EvilOmen.cs
Normal file
168
Scripts/Spells/Necromancy/EvilOmen.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
220
Scripts/Spells/Necromancy/Exorcism.cs
Normal file
220
Scripts/Spells/Necromancy/Exorcism.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Scripts/Spells/Necromancy/HorrificBeast.cs
Normal file
64
Scripts/Spells/Necromancy/HorrificBeast.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
94
Scripts/Spells/Necromancy/LichForm.cs
Normal file
94
Scripts/Spells/Necromancy/LichForm.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
200
Scripts/Spells/Necromancy/MindRot.cs
Normal file
200
Scripts/Spells/Necromancy/MindRot.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Scripts/Spells/Necromancy/NecromancerSpell.cs
Normal file
78
Scripts/Spells/Necromancy/NecromancerSpell.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
178
Scripts/Spells/Necromancy/PainSpike.cs
Normal file
178
Scripts/Spells/Necromancy/PainSpike.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
152
Scripts/Spells/Necromancy/PoisonStrike.cs
Normal file
152
Scripts/Spells/Necromancy/PoisonStrike.cs
Normal 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 item’s 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
274
Scripts/Spells/Necromancy/Strangle.cs
Normal file
274
Scripts/Spells/Necromancy/Strangle.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
258
Scripts/Spells/Necromancy/SummonFamiliar.cs
Normal file
258
Scripts/Spells/Necromancy/SummonFamiliar.cs
Normal 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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
96
Scripts/Spells/Necromancy/TransformationSpell.cs
Normal file
96
Scripts/Spells/Necromancy/TransformationSpell.cs
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Scripts/Spells/Necromancy/VampiricEmbrace.cs
Normal file
100
Scripts/Spells/Necromancy/VampiricEmbrace.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
109
Scripts/Spells/Necromancy/VengefulSpirit.cs
Normal file
109
Scripts/Spells/Necromancy/VengefulSpirit.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
123
Scripts/Spells/Necromancy/Wither.cs
Normal file
123
Scripts/Spells/Necromancy/Wither.cs
Normal 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 item’s 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
111
Scripts/Spells/Necromancy/WraithForm.cs
Normal file
111
Scripts/Spells/Necromancy/WraithForm.cs
Normal 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
Reference in New Issue
Block a user