Fixes code according to modern code style. Fixes a few expression bugs.
This commit is contained in:
parent
89eea25e5f
commit
970fd563b2
3324 changed files with 441118 additions and 433755 deletions
|
|
@ -1,31 +1,28 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This special move allows the skilled warrior to bypass his target's physical resistance, for one shot only.
|
||||
/// The Armor Ignore shot does slightly less damage than normal.
|
||||
/// Against a heavily armored opponent, this ability is a big win, but when used against a very lightly armored foe, it might be better to use a standard strike!
|
||||
/// </summary>
|
||||
public class ArmorIgnore : WeaponAbility
|
||||
{
|
||||
public ArmorIgnore()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// This special move allows the skilled warrior to bypass his target's physical resistance, for one shot only.
|
||||
/// The Armor Ignore shot does slightly less damage than normal.
|
||||
/// Against a heavily armored opponent, this ability is a big win, but when used against a very lightly armored foe, it might
|
||||
/// be better to use a standard strike!
|
||||
/// </summary>
|
||||
public class ArmorIgnore : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 30;
|
||||
public override double DamageScalar => 0.9;
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override double DamageScalar => 0.9;
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
attacker.SendLocalizedMessage(1060076); // Your attack penetrates their armor!
|
||||
defender.SendLocalizedMessage(1060077); // The blow penetrated your armor!
|
||||
|
||||
attacker.SendLocalizedMessage( 1060076 ); // Your attack penetrates their armor!
|
||||
defender.SendLocalizedMessage( 1060077 ); // The blow penetrated your armor!
|
||||
|
||||
defender.PlaySound( 0x56 );
|
||||
defender.FixedParticles( 0x3728, 200, 25, 9942, EffectLayer.Waist );
|
||||
}
|
||||
}
|
||||
}
|
||||
defender.PlaySound(0x56);
|
||||
defender.FixedParticles(0x3728, 200, 25, 9942, EffectLayer.Waist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +1,39 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Strike your opponent with great force, partially bypassing their armor and inflicting greater damage. Requires either Bushido or Ninjitsu skill
|
||||
/// </summary>
|
||||
public class ArmorPierce : WeaponAbility
|
||||
{
|
||||
public ArmorPierce()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Strike your opponent with great force, partially bypassing their armor and inflicting greater damage. Requires either
|
||||
/// Bushido or Ninjitsu skill
|
||||
/// </summary>
|
||||
public class ArmorPierce : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 30;
|
||||
public override double DamageScalar => 1.5;
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
public override bool RequiresSE => true;
|
||||
|
||||
return base.CheckSkills( from );
|
||||
}
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1063347,
|
||||
"50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override double DamageScalar => 1.5;
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
public override bool RequiresSE => true;
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
attacker.SendLocalizedMessage(1063350); // You pierce your opponent's armor!
|
||||
defender.SendLocalizedMessage(1063351); // Your attacker pierced your armor!
|
||||
|
||||
attacker.SendLocalizedMessage( 1063350 ); // You pierce your opponent's armor!
|
||||
defender.SendLocalizedMessage( 1063351 ); // Your attacker pierced your armor!
|
||||
|
||||
defender.FixedParticles( 0x3728, 1, 26, 0x26D6, 0, 0, EffectLayer.Waist );
|
||||
}
|
||||
}
|
||||
}
|
||||
defender.FixedParticles(0x3728, 1, 26, 0x26D6, 0, 0, EffectLayer.Waist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,134 +1,131 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using Server.Mobiles;
|
||||
using Server.Spells.Necromancy;
|
||||
using Server.Network;
|
||||
using Server.Spells;
|
||||
using Server.Spells.Necromancy;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Make your opponent bleed profusely with this wicked use of your weapon.
|
||||
/// When successful, the target will bleed for several seconds, taking damage as time passes for up to ten seconds.
|
||||
/// The rate of damage slows down as time passes, and the blood loss can be completely staunched with the use of bandages.
|
||||
/// </summary>
|
||||
public class BleedAttack : WeaponAbility
|
||||
{
|
||||
public BleedAttack()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Make your opponent bleed profusely with this wicked use of your weapon.
|
||||
/// When successful, the target will bleed for several seconds, taking damage as time passes for up to ten seconds.
|
||||
/// The rate of damage slows down as time passes, and the blood loss can be completely staunched with the use of bandages.
|
||||
/// </summary>
|
||||
public class BleedAttack : WeaponAbility
|
||||
{
|
||||
private static Hashtable m_Table = new Hashtable();
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override int BaseMana => 30;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
// Necromancers under Lich or Wraith Form are immune to Bleed Attacks.
|
||||
TransformContext context = TransformationSpellHelper.GetContext( defender );
|
||||
// Necromancers under Lich or Wraith Form are immune to Bleed Attacks.
|
||||
TransformContext context = TransformationSpellHelper.GetContext(defender);
|
||||
|
||||
if ( (context != null && ( context.Type == typeof( LichFormSpell ) || context.Type == typeof( WraithFormSpell ))) ||
|
||||
(defender is BaseCreature creature && creature.BleedImmune) )
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1062052 ); // Your target is not affected by the bleed attack!
|
||||
return;
|
||||
}
|
||||
if (context != null && (context.Type == typeof(LichFormSpell) || context.Type == typeof(WraithFormSpell)) ||
|
||||
defender is BaseCreature creature && creature.BleedImmune)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1062052); // Your target is not affected by the bleed attack!
|
||||
return;
|
||||
}
|
||||
|
||||
attacker.SendLocalizedMessage( 1060159 ); // Your target is bleeding!
|
||||
defender.SendLocalizedMessage( 1060160 ); // You are bleeding!
|
||||
attacker.SendLocalizedMessage(1060159); // Your target is bleeding!
|
||||
defender.SendLocalizedMessage(1060160); // You are bleeding!
|
||||
|
||||
if ( defender is PlayerMobile )
|
||||
{
|
||||
defender.LocalOverheadMessage( MessageType.Regular, 0x21, 1060757 ); // You are bleeding profusely
|
||||
defender.NonlocalOverheadMessage( MessageType.Regular, 0x21, 1060758, defender.Name ); // ~1_NAME~ is bleeding profusely
|
||||
}
|
||||
if (defender is PlayerMobile)
|
||||
{
|
||||
defender.LocalOverheadMessage(MessageType.Regular, 0x21, 1060757); // You are bleeding profusely
|
||||
defender.NonlocalOverheadMessage(MessageType.Regular, 0x21, 1060758,
|
||||
defender.Name); // ~1_NAME~ is bleeding profusely
|
||||
}
|
||||
|
||||
defender.PlaySound( 0x133 );
|
||||
defender.FixedParticles( 0x377A, 244, 25, 9950, 31, 0, EffectLayer.Waist );
|
||||
defender.PlaySound(0x133);
|
||||
defender.FixedParticles(0x377A, 244, 25, 9950, 31, 0, EffectLayer.Waist);
|
||||
|
||||
BeginBleed( defender, attacker );
|
||||
}
|
||||
BeginBleed(defender, attacker);
|
||||
}
|
||||
|
||||
private static Hashtable m_Table = new Hashtable();
|
||||
public static bool IsBleeding(Mobile m)
|
||||
{
|
||||
return m_Table.Contains(m);
|
||||
}
|
||||
|
||||
public static bool IsBleeding( Mobile m )
|
||||
{
|
||||
return m_Table.Contains( m );
|
||||
}
|
||||
public static void BeginBleed(Mobile m, Mobile from)
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
|
||||
public static void BeginBleed( Mobile m, Mobile from )
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
t?.Stop();
|
||||
|
||||
t?.Stop();
|
||||
t = new InternalTimer(from, m);
|
||||
m_Table[m] = t;
|
||||
|
||||
t = new InternalTimer( from, m );
|
||||
m_Table[m] = t;
|
||||
t.Start();
|
||||
}
|
||||
|
||||
t.Start();
|
||||
}
|
||||
public static void DoBleed(Mobile m, Mobile from, int level)
|
||||
{
|
||||
if (m.Alive)
|
||||
{
|
||||
int damage = Utility.RandomMinMax(level, level * 2);
|
||||
|
||||
public static void DoBleed( Mobile m, Mobile from, int level )
|
||||
{
|
||||
if ( m.Alive )
|
||||
{
|
||||
int damage = Utility.RandomMinMax( level, level * 2 );
|
||||
if (!m.Player)
|
||||
damage *= 2;
|
||||
|
||||
if ( !m.Player )
|
||||
damage *= 2;
|
||||
m.PlaySound(0x133);
|
||||
m.Damage(damage, from);
|
||||
|
||||
m.PlaySound( 0x133 );
|
||||
m.Damage( damage, from );
|
||||
Blood blood = new Blood();
|
||||
|
||||
Blood blood = new Blood();
|
||||
blood.ItemID = Utility.Random(0x122A, 5);
|
||||
|
||||
blood.ItemID = Utility.Random( 0x122A, 5 );
|
||||
blood.MoveToWorld(m.Location, m.Map);
|
||||
}
|
||||
else
|
||||
{
|
||||
EndBleed(m, false);
|
||||
}
|
||||
}
|
||||
|
||||
blood.MoveToWorld( m.Location, m.Map );
|
||||
}
|
||||
else
|
||||
{
|
||||
EndBleed( m, false );
|
||||
}
|
||||
}
|
||||
public static void EndBleed(Mobile m, bool message)
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
|
||||
public static void EndBleed( Mobile m, bool message )
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
if (t == null)
|
||||
return;
|
||||
|
||||
if ( t == null )
|
||||
return;
|
||||
t.Stop();
|
||||
m_Table.Remove(m);
|
||||
|
||||
t.Stop();
|
||||
m_Table.Remove( m );
|
||||
if (message)
|
||||
m.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding!
|
||||
}
|
||||
|
||||
if ( message )
|
||||
m.SendLocalizedMessage( 1060167 ); // The bleeding wounds have healed, you are no longer bleeding!
|
||||
}
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private int m_Count;
|
||||
private Mobile m_From;
|
||||
private Mobile m_Mobile;
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Mobile m_From;
|
||||
private Mobile m_Mobile;
|
||||
private int m_Count;
|
||||
public InternalTimer(Mobile from, Mobile m) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0))
|
||||
{
|
||||
m_From = from;
|
||||
m_Mobile = m;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
public InternalTimer( Mobile from, Mobile m ) : base( TimeSpan.FromSeconds( 2.0 ), TimeSpan.FromSeconds( 2.0 ) )
|
||||
{
|
||||
m_From = from;
|
||||
m_Mobile = m;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
protected override void OnTick()
|
||||
{
|
||||
DoBleed(m_Mobile, m_From, 5 - m_Count);
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
DoBleed( m_Mobile, m_From, 5 - m_Count );
|
||||
|
||||
if ( ++m_Count == 5 )
|
||||
EndBleed( m_Mobile, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (++m_Count == 5)
|
||||
EndBleed(m_Mobile, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,103 +3,101 @@ using System.Collections;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Raises your defenses for a short time. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class Block : WeaponAbility
|
||||
{
|
||||
public Block()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Raises your defenses for a short time. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class Block : WeaponAbility
|
||||
{
|
||||
private static Hashtable m_Table = new Hashtable();
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override int BaseMana => 30;
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1063347,
|
||||
"50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckSkills( from );
|
||||
}
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage( 1063345 ); // You block an attack!
|
||||
defender.SendLocalizedMessage( 1063346 ); // Your attack was blocked!
|
||||
attacker.SendLocalizedMessage(1063345); // You block an attack!
|
||||
defender.SendLocalizedMessage(1063346); // Your attack was blocked!
|
||||
|
||||
attacker.FixedParticles( 0x37C4, 1, 16, 0x251D, 0x39D, 0x3, EffectLayer.RightHand );
|
||||
attacker.FixedParticles(0x37C4, 1, 16, 0x251D, 0x39D, 0x3, EffectLayer.RightHand);
|
||||
|
||||
int bonus = (int)(10.0 * ((Math.Max( attacker.Skills[SkillName.Bushido].Value, attacker.Skills[SkillName.Ninjitsu].Value ) - 50.0) / 70.0 + 5));
|
||||
int bonus = (int)(10.0 * ((Math.Max(attacker.Skills[SkillName.Bushido].Value,
|
||||
attacker.Skills[SkillName.Ninjitsu].Value) - 50.0) / 70.0 + 5));
|
||||
|
||||
BeginBlock( attacker, bonus );
|
||||
}
|
||||
BeginBlock(attacker, bonus);
|
||||
}
|
||||
|
||||
private class BlockInfo
|
||||
{
|
||||
public Mobile m_Target;
|
||||
public Timer m_Timer;
|
||||
public int m_Bonus;
|
||||
public static bool GetBonus(Mobile targ, ref int bonus)
|
||||
{
|
||||
if (!(m_Table[targ] is BlockInfo info))
|
||||
return false;
|
||||
|
||||
public BlockInfo( Mobile target, int bonus )
|
||||
{
|
||||
m_Target = target;
|
||||
m_Bonus = bonus;
|
||||
}
|
||||
}
|
||||
bonus = info.m_Bonus;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Hashtable m_Table = new Hashtable();
|
||||
public static void BeginBlock(Mobile m, int bonus)
|
||||
{
|
||||
EndBlock(m);
|
||||
|
||||
public static bool GetBonus( Mobile targ, ref int bonus )
|
||||
{
|
||||
if ( !(m_Table[targ] is BlockInfo info) )
|
||||
return false;
|
||||
BlockInfo info = new BlockInfo(m, bonus);
|
||||
info.m_Timer = new InternalTimer(m);
|
||||
|
||||
bonus = info.m_Bonus;
|
||||
return true;
|
||||
}
|
||||
m_Table[m] = info;
|
||||
}
|
||||
|
||||
public static void BeginBlock( Mobile m, int bonus )
|
||||
{
|
||||
EndBlock( m );
|
||||
public static void EndBlock(Mobile m)
|
||||
{
|
||||
if (m_Table[m] is BlockInfo info)
|
||||
{
|
||||
info.m_Timer?.Stop();
|
||||
|
||||
BlockInfo info = new BlockInfo( m, bonus );
|
||||
info.m_Timer = new InternalTimer( m );
|
||||
m_Table.Remove(m);
|
||||
}
|
||||
}
|
||||
|
||||
m_Table[m] = info;
|
||||
}
|
||||
private class BlockInfo
|
||||
{
|
||||
public int m_Bonus;
|
||||
public Mobile m_Target;
|
||||
public Timer m_Timer;
|
||||
|
||||
public static void EndBlock( Mobile m )
|
||||
{
|
||||
if ( m_Table[m] is BlockInfo info )
|
||||
{
|
||||
info.m_Timer?.Stop();
|
||||
public BlockInfo(Mobile target, int bonus)
|
||||
{
|
||||
m_Target = target;
|
||||
m_Bonus = bonus;
|
||||
}
|
||||
}
|
||||
|
||||
m_Table.Remove( m );
|
||||
}
|
||||
}
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
public InternalTimer(Mobile m) : base(TimeSpan.FromSeconds(6.0))
|
||||
{
|
||||
m_Mobile = m;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
public InternalTimer( Mobile m ) : base( TimeSpan.FromSeconds( 6.0 ) )
|
||||
{
|
||||
m_Mobile = m;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
EndBlock( m_Mobile );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void OnTick()
|
||||
{
|
||||
EndBlock(m_Mobile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,51 +2,51 @@ using System;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This devastating strike is most effective against those who are in good health and whose reserves of mana are low, or vice versa.
|
||||
/// </summary>
|
||||
public class ConcussionBlow : WeaponAbility
|
||||
{
|
||||
public ConcussionBlow()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// This devastating strike is most effective against those who are in good health and whose reserves of mana are low, or vice
|
||||
/// versa.
|
||||
/// </summary>
|
||||
public class ConcussionBlow : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 25;
|
||||
|
||||
public override int BaseMana => 25;
|
||||
public override bool OnBeforeDamage(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return false;
|
||||
|
||||
public override bool OnBeforeDamage( Mobile attacker, Mobile defender )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return false;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
attacker.SendLocalizedMessage(1060165); // You have delivered a concussion!
|
||||
defender.SendLocalizedMessage(1060166); // You feel disoriented!
|
||||
|
||||
attacker.SendLocalizedMessage( 1060165 ); // You have delivered a concussion!
|
||||
defender.SendLocalizedMessage( 1060166 ); // You feel disoriented!
|
||||
defender.PlaySound(0x213);
|
||||
defender.FixedParticles(0x377A, 1, 32, 9949, 1153, 0, EffectLayer.Head);
|
||||
|
||||
defender.PlaySound( 0x213 );
|
||||
defender.FixedParticles( 0x377A, 1, 32, 9949, 1153, 0, EffectLayer.Head );
|
||||
Effects.SendMovingParticles(
|
||||
new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 10), defender.Map),
|
||||
new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 20), defender.Map), 0x36FE, 1, 0,
|
||||
false, false, 1133, 3, 9501, 1, 0, EffectLayer.Waist, 0x100);
|
||||
|
||||
Effects.SendMovingParticles( new Entity( Serial.Zero, new Point3D( defender.X, defender.Y, defender.Z + 10 ), defender.Map ), new Entity( Serial.Zero, new Point3D( defender.X, defender.Y, defender.Z + 20 ), defender.Map ), 0x36FE, 1, 0, false, false, 1133, 3, 9501, 1, 0, EffectLayer.Waist, 0x100 );
|
||||
int damage = 10; // Base damage is 10.
|
||||
|
||||
int damage = 10; // Base damage is 10.
|
||||
if (defender.HitsMax > 0)
|
||||
{
|
||||
double hitsPercent = defender.Hits / (double)defender.HitsMax * 100.0;
|
||||
|
||||
if ( defender.HitsMax > 0 )
|
||||
{
|
||||
double hitsPercent = ( (double)defender.Hits / (double)defender.HitsMax ) * 100.0;
|
||||
double manaPercent = 0;
|
||||
|
||||
double manaPercent = 0;
|
||||
if (defender.ManaMax > 0)
|
||||
manaPercent = defender.Mana / (double)defender.ManaMax * 100.0;
|
||||
|
||||
if ( defender.ManaMax > 0 )
|
||||
manaPercent = ( (double)defender.Mana / (double)defender.ManaMax ) * 100.0;
|
||||
damage += Math.Min((int)(Math.Abs(hitsPercent - manaPercent) / 4), 20);
|
||||
}
|
||||
|
||||
damage += Math.Min( (int)(Math.Abs( hitsPercent - manaPercent ) / 4), 20 );
|
||||
}
|
||||
// Total damage is 10 + (0~20) = 10~30, physical, non-resistable.
|
||||
|
||||
// Total damage is 10 + (0~20) = 10~30, physical, non-resistable.
|
||||
defender.Damage(damage, attacker);
|
||||
|
||||
defender.Damage( damage, attacker );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,31 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Also known as the Haymaker, this attack dramatically increases the damage done by a weapon reaching its mark.
|
||||
/// </summary>
|
||||
public class CrushingBlow : WeaponAbility
|
||||
{
|
||||
public CrushingBlow()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana => 25;
|
||||
public override double DamageScalar => 1.5;
|
||||
/// <summary>
|
||||
/// Also known as the Haymaker, this attack dramatically increases the damage done by a weapon reaching its mark.
|
||||
/// </summary>
|
||||
public class CrushingBlow : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 25;
|
||||
public override double DamageScalar => 1.5;
|
||||
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage( 1060090 ); // You have delivered a crushing blow!
|
||||
defender.SendLocalizedMessage( 1060091 ); // You take extra damage from the crushing attack!
|
||||
attacker.SendLocalizedMessage(1060090); // You have delivered a crushing blow!
|
||||
defender.SendLocalizedMessage(1060091); // You take extra damage from the crushing attack!
|
||||
|
||||
defender.PlaySound( 0x1E1 );
|
||||
defender.FixedParticles( 0, 1, 0, 9946, EffectLayer.Head );
|
||||
defender.PlaySound(0x1E1);
|
||||
defender.FixedParticles(0, 1, 0, 9946, EffectLayer.Head);
|
||||
|
||||
Effects.SendMovingParticles( new Entity( Serial.Zero, new Point3D( defender.X, defender.Y, defender.Z + 50 ), defender.Map ), new Entity( Serial.Zero, new Point3D( defender.X, defender.Y, defender.Z + 20 ), defender.Map ), 0xFB4, 1, 0, false, false, 0, 3, 9501, 1, 0, EffectLayer.Head, 0x100 );
|
||||
}
|
||||
}
|
||||
}
|
||||
Effects.SendMovingParticles(
|
||||
new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 50), defender.Map),
|
||||
new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 20), defender.Map), 0xFB4, 1, 0,
|
||||
false, false, 0, 3, 9501, 1, 0, EffectLayer.Head, 0x100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,95 +3,96 @@ using System.Collections;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Raises your physical resistance for a short time while lowering your ability to inflict damage. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class DefenseMastery : WeaponAbility
|
||||
{
|
||||
public DefenseMastery()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Raises your physical resistance for a short time while lowering your ability to inflict damage. Requires Bushido or
|
||||
/// Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class DefenseMastery : WeaponAbility
|
||||
{
|
||||
private static Hashtable m_Table = new Hashtable();
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
public override int BaseMana => 30;
|
||||
|
||||
return base.CheckSkills( from );
|
||||
}
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1063347,
|
||||
"50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int BaseMana => 30;
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage( 1063353 ); // You perform a masterful defense!
|
||||
attacker.SendLocalizedMessage(1063353); // You perform a masterful defense!
|
||||
|
||||
attacker.FixedParticles( 0x375A, 1, 17, 0x7F2, 0x3E8, 0x3, EffectLayer.Waist );
|
||||
attacker.FixedParticles(0x375A, 1, 17, 0x7F2, 0x3E8, 0x3, EffectLayer.Waist);
|
||||
|
||||
int modifier = (int)(30.0 * ((Math.Max( attacker.Skills[SkillName.Bushido].Value, attacker.Skills[SkillName.Ninjitsu].Value ) - 50.0) / 70.0));
|
||||
int modifier =
|
||||
(int)(30.0 *
|
||||
((Math.Max(attacker.Skills[SkillName.Bushido].Value, attacker.Skills[SkillName.Ninjitsu].Value) -
|
||||
50.0) / 70.0));
|
||||
|
||||
if ( m_Table[attacker] is DefenseMasteryInfo info )
|
||||
EndDefense( (object)info );
|
||||
if (m_Table[attacker] is DefenseMasteryInfo info)
|
||||
EndDefense(info);
|
||||
|
||||
ResistanceMod mod = new ResistanceMod( ResistanceType.Physical, 50 + modifier );
|
||||
attacker.AddResistanceMod( mod );
|
||||
ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, 50 + modifier);
|
||||
attacker.AddResistanceMod(mod);
|
||||
|
||||
info = new DefenseMasteryInfo( attacker, 80 - modifier, mod );
|
||||
info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 3.0 ), new TimerStateCallback( EndDefense ), info );
|
||||
info = new DefenseMasteryInfo(attacker, 80 - modifier, mod);
|
||||
info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(3.0), new TimerStateCallback(EndDefense), info);
|
||||
|
||||
m_Table[attacker] = info;
|
||||
m_Table[attacker] = info;
|
||||
|
||||
attacker.Delta( MobileDelta.WeaponDamage );
|
||||
}
|
||||
attacker.Delta(MobileDelta.WeaponDamage);
|
||||
}
|
||||
|
||||
private class DefenseMasteryInfo
|
||||
{
|
||||
public Mobile m_From;
|
||||
public Timer m_Timer;
|
||||
public int m_DamageMalus;
|
||||
public ResistanceMod m_Mod;
|
||||
public static bool GetMalus(Mobile targ, ref int damageMalus)
|
||||
{
|
||||
if (!(m_Table[targ] is DefenseMasteryInfo info))
|
||||
return false;
|
||||
|
||||
public DefenseMasteryInfo( Mobile from, int damageMalus, ResistanceMod mod )
|
||||
{
|
||||
m_From = from;
|
||||
m_DamageMalus = damageMalus;
|
||||
m_Mod = mod;
|
||||
}
|
||||
}
|
||||
damageMalus = info.m_DamageMalus;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Hashtable m_Table = new Hashtable();
|
||||
private static void EndDefense(object state)
|
||||
{
|
||||
DefenseMasteryInfo info = (DefenseMasteryInfo)state;
|
||||
|
||||
public static bool GetMalus( Mobile targ, ref int damageMalus )
|
||||
{
|
||||
if ( !(m_Table[targ] is DefenseMasteryInfo info) )
|
||||
return false;
|
||||
if (info.m_Mod != null)
|
||||
info.m_From.RemoveResistanceMod(info.m_Mod);
|
||||
|
||||
damageMalus = info.m_DamageMalus;
|
||||
return true;
|
||||
}
|
||||
info.m_Timer?.Stop();
|
||||
|
||||
private static void EndDefense( object state )
|
||||
{
|
||||
DefenseMasteryInfo info = (DefenseMasteryInfo)state;
|
||||
// No message is sent to the player.
|
||||
|
||||
if ( info.m_Mod != null )
|
||||
info.m_From.RemoveResistanceMod( info.m_Mod );
|
||||
m_Table.Remove(info.m_From);
|
||||
|
||||
info.m_Timer?.Stop();
|
||||
info.m_From.Delta(MobileDelta.WeaponDamage);
|
||||
}
|
||||
|
||||
// No message is sent to the player.
|
||||
private class DefenseMasteryInfo
|
||||
{
|
||||
public int m_DamageMalus;
|
||||
public Mobile m_From;
|
||||
public ResistanceMod m_Mod;
|
||||
public Timer m_Timer;
|
||||
|
||||
m_Table.Remove( info.m_From );
|
||||
|
||||
info.m_From.Delta( MobileDelta.WeaponDamage );
|
||||
}
|
||||
}
|
||||
}
|
||||
public DefenseMasteryInfo(Mobile from, int damageMalus, ResistanceMod mod)
|
||||
{
|
||||
m_From = from;
|
||||
m_DamageMalus = damageMalus;
|
||||
m_Mod = mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,81 +2,77 @@ using System;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This attack allows you to disarm your foe.
|
||||
/// Now in Age of Shadows, a successful Disarm leaves the victim unable to re-arm another weapon for several seconds.
|
||||
/// </summary>
|
||||
public class Disarm : WeaponAbility
|
||||
{
|
||||
public Disarm()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// This attack allows you to disarm your foe.
|
||||
/// Now in Age of Shadows, a successful Disarm leaves the victim unable to re-arm another weapon for several seconds.
|
||||
/// </summary>
|
||||
public class Disarm : WeaponAbility
|
||||
{
|
||||
public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds(5.0);
|
||||
|
||||
public override int BaseMana => 20;
|
||||
public override int BaseMana => 20;
|
||||
|
||||
// No longer active in pub21:
|
||||
/*public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( !base.CheckSkills( from ) )
|
||||
return false;
|
||||
// No longer active in pub21:
|
||||
/*public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( !base.CheckSkills( from ) )
|
||||
return false;
|
||||
|
||||
if ( !(from.Weapon is Fists) )
|
||||
return true;
|
||||
if ( !(from.Weapon is Fists) )
|
||||
return true;
|
||||
|
||||
Skill skill = from.Skills[SkillName.ArmsLore];
|
||||
Skill skill = from.Skills[SkillName.ArmsLore];
|
||||
|
||||
if ( skill != null && skill.Base >= 80.0 )
|
||||
return true;
|
||||
if ( skill != null && skill.Base >= 80.0 )
|
||||
return true;
|
||||
|
||||
from.SendLocalizedMessage( 1061812 ); // You lack the required skill in armslore to perform that attack!
|
||||
from.SendLocalizedMessage( 1061812 ); // You lack the required skill in armslore to perform that attack!
|
||||
|
||||
return false;
|
||||
}*/
|
||||
return false;
|
||||
}*/
|
||||
|
||||
public override bool RequiresTactics( Mobile from )
|
||||
{
|
||||
if ( !(from.Weapon is BaseWeapon weapon) )
|
||||
return false;
|
||||
public override bool RequiresTactics(Mobile from)
|
||||
{
|
||||
if (!(from.Weapon is BaseWeapon weapon))
|
||||
return false;
|
||||
|
||||
return weapon.Skill != SkillName.Wrestling;
|
||||
}
|
||||
return weapon.Skill != SkillName.Wrestling;
|
||||
}
|
||||
|
||||
public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds( 5.0 );
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
Item toDisarm = defender.FindItemOnLayer(Layer.OneHanded);
|
||||
|
||||
Item toDisarm = defender.FindItemOnLayer( Layer.OneHanded );
|
||||
if (toDisarm == null || !toDisarm.Movable)
|
||||
toDisarm = defender.FindItemOnLayer(Layer.TwoHanded);
|
||||
|
||||
if ( toDisarm == null || !toDisarm.Movable )
|
||||
toDisarm = defender.FindItemOnLayer( Layer.TwoHanded );
|
||||
Container pack = defender.Backpack;
|
||||
|
||||
Container pack = defender.Backpack;
|
||||
if (pack == null || toDisarm != null && !toDisarm.Movable)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent.
|
||||
}
|
||||
else if (toDisarm == null || toDisarm is BaseShield || toDisarm is Spellbook && !Core.ML)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1060849); // Your target is already unarmed!
|
||||
}
|
||||
else if (CheckMana(attacker, true))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1060092); // You disarm their weapon!
|
||||
defender.SendLocalizedMessage(1060093); // Your weapon has been disarmed!
|
||||
|
||||
if ( pack == null || (toDisarm != null && !toDisarm.Movable) )
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1004001 ); // You cannot disarm your opponent.
|
||||
}
|
||||
else if (toDisarm == null || toDisarm is BaseShield || toDisarm is Spellbook && !Core.ML )
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1060849 ); // Your target is already unarmed!
|
||||
}
|
||||
else if ( CheckMana( attacker, true ) )
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1060092 ); // You disarm their weapon!
|
||||
defender.SendLocalizedMessage( 1060093 ); // Your weapon has been disarmed!
|
||||
defender.PlaySound(0x3B9);
|
||||
defender.FixedParticles(0x37BE, 232, 25, 9948, EffectLayer.LeftHand);
|
||||
|
||||
defender.PlaySound( 0x3B9 );
|
||||
defender.FixedParticles( 0x37BE, 232, 25, 9948, EffectLayer.LeftHand );
|
||||
pack.DropItem(toDisarm);
|
||||
|
||||
pack.DropItem( toDisarm );
|
||||
|
||||
BaseWeapon.BlockEquip( defender, BlockEquipDuration );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BaseWeapon.BlockEquip(defender, BlockEquipDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,109 +1,94 @@
|
|||
using System;
|
||||
using Server.Mobiles;
|
||||
using Server.Spells.Ninjitsu;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Perfect for the foot-soldier, the Dismount special attack can unseat a mounted opponent.
|
||||
/// The fighter using this ability must be on his own two feet and not in the saddle of a steed
|
||||
/// (with one exception: players may use a lance to dismount other players while mounted).
|
||||
/// If it works, the target will be knocked off his own mount and will take some extra damage from the fall!
|
||||
/// </summary>
|
||||
public class Dismount : WeaponAbility
|
||||
{
|
||||
public Dismount()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Perfect for the foot-soldier, the Dismount special attack can unseat a mounted opponent.
|
||||
/// The fighter using this ability must be on his own two feet and not in the saddle of a steed
|
||||
/// (with one exception: players may use a lance to dismount other players while mounted).
|
||||
/// If it works, the target will be knocked off his own mount and will take some extra damage from the fall!
|
||||
/// </summary>
|
||||
public class Dismount : WeaponAbility
|
||||
{
|
||||
public static readonly TimeSpan RemountDelay = TimeSpan.FromSeconds(10.0);
|
||||
|
||||
public override int BaseMana => 20;
|
||||
public override int BaseMana => 20;
|
||||
|
||||
public override bool Validate( Mobile from )
|
||||
{
|
||||
if ( !base.Validate( from ) )
|
||||
return false;
|
||||
public override bool Validate(Mobile from)
|
||||
{
|
||||
if (!base.Validate(from))
|
||||
return false;
|
||||
|
||||
if ( from.Mounted && !(from.Weapon is Lance) )
|
||||
{
|
||||
from.SendLocalizedMessage( 1061283 ); // You cannot perform that attack while mounted!
|
||||
return false;
|
||||
}
|
||||
if (from.Mounted && !(from.Weapon is Lance))
|
||||
{
|
||||
from.SendLocalizedMessage(1061283); // You cannot perform that attack while mounted!
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static readonly TimeSpan RemountDelay = TimeSpan.FromSeconds( 10.0 );
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) )
|
||||
return;
|
||||
if (defender is ChaosDragoon || defender is ChaosDragoonElite)
|
||||
return;
|
||||
|
||||
if ( defender is ChaosDragoon || defender is ChaosDragoonElite )
|
||||
return;
|
||||
if (attacker.Mounted && (!(attacker.Weapon is Lance) || !(defender.Weapon is Lance))
|
||||
) // TODO: Should there be a message here?
|
||||
return;
|
||||
|
||||
if ( attacker.Mounted && ( !(attacker.Weapon is Lance) || !(defender.Weapon is Lance) ) ) // TODO: Should there be a message here?
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
IMount mount = defender.Mount;
|
||||
|
||||
IMount mount = defender.Mount;
|
||||
if (mount == null && !AnimalForm.UnderTransformation(defender))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1060848); // This attack only works on mounted targets
|
||||
return;
|
||||
}
|
||||
|
||||
if (mount == null && !Spells.Ninjitsu.AnimalForm.UnderTransformation( defender ) )
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1060848 ); // This attack only works on mounted targets
|
||||
return;
|
||||
}
|
||||
if (!CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
if ( !CheckMana( attacker, true ) )
|
||||
return;
|
||||
if (Core.ML && attacker is LesserHiryu && 0.8 >= Utility.RandomDouble())
|
||||
return; //Lesser Hiryu have an 80% chance of missing this attack
|
||||
|
||||
if ( Core.ML && attacker is LesserHiryu && 0.8 >= Utility.RandomDouble() )
|
||||
{
|
||||
return; //Lesser Hiryu have an 80% chance of missing this attack
|
||||
}
|
||||
attacker.SendLocalizedMessage(1060082); // The force of your attack has dislodged them from their mount!
|
||||
|
||||
attacker.SendLocalizedMessage( 1060082 ); // The force of your attack has dislodged them from their mount!
|
||||
if (attacker.Mounted)
|
||||
defender.SendLocalizedMessage(1062315); // You fall off your mount!
|
||||
else
|
||||
defender.SendLocalizedMessage(1060083); // You fall off of your mount and take damage!
|
||||
|
||||
if ( attacker.Mounted )
|
||||
defender.SendLocalizedMessage( 1062315 ); // You fall off your mount!
|
||||
else
|
||||
defender.SendLocalizedMessage( 1060083 ); // You fall off of your mount and take damage!
|
||||
defender.PlaySound(0x140);
|
||||
defender.FixedParticles(0x3728, 10, 15, 9955, EffectLayer.Waist);
|
||||
|
||||
defender.PlaySound( 0x140 );
|
||||
defender.FixedParticles( 0x3728, 10, 15, 9955, EffectLayer.Waist );
|
||||
if (defender is PlayerMobile mobile)
|
||||
{
|
||||
if (AnimalForm.UnderTransformation(mobile))
|
||||
mobile.SendLocalizedMessage(1114066, attacker.Name); // ~1_NAME~ knocked you out of animal form!
|
||||
else if (mobile.Mounted) mobile.SendLocalizedMessage(1040023); // You have been knocked off of your mount!
|
||||
|
||||
if (defender is PlayerMobile mobile)
|
||||
{
|
||||
if (Spells.Ninjitsu.AnimalForm.UnderTransformation(mobile))
|
||||
{
|
||||
mobile.SendLocalizedMessage(1114066, attacker.Name); // ~1_NAME~ knocked you out of animal form!
|
||||
}
|
||||
else if (mobile.Mounted)
|
||||
{
|
||||
mobile.SendLocalizedMessage(1040023); // You have been knocked off of your mount!
|
||||
}
|
||||
mobile.SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(10), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
defender.Mount.Rider = null;
|
||||
}
|
||||
|
||||
mobile.SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(10), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
defender.Mount.Rider = null;
|
||||
}
|
||||
if (attacker is PlayerMobile playerMobile)
|
||||
playerMobile.SetMountBlock(BlockMountType.DismountRecovery, RemountDelay, true);
|
||||
else if (Core.ML && attacker is BaseCreature bc)
|
||||
if (bc.ControlMaster is PlayerMobile pm)
|
||||
pm.SetMountBlock(BlockMountType.DismountRecovery, RemountDelay, false);
|
||||
|
||||
if ( attacker is PlayerMobile playerMobile )
|
||||
{
|
||||
playerMobile.SetMountBlock(BlockMountType.DismountRecovery, RemountDelay, true );
|
||||
}
|
||||
else if ( Core.ML && attacker is BaseCreature bc )
|
||||
{
|
||||
if ( bc.ControlMaster is PlayerMobile pm )
|
||||
{
|
||||
pm.SetMountBlock(BlockMountType.DismountRecovery, RemountDelay, false );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !attacker.Mounted )
|
||||
AOS.Damage( defender, attacker, Utility.RandomMinMax( 15, 25 ), 100, 0, 0, 0, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!attacker.Mounted)
|
||||
AOS.Damage(defender, attacker, Utility.RandomMinMax(15, 25), 100, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,48 +2,44 @@ using System;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This attack allows you to disrobe your foe.
|
||||
/// </summary>
|
||||
public class Disrobe : WeaponAbility
|
||||
{
|
||||
public Disrobe()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// This attack allows you to disrobe your foe.
|
||||
/// </summary>
|
||||
public class Disrobe : WeaponAbility
|
||||
{
|
||||
public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds(5.0);
|
||||
|
||||
public override int BaseMana => 20; // Not Sure what amount of mana a creature uses.
|
||||
public override int BaseMana => 20; // Not Sure what amount of mana a creature uses.
|
||||
|
||||
public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds( 5.0 );
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
Item toDisrobe = defender.FindItemOnLayer(Layer.InnerTorso);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
Item toDisrobe = defender.FindItemOnLayer(Layer.InnerTorso);
|
||||
if (toDisrobe == null || !toDisrobe.Movable)
|
||||
toDisrobe = defender.FindItemOnLayer(Layer.OuterTorso);
|
||||
|
||||
if ( toDisrobe == null || !toDisrobe.Movable )
|
||||
toDisrobe = defender.FindItemOnLayer( Layer.OuterTorso );
|
||||
Container pack = defender.Backpack;
|
||||
|
||||
Container pack = defender.Backpack;
|
||||
if (pack == null || toDisrobe == null || !toDisrobe.Movable)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent.
|
||||
}
|
||||
else if (CheckMana(attacker, true))
|
||||
{
|
||||
//attacker.SendLocalizedMessage( 1060092 ); // You disarm their weapon!
|
||||
defender.SendLocalizedMessage(1062002); // You can no longer wear your ~1_ARMOR~
|
||||
|
||||
if ( pack == null || toDisrobe == null || !toDisrobe.Movable )
|
||||
{
|
||||
attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent.
|
||||
}
|
||||
else if ( CheckMana( attacker, true ) )
|
||||
{
|
||||
//attacker.SendLocalizedMessage( 1060092 ); // You disarm their weapon!
|
||||
defender.SendLocalizedMessage(1062002); // You can no longer wear your ~1_ARMOR~
|
||||
defender.PlaySound(0x3B9);
|
||||
//defender.FixedParticles( 0x37BE, 232, 25, 9948, EffectLayer.InnerTorso );
|
||||
|
||||
defender.PlaySound( 0x3B9 );
|
||||
//defender.FixedParticles( 0x37BE, 232, 25, 9948, EffectLayer.InnerTorso );
|
||||
pack.DropItem(toDisrobe);
|
||||
|
||||
pack.DropItem( toDisrobe );
|
||||
|
||||
BaseWeapon.BlockEquip( defender, BlockEquipDuration );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BaseWeapon.BlockEquip(defender, BlockEquipDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +1,60 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Send two arrows flying at your opponent if you're mounted. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class DoubleShot : WeaponAbility
|
||||
{
|
||||
public DoubleShot()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Send two arrows flying at your opponent if you're mounted. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class DoubleShot : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 30;
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1063347,
|
||||
"50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
return base.CheckSkills( from );
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
Use(attacker, defender);
|
||||
}
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
Use( attacker, defender );
|
||||
}
|
||||
public override void OnMiss(Mobile attacker, Mobile defender)
|
||||
{
|
||||
Use(attacker, defender);
|
||||
}
|
||||
|
||||
public override void OnMiss( Mobile attacker, Mobile defender )
|
||||
{
|
||||
Use( attacker, defender );
|
||||
}
|
||||
public override bool Validate(Mobile from)
|
||||
{
|
||||
if (base.Validate(from))
|
||||
{
|
||||
if (from.Mounted)
|
||||
return true;
|
||||
from.SendLocalizedMessage(1070770); // You can only execute this attack while mounted!
|
||||
ClearCurrentAbility(from);
|
||||
}
|
||||
|
||||
public override bool Validate( Mobile from )
|
||||
{
|
||||
if ( base.Validate( from ) )
|
||||
{
|
||||
if ( from.Mounted )
|
||||
return true;
|
||||
from.SendLocalizedMessage( 1070770 ); // You can only execute this attack while mounted!
|
||||
ClearCurrentAbility( from );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public void Use(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true) || attacker.Weapon == null) //sanity
|
||||
return;
|
||||
|
||||
public void Use( Mobile attacker, Mobile defender )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) || attacker.Weapon == null ) //sanity
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
attacker.SendLocalizedMessage(1063348); // You launch two shots at once!
|
||||
defender.SendLocalizedMessage(1063349); // You're attacked with a barrage of shots!
|
||||
|
||||
attacker.SendLocalizedMessage( 1063348 ); // You launch two shots at once!
|
||||
defender.SendLocalizedMessage( 1063349 ); // You're attacked with a barrage of shots!
|
||||
defender.FixedParticles(0x37B9, 1, 19, 0x251D, EffectLayer.Waist);
|
||||
|
||||
defender.FixedParticles( 0x37B9, 1, 19, 0x251D, EffectLayer.Waist );
|
||||
|
||||
attacker.Weapon.OnSwing( attacker, defender );
|
||||
}
|
||||
}
|
||||
}
|
||||
attacker.Weapon.OnSwing(attacker, defender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +1,52 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// The highly skilled warrior can use this special attack to make two quick swings in succession.
|
||||
/// Landing both blows would be devastating!
|
||||
/// </summary>
|
||||
public class DoubleStrike : WeaponAbility
|
||||
{
|
||||
public DoubleStrike()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// The highly skilled warrior can use this special attack to make two quick swings in succession.
|
||||
/// Landing both blows would be devastating!
|
||||
/// </summary>
|
||||
public class DoubleStrike : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 30;
|
||||
public override double DamageScalar => 0.9;
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override double DamageScalar => 0.9;
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
attacker.SendLocalizedMessage(1060084); // You attack with lightning speed!
|
||||
defender.SendLocalizedMessage(1060085); // Your attacker strikes with lightning speed!
|
||||
|
||||
attacker.SendLocalizedMessage( 1060084 ); // You attack with lightning speed!
|
||||
defender.SendLocalizedMessage( 1060085 ); // Your attacker strikes with lightning speed!
|
||||
defender.PlaySound(0x3BB);
|
||||
defender.FixedEffect(0x37B9, 244, 25);
|
||||
|
||||
defender.PlaySound( 0x3BB );
|
||||
defender.FixedEffect( 0x37B9, 244, 25 );
|
||||
// Swing again:
|
||||
|
||||
// Swing again:
|
||||
// If no combatant, wrong map, one of us is a ghost, or cannot see, or deleted, then stop combat
|
||||
if (defender == null || defender.Deleted || attacker.Deleted || defender.Map != attacker.Map ||
|
||||
!defender.Alive || !attacker.Alive || !attacker.CanSee(defender))
|
||||
{
|
||||
attacker.Combatant = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// If no combatant, wrong map, one of us is a ghost, or cannot see, or deleted, then stop combat
|
||||
if ( defender == null || defender.Deleted || attacker.Deleted || defender.Map != attacker.Map || !defender.Alive || !attacker.Alive || !attacker.CanSee( defender ) )
|
||||
{
|
||||
attacker.Combatant = null;
|
||||
return;
|
||||
}
|
||||
IWeapon weapon = attacker.Weapon;
|
||||
|
||||
IWeapon weapon = attacker.Weapon;
|
||||
if (weapon == null)
|
||||
return;
|
||||
|
||||
if ( weapon == null )
|
||||
return;
|
||||
if (!attacker.InRange(defender, weapon.MaxRange))
|
||||
return;
|
||||
|
||||
if ( !attacker.InRange( defender, weapon.MaxRange ) )
|
||||
return;
|
||||
|
||||
if ( attacker.InLOS( defender ) )
|
||||
{
|
||||
BaseWeapon.InDoubleStrike = true;
|
||||
attacker.RevealingAction();
|
||||
attacker.NextCombatTime = Core.TickCount + (int)weapon.OnSwing(attacker, defender).TotalMilliseconds;
|
||||
BaseWeapon.InDoubleStrike = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (attacker.InLOS(defender))
|
||||
{
|
||||
BaseWeapon.InDoubleStrike = true;
|
||||
attacker.RevealingAction();
|
||||
attacker.NextCombatTime = Core.TickCount + (int)weapon.OnSwing(attacker, defender).TotalMilliseconds;
|
||||
BaseWeapon.InDoubleStrike = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +1,72 @@
|
|||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Attack faster as you swing with both weapons.
|
||||
/// </summary>
|
||||
public class DualWield : WeaponAbility
|
||||
{
|
||||
public static Hashtable Registry { get; } = new Hashtable();
|
||||
/// <summary>
|
||||
/// Attack faster as you swing with both weapons.
|
||||
/// </summary>
|
||||
public class DualWield : WeaponAbility
|
||||
{
|
||||
public static Hashtable Registry{ get; } = new Hashtable();
|
||||
|
||||
public DualWield()
|
||||
{
|
||||
}
|
||||
public override int BaseMana => 30;
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (GetSkill(from, SkillName.Ninjitsu) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1063352,
|
||||
"50"); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( GetSkill( from, SkillName.Ninjitsu ) < 50.0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063352, "50" ); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
return base.CheckSkills( from );
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
if (Registry.Contains(attacker))
|
||||
{
|
||||
DualWieldTimer existingtimer = (DualWieldTimer)Registry[attacker];
|
||||
existingtimer.Stop();
|
||||
Registry.Remove(attacker);
|
||||
}
|
||||
|
||||
if ( Registry.Contains( attacker ) )
|
||||
{
|
||||
DualWieldTimer existingtimer = (DualWieldTimer)Registry[attacker];
|
||||
existingtimer.Stop();
|
||||
Registry.Remove( attacker );
|
||||
}
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
attacker.SendLocalizedMessage(1063362); // You dually wield for increased speed!
|
||||
|
||||
attacker.SendLocalizedMessage( 1063362 ); // You dually wield for increased speed!
|
||||
attacker.FixedParticles(0x3779, 1, 15, 0x7F6, 0x3E8, 3, EffectLayer.LeftHand);
|
||||
|
||||
attacker.FixedParticles( 0x3779, 1, 15, 0x7F6, 0x3E8, 3, EffectLayer.LeftHand );
|
||||
Timer t = new DualWieldTimer(attacker,
|
||||
(int)(20.0 + 3.0 * (attacker.Skills[SkillName.Ninjitsu].Value - 50.0) / 7.0)); //20-50 % increase
|
||||
|
||||
Timer t = new DualWieldTimer( attacker, (int)(20.0 + 3.0 * (attacker.Skills[SkillName.Ninjitsu].Value - 50.0) / 7.0) ); //20-50 % increase
|
||||
t.Start();
|
||||
Registry.Add(attacker, t);
|
||||
}
|
||||
|
||||
t.Start();
|
||||
Registry.Add( attacker, t );
|
||||
}
|
||||
public class DualWieldTimer : Timer
|
||||
{
|
||||
private Mobile m_Owner;
|
||||
|
||||
public class DualWieldTimer : Timer
|
||||
{
|
||||
private Mobile m_Owner;
|
||||
public DualWieldTimer(Mobile owner, int bonusSwingSpeed)
|
||||
: base(TimeSpan.FromSeconds(6.0))
|
||||
{
|
||||
m_Owner = owner;
|
||||
BonusSwingSpeed = bonusSwingSpeed;
|
||||
Priority = TimerPriority.FiftyMS;
|
||||
}
|
||||
|
||||
public int BonusSwingSpeed { get; }
|
||||
public int BonusSwingSpeed{ get; }
|
||||
|
||||
public DualWieldTimer( Mobile owner, int bonusSwingSpeed )
|
||||
: base( TimeSpan.FromSeconds( 6.0 ) )
|
||||
{
|
||||
m_Owner = owner;
|
||||
BonusSwingSpeed = bonusSwingSpeed;
|
||||
Priority = TimerPriority.FiftyMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
Registry.Remove( m_Owner );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void OnTick()
|
||||
{
|
||||
Registry.Remove(m_Owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +1,74 @@
|
|||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Gain a defensive advantage over your primary opponent for a short time.
|
||||
/// </summary>
|
||||
public class Feint : WeaponAbility
|
||||
{
|
||||
public static Hashtable Registry { get; } = new Hashtable();
|
||||
/// <summary>
|
||||
/// Gain a defensive advantage over your primary opponent for a short time.
|
||||
/// </summary>
|
||||
public class Feint : WeaponAbility
|
||||
{
|
||||
public static Hashtable Registry{ get; } = new Hashtable();
|
||||
|
||||
public Feint()
|
||||
{
|
||||
}
|
||||
public override int BaseMana => 30;
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1063347,
|
||||
"50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
return base.CheckSkills( from );
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
if (Registry.Contains(defender))
|
||||
{
|
||||
FeintTimer existingtimer = (FeintTimer)Registry[defender];
|
||||
existingtimer.Stop();
|
||||
Registry.Remove(defender);
|
||||
}
|
||||
|
||||
if ( Registry.Contains( defender ) )
|
||||
{
|
||||
FeintTimer existingtimer = (FeintTimer)Registry[defender];
|
||||
existingtimer.Stop();
|
||||
Registry.Remove( defender );
|
||||
}
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
attacker.SendLocalizedMessage(1063360); // You baffle your target with a feint!
|
||||
defender.SendLocalizedMessage(1063361); // You were deceived by an attacker's feint!
|
||||
|
||||
attacker.SendLocalizedMessage( 1063360 ); // You baffle your target with a feint!
|
||||
defender.SendLocalizedMessage( 1063361 ); // You were deceived by an attacker's feint!
|
||||
attacker.FixedParticles(0x3728, 1, 13, 0x7F3, 0x962, 0, EffectLayer.Waist);
|
||||
|
||||
attacker.FixedParticles( 0x3728, 1, 13, 0x7F3, 0x962, 0, EffectLayer.Waist );
|
||||
Timer t = new FeintTimer(defender,
|
||||
(int)(20.0 + 3.0 * (Math.Max(attacker.Skills[SkillName.Ninjitsu].Value,
|
||||
attacker.Skills[SkillName.Bushido].Value) - 50.0) / 7.0)); //20-50 % decrease
|
||||
|
||||
Timer t = new FeintTimer( defender, (int)(20.0 + 3.0 * (Math.Max( attacker.Skills[SkillName.Ninjitsu].Value, attacker.Skills[SkillName.Bushido].Value ) - 50.0) / 7.0) ); //20-50 % decrease
|
||||
t.Start();
|
||||
Registry.Add(defender, t);
|
||||
}
|
||||
|
||||
t.Start();
|
||||
Registry.Add( defender, t );
|
||||
}
|
||||
public class FeintTimer : Timer
|
||||
{
|
||||
private Mobile m_Defender;
|
||||
|
||||
public class FeintTimer : Timer
|
||||
{
|
||||
private Mobile m_Defender;
|
||||
public FeintTimer(Mobile defender, int swingSpeedReduction)
|
||||
: base(TimeSpan.FromSeconds(6.0))
|
||||
{
|
||||
m_Defender = defender;
|
||||
SwingSpeedReduction = swingSpeedReduction;
|
||||
Priority = TimerPriority.FiftyMS;
|
||||
}
|
||||
|
||||
public int SwingSpeedReduction { get; }
|
||||
public int SwingSpeedReduction{ get; }
|
||||
|
||||
public FeintTimer( Mobile defender, int swingSpeedReduction )
|
||||
: base( TimeSpan.FromSeconds( 6.0 ) )
|
||||
{
|
||||
m_Defender = defender;
|
||||
SwingSpeedReduction = swingSpeedReduction;
|
||||
Priority = TimerPriority.FiftyMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
Registry.Remove( m_Defender );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void OnTick()
|
||||
{
|
||||
Registry.Remove(m_Defender);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,158 +4,157 @@ using Server.Spells;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// A quick attack to all enemies in range of your weapon that causes damage over time. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class FrenziedWhirlwind : WeaponAbility
|
||||
{
|
||||
public FrenziedWhirlwind()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// A quick attack to all enemies in range of your weapon that causes damage over time. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class FrenziedWhirlwind : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 30;
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
public static Hashtable Registry{ get; } = new Hashtable();
|
||||
|
||||
return base.CheckSkills( from );
|
||||
}
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (GetSkill(from, SkillName.Ninjitsu) < 50.0 && GetSkill(from, SkillName.Bushido) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1063347,
|
||||
"50"); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int BaseMana => 30;
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
public static Hashtable Registry { get; } = new Hashtable();
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker)) //Mana check after check that there are targets
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) ) //Mana check after check that there are targets
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
Map map = attacker.Map;
|
||||
|
||||
Map map = attacker.Map;
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
if ( map == null )
|
||||
return;
|
||||
if (!(attacker.Weapon is BaseWeapon weapon))
|
||||
return;
|
||||
|
||||
if ( !(attacker.Weapon is BaseWeapon weapon) )
|
||||
return;
|
||||
ArrayList list = new ArrayList();
|
||||
|
||||
ArrayList list = new ArrayList();
|
||||
foreach (Mobile m in attacker.GetMobilesInRange(1))
|
||||
list.Add(m);
|
||||
|
||||
foreach( Mobile m in attacker.GetMobilesInRange( 1 ) )
|
||||
list.Add( m );
|
||||
ArrayList targets = new ArrayList();
|
||||
|
||||
ArrayList targets = new ArrayList();
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
Mobile m = (Mobile)list[i];
|
||||
|
||||
for( int i = 0; i < list.Count; ++i )
|
||||
{
|
||||
Mobile m = (Mobile)list[i];
|
||||
if (m != defender && m != attacker && SpellHelper.ValidIndirectTarget(attacker, m))
|
||||
{
|
||||
if (m == null || m.Deleted || m.Map != attacker.Map || !m.Alive || !attacker.CanSee(m) ||
|
||||
!attacker.CanBeHarmful(m))
|
||||
continue;
|
||||
|
||||
if ( m != defender && m != attacker && SpellHelper.ValidIndirectTarget( attacker, m ) )
|
||||
{
|
||||
if ( m == null || m.Deleted || m.Map != attacker.Map || !m.Alive || !attacker.CanSee( m ) || !attacker.CanBeHarmful( m ) )
|
||||
continue;
|
||||
if (!attacker.InRange(m, weapon.MaxRange))
|
||||
continue;
|
||||
|
||||
if ( !attacker.InRange( m, weapon.MaxRange ) )
|
||||
continue;
|
||||
if (attacker.InLOS(m))
|
||||
targets.Add(m);
|
||||
}
|
||||
}
|
||||
|
||||
if ( attacker.InLOS( m ) )
|
||||
targets.Add( m );
|
||||
}
|
||||
}
|
||||
if (targets.Count > 0)
|
||||
{
|
||||
if (!CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
if ( targets.Count > 0 )
|
||||
{
|
||||
if ( !CheckMana( attacker, true ) )
|
||||
return;
|
||||
attacker.FixedEffect(0x3728, 10, 15);
|
||||
attacker.PlaySound(0x2A1);
|
||||
|
||||
attacker.FixedEffect( 0x3728, 10, 15 );
|
||||
attacker.PlaySound( 0x2A1 );
|
||||
// 5-15 damage
|
||||
int amount = (int)(10.0 * ((Math.Max(attacker.Skills[SkillName.Bushido].Value,
|
||||
attacker.Skills[SkillName.Ninjitsu].Value) - 50.0) / 70.0 + 5));
|
||||
|
||||
// 5-15 damage
|
||||
int amount = (int)(10.0 * ((Math.Max( attacker.Skills[SkillName.Bushido].Value, attacker.Skills[SkillName.Ninjitsu].Value ) - 50.0) / 70.0 + 5));
|
||||
for (int i = 0; i < targets.Count; ++i)
|
||||
{
|
||||
Mobile m = (Mobile)targets[i];
|
||||
attacker.DoHarmful(m, true);
|
||||
|
||||
for( int i = 0; i < targets.Count; ++i )
|
||||
{
|
||||
Mobile m = (Mobile)targets[i];
|
||||
attacker.DoHarmful( m, true );
|
||||
if (Registry[m] is Timer t)
|
||||
{
|
||||
t.Stop();
|
||||
Registry.Remove(m);
|
||||
}
|
||||
|
||||
if ( Registry[m] is Timer t )
|
||||
{
|
||||
t.Stop();
|
||||
Registry.Remove( m );
|
||||
}
|
||||
t = new InternalTimer(attacker, m, amount);
|
||||
t.Start();
|
||||
Registry.Add(m, t);
|
||||
}
|
||||
|
||||
t = new InternalTimer( attacker, m, amount );
|
||||
t.Start();
|
||||
Registry.Add( m, t );
|
||||
}
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(2.0), new TimerStateCallback(RepeatEffect), attacker);
|
||||
}
|
||||
}
|
||||
|
||||
Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( RepeatEffect ), attacker );
|
||||
}
|
||||
}
|
||||
private void RepeatEffect(object state)
|
||||
{
|
||||
Mobile attacker = (Mobile)state;
|
||||
|
||||
private void RepeatEffect( object state )
|
||||
{
|
||||
Mobile attacker = (Mobile)state;
|
||||
attacker.FixedEffect(0x3728, 10, 15);
|
||||
attacker.PlaySound(0x2A1);
|
||||
}
|
||||
|
||||
attacker.FixedEffect( 0x3728, 10, 15 );
|
||||
attacker.PlaySound( 0x2A1 );
|
||||
}
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private readonly double DamagePerTick;
|
||||
private Mobile m_Attacker;
|
||||
private double m_DamageRemaining;
|
||||
private double m_DamageToDo;
|
||||
private Mobile m_Defender;
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Mobile m_Attacker;
|
||||
private Mobile m_Defender;
|
||||
private double m_DamageRemaining;
|
||||
private double m_DamageToDo;
|
||||
public InternalTimer(Mobile attacker, Mobile defender, int totalDamage)
|
||||
: base(TimeSpan.Zero, TimeSpan.FromSeconds(0.25),
|
||||
12) // 3 seconds at .25 seconds apart = 12. Confirm delay inbetween of .25 each.
|
||||
{
|
||||
m_Attacker = attacker;
|
||||
m_Defender = defender;
|
||||
|
||||
private readonly double DamagePerTick;
|
||||
m_DamageRemaining = totalDamage;
|
||||
DamagePerTick = (double)totalDamage / 12 + 0.01;
|
||||
|
||||
public InternalTimer( Mobile attacker, Mobile defender, int totalDamage )
|
||||
: base( TimeSpan.Zero, TimeSpan.FromSeconds( 0.25 ), 12 ) // 3 seconds at .25 seconds apart = 12. Confirm delay inbetween of .25 each.
|
||||
{
|
||||
m_Attacker = attacker;
|
||||
m_Defender = defender;
|
||||
Priority = TimerPriority.TwentyFiveMS;
|
||||
}
|
||||
|
||||
m_DamageRemaining = (double)totalDamage;
|
||||
DamagePerTick = (double)totalDamage / 12 + 0.01;
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (!m_Defender.Alive || m_DamageRemaining <= 0)
|
||||
{
|
||||
Stop();
|
||||
Registry.Remove(m_Defender);
|
||||
return;
|
||||
}
|
||||
|
||||
Priority = TimerPriority.TwentyFiveMS;
|
||||
}
|
||||
m_DamageRemaining -= DamagePerTick;
|
||||
m_DamageToDo += DamagePerTick;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if ( !m_Defender.Alive || m_DamageRemaining <= 0 )
|
||||
{
|
||||
Stop();
|
||||
Registry.Remove( m_Defender );
|
||||
return;
|
||||
}
|
||||
if (m_DamageRemaining <= 0 && m_DamageToDo < 1)
|
||||
m_DamageToDo = 1.0; //Confirm this 'round up' at the end
|
||||
|
||||
m_DamageRemaining -= DamagePerTick;
|
||||
m_DamageToDo += DamagePerTick;
|
||||
int damage = (int)m_DamageToDo;
|
||||
|
||||
if ( m_DamageRemaining <= 0 && m_DamageToDo < 1 )
|
||||
m_DamageToDo = 1.0; //Confirm this 'round up' at the end
|
||||
if (damage > 0)
|
||||
{
|
||||
m_Defender.Damage(damage, m_Attacker);
|
||||
m_DamageToDo -= damage;
|
||||
}
|
||||
|
||||
int damage = (int)m_DamageToDo;
|
||||
|
||||
if ( damage > 0 )
|
||||
{
|
||||
m_Defender.Damage( damage, m_Attacker );
|
||||
m_DamageToDo -= damage;
|
||||
}
|
||||
|
||||
if ( !m_Defender.Alive || m_DamageRemaining <= 0 )
|
||||
{
|
||||
Stop();
|
||||
Registry.Remove( m_Defender );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_Defender.Alive || m_DamageRemaining <= 0)
|
||||
{
|
||||
Stop();
|
||||
Registry.Remove(m_Defender);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +1,78 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This special move represents a significant change to the use of poisons in Age of Shadows.
|
||||
/// Now, only certain weapon types <20> those that have Infectious Strike as an available special move <20> will be able to be poisoned.
|
||||
/// Targets will no longer be poisoned at random when hit by poisoned weapons.
|
||||
/// Instead, the wielder must use this ability to deliver the venom.
|
||||
/// While no skill in Poisoning is directly required to use this ability, being knowledgeable in the application and use of toxins
|
||||
/// will allow a character to use Infectious Strike at reduced mana cost and with a chance to inflict more deadly poison on his victim.
|
||||
/// With this change, weapons will no longer be corroded by poison.
|
||||
/// Level 5 poison will be possible when using this special move.
|
||||
/// </summary>
|
||||
public class InfectiousStrike : WeaponAbility
|
||||
{
|
||||
public InfectiousStrike()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// This special move represents a significant change to the use of poisons in Age of Shadows.
|
||||
/// Now, only certain weapon types <20> those that have Infectious Strike as an available special move <20> will be able to be
|
||||
/// poisoned.
|
||||
/// Targets will no longer be poisoned at random when hit by poisoned weapons.
|
||||
/// Instead, the wielder must use this ability to deliver the venom.
|
||||
/// While no skill in Poisoning is directly required to use this ability, being knowledgeable in the application and use of
|
||||
/// toxins
|
||||
/// will allow a character to use Infectious Strike at reduced mana cost and with a chance to inflict more deadly poison on
|
||||
/// his victim.
|
||||
/// With this change, weapons will no longer be corroded by poison.
|
||||
/// Level 5 poison will be possible when using this special move.
|
||||
/// </summary>
|
||||
public class InfectiousStrike : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 15;
|
||||
|
||||
public override int BaseMana => 15;
|
||||
public override bool RequiresTactics(Mobile from)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool RequiresTactics( Mobile from )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
if (!(attacker.Weapon is BaseWeapon weapon))
|
||||
return;
|
||||
|
||||
if ( !(attacker.Weapon is BaseWeapon weapon) )
|
||||
return;
|
||||
Poison p = weapon.Poison;
|
||||
|
||||
Poison p = weapon.Poison;
|
||||
if (p == null || weapon.PoisonCharges <= 0)
|
||||
{
|
||||
attacker.SendLocalizedMessage(
|
||||
1061141); // Your weapon must have a dose of poison to perform an infectious strike!
|
||||
return;
|
||||
}
|
||||
|
||||
if ( p == null || weapon.PoisonCharges <= 0 )
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1061141 ); // Your weapon must have a dose of poison to perform an infectious strike!
|
||||
return;
|
||||
}
|
||||
if (!CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
if ( !CheckMana( attacker, true ) )
|
||||
return;
|
||||
--weapon.PoisonCharges;
|
||||
|
||||
--weapon.PoisonCharges;
|
||||
// Infectious strike special move now uses poisoning skill to help determine potency
|
||||
int maxLevel = attacker.Skills[SkillName.Poisoning].Fixed / 200;
|
||||
if (maxLevel < 0) maxLevel = 0;
|
||||
if (p.Level > maxLevel) p = Poison.GetPoison(maxLevel);
|
||||
|
||||
// Infectious strike special move now uses poisoning skill to help determine potency
|
||||
int maxLevel = attacker.Skills[SkillName.Poisoning].Fixed / 200;
|
||||
if ( maxLevel < 0 ) maxLevel = 0;
|
||||
if ( p.Level > maxLevel ) p = Poison.GetPoison( maxLevel );
|
||||
if (attacker.Skills[SkillName.Poisoning].Value / 100.0 > Utility.RandomDouble())
|
||||
{
|
||||
int level = p.Level + 1;
|
||||
Poison newPoison = Poison.GetPoison(level);
|
||||
|
||||
if ( (attacker.Skills[SkillName.Poisoning].Value / 100.0) > Utility.RandomDouble() )
|
||||
{
|
||||
int level = p.Level + 1;
|
||||
Poison newPoison = Poison.GetPoison( level );
|
||||
if (newPoison != null)
|
||||
{
|
||||
p = newPoison;
|
||||
|
||||
if ( newPoison != null )
|
||||
{
|
||||
p = newPoison;
|
||||
attacker.SendLocalizedMessage(1060080); // Your precise strike has increased the level of the poison by 1
|
||||
defender.SendLocalizedMessage(1060081); // The poison seems extra effective!
|
||||
}
|
||||
}
|
||||
|
||||
attacker.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);
|
||||
|
||||
defender.PlaySound( 0xDD );
|
||||
defender.FixedParticles( 0x3728, 244, 25, 9941, 1266, 0, EffectLayer.Waist );
|
||||
|
||||
if ( defender.ApplyPoison( attacker, p ) != ApplyPoisonResult.Immune )
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1008096, true, defender.Name ); // You have poisoned your target :
|
||||
defender.SendLocalizedMessage( 1008097, false, attacker.Name ); // : poisoned you!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (defender.ApplyPoison(attacker, p) != ApplyPoisonResult.Immune)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1008096, true, defender.Name); // You have poisoned your target :
|
||||
defender.SendLocalizedMessage(1008097, false, attacker.Name); // : poisoned you!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,92 +3,85 @@ using System.Collections;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// The assassin's friend.
|
||||
/// A successful Mortal Strike will render its victim unable to heal any damage for several seconds.
|
||||
/// Use a gruesome follow-up to finish off your foe.
|
||||
/// </summary>
|
||||
public class MortalStrike : WeaponAbility
|
||||
{
|
||||
public MortalStrike()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// The assassin's friend.
|
||||
/// A successful Mortal Strike will render its victim unable to heal any damage for several seconds.
|
||||
/// Use a gruesome follow-up to finish off your foe.
|
||||
/// </summary>
|
||||
public class MortalStrike : WeaponAbility
|
||||
{
|
||||
public static readonly TimeSpan PlayerDuration = TimeSpan.FromSeconds(6.0);
|
||||
public static readonly TimeSpan NPCDuration = TimeSpan.FromSeconds(12.0);
|
||||
|
||||
public override int BaseMana => 30;
|
||||
private static Hashtable m_Table = new Hashtable();
|
||||
|
||||
public static readonly TimeSpan PlayerDuration = TimeSpan.FromSeconds( 6.0 );
|
||||
public static readonly TimeSpan NPCDuration = TimeSpan.FromSeconds( 12.0 );
|
||||
public override int BaseMana => 30;
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true)) return;
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage( 1060086 ); // You deliver a mortal wound!
|
||||
defender.SendLocalizedMessage( 1060087 ); // You have been mortally wounded!
|
||||
attacker.SendLocalizedMessage(1060086); // You deliver a mortal wound!
|
||||
defender.SendLocalizedMessage(1060087); // You have been mortally wounded!
|
||||
|
||||
defender.PlaySound( 0x1E1 );
|
||||
defender.FixedParticles( 0x37B9, 244, 25, 9944, 31, 0, EffectLayer.Waist );
|
||||
defender.PlaySound(0x1E1);
|
||||
defender.FixedParticles(0x37B9, 244, 25, 9944, 31, 0, EffectLayer.Waist);
|
||||
|
||||
// Do not reset timer if one is already in place.
|
||||
if ( !IsWounded( defender ) )
|
||||
BeginWound( defender, defender.Player ? PlayerDuration : NPCDuration );
|
||||
}
|
||||
// Do not reset timer if one is already in place.
|
||||
if (!IsWounded(defender))
|
||||
BeginWound(defender, defender.Player ? PlayerDuration : NPCDuration);
|
||||
}
|
||||
|
||||
private static Hashtable m_Table = new Hashtable();
|
||||
public static bool IsWounded(Mobile m)
|
||||
{
|
||||
return m_Table.Contains(m);
|
||||
}
|
||||
|
||||
public static bool IsWounded( Mobile m )
|
||||
{
|
||||
return m_Table.Contains( m );
|
||||
}
|
||||
public static void BeginWound(Mobile m, TimeSpan duration)
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
|
||||
public static void BeginWound( Mobile m, TimeSpan duration )
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
t?.Stop();
|
||||
|
||||
t?.Stop();
|
||||
t = new InternalTimer(m, duration);
|
||||
m_Table[m] = t;
|
||||
|
||||
t = new InternalTimer( m, duration );
|
||||
m_Table[m] = t;
|
||||
t.Start();
|
||||
|
||||
t.Start();
|
||||
m.YellowHealthbar = true;
|
||||
}
|
||||
|
||||
m.YellowHealthbar = true;
|
||||
}
|
||||
public static void EndWound(Mobile m)
|
||||
{
|
||||
if (!IsWounded(m))
|
||||
return;
|
||||
|
||||
public static void EndWound( Mobile m )
|
||||
{
|
||||
if ( !IsWounded( m ) )
|
||||
return;
|
||||
Timer t = (Timer)m_Table[m];
|
||||
|
||||
Timer t = (Timer)m_Table[m];
|
||||
t?.Stop();
|
||||
|
||||
t?.Stop();
|
||||
m_Table.Remove(m);
|
||||
|
||||
m_Table.Remove( m );
|
||||
m.YellowHealthbar = false;
|
||||
m.SendLocalizedMessage(1060208); // You are no longer mortally wounded.
|
||||
}
|
||||
|
||||
m.YellowHealthbar = false;
|
||||
m.SendLocalizedMessage( 1060208 ); // You are no longer mortally wounded.
|
||||
}
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
public InternalTimer(Mobile m, TimeSpan duration) : base(duration)
|
||||
{
|
||||
m_Mobile = m;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
public InternalTimer( Mobile m, TimeSpan duration ) : base( duration )
|
||||
{
|
||||
m_Mobile = m;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
EndWound( m_Mobile );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void OnTick()
|
||||
{
|
||||
EndWound(m_Mobile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +1,37 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Available on some crossbows, this special move allows archers to fire while on the move.
|
||||
/// This shot is somewhat less accurate than normal, but the ability to fire while running is a clear advantage.
|
||||
/// </summary>
|
||||
public class MovingShot : WeaponAbility
|
||||
{
|
||||
public MovingShot()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Available on some crossbows, this special move allows archers to fire while on the move.
|
||||
/// This shot is somewhat less accurate than normal, but the ability to fire while running is a clear advantage.
|
||||
/// </summary>
|
||||
public class MovingShot : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 15;
|
||||
public override int AccuracyBonus => -25;
|
||||
|
||||
public override int BaseMana => 15;
|
||||
public override int AccuracyBonus => -25;
|
||||
public override bool ValidatesDuringHit => false;
|
||||
|
||||
public override bool OnBeforeSwing( Mobile attacker, Mobile defender )
|
||||
{
|
||||
return ( Validate( attacker ) && CheckMana( attacker, true ) );
|
||||
}
|
||||
public override bool OnBeforeSwing(Mobile attacker, Mobile defender)
|
||||
{
|
||||
return Validate(attacker) && CheckMana(attacker, true);
|
||||
}
|
||||
|
||||
public override void OnMiss( Mobile attacker, Mobile defender )
|
||||
{
|
||||
//Validates in OnSwing for accuracy scalar
|
||||
public override void OnMiss(Mobile attacker, Mobile defender)
|
||||
{
|
||||
//Validates in OnSwing for accuracy scalar
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage( 1060089 ); // You fail to execute your special move
|
||||
}
|
||||
attacker.SendLocalizedMessage(1060089); // You fail to execute your special move
|
||||
}
|
||||
|
||||
public override bool ValidatesDuringHit => false;
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
//Validates in OnSwing for accuracy scalar
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
//Validates in OnSwing for accuracy scalar
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
|
||||
attacker.SendLocalizedMessage( 1060216 ); // Your shot was successful
|
||||
}
|
||||
}
|
||||
}
|
||||
attacker.SendLocalizedMessage(1060216); // Your shot was successful
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,79 +2,80 @@ using System;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Does damage and paralyses your opponent for a short time.
|
||||
/// </summary>
|
||||
public class NerveStrike : WeaponAbility
|
||||
{
|
||||
public NerveStrike()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Does damage and paralyses your opponent for a short time.
|
||||
/// </summary>
|
||||
public class NerveStrike : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 30;
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (GetSkill(from, SkillName.Bushido) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1070768,
|
||||
"50"); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( GetSkill( from, SkillName.Bushido ) < 50.0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1070768, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
return base.CheckSkills( from );
|
||||
}
|
||||
public override bool OnBeforeSwing(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (defender.Paralyzed)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1061923); // The target is already frozen.
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool OnBeforeSwing( Mobile attacker, Mobile defender )
|
||||
{
|
||||
if ( defender.Paralyzed )
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1061923 ); // The target is already frozen.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
bool cantpara = Items.ParalyzingBlow.IsImmune(defender);
|
||||
|
||||
bool cantpara = Server.Items.ParalyzingBlow.IsImmune(defender);
|
||||
if (cantpara)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1070804); // Your target resists paralysis.
|
||||
defender.SendLocalizedMessage(1070813); // You resist paralysis.
|
||||
}
|
||||
else
|
||||
{
|
||||
attacker.SendLocalizedMessage(1063356); // You cripple your target with a nerve strike!
|
||||
defender.SendLocalizedMessage(1063357); // Your attacker dealt a crippling nerve strike!
|
||||
}
|
||||
|
||||
if ( cantpara )
|
||||
{
|
||||
attacker.SendLocalizedMessage(1070804); // Your target resists paralysis.
|
||||
defender.SendLocalizedMessage(1070813); // You resist paralysis.
|
||||
}
|
||||
else
|
||||
{
|
||||
attacker.SendLocalizedMessage(1063356); // You cripple your target with a nerve strike!
|
||||
defender.SendLocalizedMessage(1063357); // Your attacker dealt a crippling nerve strike!
|
||||
}
|
||||
attacker.PlaySound(0x204);
|
||||
defender.FixedEffect(0x376A, 9, 32);
|
||||
defender.FixedParticles(0x37C4, 1, 8, 0x13AF, 0, 0, EffectLayer.Waist);
|
||||
|
||||
attacker.PlaySound(0x204);
|
||||
defender.FixedEffect(0x376A, 9, 32);
|
||||
defender.FixedParticles(0x37C4, 1, 8, 0x13AF, 0, 0, EffectLayer.Waist);
|
||||
if (Core.ML)
|
||||
{
|
||||
AOS.Damage(defender, attacker,
|
||||
(int)(15.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + Utility.Random(10)), true, 100,
|
||||
0, 0, 0, 0); //0-25
|
||||
|
||||
if ( Core.ML )
|
||||
{
|
||||
AOS.Damage( defender, attacker, (int)( 15.0 * ( attacker.Skills[SkillName.Bushido].Value - 50.0 ) / 70.0 + Utility.Random( 10 ) ), true, 100, 0, 0, 0, 0 ); //0-25
|
||||
|
||||
if (!cantpara && ((150.0 / 7.0 + (4.0 * attacker.Skills[SkillName.Bushido].Value) / 7.0) / 100.0) > Utility.RandomDouble())
|
||||
{
|
||||
defender.Paralyze( TimeSpan.FromSeconds( 2.0 ) );
|
||||
Server.Items.ParalyzingBlow.BeginImmunity( defender, Server.Items.ParalyzingBlow.FreezeDelayDuration );
|
||||
}
|
||||
}
|
||||
else if ( !cantpara )
|
||||
{
|
||||
AOS.Damage( defender, attacker, (int)(15.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 10), true, 100, 0, 0, 0, 0 ); //10-25
|
||||
defender.Freeze(TimeSpan.FromSeconds(2.0));
|
||||
Server.Items.ParalyzingBlow.BeginImmunity(defender, Server.Items.ParalyzingBlow.FreezeDelayDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cantpara && (150.0 / 7.0 + 4.0 * attacker.Skills[SkillName.Bushido].Value / 7.0) / 100.0 >
|
||||
Utility.RandomDouble())
|
||||
{
|
||||
defender.Paralyze(TimeSpan.FromSeconds(2.0));
|
||||
Items.ParalyzingBlow.BeginImmunity(defender, Items.ParalyzingBlow.FreezeDelayDuration);
|
||||
}
|
||||
}
|
||||
else if (!cantpara)
|
||||
{
|
||||
AOS.Damage(defender, attacker, (int)(15.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 10),
|
||||
true, 100, 0, 0, 0, 0); //10-25
|
||||
defender.Freeze(TimeSpan.FromSeconds(2.0));
|
||||
Items.ParalyzingBlow.BeginImmunity(defender, Items.ParalyzingBlow.FreezeDelayDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,130 +3,126 @@ using System.Collections;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// A successful Paralyzing Blow will leave the target stunned, unable to move, attack, or cast spells, for a few seconds.
|
||||
/// </summary>
|
||||
public class ParalyzingBlow : WeaponAbility
|
||||
{
|
||||
public ParalyzingBlow()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// A successful Paralyzing Blow will leave the target stunned, unable to move, attack, or cast spells, for a few seconds.
|
||||
/// </summary>
|
||||
public class ParalyzingBlow : WeaponAbility
|
||||
{
|
||||
public static readonly TimeSpan PlayerFreezeDuration = TimeSpan.FromSeconds(3.0);
|
||||
public static readonly TimeSpan NPCFreezeDuration = TimeSpan.FromSeconds(6.0);
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public static readonly TimeSpan FreezeDelayDuration = TimeSpan.FromSeconds(8.0);
|
||||
|
||||
public static readonly TimeSpan PlayerFreezeDuration = TimeSpan.FromSeconds( 3.0 );
|
||||
public static readonly TimeSpan NPCFreezeDuration = TimeSpan.FromSeconds( 6.0 );
|
||||
private static Hashtable m_Table = new Hashtable();
|
||||
|
||||
public static readonly TimeSpan FreezeDelayDuration = TimeSpan.FromSeconds( 8.0 );
|
||||
public override int BaseMana => 30;
|
||||
|
||||
// No longer active in pub21:
|
||||
/*public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( !base.CheckSkills( from ) )
|
||||
return false;
|
||||
// No longer active in pub21:
|
||||
/*public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( !base.CheckSkills( from ) )
|
||||
return false;
|
||||
|
||||
if ( !(from.Weapon is Fists) )
|
||||
return true;
|
||||
if ( !(from.Weapon is Fists) )
|
||||
return true;
|
||||
|
||||
Skill skill = from.Skills[SkillName.Anatomy];
|
||||
Skill skill = from.Skills[SkillName.Anatomy];
|
||||
|
||||
if ( skill != null && skill.Base >= 80.0 )
|
||||
return true;
|
||||
if ( skill != null && skill.Base >= 80.0 )
|
||||
return true;
|
||||
|
||||
from.SendLocalizedMessage( 1061811 ); // You lack the required anatomy skill to perform that attack!
|
||||
from.SendLocalizedMessage( 1061811 ); // You lack the required anatomy skill to perform that attack!
|
||||
|
||||
return false;
|
||||
}*/
|
||||
return false;
|
||||
}*/
|
||||
|
||||
public override bool RequiresTactics( Mobile from )
|
||||
{
|
||||
if ( !(from.Weapon is BaseWeapon weapon) )
|
||||
return true;
|
||||
public override bool RequiresTactics(Mobile from)
|
||||
{
|
||||
if (!(from.Weapon is BaseWeapon weapon))
|
||||
return true;
|
||||
|
||||
return weapon.Skill != SkillName.Wrestling;
|
||||
}
|
||||
return weapon.Skill != SkillName.Wrestling;
|
||||
}
|
||||
|
||||
public override bool OnBeforeSwing( Mobile attacker, Mobile defender )
|
||||
{
|
||||
if ( defender.Paralyzed )
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1061923 ); // The target is already frozen.
|
||||
return false;
|
||||
}
|
||||
public override bool OnBeforeSwing(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (defender.Paralyzed)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1061923); // The target is already frozen.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
if ( IsImmune( defender ) ) //Intentionally going after Mana consumption
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1070804 ); // Your target resists paralysis.
|
||||
defender.SendLocalizedMessage( 1070813 ); // You resist paralysis.
|
||||
return;
|
||||
}
|
||||
if (IsImmune(defender)) //Intentionally going after Mana consumption
|
||||
{
|
||||
attacker.SendLocalizedMessage(1070804); // Your target resists paralysis.
|
||||
defender.SendLocalizedMessage(1070813); // You resist paralysis.
|
||||
return;
|
||||
}
|
||||
|
||||
defender.FixedEffect( 0x376A, 9, 32 );
|
||||
defender.PlaySound( 0x204 );
|
||||
defender.FixedEffect(0x376A, 9, 32);
|
||||
defender.PlaySound(0x204);
|
||||
|
||||
attacker.SendLocalizedMessage( 1060163 ); // You deliver a paralyzing blow!
|
||||
defender.SendLocalizedMessage( 1060164 ); // The attack has temporarily paralyzed you!
|
||||
attacker.SendLocalizedMessage(1060163); // You deliver a paralyzing blow!
|
||||
defender.SendLocalizedMessage(1060164); // The attack has temporarily paralyzed you!
|
||||
|
||||
TimeSpan duration = defender.Player ? PlayerFreezeDuration : NPCFreezeDuration;
|
||||
TimeSpan duration = defender.Player ? PlayerFreezeDuration : NPCFreezeDuration;
|
||||
|
||||
// Treat it as paralyze not as freeze, effect must be removed when damaged.
|
||||
defender.Paralyze( duration );
|
||||
// Treat it as paralyze not as freeze, effect must be removed when damaged.
|
||||
defender.Paralyze(duration);
|
||||
|
||||
BeginImmunity( defender, duration + FreezeDelayDuration );
|
||||
}
|
||||
BeginImmunity(defender, duration + FreezeDelayDuration);
|
||||
}
|
||||
|
||||
private static Hashtable m_Table = new Hashtable();
|
||||
public static bool IsImmune(Mobile m)
|
||||
{
|
||||
return m_Table.Contains(m);
|
||||
}
|
||||
|
||||
public static bool IsImmune( Mobile m )
|
||||
{
|
||||
return m_Table.Contains( m );
|
||||
}
|
||||
public static void BeginImmunity(Mobile m, TimeSpan duration)
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
|
||||
public static void BeginImmunity( Mobile m, TimeSpan duration )
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
t?.Stop();
|
||||
|
||||
t?.Stop();
|
||||
t = new InternalTimer(m, duration);
|
||||
m_Table[m] = t;
|
||||
|
||||
t = new InternalTimer( m, duration );
|
||||
m_Table[m] = t;
|
||||
t.Start();
|
||||
}
|
||||
|
||||
t.Start();
|
||||
}
|
||||
public static void EndImmunity(Mobile m)
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
|
||||
public static void EndImmunity( Mobile m )
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
t?.Stop();
|
||||
|
||||
t?.Stop();
|
||||
m_Table.Remove(m);
|
||||
}
|
||||
|
||||
m_Table.Remove( m );
|
||||
}
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
public InternalTimer(Mobile m, TimeSpan duration) : base(duration)
|
||||
{
|
||||
m_Mobile = m;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
public InternalTimer( Mobile m, TimeSpan duration ) : base( duration )
|
||||
{
|
||||
m_Mobile = m;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
EndImmunity( m_Mobile );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void OnTick()
|
||||
{
|
||||
EndImmunity(m_Mobile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +1,77 @@
|
|||
|
||||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// If you are on foot, dismounts your opponent and damage the ethereal's rider or the
|
||||
/// living mount(which must be healed before ridden again). If you are mounted, damages
|
||||
/// and stuns the mounted opponent.
|
||||
/// </summary>
|
||||
public class RidingSwipe : WeaponAbility
|
||||
{
|
||||
public RidingSwipe()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// If you are on foot, dismounts your opponent and damage the ethereal's rider or the
|
||||
/// living mount(which must be healed before ridden again). If you are mounted, damages
|
||||
/// and stuns the mounted opponent.
|
||||
/// </summary>
|
||||
public class RidingSwipe : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 30;
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override bool RequiresSE => true;
|
||||
|
||||
public override bool RequiresSE => true;
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (GetSkill(from, SkillName.Bushido) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1070768,
|
||||
"50"); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( GetSkill( from, SkillName.Bushido ) < 50.0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1070768, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
return base.CheckSkills( from );
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!defender.Mounted)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1060848); // This attack only works on mounted targets
|
||||
ClearCurrentAbility(attacker);
|
||||
return;
|
||||
}
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !defender.Mounted )
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1060848 ); // This attack only works on mounted targets
|
||||
ClearCurrentAbility( attacker );
|
||||
return;
|
||||
}
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
if (!attacker.Mounted)
|
||||
{
|
||||
Mobile mount = defender.Mount as Mobile;
|
||||
BaseMount.Dismount(defender);
|
||||
|
||||
if ( !attacker.Mounted )
|
||||
{
|
||||
Mobile mount = defender.Mount as Mobile;
|
||||
BaseMount.Dismount( defender );
|
||||
if (mount != null) //Ethy mounts don't take damage
|
||||
{
|
||||
int amount = 10 + (int)(10.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 5);
|
||||
|
||||
if ( mount != null ) //Ethy mounts don't take damage
|
||||
{
|
||||
int amount = 10 + (int)(10.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 5);
|
||||
AOS.Damage(mount, null, amount, 100, 0, 0, 0,
|
||||
0); //The mount just takes damage, there's no flagging as if it was attacking the mount directly
|
||||
|
||||
AOS.Damage( mount, null, amount, 100, 0, 0, 0, 0 ); //The mount just takes damage, there's no flagging as if it was attacking the mount directly
|
||||
//TODO: Mount prevention until mount healed
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int amount = 10 + (int)(10.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 5);
|
||||
|
||||
//TODO: Mount prevention until mount healed
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int amount = 10 + (int)(10.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 5);
|
||||
AOS.Damage(defender, attacker, amount, 100, 0, 0, 0, 0);
|
||||
|
||||
AOS.Damage( defender, attacker, amount, 100, 0, 0, 0, 0 );
|
||||
|
||||
if ( Server.Items.ParalyzingBlow.IsImmune( defender ) ) //Does it still do damage?
|
||||
{
|
||||
attacker.SendLocalizedMessage( 1070804 ); // Your target resists paralysis.
|
||||
defender.SendLocalizedMessage( 1070813 ); // You resist paralysis.
|
||||
}
|
||||
else
|
||||
{
|
||||
defender.Paralyze( TimeSpan.FromSeconds( 3.0 ) );
|
||||
Server.Items.ParalyzingBlow.BeginImmunity( defender, Server.Items.ParalyzingBlow.FreezeDelayDuration );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Items.ParalyzingBlow.IsImmune(defender)) //Does it still do damage?
|
||||
{
|
||||
attacker.SendLocalizedMessage(1070804); // Your target resists paralysis.
|
||||
defender.SendLocalizedMessage(1070813); // You resist paralysis.
|
||||
}
|
||||
else
|
||||
{
|
||||
defender.Paralyze(TimeSpan.FromSeconds(3.0));
|
||||
Items.ParalyzingBlow.BeginImmunity(defender, Items.ParalyzingBlow.FreezeDelayDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +1,54 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This powerful ability requires secondary skills to activate.
|
||||
/// Successful use of Shadowstrike deals extra damage to the target <20> and renders the attacker invisible!
|
||||
/// Only those who are adept at the art of stealth will be able to use this ability.
|
||||
/// </summary>
|
||||
public class ShadowStrike : WeaponAbility
|
||||
{
|
||||
public ShadowStrike()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// This powerful ability requires secondary skills to activate.
|
||||
/// Successful use of Shadowstrike deals extra damage to the target <20> and renders the attacker invisible!
|
||||
/// Only those who are adept at the art of stealth will be able to use this ability.
|
||||
/// </summary>
|
||||
public class ShadowStrike : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 20;
|
||||
public override double DamageScalar => 1.25;
|
||||
|
||||
public override int BaseMana => 20;
|
||||
public override double DamageScalar => 1.25;
|
||||
public override bool RequiresTactics(Mobile from)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool RequiresTactics( Mobile from )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (!base.CheckSkills(from))
|
||||
return false;
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( !base.CheckSkills( from ) )
|
||||
return false;
|
||||
Skill skill = from.Skills[SkillName.Stealth];
|
||||
|
||||
Skill skill = from.Skills[SkillName.Stealth];
|
||||
if (skill != null && skill.Value >= 80.0)
|
||||
return true;
|
||||
|
||||
if ( skill != null && skill.Value >= 80.0 )
|
||||
return true;
|
||||
from.SendLocalizedMessage(1060183); // You lack the required stealth to perform that attack
|
||||
|
||||
from.SendLocalizedMessage( 1060183 ); // You lack the required stealth to perform that attack
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
attacker.SendLocalizedMessage(1060078); // You strike and hide in the shadows!
|
||||
defender.SendLocalizedMessage(1060079); // You are dazed by the attack and your attacker vanishes!
|
||||
|
||||
attacker.SendLocalizedMessage( 1060078 ); // You strike and hide in the shadows!
|
||||
defender.SendLocalizedMessage( 1060079 ); // You are dazed by the attack and your attacker vanishes!
|
||||
Effects.SendLocationParticles(EffectItem.Create(attacker.Location, attacker.Map, EffectItem.DefaultDuration),
|
||||
0x376A, 8, 12, 9943);
|
||||
attacker.PlaySound(0x482);
|
||||
|
||||
Effects.SendLocationParticles( EffectItem.Create( attacker.Location, attacker.Map, EffectItem.DefaultDuration ), 0x376A, 8, 12, 9943 );
|
||||
attacker.PlaySound( 0x482 );
|
||||
defender.FixedEffect(0x37BE, 20, 25);
|
||||
|
||||
defender.FixedEffect( 0x37BE, 20, 25 );
|
||||
|
||||
attacker.Combatant = null;
|
||||
attacker.Warmode = false;
|
||||
attacker.Hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
attacker.Combatant = null;
|
||||
attacker.Warmode = false;
|
||||
attacker.Hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,104 +1,101 @@
|
|||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Attack with increased damage with additional damage over time.
|
||||
/// </summary>
|
||||
public class TalonStrike : WeaponAbility
|
||||
{
|
||||
public static Hashtable Registry { get; } = new Hashtable();
|
||||
/// <summary>
|
||||
/// Attack with increased damage with additional damage over time.
|
||||
/// </summary>
|
||||
public class TalonStrike : WeaponAbility
|
||||
{
|
||||
public static Hashtable Registry{ get; } = new Hashtable();
|
||||
|
||||
public TalonStrike()
|
||||
{
|
||||
}
|
||||
public override int BaseMana => 30;
|
||||
public override double DamageScalar => 1.2;
|
||||
|
||||
public override int BaseMana => 30;
|
||||
public override double DamageScalar => 1.2;
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (GetSkill(from, SkillName.Ninjitsu) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1063352,
|
||||
"50"); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CheckSkills( Mobile from )
|
||||
{
|
||||
if ( GetSkill( from, SkillName.Ninjitsu ) < 50.0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063352, "50" ); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
return base.CheckSkills( from );
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (Registry.Contains(defender) || !Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( Registry.Contains( defender ) || !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
attacker.SendLocalizedMessage(1063358); // You deliver a talon strike!
|
||||
defender.SendLocalizedMessage(1063359); // Your attacker delivers a talon strike!
|
||||
|
||||
attacker.SendLocalizedMessage( 1063358 ); // You deliver a talon strike!
|
||||
defender.SendLocalizedMessage( 1063359 ); // Your attacker delivers a talon strike!
|
||||
defender.FixedParticles(0x373A, 1, 17, 0x26BC, 0x662, 0, EffectLayer.Waist);
|
||||
|
||||
defender.FixedParticles( 0x373A, 1, 17, 0x26BC, 0x662, 0, EffectLayer.Waist );
|
||||
Timer t = new InternalTimer(defender,
|
||||
(int)(10.0 * (attacker.Skills[SkillName.Ninjitsu].Value - 50.0) / 70.0 + 5), attacker); //5 - 15 damage
|
||||
|
||||
Timer t = new InternalTimer( defender, (int)(10.0 * (attacker.Skills[SkillName.Ninjitsu].Value - 50.0) / 70.0 + 5), attacker ); //5 - 15 damage
|
||||
t.Start();
|
||||
|
||||
t.Start();
|
||||
Registry.Add(defender, t);
|
||||
}
|
||||
|
||||
Registry.Add( defender, t );
|
||||
}
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private readonly double DamagePerTick;
|
||||
private Mobile m_Attacker;
|
||||
private double m_DamageRemaining;
|
||||
private double m_DamageToDo;
|
||||
private Mobile m_Defender;
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Mobile m_Defender;
|
||||
private double m_DamageRemaining;
|
||||
private double m_DamageToDo;
|
||||
private Mobile m_Attacker;
|
||||
public InternalTimer(Mobile defender, int totalDamage, Mobile attacker)
|
||||
: base(TimeSpan.Zero, TimeSpan.FromSeconds(0.25),
|
||||
12) // 3 seconds at .25 seconds apart = 12. Confirm delay inbetween of .25 each.
|
||||
{
|
||||
m_Defender = defender;
|
||||
m_DamageRemaining = totalDamage;
|
||||
Priority = TimerPriority.TwentyFiveMS;
|
||||
|
||||
private readonly double DamagePerTick;
|
||||
m_Attacker = attacker;
|
||||
|
||||
public InternalTimer( Mobile defender, int totalDamage, Mobile attacker )
|
||||
: base( TimeSpan.Zero, TimeSpan.FromSeconds( 0.25 ), 12 ) // 3 seconds at .25 seconds apart = 12. Confirm delay inbetween of .25 each.
|
||||
{
|
||||
m_Defender = defender;
|
||||
m_DamageRemaining = (double)totalDamage;
|
||||
Priority = TimerPriority.TwentyFiveMS;
|
||||
DamagePerTick = (double)totalDamage / 12 + .01;
|
||||
}
|
||||
|
||||
m_Attacker = attacker;
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (!m_Defender.Alive || m_DamageRemaining <= 0)
|
||||
{
|
||||
Stop();
|
||||
Registry.Remove(m_Defender);
|
||||
return;
|
||||
}
|
||||
|
||||
DamagePerTick = (double)totalDamage / 12+.01;
|
||||
}
|
||||
m_DamageRemaining -= DamagePerTick;
|
||||
m_DamageToDo += DamagePerTick;
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if ( !m_Defender.Alive || m_DamageRemaining <= 0 )
|
||||
{
|
||||
Stop();
|
||||
Registry.Remove( m_Defender );
|
||||
return;
|
||||
}
|
||||
if (m_DamageRemaining <= 0 && m_DamageToDo < 1)
|
||||
m_DamageToDo = 1.0; //Confirm this 'round up' at the end
|
||||
|
||||
m_DamageRemaining -= DamagePerTick;
|
||||
m_DamageToDo += DamagePerTick;
|
||||
int damage = (int)m_DamageToDo;
|
||||
|
||||
if ( m_DamageRemaining <= 0 && m_DamageToDo < 1 )
|
||||
m_DamageToDo = 1.0; //Confirm this 'round up' at the end
|
||||
if (damage > 0)
|
||||
{
|
||||
//m_Defender.Damage( damage, m_Attacker, false );
|
||||
m_Defender.Hits -= damage; //Don't show damage, don't disrupt
|
||||
m_DamageToDo -= damage;
|
||||
}
|
||||
|
||||
int damage = (int)m_DamageToDo;
|
||||
|
||||
if ( damage > 0 )
|
||||
{
|
||||
//m_Defender.Damage( damage, m_Attacker, false );
|
||||
m_Defender.Hits -= damage; //Don't show damage, don't disrupt
|
||||
m_DamageToDo -= damage;
|
||||
}
|
||||
|
||||
if ( !m_Defender.Alive || m_DamageRemaining <= 0 )
|
||||
{
|
||||
Stop();
|
||||
Registry.Remove( m_Defender );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_Defender.Alive || m_DamageRemaining <= 0)
|
||||
{
|
||||
Stop();
|
||||
Registry.Remove(m_Defender);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,478 +1,484 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using Server.Engines.ConPVP;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Spells;
|
||||
using Server.Mobiles;
|
||||
using Server.Spells.Bushido;
|
||||
using Server.Spells.Necromancy;
|
||||
using Server.Spells.Ninjitsu;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public abstract class WeaponAbility
|
||||
{
|
||||
public virtual int BaseMana => 0;
|
||||
|
||||
public virtual int AccuracyBonus => 0;
|
||||
public virtual double DamageScalar => 1.0;
|
||||
|
||||
public virtual bool RequiresSE => false;
|
||||
|
||||
public virtual void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnMiss( Mobile attacker, Mobile defender )
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool OnBeforeSwing( Mobile attacker, Mobile defender )
|
||||
{
|
||||
// Here because you must be sure you can use the skill before calling CheckHit if the ability has a HCI bonus for example
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool OnBeforeDamage( Mobile attacker, Mobile defender )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool RequiresTactics( Mobile from )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual double GetRequiredSkill( Mobile from )
|
||||
{
|
||||
BaseWeapon weapon = from.Weapon as BaseWeapon;
|
||||
|
||||
if ( weapon != null && weapon.PrimaryAbility == this )
|
||||
return 70.0;
|
||||
if ( weapon != null && weapon.SecondaryAbility == this )
|
||||
return 90.0;
|
||||
|
||||
return 200.0;
|
||||
}
|
||||
|
||||
public virtual int CalculateMana( Mobile from )
|
||||
{
|
||||
int mana = BaseMana;
|
||||
|
||||
double skillTotal = GetSkill( from, SkillName.Swords ) + GetSkill( from, SkillName.Macing )
|
||||
+ GetSkill( from, SkillName.Fencing ) + GetSkill( from, SkillName.Archery ) + GetSkill( from, SkillName.Parry )
|
||||
+ GetSkill( from, SkillName.Lumberjacking ) + GetSkill( from, SkillName.Stealth )
|
||||
+ GetSkill( from, SkillName.Poisoning ) + GetSkill( from, SkillName.Bushido ) + GetSkill( from, SkillName.Ninjitsu );
|
||||
|
||||
if ( skillTotal >= 300.0 )
|
||||
mana -= 10;
|
||||
else if ( skillTotal >= 200.0 )
|
||||
mana -= 5;
|
||||
|
||||
double scalar = 1.0;
|
||||
if ( !Spells.Necromancy.MindRotSpell.GetMindRotScalar( from, ref scalar ) )
|
||||
scalar = 1.0;
|
||||
|
||||
// Lower Mana Cost = 40%
|
||||
int lmc = Math.Min( AosAttributes.GetValue( from, AosAttribute.LowerManaCost ), 40 );
|
||||
|
||||
scalar -= (double)lmc / 100;
|
||||
mana = (int)(mana * scalar);
|
||||
|
||||
// Using a special move within 3 seconds of the previous special move costs double mana
|
||||
if ( GetContext( from ) != null )
|
||||
mana *= 2;
|
||||
|
||||
return mana;
|
||||
}
|
||||
|
||||
public virtual bool CheckWeaponSkill( Mobile from )
|
||||
{
|
||||
if ( !(from.Weapon is BaseWeapon weapon) )
|
||||
return false;
|
||||
|
||||
Skill skill = from.Skills[weapon.Skill];
|
||||
double reqSkill = GetRequiredSkill( from );
|
||||
bool reqTactics = Core.ML && RequiresTactics( from );
|
||||
|
||||
if ( Core.ML && reqTactics && from.Skills[SkillName.Tactics].Base < reqSkill )
|
||||
{
|
||||
from.SendLocalizedMessage( 1079308, reqSkill.ToString() ); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( skill != null && skill.Base >= reqSkill )
|
||||
return true;
|
||||
|
||||
/* <UBWS> */
|
||||
if ( weapon.WeaponAttributes.UseBestSkill > 0 && (from.Skills[SkillName.Swords].Base >= reqSkill || from.Skills[SkillName.Macing].Base >= reqSkill || from.Skills[SkillName.Fencing].Base >= reqSkill) )
|
||||
return true;
|
||||
/* </UBWS> */
|
||||
|
||||
if ( reqTactics )
|
||||
{
|
||||
from.SendLocalizedMessage( 1079308, reqSkill.ToString() ); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage( 1060182, reqSkill.ToString() ); // You need ~1_SKILL_REQUIREMENT~ weapon skill to perform that attack
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual bool CheckSkills( Mobile from )
|
||||
{
|
||||
return CheckWeaponSkill( from );
|
||||
}
|
||||
|
||||
public virtual double GetSkill( Mobile from, SkillName skillName )
|
||||
{
|
||||
Skill skill = from.Skills[skillName];
|
||||
|
||||
if ( skill == null )
|
||||
return 0.0;
|
||||
|
||||
return skill.Value;
|
||||
}
|
||||
|
||||
public virtual bool CheckMana( Mobile from, bool consume )
|
||||
{
|
||||
int mana = CalculateMana( from );
|
||||
|
||||
if ( from.Mana < mana )
|
||||
{
|
||||
if ( from is BaseCreature creature && creature.HasManaOveride )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
from.SendLocalizedMessage( 1060181, mana.ToString() ); // You need ~1_MANA_REQUIREMENT~ mana to perform that attack
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( consume )
|
||||
{
|
||||
if ( GetContext( from ) == null )
|
||||
{
|
||||
Timer timer = new WeaponAbilityTimer( from );
|
||||
timer.Start();
|
||||
|
||||
AddContext( from, new WeaponAbilityContext( timer ) );
|
||||
}
|
||||
|
||||
from.Mana -= mana;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool Validate( Mobile from )
|
||||
{
|
||||
if ( !from.Player )
|
||||
return true;
|
||||
|
||||
NetState state = from.NetState;
|
||||
|
||||
if ( state == null )
|
||||
return false;
|
||||
|
||||
if ( RequiresSE && !state.SupportsExpansion( Expansion.SE ) )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063456 ); // You must upgrade to Samurai Empire in order to use that ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( Spells.Bushido.HonorableExecution.IsUnderPenalty( from ) || Spells.Ninjitsu.AnimalForm.UnderTransformation( from ) )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063024 ); // You cannot perform this special move right now.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( Core.ML && from.Spell != null )
|
||||
{
|
||||
from.SendLocalizedMessage( 1063024 ); // You cannot perform this special move right now.
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Dueling
|
||||
string option = null;
|
||||
|
||||
if ( this is ArmorIgnore )
|
||||
option = "Armor Ignore";
|
||||
else if ( this is BleedAttack )
|
||||
option = "Bleed Attack";
|
||||
else if ( this is ConcussionBlow )
|
||||
option = "Concussion Blow";
|
||||
else if ( this is CrushingBlow )
|
||||
option = "Crushing Blow";
|
||||
else if ( this is Disarm )
|
||||
option = "Disarm";
|
||||
else if ( this is Dismount )
|
||||
option = "Dismount";
|
||||
else if ( this is DoubleStrike )
|
||||
option = "Double Strike";
|
||||
else if ( this is InfectiousStrike )
|
||||
option = "Infectious Strike";
|
||||
else if ( this is MortalStrike )
|
||||
option = "Mortal Strike";
|
||||
else if ( this is MovingShot )
|
||||
option = "Moving Shot";
|
||||
else if ( this is ParalyzingBlow )
|
||||
option = "Paralyzing Blow";
|
||||
else if ( this is ShadowStrike )
|
||||
option = "Shadow Strike";
|
||||
else if ( this is WhirlwindAttack )
|
||||
option = "Whirlwind Attack";
|
||||
else if ( this is RidingSwipe )
|
||||
option = "Riding Swipe";
|
||||
else if ( this is FrenziedWhirlwind )
|
||||
option = "Frenzied Whirlwind";
|
||||
else if ( this is Block )
|
||||
option = "Block";
|
||||
else if ( this is DefenseMastery )
|
||||
option = "Defense Mastery";
|
||||
else if ( this is NerveStrike )
|
||||
option = "Nerve Strike";
|
||||
else if ( this is TalonStrike )
|
||||
option = "Talon Strike";
|
||||
else if ( this is Feint )
|
||||
option = "Feint";
|
||||
else if ( this is DualWield )
|
||||
option = "Dual Wield";
|
||||
else if ( this is DoubleShot )
|
||||
option = "Double Shot";
|
||||
else if ( this is ArmorPierce )
|
||||
option = "Armor Pierce";
|
||||
|
||||
|
||||
if ( option != null && !Engines.ConPVP.DuelContext.AllowSpecialAbility( from, option, true ) )
|
||||
return false;
|
||||
#endregion
|
||||
|
||||
return CheckSkills( from ) && CheckMana( from, false );
|
||||
}
|
||||
|
||||
public static WeaponAbility[] Abilities { get; } = new WeaponAbility[31]
|
||||
{
|
||||
null,
|
||||
new ArmorIgnore(),
|
||||
new BleedAttack(),
|
||||
new ConcussionBlow(),
|
||||
new CrushingBlow(),
|
||||
new Disarm(),
|
||||
new Dismount(),
|
||||
new DoubleStrike(),
|
||||
new InfectiousStrike(),
|
||||
new MortalStrike(),
|
||||
new MovingShot(),
|
||||
new ParalyzingBlow(),
|
||||
new ShadowStrike(),
|
||||
new WhirlwindAttack(),
|
||||
|
||||
new RidingSwipe(),
|
||||
new FrenziedWhirlwind(),
|
||||
new Block(),
|
||||
new DefenseMastery(),
|
||||
new NerveStrike(),
|
||||
new TalonStrike(),
|
||||
new Feint(),
|
||||
new DualWield(),
|
||||
new DoubleShot(),
|
||||
new ArmorPierce(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new Disrobe()
|
||||
};
|
||||
|
||||
public static Hashtable Table { get; } = new Hashtable();
|
||||
|
||||
public static readonly WeaponAbility ArmorIgnore = Abilities[ 1];
|
||||
public static readonly WeaponAbility BleedAttack = Abilities[ 2];
|
||||
public static readonly WeaponAbility ConcussionBlow = Abilities[ 3];
|
||||
public static readonly WeaponAbility CrushingBlow = Abilities[ 4];
|
||||
public static readonly WeaponAbility Disarm = Abilities[ 5];
|
||||
public static readonly WeaponAbility Dismount = Abilities[ 6];
|
||||
public static readonly WeaponAbility DoubleStrike = Abilities[ 7];
|
||||
public static readonly WeaponAbility InfectiousStrike = Abilities[ 8];
|
||||
public static readonly WeaponAbility MortalStrike = Abilities[ 9];
|
||||
public static readonly WeaponAbility MovingShot = Abilities[10];
|
||||
public static readonly WeaponAbility ParalyzingBlow = Abilities[11];
|
||||
public static readonly WeaponAbility ShadowStrike = Abilities[12];
|
||||
public static readonly WeaponAbility WhirlwindAttack = Abilities[13];
|
||||
|
||||
public static readonly WeaponAbility RidingSwipe = Abilities[14];
|
||||
public static readonly WeaponAbility FrenziedWhirlwind = Abilities[15];
|
||||
public static readonly WeaponAbility Block = Abilities[16];
|
||||
public static readonly WeaponAbility DefenseMastery = Abilities[17];
|
||||
public static readonly WeaponAbility NerveStrike = Abilities[18];
|
||||
public static readonly WeaponAbility TalonStrike = Abilities[19];
|
||||
public static readonly WeaponAbility Feint = Abilities[20];
|
||||
public static readonly WeaponAbility DualWield = Abilities[21];
|
||||
public static readonly WeaponAbility DoubleShot = Abilities[22];
|
||||
public static readonly WeaponAbility ArmorPierce = Abilities[23];
|
||||
|
||||
public static readonly WeaponAbility Bladeweave = Abilities[24];
|
||||
public static readonly WeaponAbility ForceArrow = Abilities[25];
|
||||
public static readonly WeaponAbility LightningArrow = Abilities[26];
|
||||
public static readonly WeaponAbility PsychicAttack = Abilities[27];
|
||||
public static readonly WeaponAbility SerpentArrow = Abilities[28];
|
||||
public static readonly WeaponAbility ForceOfNature = Abilities[29];
|
||||
|
||||
public static readonly WeaponAbility Disrobe = Abilities[30];
|
||||
|
||||
public static bool IsWeaponAbility( Mobile m, WeaponAbility a )
|
||||
{
|
||||
if ( a == null )
|
||||
return true;
|
||||
|
||||
if ( !m.Player )
|
||||
return true;
|
||||
|
||||
return ( m.Weapon is BaseWeapon weapon && (weapon.PrimaryAbility == a || weapon.SecondaryAbility == a) );
|
||||
}
|
||||
|
||||
public virtual bool ValidatesDuringHit => true;
|
||||
|
||||
public static WeaponAbility GetCurrentAbility( Mobile m )
|
||||
{
|
||||
if ( !Core.AOS )
|
||||
{
|
||||
ClearCurrentAbility( m );
|
||||
return null;
|
||||
}
|
||||
|
||||
WeaponAbility a = (WeaponAbility)Table[m];
|
||||
|
||||
if ( !IsWeaponAbility( m, a ) )
|
||||
{
|
||||
ClearCurrentAbility( m );
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( a != null && a.ValidatesDuringHit && !a.Validate( m ) )
|
||||
{
|
||||
ClearCurrentAbility( m );
|
||||
return null;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
public static bool SetCurrentAbility( Mobile m, WeaponAbility a )
|
||||
{
|
||||
if ( !Core.AOS )
|
||||
{
|
||||
ClearCurrentAbility( m );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !IsWeaponAbility( m, a ) )
|
||||
{
|
||||
ClearCurrentAbility( m );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( a != null && !a.Validate( m ) )
|
||||
{
|
||||
ClearCurrentAbility( m );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( a == null )
|
||||
{
|
||||
Table.Remove( m );
|
||||
}
|
||||
else
|
||||
{
|
||||
SpecialMove.ClearCurrentMove( m );
|
||||
|
||||
Table[m] = a;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void ClearCurrentAbility( Mobile m )
|
||||
{
|
||||
Table.Remove( m );
|
||||
|
||||
if ( Core.AOS && m.NetState != null )
|
||||
m.Send( ClearWeaponAbility.Instance );
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
EventSink.SetAbility += EventSink_SetAbility;
|
||||
}
|
||||
|
||||
public WeaponAbility()
|
||||
{
|
||||
}
|
||||
|
||||
private static void EventSink_SetAbility( SetAbilityEventArgs e )
|
||||
{
|
||||
int index = e.Index;
|
||||
|
||||
if ( index == 0 )
|
||||
ClearCurrentAbility( e.Mobile );
|
||||
else if ( index >= 1 && index < Abilities.Length )
|
||||
SetCurrentAbility( e.Mobile, Abilities[index] );
|
||||
}
|
||||
|
||||
|
||||
private static Hashtable m_PlayersTable = new Hashtable();
|
||||
|
||||
private static void AddContext( Mobile m, WeaponAbilityContext context )
|
||||
{
|
||||
m_PlayersTable[m] = context;
|
||||
}
|
||||
|
||||
private static void RemoveContext( Mobile m )
|
||||
{
|
||||
WeaponAbilityContext context = GetContext( m );
|
||||
|
||||
if ( context != null )
|
||||
RemoveContext( m, context );
|
||||
}
|
||||
|
||||
private static void RemoveContext( Mobile m, WeaponAbilityContext context )
|
||||
{
|
||||
m_PlayersTable.Remove( m );
|
||||
|
||||
context.Timer.Stop();
|
||||
}
|
||||
|
||||
private static WeaponAbilityContext GetContext( Mobile m )
|
||||
{
|
||||
return ( m_PlayersTable[m] as WeaponAbilityContext );
|
||||
}
|
||||
|
||||
private class WeaponAbilityTimer : Timer
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
|
||||
public WeaponAbilityTimer( Mobile from ) : base ( TimeSpan.FromSeconds( 3.0 ) )
|
||||
{
|
||||
m_Mobile = from;
|
||||
|
||||
Priority = TimerPriority.TwentyFiveMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
RemoveContext( m_Mobile );
|
||||
}
|
||||
}
|
||||
|
||||
private class WeaponAbilityContext
|
||||
{
|
||||
public Timer Timer { get; }
|
||||
|
||||
public WeaponAbilityContext( Timer timer )
|
||||
{
|
||||
Timer = timer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract class WeaponAbility
|
||||
{
|
||||
public static readonly WeaponAbility ArmorIgnore = Abilities[1];
|
||||
public static readonly WeaponAbility BleedAttack = Abilities[2];
|
||||
public static readonly WeaponAbility ConcussionBlow = Abilities[3];
|
||||
public static readonly WeaponAbility CrushingBlow = Abilities[4];
|
||||
public static readonly WeaponAbility Disarm = Abilities[5];
|
||||
public static readonly WeaponAbility Dismount = Abilities[6];
|
||||
public static readonly WeaponAbility DoubleStrike = Abilities[7];
|
||||
public static readonly WeaponAbility InfectiousStrike = Abilities[8];
|
||||
public static readonly WeaponAbility MortalStrike = Abilities[9];
|
||||
public static readonly WeaponAbility MovingShot = Abilities[10];
|
||||
public static readonly WeaponAbility ParalyzingBlow = Abilities[11];
|
||||
public static readonly WeaponAbility ShadowStrike = Abilities[12];
|
||||
public static readonly WeaponAbility WhirlwindAttack = Abilities[13];
|
||||
|
||||
public static readonly WeaponAbility RidingSwipe = Abilities[14];
|
||||
public static readonly WeaponAbility FrenziedWhirlwind = Abilities[15];
|
||||
public static readonly WeaponAbility Block = Abilities[16];
|
||||
public static readonly WeaponAbility DefenseMastery = Abilities[17];
|
||||
public static readonly WeaponAbility NerveStrike = Abilities[18];
|
||||
public static readonly WeaponAbility TalonStrike = Abilities[19];
|
||||
public static readonly WeaponAbility Feint = Abilities[20];
|
||||
public static readonly WeaponAbility DualWield = Abilities[21];
|
||||
public static readonly WeaponAbility DoubleShot = Abilities[22];
|
||||
public static readonly WeaponAbility ArmorPierce = Abilities[23];
|
||||
|
||||
public static readonly WeaponAbility Bladeweave = Abilities[24];
|
||||
public static readonly WeaponAbility ForceArrow = Abilities[25];
|
||||
public static readonly WeaponAbility LightningArrow = Abilities[26];
|
||||
public static readonly WeaponAbility PsychicAttack = Abilities[27];
|
||||
public static readonly WeaponAbility SerpentArrow = Abilities[28];
|
||||
public static readonly WeaponAbility ForceOfNature = Abilities[29];
|
||||
|
||||
public static readonly WeaponAbility Disrobe = Abilities[30];
|
||||
|
||||
|
||||
private static Hashtable m_PlayersTable = new Hashtable();
|
||||
|
||||
public virtual int BaseMana => 0;
|
||||
|
||||
public virtual int AccuracyBonus => 0;
|
||||
public virtual double DamageScalar => 1.0;
|
||||
|
||||
public virtual bool RequiresSE => false;
|
||||
|
||||
public static WeaponAbility[] Abilities{ get; } = new WeaponAbility[31]
|
||||
{
|
||||
null,
|
||||
new ArmorIgnore(),
|
||||
new BleedAttack(),
|
||||
new ConcussionBlow(),
|
||||
new CrushingBlow(),
|
||||
new Disarm(),
|
||||
new Dismount(),
|
||||
new DoubleStrike(),
|
||||
new InfectiousStrike(),
|
||||
new MortalStrike(),
|
||||
new MovingShot(),
|
||||
new ParalyzingBlow(),
|
||||
new ShadowStrike(),
|
||||
new WhirlwindAttack(),
|
||||
|
||||
new RidingSwipe(),
|
||||
new FrenziedWhirlwind(),
|
||||
new Block(),
|
||||
new DefenseMastery(),
|
||||
new NerveStrike(),
|
||||
new TalonStrike(),
|
||||
new Feint(),
|
||||
new DualWield(),
|
||||
new DoubleShot(),
|
||||
new ArmorPierce(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new Disrobe()
|
||||
};
|
||||
|
||||
public static Hashtable Table{ get; } = new Hashtable();
|
||||
|
||||
public virtual bool ValidatesDuringHit => true;
|
||||
|
||||
public virtual void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnMiss(Mobile attacker, Mobile defender)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool OnBeforeSwing(Mobile attacker, Mobile defender)
|
||||
{
|
||||
// Here because you must be sure you can use the skill before calling CheckHit if the ability has a HCI bonus for example
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool OnBeforeDamage(Mobile attacker, Mobile defender)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool RequiresTactics(Mobile from)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual double GetRequiredSkill(Mobile from)
|
||||
{
|
||||
BaseWeapon weapon = from.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon != null && weapon.PrimaryAbility == this)
|
||||
return 70.0;
|
||||
if (weapon != null && weapon.SecondaryAbility == this)
|
||||
return 90.0;
|
||||
|
||||
return 200.0;
|
||||
}
|
||||
|
||||
public virtual int CalculateMana(Mobile from)
|
||||
{
|
||||
int mana = BaseMana;
|
||||
|
||||
double skillTotal = GetSkill(from, SkillName.Swords) + GetSkill(from, SkillName.Macing)
|
||||
+ GetSkill(from, SkillName.Fencing) +
|
||||
GetSkill(from, SkillName.Archery) +
|
||||
GetSkill(from, SkillName.Parry)
|
||||
+ GetSkill(from, SkillName.Lumberjacking) +
|
||||
GetSkill(from, SkillName.Stealth)
|
||||
+ GetSkill(from, SkillName.Poisoning) +
|
||||
GetSkill(from, SkillName.Bushido) +
|
||||
GetSkill(from, SkillName.Ninjitsu);
|
||||
|
||||
if (skillTotal >= 300.0)
|
||||
mana -= 10;
|
||||
else if (skillTotal >= 200.0)
|
||||
mana -= 5;
|
||||
|
||||
double scalar = 1.0;
|
||||
if (!MindRotSpell.GetMindRotScalar(from, ref scalar))
|
||||
scalar = 1.0;
|
||||
|
||||
// Lower Mana Cost = 40%
|
||||
int lmc = Math.Min(AosAttributes.GetValue(from, AosAttribute.LowerManaCost), 40);
|
||||
|
||||
scalar -= (double)lmc / 100;
|
||||
mana = (int)(mana * scalar);
|
||||
|
||||
// Using a special move within 3 seconds of the previous special move costs double mana
|
||||
if (GetContext(from) != null)
|
||||
mana *= 2;
|
||||
|
||||
return mana;
|
||||
}
|
||||
|
||||
public virtual bool CheckWeaponSkill(Mobile from)
|
||||
{
|
||||
if (!(from.Weapon is BaseWeapon weapon))
|
||||
return false;
|
||||
|
||||
Skill skill = from.Skills[weapon.Skill];
|
||||
double reqSkill = GetRequiredSkill(from);
|
||||
bool reqTactics = Core.ML && RequiresTactics(from);
|
||||
|
||||
if (Core.ML && reqTactics && from.Skills[SkillName.Tactics].Base < reqSkill)
|
||||
{
|
||||
from.SendLocalizedMessage(1079308,
|
||||
reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack
|
||||
return false;
|
||||
}
|
||||
|
||||
if (skill != null && skill.Base >= reqSkill)
|
||||
return true;
|
||||
|
||||
/* <UBWS> */
|
||||
if (weapon.WeaponAttributes.UseBestSkill > 0 && (from.Skills[SkillName.Swords].Base >= reqSkill ||
|
||||
from.Skills[SkillName.Macing].Base >= reqSkill ||
|
||||
from.Skills[SkillName.Fencing].Base >= reqSkill))
|
||||
return true;
|
||||
/* </UBWS> */
|
||||
|
||||
if (reqTactics)
|
||||
from.SendLocalizedMessage(1079308,
|
||||
reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack
|
||||
else
|
||||
from.SendLocalizedMessage(1060182,
|
||||
reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon skill to perform that attack
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual bool CheckSkills(Mobile from)
|
||||
{
|
||||
return CheckWeaponSkill(from);
|
||||
}
|
||||
|
||||
public virtual double GetSkill(Mobile from, SkillName skillName)
|
||||
{
|
||||
Skill skill = from.Skills[skillName];
|
||||
|
||||
if (skill == null)
|
||||
return 0.0;
|
||||
|
||||
return skill.Value;
|
||||
}
|
||||
|
||||
public virtual bool CheckMana(Mobile from, bool consume)
|
||||
{
|
||||
int mana = CalculateMana(from);
|
||||
|
||||
if (from.Mana < mana)
|
||||
{
|
||||
if (from is BaseCreature creature && creature.HasManaOveride) return true;
|
||||
|
||||
from.SendLocalizedMessage(1060181,
|
||||
mana.ToString()); // You need ~1_MANA_REQUIREMENT~ mana to perform that attack
|
||||
return false;
|
||||
}
|
||||
|
||||
if (consume)
|
||||
{
|
||||
if (GetContext(from) == null)
|
||||
{
|
||||
Timer timer = new WeaponAbilityTimer(from);
|
||||
timer.Start();
|
||||
|
||||
AddContext(from, new WeaponAbilityContext(timer));
|
||||
}
|
||||
|
||||
from.Mana -= mana;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool Validate(Mobile from)
|
||||
{
|
||||
if (!from.Player)
|
||||
return true;
|
||||
|
||||
NetState state = from.NetState;
|
||||
|
||||
if (state == null)
|
||||
return false;
|
||||
|
||||
if (RequiresSE && !state.SupportsExpansion(Expansion.SE))
|
||||
{
|
||||
from.SendLocalizedMessage(1063456); // You must upgrade to Samurai Empire in order to use that ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HonorableExecution.IsUnderPenalty(from) || AnimalForm.UnderTransformation(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1063024); // You cannot perform this special move right now.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Core.ML && from.Spell != null)
|
||||
{
|
||||
from.SendLocalizedMessage(1063024); // You cannot perform this special move right now.
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Dueling
|
||||
|
||||
string option = null;
|
||||
|
||||
if (this is ArmorIgnore)
|
||||
option = "Armor Ignore";
|
||||
else if (this is BleedAttack)
|
||||
option = "Bleed Attack";
|
||||
else if (this is ConcussionBlow)
|
||||
option = "Concussion Blow";
|
||||
else if (this is CrushingBlow)
|
||||
option = "Crushing Blow";
|
||||
else if (this is Disarm)
|
||||
option = "Disarm";
|
||||
else if (this is Dismount)
|
||||
option = "Dismount";
|
||||
else if (this is DoubleStrike)
|
||||
option = "Double Strike";
|
||||
else if (this is InfectiousStrike)
|
||||
option = "Infectious Strike";
|
||||
else if (this is MortalStrike)
|
||||
option = "Mortal Strike";
|
||||
else if (this is MovingShot)
|
||||
option = "Moving Shot";
|
||||
else if (this is ParalyzingBlow)
|
||||
option = "Paralyzing Blow";
|
||||
else if (this is ShadowStrike)
|
||||
option = "Shadow Strike";
|
||||
else if (this is WhirlwindAttack)
|
||||
option = "Whirlwind Attack";
|
||||
else if (this is RidingSwipe)
|
||||
option = "Riding Swipe";
|
||||
else if (this is FrenziedWhirlwind)
|
||||
option = "Frenzied Whirlwind";
|
||||
else if (this is Block)
|
||||
option = "Block";
|
||||
else if (this is DefenseMastery)
|
||||
option = "Defense Mastery";
|
||||
else if (this is NerveStrike)
|
||||
option = "Nerve Strike";
|
||||
else if (this is TalonStrike)
|
||||
option = "Talon Strike";
|
||||
else if (this is Feint)
|
||||
option = "Feint";
|
||||
else if (this is DualWield)
|
||||
option = "Dual Wield";
|
||||
else if (this is DoubleShot)
|
||||
option = "Double Shot";
|
||||
else if (this is ArmorPierce)
|
||||
option = "Armor Pierce";
|
||||
|
||||
|
||||
if (option != null && !DuelContext.AllowSpecialAbility(from, option, true))
|
||||
return false;
|
||||
|
||||
#endregion
|
||||
|
||||
return CheckSkills(from) && CheckMana(from, false);
|
||||
}
|
||||
|
||||
public static bool IsWeaponAbility(Mobile m, WeaponAbility a)
|
||||
{
|
||||
if (a == null)
|
||||
return true;
|
||||
|
||||
if (!m.Player)
|
||||
return true;
|
||||
|
||||
return m.Weapon is BaseWeapon weapon && (weapon.PrimaryAbility == a || weapon.SecondaryAbility == a);
|
||||
}
|
||||
|
||||
public static WeaponAbility GetCurrentAbility(Mobile m)
|
||||
{
|
||||
if (!Core.AOS)
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return null;
|
||||
}
|
||||
|
||||
WeaponAbility a = (WeaponAbility)Table[m];
|
||||
|
||||
if (!IsWeaponAbility(m, a))
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (a != null && a.ValidatesDuringHit && !a.Validate(m))
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return null;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
public static bool SetCurrentAbility(Mobile m, WeaponAbility a)
|
||||
{
|
||||
if (!Core.AOS)
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsWeaponAbility(m, a))
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a != null && !a.Validate(m))
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a == null)
|
||||
{
|
||||
Table.Remove(m);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpecialMove.ClearCurrentMove(m);
|
||||
|
||||
Table[m] = a;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void ClearCurrentAbility(Mobile m)
|
||||
{
|
||||
Table.Remove(m);
|
||||
|
||||
if (Core.AOS && m.NetState != null)
|
||||
m.Send(ClearWeaponAbility.Instance);
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
EventSink.SetAbility += EventSink_SetAbility;
|
||||
}
|
||||
|
||||
private static void EventSink_SetAbility(SetAbilityEventArgs e)
|
||||
{
|
||||
int index = e.Index;
|
||||
|
||||
if (index == 0)
|
||||
ClearCurrentAbility(e.Mobile);
|
||||
else if (index >= 1 && index < Abilities.Length)
|
||||
SetCurrentAbility(e.Mobile, Abilities[index]);
|
||||
}
|
||||
|
||||
private static void AddContext(Mobile m, WeaponAbilityContext context)
|
||||
{
|
||||
m_PlayersTable[m] = context;
|
||||
}
|
||||
|
||||
private static void RemoveContext(Mobile m)
|
||||
{
|
||||
WeaponAbilityContext context = GetContext(m);
|
||||
|
||||
if (context != null)
|
||||
RemoveContext(m, context);
|
||||
}
|
||||
|
||||
private static void RemoveContext(Mobile m, WeaponAbilityContext context)
|
||||
{
|
||||
m_PlayersTable.Remove(m);
|
||||
|
||||
context.Timer.Stop();
|
||||
}
|
||||
|
||||
private static WeaponAbilityContext GetContext(Mobile m)
|
||||
{
|
||||
return m_PlayersTable[m] as WeaponAbilityContext;
|
||||
}
|
||||
|
||||
private class WeaponAbilityTimer : Timer
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
|
||||
public WeaponAbilityTimer(Mobile from) : base(TimeSpan.FromSeconds(3.0))
|
||||
{
|
||||
m_Mobile = from;
|
||||
|
||||
Priority = TimerPriority.TwentyFiveMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
RemoveContext(m_Mobile);
|
||||
}
|
||||
}
|
||||
|
||||
private class WeaponAbilityContext
|
||||
{
|
||||
public WeaponAbilityContext(Timer timer)
|
||||
{
|
||||
Timer = timer;
|
||||
}
|
||||
|
||||
public Timer Timer{ get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,82 +4,80 @@ using Server.Spells;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// A godsend to a warrior surrounded, the Whirlwind Attack allows the fighter to strike at all nearby targets in one mighty spinning swing.
|
||||
/// </summary>
|
||||
public class WhirlwindAttack : WeaponAbility
|
||||
{
|
||||
public WhirlwindAttack()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// A godsend to a warrior surrounded, the Whirlwind Attack allows the fighter to strike at all nearby targets in one mighty
|
||||
/// spinning swing.
|
||||
/// </summary>
|
||||
public class WhirlwindAttack : WeaponAbility
|
||||
{
|
||||
public override int BaseMana => 15;
|
||||
|
||||
public override int BaseMana => 15;
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker))
|
||||
return;
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if ( !Validate( attacker ) )
|
||||
return;
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
ClearCurrentAbility( attacker );
|
||||
Map map = attacker.Map;
|
||||
|
||||
Map map = attacker.Map;
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
if ( map == null )
|
||||
return;
|
||||
if (!(attacker.Weapon is BaseWeapon weapon))
|
||||
return;
|
||||
|
||||
if ( !(attacker.Weapon is BaseWeapon weapon) )
|
||||
return;
|
||||
if (!CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
if ( !CheckMana( attacker, true ) )
|
||||
return;
|
||||
attacker.FixedEffect(0x3728, 10, 15);
|
||||
attacker.PlaySound(0x2A1);
|
||||
|
||||
attacker.FixedEffect( 0x3728, 10, 15 );
|
||||
attacker.PlaySound( 0x2A1 );
|
||||
ArrayList list = new ArrayList();
|
||||
|
||||
ArrayList list = new ArrayList();
|
||||
foreach (Mobile m in attacker.GetMobilesInRange(1))
|
||||
list.Add(m);
|
||||
|
||||
foreach ( Mobile m in attacker.GetMobilesInRange( 1 ) )
|
||||
list.Add( m );
|
||||
ArrayList targets = new ArrayList();
|
||||
|
||||
ArrayList targets = new ArrayList();
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
Mobile m = (Mobile)list[i];
|
||||
|
||||
for ( int i = 0; i < list.Count; ++i )
|
||||
{
|
||||
Mobile m = (Mobile)list[i];
|
||||
if (m != defender && m != attacker && SpellHelper.ValidIndirectTarget(attacker, m))
|
||||
{
|
||||
if (m == null || m.Deleted || m.Map != attacker.Map || !m.Alive || !attacker.CanSee(m) ||
|
||||
!attacker.CanBeHarmful(m))
|
||||
continue;
|
||||
|
||||
if ( m != defender && m != attacker && SpellHelper.ValidIndirectTarget( attacker, m ) )
|
||||
{
|
||||
if ( m == null || m.Deleted || m.Map != attacker.Map || !m.Alive || !attacker.CanSee( m ) || !attacker.CanBeHarmful( m ) )
|
||||
continue;
|
||||
if (!attacker.InRange(m, weapon.MaxRange))
|
||||
continue;
|
||||
|
||||
if ( !attacker.InRange( m, weapon.MaxRange ) )
|
||||
continue;
|
||||
if (attacker.InLOS(m))
|
||||
targets.Add(m);
|
||||
}
|
||||
}
|
||||
|
||||
if ( attacker.InLOS( m ) )
|
||||
targets.Add( m );
|
||||
}
|
||||
}
|
||||
if (targets.Count > 0)
|
||||
{
|
||||
double bushido = attacker.Skills.Bushido.Value;
|
||||
double damageBonus = 1.0 + Math.Pow(targets.Count * bushido / 60, 2) / 100;
|
||||
|
||||
if ( targets.Count > 0 )
|
||||
{
|
||||
double bushido = attacker.Skills.Bushido.Value;
|
||||
double damageBonus = 1.0 + Math.Pow( (targets.Count * bushido) / 60, 2 ) / 100;
|
||||
if (damageBonus > 2.0)
|
||||
damageBonus = 2.0;
|
||||
|
||||
if ( damageBonus > 2.0 )
|
||||
damageBonus = 2.0;
|
||||
attacker.RevealingAction();
|
||||
|
||||
attacker.RevealingAction();
|
||||
for (int i = 0; i < targets.Count; ++i)
|
||||
{
|
||||
Mobile m = (Mobile)targets[i];
|
||||
|
||||
for ( int i = 0; i < targets.Count; ++i )
|
||||
{
|
||||
Mobile m = (Mobile)targets[i];
|
||||
attacker.SendLocalizedMessage(1060161); // The whirling attack strikes a target!
|
||||
m.SendLocalizedMessage(1060162); // You are struck by the whirling attack and take damage!
|
||||
|
||||
attacker.SendLocalizedMessage( 1060161 ); // The whirling attack strikes a target!
|
||||
m.SendLocalizedMessage( 1060162 ); // You are struck by the whirling attack and take damage!
|
||||
|
||||
weapon.OnHit( attacker, m, damageBonus );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
weapon.OnHit(attacker, m, damageBonus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue