Overwrite

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

View File

@@ -0,0 +1,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;
}
}
}

View 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();
}
}
}
}

View 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);
}
}
}

View 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));
}
}
}

View 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();
}
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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);
}
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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();
}
}
}
}

View 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
}
}

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

View 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)
{
}
}
}

View 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;
}
}
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}
}

View 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;
}
}
}

View 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();
}
}
}

View 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;
}
}
}
}

View 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);
}
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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];
}
}
}

View 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;
}
}
}
}
}

View 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);
}
}
}

View 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();
}
}
}
}

View 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;
}
}
}

View 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()
{
}
}
}

View 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)));
}
}
}
}

View 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;
}
}
}

View 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());
}
}
}
}

View 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();
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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();
}
}
}

View 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();
}
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}

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

View 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();
}
}
}

View 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);
});
}
}
}