Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
165
Scripts/Spells/Skill Masteries/BardSpells/BardSpell.cs
Normal file
165
Scripts/Spells/Skill Masteries/BardSpells/BardSpell.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using System.Collections.Generic;
|
||||
using Server.Engines.PartySystem;
|
||||
using Server.Targeting;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public abstract class BardSpell : SkillMasterySpell
|
||||
{
|
||||
private BaseInstrument m_Instrument;
|
||||
public BaseInstrument Instrument { get { return m_Instrument; } }
|
||||
|
||||
public virtual double SlayerBonus { get { return 1.5; } }
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override double UpKeep { get { return 0; } }
|
||||
public override int RequiredMana { get { return 0; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
public override bool DamageCanDisrupt { get { return true; } }
|
||||
|
||||
public override double BaseSkillBonus
|
||||
{
|
||||
get
|
||||
{
|
||||
return Math.Floor(2 + (((Caster.Skills[CastSkill].Base - 90) / 10) + ((Caster.Skills[DamageSkill].Base - 90) / 10)));
|
||||
}
|
||||
}
|
||||
|
||||
public override double CollectiveBonus
|
||||
{
|
||||
get
|
||||
{
|
||||
double bonus = 0;
|
||||
double prov = Caster.Skills[SkillName.Provocation].Base;
|
||||
double peac = Caster.Skills[SkillName.Peacemaking].Base;
|
||||
double disc = Caster.Skills[SkillName.Discordance].Base;
|
||||
|
||||
switch(CastSkill)
|
||||
{
|
||||
default: return 0.0;
|
||||
case SkillName.Provocation:
|
||||
if (peac >= 100) bonus += 1 + ((peac - 100) / 10);
|
||||
if (disc >= 100) bonus += 1 + ((disc - 100) / 10);
|
||||
break;
|
||||
case SkillName.Peacemaking:
|
||||
if (prov >= 100) bonus += 1 + ((peac - 100) / 10);
|
||||
if (disc >= 100) bonus += 1 + ((disc - 100) / 10);
|
||||
break;
|
||||
case SkillName.Discordance:
|
||||
if (prov >= 100) bonus += 1 + ((peac - 100) / 10);
|
||||
if (peac >= 100) bonus += 1 + ((disc - 100) / 10);
|
||||
break;
|
||||
}
|
||||
|
||||
return bonus;
|
||||
}
|
||||
}
|
||||
|
||||
public override SkillName DamageSkill{ get{ return SkillName.Musicianship; } }
|
||||
|
||||
public override int UpkeepCancelMessage { get { return 1115665; } } // You do not have enough mana to continue infusing your song with magic.
|
||||
public override int OutOfRangeMessage { get { return 1115771; } } // Your target is no longer in range of your spellsong.
|
||||
public override int DisruptMessage { get { return 1115710; } } // Your spell song has been interrupted.
|
||||
|
||||
public BardSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, null, info )
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
int mana = ScaleMana(RequiredMana);
|
||||
|
||||
if (!base.CheckCast())
|
||||
return false;
|
||||
|
||||
m_Instrument = BaseInstrument.GetInstrument(Caster);
|
||||
|
||||
if (m_Instrument == null)
|
||||
{
|
||||
BaseInstrument.PickInstrument(Caster, new InstrumentPickedCallback(OnPickedInstrument));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnPickedInstrument(Mobile from, BaseInstrument instrument)
|
||||
{
|
||||
from.SendMessage("You choose a muscial instrument. Try using the bard mastery again.");
|
||||
}
|
||||
|
||||
public override bool CheckFizzle()
|
||||
{
|
||||
bool check = base.CheckFizzle();
|
||||
|
||||
if (check)
|
||||
{
|
||||
if (m_Instrument != null)
|
||||
{
|
||||
m_Instrument.PlayInstrumentWell(Caster);
|
||||
m_Instrument.ConsumeUse(Caster);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Caster.SendLocalizedMessage(500612); // You play poorly, and there is no effect.
|
||||
|
||||
if(m_Instrument != null)
|
||||
m_Instrument.PlayInstrumentBadly(Caster);
|
||||
}
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.FixedEffect( 0x37C4, 10, (int)( GetCastDelay().TotalSeconds * 28 ), 4, 3 );
|
||||
}
|
||||
|
||||
public override void GetCastSkills( out double min, out double max )
|
||||
{
|
||||
min = RequiredSkill;
|
||||
max = RequiredSkill + 25.0;
|
||||
}
|
||||
|
||||
public static int GetMasteryBonus(PlayerMobile pm, SkillName useSkill)
|
||||
{
|
||||
if (useSkill == pm.Skills.CurrentMastery)
|
||||
return 10;
|
||||
|
||||
if (pm.Skills.CurrentMastery == SkillName.Provocation
|
||||
|| pm.Skills.CurrentMastery == SkillName.Discordance
|
||||
|| pm.Skills.CurrentMastery == SkillName.Peacemaking)
|
||||
return 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual double GetSlayerBonus()
|
||||
{
|
||||
if (Target == null)
|
||||
return 1.0;
|
||||
|
||||
ISlayer slayer = Instrument as ISlayer;
|
||||
|
||||
if (slayer != null)
|
||||
{
|
||||
SlayerEntry se1 = SlayerGroup.GetEntryByName(slayer.Slayer);
|
||||
SlayerEntry se2 = SlayerGroup.GetEntryByName(slayer.Slayer2);
|
||||
|
||||
if ((se1 != null && se1.Slays(Target)) || (se2 != null && se2.Slays(Target)))
|
||||
{
|
||||
return SlayerBonus;
|
||||
}
|
||||
}
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
167
Scripts/Spells/Skill Masteries/BardSpells/Despair.cs
Normal file
167
Scripts/Spells/Skill Masteries/BardSpells/Despair.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Targeting;
|
||||
|
||||
/*Target Strength Reduced by up to 32, 20 – 60 Damage (Physical), every 2 seconds,
|
||||
affected by the target's magic resistance. (PvP and specific Mobs only).*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class DespairSpell : BardSpell
|
||||
{
|
||||
public static readonly string ModName = "Despair";
|
||||
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Despair", "Kal Des Mani Tym",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill{ get { return 90; } }
|
||||
public override double UpKeep { get { return 12; } }
|
||||
public override int RequiredMana{ get { return 26; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
public override SkillName CastSkill { get { return SkillName.Discordance; } }
|
||||
public override double SlayerBonus { get { return 3.0; } }
|
||||
|
||||
private int m_StatMod;
|
||||
private int m_Damage;
|
||||
private int m_Rounds;
|
||||
|
||||
public DespairSpell( Mobile caster, Item scroll ) : base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
BardSpell spell = SkillMasterySpell.GetSpell(Caster, this.GetType()) as BardSpell;
|
||||
|
||||
if(spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
Caster.SendLocalizedMessage(1115774); //You halt your spellsong.
|
||||
}
|
||||
else
|
||||
{
|
||||
Caster.Target = new InternalTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTarget( Mobile m )
|
||||
{
|
||||
if ( !Caster.CanSee( m ) )
|
||||
{
|
||||
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
|
||||
}
|
||||
else if (!m.Alive)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1115773); // Your target is dead.
|
||||
}
|
||||
else if (Caster == m)
|
||||
{
|
||||
// TODO: Message?
|
||||
}
|
||||
else if (BardSpell.HasHarmfulEffects(m, this.GetType()))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1115772); //Your target is already under the effect of this spellsong.
|
||||
}
|
||||
else if (CheckHSequence(m))
|
||||
{
|
||||
SpellHelper.Turn(Caster, m);
|
||||
|
||||
Target = m;
|
||||
//Caster.SendLocalizedMessage(1234567); //TODO: Message?
|
||||
|
||||
HarmfulSpell(m);
|
||||
|
||||
m.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist);
|
||||
|
||||
int rounds = 5 + (int)((double)BaseSkillBonus * .75);
|
||||
|
||||
m_StatMod = (int)((BaseSkillBonus * 2) + CollectiveBonus);
|
||||
m_Damage = (int)((BaseSkillBonus * 4.5) + (CollectiveBonus * 2));
|
||||
m_Rounds = 5 + (int)((BaseSkillBonus * .75) + (CollectiveBonus / 2));
|
||||
|
||||
string args = String.Format("{0}\t{1}", m_StatMod, m_Damage);
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.DespairTarget, 1115741, 1115743, args.ToString()));
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.DespairCaster, 1115741, 1115743, args.ToString()));
|
||||
|
||||
BeginTimer();
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Target, BuffIcon.DespairTarget);
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.DespairCaster);
|
||||
}
|
||||
|
||||
public override void AddStatMods()
|
||||
{
|
||||
int offset = m_StatMod;
|
||||
|
||||
if(Target != null)
|
||||
Target.AddStatMod(new StatMod(StatType.Str, ModName, offset, TimeSpan.Zero));
|
||||
}
|
||||
|
||||
public override void RemoveStatMods()
|
||||
{
|
||||
if(Target != null)
|
||||
Target.RemoveStatMod(ModName);
|
||||
}
|
||||
|
||||
public override bool OnTick()
|
||||
{
|
||||
bool tick = base.OnTick();
|
||||
|
||||
if (Target == null || !Caster.InRange(Target.Location, PartyRange))
|
||||
return false;
|
||||
|
||||
int damage = m_Damage;
|
||||
|
||||
if (!Target.Player)
|
||||
damage += AOS.Scale(damage, 50); // pvm = 1.5x
|
||||
|
||||
damage = (int)((double)damage * GetSlayerBonus()); // 3.0x slayer bonus
|
||||
damage -= (int)((double)damage * DamageModifier(Target)); // resist modifier
|
||||
|
||||
AOS.Damage(Target, Caster, damage, 100, 0, 0, 0, 0); // Now only does physical
|
||||
|
||||
if (Target != null && Target.Alive && Target.Map != null)
|
||||
Target.FixedEffect(0x376A, 1, 32);
|
||||
|
||||
if (m_Rounds-- == 0)
|
||||
{
|
||||
Expire();
|
||||
}
|
||||
|
||||
return tick;
|
||||
}
|
||||
|
||||
private class InternalTarget : Target
|
||||
{
|
||||
private DespairSpell m_Owner;
|
||||
|
||||
public InternalTarget(DespairSpell spell) : base(10, false, TargetFlags.Harmful)
|
||||
{
|
||||
m_Owner = spell;
|
||||
}
|
||||
|
||||
protected override void OnTarget( Mobile from, object o )
|
||||
{
|
||||
if ( o is Mobile )
|
||||
m_Owner.OnTarget( (Mobile)o );
|
||||
}
|
||||
|
||||
protected override void OnTargetFinish( Mobile from )
|
||||
{
|
||||
m_Owner.FinishSequence();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Scripts/Spells/Skill Masteries/BardSpells/Perseverance.cs
Normal file
110
Scripts/Spells/Skill Masteries/BardSpells/Perseverance.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
|
||||
/*Party Defense Chance increased by up to 22%, Damage reduced by up to 22%.
|
||||
Casting focus bonus 1-6%.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class PerseveranceSpell : BardSpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Perserverance", "Unus Jux Sanct",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill{ get { return 90; } }
|
||||
public override double UpKeep { get { return 5; } }
|
||||
public override int RequiredMana{ get { return 18; } }
|
||||
public override bool PartyEffects { get { return true; } }
|
||||
public override SkillName CastSkill { get { return SkillName.Peacemaking; } }
|
||||
|
||||
private int m_PropertyBonus;
|
||||
private int m_PropertyBonus2;
|
||||
private int m_DamageMod;
|
||||
|
||||
public PerseveranceSpell( Mobile caster, Item scroll ) : base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
BardSpell spell = SkillMasterySpell.GetSpell(Caster, this.GetType()) as BardSpell;
|
||||
|
||||
if(spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
Caster.SendLocalizedMessage(1115774); //You halt your spellsong.
|
||||
}
|
||||
else if ( CheckSequence() )
|
||||
{
|
||||
m_PropertyBonus = (int)((BaseSkillBonus * 3) + CollectiveBonus); // 2 - 24 (30)
|
||||
m_PropertyBonus2 = (int)((BaseSkillBonus / 2) + (CollectiveBonus / 3)); // 1 - 4 (6)
|
||||
m_DamageMod = (int)((BaseSkillBonus * 3) + CollectiveBonus); // 2 - 24 (30)
|
||||
|
||||
UpdateParty();
|
||||
BeginTimer();
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void AddPartyEffects(Mobile m)
|
||||
{
|
||||
m.FixedParticles(0x373A, 10, 15, 5018, EffectLayer.Waist);
|
||||
m.SendLocalizedMessage(1115739); // The bard's spellsong fills you with a feeling of invincibility.
|
||||
|
||||
string args = String.Format("{0}\t-{1}\t{2}", m_PropertyBonus, m_DamageMod, m_PropertyBonus2);
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Perseverance, 1115615, 1115732, args.ToString()));
|
||||
}
|
||||
|
||||
public override void RemovePartyEffects(Mobile m)
|
||||
{
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Perseverance);
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
if (PartyList != null)
|
||||
{
|
||||
foreach (Mobile m in PartyList) //Original Party list
|
||||
{
|
||||
RemovePartyEffects(m);
|
||||
}
|
||||
}
|
||||
|
||||
RemovePartyEffects(Caster);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defense Chance Bonus
|
||||
/// </summary>
|
||||
/// <returns>Defense Chance Bonus</returns>
|
||||
public override int PropertyBonus()
|
||||
{
|
||||
return m_PropertyBonus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casting Focus
|
||||
/// </summary>
|
||||
/// <returns>Casting Focus</returns>
|
||||
public override int PropertyBonus2()
|
||||
{
|
||||
return m_PropertyBonus2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// modifies total damage dealt
|
||||
/// </summary>
|
||||
/// <param name="damage"></param>
|
||||
public void AbsorbDamage(ref int damage)
|
||||
{
|
||||
damage -= AOS.Scale(damage, m_DamageMod);
|
||||
}
|
||||
}
|
||||
}
|
||||
103
Scripts/Spells/Skill Masteries/BardSpells/Resilience.cs
Normal file
103
Scripts/Spells/Skill Masteries/BardSpells/Resilience.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
|
||||
/*Poison resistance increase(not the stat), Mortal, Bleed, Curse effect Durations decreased,
|
||||
Hp regen bonus 2-11, mana regen bonus 2-11, stamina regen bonus 2-11.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class ResilienceSpell : BardSpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Resilience", "Kal Mani Tym",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill{ get { return 90; } }
|
||||
public override double UpKeep { get { return 4; } }
|
||||
public override int RequiredMana { get { return 16; } }
|
||||
public override bool PartyEffects { get { return true; } }
|
||||
public override SkillName CastSkill { get { return SkillName.Peacemaking; } }
|
||||
|
||||
private int m_PropertyBonus;
|
||||
|
||||
public ResilienceSpell( Mobile caster, Item scroll ) : base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
BardSpell spell = SkillMasterySpell.GetSpell(Caster, this.GetType()) as BardSpell;
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
Caster.SendLocalizedMessage(1115774); //You halt your spellsong.
|
||||
}
|
||||
else if (CheckSequence())
|
||||
{
|
||||
m_PropertyBonus = (int)((BaseSkillBonus * 2) + CollectiveBonus); // 2 - 16 (22)
|
||||
|
||||
UpdateParty();
|
||||
BeginTimer();
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void AddPartyEffects(Mobile m)
|
||||
{
|
||||
m.FixedParticles(0x373A, 10, 15, 5018, EffectLayer.Waist);
|
||||
m.SendLocalizedMessage(1115738); // The bard's spellsong fills you with a feeling of resilience.
|
||||
|
||||
string args = String.Format("{0}\t{1}\t{2}", m_PropertyBonus, m_PropertyBonus, m_PropertyBonus);
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Resilience, 1115614, 1115731, args.ToString()));
|
||||
|
||||
m.ResetStatTimers();
|
||||
}
|
||||
|
||||
public override void RemovePartyEffects(Mobile m)
|
||||
{
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Resilience);
|
||||
|
||||
m.ResetStatTimers();
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
if (PartyList != null)
|
||||
{
|
||||
foreach (Mobile m in PartyList) //Original Party list
|
||||
{
|
||||
RemovePartyEffects(m);
|
||||
}
|
||||
}
|
||||
|
||||
RemovePartyEffects(Caster);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called in AOS.cs - Regen bonus
|
||||
/// </summary>
|
||||
/// <returns>All 3 regen bonuses</returns>
|
||||
public override int PropertyBonus()
|
||||
{
|
||||
return m_PropertyBonus;
|
||||
}
|
||||
|
||||
/*Notes:
|
||||
* Poison Resist 25% flat rate in spell is active - TODO: Get OSI Rate???
|
||||
* Bleed, Mortal and Curse cuts time by 1/2
|
||||
* Reference PlayerMobile, BleedAttack, MortalStrike and CurseSpell
|
||||
*/
|
||||
|
||||
public static bool UnderEffects(Mobile m)
|
||||
{
|
||||
return SkillMasterySpell.UnderPartyEffects(m, typeof(ResilienceSpell));
|
||||
}
|
||||
}
|
||||
}
|
||||
168
Scripts/Spells/Skill Masteries/BardSpells/Tribulation.cs
Normal file
168
Scripts/Spells/Skill Masteries/BardSpells/Tribulation.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Targeting;
|
||||
using Server.Items;
|
||||
|
||||
/*Target Hit Chance reduced by up to 33%, Spell Damaged reduced by 33%, Damage
|
||||
Taken can trigger additional damage between 20-60% of the damage taken as
|
||||
physical once per second. (Discordance Based) (Chance to Trigger damage
|
||||
Musicianship Based) affected by the target's magic resistance. (PvP and
|
||||
specific Mobs only)*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class TribulationSpell : BardSpell
|
||||
{
|
||||
private DateTime m_NextDamage;
|
||||
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Tribulation", "In Jux Hur Rel",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill{ get { return 90; } }
|
||||
public override double UpKeep { get { return 10; } }
|
||||
public override int RequiredMana{ get { return 24; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
public override double TickTime { get { return 2.0; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Discordance; } }
|
||||
|
||||
private int m_PropertyBonus;
|
||||
private double m_DamageChance;
|
||||
private int m_DamageFactor;
|
||||
private int m_Rounds;
|
||||
|
||||
public TribulationSpell( Mobile caster, Item scroll ) : base(caster, scroll, m_Info)
|
||||
{
|
||||
m_NextDamage = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
BardSpell spell = SkillMasterySpell.GetSpell(Caster, this.GetType()) as BardSpell;
|
||||
|
||||
if(spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
Caster.SendLocalizedMessage(1115774); //You halt your spellsong.
|
||||
}
|
||||
else
|
||||
{
|
||||
Caster.Target = new InternalTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTarget( Mobile m )
|
||||
{
|
||||
if ( !Caster.CanSee( m ) )
|
||||
{
|
||||
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
|
||||
}
|
||||
else if (Caster == m)
|
||||
{
|
||||
Caster.SendMessage("You cannot target yourself!");
|
||||
}
|
||||
else if (BardSpell.HasHarmfulEffects(m, this.GetType()))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1115772); //Your target is already under the effect of this spellsong.
|
||||
}
|
||||
else if (CheckHSequence(m))
|
||||
{
|
||||
SpellHelper.Turn(Caster, m);
|
||||
|
||||
Target = m;
|
||||
|
||||
HarmfulSpell(m);
|
||||
|
||||
m.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist);
|
||||
|
||||
double cast = Caster.Skills[CastSkill].Value;
|
||||
double dam = Caster.Skills[DamageSkill].Value;
|
||||
|
||||
m_PropertyBonus = (int)((BaseSkillBonus * 2.75) + (CollectiveBonus * 1.667)); // 5 - 22 (32)
|
||||
m_DamageChance = (int)((BaseSkillBonus * 7.5) + (CollectiveBonus * 3)); // 15 - 60 (84)
|
||||
m_DamageFactor = (int)((BaseSkillBonus * 4) + (CollectiveBonus * 3)); // 8 - 32 (50)
|
||||
m_Rounds = 5 + (int)((BaseSkillBonus * .75) + (CollectiveBonus / 2)); // 5 - 11 (14)
|
||||
|
||||
// ~1_HCI~% Hit Chance.<br>~2_SDI~% Spell Damage.<br>Damage taken has a ~3_EXP~% chance to cause additional burst of physical damage.<br>
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.TribulationTarget, 1115740, 1115742, String.Format("{0}\t{1}\t{2}", m_PropertyBonus, m_PropertyBonus, (int)m_DamageChance)));
|
||||
|
||||
// Target: ~1_val~ <br> Damage Factor: ~2_val~% <br> Damage Chance: ~3_val~%
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.TribulationCaster, 1115740, 1151388, String.Format("{0}\t{1}\t{2}", m.Name, (int)m_DamageFactor, (int)m_DamageChance)));
|
||||
|
||||
BeginTimer();
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override bool OnTick()
|
||||
{
|
||||
if(Target != null && Target.Alive && Target.Map != null)
|
||||
Target.FixedEffect(0x376A, 1, 32);
|
||||
|
||||
if (m_Rounds-- <= 0)
|
||||
{
|
||||
Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.OnTick();
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Target, BuffIcon.TribulationTarget);
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.TribulationCaster);
|
||||
}
|
||||
|
||||
public override void OnTargetDamaged(Mobile attacker, Mobile victim, DamageType type, ref int damageTaken)
|
||||
{
|
||||
if(m_NextDamage > DateTime.UtcNow)
|
||||
return;
|
||||
|
||||
if (m_DamageChance / 100 > Utility.RandomDouble())
|
||||
{
|
||||
m_NextDamage = DateTime.UtcNow + TimeSpan.FromSeconds(1);
|
||||
|
||||
int damage = AOS.Scale(damageTaken, m_DamageFactor);
|
||||
damage = (int)((double)damage * GetSlayerBonus()); // 1.5 slayer bonus
|
||||
damage -= (int)((double)damage * DamageModifier(Target)); // resist modifier
|
||||
|
||||
AOS.Damage(victim, Caster, damage, 0, 0, 0, 0, 0, 0, 100);
|
||||
victim.FixedParticles(0x374A, 10, 15, 5038, 1181, 0, EffectLayer.Head);
|
||||
}
|
||||
}
|
||||
|
||||
public override int PropertyBonus()
|
||||
{
|
||||
return m_PropertyBonus;
|
||||
}
|
||||
|
||||
private class InternalTarget : Target
|
||||
{
|
||||
private TribulationSpell m_Owner;
|
||||
|
||||
public InternalTarget(TribulationSpell spell) : base(10, false, TargetFlags.Harmful)
|
||||
{
|
||||
m_Owner = spell;
|
||||
}
|
||||
|
||||
protected override void OnTarget( Mobile from, object o )
|
||||
{
|
||||
if ( o is Mobile )
|
||||
m_Owner.OnTarget( (Mobile)o );
|
||||
}
|
||||
|
||||
protected override void OnTargetFinish( Mobile from )
|
||||
{
|
||||
m_Owner.FinishSequence();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Scripts/Spells/Skill Masteries/BardSpells/inspire.cs
Normal file
106
Scripts/Spells/Skill Masteries/BardSpells/inspire.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
|
||||
/*Party Hit chance increase by up to 15%, Damage increase by up to 40%,
|
||||
SDI increased by up to 15% (PvP Cap 15)(Provocation Based)*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class InspireSpell : BardSpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Inspire", "Unus Por",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill{ get { return 90; } }
|
||||
public override double UpKeep { get { return 4; } }
|
||||
public override int RequiredMana{ get { return 16; } }
|
||||
public override SkillName CastSkill { get { return SkillName.Provocation; } }
|
||||
public override bool PartyEffects { get { return true; } }
|
||||
|
||||
private int m_PropertyBonus;
|
||||
private int m_DamageBonus;
|
||||
private int m_DamageModifier;
|
||||
|
||||
public InspireSpell( Mobile caster, Item scroll ) : base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
BardSpell spell = SkillMasterySpell.GetSpell(Caster, this.GetType()) as BardSpell;
|
||||
|
||||
if(spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
Caster.SendLocalizedMessage(1115774); //You halt your spellsong.
|
||||
}
|
||||
else if ( CheckSequence() )
|
||||
{
|
||||
m_PropertyBonus = (int)((BaseSkillBonus * 2) + CollectiveBonus);
|
||||
m_DamageBonus = (int)((BaseSkillBonus * 5) + (CollectiveBonus * 3));
|
||||
m_DamageModifier = (int)((BaseSkillBonus + 1) + CollectiveBonus);
|
||||
|
||||
UpdateParty();
|
||||
BeginTimer();
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void AddPartyEffects(Mobile m)
|
||||
{
|
||||
m.FixedParticles(0x373A, 10, 15, 5018, EffectLayer.Waist);
|
||||
m.SendLocalizedMessage(1115736); // You feel inspired by the bard's spellsong.
|
||||
|
||||
string args = String.Format("{0}\t{1}\t{2}\t{3}", m_PropertyBonus, m_PropertyBonus, m_DamageBonus, m_DamageModifier);
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Inspire, 1115683, 1151951, args.ToString()));
|
||||
}
|
||||
|
||||
public override void RemovePartyEffects(Mobile m)
|
||||
{
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Inspire);
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
if (PartyList != null)
|
||||
{
|
||||
foreach (Mobile m in PartyList) //Original Party list
|
||||
{
|
||||
RemovePartyEffects(m);
|
||||
}
|
||||
}
|
||||
|
||||
RemovePartyEffects(Caster);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called in AOS.cs - Hit Chance/Spell Damage Bonus
|
||||
/// </summary>
|
||||
/// <returns>HCI/SDI Bonus</returns>
|
||||
public override int PropertyBonus()
|
||||
{
|
||||
return m_PropertyBonus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called in AOS.cs - Weapon Damage Bonus
|
||||
/// </summary>
|
||||
/// <returns>DamInc Bonus</returns>
|
||||
public override int DamageBonus()
|
||||
{
|
||||
return m_DamageBonus;
|
||||
}
|
||||
|
||||
public void DoDamage(ref int damageTaken)
|
||||
{
|
||||
damageTaken += AOS.Scale(damageTaken, m_DamageModifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
153
Scripts/Spells/Skill Masteries/BardSpells/invigorate.cs
Normal file
153
Scripts/Spells/Skill Masteries/BardSpells/invigorate.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
/*Party Hit Points increased by up to 20 + 6(Collection Bonus), Party healed for 9-20 dmg every 4 seconds.
|
||||
(Provocation Based). Party Strength, Dex, Int, Increased by Up to 8.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class InvigorateSpell : BardSpell
|
||||
{
|
||||
public static readonly string StatModName = "Invigorate";
|
||||
|
||||
private DateTime m_NextHeal;
|
||||
private List<Mobile> m_Mods = new List<Mobile>();
|
||||
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Invigorate", "An Zu",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill{ get { return 90; } }
|
||||
public override double UpKeep { get { return 5; } }
|
||||
public override int RequiredMana{ get { return 22; } }
|
||||
public override bool PartyEffects { get { return true; } }
|
||||
public override SkillName CastSkill { get { return SkillName.Provocation; } }
|
||||
|
||||
private int m_HPBonus;
|
||||
private int m_StatBonus;
|
||||
|
||||
public InvigorateSpell( Mobile caster, Item scroll ) : base(caster, scroll, m_Info)
|
||||
{
|
||||
m_NextHeal = DateTime.UtcNow + TimeSpan.FromSeconds(4);
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
BardSpell spell = SkillMasterySpell.GetSpell(Caster, this.GetType()) as BardSpell;
|
||||
|
||||
if(spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
Caster.SendLocalizedMessage(1115774); //You halt your spellsong.
|
||||
}
|
||||
else if ( CheckSequence() )
|
||||
{
|
||||
m_StatBonus = (int)(BaseSkillBonus + CollectiveBonus);
|
||||
m_HPBonus = (int)((2.5 * BaseSkillBonus) + CollectiveBonus);
|
||||
|
||||
UpdateParty();
|
||||
BeginTimer();
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void AddPartyEffects(Mobile m)
|
||||
{
|
||||
m.FixedParticles(0x373A, 10, 15, 5018, EffectLayer.Waist);
|
||||
m.SendLocalizedMessage(1115737); // You feel invigorated by the bard's spellsong.
|
||||
|
||||
string args = String.Format("{0}\t{1}\t{2}\t{3}", m_HPBonus, m_StatBonus, m_StatBonus, m_StatBonus);
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Invigorate, 1115613, 1115730, args.ToString()));
|
||||
|
||||
m.AddStatMod(new StatMod(StatType.Str, StatModName + "str", m_StatBonus, TimeSpan.Zero));
|
||||
m.AddStatMod(new StatMod(StatType.Dex, StatModName + "dex", m_StatBonus, TimeSpan.Zero));
|
||||
m.AddStatMod(new StatMod(StatType.Int, StatModName + "int", m_StatBonus, TimeSpan.Zero));
|
||||
|
||||
m_Mods.Add(m);
|
||||
}
|
||||
|
||||
public override void RemovePartyEffects(Mobile m)
|
||||
{
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Invigorate);
|
||||
|
||||
if (m_Mods.Contains(m))
|
||||
{
|
||||
m.RemoveStatMod(StatModName + "str");
|
||||
m.RemoveStatMod(StatModName + "dex");
|
||||
m.RemoveStatMod(StatModName + "int");
|
||||
|
||||
m_Mods.Remove(m);
|
||||
}
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
if (PartyList != null)
|
||||
{
|
||||
foreach (Mobile m in PartyList) //Original Party list
|
||||
{
|
||||
RemovePartyEffects(m);
|
||||
}
|
||||
}
|
||||
|
||||
RemovePartyEffects(Caster);
|
||||
}
|
||||
|
||||
public override bool OnTick()
|
||||
{
|
||||
base.OnTick();
|
||||
|
||||
if(m_NextHeal > DateTime.UtcNow)
|
||||
return false;
|
||||
|
||||
PartyList.IterateReverse(m =>
|
||||
{
|
||||
if (CheckPartyEffects(m, true))
|
||||
{
|
||||
int healRange = (int)((BaseSkillBonus * 2) + CollectiveBonus ); // 4 - 16 (22)
|
||||
|
||||
if (m.Hits < m.HitsMax)
|
||||
{
|
||||
m.Heal(Utility.RandomMinMax(healRange - 2, healRange + 2));
|
||||
m.FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist);
|
||||
m.PlaySound(0x1F2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RemovePartyMember(m);
|
||||
}
|
||||
});
|
||||
|
||||
m_NextHeal = DateTime.UtcNow + TimeSpan.FromSeconds(4);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called in AOS.cs - HP Bonus
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int StatBonus()
|
||||
{
|
||||
return m_HPBonus;
|
||||
}
|
||||
|
||||
public static int GetHPBonus(Mobile m)
|
||||
{
|
||||
var spell = SkillMasterySpell.GetSpellForParty(m, typeof(InvigorateSpell));
|
||||
|
||||
if (spell != null)
|
||||
return spell.StatBonus();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
322
Scripts/Spells/Skill Masteries/BodyGuard.cs
Normal file
322
Scripts/Spells/Skill Masteries/BodyGuard.cs
Normal file
@@ -0,0 +1,322 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Gumps;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class BodyGuardSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Body Guard", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override int RequiredMana { get { return 40; } }
|
||||
public override int DisruptMessage { get { return 1156103; } } // Bodyguard has expired.
|
||||
public override bool BlocksMovement { get { return false; } }
|
||||
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(1.0); } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Parry; } }
|
||||
|
||||
private double _Block;
|
||||
|
||||
public BodyGuardSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (_Table != null && _Table.ContainsKey(Caster))
|
||||
{
|
||||
RemoveGumpTimer(_Table[Caster], Caster);
|
||||
return false;
|
||||
}
|
||||
|
||||
BodyGuardSpell spell = GetSpell(Caster, this.GetType()) as BodyGuardSpell;
|
||||
|
||||
if(spell != null)
|
||||
{
|
||||
spell.Expire(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HasShield())
|
||||
return false;
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (Caster is BaseCreature && ((BaseCreature)Caster).ControlMaster != null)
|
||||
{
|
||||
var master = ((BaseCreature)Caster).ControlMaster;
|
||||
|
||||
if (Caster.CanSee(master) && Caster.InRange(master.Location, 8))
|
||||
{
|
||||
SpellHelper.Turn(Caster, master);
|
||||
OnTarget(master);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Caster.BeginTarget(8, false, Server.Targeting.TargetFlags.None, (m, o) =>
|
||||
{
|
||||
if (!Caster.CanSee(o))
|
||||
{
|
||||
Caster.SendLocalizedMessage(500237); // Target can not be seen.
|
||||
}
|
||||
else
|
||||
{
|
||||
SpellHelper.Turn(Caster, o);
|
||||
OnTarget(o);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTarget(object o)
|
||||
{
|
||||
if (!HasShield())
|
||||
return;
|
||||
|
||||
Mobile protectee = o as Mobile;
|
||||
Mobile master = null;
|
||||
|
||||
if (protectee is BaseCreature && !((BaseCreature)protectee).Summoned && ((BaseCreature)protectee).GetMaster() is PlayerMobile)
|
||||
master = ((BaseCreature)protectee).GetMaster();
|
||||
|
||||
if (protectee != null)
|
||||
{
|
||||
BodyGuardSpell spell = GetSpell(s => s.GetType() == typeof(BodyGuardSpell) && s.Target == protectee) as BodyGuardSpell;
|
||||
|
||||
if(spell != null)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156094); // Your target is already under the effect of this ability.
|
||||
}
|
||||
if (!protectee.Alive)
|
||||
{
|
||||
Caster.SendLocalizedMessage( 501857 ); // This spell won't work on that!
|
||||
}
|
||||
else if ( !Caster.CanBeBeneficial( protectee, true ))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1001017); // You cannot perform beneficial acts on your target.
|
||||
}
|
||||
else if (protectee != Caster)
|
||||
{
|
||||
Mobile responsible = master != null ? master : protectee;
|
||||
|
||||
Caster.FixedParticles( 0x376A, 9, 32, 5030, 1168, 0, EffectLayer.Waist, 0 );
|
||||
|
||||
if (Caster.Player)
|
||||
{
|
||||
Caster.PlaySound(Caster.Female ? 0x338 : 0x44A);
|
||||
}
|
||||
else if (Caster is BaseCreature)
|
||||
{
|
||||
Caster.PlaySound(((BaseCreature)Caster).GetAngerSound());
|
||||
}
|
||||
|
||||
if (Caster is PlayerMobile)
|
||||
{
|
||||
protectee.SendGump(new AcceptBodyguardGump(Caster, protectee, this));
|
||||
AddGumpTimer(responsible, Caster);
|
||||
}
|
||||
else
|
||||
{
|
||||
AcceptBodyGuard(responsible);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AcceptBodyGuard(Mobile toGuard)
|
||||
{
|
||||
RemoveGumpTimer(toGuard, Caster);
|
||||
|
||||
if(CheckBSequence(toGuard))
|
||||
{
|
||||
_Block = ((Caster.Skills[CastSkill].Value + GetWeaponSkill() + (GetMasteryLevel() * 40)) / 3) / 2.4;
|
||||
Target = toGuard;
|
||||
|
||||
Expires = DateTime.UtcNow + TimeSpan.FromSeconds(90);
|
||||
BeginTimer();
|
||||
|
||||
Caster.SendLocalizedMessage(1049452, "\t" + toGuard.Name); // You are now protecting ~2_NAME~.
|
||||
toGuard.SendLocalizedMessage(1049451, Caster.Name); // You are now being protected by ~1_NAME~.
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Bodyguard, 1155924, 1156061, TimeSpan.FromSeconds(90), Caster, String.Format("{0}\t{1}\t{2}\t{3}", Caster.Name, ((int)(_Block + 5)).ToString(), toGuard.Name, ((int)_Block).ToString())));
|
||||
BuffInfo.AddBuff(toGuard, new BuffInfo(BuffIcon.Bodyguard, 1155924, 1156061, TimeSpan.FromSeconds(90), toGuard, String.Format("{0}\t{1}\t{2}\t{3}", Caster.Name, ((int)(_Block + 5)).ToString(), toGuard.Name, ((int)_Block).ToString())));
|
||||
//~1_NAME~ receives ~2_DAMAGE~% of all damage dealt to ~3_NAME~. All damage dealt to ~3_NAME~ will be reduced by ~4_DAMAGE~%. Body guard must be within 2 tiles.
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
private bool HasShield()
|
||||
{
|
||||
if (!Caster.Player)
|
||||
return true;
|
||||
|
||||
BaseShield shield = Caster.FindItemOnLayer(Layer.TwoHanded) as BaseShield;
|
||||
|
||||
if (shield == null)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156096); // You must be wielding a shield to use this ability!
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool OnTick()
|
||||
{
|
||||
if (!HasShield())
|
||||
{
|
||||
Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.OnTick();
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
if (Target != null)
|
||||
{
|
||||
Target.SendLocalizedMessage(1156103); // Bodyguard has expired.
|
||||
BuffInfo.RemoveBuff(Target, BuffIcon.Bodyguard);
|
||||
}
|
||||
|
||||
Caster.SendLocalizedMessage(1156103); // Bodyguard has expired.
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.Bodyguard);
|
||||
}
|
||||
|
||||
public void DeclineBodyGuard(Mobile protectee)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1049454, "\t" + protectee.Name); // ~2_NAME~ has declined your protection.
|
||||
protectee.SendLocalizedMessage(1049453, Caster.Name); // You have declined protection from ~1_NAME~.
|
||||
|
||||
RemoveGumpTimer(protectee, Caster);
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void OnTargetDamaged(Mobile attacker, Mobile defender, DamageType type, ref int damage)
|
||||
{
|
||||
if (defender == Target && Caster.InRange(defender, 2))
|
||||
{
|
||||
double mod = (double)PropertyBonus() / 100.0;
|
||||
|
||||
damage = damage - (int)((double)damage * mod);
|
||||
int casterDamage = damage - (int)((double)damage * (mod - .05));
|
||||
|
||||
if (type >= DamageType.Spell)
|
||||
casterDamage /= 2;
|
||||
|
||||
Caster.Damage(casterDamage, attacker);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveGumpTimer(Mobile m, Mobile caster)
|
||||
{
|
||||
if (_Table != null && _Table.ContainsKey(caster))
|
||||
_Table.Remove(caster);
|
||||
|
||||
if (m.HasGump(typeof(AcceptBodyguardGump)))
|
||||
{
|
||||
m.CloseGump(typeof(AcceptBodyguardGump));
|
||||
m.SendLocalizedMessage(1156103); // Bodyguard has expired.
|
||||
caster.SendLocalizedMessage(1156103); // Bodyguard has expired.
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddGumpTimer(Mobile m, Mobile caster)
|
||||
{
|
||||
if (_Table == null)
|
||||
_Table = new Dictionary<Mobile, Mobile>();
|
||||
|
||||
_Table[caster] = m;
|
||||
|
||||
Server.Timer.DelayCall(TimeSpan.FromSeconds(10), () =>
|
||||
{
|
||||
RemoveGumpTimer(m, caster);
|
||||
});
|
||||
}
|
||||
|
||||
private static Dictionary<Mobile, Mobile> _Table;
|
||||
|
||||
public override int PropertyBonus()
|
||||
{
|
||||
return (int)_Block;
|
||||
}
|
||||
}
|
||||
|
||||
public class AcceptBodyguardGump : Gump
|
||||
{
|
||||
private Mobile m_Protector;
|
||||
private Mobile m_Protectee;
|
||||
private BodyGuardSpell m_Spell;
|
||||
|
||||
public AcceptBodyguardGump( Mobile protector, Mobile protectee, BodyGuardSpell spell ) : base( 150, 50 )
|
||||
{
|
||||
m_Protector = protector;
|
||||
m_Protectee = protectee;
|
||||
m_Spell = spell;
|
||||
|
||||
Closable = false;
|
||||
|
||||
AddPage( 0 );
|
||||
|
||||
AddBackground( 0, 0, 396, 218, 3600 );
|
||||
|
||||
AddImageTiled( 15, 15, 365, 190, 2624 );
|
||||
AddAlphaRegion( 15, 15, 365, 190 );
|
||||
|
||||
AddHtmlLocalized( 30, 20, 360, 25, 1156099, 0x7FFF, false, false ); // Another player is offering to bodyguard you:
|
||||
AddLabel( 90, 55, 1153, String.Format("{0} will body guard {1}", protector.Name, protectee.Name));
|
||||
|
||||
AddImage( 50, 45, 9005 );
|
||||
AddImageTiled( 80, 80, 200, 1, 9107 );
|
||||
AddImageTiled( 95, 82, 200, 1, 9157 );
|
||||
|
||||
AddRadio( 30, 110, 9727, 9730, true, 1 );
|
||||
AddHtmlLocalized( 65, 115, 300, 25, 1049444, 0x7FFF, false, false ); // Yes, I would like their protection.
|
||||
|
||||
AddRadio( 30, 145, 9727, 9730, false, 0 );
|
||||
AddHtmlLocalized( 65, 148, 300, 25, 1049445, 0x7FFF, false, false ); // No thanks, I can take care of myself.
|
||||
|
||||
AddButton( 160, 175, 247, 248, 2, GumpButtonType.Reply, 0 );
|
||||
|
||||
AddImage( 215, 0, 50581 );
|
||||
|
||||
AddImageTiled( 15, 14, 365, 1, 9107 );
|
||||
AddImageTiled( 380, 14, 1, 190, 9105 );
|
||||
AddImageTiled( 15, 205, 365, 1, 9107 );
|
||||
AddImageTiled( 15, 14, 1, 190, 9105 );
|
||||
AddImageTiled( 0, 0, 395, 1, 9157 );
|
||||
AddImageTiled( 394, 0, 1, 217, 9155 );
|
||||
AddImageTiled( 0, 216, 395, 1, 9157 );
|
||||
AddImageTiled( 0, 0, 1, 217, 9155 );
|
||||
}
|
||||
|
||||
public override void OnResponse( Server.Network.NetState sender, RelayInfo info )
|
||||
{
|
||||
if ( info.ButtonID == 2 )
|
||||
{
|
||||
bool okay = info.IsSwitched( 1 );
|
||||
|
||||
if(okay)
|
||||
m_Spell.AcceptBodyGuard(m_Protectee);
|
||||
else
|
||||
m_Spell.DeclineBodyGuard(m_Protectee);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Scripts/Spells/Skill Masteries/CalledShot.cs
Normal file
110
Scripts/Spells/Skill Masteries/CalledShot.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class CalledShotSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Called Shot", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override double UpKeep { get { return 0; } }
|
||||
public override int RequiredMana { get { return 40; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Throwing; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Tactics; } }
|
||||
|
||||
private int _HCIBonus;
|
||||
private int _DamageBonus;
|
||||
|
||||
public CalledShotSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (IsInCooldown(Caster, this.GetType()))
|
||||
return false;
|
||||
|
||||
if (!CheckWeapon())
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156016); // You must have a throwing weapon equipped to use this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
CalledShotSpell spell = GetSpell(Caster, this.GetType()) as CalledShotSpell;
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.PlaySound(0x5AA);
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
Caster.PlaySound(0x101);
|
||||
Caster.FixedEffect(0x37C4, 10, 40, 2720, 3);
|
||||
|
||||
Caster.PrivateOverheadMessage(MessageType.Regular, 1150, 1156024, Caster.NetState); // *You call your next shot...*
|
||||
|
||||
TimeSpan duration = TimeSpan.FromSeconds(10);
|
||||
|
||||
_HCIBonus = (int)(Caster.Skills[DamageSkill].Value / 2.66);
|
||||
_DamageBonus = (int)(Caster.Skills[CastSkill].Value / 1.6);
|
||||
|
||||
Expires = DateTime.UtcNow + duration;
|
||||
BeginTimer();
|
||||
|
||||
AddToCooldown(TimeSpan.FromSeconds(60));
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.CalledShot, 1156025, 1156026, duration, Caster, String.Format("{0}\t{1}", _HCIBonus.ToString(), _DamageBonus.ToString())));
|
||||
//Hit Chance Increase: ~1_VAL~%<br>Damage Increase: ~2_VAL~%
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.CalledShot);
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile defender, ref int damage)
|
||||
{
|
||||
if (SpecialMove.GetCurrentMove(Caster) != null)
|
||||
return;
|
||||
|
||||
damage = damage + (int)((double)damage * ((double)_DamageBonus / 100.0));
|
||||
|
||||
if (defender is PlayerMobile && damage > 100)
|
||||
damage = 100;
|
||||
}
|
||||
|
||||
public static int GetHitChanceBonus(Mobile m)
|
||||
{
|
||||
CalledShotSpell spell = GetSpell(m, typeof(CalledShotSpell)) as CalledShotSpell;
|
||||
|
||||
if (spell != null)
|
||||
return spell._HCIBonus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
472
Scripts/Spells/Skill Masteries/CombatTraining.cs
Normal file
472
Scripts/Spells/Skill Masteries/CombatTraining.cs
Normal file
@@ -0,0 +1,472 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Gumps;
|
||||
using Server.Targeting;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public enum TrainingType
|
||||
{
|
||||
Empowerment,
|
||||
Berserk,
|
||||
ConsumeDamage,
|
||||
AsOne
|
||||
}
|
||||
|
||||
public class CombatTrainingSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Combat Training", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double UpKeep
|
||||
{
|
||||
get
|
||||
{
|
||||
double taming = Caster.Skills[CastSkill].Base;
|
||||
double lore = Caster.Skills[SkillName.AnimalLore].Base;
|
||||
bool asone = SpellType == TrainingType.AsOne;
|
||||
|
||||
double skillvalue = (taming + (lore/2));
|
||||
int mastery_base = 12;
|
||||
if (skillvalue < 150) mastery_base = 12;
|
||||
if (skillvalue < 165) mastery_base = 10;
|
||||
if (skillvalue < 180) mastery_base = 8;
|
||||
if (skillvalue >= 180) mastery_base = 6;
|
||||
|
||||
return asone ? mastery_base*2 : mastery_base;
|
||||
}
|
||||
}
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override int RequiredMana { get { return 40; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
public override SkillName CastSkill { get { return SkillName.AnimalTaming; } }
|
||||
|
||||
public TrainingType SpellType { get; set; }
|
||||
|
||||
private int _Phase;
|
||||
private int _DamageTaken;
|
||||
private bool _Expired;
|
||||
|
||||
public int Phase { get { return _Phase; } set { _Phase = value; } }
|
||||
public int DamageTaken { get { return _DamageTaken; } set { _DamageTaken = value; } }
|
||||
|
||||
public CombatTrainingSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Cast()
|
||||
{
|
||||
CombatTrainingSpell spell = GetSpell(Caster, typeof(CombatTrainingSpell)) as CombatTrainingSpell;
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.Cast();
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (Caster is PlayerMobile && ((PlayerMobile)Caster).AllFollowers == null || ((PlayerMobile)Caster).AllFollowers.Count == 0)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156112); // This ability requires you to have pets.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
base.SendCastEffect();
|
||||
|
||||
Caster.PrivateOverheadMessage(MessageType.Regular, 0x35, false, "You ready your pet for combat, increasing its battle effectiveness!", Caster.NetState);
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new InternalTarget(this);
|
||||
}
|
||||
|
||||
public void OnSelected(TrainingType type, Mobile target)
|
||||
{
|
||||
if (!CheckSequence() || (type == TrainingType.AsOne && Caster is PlayerMobile && ((PlayerMobile)Caster).AllFollowers.Where(mob => mob != target).Count() == 0))
|
||||
{
|
||||
FinishSequence();
|
||||
return;
|
||||
}
|
||||
|
||||
SpellType = type;
|
||||
Target = target;
|
||||
|
||||
_Phase = 0;
|
||||
|
||||
BeginTimer();
|
||||
|
||||
Target.FixedParticles(0x373A, 10, 80, 5018, 0, 0, EffectLayer.Waist);
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.CombatTraining, 1155933, 1156107, String.Format("{0}\t{1}\t{2}", SpellType.ToString(), Target.Name, ((int)ScaleUpkeep()).ToString())));
|
||||
//You train ~2_NAME~ to use ~1_SKILLNAME~.<br>Mana Upkeep: ~3_COST~
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.CombatTraining);
|
||||
Caster.SendSound(0x1ED);
|
||||
|
||||
_Expired = true;
|
||||
}
|
||||
|
||||
protected override void DoEffects()
|
||||
{
|
||||
Caster.FixedParticles(0x376A, 10, 30, 5052, 1261, 0, EffectLayer.LeftFoot, 0);
|
||||
Caster.DisruptiveAction();
|
||||
}
|
||||
|
||||
public override bool OnTick()
|
||||
{
|
||||
if (Target == null || Target.IsDeadBondedPet /* || Target.Map != Caster.Map*/)
|
||||
{
|
||||
Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.OnTick();
|
||||
}
|
||||
|
||||
public double DamageMod
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Target == null || SpellType == TrainingType.AsOne)
|
||||
return 0.0;
|
||||
|
||||
double dam = (double)_DamageTaken / ((double)Target.HitsMax * .66);
|
||||
|
||||
if (dam > 1.0) dam = 1.0;
|
||||
|
||||
return dam;
|
||||
}
|
||||
}
|
||||
|
||||
private void EndPhase1()
|
||||
{
|
||||
if (_Expired)
|
||||
return;
|
||||
|
||||
_Phase = 2;
|
||||
|
||||
Server.Timer.DelayCall(TimeSpan.FromSeconds(SpellType == TrainingType.Berserk ? 8 : 10), EndPhase2);
|
||||
}
|
||||
|
||||
private void EndPhase2()
|
||||
{
|
||||
if (_Expired)
|
||||
return;
|
||||
|
||||
_DamageTaken = 0;
|
||||
_Phase = 0;
|
||||
|
||||
if (SpellType == TrainingType.Berserk)
|
||||
{
|
||||
AddRageCooldown(Target);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CheckDamage(Mobile attacker, Mobile defender, DamageType type, ref int damage)
|
||||
{
|
||||
if (defender is BaseCreature && (((BaseCreature)defender).Controlled || ((BaseCreature)defender).Summoned))
|
||||
{
|
||||
CombatTrainingSpell spell = GetSpell<CombatTrainingSpell>(sp => sp.Target == defender);
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
int storedDamage = damage;
|
||||
|
||||
switch (spell.SpellType)
|
||||
{
|
||||
case TrainingType.Empowerment:
|
||||
break;
|
||||
case TrainingType.Berserk:
|
||||
if (InRageCooldown(defender))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (spell.Phase > 1)
|
||||
{
|
||||
damage = damage - (int)((double)damage * spell.DamageMod);
|
||||
defender.FixedParticles(0x376A, 10, 30, 5052, 1261, 7, EffectLayer.LeftFoot, 0);
|
||||
}
|
||||
break;
|
||||
case TrainingType.ConsumeDamage:
|
||||
if (spell.Phase < 2)
|
||||
{
|
||||
defender.SendDamagePacket(attacker, damage);
|
||||
damage = 0;
|
||||
}
|
||||
break;
|
||||
case TrainingType.AsOne:
|
||||
if (((BaseCreature)defender).GetMaster() is PlayerMobile)
|
||||
{
|
||||
var pm = ((BaseCreature)defender).GetMaster() as PlayerMobile;
|
||||
var list = pm.AllFollowers.Where(m => (m == defender || m.InRange(defender.Location, 3)) && m.CanBeHarmful(attacker)).ToList();
|
||||
|
||||
if (list.Count > 0)
|
||||
{
|
||||
damage = damage / list.Count;
|
||||
|
||||
foreach (var m in list.Where(mob => mob != defender))
|
||||
{
|
||||
m.Damage(damage, attacker, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
ColUtility.Free(list);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (spell.Phase < 2)
|
||||
{
|
||||
if (spell.Phase != 1)
|
||||
{
|
||||
spell.Phase = 1;
|
||||
|
||||
if (spell.SpellType != TrainingType.AsOne && (spell.SpellType != TrainingType.Berserk || !InRageCooldown(defender)))
|
||||
{
|
||||
Server.Timer.DelayCall(TimeSpan.FromSeconds(5), spell.EndPhase1);
|
||||
}
|
||||
}
|
||||
|
||||
if (spell.DamageTaken == 0)
|
||||
defender.FixedEffect(0x3779, 10, 30, 1743, 0);
|
||||
|
||||
spell.DamageTaken += storedDamage;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attacker is BaseCreature && (((BaseCreature)attacker).Controlled || ((BaseCreature)attacker).Summoned))
|
||||
{
|
||||
CombatTrainingSpell spell = GetSpell<CombatTrainingSpell>(sp => sp.Target == attacker);
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
switch (spell.SpellType)
|
||||
{
|
||||
case TrainingType.Empowerment:
|
||||
if (spell.Phase > 1)
|
||||
{
|
||||
damage = damage + (int)((double)damage * spell.DamageMod);
|
||||
attacker.FixedParticles(0x376A, 10, 30, 5052, 1261, 7, EffectLayer.LeftFoot, 0);
|
||||
}
|
||||
break;
|
||||
case TrainingType.Berserk:
|
||||
case TrainingType.ConsumeDamage:
|
||||
case TrainingType.AsOne:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnCreatureHit(Mobile attacker, Mobile defender, ref int damage)
|
||||
{
|
||||
if (attacker is BaseCreature && (((BaseCreature)attacker).Controlled || ((BaseCreature)attacker).Summoned))
|
||||
{
|
||||
CombatTrainingSpell spell = GetSpell<CombatTrainingSpell>(sp => sp.Target == attacker);
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
switch (spell.SpellType)
|
||||
{
|
||||
case TrainingType.Empowerment:
|
||||
break;
|
||||
case TrainingType.Berserk:
|
||||
if (spell.Phase > 1)
|
||||
{
|
||||
damage = damage + (int)((double)damage * spell.DamageMod);
|
||||
attacker.FixedParticles(0x376A, 10, 30, 5052, 1261, 7, EffectLayer.LeftFoot, 0);
|
||||
}
|
||||
break;
|
||||
case TrainingType.ConsumeDamage:
|
||||
case TrainingType.AsOne:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int RegenBonus(Mobile m)
|
||||
{
|
||||
if (m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned))
|
||||
{
|
||||
CombatTrainingSpell spell = GetSpell<CombatTrainingSpell>(sp => sp.Target == m);
|
||||
|
||||
if (spell != null && spell.SpellType == TrainingType.ConsumeDamage && spell.Phase > 1)
|
||||
{
|
||||
return (int)(30.0 * spell.DamageMod);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int GetHitChanceBonus(Mobile m)
|
||||
{
|
||||
if (m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned))
|
||||
{
|
||||
CombatTrainingSpell spell = GetSpell<CombatTrainingSpell>(sp => sp.Target == m);
|
||||
|
||||
if (spell != null && spell.SpellType == TrainingType.ConsumeDamage && spell.Phase > 1)
|
||||
{
|
||||
return (int)(45 * spell.DamageMod);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public class InternalTarget : Target
|
||||
{
|
||||
public CombatTrainingSpell Spell { get; set; }
|
||||
|
||||
public InternalTarget(CombatTrainingSpell spell)
|
||||
: base(8, false, TargetFlags.None)
|
||||
{
|
||||
Spell = spell;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (targeted is Server.Engines.Despise.DespiseCreature)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (targeted is BaseCreature && ((BaseCreature)targeted).GetMaster() == from && from.Spell == Spell)
|
||||
{
|
||||
Spell.Caster.FixedEffect(0x3779, 10, 20, 1270, 0);
|
||||
Spell.Caster.SendSound(0x64E);
|
||||
|
||||
int taming = (int)from.Skills[SkillName.AnimalTaming].Value;
|
||||
int lore = (int)from.Skills[SkillName.AnimalLore].Value;
|
||||
|
||||
from.CheckTargetSkill(SkillName.AnimalTaming, (BaseCreature)targeted, taming - 25, taming + 25);
|
||||
from.CheckTargetSkill(SkillName.AnimalLore, (BaseCreature)targeted, lore - 25, lore + 25);
|
||||
|
||||
from.CloseGump(typeof(ChooseTrainingGump));
|
||||
from.SendGump(new ChooseTrainingGump(from, (BaseCreature)targeted, Spell));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
|
||||
{
|
||||
from.SendLocalizedMessage(1156110); // Your ability was canceled.
|
||||
Spell.FinishSequence();
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddRageCooldown(Mobile m)
|
||||
{
|
||||
if (_RageCooldown == null)
|
||||
_RageCooldown = new Dictionary<Mobile, Timer>();
|
||||
|
||||
_RageCooldown[m] = Server.Timer.DelayCall<Mobile>(TimeSpan.FromSeconds(60), EndRageCooldown, m);
|
||||
}
|
||||
|
||||
public static bool InRageCooldown(Mobile m)
|
||||
{
|
||||
return _RageCooldown != null && _RageCooldown.ContainsKey(m);
|
||||
}
|
||||
|
||||
public static void EndRageCooldown(Mobile m)
|
||||
{
|
||||
if (_RageCooldown != null && _RageCooldown.ContainsKey(m))
|
||||
{
|
||||
_RageCooldown.Remove(m);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<Mobile, Timer> _RageCooldown;
|
||||
}
|
||||
|
||||
public class ChooseTrainingGump : Gump
|
||||
{
|
||||
public CombatTrainingSpell Spell { get; private set; }
|
||||
public Mobile Caster { get; private set; }
|
||||
public BaseCreature Target { get; private set; }
|
||||
|
||||
public const int Hue = 0x07FF;
|
||||
|
||||
public ChooseTrainingGump(Mobile caster, BaseCreature target, CombatTrainingSpell spell) : base(100, 100)
|
||||
{
|
||||
Spell = spell;
|
||||
Caster = caster;
|
||||
Target = target;
|
||||
|
||||
AddBackground(0, 0, 260, 187, 3600);
|
||||
AddAlphaRegion(10, 10, 240, 167);
|
||||
|
||||
AddImageTiled(220, 15, 30, 162, 10464);
|
||||
|
||||
AddHtmlLocalized(20, 20, 150, 16, 1156113, Hue, false, false); // Select Training
|
||||
|
||||
int y = 40;
|
||||
if (MasteryInfo.HasLearned(caster, SkillName.AnimalTaming, 1))
|
||||
{
|
||||
AddButton(20, y, 9762, 9763, 1, GumpButtonType.Reply, 0);
|
||||
AddHtmlLocalized(43, y, 150, 16, 1156109, Hue, false, false); // Empowerment
|
||||
y += 20;
|
||||
}
|
||||
|
||||
if (MasteryInfo.HasLearned(caster, SkillName.AnimalTaming, 2))
|
||||
{
|
||||
AddButton(20, y, 9762, 9763, 2, GumpButtonType.Reply, 0);
|
||||
AddHtmlLocalized(43, y, 150, 16, 1153271, Hue, false, false); // Berserk
|
||||
y += 20;
|
||||
}
|
||||
|
||||
if (MasteryInfo.HasLearned(caster, SkillName.AnimalTaming, 3))
|
||||
{
|
||||
AddButton(20, y, 9762, 9763, 3, GumpButtonType.Reply, 0);
|
||||
AddHtmlLocalized(43, y, 150, 16, 1156108, Hue, false, false); // Consume Damage
|
||||
y += 20;
|
||||
}
|
||||
|
||||
if (MasteryInfo.HasLearned(caster, SkillName.AnimalTaming, 1))
|
||||
{
|
||||
AddButton(20, y, 9762, 9763, 4, GumpButtonType.Reply, 0);
|
||||
AddHtmlLocalized(43, y, 150, 16, 1157544, Hue, false, false); // As One
|
||||
y += 20;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState state, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID == 0)
|
||||
{
|
||||
Spell.FinishSequence();
|
||||
state.Mobile.SendLocalizedMessage(1156110); // Your ability was canceled.
|
||||
return;
|
||||
}
|
||||
|
||||
Spell.OnSelected((TrainingType)info.ButtonID - 1, Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
160
Scripts/Spells/Skill Masteries/CommandUndead.cs
Normal file
160
Scripts/Spells/Skill Masteries/CommandUndead.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class CommandUndeadSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Command Undead", "In Corp Xen Por",
|
||||
204,
|
||||
9061,
|
||||
Reagent.DaemonBlood,
|
||||
Reagent.PigIron,
|
||||
Reagent.BatWing
|
||||
);
|
||||
|
||||
public override double RequiredSkill{ get { return 90; } }
|
||||
public override double UpKeep { get { return 0; } }
|
||||
public override int RequiredMana{ get { return 40; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Necromancy; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.SpiritSpeak; } }
|
||||
|
||||
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(3.0); } }
|
||||
|
||||
public CommandUndeadSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new MasteryTarget(this);
|
||||
}
|
||||
|
||||
protected override void OnTarget(object o)
|
||||
{
|
||||
BaseCreature bc = o as BaseCreature;
|
||||
|
||||
if (bc == null || !Caster.CanSee(bc.Location) || !Caster.InLOS(bc))
|
||||
{
|
||||
Caster.SendLocalizedMessage(500237); // Target can not be seen.
|
||||
}
|
||||
else if (ValidateTarget(bc))
|
||||
{
|
||||
if (Caster.Followers + 2 > Caster.FollowersMax)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1049607); // You have too many followers to control that creature.
|
||||
}
|
||||
else if (bc.Controlled || bc.Summoned)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156015); // You cannot command that!
|
||||
}
|
||||
else if (CheckSequence())
|
||||
{
|
||||
double difficulty = Items.BaseInstrument.GetBaseDifficulty(bc);
|
||||
double skill = ((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 2) + (GetMasteryLevel() * 3) + 1;
|
||||
|
||||
double chance = (skill - (difficulty - 25)) / ((difficulty + 25) - (difficulty - 25));
|
||||
|
||||
if (chance >= Utility.RandomDouble())
|
||||
{
|
||||
bc.ControlSlots = 2;
|
||||
bc.Combatant = null;
|
||||
|
||||
if (Caster.Combatant == bc)
|
||||
{
|
||||
Caster.Combatant = null;
|
||||
Caster.Warmode = false;
|
||||
}
|
||||
|
||||
if (bc.SetControlMaster(Caster))
|
||||
{
|
||||
bc.PlaySound(0x5C4);
|
||||
bc.Allured = true;
|
||||
|
||||
Container pack = bc.Backpack;
|
||||
|
||||
if (pack != null)
|
||||
{
|
||||
for (int i = pack.Items.Count - 1; i >= 0; --i)
|
||||
{
|
||||
if (i >= pack.Items.Count)
|
||||
continue;
|
||||
|
||||
pack.Items[i].Delete();
|
||||
}
|
||||
}
|
||||
|
||||
if (bc is SkeletalDragon)
|
||||
{
|
||||
Server.Engines.Quests.Doom.BellOfTheDead.TryRemoveDragon((SkeletalDragon)bc);
|
||||
}
|
||||
|
||||
Caster.PlaySound(0x5C4);
|
||||
Caster.SendLocalizedMessage(1156013); // You command the undead to follow and protect you.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156014); // The undead becomes enraged by your command attempt and attacks you.
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Caster.SendLocalizedMessage(1156015); // You cannot command that!
|
||||
|
||||
//FinishSequence();
|
||||
}
|
||||
|
||||
public static Type[] CommandTypes { get { return _CommandTypes; } }
|
||||
public static Type[] NoCommandTypes { get { return _NoCommandTypes; } }
|
||||
|
||||
private static Type[] _CommandTypes =
|
||||
{
|
||||
typeof(SkeletalDragon)
|
||||
};
|
||||
|
||||
private static Type[] _NoCommandTypes =
|
||||
{
|
||||
|
||||
typeof(UnfrozenMummy),
|
||||
typeof(RedDeath),
|
||||
typeof(SirPatrick),
|
||||
typeof(LadyJennifyr),
|
||||
typeof(MasterMikael),
|
||||
typeof(MasterJonath),
|
||||
typeof(LadyMarai),
|
||||
typeof(Niporailem),
|
||||
typeof(PestilentBandage),
|
||||
};
|
||||
|
||||
public static bool ValidateTarget(BaseCreature bc)
|
||||
{
|
||||
if (bc is BaseRenowned || bc is BaseChampion || bc is Server.Engines.Shadowguard.ShadowguardBoss)
|
||||
return false;
|
||||
|
||||
foreach (var t in _CommandTypes)
|
||||
{
|
||||
if (t == bc.GetType())
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var t in _NoCommandTypes)
|
||||
{
|
||||
if (t == bc.GetType())
|
||||
return false;
|
||||
}
|
||||
|
||||
SlayerEntry entry = SlayerGroup.GetEntryByName(SlayerName.Silver);
|
||||
|
||||
return entry != null && entry.Slays(bc);
|
||||
}
|
||||
}
|
||||
}
|
||||
171
Scripts/Spells/Skill Masteries/Conduit.cs
Normal file
171
Scripts/Spells/Skill Masteries/Conduit.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class ConduitSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Conduit", "Uus Corp Grav",
|
||||
204,
|
||||
9061,
|
||||
Reagent.NoxCrystal,
|
||||
Reagent.BatWing,
|
||||
Reagent.GraveDust
|
||||
);
|
||||
|
||||
public override double RequiredSkill{ get { return 90; } }
|
||||
public override double UpKeep { get { return 0; } }
|
||||
public override int RequiredMana{ get { return 40; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Necromancy; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.SpiritSpeak; } }
|
||||
|
||||
public int Strength { get; set; }
|
||||
public List<Item> Skulls { get; set; }
|
||||
public Rectangle2D Zone { get; set; }
|
||||
|
||||
public ConduitSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnBeginCast()
|
||||
{
|
||||
base.OnBeginCast();
|
||||
|
||||
Effects.SendLocationParticles(EffectItem.Create(Caster.Location, Caster.Map, EffectItem.DefaultDuration), 0x36CB, 1, 14, 0x55C, 7, 9915, 0);
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new MasteryTarget(this, 10, true, Server.Targeting.TargetFlags.None);
|
||||
}
|
||||
|
||||
protected override void OnTarget(object o)
|
||||
{
|
||||
IPoint3D p = o as IPoint3D;
|
||||
|
||||
if (p != null && CheckSequence())
|
||||
{
|
||||
Rectangle2D rec = new Rectangle2D(p.X - 3, p.Y - 3, 6, 6);
|
||||
Skulls = new List<Item>();
|
||||
|
||||
Item skull = new InternalItem();
|
||||
skull.MoveToWorld(new Point3D(rec.X, rec.Y, Caster.Map.GetAverageZ(rec.X, rec.Y)), Caster.Map);
|
||||
Skulls.Add(skull);
|
||||
|
||||
skull = new InternalItem();
|
||||
skull.MoveToWorld(new Point3D(rec.X + rec.Width, rec.Y + rec.Height, Caster.Map.GetAverageZ(rec.X + rec.Width, rec.Y + rec.Height)), Caster.Map);
|
||||
Skulls.Add(skull);
|
||||
|
||||
skull = new InternalItem();
|
||||
skull.MoveToWorld(new Point3D(rec.X + rec.Width, rec.Y, Caster.Map.GetAverageZ(rec.X + rec.Width, rec.Y)), Caster.Map);
|
||||
Skulls.Add(skull);
|
||||
|
||||
skull = new InternalItem();
|
||||
skull.MoveToWorld(new Point3D(rec.X, rec.Y + rec.Height, Caster.Map.GetAverageZ(rec.X, rec.Y + rec.Height)), Caster.Map);
|
||||
Skulls.Add(skull);
|
||||
|
||||
skull = new InternalItem();
|
||||
skull.MoveToWorld(new Point3D(rec.X + (rec.Width / 2), rec.Y + (rec.Height / 2), Caster.Map.GetAverageZ(rec.X + (rec.Width / 2), rec.Y + (rec.Height / 2))), Caster.Map);
|
||||
Skulls.Add(skull);
|
||||
|
||||
Zone = rec;
|
||||
Strength = (int)((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value + (GetMasteryLevel() * 20)) / 3.75);
|
||||
Expires = DateTime.UtcNow + TimeSpan.FromSeconds(Core.TOL ? 6 : 4 + (Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 36);
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Conduit, 1155901, 1156053, Strength.ToString())); //Targeted Necromancy spells used on a target within the Conduit field will affect all valid targets within the field at ~1_PERCT~% strength.
|
||||
|
||||
BeginTimer();
|
||||
}
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
ColUtility.ForEach(Skulls.Where(i => i != null && !i.Deleted), i => i.Delete());
|
||||
ColUtility.Free(Skulls);
|
||||
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.Conduit);
|
||||
}
|
||||
|
||||
public static bool CheckAffected(Mobile caster, IDamageable victim, Action<Mobile, double> callback)
|
||||
{
|
||||
if (victim == null || victim.Map == null)
|
||||
return false;
|
||||
|
||||
foreach (SkillMasterySpell spell in EnumerateSpells(caster, typeof(ConduitSpell)))
|
||||
{
|
||||
ConduitSpell conduit = spell as ConduitSpell;
|
||||
|
||||
if (conduit == null)
|
||||
continue;
|
||||
|
||||
if (conduit.Zone.Contains(victim))
|
||||
{
|
||||
IPooledEnumerable eable = victim.Map.GetMobilesInBounds(conduit.Zone);
|
||||
List<Mobile> toAffect = null;
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m != victim && conduit.Caster.CanBeHarmful(m))
|
||||
{
|
||||
if (toAffect == null)
|
||||
toAffect = new List<Mobile>();
|
||||
|
||||
toAffect.Add(m);
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
if (toAffect != null && callback != null)
|
||||
{
|
||||
toAffect.ForEach(m => callback(m, (double)conduit.Strength / 100.0));
|
||||
ColUtility.Free(toAffect);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private class InternalItem : Item
|
||||
{
|
||||
public InternalItem()
|
||||
: base(Utility.RandomList(0x1853, 0x1858))
|
||||
{
|
||||
}
|
||||
|
||||
public InternalItem(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
651
Scripts/Spells/Skill Masteries/Core/MasteryInfo.cs
Normal file
651
Scripts/Spells/Skill Masteries/Core/MasteryInfo.cs
Normal file
@@ -0,0 +1,651 @@
|
||||
using Server;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using System.Linq;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public enum Volume
|
||||
{
|
||||
None,
|
||||
One,
|
||||
Two,
|
||||
Three
|
||||
}
|
||||
|
||||
public enum PassiveSpell
|
||||
{
|
||||
None,
|
||||
EnchantedSummoning,
|
||||
Intuition,
|
||||
SavingThrow,
|
||||
Potency,
|
||||
Knockout,
|
||||
Boarding,
|
||||
AnticipateHit
|
||||
}
|
||||
|
||||
public class MasteryInfo
|
||||
{
|
||||
public static readonly int MinSkillRequirement = 90;
|
||||
|
||||
public static void Configure()
|
||||
{
|
||||
Infos = new List<MasteryInfo>();
|
||||
|
||||
EventSink.Login += new LoginEventHandler(OnLogin);
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.InspireSpell), 700, SkillName.Provocation));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.InvigorateSpell), 701, SkillName.Provocation));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.ResilienceSpell), 702, SkillName.Peacemaking));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.PerseveranceSpell), 703, SkillName.Peacemaking));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.TribulationSpell), 704, SkillName.Discordance));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.DespairSpell), 705, SkillName.Discordance));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.DeathRaySpell), 706, SkillName.Magery));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.EtherealBurstSpell), 707, SkillName.Magery));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.NetherBlastSpell), 708, SkillName.Mysticism));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.MysticWeaponSpell), 709, SkillName.Mysticism));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.CommandUndeadSpell), 710, SkillName.Necromancy));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.ConduitSpell), 711, SkillName.Necromancy));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.ManaShieldSpell), 712, SkillName.Spellweaving));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.SummonReaperSpell), 713, SkillName.Spellweaving));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.WarcrySpell), 716, SkillName.Bushido));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.RejuvinateSpell), 718, SkillName.Chivalry));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.HolyFistSpell), 719, SkillName.Chivalry));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.ShadowSpell), 720, SkillName.Ninjitsu));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.WhiteTigerFormSpell), 721, SkillName.Ninjitsu));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.FlamingShotSpell), 722, SkillName.Archery));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.PlayingTheOddsSpell), 723, SkillName.Archery));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.ThrustSpell), 724, SkillName.Fencing));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.PierceSpell), 725, SkillName.Fencing));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.StaggerSpell), 726, SkillName.Macing));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.ToughnessSpell), 727, SkillName.Macing));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.OnslaughtSpell), 728, SkillName.Swords));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.FocusedEyeSpell), 729, SkillName.Swords));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.ElementalFurySpell), 730, SkillName.Throwing));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.CalledShotSpell), 731, SkillName.Throwing));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.ShieldBashSpell), 733, SkillName.Parry));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.BodyGuardSpell), 734, SkillName.Parry));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.HeightenedSensesSpell), 735, SkillName.Parry));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.ToleranceSpell), 736, SkillName.Poisoning));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.InjectedStrikeSpell), 737, SkillName.Poisoning));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.RampageSpell), 739, SkillName.Wrestling));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.FistsOfFurySpell), 740, SkillName.Wrestling));
|
||||
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.WhisperingSpell), 742, SkillName.AnimalTaming));
|
||||
Infos.Add(new MasteryInfo(typeof(SkillMasteries.CombatTrainingSpell), 743, SkillName.AnimalTaming));
|
||||
|
||||
//Passive Masteries
|
||||
Infos.Add(new MasteryInfo(null, 714, SkillName.Magery, PassiveSpell.EnchantedSummoning)); // Enchanted Summoning
|
||||
Infos.Add(new MasteryInfo(null, 714, SkillName.Necromancy, PassiveSpell.EnchantedSummoning)); // Enchanted Summoning
|
||||
Infos.Add(new MasteryInfo(null, 714, SkillName.Spellweaving, PassiveSpell.EnchantedSummoning)); // Enchanted Summoning
|
||||
Infos.Add(new MasteryInfo(null, 714, SkillName.Mysticism, PassiveSpell.EnchantedSummoning)); // Enchanted Summoning
|
||||
|
||||
Infos.Add(new MasteryInfo(null, 715, SkillName.Bushido, PassiveSpell.AnticipateHit)); // Anticipate Hit
|
||||
|
||||
Infos.Add(new MasteryInfo(null, 717, SkillName.Bushido, PassiveSpell.Intuition)); // Intuition
|
||||
Infos.Add(new MasteryInfo(null, 717, SkillName.Ninjitsu, PassiveSpell.Intuition)); // Intuition
|
||||
Infos.Add(new MasteryInfo(null, 717, SkillName.Chivalry, PassiveSpell.Intuition)); // Intuition
|
||||
|
||||
Infos.Add(new MasteryInfo(null, 732, SkillName.Archery, PassiveSpell.SavingThrow)); // Saving Throw
|
||||
Infos.Add(new MasteryInfo(null, 732, SkillName.Fencing, PassiveSpell.SavingThrow)); // Saving Throw
|
||||
Infos.Add(new MasteryInfo(null, 732, SkillName.Swords, PassiveSpell.SavingThrow)); // Saving Throw
|
||||
Infos.Add(new MasteryInfo(null, 732, SkillName.Macing, PassiveSpell.SavingThrow)); // Saving Throw
|
||||
Infos.Add(new MasteryInfo(null, 732, SkillName.Throwing, PassiveSpell.SavingThrow)); // Saving Throw
|
||||
|
||||
Infos.Add(new MasteryInfo(null, 738, SkillName.Poisoning, PassiveSpell.Potency)); // Potency
|
||||
Infos.Add(new MasteryInfo(null, 741, SkillName.Wrestling, PassiveSpell.Knockout)); // Knockout
|
||||
Infos.Add(new MasteryInfo(null, 744, SkillName.AnimalTaming, PassiveSpell.Boarding)); // Boarding
|
||||
}
|
||||
|
||||
public static List<MasteryInfo> Infos { get; set; }
|
||||
|
||||
public Type SpellType { get; set; }
|
||||
public int SpellID { get; set; }
|
||||
public SkillName MasterySkill { get; set; }
|
||||
public int NameLocalization { get; set; }
|
||||
|
||||
public bool Passive { get { return PassiveSpell != PassiveSpell.None; } }
|
||||
public PassiveSpell PassiveSpell { get; set; }
|
||||
|
||||
public MasteryInfo(Type skillType, int spellID, SkillName masterySkill, PassiveSpell passive = PassiveSpell.None)
|
||||
{
|
||||
SpellType = skillType;
|
||||
SpellID = spellID;
|
||||
|
||||
MasterySkill = masterySkill;
|
||||
PassiveSpell = passive;
|
||||
|
||||
NameLocalization = GetLocalization(masterySkill);
|
||||
}
|
||||
|
||||
public static MasteryInfo GetInfo(Type spell, SkillName skill)
|
||||
{
|
||||
return Infos.FirstOrDefault(info => info.SpellType == spell && info.MasterySkill == skill);
|
||||
}
|
||||
|
||||
public static MasteryInfo GetInfo(int spellID)
|
||||
{
|
||||
return Infos.FirstOrDefault(info => info.SpellID == spellID);
|
||||
}
|
||||
|
||||
public static MasteryInfo GetInfo(int spellID, SkillName name)
|
||||
{
|
||||
return Infos.FirstOrDefault(info => info.SpellID == spellID && info.MasterySkill == name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obsolete, used to serialize old types
|
||||
/// </summary>
|
||||
/// <param name="spellID"></param>
|
||||
/// <param name="skill"></param>
|
||||
/// <returns></returns>
|
||||
public static int GetVolume(int spellID, SkillName skill)
|
||||
{
|
||||
if (IsPassiveMastery(spellID) || spellID == 733)
|
||||
return 1;
|
||||
else if (spellID <= 715)
|
||||
{
|
||||
if (spellID % 2 == 0)
|
||||
return 3;
|
||||
|
||||
return 2;
|
||||
}
|
||||
else if (spellID <= 731 || (spellID >= 736 && spellID <= 743))
|
||||
{
|
||||
if (spellID % 2 == 0)
|
||||
return 2;
|
||||
|
||||
return 3;
|
||||
}
|
||||
else if (spellID == 734)
|
||||
return 2;
|
||||
else if (spellID == 735)
|
||||
return 3;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static SkillName GetSkillForID(int spellID)
|
||||
{
|
||||
MasteryInfo info = GetInfo(spellID);
|
||||
|
||||
if (info != null)
|
||||
return info.MasterySkill;
|
||||
|
||||
return SkillName.Archery;
|
||||
}
|
||||
|
||||
public static bool HasLearned(Mobile m, SkillName skill)
|
||||
{
|
||||
return m.Skills[skill].HasLearnedMastery();
|
||||
}
|
||||
|
||||
public static bool HasLearned(Mobile m, SkillName skill, int volume)
|
||||
{
|
||||
return m.Skills[skill].HasLearnedVolume(volume);
|
||||
}
|
||||
|
||||
public static bool HasLearned(Mobile m, Type spell, SkillName skill)
|
||||
{
|
||||
MasteryInfo info = GetInfo(spell, skill);
|
||||
|
||||
return info != null && m.Skills[info.MasterySkill].HasLearnedMastery();
|
||||
}
|
||||
|
||||
public static int GetMasteryLevel(Mobile m, SkillName name)
|
||||
{
|
||||
return m.Skills[name].VolumeLearned;
|
||||
}
|
||||
|
||||
public static bool CanLearn(Mobile m, int spellID, SkillName skill)
|
||||
{
|
||||
MasteryInfo info = GetInfo(spellID, skill);
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
return m.Skills[info.MasterySkill].Base >= MinSkillRequirement;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool LearnMastery(Mobile m, SkillName skill, int volume)
|
||||
{
|
||||
if (GetMasteryLevel(m, skill) < volume)
|
||||
{
|
||||
m.Skills[skill].LearnMastery((int)volume);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsPassiveMastery(int spellID)
|
||||
{
|
||||
return spellID == 714 || spellID == 715 || spellID == 716 || spellID == 732 || spellID == 738 || spellID == 741 || spellID == 744;
|
||||
}
|
||||
|
||||
public static void OnMasteryChanged(Mobile m, SkillName oldMastery)
|
||||
{
|
||||
PassiveSpell passive = GetActivePassive(m);
|
||||
SkillName newMastery = m.Skills.CurrentMastery;
|
||||
|
||||
if (oldMastery != newMastery)
|
||||
{
|
||||
List<SkillMasterySpell> list = SkillMasterySpell.GetSpells(m);
|
||||
|
||||
if (list != null)
|
||||
{
|
||||
list.ForEach(spell =>
|
||||
{
|
||||
spell.Expire();
|
||||
});
|
||||
|
||||
ColUtility.Free(list);
|
||||
}
|
||||
|
||||
if (m is PlayerMobile && oldMastery == SkillName.Necromancy)
|
||||
{
|
||||
((PlayerMobile)m).AllFollowers.IterateReverse(mob =>
|
||||
{
|
||||
if (mob is BaseCreature && CommandUndeadSpell.ValidateTarget((BaseCreature)mob))
|
||||
{
|
||||
((BaseCreature)mob).SetControlMaster(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SpecialMove move = SpecialMove.GetCurrentMove(m);
|
||||
|
||||
if(move is SkillMasteryMove)
|
||||
SpecialMove.ClearCurrentMove(m);
|
||||
|
||||
m.RemoveStatMod("SavingThrow_Str");
|
||||
|
||||
ColUtility.Free(list);
|
||||
RemovePassiveBuffs(m);
|
||||
}
|
||||
|
||||
if (passive != PassiveSpell.None && passive != PassiveSpell.AnticipateHit)
|
||||
{
|
||||
switch (passive)
|
||||
{
|
||||
case PassiveSpell.EnchantedSummoning:
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EnchantedSummoning, 1155904, 1156090, String.Format("{0}\t{0}", EnchantedSummoningBonus(m).ToString()), true)); // +~1_STAMINA~ Stamina Regeneration and +~2_HP~% Hit Points for summoned pets.<br>Increased difficulty for summoned pets to be dispelled.
|
||||
break;
|
||||
case PassiveSpell.Intuition:
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Intuition, 1155907, 1156089, IntuitionBonus(m).ToString(), true)); // Mana Increase ~1_VAL~
|
||||
break;
|
||||
case PassiveSpell.SavingThrow:
|
||||
{
|
||||
string args = null;
|
||||
|
||||
switch (GetMasteryLevel(m, newMastery))
|
||||
{
|
||||
default: args = "5\t0\t0\t0"; break;
|
||||
case 2: args = "5\t5\t0\t0"; break;
|
||||
case 3: args = "5\t5\t5\t5"; break;
|
||||
}
|
||||
|
||||
m.AddStatMod(new StatMod(StatType.Str, "SavingThrow_Str", 5, TimeSpan.Zero));
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.SavingThrow, 1156031, 1156032, args, true)); // Provides a chance to block disarm attempts based on Mastery level, weapon skill level and tactics skill level.
|
||||
}
|
||||
break;
|
||||
case PassiveSpell.Potency:
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Potency, 1155928, 1156195, NonPoisonConsumeChance(m).ToString(), true)); // ~1_VAL~% chance to not consume poison charges when using infecting strike or injected strike.
|
||||
break;
|
||||
case PassiveSpell.Knockout:
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Knockout, 1155931, 1156030, String.Format("{0}\t{1}", GetKnockoutModifier(m).ToString(), GetKnockoutModifier(m, true).ToString(), true))); // Wrestling Damage Bonus:<br>+~1_VAL~% PvM<br>+~2_VAL~% PvP
|
||||
break;
|
||||
case PassiveSpell.Boarding:
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Boarding, 1155934, 1156194, BoardingSlotIncrease(m).ToString(), true)); // Your number of stable slots has been increased by ~1_VAL~.
|
||||
break;
|
||||
}
|
||||
|
||||
m.Delta(MobileDelta.WeaponDamage);
|
||||
m.UpdateResistances();
|
||||
|
||||
if (m.Mana > m.ManaMax)
|
||||
m.Mana = m.ManaMax;
|
||||
}
|
||||
|
||||
if (m.Backpack != null)
|
||||
{
|
||||
foreach (Item item in m.Backpack.FindItemsByType(typeof(BookOfMasteries)))
|
||||
{
|
||||
BookOfMasteries book = item as BookOfMasteries;
|
||||
|
||||
if (book != null)
|
||||
book.InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Item item in m.Items.Where(i => i is BookOfMasteries))
|
||||
{
|
||||
BookOfMasteries book = item as BookOfMasteries;
|
||||
|
||||
if (book != null)
|
||||
book.InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public static PassiveSpell GetActivePassive(Mobile m)
|
||||
{
|
||||
if (m == null || m.Skills == null || Infos == null)
|
||||
return PassiveSpell.None;
|
||||
|
||||
SkillName mastery = m.Skills.CurrentMastery;
|
||||
|
||||
MasteryInfo info = Infos.FirstOrDefault(i => i.Passive && i.MasterySkill == mastery && i.PassiveSpell != PassiveSpell.AnticipateHit);
|
||||
|
||||
if (info != null)
|
||||
return info.PassiveSpell;
|
||||
|
||||
return PassiveSpell.None;
|
||||
}
|
||||
|
||||
public static bool IsActivePassive(Mobile m, PassiveSpell spell)
|
||||
{
|
||||
if (spell == PassiveSpell.AnticipateHit)
|
||||
return m.Skills.CurrentMastery == SkillName.Bushido;
|
||||
|
||||
return GetActivePassive(m) == spell;
|
||||
}
|
||||
|
||||
public static void RemovePassiveBuffs(Mobile m)
|
||||
{
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.EnchantedSummoning);
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.AnticipateHit);
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Intuition);
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.SavingThrow);
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Potency);
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Knockout);
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Boarding);
|
||||
}
|
||||
|
||||
public static void OnLogin(LoginEventArgs e)
|
||||
{
|
||||
Mobile m = e.Mobile;
|
||||
|
||||
if ((int)m.Skills.CurrentMastery > 0)
|
||||
OnMasteryChanged(m, m.Skills.CurrentMastery);
|
||||
}
|
||||
|
||||
public static int GetSpellID(PassiveSpell spell)
|
||||
{
|
||||
switch (spell)
|
||||
{
|
||||
case PassiveSpell.EnchantedSummoning: return 714;
|
||||
case PassiveSpell.AnticipateHit: return 715;
|
||||
case PassiveSpell.Intuition: return 717;
|
||||
case PassiveSpell.SavingThrow: return 732;
|
||||
case PassiveSpell.Potency: return 738;
|
||||
case PassiveSpell.Knockout: return 741;
|
||||
case PassiveSpell.Boarding: return 744;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int GetSpellID(SkillName name)
|
||||
{
|
||||
MasteryInfo info = Infos.FirstOrDefault(i => i.MasterySkill == name && i.Passive);
|
||||
|
||||
if (info == null)
|
||||
return -1;
|
||||
|
||||
return info.SpellID;
|
||||
}
|
||||
|
||||
public static int GetLocalization(SkillName name)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
default:
|
||||
case SkillName.Discordance: return 1151945;
|
||||
case SkillName.Provocation: return 1151946;
|
||||
case SkillName.Peacemaking: return 1151947;
|
||||
case SkillName.Magery: return 1155771;
|
||||
case SkillName.Mysticism: return 1155772;
|
||||
case SkillName.Necromancy: return 1155773;
|
||||
case SkillName.Spellweaving: return 1155774;
|
||||
case SkillName.Bushido: return 1155775;
|
||||
case SkillName.Chivalry: return 1155776;
|
||||
case SkillName.Ninjitsu: return 1155777;
|
||||
case SkillName.Archery: return 1155786;
|
||||
case SkillName.Fencing: return 1155778;
|
||||
case SkillName.Macing: return 1155779;
|
||||
case SkillName.Swords: return 1155780;
|
||||
case SkillName.Throwing: return 1155781;
|
||||
case SkillName.Parry: return 1155782;
|
||||
case SkillName.Poisoning: return 1155783;
|
||||
case SkillName.Wrestling: return 1155784;
|
||||
case SkillName.AnimalTaming: return 1155785;
|
||||
}
|
||||
}
|
||||
|
||||
#region Passive Bonuses/Maluses
|
||||
public static int EnchantedSummoningBonus(BaseCreature bc)
|
||||
{
|
||||
if (bc.Summoned)
|
||||
return EnchantedSummoningBonus(bc.SummonMaster);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int EnchantedSummoningBonus(Mobile m)
|
||||
{
|
||||
if (IsActivePassive(m, PassiveSpell.EnchantedSummoning))
|
||||
{
|
||||
SkillName sk = m.Skills.CurrentMastery;
|
||||
|
||||
return (int)((m.Skills[sk].Value + (GetMasteryLevel(m, sk) * 40)) / 16);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int AnticipateHitBonus(Mobile m)
|
||||
{
|
||||
if (IsActivePassive(m, PassiveSpell.AnticipateHit))
|
||||
{
|
||||
return (int)(m.Skills[SkillName.Bushido].Value * .67);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int IntuitionBonus(Mobile m)
|
||||
{
|
||||
if (IsActivePassive(m, PassiveSpell.Intuition))
|
||||
{
|
||||
SkillName sk = m.Skills.CurrentMastery;
|
||||
|
||||
return (int)((GetMasteryLevel(m, sk) * 40) / 8);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int NonPoisonConsumeChance(Mobile m)
|
||||
{
|
||||
if (IsActivePassive(m, PassiveSpell.Potency))
|
||||
{
|
||||
double skill = m.Skills[SkillName.Poisoning].Value + m.Skills[SkillName.Anatomy].Value;
|
||||
skill += GetMasteryLevel(m, SkillName.Poisoning) * 20;
|
||||
|
||||
return (int)(skill / 4.375);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int GetKnockoutModifier(Mobile m, bool pvp = false)
|
||||
{
|
||||
if (IsActivePassive(m, PassiveSpell.Knockout))
|
||||
{
|
||||
switch (GetMasteryLevel(m, SkillName.Wrestling))
|
||||
{
|
||||
default: return 0;
|
||||
case 3: return pvp ? 50 : 100;
|
||||
case 2: return pvp ? 25 : 50;
|
||||
case 1: return pvp ? 10 : 25;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int BoardingSlotIncrease(Mobile m)
|
||||
{
|
||||
if (IsActivePassive(m, PassiveSpell.Boarding))
|
||||
{
|
||||
return GetMasteryLevel(m, SkillName.AnimalTaming);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int SavingThrowChance(Mobile m, AosAttribute attr)
|
||||
{
|
||||
if (IsActivePassive(m, PassiveSpell.SavingThrow))
|
||||
{
|
||||
int level = GetMasteryLevel(m, m.Skills.CurrentMastery);
|
||||
|
||||
if (level <= 0)
|
||||
return 0;
|
||||
|
||||
switch (attr)
|
||||
{
|
||||
case AosAttribute.AttackChance: return 5;
|
||||
case AosAttribute.DefendChance: return level > 1 ? 5 : 0;
|
||||
case AosAttribute.BonusStr: return level > 2 ? 5 : 0;
|
||||
case AosAttribute.WeaponDamage: return level > 2 ? 5 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Mastery Skills
|
||||
public static SkillName[] Skills { get { return _Skills; } }
|
||||
|
||||
private static SkillName[] _Skills =
|
||||
{
|
||||
SkillName.Peacemaking,
|
||||
SkillName.Provocation,
|
||||
SkillName.Discordance,
|
||||
SkillName.Magery,
|
||||
SkillName.Mysticism,
|
||||
SkillName.Necromancy,
|
||||
SkillName.Spellweaving,
|
||||
SkillName.Bushido,
|
||||
SkillName.Chivalry,
|
||||
SkillName.Ninjitsu,
|
||||
SkillName.Fencing,
|
||||
SkillName.Macing,
|
||||
SkillName.Swords,
|
||||
SkillName.Throwing,
|
||||
SkillName.Parry,
|
||||
SkillName.Poisoning,
|
||||
SkillName.Wrestling,
|
||||
SkillName.AnimalTaming,
|
||||
SkillName.Archery
|
||||
};
|
||||
|
||||
private static int[] _Descriptions =
|
||||
{
|
||||
1115707,
|
||||
1115706,
|
||||
1115708,
|
||||
1156303,
|
||||
1156316,
|
||||
1156311,
|
||||
1156315,
|
||||
1156313,
|
||||
1156312,
|
||||
1156314,
|
||||
1156309,
|
||||
1156308,
|
||||
1156307,
|
||||
1156317,
|
||||
1156302,
|
||||
1156304,
|
||||
1156310,
|
||||
1156306,
|
||||
1156305
|
||||
};
|
||||
|
||||
private static string[] _Titles =
|
||||
{
|
||||
"the Galvanizer",
|
||||
"the Exhilarator",
|
||||
"the Desponder",
|
||||
"the Marvelous",
|
||||
"the Enigmatic",
|
||||
"the Undying",
|
||||
"the Mysterious",
|
||||
"the Disciplined",
|
||||
"the Courageous",
|
||||
"the Unseen",
|
||||
"the Needle",
|
||||
"the Crushing",
|
||||
"the Blade",
|
||||
"the Precise",
|
||||
"the Deflector",
|
||||
"the Lethal",
|
||||
"the Champion",
|
||||
"the Beastmaster",
|
||||
"the Exact"
|
||||
};
|
||||
|
||||
public static int GetDescription(Mobile m)
|
||||
{
|
||||
SkillName sk = m.Skills.CurrentMastery;
|
||||
|
||||
for (int i = 0; i < _Skills.Length; i++)
|
||||
{
|
||||
if (_Skills[i] == sk)
|
||||
return _Descriptions[i];
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static string GetTitle(Mobile m)
|
||||
{
|
||||
SkillName sk = m.Skills.CurrentMastery;
|
||||
|
||||
for(int i = 0; i < _Skills.Length; i++)
|
||||
{
|
||||
if (_Skills[i] == sk)
|
||||
return _Titles[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
78
Scripts/Spells/Skill Masteries/Core/SelectMasteryGump.cs
Normal file
78
Scripts/Spells/Skill Masteries/Core/SelectMasteryGump.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Spells.SkillMasteries;
|
||||
using System.Linq;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class MasterySelectionGump : BaseGump
|
||||
{
|
||||
//public const int Red = 0x4800;
|
||||
//public const int Blue = 0x000F;
|
||||
public const int Red = 0x8e2525;
|
||||
public const int Blue = 0x000066;
|
||||
|
||||
public BookOfMasteries Book { get; private set; }
|
||||
|
||||
public MasterySelectionGump(PlayerMobile user, BookOfMasteries book)
|
||||
: base(user, 75, 25)
|
||||
{
|
||||
Book = book;
|
||||
}
|
||||
|
||||
public override void AddGumpLayout()
|
||||
{
|
||||
AddBackground(0, 0, 404, 550, 9380);
|
||||
|
||||
AddHtmlLocalized(0, 40, 404, 16, CenterLoc, "#1151948", 0, false, false); // Switch Mastery
|
||||
|
||||
int y = 58;
|
||||
SkillName current = User.Skills.CurrentMastery;
|
||||
|
||||
foreach (SkillName skName in MasteryInfo.Skills)
|
||||
{
|
||||
Skill sk = User.Skills[skName];
|
||||
|
||||
if (sk != null && sk.IsMastery && sk.VolumeLearned > 0)
|
||||
{
|
||||
AddButton(30, y, 4005, 4007, (int)skName + 1, GumpButtonType.Reply, 0);
|
||||
|
||||
AddHtmlLocalized(72, y, 200, 16, MasteryInfo.GetLocalization(skName), skName == current ? C32216(Red) : C32216(Blue), false, false);
|
||||
AddHtmlLocalized(265, y, 100, 16, 1156052, MasteryInfo.GetMasteryLevel(User, skName).ToString(), 0, false, false);
|
||||
|
||||
y += 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID == 0)
|
||||
return;
|
||||
|
||||
SkillName n = (SkillName)info.ButtonID - 1;
|
||||
SkillName current = User.Skills.CurrentMastery;
|
||||
|
||||
if (n == current)
|
||||
{
|
||||
User.Skills.CurrentMastery = SkillName.Alchemy;
|
||||
MasteryInfo.OnMasteryChanged(User, current);
|
||||
}
|
||||
else if (User.Skills[n].Base >= MasteryInfo.MinSkillRequirement)
|
||||
{
|
||||
User.SendLocalizedMessage(1155886, User.Skills[n].Info.Name); // Your active skill mastery is now set to ~1_MasterySkill~!
|
||||
User.Skills.CurrentMastery = n;
|
||||
|
||||
MasteryInfo.OnMasteryChanged(User, current);
|
||||
|
||||
BookOfMasteries.AddToCooldown(User);
|
||||
}
|
||||
else
|
||||
User.SendLocalizedMessage(1156236, String.Format("{0}\t{1}", MasteryInfo.MinSkillRequirement.ToString(), User.Skills[n].Info.Name)); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that mastery.
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Scripts/Spells/Skill Masteries/Core/SkillMasteryMove.cs
Normal file
110
Scripts/Spells/Skill Masteries/Core/SkillMasteryMove.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using Server;
|
||||
using System.Globalization;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class SkillMasteryMove : SpecialMove
|
||||
{
|
||||
public Dictionary<Mobile, DateTime> Cooldown { get; set; }
|
||||
|
||||
public virtual TimeSpan CooldownPeriod { get { return TimeSpan.MinValue; } }
|
||||
public override bool ValidatesDuringHit { get { return false; } }
|
||||
|
||||
public SkillMasteryMove()
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendAbilityMessage(Mobile m)
|
||||
{
|
||||
if(AbilityMessage.Number > 0)
|
||||
m.PrivateOverheadMessage(MessageType.Regular, 1150, AbilityMessage.Number, m.NetState);
|
||||
else
|
||||
m.PrivateOverheadMessage(MessageType.Regular, 1150, false, AbilityMessage.String, m.NetState);
|
||||
}
|
||||
|
||||
public override bool Validate(Mobile from)
|
||||
{
|
||||
SkillMasteryMove move = SpecialMove.GetCurrentMove(from) as SkillMasteryMove;
|
||||
|
||||
if ((move == null || move.GetType() != this.GetType()) && !CheckCooldown(from))
|
||||
return false;
|
||||
|
||||
if (from.Player && from.Skills.CurrentMastery != MoveSkill)
|
||||
{
|
||||
from.SendLocalizedMessage(1115664); // You are not on the correct path for using this mastery ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.Validate(from);
|
||||
}
|
||||
|
||||
public bool CheckCooldown(Mobile from)
|
||||
{
|
||||
if (CooldownPeriod > TimeSpan.MinValue && IsInCooldown(from))
|
||||
{
|
||||
double left = (Cooldown[from] - DateTime.UtcNow).TotalMinutes;
|
||||
|
||||
if (left > 1)
|
||||
{
|
||||
from.SendLocalizedMessage(1155787, ((int)left).ToString()); // You must wait ~1_minutes~ minutes before you can use this ability.
|
||||
}
|
||||
else
|
||||
{
|
||||
left = (Cooldown[from] - DateTime.UtcNow).TotalSeconds;
|
||||
from.SendLocalizedMessage(1079335, left.ToString("F", CultureInfo.InvariantCulture)); // You must wait ~1_seconds~ seconds before you can use this ability again.
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CheckWeapon(Mobile from)
|
||||
{
|
||||
if (!from.Player)
|
||||
return true;
|
||||
|
||||
BaseWeapon wep = from.Weapon as BaseWeapon;
|
||||
|
||||
return wep != null && wep.DefSkill == MoveSkill;
|
||||
}
|
||||
|
||||
public virtual bool IsInCooldown(Mobile m)
|
||||
{
|
||||
return Cooldown != null && Cooldown.ContainsKey(m);
|
||||
}
|
||||
|
||||
public virtual void AddToCooldown(Mobile m)
|
||||
{
|
||||
if (CooldownPeriod > TimeSpan.MinValue)
|
||||
{
|
||||
if (Cooldown == null)
|
||||
Cooldown = new Dictionary<Mobile, DateTime>();
|
||||
|
||||
Cooldown[m] = DateTime.UtcNow + CooldownPeriod;
|
||||
Timer.DelayCall(CooldownPeriod, () => RemoveCooldown(m));
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void RemoveCooldown(Mobile m)
|
||||
{
|
||||
if (Cooldown.ContainsKey(m))
|
||||
Cooldown.Remove(m);
|
||||
}
|
||||
|
||||
public virtual void OnGotHit(Mobile attacker, Mobile defender, ref int damage)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnDamaged(Mobile attacker, Mobile defender, DamageType type, ref int damage)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
159
Scripts/Spells/Skill Masteries/Core/SkillMasteryPrimer.cs
Normal file
159
Scripts/Spells/Skill Masteries/Core/SkillMasteryPrimer.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Mobiles;
|
||||
using Server.Spells.SkillMasteries;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.ContextMenus;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class SkillMasteryPrimer : Item
|
||||
{
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public SkillName Skill { get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Volume { get; set; }
|
||||
|
||||
public override bool ForceShowProperties { get { return true; } }
|
||||
|
||||
[Constructable]
|
||||
public SkillMasteryPrimer(SkillName skill, int volume) : base(7714)
|
||||
{
|
||||
Skill = skill;
|
||||
LootType = LootType.Cursed;
|
||||
|
||||
Volume = volume;
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (IsChildOf(from.Backpack))
|
||||
{
|
||||
if (MasteryInfo.HasLearned(from, Skill, Volume))
|
||||
{
|
||||
from.SendLocalizedMessage(1155884, String.Format("#{0}", MasteryInfo.GetLocalization(Skill))); // You are already proficient in this level of ~1_MasterySkill~
|
||||
}
|
||||
else if (MasteryInfo.LearnMastery(from, Skill, Volume))
|
||||
{
|
||||
from.SendLocalizedMessage(1155885, String.Format("#{0}", MasteryInfo.GetLocalization(Skill))); // You have increased your proficiency in ~1_SkillMastery~!
|
||||
|
||||
Effects.SendLocationParticles(EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration), 0, 0, 0, 0, 0, 5060, 0);
|
||||
Effects.PlaySound(from.Location, from.Map, 0x243);
|
||||
|
||||
Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map), from, 0x36D4, 7, 0, false, true, 0xAA8, 0, 9502, 1, 0, (EffectLayer)255, 0x100);
|
||||
Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 4, from.Y - 6, from.Z + 15), from.Map), from, 0x36D4, 7, 0, false, true, 0xAA8, 0, 9502, 1, 0, (EffectLayer)255, 0x100);
|
||||
Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 4, from.Z + 15), from.Map), from, 0x36D4, 7, 0, false, true, 0xAA8, 0, 9502, 1, 0, (EffectLayer)255, 0x100);
|
||||
|
||||
Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
|
||||
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddNameProperty(ObjectPropertyList list)
|
||||
{
|
||||
list.Add(1155882, String.Format("#{0}", MasteryInfo.GetLocalization(Skill))); // Primer on ~1_Skill~
|
||||
}
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
list.Add(1155883, String.Format("{0}", GetVolume(Volume))); // Volume ~1_Level~
|
||||
}
|
||||
|
||||
private string GetVolume(int volume)
|
||||
{
|
||||
if (volume == 1)
|
||||
return "I";
|
||||
|
||||
if (volume == 2)
|
||||
return "II";
|
||||
|
||||
return "III";
|
||||
}
|
||||
|
||||
public static void CheckPrimerDrop(BaseCreature killed)
|
||||
{
|
||||
List<DamageStore> rights = killed.GetLootingRights();
|
||||
|
||||
rights.ForEach(ds =>
|
||||
{
|
||||
if (ds.m_HasRight)
|
||||
{
|
||||
Mobile m = ds.m_Mobile;
|
||||
|
||||
if (Utility.RandomDouble() < 0.10)
|
||||
{
|
||||
SkillMasteryPrimer primer = GetRandom();
|
||||
|
||||
if (primer != null)
|
||||
{
|
||||
if (m.Backpack == null || !m.Backpack.TryDropItem(m, primer, false))
|
||||
m.BankBox.DropItem(primer);
|
||||
}
|
||||
|
||||
m.SendLocalizedMessage(1156209); // You have received a mastery primer!
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static SkillMasteryPrimer GetRandom()
|
||||
{
|
||||
SkillName skill = MasteryInfo.Skills[Utility.RandomMinMax(3, 18)];
|
||||
int volume = 1;
|
||||
|
||||
double random = Utility.RandomDouble();
|
||||
|
||||
if (0.2 >= random)
|
||||
volume = 3;
|
||||
else if (0.5 >= random)
|
||||
volume = 2;
|
||||
|
||||
SkillMasteryPrimer primer = new SkillMasteryPrimer(skill, volume);
|
||||
|
||||
return primer;
|
||||
}
|
||||
|
||||
public SkillMasteryPrimer(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize( GenericWriter writer )
|
||||
{
|
||||
base.Serialize( writer );
|
||||
|
||||
writer.Write( (int) 1 ); // version
|
||||
|
||||
writer.Write(Volume);
|
||||
writer.Write((int)Skill);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
Volume = reader.ReadInt();
|
||||
Skill = (SkillName)reader.ReadInt();
|
||||
break;
|
||||
case 0:
|
||||
|
||||
Skill = (SkillName)reader.ReadInt();
|
||||
int id = reader.ReadInt();
|
||||
|
||||
Volume = MasteryInfo.GetVolume(id, Skill);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1299
Scripts/Spells/Skill Masteries/Core/SkillMasterySpell.cs
Normal file
1299
Scripts/Spells/Skill Masteries/Core/SkillMasterySpell.cs
Normal file
File diff suppressed because it is too large
Load Diff
140
Scripts/Spells/Skill Masteries/DeathRay.cs
Normal file
140
Scripts/Spells/Skill Masteries/DeathRay.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class DeathRaySpell : SkillMasterySpell
|
||||
{
|
||||
/*The mage focuses a death ray on their opponent which snares the mage to their
|
||||
* location and does damage based on magery skill, evaluating intelligence skill,
|
||||
* and mastery level as long as the mage has mana and the target is in range.*/
|
||||
|
||||
// BuffIcon: 1155798 ~1_STR~ Energy Resist.<br>~2_DAM~ energy damage every 3 seconds while death ray remains in effect.<br>
|
||||
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Death Ray", "In Grav Corp",
|
||||
204,
|
||||
9061,
|
||||
Reagent.BlackPearl,
|
||||
Reagent.Bloodmoss,
|
||||
Reagent.SpidersSilk
|
||||
);
|
||||
|
||||
private Point3D _Location;
|
||||
private ResistanceMod _Mod;
|
||||
|
||||
public override double UpKeep { get { return 35; } }
|
||||
public override int RequiredMana{ get { return 50; } }
|
||||
public override int DamageThreshold { get { return 1; } }
|
||||
public override bool DamageCanDisrupt { get { return true; } }
|
||||
public override double TickTime { get { return 3; } }
|
||||
|
||||
public override int UpkeepCancelMessage { get { return 1155874; } } // You do not have enough mana to keep your death ray active.
|
||||
public override int DisruptMessage { get { return 1155793; } } // This action disturbs the focus necessary to keep your death ray active and it dissipates.
|
||||
|
||||
public override TimeSpan ExpirationPeriod { get { return TimeSpan.FromMinutes(360); } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Magery; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.EvalInt; } }
|
||||
|
||||
public DeathRaySpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new MasteryTarget(this);
|
||||
}
|
||||
|
||||
protected override void OnTarget(object o)
|
||||
{
|
||||
Mobile m = o as Mobile;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
if (GetSpell<DeathRaySpell>(Caster, m) != null)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156094); // Your target is already under the effect of this ability.
|
||||
}
|
||||
else if (CheckHSequence(m))
|
||||
{
|
||||
if (CheckResisted(m))
|
||||
{
|
||||
m.SendLocalizedMessage(1156101); // You resist the effects of death ray.
|
||||
Caster.SendLocalizedMessage(1156102); // Your target resists the effects of death ray.
|
||||
}
|
||||
else
|
||||
{
|
||||
SpellHelper.CheckReflect(0, Caster, ref m);
|
||||
_Location = Caster.Location;
|
||||
|
||||
m.FixedParticles(0x374A, 1, 15, 5054, 0x7A2, 7, EffectLayer.Head);
|
||||
Caster.FixedParticles(0x0000, 10, 5, 2054, EffectLayer.Head);
|
||||
|
||||
double damage = (Caster.Skills[CastSkill].Base + Caster.Skills[DamageSkill].Base) * ((double)GetMasteryLevel() * .8);
|
||||
damage /= Target is PlayerMobile ? 5.15 : 2.5;
|
||||
|
||||
int mod = (int)Caster.Skills[DamageSkill].Value / 12;
|
||||
_Mod = new ResistanceMod(ResistanceType.Energy, -mod);
|
||||
m.AddResistanceMod(_Mod);
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.DeathRay, 1155896, 1156085, String.Format("{0}\t{1}", ((int)damage).ToString(), m.Name))); // Deals ~2_DAMAGE~ to ~1_NAME~ every 3 seconds while in range. Preforming any action will end spell.
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.DeathRayDebuff, 1155896, 1156086, mod.ToString())); // Energy Resist Debuff: ~1_VAL~%
|
||||
|
||||
Target = m;
|
||||
BeginTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
if (Target != null && _Mod != null)
|
||||
Target.RemoveResistanceMod(_Mod);
|
||||
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.DeathRay);
|
||||
|
||||
if(Target != null)
|
||||
BuffInfo.RemoveBuff(Target, BuffIcon.DeathRayDebuff);
|
||||
}
|
||||
|
||||
public override bool OnTick()
|
||||
{
|
||||
if (!base.OnTick())
|
||||
return false;
|
||||
|
||||
if (Target == Caster || !Target.Alive)
|
||||
{
|
||||
Expire();
|
||||
Caster.SendLocalizedMessage(1156097); // Your ability was interrupted.
|
||||
}
|
||||
else if (Caster.Location != _Location)
|
||||
{
|
||||
Expire(true);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
double damage = (Caster.Skills[CastSkill].Base + Caster.Skills[DamageSkill].Base) * ((double)GetMasteryLevel() * .8);
|
||||
damage /= Target is PlayerMobile ? 5.15 : 2.5;
|
||||
|
||||
damage *= GetDamageScalar(Target);
|
||||
|
||||
int sdiBonus = SpellHelper.GetSpellDamageBonus(Caster, Target, CastSkill, Caster.Player && Target.Player);
|
||||
|
||||
damage *= (100 + sdiBonus);
|
||||
damage /= 100;
|
||||
|
||||
SpellHelper.Damage(this, Target, (int)damage, 0, 0, 0, 0, 100);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
187
Scripts/Spells/Skill Masteries/ElementalFury.cs
Normal file
187
Scripts/Spells/Skill Masteries/ElementalFury.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class ElementalFurySpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Anticipate Hit", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override int RequiredMana { get { return 20; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Throwing; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Tactics; } }
|
||||
|
||||
private int _MaxAdd;
|
||||
private ResistanceType _Type;
|
||||
|
||||
private Dictionary<Mobile, int> _Table;
|
||||
|
||||
public ElementalFurySpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (IsInCooldown(Caster, this.GetType()))
|
||||
return false;
|
||||
|
||||
if (!CheckWeapon())
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156016); // You must have a throwing weapon equipped to use this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
ElementalFurySpell spell = GetSpell(Caster, this.GetType()) as ElementalFurySpell;
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.PlaySound(0x457);
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if(CheckSequence())
|
||||
{
|
||||
Caster.FixedParticles(0x376A, 9, 32, 5030, EffectLayer.Waist);
|
||||
Caster.PlaySound(0x101);
|
||||
|
||||
Caster.PrivateOverheadMessage(MessageType.Regular, 1150, 1156017, Caster.NetState); // *Your throw is enhanced by the Elemental Fury!*
|
||||
|
||||
double skill = BaseSkillBonus;
|
||||
|
||||
TimeSpan duration = TimeSpan.FromSeconds(skill);
|
||||
_MaxAdd = (int)(skill / 10) + Utility.RandomMinMax(-1, 0);
|
||||
|
||||
Expires = DateTime.UtcNow + duration;
|
||||
BeginTimer();
|
||||
|
||||
_Type = GetResistanceType(GetWeapon());
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.ElementalFury, 1156018, 1156019, duration, Caster, String.Format("{0}\t69\t{1}", _Type.ToString(), _MaxAdd.ToString())));
|
||||
//Each attack the caster deals with ~1_TYPE~ damage will add up to ~3_VAL~ damage to the Fury Pool. Once the Fury Pool
|
||||
//reaches ~2_VAL~ the throwing weapon will unleash the Elemental Fury.
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile defender, ref int damage)
|
||||
{
|
||||
if (_Table == null)
|
||||
_Table = new Dictionary<Mobile, int>();
|
||||
|
||||
if (!_Table.ContainsKey(defender))
|
||||
_Table[defender] = 0;
|
||||
|
||||
_Table[defender] += Math.Min(_MaxAdd, damage);
|
||||
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.ElementalFuryDebuff, 1155920, BuffInfo.Blank, ""));
|
||||
|
||||
if (_Table[defender] >= 69)
|
||||
{
|
||||
defender.FixedParticles(0x3709, 10, 30, 5052, 2719, 0, EffectLayer.LeftFoot, 0);
|
||||
defender.PlaySound(0x208);
|
||||
|
||||
int d;
|
||||
|
||||
if(defender is PlayerMobile)
|
||||
d = (int)(BaseSkillBonus / 6);
|
||||
else
|
||||
d = (int)(BaseSkillBonus / 3) + Utility.RandomMinMax(40, 60);
|
||||
|
||||
switch (_Type)
|
||||
{
|
||||
case ResistanceType.Physical:
|
||||
AOS.Damage(defender, Caster, d, 100, 0, 0, 0, 0);
|
||||
break;
|
||||
case ResistanceType.Fire:
|
||||
AOS.Damage(defender, Caster, d, 0, 100, 0, 0, 0);
|
||||
break;
|
||||
case ResistanceType.Cold:
|
||||
AOS.Damage(defender, Caster, d, 0, 0, 100, 0, 0);
|
||||
break;
|
||||
case ResistanceType.Poison:
|
||||
AOS.Damage(defender, Caster, d, 0, 0, 0, 100, 0);
|
||||
break;
|
||||
case ResistanceType.Energy:
|
||||
AOS.Damage(defender, Caster, d, 0, 0, 0, 0, 100);
|
||||
break;
|
||||
}
|
||||
|
||||
BuffInfo.RemoveBuff(defender, BuffIcon.ElementalFuryDebuff);
|
||||
_Table.Remove(defender);
|
||||
}
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.ElementalFury);
|
||||
|
||||
if (_Table != null)
|
||||
{
|
||||
foreach (Mobile m in _Table.Keys)
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.ElementalFuryDebuff);
|
||||
|
||||
_Table.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private ResistanceType GetResistanceType(BaseWeapon weapon)
|
||||
{
|
||||
if (weapon == null)
|
||||
return ResistanceType.Physical;
|
||||
|
||||
int phys, fire, cold, pois, nrgy, chaos, direct;
|
||||
weapon.GetDamageTypes(null, out phys, out fire, out cold, out pois, out nrgy, out chaos, out direct);
|
||||
|
||||
int highest = phys;
|
||||
int type = 0;
|
||||
|
||||
if (fire > phys)
|
||||
{
|
||||
type = 1;
|
||||
highest = fire;
|
||||
}
|
||||
|
||||
if (cold > highest)
|
||||
{
|
||||
type = 2;
|
||||
highest = cold;
|
||||
}
|
||||
|
||||
if (pois > highest)
|
||||
{
|
||||
type = 3;
|
||||
highest = pois;
|
||||
}
|
||||
|
||||
if (nrgy > highest)
|
||||
{
|
||||
type = 4;
|
||||
highest = nrgy;
|
||||
}
|
||||
|
||||
return (ResistanceType)type;
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Scripts/Spells/Skill Masteries/EtherealBurst.cs
Normal file
62
Scripts/Spells/Skill Masteries/EtherealBurst.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class EtherealBurstSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Ethereal Blast", "Uus Ort Grav",
|
||||
-1,
|
||||
9002,
|
||||
Reagent.Bloodmoss,
|
||||
Reagent.Ginseng,
|
||||
Reagent.MandrakeRoot
|
||||
);
|
||||
|
||||
public override double RequiredSkill{ get { return 90; } }
|
||||
public override double UpKeep { get { return 0; } }
|
||||
public override int RequiredMana{ get { return 0; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Magery; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.EvalInt; } }
|
||||
|
||||
public EtherealBurstSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
Caster.Mana = Caster.ManaMax;
|
||||
|
||||
int duration = 120;
|
||||
double skill = ((double)(Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 2.1) + GetMasteryLevel() * 2;
|
||||
|
||||
if (skill >= 120)
|
||||
duration = 30;
|
||||
|
||||
if (skill >= 100)
|
||||
duration = 60;
|
||||
|
||||
if (duration >= 60)
|
||||
duration = 90;
|
||||
|
||||
AddToCooldown(TimeSpan.FromMinutes(duration));
|
||||
|
||||
Caster.PlaySound(0x102);
|
||||
Effects.SendTargetParticles(Caster, 0x376A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
|
||||
Caster.SendLocalizedMessage(1155789); // You feel completely rejuvinated!
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
}
|
||||
}
|
||||
154
Scripts/Spells/Skill Masteries/FistsOfFury.cs
Normal file
154
Scripts/Spells/Skill Masteries/FistsOfFury.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/*The wrestler attempts to land three hits in rapid succession to the next target that damages you within a 2 tile radius.
|
||||
If successful the third hit will deal direct damage based on the wrestler's mastery level. The duration of this ability
|
||||
is based on wrestling skill and anatomy skill or evaluating intelligence skill.*/
|
||||
|
||||
// Add OnCasterDamaged virutal in SkillMagerySpell and point to it in CheckDisruption(...) method
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class FistsOfFurySpell : SkillMasteryMove
|
||||
{
|
||||
public override int BaseMana { get { return 20; } }
|
||||
public override double RequiredSkill { get { return 90.0; } }
|
||||
|
||||
public override SkillName MoveSkill { get { return SkillName.Wrestling; } }
|
||||
public override TextDefinition AbilityMessage { get { return new TextDefinition(1155895); } } // You ready yourself to unleash your fists of fury!
|
||||
|
||||
public override TimeSpan CooldownPeriod { get { return TimeSpan.FromSeconds(20); } }
|
||||
|
||||
private Dictionary<Mobile, FistsOfFuryContext> _Table;
|
||||
|
||||
public FistsOfFurySpell()
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Validate(Mobile from)
|
||||
{
|
||||
if(!CheckWeapon(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1155979); // You may not wield a weapon and use this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool validate = base.Validate(from);
|
||||
|
||||
if (!validate)
|
||||
return false;
|
||||
|
||||
return CheckMana(from, true);
|
||||
}
|
||||
|
||||
public override void OnUse(Mobile from)
|
||||
{
|
||||
SkillName damageSkill = from.Skills[SkillName.Anatomy].Value > from.Skills[SkillName.EvalInt].Value ? SkillName.Anatomy : SkillName.EvalInt;
|
||||
double duration = (from.Skills[MoveSkill].Value + from.Skills[damageSkill].Value) / 24;
|
||||
|
||||
AddToCooldown(from);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromMilliseconds(400), () =>
|
||||
{
|
||||
Effects.SendTargetParticles(from, 0x376A, 1, 40, 2724, 5, 9907, EffectLayer.Waist, 0);
|
||||
Effects.SendTargetParticles(from, 0x37CC, 1, 40, 2724, 5, 9907, EffectLayer.Waist, 0);
|
||||
from.PlaySound(0x101);
|
||||
from.PlaySound(0x056D);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(duration), () => Expire(from));
|
||||
|
||||
BuffInfo.AddBuff(from, new BuffInfo(BuffIcon.FistsOfFury, 1155930, 1156256, TimeSpan.FromSeconds(duration), from));
|
||||
// You prepare yourself to attempt to land three hits in rapid succession to the next target that damages you within a 2 tile radius.
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnDamaged(Mobile attacker, Mobile defender, DamageType type, ref int damage)
|
||||
{
|
||||
if (defender == null || attacker == null)
|
||||
return;
|
||||
|
||||
BaseWeapon wep = defender.Weapon as BaseWeapon;
|
||||
|
||||
if (wep == null || !(wep is Fists))
|
||||
{
|
||||
defender.SendLocalizedMessage(1155979); // You may not wield a weapon and use this ability.
|
||||
Expire(defender);
|
||||
}
|
||||
else if (defender.InRange(attacker.Location, 2) && !UnderEffects(defender))
|
||||
{
|
||||
if (_Table == null)
|
||||
_Table = new Dictionary<Mobile, FistsOfFuryContext>();
|
||||
|
||||
_Table[defender] = new FistsOfFuryContext(attacker);
|
||||
defender.NextCombatTime = Core.TickCount + (int)(wep.GetDelay(defender).TotalMilliseconds);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
wep.OnSwing(defender, attacker);
|
||||
}
|
||||
|
||||
if (_Table[defender].Hit > 0)
|
||||
{
|
||||
attacker.FixedParticles(0x36BD, 20, 10, 5044, 2724, 0, EffectLayer.Head, 0);
|
||||
attacker.PlaySound(0x3B3);
|
||||
}
|
||||
|
||||
_Table.Remove(defender);
|
||||
|
||||
if (_Table.Count == 0)
|
||||
_Table = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!UnderEffects(attacker))
|
||||
return;
|
||||
|
||||
if (_Table[attacker].Target == defender)
|
||||
{
|
||||
_Table[attacker].Hit++;
|
||||
|
||||
if (_Table[attacker].Hit >= 3)
|
||||
{
|
||||
int level = MasteryInfo.GetMasteryLevel(attacker, MoveSkill);
|
||||
int newDam = damage + Utility.RandomMinMax(level, level * 2);
|
||||
|
||||
AOS.Damage(defender, attacker, Utility.RandomMinMax(level + 1, (level * 7) - 1), 0, 0, 0, 0, 0, 0, 100);
|
||||
damage = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Expire(Mobile from)
|
||||
{
|
||||
ClearCurrentMove(from);
|
||||
}
|
||||
|
||||
public override void OnClearMove(Mobile from)
|
||||
{
|
||||
BuffInfo.RemoveBuff(from, BuffIcon.FistsOfFury);
|
||||
}
|
||||
|
||||
private bool UnderEffects(Mobile from)
|
||||
{
|
||||
return _Table != null && _Table.ContainsKey(from);
|
||||
}
|
||||
|
||||
public class FistsOfFuryContext
|
||||
{
|
||||
public Mobile Target { get; set; }
|
||||
public int Hit { get; set; }
|
||||
|
||||
public FistsOfFuryContext(Mobile target)
|
||||
{
|
||||
Target = target;
|
||||
Hit = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
104
Scripts/Spells/Skill Masteries/FlamingShot.cs
Normal file
104
Scripts/Spells/Skill Masteries/FlamingShot.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class FlamingShotSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Flameing Shot", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override int RequiredMana { get { return 30; } }
|
||||
|
||||
public override DamageType SpellDamageType { get { return DamageType.SpellAOE; } }
|
||||
public override SkillName CastSkill { get { return SkillName.Archery; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Tactics; } }
|
||||
public override bool DelayedDamage { get { return true; } }
|
||||
|
||||
public FlamingShotSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (!CheckWeapon())
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156000); // You must have an Archery weapon to use this ability!
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.PrivateOverheadMessage(MessageType.Regular, 1150, 1155999, Caster.NetState); // You ready a volley of flaming arrows!
|
||||
Effects.SendTargetParticles(Caster, 0x3709, 10, 30, 2724, 0, 9907, EffectLayer.LeftFoot, 0);
|
||||
Caster.PlaySound(0x5CF);
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new MasteryTarget(this, allowGround: true);
|
||||
}
|
||||
|
||||
protected override void OnTarget(object o)
|
||||
{
|
||||
BaseWeapon weapon = GetWeapon();
|
||||
|
||||
if (weapon is BaseRanged && !(weapon is BaseThrown))
|
||||
{
|
||||
IPoint3D p = o as IPoint3D;
|
||||
|
||||
if (p != null && SpellHelper.CheckTown(p, Caster) && CheckSequence())
|
||||
{
|
||||
var targets = AcquireIndirectTargets(p, 5).OfType<Mobile>().ToList();
|
||||
int count = targets.Count;
|
||||
|
||||
foreach (var mob in targets)
|
||||
{
|
||||
Caster.MovingEffect(mob, ((BaseRanged)weapon).EffectID, 18, 1, false, false);
|
||||
|
||||
if (weapon.CheckHit(Caster, mob))
|
||||
{
|
||||
double damage = GetNewAosDamage(40, 1, 5, mob);
|
||||
|
||||
if (count > 2)
|
||||
damage = damage / count;
|
||||
|
||||
damage *= GetDamageScalar(mob);
|
||||
Caster.DoHarmful(mob);
|
||||
SpellHelper.Damage(this, mob, damage, 0, 100, 0, 0, 0);
|
||||
|
||||
Server.Timer.DelayCall(TimeSpan.FromMilliseconds(800), obj =>
|
||||
{
|
||||
Mobile mobile = obj as Mobile;
|
||||
|
||||
if (mobile != null)
|
||||
mobile.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head);
|
||||
}, mob);
|
||||
|
||||
mob.PlaySound(0x1DD);
|
||||
}
|
||||
}
|
||||
|
||||
ColUtility.Free(targets);
|
||||
|
||||
weapon.PlaySwingAnimation(Caster);
|
||||
Caster.PlaySound(0x101);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Scripts/Spells/Skill Masteries/FocusedEye.cs
Normal file
100
Scripts/Spells/Skill Masteries/FocusedEye.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class FocusedEyeSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Focused Eye", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override double UpKeep { get { return 20; } }
|
||||
public override int RequiredMana { get { return 20; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Swords; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Tactics; } }
|
||||
|
||||
private int _PropertyBonus;
|
||||
|
||||
public FocusedEyeSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
SkillMasterySpell spell = GetSpell(Caster, this.GetType());
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckWeapon())
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156006); // You must have a swordsmanship weapon equipped to use this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnBeginCast()
|
||||
{
|
||||
base.OnBeginCast();
|
||||
|
||||
Caster.PlaySound(0x1FD);
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
_PropertyBonus = (int)((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value + (GetMasteryLevel() * 40)) / 12);
|
||||
|
||||
Caster.PrivateOverheadMessage(MessageType.Regular, 1150, 1156002, Caster.NetState); // *You focus your eye on your opponents!*
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.FocusedEye, 1156003, 1156004, String.Format("{0}\t{1}", _PropertyBonus.ToString(), ScaleUpkeep().ToString()))); // +~1_VAL~% Hit Chance Increase.<br>Mana Upkeep Cost: ~2_VAL~.
|
||||
|
||||
Caster.PlaySound(0x101);
|
||||
Effects.SendTargetParticles(Caster, 0x3789, 1, 40, 2726, 5, 9907, EffectLayer.RightFoot, 0);
|
||||
|
||||
BeginTimer();
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void OnExpire()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.FocusedEye);
|
||||
}
|
||||
|
||||
public override int PropertyBonus()
|
||||
{
|
||||
return _PropertyBonus;
|
||||
}
|
||||
|
||||
public static int HitChanceBonus(Mobile attacker)
|
||||
{
|
||||
SkillMasterySpell spell = GetSpell(attacker, typeof(FocusedEyeSpell));
|
||||
|
||||
if (spell != null)
|
||||
return spell.PropertyBonus();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
124
Scripts/Spells/Skill Masteries/HeightenSenses.cs
Normal file
124
Scripts/Spells/Skill Masteries/HeightenSenses.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
|
||||
/*Toggle ability that provides the Parrying Master with increased chance to parry based on parry skill,
|
||||
best weapon skill and mastery level that consumes mana while active.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class HeightenedSensesSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Heightened Senses", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double UpKeep { get { return 10; } }
|
||||
public override int RequiredMana{ get { return 10; } }
|
||||
public override double TickTime { get { return 3; } }
|
||||
public override bool BlocksMovement{ get{ return false; } }
|
||||
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(1.0); } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Parry; } }
|
||||
|
||||
public HeightenedSensesSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
HeightenedSensesSpell spell = GetSpell(Caster, this.GetType()) as HeightenedSensesSpell;
|
||||
|
||||
if(spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HasShieldOrWeapon())
|
||||
return false;
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if(CheckSequence())
|
||||
{
|
||||
Caster.FixedParticles( 0x376A, 9, 32, 5030, 1168, 0, EffectLayer.Waist, 0);
|
||||
Caster.PlaySound(0x5BC);
|
||||
|
||||
Caster.SendLocalizedMessage(1156023); // Your senses heighten!
|
||||
|
||||
BeginTimer();
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.HeightenedSenses, 1155925, 1156062, String.Format("{0}\t{1}", PropertyBonus().ToString(), ScaleUpkeep().ToString()))); // +~1_ARG~% Parry Bonus.<br>Mana Upkeep Cost: ~2_VAL~.
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override bool OnTick()
|
||||
{
|
||||
if (!HasShieldOrWeapon())
|
||||
{
|
||||
Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.OnTick();
|
||||
}
|
||||
|
||||
public bool HasShieldOrWeapon()
|
||||
{
|
||||
if (!Caster.Player)
|
||||
return true;
|
||||
|
||||
BaseShield shield = Caster.FindItemOnLayer(Layer.TwoHanded) as BaseShield;
|
||||
|
||||
if (shield == null)
|
||||
{
|
||||
BaseWeapon weapon = Caster.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon == null || weapon is Fists)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156096); // You must be wielding a shield to use this ability!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void DoEffects()
|
||||
{
|
||||
Caster.FixedParticles(0x376A, 9, 32, 5005, 1167, 0, EffectLayer.Waist, 0);
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.HeightenedSenses);
|
||||
}
|
||||
|
||||
public override int PropertyBonus()
|
||||
{
|
||||
return (int)((Caster.Skills[CastSkill].Value + GetWeaponSkill() + (GetMasteryLevel() * 40)) / 3) / 10;
|
||||
}
|
||||
|
||||
public static double GetParryBonus(Mobile m)
|
||||
{
|
||||
HeightenedSensesSpell spell = GetSpell(m, typeof(HeightenedSensesSpell)) as HeightenedSensesSpell;
|
||||
|
||||
if(spell != null)
|
||||
return (double)spell.PropertyBonus() / 100.0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
152
Scripts/Spells/Skill Masteries/HolyFistSpell.cs
Normal file
152
Scripts/Spells/Skill Masteries/HolyFistSpell.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
using Server.Spells.Ninjitsu;
|
||||
|
||||
/*The paladin unleashes a flying fist against a target that does energy damage based on the paladin's chivalry
|
||||
* skill, best weapon skill, and mastery level. A bonus to damage is provided by high karma as well against undead
|
||||
* targets.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class HolyFistSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Holy Fist", "Kal Vas Grav",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override int RequiredMana { get { return 50; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Chivalry; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Chivalry; } }
|
||||
|
||||
public int RequiredTithing { get { return 100; } }
|
||||
|
||||
public override bool DelayedDamage { get { return true; } }
|
||||
|
||||
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(2.5); } }
|
||||
|
||||
public HolyFistSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.FixedEffect(0x37C4, 87, (int)(GetCastDelay().TotalSeconds * 28), 4, 3);
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (Caster is PlayerMobile && Caster.TithingPoints < RequiredTithing)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1060173, RequiredTithing.ToString()); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability,
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new MasteryTarget(this);
|
||||
}
|
||||
|
||||
protected override void OnTarget(object o)
|
||||
{
|
||||
IDamageable m = o as IDamageable;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
if (CheckHSequence(m))
|
||||
{
|
||||
IDamageable target = m;
|
||||
IDamageable source = Caster;
|
||||
|
||||
SpellHelper.Turn(Caster, target);
|
||||
|
||||
if (SpellHelper.CheckReflect(0, ref source, ref target))
|
||||
{
|
||||
Server.Timer.DelayCall(TimeSpan.FromSeconds(.5), () =>
|
||||
{
|
||||
source.MovingParticles(target, 0x9BB5, 7, 0, false, true, 9502, 4019, 0x160);
|
||||
source.PlaySound(0x5CE);
|
||||
});
|
||||
}
|
||||
|
||||
double skill = (Caster.Skills[CastSkill].Value + GetWeaponSkill() + (GetMasteryLevel() * 40)) / 3;
|
||||
double damage = skill + (double)Caster.Karma / 1000;
|
||||
|
||||
damage += Utility.RandomMinMax(0, 5);
|
||||
|
||||
if (m is BaseCreature && IsUndead((BaseCreature)m))
|
||||
damage *= 1.5;
|
||||
else if (m is PlayerMobile)
|
||||
damage = Math.Min(35, damage);
|
||||
|
||||
Caster.MovingParticles(m, 0x9BB5, 7, 0, false, true, 9502, 4019, 0x160);
|
||||
Caster.PlaySound(0x5CE);
|
||||
|
||||
if (m is Mobile)
|
||||
{
|
||||
damage *= GetDamageScalar((Mobile)m);
|
||||
}
|
||||
|
||||
int sdiBonus = SpellHelper.GetSpellDamageBonus(Caster, m, CastSkill, m is Mobile ? Caster.Player && ((Mobile)m).Player : false);
|
||||
|
||||
damage *= (100 + sdiBonus);
|
||||
damage /= 100;
|
||||
|
||||
SpellHelper.Damage(this, target, damage, 0, 0, 0, 0, 100);
|
||||
|
||||
if (target is Mobile && !CheckResisted((Mobile)target) && ((Mobile)target).NetState != null)
|
||||
{
|
||||
Mobile mob = target as Mobile;
|
||||
|
||||
if (!TransformationSpellHelper.UnderTransformation(mob, typeof(AnimalForm)))
|
||||
mob.SendSpeedControl(SpeedControlType.WalkSpeed);
|
||||
|
||||
Server.Timer.DelayCall(TimeSpan.FromSeconds(skill / 60), () =>
|
||||
{
|
||||
if (!TransformationSpellHelper.UnderTransformation(mob, typeof(AnimalForm)) &&
|
||||
(Core.SA || !TransformationSpellHelper.UnderTransformation(mob, typeof(Server.Spells.Spellweaving.ReaperFormSpell))))
|
||||
mob.SendSpeedControl(SpeedControlType.Disable);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CheckSequence()
|
||||
{
|
||||
int requiredTithing = this.RequiredTithing;
|
||||
|
||||
if (Caster is PlayerMobile && Caster.TithingPoints < requiredTithing)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1060173, RequiredTithing.ToString()); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AosAttributes.GetValue(Caster, AosAttribute.LowerRegCost) > Utility.Random(100))
|
||||
requiredTithing = 0;
|
||||
|
||||
if(requiredTithing > 0 && Caster is PlayerMobile)
|
||||
Caster.TithingPoints -= requiredTithing;
|
||||
|
||||
return base.CheckSequence();
|
||||
}
|
||||
|
||||
private bool IsUndead(BaseCreature bc)
|
||||
{
|
||||
SlayerEntry entry = SlayerGroup.GetEntryByName(SlayerName.Silver);
|
||||
|
||||
return entry != null && entry.Slays(bc);
|
||||
}
|
||||
}
|
||||
}
|
||||
277
Scripts/Spells/Skill Masteries/InjectedStrike.cs
Normal file
277
Scripts/Spells/Skill Masteries/InjectedStrike.cs
Normal file
@@ -0,0 +1,277 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class InjectedStrikeSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Injected Strike", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override int RequiredMana { get { return 30; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Poisoning; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Anatomy; } }
|
||||
|
||||
public override bool CancelsWeaponAbility { get { return true; } }
|
||||
|
||||
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(1.0); } }
|
||||
|
||||
public override void GetCastSkills(out double min, out double max)
|
||||
{
|
||||
min = RequiredSkill;
|
||||
max = RequiredSkill + 10.0;
|
||||
}
|
||||
|
||||
public InjectedStrikeSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.FixedParticles(0x3728, 0xA, 0x7, 0x13CB, 0x66C, 3, (EffectLayer)2, 0);
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
BaseWeapon weapon = GetWeapon();
|
||||
|
||||
if(CheckWeapon())
|
||||
{
|
||||
if (weapon.Poison == null || weapon.PoisonCharges == 0)
|
||||
{
|
||||
var poison = GetLastPotion(Caster);
|
||||
|
||||
Caster.SendLocalizedMessage(502137); // Select the poison you wish to use.
|
||||
Caster.Target = new MasteryTarget(this, autoEnd: false);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (!HasSpell(Caster, this.GetType()))
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
BeginTimer();
|
||||
Caster.SendLocalizedMessage(1156138); // You ready your weapon to unleash an injected strike!
|
||||
|
||||
int bonus = 30;
|
||||
|
||||
// Your next successful attack will poison your target and reduce its poison resist by:<br>~1_VAL~% PvM<br>~2_VAL~% PvP
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.InjectedStrike, 1155927, 1156163, String.Format("{0}\t{1}", bonus.ToString(), (bonus / 2).ToString())));
|
||||
Caster.FixedParticles(0x3728, 0x1, 0xA, 0x251E, 0x4F7, 7, (EffectLayer)2, 0);
|
||||
|
||||
weapon.InvalidateProperties();
|
||||
}
|
||||
}
|
||||
else
|
||||
Caster.SendLocalizedMessage(501775); // This spell is already in effect.
|
||||
}
|
||||
else
|
||||
Caster.SendLocalizedMessage(1060179); //You must be wielding a weapon to use this ability!
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
protected override void OnTarget(object o)
|
||||
{
|
||||
BaseWeapon weapon = GetWeapon();
|
||||
BasePoisonPotion potion = GetLastPotion(Caster);
|
||||
|
||||
if (o is BasePoisonPotion)
|
||||
{
|
||||
potion = o as BasePoisonPotion;
|
||||
|
||||
if (!potion.IsChildOf(Caster.Backpack))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1080058); // This must be in your backpack to use it.
|
||||
}
|
||||
else if (CheckSequence())
|
||||
{
|
||||
if (Caster.CheckTargetSkill(CastSkill, potion, potion.MinPoisoningSkill, potion.MaxPoisoningSkill))
|
||||
{
|
||||
ApplyPoison(weapon, potion);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Caster.SendLocalizedMessage(1010518); // You fail to apply a sufficient dose of poison
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (o is BaseWeapon && weapon != null && (BaseWeapon)o == weapon && potion != null)
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
if (potion != null)
|
||||
{
|
||||
if (Caster.CheckTargetSkill(CastSkill, potion, potion.MinPoisoningSkill, potion.MaxPoisoningSkill))
|
||||
{
|
||||
ApplyPoison(weapon, potion);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Caster.SendLocalizedMessage(1010518); // You fail to apply a sufficient dose of poison
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (potion == null)
|
||||
Caster.SendLocalizedMessage(502143); // The poison vial not usable.
|
||||
else
|
||||
Caster.SendLocalizedMessage(1060179); //You must be wielding a weapon to use this ability!
|
||||
|
||||
}
|
||||
|
||||
private void ApplyPoison(BaseWeapon weapon, BasePoisonPotion potion)
|
||||
{
|
||||
if (potion == null || !Caster.InRange(potion.GetWorldLocation(), 2) || !Caster.InLOS(potion))
|
||||
{
|
||||
Caster.SendLocalizedMessage(502138); // That is too far away for you to use.
|
||||
return;
|
||||
}
|
||||
|
||||
weapon.Poison = potion.Poison;
|
||||
weapon.PoisonCharges = 18 - (potion.Poison.RealLevel * 2);
|
||||
|
||||
Caster.SendLocalizedMessage(1010517); // You apply the poison
|
||||
Caster.PlaySound(0x246);
|
||||
|
||||
potion.Consume();
|
||||
Caster.Backpack.DropItem(new Bottle());
|
||||
|
||||
OnCast();
|
||||
|
||||
if (potion.Deleted)
|
||||
{
|
||||
if (_LastPotion != null && _LastPotion.ContainsKey(Caster) && _LastPotion[Caster] == potion)
|
||||
{
|
||||
_LastPotion.Remove(Caster);
|
||||
|
||||
if (_LastPotion.Count == 0)
|
||||
_LastPotion = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_LastPotion == null)
|
||||
_LastPotion = new Dictionary<Mobile, BasePoisonPotion>();
|
||||
|
||||
if (!_LastPotion.ContainsKey(Caster) || _LastPotion[Caster] != potion)
|
||||
_LastPotion[Caster] = potion;
|
||||
}
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.InjectedStrike);
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile defender, ref int damage)
|
||||
{
|
||||
BaseWeapon weapon = GetWeapon();
|
||||
|
||||
if (!CheckWeapon())
|
||||
return;
|
||||
|
||||
Poison p = weapon.Poison;
|
||||
|
||||
if (p == null || weapon.PoisonCharges <= 0)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1061141); // Your weapon must have a dose of poison to perform an infectious strike!
|
||||
return;
|
||||
}
|
||||
|
||||
// Skill Masteries
|
||||
int noChargeChance = MasteryInfo.NonPoisonConsumeChance(Caster);
|
||||
|
||||
if (noChargeChance == 0 || noChargeChance < Utility.Random(100))
|
||||
--weapon.PoisonCharges;
|
||||
else
|
||||
Caster.SendLocalizedMessage(1156095); // Your mastery of poisoning allows you to use your poison charge without consuming it.
|
||||
|
||||
int maxLevel = Caster.Skills[SkillName.Poisoning].Fixed / 200;
|
||||
if (maxLevel < 0) maxLevel = 0;
|
||||
|
||||
#region Mondain's Legacy
|
||||
if (p == Poison.DarkGlow)
|
||||
p = Poison.GetPoison(10 + Math.Min(maxLevel, 2));
|
||||
else if (p == Poison.Parasitic)
|
||||
p = Poison.GetPoison(14 + Math.Min(maxLevel, 3));
|
||||
else if (p.Level > maxLevel)
|
||||
p = Poison.GetPoison(maxLevel);
|
||||
#endregion
|
||||
|
||||
if ((Caster.Skills[SkillName.Poisoning].Value / 100.0) > Utility.RandomDouble() && p.Level < 3)
|
||||
{
|
||||
int level = p.Level + 1;
|
||||
Poison newPoison = Poison.GetPoison(level);
|
||||
|
||||
if (newPoison != null)
|
||||
{
|
||||
p = newPoison;
|
||||
|
||||
Caster.SendLocalizedMessage(1060080); // Your precise strike has increased the level of the poison by 1
|
||||
defender.SendLocalizedMessage(1060081); // The poison seems extra effective!
|
||||
}
|
||||
}
|
||||
|
||||
defender.PlaySound(0xDD);
|
||||
defender.FixedParticles(0x3728, 244, 25, 9941, 1266, 0, EffectLayer.Waist);
|
||||
|
||||
if (defender.ApplyPoison(Caster, p) != ApplyPoisonResult.Immune)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1008096, true, defender.Name); // You have poisoned your target :
|
||||
defender.SendLocalizedMessage(1008097, false, Caster.Name); // : poisoned you!
|
||||
}
|
||||
|
||||
int malus = 30;
|
||||
|
||||
if (defender is PlayerMobile)
|
||||
malus /= 2;
|
||||
|
||||
if (weapon is BaseRanged)
|
||||
malus /= 2;
|
||||
|
||||
ResistanceMod mod = new ResistanceMod(ResistanceType.Poison, -malus);
|
||||
defender.AddResistanceMod(mod);
|
||||
|
||||
// ~2_NAME~ reduces your poison resistance by ~1_VAL~.
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.InjectedStrikeDebuff, 1155927, 1156133, TimeSpan.FromSeconds(7), defender, String.Format("{0}\t{1}", malus, Caster.Name)));
|
||||
|
||||
Server.Timer.DelayCall(TimeSpan.FromSeconds(7), () =>
|
||||
{
|
||||
defender.RemoveResistanceMod(mod);
|
||||
});
|
||||
|
||||
Expire();
|
||||
}
|
||||
|
||||
public override void OnWeaponRemoved(BaseWeapon weapon)
|
||||
{
|
||||
Expire();
|
||||
}
|
||||
|
||||
private static Dictionary<Mobile, BasePoisonPotion> _LastPotion;
|
||||
|
||||
public static BasePoisonPotion GetLastPotion(Mobile m)
|
||||
{
|
||||
if (_LastPotion == null || !_LastPotion.ContainsKey(m))
|
||||
return null;
|
||||
|
||||
if (_LastPotion[m] == null || _LastPotion[m].Deleted)
|
||||
return null;
|
||||
|
||||
return _LastPotion[m];
|
||||
}
|
||||
}
|
||||
}
|
||||
103
Scripts/Spells/Skill Masteries/ManaShield.cs
Normal file
103
Scripts/Spells/Skill Masteries/ManaShield.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Spells.Spellweaving;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class ManaShieldSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Mana Shield", "Faerkulggen",
|
||||
-1,
|
||||
9061
|
||||
);
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override double UpKeep { get { return 0; } }
|
||||
public override int RequiredMana { get { return 40; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
public override bool RevealOnTick { get { return false; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Spellweaving; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Meditation; } }
|
||||
|
||||
public double Chance { get; set; }
|
||||
|
||||
public ManaShieldSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.FixedEffect(0x37C4, 87, (int)(GetCastDelay().TotalSeconds * 28), 1371, 2);
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (Caster is PlayerMobile && !((PlayerMobile)Caster).Spellweaving)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1073220); // You must have completed the epic arcanist quest to use this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
SkillMasterySpell spell = GetSpell(Caster, this.GetType());
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
double skill = ((Caster.Skills[CastSkill].Value + ArcanistSpell.GetFocusLevel(Caster) * 20) / 2) + (GetMasteryLevel() * 20) + 20;
|
||||
Chance = (skill / 13.0) / 100.0;
|
||||
|
||||
Expires = DateTime.UtcNow + TimeSpan.FromSeconds(600);
|
||||
BeginTimer();
|
||||
|
||||
Caster.PlaySound(0x29);
|
||||
Caster.FixedParticles(0x4B8F, 0x1, 0xF, 9502, 0x811, 0, EffectLayer.Waist);
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.ManaShield, 1155902, 1156056, TimeSpan.FromSeconds(600), Caster, String.Format("{0}\t{1}\t{1}", ((int)(Chance * 100)).ToString(), "50"))); // ~1_CHANCE~% chance to reduce incoming damage by ~2_DAMAGE~%. Costs ~2_DAMAGE~% of original damage in mana.
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156087); // Your Mana Shield has expired.
|
||||
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.ManaShield);
|
||||
}
|
||||
|
||||
public override void OnDamaged(Mobile attacker, Mobile defender, DamageType type, ref int damage)
|
||||
{
|
||||
if (Chance >= Utility.RandomDouble())
|
||||
{
|
||||
int toShield = damage / 2;
|
||||
|
||||
if (defender.Mana >= toShield)
|
||||
{
|
||||
defender.Mana -= toShield;
|
||||
damage -= toShield;
|
||||
}
|
||||
else
|
||||
{
|
||||
damage -= defender.Mana;
|
||||
defender.Mana = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
114
Scripts/Spells/Skill Masteries/MysticWeapon.cs
Normal file
114
Scripts/Spells/Skill Masteries/MysticWeapon.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class MysticWeaponSpell : SkillMasterySpell
|
||||
{
|
||||
public static string ModName = "MysticWeapon";
|
||||
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Mystic Weapon", "Vas Ylem Wis",
|
||||
-1,
|
||||
9002,
|
||||
Reagent.FertileDirt,
|
||||
Reagent.Bone
|
||||
);
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override int RequiredMana { get { return 40; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Mysticism; } }
|
||||
public override SkillName DamageSkill
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Caster.Skills[SkillName.Focus].Value > Caster.Skills[SkillName.Imbuing].Value)
|
||||
return SkillName.Focus;
|
||||
|
||||
return SkillName.Imbuing;
|
||||
}
|
||||
}
|
||||
|
||||
private BaseWeapon _Weapon;
|
||||
|
||||
public MysticWeaponSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.FixedEffect(0x37C4, 87, (int)(GetCastDelay().TotalSeconds * 28), 0x66C, 3);
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
BaseWeapon weapon = GetWeapon();
|
||||
|
||||
if (weapon == null || weapon is Fists)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1060179); //You must be wielding a weapon to use this ability!
|
||||
return false;
|
||||
}
|
||||
else if (weapon.ExtendedWeaponAttributes.MysticWeapon > 0 || Enhancement.GetValue(Caster, ExtendedWeaponAttribute.MysticWeapon) > 0)
|
||||
{
|
||||
Caster.SendMessage("That weapon is already under these effects.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
BaseWeapon weapon = GetWeapon();
|
||||
|
||||
if (weapon == null || weapon is Fists)
|
||||
Caster.SendLocalizedMessage(1060179); //You must be wielding a weapon to use this ability!
|
||||
else if (CheckSequence())
|
||||
{
|
||||
double skill = ((Caster.Skills[CastSkill].Value * 1.5) + Caster.Skills[DamageSkill].Value);
|
||||
double duration = (skill + (GetMasteryLevel() * 50)) * 2;
|
||||
|
||||
Enhancement.SetValue(Caster, ExtendedWeaponAttribute.MysticWeapon, 25, "MysticWeapon");
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.MysticWeapon, 1155899, 1156055, TimeSpan.FromSeconds(duration), Caster));
|
||||
|
||||
Effects.SendLocationParticles(EffectItem.Create(Caster.Location, Caster.Map, EffectItem.DefaultDuration), 0x36CB, 1, 14, 0x55C, 7, 9915, 0);
|
||||
Caster.PlaySound(0x64E);
|
||||
|
||||
weapon.AddMysticMod(Caster);
|
||||
weapon.InvalidateProperties();
|
||||
|
||||
Expires = DateTime.UtcNow + TimeSpan.FromSeconds(duration);
|
||||
BeginTimer();
|
||||
|
||||
_Weapon = weapon;
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void OnWeaponRemoved(BaseWeapon weapon)
|
||||
{
|
||||
Expire();
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.MysticWeapon);
|
||||
|
||||
Enhancement.RemoveMobile(Caster);
|
||||
_Weapon.RemoveMysticMod();
|
||||
|
||||
Caster.SendLocalizedMessage(1115273); // The enchantment on your weapon has expired.
|
||||
Caster.PlaySound(0x1ED);
|
||||
}
|
||||
}
|
||||
}
|
||||
234
Scripts/Spells/Skill Masteries/NetherBlast.cs
Normal file
234
Scripts/Spells/Skill Masteries/NetherBlast.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Misc;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using System.Linq;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class NetherBlastSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Nether Blast", "In Vas Por Grav",
|
||||
204,
|
||||
9061,
|
||||
Reagent.DragonBlood,
|
||||
Reagent.DaemonBone
|
||||
);
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override double UpKeep { get { return 0; } }
|
||||
public override int RequiredMana { get { return 40; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(2.0); } }
|
||||
public override double TickTime { get { return 1; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Mysticism; } }
|
||||
public override SkillName DamageSkill
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Caster.Skills[SkillName.Focus].Value > Caster.Skills[SkillName.Imbuing].Value)
|
||||
return SkillName.Focus;
|
||||
|
||||
return SkillName.Imbuing;
|
||||
}
|
||||
}
|
||||
|
||||
public List<InternalItem> Items { get; set; } = new List<InternalItem>();
|
||||
|
||||
public NetherBlastSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.FixedEffect(0x37C4, 87, (int)(GetCastDelay().TotalSeconds * 28), 0x66C, 3);
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (HasSpell(Caster, this.GetType()))
|
||||
{
|
||||
Caster.SendMessage("You cannot use this ability until the last one has expired.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new MasteryTarget(this, 10, true, Server.Targeting.TargetFlags.None);
|
||||
}
|
||||
|
||||
protected override void OnTarget(object o)
|
||||
{
|
||||
if (o is IPoint3D)
|
||||
{
|
||||
IPoint3D p = o as IPoint3D;
|
||||
|
||||
SpellHelper.Turn(Caster, p);
|
||||
|
||||
if (SpellHelper.CheckTown(Caster, Caster) && CheckSequence())
|
||||
{
|
||||
double skill = ((Caster.Skills[CastSkill].Value * 2) + Caster.Skills[DamageSkill].Value) / 3;
|
||||
TimeSpan duration = TimeSpan.FromSeconds(1.0 + (skill / 40.0));
|
||||
|
||||
Direction d = Utility.GetDirection(Caster, p);
|
||||
Point3D loc = Caster.Location;
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
Server.Timer.DelayCall(TimeSpan.FromMilliseconds(i*250), () =>
|
||||
{
|
||||
int x = loc.X;
|
||||
int y = loc.Y;
|
||||
int z = loc.Z;
|
||||
|
||||
Movement.Movement.Offset(d, ref x, ref y);
|
||||
|
||||
loc = new Point3D(x, y, z);
|
||||
|
||||
bool canFit = SpellHelper.AdjustField(ref loc, Caster.Map, 12, false);
|
||||
|
||||
if (canFit)
|
||||
{
|
||||
var item = new InternalItem(Caster, 0x37CC, loc, Caster.Map);
|
||||
item.ProcessDelta();
|
||||
Effects.SendLocationParticles(EffectItem.Create(loc, Caster.Map, EffectItem.DefaultDuration), 0x376A, 9, 10, 5048);
|
||||
|
||||
Items.Add(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Expires = DateTime.UtcNow + duration;
|
||||
BeginTimer();
|
||||
|
||||
Caster.PlaySound(0x211);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnTick()
|
||||
{
|
||||
Dictionary<Mobile, InternalItem> list = new Dictionary<Mobile, InternalItem>();
|
||||
|
||||
foreach (var item in Items.Where(i => !i.Deleted))
|
||||
{
|
||||
foreach (var m in AcquireIndirectTargets(item.Location, 1).OfType<Mobile>().Where(m =>
|
||||
(m.Z + 16) > item.Z &&
|
||||
(item.Z + 12) > m.Z))
|
||||
{
|
||||
if (!list.ContainsKey(m))
|
||||
{
|
||||
list.Add(m, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kvp in list)
|
||||
{
|
||||
DoDamage(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
list.Clear();
|
||||
return base.OnTick();
|
||||
}
|
||||
|
||||
public override void OnExpire()
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
item.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private bool DoDamage(Mobile m, InternalItem item)
|
||||
{
|
||||
if (item.Visible && Caster != null && (!Core.AOS || m != Caster) && SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false))
|
||||
{
|
||||
if (SpellHelper.CanRevealCaster(m))
|
||||
Caster.RevealingAction();
|
||||
|
||||
SkillName damageSkill = Caster.Skills[SkillName.Focus].Value > Caster.Skills[SkillName.Imbuing].Value ? SkillName.Focus : SkillName.Imbuing;
|
||||
|
||||
double skill = ((Caster.Skills[SkillName.Mysticism].Value) + Caster.Skills[damageSkill].Value * 2) / 3;
|
||||
skill /= m.Player ? 3.5 : 2;
|
||||
|
||||
int damage = (int)skill + Utility.RandomMinMax(-3, 3);
|
||||
damage *= (int)GetDamageScalar(m);
|
||||
|
||||
int sdiBonus = SpellHelper.GetSpellDamageBonus(Caster, m, CastSkill, Caster.Player && m.Player);
|
||||
|
||||
damage *= (100 + sdiBonus);
|
||||
damage /= 100;
|
||||
|
||||
AOS.Damage(m, Caster, damage, 0, 0, 0, 0, 0, 100, 0, DamageType.SpellAOE);
|
||||
|
||||
m.FixedParticles(0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255);
|
||||
|
||||
int manaRip = Math.Min(m.Mana, damage / 4);
|
||||
|
||||
if (manaRip > 0)
|
||||
{
|
||||
m.Mana -= manaRip;
|
||||
Caster.Mana += manaRip;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[DispellableField]
|
||||
public class InternalItem : Item
|
||||
{
|
||||
public override bool BlocksFit { get { return true; } }
|
||||
|
||||
public InternalItem(Mobile caster, int itemID, Point3D loc, Map map)
|
||||
: base(itemID)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
Light = LightType.Circle300;
|
||||
|
||||
MoveToWorld(loc, map);
|
||||
|
||||
if (caster.InLOS(this))
|
||||
Visible = true;
|
||||
else
|
||||
Delete();
|
||||
|
||||
if (Deleted)
|
||||
return;
|
||||
}
|
||||
|
||||
public InternalItem(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
123
Scripts/Spells/Skill Masteries/Onslaught.cs
Normal file
123
Scripts/Spells/Skill Masteries/Onslaught.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class OnslaughtSpell : SkillMasteryMove
|
||||
{
|
||||
public override int BaseMana { get { return 20; } }
|
||||
public override double RequiredSkill { get { return 90.0; } }
|
||||
|
||||
public override SkillName MoveSkill { get { return SkillName.Swords; } }
|
||||
public override TextDefinition AbilityMessage { get { return new TextDefinition(1156007); } } // *You ready an onslaught!*
|
||||
|
||||
public OnslaughtSpell()
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Validate(Mobile from)
|
||||
{
|
||||
if (!CheckWeapon(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1156006); // You must have a swordsmanship weapon equipped to use this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.Validate(from);
|
||||
}
|
||||
|
||||
public override void OnUse(Mobile from)
|
||||
{
|
||||
from.PlaySound(0x1EC);
|
||||
|
||||
from.FixedEffect(0x3779, 10, 20, 1372, 0);
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon != null && !HasOnslaught(attacker, defender))
|
||||
{
|
||||
ClearCurrentMove(attacker);
|
||||
|
||||
int phys, fire, cold, pois, nrgy, chaos, direct;
|
||||
weapon.GetDamageTypes(null, out phys, out fire, out cold, out pois, out nrgy, out chaos, out direct);
|
||||
|
||||
int highest = phys;
|
||||
int type = 0;
|
||||
|
||||
if (fire > phys)
|
||||
{
|
||||
type = 1;
|
||||
highest = fire;
|
||||
}
|
||||
|
||||
if (cold > highest)
|
||||
{
|
||||
type = 2;
|
||||
highest = cold;
|
||||
}
|
||||
|
||||
if (pois > highest)
|
||||
{
|
||||
type = 3;
|
||||
highest = pois;
|
||||
}
|
||||
|
||||
if (nrgy > highest)
|
||||
{
|
||||
type = 4;
|
||||
highest = nrgy;
|
||||
}
|
||||
|
||||
ResistanceType resistType = (ResistanceType)type;
|
||||
|
||||
int amount = (int)((attacker.Skills[MoveSkill].Value + attacker.Skills[SkillName.Tactics].Value) / 12);
|
||||
int duration = (MasteryInfo.GetMasteryLevel(attacker, MoveSkill) * 2) + 1;
|
||||
|
||||
if (defender is PlayerMobile)
|
||||
amount /= 2;
|
||||
|
||||
ResistanceMod mod = new ResistanceMod(resistType, -amount);
|
||||
defender.AddResistanceMod(mod);
|
||||
|
||||
attacker.PrivateOverheadMessage(MessageType.Regular, 1150, 1156008, attacker.NetState); // You deliver an onslaught of sword strikes!
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.Onslaught, 1156009, 1156010, TimeSpan.FromSeconds(duration), defender, String.Format("{0}\t{1}", amount.ToString(), resistType.ToString()))); // -~2_VAL~% ~1_RESIST~ Debuff.
|
||||
|
||||
defender.FixedEffect(0x37B9, 10, 5, 632, 0);
|
||||
|
||||
if (_Table == null)
|
||||
_Table = new Dictionary<Mobile, Mobile>();
|
||||
|
||||
_Table[attacker] = defender;
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(duration), () =>
|
||||
{
|
||||
defender.RemoveResistanceMod(mod);
|
||||
_Table.Remove(attacker);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnClearMove(Mobile from)
|
||||
{
|
||||
BuffInfo.RemoveBuff(from, BuffIcon.Onslaught);
|
||||
}
|
||||
|
||||
private static Dictionary<Mobile, Mobile> _Table;
|
||||
|
||||
public static bool HasOnslaught(Mobile attacker, Mobile victim)
|
||||
{
|
||||
return _Table != null && _Table.ContainsKey(attacker) && _Table[attacker] == victim;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Scripts/Spells/Skill Masteries/PassiveMastery.cs
Normal file
31
Scripts/Spells/Skill Masteries/PassiveMastery.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class PassiveMasterySpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Passive", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public PassiveMasterySpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
130
Scripts/Spells/Skill Masteries/Pierce.cs
Normal file
130
Scripts/Spells/Skill Masteries/Pierce.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/*The fencer executes a piercing move on their opponent causing stamina drain on the
|
||||
victim based on the fencer's fencing and tactics skill, and mastery level.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class PierceSpell : SkillMasteryMove
|
||||
{
|
||||
public override int BaseMana { get { return 20; } }
|
||||
public override double RequiredSkill { get { return 90.0; } }
|
||||
|
||||
public override SkillName MoveSkill { get { return SkillName.Fencing; } }
|
||||
public override TextDefinition AbilityMessage { get { return new TextDefinition(1155991); } } // You ready yourself to pierce your opponent!
|
||||
|
||||
private Dictionary<Mobile, Timer> _Table;
|
||||
|
||||
public PierceSpell()
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Validate(Mobile from)
|
||||
{
|
||||
if (!CheckWeapon(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1156005); // You must have a fencing weapon equipped to use this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.Validate(from);
|
||||
}
|
||||
|
||||
public override void OnUse(Mobile from)
|
||||
{
|
||||
if (from.Player)
|
||||
{
|
||||
from.PlaySound(from.Female ? 0x338 : 0x44A);
|
||||
}
|
||||
else if (from is BaseCreature)
|
||||
{
|
||||
from.PlaySound(((BaseCreature)from).GetAngerSound());
|
||||
}
|
||||
|
||||
from.FixedParticles(0x376A, 1, 31, 9961, 1160, 0, EffectLayer.Waist);
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentMove(attacker);
|
||||
|
||||
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon != null && (_Table == null || !_Table.ContainsKey(attacker)))
|
||||
{
|
||||
int toDrain = (int)(attacker.Skills[MoveSkill].Value + attacker.Skills[SkillName.Tactics].Value + (MasteryInfo.GetMasteryLevel(attacker, SkillName.Fencing) * 40) / 3);
|
||||
toDrain /= 3;
|
||||
|
||||
Server.Timer t;
|
||||
|
||||
if (_Table == null)
|
||||
_Table = new Dictionary<Mobile, Timer>();
|
||||
|
||||
_Table[attacker] = t = new InternalTimer(this, attacker, defender, toDrain);
|
||||
t.Start();
|
||||
|
||||
attacker.PrivateOverheadMessage(MessageType.Regular, 1150, 1155993, attacker.NetState); // You deliver a piercing blow!
|
||||
defender.FixedEffect(0x36BD, 20, 10, 2725, 5);
|
||||
|
||||
int drain = (int)((double)defender.StamMax * ((double)toDrain / 100.0));
|
||||
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.Pierce, 1155994, 1155995, TimeSpan.FromSeconds(10), defender, (drain / 7).ToString()));
|
||||
//-~1_VAL~ Stamina Regeneration.
|
||||
}
|
||||
else
|
||||
{
|
||||
attacker.SendLocalizedMessage(1095215); // Your target is already under the effect of this attack.
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveEffects(Mobile attacker)
|
||||
{
|
||||
if (_Table != null && _Table.ContainsKey(attacker))
|
||||
{
|
||||
_Table[attacker].Stop();
|
||||
_Table.Remove(attacker);
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
public Mobile Attacker { get; private set; }
|
||||
public Mobile Defender { get; private set; }
|
||||
public PierceSpell Spell { get; private set; }
|
||||
public int ToDrain { get; private set; }
|
||||
public int Ticks { get; private set; }
|
||||
|
||||
public InternalTimer(PierceSpell spell, Mobile attacker, Mobile defender, int toDrain)
|
||||
: base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))
|
||||
{
|
||||
Spell = spell;
|
||||
Attacker = attacker;
|
||||
Defender = defender;
|
||||
ToDrain = toDrain;
|
||||
|
||||
Ticks = 0;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (!Defender.Alive || Ticks >= 10)
|
||||
{
|
||||
Spell.RemoveEffects(Attacker);
|
||||
return;
|
||||
}
|
||||
|
||||
Ticks++;
|
||||
Defender.Stam = Math.Max(0, Defender.Stam - ((ToDrain / 10) + Utility.RandomMinMax(-2, 2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
187
Scripts/Spells/Skill Masteries/PlayingTheOdds.cs
Normal file
187
Scripts/Spells/Skill Masteries/PlayingTheOdds.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class PlayingTheOddsSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Playing the Odds", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override double UpKeep { get { return 0; } } // get
|
||||
public override int RequiredMana { get { return 25; } }
|
||||
public override bool PartyEffects { get { return true; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Archery; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Tactics; } }
|
||||
|
||||
private int _HCIBonus;
|
||||
private int _SSIBonus;
|
||||
|
||||
public PlayingTheOddsSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
base.SendCastEffect();
|
||||
|
||||
Effects.SendTargetParticles(Caster, 0x3709, 10, 30, 2728, 0, 9907, EffectLayer.LeftFoot, 0);
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (IsInCooldown(Caster, this.GetType()))
|
||||
return false;
|
||||
|
||||
if (!CheckWeapon())
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156000); // You must have an Archery weapon to use this ability!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SkillMasterySpell.UnderPartyEffects(Caster, typeof(PlayingTheOddsSpell)))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1062945); // That ability is already in effect.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
BaseWeapon wep = GetWeapon();
|
||||
|
||||
if (wep != null && CheckSequence())
|
||||
{
|
||||
wep.PlaySwingAnimation(Caster);
|
||||
|
||||
double skill = (Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value) / 2;
|
||||
TimeSpan duration = TimeSpan.FromMinutes(1);
|
||||
|
||||
_HCIBonus = (int)Math.Max(45, skill / 2.667);
|
||||
_SSIBonus = (int)Math.Max(30, skill / 4);
|
||||
|
||||
string args = String.Format("{0}\t{1}\t{2}", Caster.Name, _HCIBonus.ToString(), _SSIBonus.ToString());
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.PlayingTheOddsDebuff, 1155913, 1156091, duration, Caster));
|
||||
//Your bow range has been reduced as you play the odds.
|
||||
|
||||
UpdateParty(true);
|
||||
|
||||
Caster.SendLocalizedMessage(1156091); // Your bow range has been reduced as you play the odds.
|
||||
|
||||
Expires = DateTime.UtcNow + duration;
|
||||
BeginTimer();
|
||||
|
||||
AddToCooldown(TimeSpan.FromSeconds(90));
|
||||
|
||||
foreach (var mob in AcquireIndirectTargets(Caster.Location, 5).OfType<Mobile>())
|
||||
{
|
||||
if (HitLower.ApplyDefense(mob))
|
||||
{
|
||||
if (wep is BaseRanged && !(wep is BaseThrown))
|
||||
Caster.MovingEffect(mob, ((BaseRanged)wep).EffectID, 18, 1, false, false);
|
||||
|
||||
mob.PlaySound(0x28E);
|
||||
Effects.SendTargetEffect(mob, 0x37BE, 1, 4, 0x23, 3);
|
||||
|
||||
Caster.DoHarmful(mob);
|
||||
}
|
||||
}
|
||||
|
||||
wep.InvalidateProperties();
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void AddPartyEffects(Mobile m)
|
||||
{
|
||||
m.PlaySound(0x101);
|
||||
m.FixedEffect(0x13B2, 10, 20, 2728, 5);
|
||||
m.FixedEffect(0x37C4, 10, 20, 2728, 5);
|
||||
|
||||
if (m != Caster)
|
||||
{
|
||||
string args = String.Format("{0}\t{1}\t{2}", Caster.Name, _HCIBonus.ToString(), _SSIBonus.ToString());
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.PlayingTheOdds, 1155913, 1155998, Expires - DateTime.UtcNow, m, args));
|
||||
//~1_NAME~ grants you the following:<br>+~2_VAl~% Hit Chance Increase.<br>+~3_VAL~% Swing Speed Increase.
|
||||
}
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
if (PartyList != null)
|
||||
{
|
||||
foreach(var m in PartyList)
|
||||
{
|
||||
RemovePartyEffects(m);
|
||||
}
|
||||
}
|
||||
|
||||
BaseWeapon wep = GetWeapon();
|
||||
|
||||
if (wep != null)
|
||||
wep.InvalidateProperties();
|
||||
|
||||
RemovePartyEffects(Caster);
|
||||
Caster.SendLocalizedMessage(1156092); // Your bow range has returned to normal.
|
||||
}
|
||||
|
||||
public override void RemovePartyEffects(Mobile m)
|
||||
{
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.PlayingTheOdds);
|
||||
}
|
||||
|
||||
public static int HitChanceBonus(Mobile m)
|
||||
{
|
||||
PlayingTheOddsSpell spell = GetSpellForParty(m, typeof(PlayingTheOddsSpell)) as PlayingTheOddsSpell;
|
||||
|
||||
if (spell != null)
|
||||
return spell._HCIBonus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int SwingSpeedBonus(Mobile m)
|
||||
{
|
||||
PlayingTheOddsSpell spell = GetSpellForParty(m, typeof(PlayingTheOddsSpell)) as PlayingTheOddsSpell;
|
||||
|
||||
if (spell != null)
|
||||
return spell._SSIBonus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int RangeModifier(BaseWeapon weapon)
|
||||
{
|
||||
if (weapon is BaseRanged && !(weapon is BaseThrown))
|
||||
{
|
||||
Mobile m = weapon.RootParent as Mobile;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
PlayingTheOddsSpell spell = GetSpell(m, typeof(PlayingTheOddsSpell)) as PlayingTheOddsSpell;
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
return weapon.DefMaxRange / 2;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return weapon.DefMaxRange;
|
||||
}
|
||||
}
|
||||
}
|
||||
220
Scripts/Spells/Skill Masteries/Rampage.cs
Normal file
220
Scripts/Spells/Skill Masteries/Rampage.cs
Normal file
@@ -0,0 +1,220 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
|
||||
// Check: Wrestling, poisoning and parry masteries. In but not tested.
|
||||
|
||||
/*The wrestler attempts to continually hit their opponent where with each successful hit the wrestler receives a
|
||||
bonus to hit point regeneration, stamina regeneration, casting focus, and swing speed increase based on mastery level.
|
||||
The effect is lost if the wrestler misses, the wrestler's opponent parries the attack, or fails to cast a spell.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class RampageSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Rampage", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override int RequiredMana { get { return 20; } }
|
||||
public override int DamageThreshold { get { return 1; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Wrestling; } }
|
||||
|
||||
public RampageSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
BaseWeapon wep = GetWeapon();
|
||||
|
||||
if(Caster.Player && (wep == null || !(wep is Fists)))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1155979); // You may not wield a weapon and use this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnBeginCast()
|
||||
{
|
||||
base.OnBeginCast();
|
||||
|
||||
if (!HasSpell(Caster, this.GetType()))
|
||||
{
|
||||
Caster.PrivateOverheadMessage(MessageType.Regular, 1150, 1155890, Caster.NetState); // *You attempt channel your wrestling mastery into a fit of rage!*
|
||||
|
||||
if (Caster.Player)
|
||||
{
|
||||
Caster.PlaySound(Caster.Female ? 0x338 : 0x44A);
|
||||
}
|
||||
else if(Caster is BaseCreature)
|
||||
{
|
||||
Caster.PlaySound(((BaseCreature)Caster).GetAngerSound());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
RampageSpell spell = GetSpell(Caster, typeof(RampageSpell)) as RampageSpell;
|
||||
|
||||
if (spell != null)
|
||||
spell.Expire();
|
||||
else if(CheckSequence())
|
||||
{
|
||||
Effects.SendTargetParticles(Caster, 0x37CC, 1, 40, 2724, 5, 9907, EffectLayer.LeftFoot, 0);
|
||||
Caster.PlaySound(0x101);
|
||||
|
||||
TimeSpan duration = TimeSpan.FromSeconds(60);
|
||||
|
||||
Expires = DateTime.UtcNow + duration;
|
||||
BeginTimer();
|
||||
|
||||
AddToTable();
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public void AddToTable()
|
||||
{
|
||||
if (_Table == null)
|
||||
_Table = new Dictionary<Mobile, RampageContext>();
|
||||
|
||||
RampageContext c;
|
||||
|
||||
_Table[Caster] = c = new RampageContext(this);
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Rampage, 1155929, 1155893, TimeSpan.FromSeconds(60), Caster,
|
||||
String.Format("{0}\t{1}\t{1}\t{1}\t{2}\t{3}\t{4}\t{5}",
|
||||
(1 + GetMasteryLevel()).ToString(),
|
||||
GetMasteryLevel().ToString(),
|
||||
c.HitsRegen.ToString(),
|
||||
c.StamRegen.ToString(),
|
||||
c.SwingSpeed.ToString(),
|
||||
c.Focus.ToString()
|
||||
)));
|
||||
//Each successful hit or offensive spell grants:<br>+~1_VAL~ Hit Point Regeneration<br>+~2_VAL~ Stamina Regeneration<br>+~3_VAL~ Swing Speed Increase.<br>+~4_VAL~ Casting Focus.<br>(Once you miss your target this buff will end)<br>Current totals:<br>+~5_VAL~ Hit Point Regeneration<br>+~6_VAL~ Stamina Regeneration<br>+~7_VAL~ Swing Speed Increase.<br>+~8_VAL~ Casting Focus.<br>
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
RemoveFromTable(Caster);
|
||||
}
|
||||
|
||||
public override void OnGotParried(Mobile defender)
|
||||
{
|
||||
RemoveFromTable(Caster);
|
||||
Expire();
|
||||
}
|
||||
|
||||
public override void OnMiss(Mobile defender)
|
||||
{
|
||||
RemoveFromTable(Caster);
|
||||
Expire();
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile defender, ref int damage)
|
||||
{
|
||||
if (_Table != null && _Table.ContainsKey(Caster))
|
||||
{
|
||||
Caster.PlaySound(0x3B4);
|
||||
|
||||
RampageContext c = _Table[Caster];
|
||||
c.IncreaseBuffs();
|
||||
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.Rampage);
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Rampage, 1155929, 1155893, TimeSpan.FromSeconds(60), Caster,
|
||||
String.Format("{0}\t{1}\t{1}\t{1}\t{2}\t{3}\t{4}\t{5}",
|
||||
(1 + GetMasteryLevel()).ToString(),
|
||||
GetMasteryLevel().ToString(),
|
||||
c.HitsRegen.ToString(),
|
||||
c.StamRegen.ToString(),
|
||||
c.SwingSpeed.ToString(),
|
||||
c.Focus.ToString()
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
public static bool RemoveFromTable(Mobile m)
|
||||
{
|
||||
bool removed = false;
|
||||
|
||||
if(_Table != null && _Table.ContainsKey(m))
|
||||
{
|
||||
removed = true;
|
||||
_Table.Remove(m);
|
||||
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Rampage);
|
||||
}
|
||||
|
||||
if(_Table != null && _Table.Count == 0)
|
||||
_Table = null;
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
public static int GetBonus(Mobile m, BonusType type)
|
||||
{
|
||||
if(_Table == null || !_Table.ContainsKey(m))
|
||||
return 0;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
default:
|
||||
case BonusType.HitPointRegen: return _Table[m].HitsRegen;
|
||||
case BonusType.StamRegen: return _Table[m].StamRegen;
|
||||
case BonusType.Focus: return _Table[m].Focus;
|
||||
case BonusType.SwingSpeed: return _Table[m].SwingSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<Mobile, RampageContext> _Table;
|
||||
|
||||
public enum BonusType
|
||||
{
|
||||
HitPointRegen,
|
||||
StamRegen,
|
||||
Focus,
|
||||
SwingSpeed
|
||||
}
|
||||
|
||||
private class RampageContext
|
||||
{
|
||||
public RampageSpell Spell { get; set; }
|
||||
|
||||
public int HitsRegen { get; set; }
|
||||
public int StamRegen { get; set; }
|
||||
public int Focus { get; set; }
|
||||
public int SwingSpeed { get; set; }
|
||||
|
||||
private const int _HitsMax = 18;
|
||||
private const int _StamMax = 24;
|
||||
private const int _SwingMax = 60;
|
||||
private const int _FocusMax = 12;
|
||||
|
||||
public RampageContext(RampageSpell spell)
|
||||
{
|
||||
Spell = spell;
|
||||
}
|
||||
|
||||
public void IncreaseBuffs()
|
||||
{
|
||||
HitsRegen = Math.Min(_HitsMax, HitsRegen + (1 + Spell.GetMasteryLevel()));
|
||||
StamRegen = Math.Min(_StamMax, StamRegen + Spell.GetMasteryLevel());
|
||||
Focus = Math.Min(_FocusMax, Focus + Spell.GetMasteryLevel());
|
||||
SwingSpeed = Math.Min(_SwingMax, SwingSpeed + Spell.GetMasteryLevel());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
215
Scripts/Spells/Skill Masteries/Rejuvinate.cs
Normal file
215
Scripts/Spells/Skill Masteries/Rejuvinate.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Spells.Necromancy;
|
||||
using Server.Spells.First;
|
||||
using Server.Spells.Fourth;
|
||||
using Server.Items;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class RejuvinateSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Rejuvinate", "In Vas Ort Grav Mani",
|
||||
204,
|
||||
9061
|
||||
);
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override double UpKeep { get { return 0; } }
|
||||
public override int RequiredMana { get { return 10; } }
|
||||
|
||||
public int RequiredTithing { get { return 100; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Chivalry; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Chivalry; } }
|
||||
|
||||
public RejuvinateSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.FixedEffect(0x37C4, 87, (int)(GetCastDelay().TotalSeconds * 28), 4, 3);
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (Caster is PlayerMobile && (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;
|
||||
}
|
||||
|
||||
BaseWeapon weapon = GetWeapon();
|
||||
|
||||
if (weapon == null)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156006); // You must have a swordsmanship weapon equipped to use this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new MasteryTarget(this);
|
||||
}
|
||||
|
||||
protected override void OnTarget(object o)
|
||||
{
|
||||
Mobile m = o as Mobile;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
if (m.IsDeadBondedPet)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1046439); // That is not a valid target.
|
||||
}
|
||||
else if (m is BaseCreature && ((BaseCreature)m).IsAnimatedDead)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1046439); // That is not a valid target.
|
||||
}
|
||||
else if (m is Golem)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1046439); // That is not a valid target.
|
||||
}
|
||||
else if (m.Hits > m.HitsMax && m.Stam >= m.StamMax && m.Mana >= m.ManaMax)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1155788); // Your target is already at full health, mana and stamina!
|
||||
}
|
||||
else if (CheckBSequence(m))
|
||||
{
|
||||
double rejuv = ((double)GetMasteryLevel() * 33.3) / 100;
|
||||
|
||||
if (rejuv > 1.0) rejuv = 1.0;
|
||||
|
||||
int hitsNeeds = m.HitsMax - m.Hits;
|
||||
int stamNeeds = m.StamMax - m.Stam;
|
||||
int manaNeeds = m.ManaMax - m.Mana;
|
||||
|
||||
int toRejuv = 0;
|
||||
|
||||
if (hitsNeeds > 0)
|
||||
{
|
||||
toRejuv = (int)Math.Ceiling(hitsNeeds * rejuv);
|
||||
|
||||
if (toRejuv > 0)
|
||||
SpellHelper.Heal(toRejuv, m, Caster, false);
|
||||
}
|
||||
|
||||
if (stamNeeds > 0)
|
||||
{
|
||||
toRejuv = (int)Math.Ceiling(stamNeeds * rejuv);
|
||||
|
||||
if (toRejuv > 0)
|
||||
m.Stam += toRejuv;
|
||||
}
|
||||
|
||||
if (manaNeeds > 0)
|
||||
{
|
||||
toRejuv = (int)Math.Ceiling(manaNeeds * rejuv);
|
||||
|
||||
if (toRejuv > 0)
|
||||
m.Mana += toRejuv;
|
||||
}
|
||||
|
||||
if (Caster.Karma > Utility.Random(5000))
|
||||
{
|
||||
if (m.Poison != null)
|
||||
m.CurePoison(Caster);
|
||||
|
||||
StatMod mod;
|
||||
|
||||
mod = m.GetStatMod("[Magic] Str Offset");
|
||||
if (mod != null && mod.Offset < 0)
|
||||
m.RemoveStatMod("[Magic] Str Offset");
|
||||
|
||||
mod = m.GetStatMod("[Magic] Dex Offset");
|
||||
if (mod != null && mod.Offset < 0)
|
||||
m.RemoveStatMod("[Magic] Dex Offset");
|
||||
|
||||
mod = m.GetStatMod("[Magic] Int Offset");
|
||||
if (mod != null && mod.Offset < 0)
|
||||
m.RemoveStatMod("[Magic] Int Offset");
|
||||
|
||||
m.Paralyzed = false;
|
||||
|
||||
EvilOmenSpell.TryEndEffect(m);
|
||||
StrangleSpell.RemoveCurse(m);
|
||||
CorpseSkinSpell.RemoveCurse(m);
|
||||
CurseSpell.RemoveEffect(m);
|
||||
MortalStrike.EndWound(m);
|
||||
BloodOathSpell.RemoveCurse(m);
|
||||
MindRotSpell.ClearMindRotScalar(m);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Caster.PlaySound(0x102);
|
||||
|
||||
m.SendLocalizedMessage(1155789); // You feel completely rejuvenated!
|
||||
|
||||
if (Caster != m)
|
||||
{
|
||||
m.PlaySound(0x102);
|
||||
Caster.SendLocalizedMessage(1155790); // Your target has been rejuvenated!
|
||||
}
|
||||
|
||||
int skill = ((int)Caster.Skills[CastSkill].Value + GetWeaponSkill() + GetMasteryLevel() * 40) / 3;
|
||||
int duration;
|
||||
|
||||
if (skill >= 120)
|
||||
duration = 60;
|
||||
else if (skill >= 110)
|
||||
duration = 120;
|
||||
else
|
||||
duration = 180;
|
||||
|
||||
TimeSpan d;
|
||||
|
||||
if(Caster.AccessLevel == AccessLevel.Player)
|
||||
d = TimeSpan.FromMinutes(duration);
|
||||
else
|
||||
d = TimeSpan.FromSeconds(10);
|
||||
|
||||
AddToCooldown(d);
|
||||
}
|
||||
}
|
||||
else
|
||||
Caster.SendLocalizedMessage(1046439); // That is not a valid target.
|
||||
}
|
||||
|
||||
public override bool CheckSequence()
|
||||
{
|
||||
int requiredTithing = this.RequiredTithing;
|
||||
|
||||
if (Caster is PlayerMobile && (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;
|
||||
}
|
||||
|
||||
if (AosAttributes.GetValue(Caster, AosAttribute.LowerRegCost) > Utility.Random(100))
|
||||
requiredTithing = 0;
|
||||
|
||||
if (requiredTithing > 0 && Caster is PlayerMobile)
|
||||
Caster.TithingPoints -= requiredTithing;
|
||||
|
||||
return base.CheckSequence();
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Scripts/Spells/Skill Masteries/Shadow.cs
Normal file
78
Scripts/Spells/Skill Masteries/Shadow.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class ShadowSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Shadow", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double UpKeep { get { return 4; } }
|
||||
public override int RequiredMana { get { return 10; } }
|
||||
public override bool RevealOnTick { get { return false; } }
|
||||
public override bool RevealOnCast { get { return false; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Ninjitsu; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Stealth; } }
|
||||
|
||||
public ShadowSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
SkillMasterySpell spell = GetSpell(Caster, this.GetType());
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.Shadow);
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
Caster.FixedParticles(0x3709, 10, 30, 5052, 2050, 7, EffectLayer.LeftFoot, 0);
|
||||
Caster.PlaySound(0x22F);
|
||||
|
||||
double skill = (Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value + (GetMasteryLevel() * 40)) / 3;
|
||||
int duration = (int)(skill / 3.4);
|
||||
|
||||
Expires = DateTime.UtcNow + TimeSpan.FromSeconds(duration);
|
||||
BeginTimer();
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Shadow, 1155910, 1156059, TimeSpan.FromSeconds(duration), Caster)); // Increases difficulty to be detected while hidden. <br>Increases difficulty to unhide from taking damage.
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public static double GetDifficultyFactor(Mobile m)
|
||||
{
|
||||
ShadowSpell spell = GetSpell(m, typeof(ShadowSpell)) as ShadowSpell;
|
||||
|
||||
if(spell != null)
|
||||
return ((spell.Caster.Skills[spell.CastSkill].Value + spell.Caster.Skills[spell.DamageSkill].Value + (spell.GetMasteryLevel() * 40)) / 3) / 150;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
protected override void DoEffects()
|
||||
{
|
||||
Caster.FixedParticles(0x376A, 9, 32, 5005, 2123, 0, EffectLayer.Waist, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
184
Scripts/Spells/Skill Masteries/ShieldBash.cs
Normal file
184
Scripts/Spells/Skill Masteries/ShieldBash.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
|
||||
/*When activated the shield user will execute a shield bash on successfully hitting or parrying their opponent
|
||||
causing physical damage and paralyzing their opponent based on parry skill, best weapon skill, and mastery level.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class ShieldBashSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Shield Bash", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override int RequiredMana { get { return 40; } }
|
||||
public override bool BlocksMovement { get { return false; } }
|
||||
public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(1.0); } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Parry; } }
|
||||
|
||||
public double Multiplier { get { return (Caster.Skills[GetBestSkill()].Value + Caster.Skills[SkillName.Parry].Value + (GetMasteryLevel() * 40)) / 360; } }
|
||||
|
||||
public ShieldBashSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (!HasShield())
|
||||
return false;
|
||||
|
||||
if (HasSpell(Caster, this.GetType()))
|
||||
return false;
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
Caster.FixedParticles(0x376A, 9, 32, 5030, 1168, 0, EffectLayer.Waist, 0);
|
||||
Caster.PlaySound(0x51A);
|
||||
|
||||
TimeSpan duration = TimeSpan.FromSeconds((int)Math.Max(3, 5.0 * Multiplier));
|
||||
|
||||
Caster.SendLocalizedMessage(1156022); // You ready your shield.
|
||||
|
||||
Expires = DateTime.UtcNow + duration;
|
||||
BeginTimer();
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.ShieldBash, 1155923, 1156093, duration, Caster));
|
||||
//Places you in an offensive stance which allows you to strike your target with your shield on your next successful attack or parry.
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override bool OnTick()
|
||||
{
|
||||
if (!HasShield())
|
||||
{
|
||||
Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.OnTick();
|
||||
}
|
||||
|
||||
private bool HasShield()
|
||||
{
|
||||
if (!Caster.Player)
|
||||
return true;
|
||||
|
||||
BaseShield shield = Caster.FindItemOnLayer(Layer.TwoHanded) as BaseShield;
|
||||
|
||||
if (shield == null)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156096); // You must be wielding a shield to use this ability!
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.ShieldBash);
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile defender, ref int damage)
|
||||
{
|
||||
if (!HasShield())
|
||||
{
|
||||
Expire();
|
||||
return;
|
||||
}
|
||||
|
||||
Caster.SendLocalizedMessage(1156027); // You bash you target with your shield!
|
||||
bool pvp = Caster is PlayerMobile && defender is PlayerMobile;
|
||||
|
||||
var multiplier = Multiplier;
|
||||
|
||||
damage = pvp ? (int)(damage * (multiplier * 3)) : (int)(damage * (multiplier * 7));
|
||||
|
||||
if (pvp && damage > 35)
|
||||
damage = 35;
|
||||
|
||||
Server.Timer.DelayCall(TimeSpan.FromMilliseconds(100), () =>
|
||||
{
|
||||
if (defender.Alive)
|
||||
{
|
||||
CheckParalyze(defender, TimeSpan.FromSeconds(pvp ? multiplier * 3 : multiplier * 6));
|
||||
}
|
||||
});
|
||||
|
||||
Expire();
|
||||
}
|
||||
|
||||
private SkillName GetBestSkill()
|
||||
{
|
||||
double swrd = Caster.Skills[SkillName.Swords].Value;
|
||||
double fenc = Caster.Skills[SkillName.Fencing].Value;
|
||||
double mcng = Caster.Skills[SkillName.Macing].Value;
|
||||
double wres = Caster.Skills[SkillName.Wrestling].Value;
|
||||
|
||||
SkillName sk = SkillName.Swords;
|
||||
double val = swrd;
|
||||
|
||||
if (fenc > val)
|
||||
{
|
||||
sk = SkillName.Fencing;
|
||||
val = fenc;
|
||||
}
|
||||
if (mcng > val)
|
||||
{
|
||||
sk = SkillName.Macing;
|
||||
val = mcng;
|
||||
}
|
||||
if (wres > val)
|
||||
{
|
||||
sk = SkillName.Wrestling;
|
||||
}
|
||||
|
||||
return sk;
|
||||
}
|
||||
|
||||
private void CheckParalyze(Mobile defender, TimeSpan duration)
|
||||
{
|
||||
if (ParalyzingBlow.IsImmune(defender))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1070804); // Your target resists paralysis.
|
||||
defender.SendLocalizedMessage(1070813); // You resist paralysis.
|
||||
return;
|
||||
}
|
||||
|
||||
defender.FixedEffect(0x376A, 9, 32);
|
||||
defender.PlaySound(0x204);
|
||||
|
||||
Caster.SendLocalizedMessage(1060163); // You deliver a paralyzing blow!
|
||||
defender.SendLocalizedMessage(1060164); // The attack has temporarily paralyzed you!
|
||||
|
||||
// Treat it as paralyze not as freeze, effect must be removed when damaged.
|
||||
defender.Paralyze(duration);
|
||||
|
||||
ParalyzingBlow.BeginImmunity(defender, duration);
|
||||
}
|
||||
|
||||
public override void OnParried(Mobile attacker)
|
||||
{
|
||||
BaseWeapon wep = Caster.Weapon as BaseWeapon;
|
||||
|
||||
if (wep != null)
|
||||
wep.OnHit(Caster, attacker, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Scripts/Spells/Skill Masteries/Stagger.cs
Normal file
102
Scripts/Spells/Skill Masteries/Stagger.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class StaggerSpell : SkillMasteryMove
|
||||
{
|
||||
public override int BaseMana { get { return 20; } }
|
||||
public override double RequiredSkill { get { return 90.0; } }
|
||||
|
||||
public override SkillName MoveSkill { get { return SkillName.Macing; } }
|
||||
public override TextDefinition AbilityMessage { get { return new TextDefinition(1155980); } } // *You ready yourself to stagger your opponent!*
|
||||
public override TimeSpan CooldownPeriod { get { return TimeSpan.FromSeconds(2); } }
|
||||
|
||||
private static Dictionary<Mobile, int> _Table;
|
||||
|
||||
public StaggerSpell()
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Validate(Mobile from)
|
||||
{
|
||||
if (!CheckWeapon(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1155983); // You must have a mace weapon equipped to use this ability!
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.Validate(from);
|
||||
}
|
||||
|
||||
public override void OnUse(Mobile from)
|
||||
{
|
||||
if (from.Player)
|
||||
{
|
||||
from.PlaySound(from.Female ? 0x338 : 0x44A);
|
||||
}
|
||||
else if (from is BaseCreature)
|
||||
{
|
||||
from.PlaySound(((BaseCreature)from).GetAngerSound());
|
||||
}
|
||||
|
||||
from.FixedParticles(0x373A, 10, 15, 5018, 2719, 0, EffectLayer.Waist);
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentMove(attacker);
|
||||
|
||||
attacker.PrivateOverheadMessage(MessageType.Regular, 1150, 1155984, attacker.NetState);
|
||||
|
||||
defender.FixedEffect(0x3779, 20, 10, 2719, 0);
|
||||
|
||||
double skills = (attacker.Skills[MoveSkill].Value + attacker.Skills[SkillName.Tactics].Value + (MasteryInfo.GetMasteryLevel(attacker, MoveSkill) * 40)) / 3;
|
||||
|
||||
AddToTable(defender, (int)(skills / 2));
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.Stagger, 1155981, 1155982, TimeSpan.FromSeconds(10), defender, ((int)skills / 2).ToString()));
|
||||
|
||||
defender.Delta(MobileDelta.WeaponDamage);
|
||||
|
||||
AddToCooldown(attacker);
|
||||
}
|
||||
|
||||
public override double GetDamageScalar(Mobile attacker, Mobile defender)
|
||||
{
|
||||
return defender is PlayerMobile ? 1.25 : 1.5;
|
||||
}
|
||||
|
||||
public static void AddToTable(Mobile defender, int amount)
|
||||
{
|
||||
if (_Table != null && _Table.ContainsKey(defender))
|
||||
return;
|
||||
|
||||
if (_Table == null)
|
||||
_Table = new Dictionary<Mobile, int>();
|
||||
|
||||
_Table[defender] = amount;
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(10), () =>
|
||||
{
|
||||
_Table.Remove(defender);
|
||||
});
|
||||
}
|
||||
|
||||
public static int GetStagger(Mobile from)
|
||||
{
|
||||
if (_Table != null && _Table.ContainsKey(from))
|
||||
{
|
||||
return _Table[from];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
209
Scripts/Spells/Skill Masteries/SummonReaper.cs
Normal file
209
Scripts/Spells/Skill Masteries/SummonReaper.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
using Server.Spells.Spellweaving;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class SummonReaperSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Summon Reaper", "Lartarisstree",
|
||||
204,
|
||||
9061
|
||||
);
|
||||
|
||||
public override double RequiredSkill { get { return 90; } }
|
||||
public override double UpKeep { get { return 0; } }
|
||||
public override int RequiredMana { get { return 50; } }
|
||||
public override bool PartyEffects { get { return false; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Spellweaving; } }
|
||||
|
||||
public SummonReaperSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.FixedEffect(0x37C4, 87, (int)(GetCastDelay().TotalSeconds * 28), 1371, 2);
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (!base.CheckCast())
|
||||
return false;
|
||||
|
||||
if (Caster is PlayerMobile && !((PlayerMobile)Caster).Spellweaving)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1073220); // You must have completed the epic arcanist quest to use this ability.
|
||||
return false;
|
||||
}
|
||||
else if (Caster.Followers + 5 > Caster.FollowersMax)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
Caster.Target = new MasteryTarget(this, 10, true, Server.Targeting.TargetFlags.None);
|
||||
}
|
||||
|
||||
protected override void OnTarget(object o)
|
||||
{
|
||||
if (o is IPoint3D)
|
||||
{
|
||||
Map map = Caster.Map;
|
||||
IPoint3D p = o as IPoint3D;
|
||||
|
||||
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 = TimeSpan.FromSeconds(((Caster.Skills[CastSkill].Value + (ArcanistSpell.GetFocusLevel(Caster) * 20)) / 240) * 75);
|
||||
BaseCreature.Summon(new SummonedReaper(Caster, this), false, this.Caster, new Point3D(p), 442, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CorpseName("a reapers corpse")]
|
||||
public class SummonedReaper : BaseCreature
|
||||
{
|
||||
private int m_DispelDifficulty;
|
||||
|
||||
public override double DispelDifficulty { get { return m_DispelDifficulty; } }
|
||||
public override double DispelFocus { get { return 45.0; } }
|
||||
|
||||
private long _NextAura;
|
||||
|
||||
[Constructable]
|
||||
public SummonedReaper(Mobile caster, SummonReaperSpell spell)
|
||||
: base(AIType.AI_Spellweaving, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
Name = "a reaper";
|
||||
Body = 47;
|
||||
BaseSoundID = 442;
|
||||
|
||||
double scale = 1.0 + ((caster.Skills[spell.CastSkill].Value + (double)(spell.GetMasteryLevel() * 40) + (double)(ArcanistSpell.GetFocusLevel(caster) * 20))) / 1000.0;
|
||||
|
||||
SetStr((int)(450 * scale), (int)(500 * scale));
|
||||
SetDex((int)(130 * scale));
|
||||
SetInt((int)(247 * scale));
|
||||
|
||||
SetHits((int)(450 * scale));
|
||||
|
||||
SetDamage(16, 20);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 80);
|
||||
SetDamageType(ResistanceType.Poison, 20);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 70);
|
||||
SetResistance(ResistanceType.Fire, 15);
|
||||
SetResistance(ResistanceType.Cold, 18);
|
||||
SetResistance(ResistanceType.Poison, 100);
|
||||
SetResistance(ResistanceType.Energy, 69);
|
||||
|
||||
SetSkill(SkillName.Spellweaving, Math.Max(100, 75 * scale));
|
||||
SetSkill(SkillName.Anatomy, Math.Max(100, 75 * scale));
|
||||
SetSkill(SkillName.MagicResist, Math.Max(100, 75 * scale));
|
||||
SetSkill(SkillName.Tactics, Math.Max(100, 75 * scale));
|
||||
SetSkill(SkillName.Wrestling, Math.Max(100, 75 * scale));
|
||||
|
||||
ControlSlots = 5;
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
|
||||
{
|
||||
ArcaneFocus casterFocus = ArcanistSpell.FindArcaneFocus(caster);
|
||||
|
||||
if (casterFocus != null)
|
||||
{
|
||||
ArcaneFocus f = new ArcaneFocus(casterFocus.LifeSpan, casterFocus.StrengthBonus);
|
||||
f.CreationTime = casterFocus.CreationTime;
|
||||
f.Movable = false;
|
||||
|
||||
PackItem(f);
|
||||
}
|
||||
});
|
||||
|
||||
m_DispelDifficulty = 91 + (int)((caster.Skills[SkillName.Spellweaving].Base * 83) / 5.2);
|
||||
|
||||
_NextAura = Core.TickCount + 3000;
|
||||
SetWeaponAbility(WeaponAbility.WhirlwindAttack);
|
||||
}
|
||||
|
||||
public override Poison PoisonImmune { get { return Poison.Greater; } }
|
||||
public override bool DisallowAllMoves { get { return true; } }
|
||||
public override bool AlwaysMurderer { get { return true; } }
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
|
||||
if (_NextAura < Core.TickCount)
|
||||
{
|
||||
DoAura();
|
||||
|
||||
_NextAura = Core.TickCount + 2000;
|
||||
}
|
||||
}
|
||||
|
||||
private void DoAura()
|
||||
{
|
||||
DoEffects();
|
||||
|
||||
foreach (Mobile m in SpellHelper.AcquireIndirectTargets(this, this, Map, 4).OfType<Mobile>())
|
||||
{
|
||||
int damage = Utility.RandomMinMax(10, 20);
|
||||
|
||||
AOS.Damage( m, this, damage, 0, 0, 0, 100, 0, DamageType.SpellAOE);
|
||||
|
||||
m.RevealingAction();
|
||||
}
|
||||
}
|
||||
|
||||
private void DoEffects()
|
||||
{
|
||||
Server.Misc.Geometry.Circle2D(Location, Map, 4, (pnt, map) =>
|
||||
{
|
||||
Effects.SendLocationEffect(pnt, map, 0x3709, 0x14, 0x1, 0x8AF, 4);
|
||||
});
|
||||
|
||||
Server.Misc.Geometry.Circle2D(Location, this.Map, 5, (pnt, map) =>
|
||||
{
|
||||
Effects.SendLocationEffect(pnt, map, 0x3709, 0x14, 0x1, 0x8AF, 4);
|
||||
});
|
||||
}
|
||||
|
||||
public SummonedReaper(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
205
Scripts/Spells/Skill Masteries/Thrust.cs
Normal file
205
Scripts/Spells/Skill Masteries/Thrust.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Items;
|
||||
|
||||
/*Toggle ability that provides increased physical attack damage and decreases targets physical attack damage based on
|
||||
the mastery level of the fencer. This ability consumes mana while active. This ability does not stack with the special move Feint.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class ThrustSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Thrust", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override int RequiredMana { get { return 30; } }
|
||||
public override SkillName CastSkill { get { return SkillName.Fencing; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Tactics; } }
|
||||
|
||||
private int _DefenseMod;
|
||||
|
||||
public int AttackModifier { get { return (GetMasteryLevel() * 6) * Phase; } }
|
||||
public int DefenseModifier
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DefenseMod;
|
||||
}
|
||||
set
|
||||
{
|
||||
_DefenseMod = Math.Min((GetMasteryLevel() * 6) * 3, value);
|
||||
}
|
||||
}
|
||||
|
||||
public int DefenseModDisplayed { get { return Math.Min(18, DefenseModifier); } }
|
||||
|
||||
public int _Phase;
|
||||
public int Phase
|
||||
{
|
||||
get { return _Phase; }
|
||||
set
|
||||
{
|
||||
if (value > 3)
|
||||
_Phase = 1;
|
||||
else
|
||||
_Phase = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ThrustSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.PlaySound(0x524);
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.Thrust);
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if(!CheckWeapon())
|
||||
{
|
||||
Caster.SendLocalizedMessage(1155992); // You must have a fencing weapon equipped to use this ability!
|
||||
return false;
|
||||
}
|
||||
|
||||
ThrustSpell spell = GetSpell(Caster, this.GetType()) as ThrustSpell;
|
||||
|
||||
if(spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (!CheckSequence())
|
||||
return;
|
||||
|
||||
Phase = 1;
|
||||
DefenseModifier = GetMasteryLevel() * 6;
|
||||
|
||||
Caster.PlaySound(0x101);
|
||||
Caster.FixedEffect(0x37C4, 0x1, 0x8, 0x4EB, 0);
|
||||
|
||||
Caster.PrivateOverheadMessage(MessageType.Regular, 1150, 1155988, Caster.NetState); // *You enter a thrusting stance!*
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Thrust, 1155989, 1155990, String.Format("{0}\t{1}\t{2}", AttackModifier.ToString(), DefenseModifier.ToString(), ScaleMana(30).ToString())));
|
||||
//Your next physical attack will be increased by +~1_VAL~% damage while reducing your victim's physical attack damage by ~2_VAL~%.<br>Mana Upkeep Cost: ~3_VAL~.
|
||||
|
||||
FinishSequence();
|
||||
BeginTimer();
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile defender, ref int damage)
|
||||
{
|
||||
int currentMod = AttackModifier;
|
||||
|
||||
if(Target != defender)
|
||||
{
|
||||
Phase = 1;
|
||||
DefenseModifier = (GetMasteryLevel() * 6);
|
||||
|
||||
Target = defender;
|
||||
new InternalTimer(this, defender);
|
||||
}
|
||||
else
|
||||
{
|
||||
DefenseModifier += (GetMasteryLevel() * 6);
|
||||
Phase++;
|
||||
}
|
||||
|
||||
damage = (int)((double)damage + ((double)damage * ((double)currentMod / 100.0)));
|
||||
defender.FixedEffect(0x36BD, 0x1, 0xE, 0x776, 0);
|
||||
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.ThrustDebuff, 1155989, 1156234, TimeSpan.FromSeconds(8), defender, DefenseModifier.ToString()));
|
||||
// All damage from your physical attacks have been reduced by ~1_val~%.
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Thrust, 1155989, 1155990, String.Format("{0}\t{1}\t{2}", AttackModifier.ToString(), (GetMasteryLevel() * 6).ToString(), ScaleMana(30).ToString())));
|
||||
//Your next physical attack will be increased by +~1_VAL~% damage while reducing your victim's physical attack damage by ~2_VAL~%.<br>Mana Upkeep Cost: ~3_VAL~.
|
||||
|
||||
if (!CheckMana())
|
||||
{
|
||||
Reset();
|
||||
Expire();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGotHit(Mobile attacker, ref int damage)
|
||||
{
|
||||
if(Target == attacker && DefenseModifier > 0)
|
||||
damage = (int)((double)damage - ((double)damage * ((double)DefenseModifier / 100.0)));
|
||||
}
|
||||
|
||||
private bool CheckMana()
|
||||
{
|
||||
int mana = ScaleMana(GetMana());
|
||||
|
||||
if (Caster.Mana < mana)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Caster.Mana -= mana;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
DefenseModifier = 0;
|
||||
Target = null;
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Thrust, 1155989, 1155990, String.Format("{0}\t{1}\t{2}", AttackModifier.ToString(), (GetMasteryLevel() * 6).ToString(), ScaleMana(30).ToString())));
|
||||
//Your next physical attack will be increased by +~1_VAL~% damage while reducing your victim's physical attack damage by ~2_VAL~%.<br>Mana Upkeep Cost: ~3_VAL~.
|
||||
|
||||
if (Target != null)
|
||||
{
|
||||
BuffInfo.RemoveBuff(Target, BuffIcon.ThrustDebuff);
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
public Mobile Target { get; set; }
|
||||
public DateTime Expires { get; set; }
|
||||
public ThrustSpell Spell { get; set; }
|
||||
|
||||
public int DamageModifier { get; set; }
|
||||
|
||||
public InternalTimer(ThrustSpell spell, Mobile target)
|
||||
: base(TimeSpan.FromMilliseconds(250), TimeSpan.FromMilliseconds(250))
|
||||
{
|
||||
Target = target;
|
||||
Spell = spell;
|
||||
DamageModifier = spell.DefenseModifier;
|
||||
|
||||
Expires = DateTime.UtcNow + TimeSpan.FromSeconds(8);
|
||||
Start();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (Expires < DateTime.UtcNow)
|
||||
{
|
||||
Spell.Reset();
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
Scripts/Spells/Skill Masteries/Tolerance.cs
Normal file
85
Scripts/Spells/Skill Masteries/Tolerance.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
|
||||
/*Toggle ability that grants the poisoner a reduction to
|
||||
poison level when poisoned at a stamina cost based on mastery level.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class ToleranceSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Tolerence", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override int RequiredMana{ get { return 20; } }
|
||||
public override SkillName CastSkill { get { return SkillName.Poisoning; } }
|
||||
|
||||
public ToleranceSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
ToleranceSpell spell = GetSpell(Caster, typeof(ToleranceSpell)) as ToleranceSpell;
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if(CheckSequence())
|
||||
{
|
||||
Caster.SendSound(0xF6);
|
||||
Effects.SendTargetParticles(Caster, 0x3709, 10, 30, 1166, 0, 9907, EffectLayer.LeftFoot, 0);
|
||||
|
||||
BeginTimer();
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Tolerance, 1155926, 1156063)); // Reduces poison strength when poisoned at the cost of stamina.
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.Tolerance);
|
||||
}
|
||||
|
||||
public static bool OnPoisonApplied(Mobile m)
|
||||
{
|
||||
ToleranceSpell spell = GetSpell(m, typeof(ToleranceSpell)) as ToleranceSpell;
|
||||
|
||||
if(spell != null)
|
||||
{
|
||||
double stamCost = (m.Skills[spell.CastSkill].Base + ((MasteryInfo.GetMasteryLevel(m, SkillName.Poisoning) * 30) + 10)) / 2;
|
||||
|
||||
stamCost /= 4;
|
||||
stamCost = Math.Max(18, (25 - stamCost) + 18);
|
||||
|
||||
if(m.Stam < (int)stamCost)
|
||||
{
|
||||
spell.Caster.SendLocalizedMessage(1156036, ((int)stamCost).ToString()); // You must have at least ~1_STAM_REQUIREMENT~ Stamina to use this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
spell.Caster.Stam -= (int)stamCost;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
93
Scripts/Spells/Skill Masteries/Toughness.cs
Normal file
93
Scripts/Spells/Skill Masteries/Toughness.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class ToughnessSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Toughness", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override double UpKeep { get { return 20; } }
|
||||
public override int RequiredMana { get { return 20; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Macing; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Tactics; } }
|
||||
|
||||
private int _HPBonus;
|
||||
|
||||
public ToughnessSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (!CheckWeapon())
|
||||
{
|
||||
Caster.SendLocalizedMessage(1155983); // You must have a mace weapon equipped to use this ability!
|
||||
return false;
|
||||
}
|
||||
|
||||
ToughnessSpell spell = GetSpell(Caster, this.GetType()) as ToughnessSpell;
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
spell.Expire();
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
if (Caster.Player)
|
||||
{
|
||||
Caster.PlaySound(Caster.Female ? 0x338 : 0x44A);
|
||||
}
|
||||
else if (Caster is BaseCreature)
|
||||
{
|
||||
Caster.PlaySound(((BaseCreature)Caster).GetAngerSound());
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
Effects.SendTargetParticles(Caster, 0x37CC, 1, 40, 1953, 0, 9907, EffectLayer.LeftFoot, 0);
|
||||
Caster.PlaySound(0x1EE);
|
||||
|
||||
_HPBonus = (int)(BaseSkillBonus / 4);
|
||||
|
||||
BeginTimer();
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Toughness, 1155985, 1155986, String.Format("{0}\t{1}", _HPBonus.ToString(), ScaleMana((int)UpKeep)))); // Hit Point Increase: ~1_VAL~.<br>Mana Upkeep Cost: ~2_VAL~.
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public override void EndEffects()
|
||||
{
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.Toughness);
|
||||
}
|
||||
|
||||
public static int GetHPBonus(Mobile m)
|
||||
{
|
||||
ToughnessSpell spell = GetSpell(m, typeof(ToughnessSpell)) as ToughnessSpell;
|
||||
|
||||
if (spell != null)
|
||||
return spell._HPBonus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Scripts/Spells/Skill Masteries/Warcry.cs
Normal file
91
Scripts/Spells/Skill Masteries/Warcry.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using Server;
|
||||
using System.Collections.Generic;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class WarcrySpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
|
||||
"Warcry", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override int RequiredMana { get { return 40; } }
|
||||
public override SkillName CastSkill { get { return SkillName.Bushido; } }
|
||||
|
||||
private int _DamageMalus;
|
||||
private int _Radius;
|
||||
|
||||
public WarcrySpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (CheckSequence())
|
||||
{
|
||||
int skill = (int)(Caster.Skills[CastSkill].Value + GetWeaponSkill() + (GetMasteryLevel() * 40)) / 3;
|
||||
|
||||
_Radius = skill / 40;
|
||||
_DamageMalus = (int)((double)skill / 2.4);
|
||||
|
||||
Caster.PublicOverheadMessage(MessageType.Regular, Caster.SpeechHue, false, "Prepare Yourself!");
|
||||
|
||||
if (Caster.Player)
|
||||
{
|
||||
Caster.PlaySound(Caster.Female ? 0x338 : 0x44A);
|
||||
}
|
||||
else if (Caster is BaseCreature)
|
||||
{
|
||||
Caster.PlaySound(((BaseCreature)Caster).GetAngerSound());
|
||||
}
|
||||
|
||||
TimeSpan d;
|
||||
|
||||
if (Caster.AccessLevel == AccessLevel.Player)
|
||||
d = TimeSpan.FromMinutes(20);
|
||||
else
|
||||
d = TimeSpan.FromSeconds(10);
|
||||
|
||||
AddToCooldown(d);
|
||||
|
||||
Expires = DateTime.UtcNow + TimeSpan.FromSeconds(10);
|
||||
BeginTimer();
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Warcry, 1155906, 1156058, TimeSpan.FromSeconds(10), Caster, String.Format("{0}\t{1}", _Radius.ToString(), _DamageMalus.ToString())));
|
||||
//Reduces all incoming attack damage from opponents who hear the war cry within ~1_RANGE~ tiles by ~2_val~%.
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
//public override void OnGotHit(Mobile attacker, ref int damage)
|
||||
public override void OnDamaged(Mobile attacker, Mobile victim, DamageType type, ref int damage)
|
||||
{
|
||||
if (attacker.InRange(Caster, _Radius))
|
||||
{
|
||||
damage -= (int)((double)damage * ((double)_DamageMalus / 100.00));
|
||||
|
||||
if (Caster.Player)
|
||||
{
|
||||
Caster.PlaySound(attacker.Female ? 0x338 : 0x44A);
|
||||
}
|
||||
else if (Caster is BaseCreature)
|
||||
{
|
||||
Caster.PlaySound(((BaseCreature)Caster).GetAngerSound());
|
||||
}
|
||||
|
||||
Caster.FixedEffect(0x3779, 10, 20, 1372, 4);
|
||||
|
||||
//Caster.SendLocalizedMessage(1156161, attacker.Name); // ~1_NAME~ attacks you for 50% damage.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Scripts/Spells/Skill Masteries/Whispering.cs
Normal file
98
Scripts/Spells/Skill Masteries/Whispering.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using System.Linq;
|
||||
using Server.Items;
|
||||
|
||||
/*The animal tamer attempts to guide their pet on the path of skill gain, increasing the pet's skill gains based on the tamer's
|
||||
animal taming skill, animal lore skill, and mastery level. This ability functions similarly to a scroll of alacrity.*/
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class WhisperingSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"Whispering", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override int RequiredMana { get { return 40; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.AnimalTaming; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.AnimalLore; } }
|
||||
public override bool RevealOnTick { get { return false; } }
|
||||
|
||||
private int _EnhancedGainChance;
|
||||
public int EnhancedGainChance { get { return _EnhancedGainChance; } }
|
||||
|
||||
public WhisperingSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if(IsInCooldown(Caster, this.GetType()))
|
||||
return false;
|
||||
|
||||
if(GetSpell(Caster, this.GetType()) != null) // does this expire or not let you cast it again?>
|
||||
{
|
||||
Caster.SendLocalizedMessage(1155889); // You are already under the effect of this ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Caster is PlayerMobile && ((PlayerMobile)Caster).AllFollowers == null || ((PlayerMobile)Caster).AllFollowers.Where(m => !(m is Server.Engines.Despise.DespiseCreature)).Count() == 0)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1156112); // This ability requires you to have pets.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
base.SendCastEffect();
|
||||
|
||||
Caster.PrivateOverheadMessage(MessageType.Regular, 0x35, false, "You guide your pet's behaviors, enhancing its skill gains!", Caster.NetState);
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if(CheckSequence())
|
||||
{
|
||||
if (Caster is PlayerMobile)
|
||||
{
|
||||
foreach (Mobile m in ((PlayerMobile)Caster).AllFollowers.Where(m => m.Map == Caster.Map && Caster.InRange(m.Location, PartyRange) && !(m is Server.Engines.Despise.DespiseCreature)))
|
||||
{
|
||||
Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0, 0, 0, 0, 0, 5060, 0);
|
||||
Effects.PlaySound(m.Location, m.Map, 0x243);
|
||||
|
||||
Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(m.X - 6, m.Y - 6, m.Z + 15), m.Map), m, 0x36D4, 7, 0, false, true, 1494, 0, 9502, 1, 0, (EffectLayer)255, 0x100);
|
||||
Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(m.X - 4, m.Y - 6, m.Z + 15), m.Map), m, 0x36D4, 7, 0, false, true, 1494, 0, 9502, 1, 0, (EffectLayer)255, 0x100);
|
||||
Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(m.X - 6, m.Y - 4, m.Z + 15), m.Map), m, 0x36D4, 7, 0, false, true, 1494, 0, 9502, 1, 0, (EffectLayer)255, 0x100);
|
||||
|
||||
Effects.SendTargetParticles(m, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
|
||||
}
|
||||
}
|
||||
|
||||
Caster.SendSound(0x64E);
|
||||
|
||||
TimeSpan duration = TimeSpan.FromSeconds(600);
|
||||
Expires = DateTime.UtcNow + duration;
|
||||
BeginTimer();
|
||||
|
||||
_EnhancedGainChance = (int)(BaseSkillBonus / 1.26);
|
||||
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Whispering, 1155932, 1156106, duration, Caster, _EnhancedGainChance.ToString()));
|
||||
|
||||
AddToCooldown(TimeSpan.FromMinutes(30));
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
}
|
||||
}
|
||||
236
Scripts/Spells/Skill Masteries/WhiteTigerForm.cs
Normal file
236
Scripts/Spells/Skill Masteries/WhiteTigerForm.cs
Normal file
@@ -0,0 +1,236 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
using Server.Spells.Ninjitsu;
|
||||
using Server.Spells.Seventh;
|
||||
using Server.Spells.Sixth;
|
||||
using Server.Spells.Fifth;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Spells.SkillMasteries
|
||||
{
|
||||
public class WhiteTigerFormSpell : SkillMasterySpell
|
||||
{
|
||||
private static SpellInfo m_Info = new SpellInfo(
|
||||
"White Tiger Form", "",
|
||||
-1,
|
||||
9002
|
||||
);
|
||||
|
||||
public override int RequiredMana { get { return 10; } }
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Ninjitsu; } }
|
||||
public override SkillName DamageSkill { get { return SkillName.Stealth; } }
|
||||
|
||||
public override bool BlockedByAnimalForm { get { return false; } }
|
||||
public override bool BlocksMovement { get { return false; } }
|
||||
public override int CastRecoveryBase { get { return (Core.ML ? 10 : base.CastRecoveryBase); } }
|
||||
|
||||
public WhiteTigerFormSpell(Mobile caster, Item scroll)
|
||||
: base(caster, scroll, m_Info)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SendCastEffect()
|
||||
{
|
||||
Caster.FixedEffect(0x37C4, 87, (int)(GetCastDelay().TotalSeconds * 28), 0x66C, 3);
|
||||
}
|
||||
|
||||
public static void AutoCast(Mobile m)
|
||||
{
|
||||
var spell = new WhiteTigerFormSpell(m, null);
|
||||
spell.Cast();
|
||||
}
|
||||
|
||||
public override bool CheckCast()
|
||||
{
|
||||
if (!Caster.CanBeginAction(typeof(PolymorphSpell)))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed.
|
||||
return false;
|
||||
}
|
||||
else if (TransformationSpellHelper.UnderTransformation(Caster))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1063219); // You cannot mimic an animal while in that form.
|
||||
return false;
|
||||
}
|
||||
else if (DisguiseTimers.IsDisguised(Caster))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1061631); // You can't do that while disguised.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckCast();
|
||||
}
|
||||
|
||||
public override bool CheckFizzle()
|
||||
{
|
||||
// Spell is initially always successful, and with no skill gain.
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnCast()
|
||||
{
|
||||
if (!Caster.CanBeginAction(typeof(PolymorphSpell)))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed.
|
||||
}
|
||||
else if (TransformationSpellHelper.UnderTransformation(Caster))
|
||||
{
|
||||
Caster.SendLocalizedMessage(1063219); // You cannot mimic an animal while in that form.
|
||||
}
|
||||
else if (!Caster.CanBeginAction(typeof(IncognitoSpell)) || (Caster.IsBodyMod && AnimalForm.GetContext(Caster) == null))
|
||||
{
|
||||
DoFizzle();
|
||||
}
|
||||
else if (CheckSequence())
|
||||
{
|
||||
AnimalFormContext context = AnimalForm.GetContext(Caster);
|
||||
int mana = ScaleMana(RequiredMana);
|
||||
|
||||
Ninjitsu.AnimalForm.AddLastAnimalForm(Caster, 16);
|
||||
|
||||
if (mana > Caster.Mana)
|
||||
{
|
||||
Caster.SendLocalizedMessage(1060174, mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
|
||||
}
|
||||
else if (context != null)
|
||||
{
|
||||
AnimalForm.RemoveContext(Caster, context, true);
|
||||
Caster.Mana -= mana;
|
||||
|
||||
BuffInfo.RemoveBuff(Caster, BuffIcon.WhiteTigerForm);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
double ninjitsu = Caster.Skills.Ninjitsu.Value;
|
||||
|
||||
if (ninjitsu < RequiredSkill + 37.5)
|
||||
{
|
||||
double chance = (ninjitsu - RequiredSkill) / 37.5;
|
||||
|
||||
if (chance < Utility.RandomDouble())
|
||||
{
|
||||
DoFizzle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist);
|
||||
Caster.Mana -= mana;
|
||||
|
||||
Caster.CheckSkill(SkillName.Ninjitsu, 0.0, 90.0);
|
||||
|
||||
BaseMount.Dismount(Caster);
|
||||
|
||||
int bodyMod = Caster.Female ? 1255 : 1254;
|
||||
int hueMod = 2500;
|
||||
|
||||
Caster.BodyMod = bodyMod;
|
||||
Caster.HueMod = hueMod;
|
||||
|
||||
Caster.SendSpeedControl(SpeedControlType.MountSpeed);
|
||||
|
||||
Timer timer = new AnimalFormTimer(Caster, bodyMod, hueMod);
|
||||
timer.Start();
|
||||
|
||||
int skills = (int)((Caster.Skills[CastSkill].Value + Caster.Skills[DamageSkill].Value + (GetMasteryLevel() * 40)) / 3);
|
||||
|
||||
AnimalForm.AddContext(Caster, new AnimalFormContext(timer, null, true, typeof(WildWhiteTiger), null));
|
||||
Caster.CheckStatTimers();
|
||||
|
||||
int bleedMod = (int)(((Caster.Skills[SkillName.Ninjitsu].Value + Caster.Skills[SkillName.Stealth].Value + (GetMasteryLevel() * 40)) / 3) / 10);
|
||||
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.WhiteTigerForm, 1155911, 1156060, String.Format("{0}\t{1}\t{2}\t{3}", "20", "5", "", bleedMod.ToString())));
|
||||
// +~1_ARG~ Defense Chance Increase.<br>+~2_ARG~ Max Defense Chance Increase Cap.<br> Chance to evade attacks.<br>Applies bleed to victim with a max damage of ~4_ARG~.
|
||||
|
||||
Caster.Delta(MobileDelta.WeaponDamage);
|
||||
}
|
||||
|
||||
FinishSequence();
|
||||
}
|
||||
|
||||
public static bool CheckEvasion(Mobile m)
|
||||
{
|
||||
if (IsActive(m))
|
||||
return MasteryInfo.GetMasteryLevel(m, SkillName.Ninjitsu) + 2 > Utility.Random(100);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int GetDamageBonus(Mobile m)
|
||||
{
|
||||
AnimalFormContext context = AnimalForm.GetContext(m);
|
||||
|
||||
if (context != null && context.Type == typeof(WildWhiteTiger))
|
||||
return (int)(((m.Skills[SkillName.Ninjitsu].Value + m.Skills[SkillName.Stealth].Value + (MasteryInfo.GetMasteryLevel(m, SkillName.Ninjitsu) * 40)) / 3) / 10) / 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static bool IsActive(Mobile m)
|
||||
{
|
||||
AnimalFormContext context = AnimalForm.GetContext(m);
|
||||
|
||||
return context != null && context.Type == typeof(WildWhiteTiger);
|
||||
}
|
||||
|
||||
public static int GetDefenseCap(Mobile m)
|
||||
{
|
||||
AnimalFormContext context = AnimalForm.GetContext(m);
|
||||
|
||||
if (context != null && context.Type == typeof(WildWhiteTiger))
|
||||
return 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void OnHit(Mobile attacker, Mobile defender)
|
||||
{
|
||||
CheckTable();
|
||||
|
||||
int damage;
|
||||
if (!HasBleedMod(attacker, out damage) || (_Table != null && _Table.ContainsKey(attacker)))
|
||||
return;
|
||||
|
||||
double bleedchance = (double)((attacker.Skills.Ninjitsu.Value + attacker.Skills.Stealth.Value + (MasteryInfo.GetMasteryLevel(attacker, SkillName.Ninjitsu) * 40)) / 3.0) / 15.0;
|
||||
|
||||
if (bleedchance > Utility.RandomDouble())
|
||||
{
|
||||
BleedAttack.BeginBleed(defender, attacker, false);
|
||||
|
||||
if (_Table == null)
|
||||
_Table = new Dictionary<Mobile, DateTime>();
|
||||
|
||||
_Table[attacker] = DateTime.UtcNow + TimeSpan.FromMinutes(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasBleedMod(Mobile m, out int damage)
|
||||
{
|
||||
CheckTable();
|
||||
|
||||
damage = GetDamageBonus(m);
|
||||
|
||||
return damage > 0;
|
||||
}
|
||||
|
||||
private static Dictionary<Mobile, DateTime> _Table;
|
||||
|
||||
private static void CheckTable()
|
||||
{
|
||||
if (_Table == null)
|
||||
return;
|
||||
|
||||
ColUtility.ForEach(_Table, (mob, expires) =>
|
||||
{
|
||||
if (expires < DateTime.UtcNow)
|
||||
_Table.Remove(mob);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user