Files
abysmal-isle/Scripts/Spells/Skill Masteries/Core/SkillMasterySpell.cs
Unstable Kitsune b918192e4e Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
2023-11-28 23:20:26 -05:00

1300 lines
38 KiB
C#

using System;
using Server;
using Server.Spells;
using Server.Network;
using Server.Mobiles;
using System.Collections;
using System.Collections.Generic;
using Server.Engines.PartySystem;
using Server.Targeting;
using Server.Items;
using Server.Commands;
using System.Linq;
namespace Server.Spells.SkillMasteries
{
public abstract class SkillMasterySpell : Spell
{
public static void Initialize()
{
CommandSystem.Register("LearnAllMasteries", AccessLevel.GameMaster, LearnAllSpells);
CommandSystem.Register("RandomMastery", AccessLevel.GameMaster, RandomMastery);
}
public UpkeepTimer Timer { get; set; }
public Mobile Target { get; set; }
public List<Mobile> PartyList { get; set; }
public DateTime Expires { get; set; }
public virtual double RequiredSkill { get { return 90.0; } }
public virtual double UpKeep { get { return 0; } }
public virtual int RequiredMana { get { return 10; } }
public virtual bool PartyEffects { get { return false; } }
public virtual int DamageThreshold { get { return 45; } }
public virtual bool DamageCanDisrupt { get { return false; } }
public virtual double TickTime { get { return 2; } }
public virtual int PartyRange { get { return 12; } }
public virtual int UpkeepCancelMessage { get { return 1156111; } } // You do not have enough mana to keep your ability active.
public virtual int OutOfRangeMessage { get { return 1156098; } } // Your target is no longer in range of your ability.
public virtual int DisruptMessage { get { return 1156110; } } // Your ability was canceled.
public virtual bool CancelsWeaponAbility { get { return false; } }
public virtual bool CancelsSpecialMove { get { return CancelsWeaponAbility; } }
public virtual bool RevealOnTick { get { return true; } }
public virtual TimeSpan ExpirationPeriod { get { return TimeSpan.FromMinutes(30); } }
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(2.25); } }
public virtual double BaseSkillBonus
{
get
{
if(Caster == null)
return 0.0;
return (Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value + (GetMasteryLevel() * 40)) / 3;
}
}
public virtual double CollectiveBonus
{
get
{
return 0;
}
}
public override bool ClearHandsOnCast{ get{ return false; } }
public override bool BlocksMovement{ get{ return true; } }
public SkillMasterySpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, null, info )
{
}
public override bool CheckCast()
{
int mana = ScaleMana( RequiredMana );
if ( !base.CheckCast() )
return false;
if (IsInCooldown(Caster, this.GetType()))
return false;
if (Caster.Player && Caster.Skills[CastSkill].Value < RequiredSkill)
Caster.SendLocalizedMessage(1115709); // Your skills are not high enough to invoke this mastery ability.
else if (Caster is PlayerMobile && Caster.Skills.CurrentMastery != CastSkill)
Caster.SendLocalizedMessage(1115664); // You are not on the correct path for using this mastery ability.
else if (Caster is PlayerMobile && !MasteryInfo.HasLearned(Caster, CastSkill))
Caster.SendLocalizedMessage(1115664); // You are not on the correct path for using this mastery ability.
else if (Caster.Mana < mana)
Caster.SendLocalizedMessage(1060174, mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
else
{
if (CancelsWeaponAbility)
WeaponAbility.ClearCurrentAbility(Caster);
if (CancelsSpecialMove)
SpecialMove.ClearCurrentMove(Caster);
return true;
}
return false;
}
public override void DoFizzle()
{
Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502632); // The spell fizzles.
if (Caster.Player)
{
Caster.FixedParticles(0x3735, 1, 30, 9503, EffectLayer.Waist);
//m_Caster.PlaySound(0x5C);
}
}
public override void GetCastSkills( out double min, out double max )
{
min = RequiredSkill;
max = RequiredSkill + 25.0;
}
public override int GetMana()
{
return RequiredMana;
}
public BaseWeapon GetWeapon()
{
return Caster.Weapon as BaseWeapon;
}
public bool CheckWeapon()
{
if (!Caster.Player)
return true;
BaseWeapon wep = GetWeapon();
if (CastSkill == SkillName.Poisoning && wep != null && !(wep is Fists))
return true;
return wep != null && wep.DefSkill == CastSkill;
}
public virtual bool OnTick()
{
UpdateParty();
if (RevealOnTick)
{
Caster.RevealingAction();
}
int upkeep = ScaleUpkeep();
if (0.10 > Utility.RandomDouble())
{
NegativeAttributes.OnCombatAction(Caster);
}
if ((Caster is PlayerMobile && Caster.NetState == null) || Expires < DateTime.UtcNow || !Caster.Alive || Caster.IsDeadBondedPet)
{
Expire();
}
else if (Target != null && !Target.Alive)
{
Expire();
}
else if (Target != null && !Caster.InRange(Target.Location, PartyRange))
{
Expire();
if (OutOfRangeMessage > 0)
Caster.SendLocalizedMessage(OutOfRangeMessage);
}
else if (Caster.Mana < upkeep)
{
if (UpkeepCancelMessage > 0)
Caster.SendLocalizedMessage(UpkeepCancelMessage);
Expire();
}
else if (Caster.Player && Caster.Skills[CastSkill].Value < RequiredSkill)
{
Expire();
}
else
{
DoEffects();
Caster.Mana -= upkeep;
return true;
}
return false;
}
protected virtual void DoEffects()
{
}
public virtual int PropertyBonus()
{
return 0;
}
public virtual int PropertyBonus2()
{
return 0;
}
//Used for hits/stam/mana
public virtual int StatBonus()
{
return 0;
}
public virtual void AddStatMods()
{
}
public virtual void RemoveStatMods()
{
}
public virtual void EndEffects()
{
}
public virtual int DamageBonus()
{
return 0;
}
public virtual void OnDamaged(Mobile attacker, Mobile defender, DamageType type, ref int damage)
{
}
public virtual void OnHit(Mobile defender, ref int damage)
{
}
public virtual void OnGotHit(Mobile attacker, ref int damage)
{
}
public virtual void OnMiss(Mobile defender)
{
}
public virtual void OnGotMiss(Mobile attacker)
{
}
public virtual void OnParried(Mobile attacker)
{
}
public virtual void OnGotParried(Mobile defender)
{
}
public virtual void OnTargetDamaged(Mobile attacker, Mobile victim, DamageType type, ref int damage)
{
}
public virtual void OnWeaponRemoved(BaseWeapon weapon)
{
}
public virtual int ScaleUpkeep()
{
if (UpKeep == 0)
return 0;
double mod = CollectiveBonus;
double upkeep = UpKeep;
int mana = (int)(upkeep - ((upkeep * mod) / 4.5));
return ScaleMana(mana);
}
public virtual void Expire(bool disrupt = false)
{
if (Timer != null)
{
Timer.Stop();
Timer = null;
}
if(disrupt && DisruptMessage > 0)
Caster.SendLocalizedMessage(DisruptMessage);
Server.Timer.DelayCall(RemoveFromTable);
RemoveStatMods();
EndEffects();
Caster.Delta(MobileDelta.WeaponDamage);
if(Target != null)
Target.Delta(MobileDelta.WeaponDamage);
if (PartyList != null)
{
foreach(Mobile m in PartyList)
m.Delta(MobileDelta.WeaponDamage);
ColUtility.Free(PartyList);
}
OnExpire();
}
public virtual void OnExpire()
{
}
public virtual double DamageModifier(Mobile victim)
{
double dSkill = Caster.Skills[DamageSkill].Value;
double vSkill = GetResistSkill(victim);
double reduce = 1.0 - ((dSkill - vSkill) / dSkill);
if(reduce < 0) reduce = 0;
if(reduce > 1) reduce = 1;
return reduce;
}
public virtual bool CheckResisted(Mobile target)
{
int volumeMod = GetMasteryLevel();
volumeMod *= 2;
double n = GetResistPercent(target, volumeMod);
n /= 100.0;
if (n <= 0.0)
return false;
if (n >= 1.0)
return true;
int maxSkill = (1 + volumeMod) * 10;
maxSkill += (1 + (volumeMod / 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 GetResistPercent(Mobile target, int level)
{
double value = GetResistSkill(target);
double firstPercent = value / 5.0;
double secondPercent = value - (((Caster.Skills[CastSkill].Value - 20.0) / 5.0) + (1 + level) * 5.0);
return (firstPercent > secondPercent ? firstPercent : secondPercent) / 2.0;
}
public int GetMasteryLevel()
{
return (int)MasteryInfo.GetMasteryLevel(Caster, CastSkill);
}
public void UpdateParty()
{
UpdateParty(false);
}
public void UpdateParty(bool playersOnly)
{
var p = Party.Get(Caster);
if (PartyList == null)
{
PartyList = new List<Mobile>();
}
if (p != null)
{
foreach (var m in p.Members.Select(x => x.Mobile))
{
if (!PartyList.Contains(m) && (!playersOnly || m is PlayerMobile) && ValidPartyMember(m))
{
AddPartyMember(m);
}
else if (PartyList.Contains(m) && !ValidPartyMember(m))
{
RemovePartyMember(m);
}
else
{
UpdatePets(m);
}
}
}
else if (!PartyList.Contains(Caster))
{
AddPartyMember(Caster);
}
}
public virtual bool CheckPartyEffects(Mobile m, bool beneficial = false)
{
if (m == Caster)
return true;
if (Caster.IsBeneficialCriminal(m))
{
int casterNoto = Notoriety.Compute(Caster, m);
int mNoto = Notoriety.Compute(m, Caster);
if (casterNoto == Notoriety.Enemy || casterNoto != mNoto)
{
return false;
}
}
if (beneficial)
Caster.DoBeneficial(m);
return true;
}
protected virtual bool ValidPartyMember(Mobile m)
{
return m.Alive && m.InRange(Caster, PartyRange) && m.Map == Caster.Map && CheckPartyEffects(m);
}
protected void AddPartyMember(Mobile m)
{
PartyList.Add(m);
AddPartyEffects(m);
if (m is PlayerMobile)
{
foreach (var pet in ((PlayerMobile)m).AllFollowers.Where(p => !PartyList.Contains(p) && ValidPartyMember(p)))
{
AddPartyMember(pet);
}
}
}
protected void RemovePartyMember(Mobile m)
{
PartyList.Remove(m);
RemovePartyEffects(m);
if (m is PlayerMobile)
{
foreach (var pet in ((PlayerMobile)m).AllFollowers.Where(p => PartyList.Contains(p)))
{
RemovePartyMember(pet);
}
}
}
private void UpdatePets(Mobile m)
{
if (m is PlayerMobile)
{
foreach (var pet in ((PlayerMobile)m).AllFollowers.Where(p => !PartyList.Contains(p) && ValidPartyMember(p)))
{
AddPartyMember(pet);
}
}
}
public virtual void AddPartyEffects(Mobile m)
{
}
public virtual void RemovePartyEffects(Mobile m)
{
}
public static void OnPartyRemoved(Mobile m, bool disband)
{
foreach (var spell in GetSpells(s => s.PartyEffects && s.PartyList != null && (s.Caster == m || s.PartyList.Contains(m))))
{
if (disband)
{
spell.PartyList.IterateReverse(mob =>
{
if (mob != spell.Caster || (mob is BaseCreature && ((BaseCreature)mob).GetMaster() != mob))
{
spell.RemovePartyMember(mob);
}
});
}
else
{
spell.RemovePartyMember(m);
}
}
}
private static Dictionary<Mobile, List<SkillMasterySpell>> m_Table = new Dictionary<Mobile, List<SkillMasterySpell>>();
public static SkillMasterySpell GetHarmfulSpell(Mobile target, Type type)
{
foreach (Mobile m in m_Table.Keys)
{
foreach (SkillMasterySpell spell in m_Table[m])
{
if (spell != null && spell.GetType() == type && spell.Target == target)
return spell;
}
}
return null;
}
public static bool HasHarmfulEffects(Mobile target, Type type)
{
foreach (Mobile m in m_Table.Keys)
{
foreach (SkillMasterySpell spell in m_Table[m])
{
if (spell != null && spell.GetType() == type && spell.Target == target)
return true;
}
}
return false;
}
public static SkillMasterySpell GetSpell(Mobile from, Type type)
{
CheckTable(from);
if (m_Table.ContainsKey(from))
{
return m_Table[from].FirstOrDefault(spell => spell != null && spell.GetType() == type);
}
return null;
}
public static TSpell GetSpell<TSpell>(Mobile m) where TSpell : SkillMasterySpell
{
if (m_Table.ContainsKey(m))
{
return m_Table[m].FirstOrDefault(sms => sms.GetType() == typeof(TSpell)) as TSpell;
}
return null;
}
public static TSpell GetSpell<TSpell>(Mobile caster, Mobile target) where TSpell : SkillMasterySpell
{
if (m_Table.ContainsKey(caster))
{
return m_Table[caster].FirstOrDefault(sms => sms.GetType() == typeof(TSpell) && sms.Target == target) as TSpell;
}
return null;
}
public static SkillMasterySpell GetSpell(Func<SkillMasterySpell, bool> predicate)
{
foreach (SkillMasterySpell spell in EnumerateAllSpells())
{
if (predicate != null && predicate(spell))
return spell;
}
return null;
}
public static TSpell GetSpell<TSpell>(Func<SkillMasterySpell, bool> predicate) where TSpell : SkillMasterySpell
{
foreach (SkillMasterySpell spell in EnumerateAllSpells().Where(sp => sp.GetType() == typeof(TSpell)))
{
if (predicate != null && predicate(spell))
return spell as TSpell;
}
return null;
}
public static IEnumerable<SkillMasterySpell> GetSpells(Func<SkillMasterySpell, bool> predicate)
{
foreach (SkillMasterySpell spell in EnumerateAllSpells())
{
if (spell != null && predicate != null && predicate(spell))
{
yield return spell;
}
}
}
public static IEnumerable<SkillMasterySpell> GetSpells(Mobile caster, Func<SkillMasterySpell, bool> predicate)
{
foreach (SkillMasterySpell spell in EnumerateSpells(caster))
{
if (spell != null && predicate != null && predicate(spell))
{
yield return spell;
}
}
}
public static bool HasSpell(Mobile from, Type type)
{
CheckTable(from);
if (m_Table.ContainsKey(from))
{
return m_Table[from].Any(spell => spell.GetType() == type);
}
return false;
}
public static bool HasSpell<TSpell>(Mobile from) where TSpell : SkillMasterySpell
{
CheckTable(from);
if (m_Table.ContainsKey(from))
{
return m_Table[from].Any(spell => spell.GetType() == typeof(TSpell));
}
return false;
}
public static bool UnderPartyEffects(Mobile from, Type type)
{
return GetSpellForParty(from, type) != null;
}
public static SkillMasterySpell GetSpellForParty(Mobile from, Type type)
{
CheckTable(from);
Mobile check = from;
if (from is BaseCreature && (((BaseCreature)from).Controlled || ((BaseCreature)from).Summoned) && ((BaseCreature)from).GetMaster() != null)
{
check = ((BaseCreature)from).GetMaster();
CheckTable(check);
}
//First checks the caster
if (m_Table.ContainsKey(check))
{
foreach (SkillMasterySpell spell in m_Table[check])
{
if (spell != null && spell.GetType() == type)
return spell;
}
}
else
{
Party p = Party.Get(check);
if (p != null)
{
foreach (PartyMemberInfo info in p.Members)
{
SkillMasterySpell spell = GetSpell(info.Mobile, type);
if (spell != null && spell.PartyEffects && from.InRange(info.Mobile.Location, spell.PartyRange) && spell.CheckPartyEffects(info.Mobile))
return spell;
}
}
}
return null;
}
private static object _Lock = new object();
public static void CheckTable(Mobile m)
{
if (m == null)
return;
lock (_Lock)
{
if (m_Table.ContainsKey(m))
{
if (m_Table[m] == null || m_Table[m].Count == 0)
{
m_Table.Remove(m);
}
}
}
}
public static IEnumerable<SkillMasterySpell> EnumerateAllSpells()
{
if (m_Table == null || m_Table.Count == 0)
yield break;
List<SkillMasterySpell> list = new List<SkillMasterySpell>();
lock (_Lock)
{
foreach (KeyValuePair<Mobile, List<SkillMasterySpell>> kvp in m_Table)
{
list.AddRange(kvp.Value);
}
}
foreach (SkillMasterySpell spell in list)
{
yield return spell;
}
}
public static IEnumerable<SkillMasterySpell> EnumerateSpells(Mobile from, Type t = null)
{
if (m_Table == null || m_Table.Count == 0 || !m_Table.ContainsKey(from))
yield break;
List<SkillMasterySpell> list;
lock (_Lock)
{
list = m_Table[from];
if (list == null || list.Count == 0)
{
yield break;
}
}
IEnumerable<SkillMasterySpell> e;
lock (_Lock)
{
e = list.Where(s => s.GetType() == t || t == null);
}
foreach (SkillMasterySpell spell in e)
{
yield return spell;
}
}
public static List<SkillMasterySpell> GetSpells(Mobile m)
{
if (m_Table != null && m_Table.ContainsKey(m))
{
return new List<SkillMasterySpell>(m_Table[m]);
}
return null;
}
protected void AddToTable(Mobile from, SkillMasterySpell spell)
{
lock (_Lock)
{
if (!m_Table.ContainsKey(from))
{
m_Table[from] = new List<SkillMasterySpell>();
}
if (!m_Table[from].Contains(spell))
{
m_Table[from].Add(spell);
}
}
}
protected void RemoveFromTable()
{
if(m_Table.ContainsKey(Caster) && m_Table[Caster].Contains(this))
{
lock (_Lock)
{
m_Table[Caster].Remove(this);
if (m_Table[Caster].Count == 0)
{
m_Table.Remove(Caster);
}
}
}
}
/// <summary>
/// Called in Aos.cs, should include all damage types
/// </summary>
/// <param name="victim"></param>
/// <param name="damager"></param>
/// <param name="damage"></param>
public static void OnDamage(Mobile victim, Mobile damager, DamageType type, ref int damage)
{
if(victim == null || damager == null)
return;
CheckTable(victim);
foreach (SkillMasterySpell sp in EnumerateSpells(victim))
{
if (sp.DamageCanDisrupt && damage > sp.DamageThreshold)
sp.Expire(true);
sp.OnDamaged(damager, victim, type, ref damage);
}
foreach (SkillMasterySpell sp in GetSpells(s => s.Target == victim))
{
sp.OnTargetDamaged(damager, victim, type, ref damage);
}
SkillMasteryMove move = SpecialMove.GetCurrentMove(victim) as SkillMasteryMove;
if (move != null)
move.OnDamaged(damager, victim, type, ref damage);
PerseveranceSpell preserve = SkillMasterySpell.GetSpellForParty(victim, typeof(PerseveranceSpell)) as PerseveranceSpell;
if (preserve != null)
preserve.AbsorbDamage(ref damage);
InspireSpell inspire = SkillMasterySpell.GetSpellForParty(damager, typeof(InspireSpell)) as InspireSpell;
if (inspire != null)
inspire.DoDamage(ref damage);
CombatTrainingSpell.CheckDamage(damager, victim, type, ref damage);
}
/// <summary>
/// Called in BaseWeapon, intended as a melee/ranged hit
/// </summary>
/// <param name="attacker"></param>
/// <param name="defender"></param>
/// <param name="damage"></param>
public static void OnHit(Mobile attacker, Mobile defender, ref int damage)
{
if (attacker == null || defender == null)
return;
foreach(SkillMasterySpell spell in EnumerateSpells(attacker))
{
spell.OnHit(defender, ref damage);
}
foreach (SkillMasterySpell spell in EnumerateSpells(defender))
{
spell.OnGotHit(defender, ref damage);
}
SkillMasteryMove move = SpecialMove.GetCurrentMove(defender) as SkillMasteryMove;
if (move != null)
move.OnGotHit(attacker, defender, ref damage);
if(attacker is BaseCreature || defender is BaseCreature)
CombatTrainingSpell.OnCreatureHit(attacker, defender, ref damage);
}
/// <summary>
/// Called in BaseWeapon, intended as a melee/ranged miss
/// </summary>
/// <param name="attacker"></param>
/// <param name="defender"></param>
public static void OnMiss(Mobile attacker, Mobile defender)
{
if (attacker == null || defender == null)
return;
foreach (SkillMasterySpell spell in EnumerateSpells(attacker))
{
spell.OnMiss(defender);
}
foreach (SkillMasterySpell spell in EnumerateSpells(defender))
{
spell.OnGotMiss(attacker);
}
}
/// <summary>
/// Called in BaseWeapon, intended as a melee/ranged parry
/// </summary>
/// <param name="attacker"></param>
/// <param name="defender"></param>
public static void OnParried(Mobile attacker, Mobile defender)
{
if (attacker == null || defender == null)
return;
foreach (SkillMasterySpell spell in EnumerateSpells(defender))
{
spell.OnParried(attacker);
}
foreach (SkillMasterySpell spell in EnumerateSpells(attacker))
{
spell.OnGotParried(defender);
}
}
public static bool HasMastery(Mobile mobile, SkillName name)
{
Skill sk = mobile.Skills[name];
return sk.IsMastery && sk.VolumeLearned != 0;
}
public static bool SetActiveMastery(Mobile mobile, SkillName name)
{
return mobile.Skills[name].SetCurrent();
}
protected virtual void BeginTimer()
{
if(Timer != null)
{
Timer.Stop();
Timer = null;
}
Timer = new UpkeepTimer(this);
Timer.Start();
if(Expires < DateTime.UtcNow)
Expires = DateTime.UtcNow + ExpirationPeriod;
AddToTable(Caster, this);
AddStatMods();
if (RevealOnTick)
{
Caster.RevealingAction();
}
Caster.Delta(MobileDelta.WeaponDamage);
if(Target != null)
Target.Delta(MobileDelta.WeaponDamage);
if (PartyList != null)
{
foreach (Mobile m in PartyList)
m.Delta(MobileDelta.WeaponDamage);
}
}
public int GetWeaponSkill()
{
double swrd = Caster.Skills[SkillName.Swords].Value;
double fenc = Caster.Skills[SkillName.Fencing].Value;
double mcng = Caster.Skills[SkillName.Macing].Value;
double arch = Caster.Skills[SkillName.Archery].Value;
double thro = Caster.Skills[SkillName.Throwing].Value;
double wres = Caster.Skills[SkillName.Wrestling].Value;
double val = swrd;
if (fenc > val)
val = fenc;
if (mcng > val)
val = mcng;
if (arch > val)
val = arch;
if (thro > val)
val = thro;
if (wres > val)
val = wres;
return (int)val;
}
public static void OnWeaponRemoved(Mobile from, BaseWeapon weapon)
{
foreach (SkillMasterySpell spell in EnumerateSpells(from))
{
spell.OnWeaponRemoved(weapon);
}
}
public static void CancelWeaponAbility(Mobile attacker)
{
foreach (SkillMasterySpell spell in EnumerateSpells(attacker).Where(s => s.CancelsWeaponAbility))
{
spell.Expire();
}
}
public static void CancelSpecialMove(Mobile attacker)
{
foreach (SkillMasterySpell spell in EnumerateSpells(attacker).Where(s => s.CancelsSpecialMove))
{
spell.Expire();
}
}
private static Dictionary<SkillMasterySpell, DateTime> _Cooldown;
protected void AddToCooldown(TimeSpan ts)
{
if (_Cooldown == null)
_Cooldown = new Dictionary<SkillMasterySpell, DateTime>();
_Cooldown[this] = DateTime.UtcNow + ts;
Server.Timer.DelayCall(ts, () => RemoveFromCooldown(this.GetType(), Caster));
}
public static bool IsInCooldown(Mobile m, Type type, bool message = true)
{
CheckCooldown();
if (_Cooldown == null)
return false;
bool iscooling = false;
foreach (KeyValuePair<SkillMasterySpell, DateTime> kvp in _Cooldown)
{
SkillMasterySpell spell = kvp.Key;
DateTime dt = kvp.Value;
if (!iscooling && spell.GetType() == type && spell.Caster == m)
{
if (message)
{
double left = (dt - DateTime.UtcNow).TotalMinutes;
if (left > 1)
m.SendLocalizedMessage(1155787, ((int)left).ToString()); // You must wait ~1_minutes~ minutes before you can use this ability.
else
{
left = (_Cooldown[spell] - DateTime.UtcNow).TotalSeconds;
if(left > 0)
m.SendLocalizedMessage(1079335, left.ToString("F", System.Globalization.CultureInfo.InvariantCulture)); // You must wait ~1_seconds~ seconds before you can use this ability again.
}
}
iscooling = true;
}
}
return iscooling;
}
public static void RemoveFromCooldown(Type type, Mobile m)
{
if (_Cooldown == null)
return;
SkillMasterySpell spell = null;
foreach (KeyValuePair<SkillMasterySpell, DateTime> kvp in _Cooldown)
{
if (kvp.Key.GetType() == type && kvp.Key.Caster == m)
spell = kvp.Key;
}
if (spell != null)
_Cooldown.Remove(spell);
CheckCooldown();
}
public static void CheckCooldown()
{
if (_Cooldown == null)
return;
List<SkillMasterySpell> spells = new List<SkillMasterySpell>();
foreach (KeyValuePair<SkillMasterySpell, DateTime> kvp in _Cooldown)
{
if (kvp.Value < DateTime.UtcNow)
spells.Add(kvp.Key);
}
spells.ForEach(sp => _Cooldown.Remove(sp));
if (_Cooldown != null && _Cooldown.Count == 0)
_Cooldown = null;
}
public static int GetAttributeBonus(Mobile m, AosAttribute attr)
{
int value = 0;
SkillMasterySpell spell = null;
switch (attr)
{
case AosAttribute.AttackChance:
spell = SkillMasterySpell.GetSpellForParty(m, typeof(InspireSpell));
if (spell != null)
value += spell.PropertyBonus();
spell = SkillMasterySpell.GetSpellForParty(m, typeof(TribulationSpell));
if (spell != null)
value += spell.PropertyBonus();
value += FocusedEyeSpell.HitChanceBonus(m);
value += PlayingTheOddsSpell.HitChanceBonus(m);
value += CalledShotSpell.GetHitChanceBonus(m);
value += CombatTrainingSpell.GetHitChanceBonus(m);
value += MasteryInfo.SavingThrowChance(m, attr);
break;
case AosAttribute.DefendChance:
spell = SkillMasterySpell.GetSpellForParty(m, typeof(PerseveranceSpell));
if (spell != null)
value += spell.PropertyBonus();
if (Server.Spells.SkillMasteries.WhiteTigerFormSpell.IsActive(m))
value += 20;
value += MasteryInfo.SavingThrowChance(m, attr);
break;
case AosAttribute.RegenHits:
spell = SkillMasterySpell.GetSpellForParty(m, typeof(ResilienceSpell));
if (spell != null)
value += spell.PropertyBonus();
break;
case AosAttribute.RegenStam:
spell = SkillMasterySpell.GetSpellForParty(m, typeof(ResilienceSpell));
if (spell != null)
value += spell.PropertyBonus();
break;
case AosAttribute.RegenMana:
spell = SkillMasterySpell.GetSpellForParty(m, typeof(ResilienceSpell));
if (spell != null)
value += spell.PropertyBonus();
break;
case AosAttribute.WeaponDamage:
spell = SkillMasterySpell.GetSpellForParty(m, typeof(InspireSpell));
if (spell != null)
value += spell.DamageBonus();
value += MasteryInfo.SavingThrowChance(m, attr);
break;
case AosAttribute.SpellDamage:
spell = SkillMasterySpell.GetSpellForParty(m, typeof(InspireSpell));
if (spell != null)
value += spell.PropertyBonus();
break;
case AosAttribute.WeaponSpeed:
value += RampageSpell.GetBonus(m, RampageSpell.BonusType.SwingSpeed);
value += PlayingTheOddsSpell.SwingSpeedBonus(m);
value -= StaggerSpell.GetStagger(m);
break;
case AosAttribute.BonusStr:
value += MasteryInfo.SavingThrowChance(m, attr);
break;
}
return value;
}
public static int GetAttributeBonus(Mobile m, SAAbsorptionAttribute attr)
{
int value = 0;
switch (attr)
{
case SAAbsorptionAttribute.CastingFocus:
SkillMasterySpell spell = SkillMasterySpell.GetSpellForParty(m, typeof(PerseveranceSpell));
if (spell != null)
value += spell.PropertyBonus2();
break;
}
return value;
}
protected virtual void OnTarget(object o)
{
}
public class MasteryTarget : Target
{
public SkillMasterySpell Owner { get; set; }
public bool AutoFinishSequence { get; set; }
public MasteryTarget(SkillMasterySpell spell, int range = 10, bool allowGround = false, TargetFlags flags = TargetFlags.None, bool autoEnd = true)
: base(range, allowGround, flags)
{
Owner = spell;
AutoFinishSequence = autoEnd;
}
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)
{
if(AutoFinishSequence)
Owner.FinishSequence();
}
}
public class UpkeepTimer : Timer
{
private SkillMasterySpell m_Spell;
public SkillMasterySpell Spell { get { return m_Spell; } }
public UpkeepTimer(SkillMasterySpell spell) : base(TimeSpan.FromSeconds(spell.TickTime), TimeSpan.FromSeconds(spell.TickTime))
{
m_Spell = spell;
}
protected override void OnTick()
{
if(m_Spell != null)
m_Spell.OnTick();
}
}
[Usage("LearnAllMasteries")]
[Description("Select a target to learn all skill masteries.")]
public static void LearnAllSpells(CommandEventArgs e)
{
e.Mobile.SendMessage("Target the mobile who will learn all skill masteries.");
e.Mobile.BeginTarget(-1, false, TargetFlags.None, (mobile, targeted) =>
{
if (targeted is Mobile)
{
Mobile m = targeted as Mobile;
int count = 0;
foreach (Skill sk in m.Skills)
{
if (sk.IsMastery)
{
count++;
sk.VolumeLearned = 3;
}
}
e.Mobile.SendMessage("They have learned {0} masteries!", count.ToString());
}
});
}
[Usage("RandomMastery")]
[Description("Drops a random mastery primer on target.")]
public static void RandomMastery(CommandEventArgs e)
{
e.Mobile.BeginTarget(-1, false, TargetFlags.None, (mobile, targeted) =>
{
Item mastery = SkillMasteryPrimer.GetRandom();
if (targeted is Mobile)
{
Mobile m = targeted as Mobile;
m.Backpack.DropItem(mastery);
e.Mobile.SendMessage("A mastery has been added to your pack!");
}
else if (targeted is IPoint3D)
{
IPoint3D p = targeted as IPoint3D;
mastery.MoveToWorld(new Point3D(p.X, p.Y, p.Z), e.Mobile.Map);
}
else
mastery.Delete();
});
}
}
}