This commit is contained in:
mark 2006-06-15 04:14:30 +00:00
commit 47711d616e
2644 changed files with 479454 additions and 0 deletions

View file

@ -0,0 +1,33 @@
using System;
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()
{
}
public override int BaseMana{ get{ return 30; } }
public override double DamageScalar{ get{ return 0.9; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
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 );
}
}
}

View file

@ -0,0 +1,44 @@
using System;
using Server;
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()
{
}
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 );
}
public override int BaseMana{ get{ return 30; } }
public override double DamageScalar{ get{ return 1.5; } }
public override bool RequiresSE { get { return true; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
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 );
}
}
}

View file

@ -0,0 +1,133 @@
using System;
using System.Collections;
using Server.Mobiles;
using Server.Spells.Necromancy;
using Server.Network;
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()
{
}
public override int BaseMana{ get{ return 30; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
// Necromancers under Lich or Wraith Form are immune to Bleed Attacks.
TransformContext context = TransformationSpell.GetContext( defender );
if ( (context != null && ( context.Type == typeof( LichFormSpell ) || context.Type == typeof( WraithFormSpell ))) ||
(defender is BaseCreature && ((BaseCreature)defender).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!
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 );
BeginBleed( defender, attacker );
}
private static Hashtable m_Table = new Hashtable();
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];
if ( t != null )
t.Stop();
t = new InternalTimer( from, m );
m_Table[m] = t;
t.Start();
}
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;
m.PlaySound( 0x133 );
m.Damage( damage, from );
Blood blood = new Blood();
blood.ItemID = Utility.Random( 0x122A, 5 );
blood.MoveToWorld( m.Location, m.Map );
}
else
{
EndBleed( m, false );
}
}
public static void EndBleed( Mobile m, bool message )
{
Timer t = (Timer)m_Table[m];
if ( t == null )
return;
t.Stop();
m_Table.Remove( m );
m.SendLocalizedMessage( 1060167 ); // The bleeding wounds have healed, you are no longer bleeding!
}
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;
}
protected override void OnTick()
{
DoBleed( m_Mobile, m_From, 5 - m_Count );
if ( ++m_Count == 5 )
EndBleed( m_Mobile, true );
}
}
}
}

View file

@ -0,0 +1,111 @@
using System;
using Server;
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()
{
}
public override int BaseMana{ get{ return 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;
}
return base.CheckSkills( from );
}
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
attacker.SendLocalizedMessage( 1063345 ); // You block an attack!
defender.SendLocalizedMessage( 1063346 ); // Your attack was blocked!
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));
BeginBlock( attacker, bonus );
}
private class BlockInfo
{
public Mobile m_Target;
public Timer m_Timer;
public int m_Bonus;
public BlockInfo( Mobile target, int bonus )
{
m_Target = target;
m_Bonus = bonus;
}
}
private static Hashtable m_Table = new Hashtable();
public static bool GetBonus( Mobile targ, ref int bonus )
{
BlockInfo info = m_Table[targ] as BlockInfo;
if ( info == null )
return false;
bonus = info.m_Bonus;
return true;
}
public static void BeginBlock( Mobile m, int bonus )
{
EndBlock( m );
BlockInfo info = new BlockInfo( m, bonus );
info.m_Timer = new InternalTimer( m );
m_Table[m] = info;
}
public static void EndBlock( Mobile m )
{
BlockInfo info = m_Table[m] as BlockInfo;
if ( info != null )
{
if ( info.m_Timer != null )
info.m_Timer.Stop();
m_Table.Remove( m );
}
}
private class InternalTimer : Timer
{
private Mobile m_Mobile;
public InternalTimer( Mobile m ) : base( TimeSpan.FromSeconds( 6.0 ) )
{
m_Mobile = m;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
EndBlock( m_Mobile );
}
}
}
}

View file

@ -0,0 +1,52 @@
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()
{
}
public override int BaseMana{ get{ return 25; } }
public override bool OnBeforeDamage( Mobile attacker, Mobile defender )
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return false;
ClearCurrentAbility( attacker );
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 );
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.
if ( defender.HitsMax > 0 )
{
double hitsPercent = ( (double)defender.Hits / (double)defender.HitsMax ) * 100.0;
double manaPercent = 0;
if ( defender.ManaMax > 0 )
manaPercent = ( (double)defender.Mana / (double)defender.ManaMax ) * 100.0;
damage += Math.Min( (int)(Math.Abs( hitsPercent - manaPercent ) / 4), 20 );
}
// Total damage is 10 + (0~20) = 10~30, physical, non-resistable.
defender.Damage( damage, attacker );
return true;
}
}
}

View file

@ -0,0 +1,34 @@
using System;
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{ get{ return 25; } }
public override double DamageScalar{ get{ return 1.5; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
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 );
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 );
}
}
}

View file

@ -0,0 +1,103 @@
using System;
using Server;
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()
{
}
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 );
}
public override int BaseMana { get { return 30; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
attacker.SendLocalizedMessage( 1063353 ); // You perform a masterful defense!
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));
DefenseMasteryInfo info = m_Table[attacker] as DefenseMasteryInfo;
if( info != null )
EndDefense( (object)info );
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 );
m_Table[attacker] = info;
attacker.Delta( MobileDelta.WeaponDamage );
}
private class DefenseMasteryInfo
{
public Mobile m_From;
public Timer m_Timer;
public int m_DamageMalus;
public ResistanceMod m_Mod;
public DefenseMasteryInfo( Mobile from, int damageMalus, ResistanceMod mod )
{
m_From = from;
m_DamageMalus = damageMalus;
m_Mod = mod;
}
}
private static Hashtable m_Table = new Hashtable();
public static bool GetMalus( Mobile targ, ref int damageMalus )
{
DefenseMasteryInfo info = m_Table[targ] as DefenseMasteryInfo;
if( info == null )
return false;
damageMalus = info.m_DamageMalus;
return true;
}
private static void EndDefense( object state )
{
DefenseMasteryInfo info = (DefenseMasteryInfo)state;
if( info.m_Mod != null )
info.m_From.RemoveResistanceMod( info.m_Mod );
if( info.m_Timer != null )
info.m_Timer.Stop();
// No message is sent to the player.
m_Table.Remove( info.m_From );
info.m_From.Delta( MobileDelta.WeaponDamage );
}
}
}

View file

@ -0,0 +1,74 @@
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()
{
}
public override int BaseMana{ get{ return 20; } }
// No longer active in pub21:
/*public override bool CheckSkills( Mobile from )
{
if ( !base.CheckSkills( from ) )
return false;
if ( !(from.Weapon is Fists) )
return true;
Skill skill = from.Skills[SkillName.ArmsLore];
if ( skill != null && skill.Base >= 80.0 )
return true;
from.SendLocalizedMessage( 1061812 ); // You lack the required skill in armslore to perform that attack!
return false;
}*/
public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds( 5.0 );
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) )
return;
ClearCurrentAbility( attacker );
Item toDisarm = defender.FindItemOnLayer( Layer.OneHanded );
if ( toDisarm == null || !toDisarm.Movable )
toDisarm = defender.FindItemOnLayer( Layer.TwoHanded );
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 )
{
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 );
pack.DropItem( toDisarm );
BaseWeapon.BlockEquip( defender, BlockEquipDuration );
}
}
}
}

View file

@ -0,0 +1,77 @@
using System;
using Server.Mobiles;
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()
{
}
public override int BaseMana{ get{ return 20; } }
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;
}
return true;
}
public static readonly TimeSpan DefenderRemountDelay = TimeSpan.FromSeconds( 10.0 ); // TODO: Taken from bola script, needs to be verified
public static readonly TimeSpan AttackerRemountDelay = TimeSpan.FromSeconds( 3.0 );
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) )
return;
if ( attacker.Mounted && !(defender.Weapon is Lance) ) // TODO: Should there be a message here?
return;
ClearCurrentAbility( attacker );
IMount mount = defender.Mount;
if ( mount == null )
{
attacker.SendLocalizedMessage( 1060848 ); // This attack only works on mounted targets
return;
}
if ( !CheckMana( attacker, true ) )
return;
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!
defender.PlaySound( 0x140 );
defender.FixedParticles( 0x3728, 10, 15, 9955, EffectLayer.Waist );
mount.Rider = null;
BaseMount.SetMountPrevention( defender, BlockMountType.Dazed, DefenderRemountDelay );
BaseMount.SetMountPrevention( attacker, BlockMountType.DismountRecovery, AttackerRemountDelay );
if ( !attacker.Mounted )
AOS.Damage( defender, attacker, Utility.RandomMinMax( 15, 25 ), 100, 0, 0, 0, 0 );
}
}
}

View file

@ -0,0 +1,69 @@
using System;
using Server;
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()
{
}
public override int BaseMana { get { return 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;
}
return base.CheckSkills( from );
}
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 bool Validate( Mobile from )
{
if( base.Validate( from ) )
{
if( from.Mounted )
return true;
else
{
from.SendLocalizedMessage( 1070770 ); // You can only execute this attack while mounted!
ClearCurrentAbility( from );
}
}
return false;
}
public void Use( Mobile attacker, Mobile defender )
{
if( !Validate( attacker ) || !CheckMana( attacker, true ) || attacker.Weapon == null ) //sanity
return;
ClearCurrentAbility( attacker );
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 );
attacker.Weapon.OnSwing( attacker, defender );
}
}
}

View file

@ -0,0 +1,57 @@
using System;
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()
{
}
public override int BaseMana{ get{ return 30; } }
public override double DamageScalar{ get{ return 0.9; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
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 );
// 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;
}
IWeapon weapon = attacker.Weapon;
if ( weapon == null )
return;
if ( !attacker.InRange( defender, weapon.MaxRange ) )
return;
if ( attacker.InLOS( defender ) )
{
BaseWeapon.InDoubleStrike = true;
attacker.RevealingAction();
attacker.NextCombatTime = DateTime.Now + weapon.OnSwing( attacker, defender );
BaseWeapon.InDoubleStrike = false;
}
}
}
}

View file

@ -0,0 +1,78 @@
using System;
using Server;
using System.Collections;
namespace Server.Items
{
/// <summary>
/// Attack faster as you swing with both weapons.
/// </summary>
public class DualWield : WeaponAbility
{
private static Hashtable m_Registry = new Hashtable();
public static Hashtable Registry { get { return m_Registry; } }
public DualWield()
{
}
public override int BaseMana { get { return 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;
}
return base.CheckSkills( from );
}
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 );
}
ClearCurrentAbility( attacker );
attacker.SendLocalizedMessage( 1063362 ); // You dually wield for increased speed!
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
t.Start();
Registry.Add( attacker, t );
}
public class DualWieldTimer : Timer
{
private Mobile m_Owner;
private int m_BonusSwingSpeed;
public int BonusSwingSpeed { get { return m_BonusSwingSpeed; } }
public DualWieldTimer( Mobile owner, int bonusSwingSpeed )
: base( TimeSpan.FromSeconds( 6.0 ) )
{
m_Owner = owner;
m_BonusSwingSpeed = bonusSwingSpeed;
Priority = TimerPriority.FiftyMS;
}
protected override void OnTick()
{
Registry.Remove( m_Owner );
}
}
}
}

View file

@ -0,0 +1,79 @@
using System;
using System.Collections;
using Server.Items;
namespace Server.Items
{
/// <summary>
/// Gain a defensive advantage over your primary opponent for a short time.
/// </summary>
public class Feint : WeaponAbility
{
private static Hashtable m_Registry = new Hashtable();
public static Hashtable Registry { get { return m_Registry; } }
public Feint()
{
}
public override int BaseMana { get { return 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;
}
return base.CheckSkills( from );
}
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 );
}
ClearCurrentAbility( attacker );
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 );
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 );
}
public class FeintTimer : Timer
{
private Mobile m_Defender;
private int m_SwingSpeedReduction;
public int SwingSpeedReduction { get { return m_SwingSpeedReduction; } }
public FeintTimer( Mobile defender, int swingSpeedReduction )
: base( TimeSpan.FromSeconds( 6.0 ) )
{
m_Defender = defender;
m_SwingSpeedReduction = swingSpeedReduction;
Priority = TimerPriority.FiftyMS;
}
protected override void OnTick()
{
Registry.Remove( m_Defender );
}
}
}
}

View file

@ -0,0 +1,167 @@
using System;
using System.Collections;
using Server;
using Server.Spells;
using Server.Engines.PartySystem;
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()
{
}
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 );
}
public override int BaseMana { get { return 30; } }
private static Hashtable m_Registry = new Hashtable();
public static Hashtable Registry { get { return m_Registry; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if( !Validate( attacker ) ) //Mana check after check that there are targets
return;
ClearCurrentAbility( attacker );
Map map = attacker.Map;
if( map == null )
return;
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
if( weapon == null )
return;
ArrayList list = new ArrayList();
foreach( Mobile m in attacker.GetMobilesInRange( 1 ) )
list.Add( m );
ArrayList targets = new ArrayList();
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( !attacker.InRange( m, weapon.MaxRange ) )
continue;
if( attacker.InLOS( m ) )
targets.Add( m );
}
}
if( targets.Count > 0 )
{
if( !CheckMana( attacker, true ) )
return;
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));
for( int i = 0; i < targets.Count; ++i )
{
Mobile m = (Mobile)targets[i];
Timer t = Registry[m] as Timer;
if( t != null )
{
t.Stop();
Registry.Remove( m );
}
t = new InternalTimer( attacker, m, amount );
t.Start();
Registry.Add( m, t );
}
Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( RepeatEffect ), attacker );
}
}
private void RepeatEffect( object state )
{
Mobile attacker = (Mobile)state;
attacker.FixedEffect( 0x3728, 10, 15 );
attacker.PlaySound( 0x2A1 );
}
private class InternalTimer : Timer
{
private Mobile m_Attacker;
private Mobile m_Defender;
private double m_DamageRemaining;
private double m_DamageToDo;
private readonly double DamagePerTick;
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;
m_DamageRemaining = (double)totalDamage;
DamagePerTick = (double)totalDamage / 12 + 0.01;
Priority = TimerPriority.TwentyFiveMS;
}
protected override void OnTick()
{
if( !m_Defender.Alive || m_DamageRemaining <= 0 )
{
Stop();
Server.Items.FrenziedWhirlwind.Registry.Remove( m_Defender );
return;
}
m_DamageRemaining -= DamagePerTick;
m_DamageToDo += DamagePerTick;
if( m_DamageRemaining <= 0 && m_DamageToDo < 1 )
m_DamageToDo = 1.0; //Confirm this 'round up' at the end
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();
Server.Items.FrenziedWhirlwind.Registry.Remove( m_Defender );
}
}
}
}
}

View file

@ -0,0 +1,77 @@
using System;
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 — those that have Infectious Strike as an available special move — 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()
{
}
public override int BaseMana{ get{ return 15; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) )
return;
ClearCurrentAbility( attacker );
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
if ( weapon == null )
return;
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 ( !CheckMana( attacker, true ) )
return;
--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 );
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;
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 );
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!
}
}
}
}

View file

@ -0,0 +1,91 @@
using System;
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()
{
}
public override int BaseMana{ get{ return 30; } }
public static readonly TimeSpan PlayerDuration = TimeSpan.FromSeconds( 6.0 );
public static readonly TimeSpan NPCDuration = TimeSpan.FromSeconds( 12.0 );
public override void OnHit(Mobile attacker, Mobile defender, int damage)
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
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 );
// 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 void BeginWound( Mobile m, TimeSpan duration )
{
Timer t = (Timer)m_Table[m];
if ( t != null )
t.Stop();
t = new InternalTimer( m, duration );
m_Table[m] = t;
t.Start();
m.YellowHealthbar = true;
}
public static void EndWound( Mobile m )
{
Timer t = (Timer)m_Table[m];
if ( t != null )
t.Stop();
m_Table.Remove( m );
m.YellowHealthbar = false;
m.SendLocalizedMessage( 1060208 ); // You are no longer mortally wounded.
}
private class InternalTimer : Timer
{
private Mobile m_Mobile;
public InternalTimer( Mobile m, TimeSpan duration ) : base( duration )
{
m_Mobile = m;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
EndWound( m_Mobile );
}
}
}
}

View file

@ -0,0 +1,43 @@
using System;
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()
{
}
public override int BaseMana{ get{ return 15; } }
public override double AccuracyScalar{ get{ return 0.75; } }
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
ClearCurrentAbility( attacker );
attacker.SendLocalizedMessage( 1060089 ); // You fail to execute your special move
}
public override bool ValidatesDuringHit { get { return false; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
//Validates in OnSwing for accuracy scalar
ClearCurrentAbility( attacker );
attacker.SendLocalizedMessage( 1060216 ); // Your shot was successful
}
}
}

View file

@ -0,0 +1,66 @@
using System;
using Server;
namespace Server.Items
{
/// <summary>
/// Does damage and paralyses your opponent for a short time.
/// </summary>
public class NerveStrike : WeaponAbility
{
public NerveStrike()
{
}
public override int BaseMana { get { return 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;
}
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;
}
return true;
}
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
if( Server.Items.ParalyzingBlow.IsImmune( defender ) ) //After mana consumption intentional
{
attacker.SendLocalizedMessage( 1070804 ); // Your target resists paralysis.
defender.SendLocalizedMessage( 1070813 ); // You resist paralysis.
return;
}
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 );
AOS.Damage( defender, attacker, (int)(15.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 10), 100, 0, 0, 0, 0 ); //10-25
defender.Paralyze( TimeSpan.FromSeconds( 3.0 ) );
Server.Items.ParalyzingBlow.BeginImmunity( defender, Server.Items.ParalyzingBlow.FreezeDelayDuration );
}
}
}

View file

@ -0,0 +1,126 @@
using System;
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()
{
}
public override int BaseMana{ get{ return 30; } }
public static readonly TimeSpan PlayerFreezeDuration = TimeSpan.FromSeconds( 3.0 );
public static readonly TimeSpan NPCFreezeDuration = TimeSpan.FromSeconds( 6.0 );
public static readonly TimeSpan FreezeDelayDuration = TimeSpan.FromSeconds( 8.0 );
// No longer active in pub21:
/*public override bool CheckSkills( Mobile from )
{
if ( !base.CheckSkills( from ) )
return false;
if ( !(from.Weapon is Fists) )
return true;
Skill skill = from.Skills[SkillName.Anatomy];
if ( skill != null && skill.Base >= 80.0 )
return true;
from.SendLocalizedMessage( 1061811 ); // You lack the required anatomy skill to perform that attack!
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;
}
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
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 );
attacker.SendLocalizedMessage( 1060163 ); // You deliver a paralyzing blow!
defender.SendLocalizedMessage( 1060164 ); // The attack has temporarily paralyzed you!
TimeSpan duration = defender.Player ? PlayerFreezeDuration : NPCFreezeDuration;
// Treat it as paralyze not as freeze, effect must be removed when damaged.
defender.Paralyze( duration );
BeginImmunity( defender, duration + FreezeDelayDuration );
}
private static Hashtable m_Table = new Hashtable();
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];
if ( t != null )
t.Stop();
t = new InternalTimer( m, duration );
m_Table[m] = t;
t.Start();
}
public static void EndImmunity( Mobile m )
{
Timer t = (Timer)m_Table[m];
if ( t != null )
t.Stop();
m_Table.Remove( m );
}
private class InternalTimer : Timer
{
private Mobile m_Mobile;
public InternalTimer( Mobile m, TimeSpan duration ) : base( duration )
{
m_Mobile = m;
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
EndImmunity( m_Mobile );
}
}
}
}

View file

@ -0,0 +1,72 @@
using System;
using Server.Items;
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()
{
}
public override int BaseMana { get { return 30; } }
public override bool RequiresSE { get { return 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;
}
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;
}
if( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
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);
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);
AOS.Damage( defender, attacker, amount, 100, 0, 0, 0, 0 );
defender.Paralyze( TimeSpan.FromSeconds( 3.0 ) );
}
}
}
}

View file

@ -0,0 +1,54 @@
using System;
namespace Server.Items
{
/// <summary>
/// This powerful ability requires secondary skills to activate.
/// Successful use of Shadowstrike deals extra damage to the target — 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()
{
}
public override int BaseMana{ get{ return 20; } }
public override double DamageScalar{ get{ return 1.25; } }
public override bool CheckSkills( Mobile from )
{
if ( !base.CheckSkills( from ) )
return false;
Skill skill = from.Skills[SkillName.Stealth];
if ( skill != null && skill.Value >= 80.0 )
return true;
from.SendLocalizedMessage( 1060183 ); // You lack the required stealth to perform that attack
return false;
}
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
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!
Effects.SendLocationParticles( EffectItem.Create( attacker.Location, attacker.Map, EffectItem.DefaultDuration ), 0x376A, 8, 12, 9943 );
attacker.PlaySound( 0x482 );
defender.FixedEffect( 0x37BE, 20, 25 );
attacker.Combatant = null;
attacker.Warmode = false;
attacker.Hidden = true;
}
}
}

View file

@ -0,0 +1,106 @@
using System;
using Server;
using System.Collections;
namespace Server.Items
{
/// <summary>
/// Attack with increased damage with additional damage over time.
/// </summary>
public class TalonStrike : WeaponAbility
{
private static Hashtable m_Registry = new Hashtable();
public static Hashtable Registry { get { return m_Registry; } }
public TalonStrike()
{
}
public override int BaseMana { get { return 30; } }
public override double DamageScalar { get { return 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;
}
return base.CheckSkills( from );
}
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if( Registry.Contains( defender ) || !Validate( attacker ) || !CheckMana( attacker, true ) )
return;
ClearCurrentAbility( attacker );
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 );
Timer t = new InternalTimer( defender, (int)(10.0 * (attacker.Skills[SkillName.Ninjitsu].Value - 50.0) / 70.0 + 5), attacker ); //5 - 15 damage
t.Start();
Registry.Add( defender, t );
}
private class InternalTimer : Timer
{
private Mobile m_Defender;
private double m_DamageRemaining;
private double m_DamageToDo;
private Mobile m_Attacker;
private readonly double DamagePerTick;
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;
m_Attacker = attacker;
DamagePerTick = (double)totalDamage / 12+.01;
}
protected override void OnTick()
{
if( !m_Defender.Alive || m_DamageRemaining <= 0 )
{
Stop();
Server.Items.TalonStrike.Registry.Remove( m_Defender );
return;
}
m_DamageRemaining -= DamagePerTick;
m_DamageToDo += DamagePerTick;
if( m_DamageRemaining <= 0 && m_DamageToDo < 1 )
m_DamageToDo = 1.0; //Confirm this 'round up' at the end
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();
Server.Items.TalonStrike.Registry.Remove( m_Defender );
}
}
}
}
}

View file

@ -0,0 +1,398 @@
using System;
using System.Collections;
using Server;
using Server.Network;
using Server.Spells;
namespace Server.Items
{
public abstract class WeaponAbility
{
public virtual int BaseMana{ get{ return 0; } }
public virtual double AccuracyScalar{ get{ return 1.0; } }
public virtual double DamageScalar{ get{ return 1.0; } }
public virtual bool RequiresSE { get { return 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 double GetRequiredSkill( Mobile from )
{
BaseWeapon weapon = from.Weapon as BaseWeapon;
if ( weapon != null && weapon.PrimaryAbility == this )
return 70.0;
else 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 ( !Server.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 )
{
BaseWeapon weapon = from.Weapon as BaseWeapon;
if ( weapon == null )
return false;
Skill skill = from.Skills[weapon.Skill];
double reqSkill = GetRequiredSkill( from );
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> */
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 )
{
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;
int flags = (from.NetState == null) ? 0 : from.NetState.Flags;
if( RequiresSE && (flags & 0x10) == 0 ) //TODO: Convert to expansionInfo
{
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;
}
return CheckSkills( from ) && CheckMana( from, false );
}
private static WeaponAbility[] m_Abilities = new WeaponAbility[30]
{
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
};
public static WeaponAbility[] Abilities{ get{ return m_Abilities; } }
private static Hashtable m_Table = new Hashtable();
public static Hashtable Table{ get{ return m_Table; } }
public static readonly WeaponAbility ArmorIgnore = m_Abilities[ 1];
public static readonly WeaponAbility BleedAttack = m_Abilities[ 2];
public static readonly WeaponAbility ConcussionBlow = m_Abilities[ 3];
public static readonly WeaponAbility CrushingBlow = m_Abilities[ 4];
public static readonly WeaponAbility Disarm = m_Abilities[ 5];
public static readonly WeaponAbility Dismount = m_Abilities[ 6];
public static readonly WeaponAbility DoubleStrike = m_Abilities[ 7];
public static readonly WeaponAbility InfectiousStrike = m_Abilities[ 8];
public static readonly WeaponAbility MortalStrike = m_Abilities[ 9];
public static readonly WeaponAbility MovingShot = m_Abilities[10];
public static readonly WeaponAbility ParalyzingBlow = m_Abilities[11];
public static readonly WeaponAbility ShadowStrike = m_Abilities[12];
public static readonly WeaponAbility WhirlwindAttack = m_Abilities[13];
public static readonly WeaponAbility RidingSwipe = m_Abilities[14];
public static readonly WeaponAbility FrenziedWhirlwind = m_Abilities[15];
public static readonly WeaponAbility Block = m_Abilities[16];
public static readonly WeaponAbility DefenseMastery = m_Abilities[17];
public static readonly WeaponAbility NerveStrike = m_Abilities[18];
public static readonly WeaponAbility TalonStrike = m_Abilities[19];
public static readonly WeaponAbility Feint = m_Abilities[20];
public static readonly WeaponAbility DualWield = m_Abilities[21];
public static readonly WeaponAbility DoubleShot = m_Abilities[22];
public static readonly WeaponAbility ArmorPierce = m_Abilities[23];
public static readonly WeaponAbility Bladeweave = m_Abilities[24];
public static readonly WeaponAbility ForceArrow = m_Abilities[25];
public static readonly WeaponAbility LightningArrow = m_Abilities[26];
public static readonly WeaponAbility PsychicAttack = m_Abilities[27];
public static readonly WeaponAbility SerpentArrow = m_Abilities[28];
public static readonly WeaponAbility ForceOfNature = m_Abilities[29];
public static bool IsWeaponAbility( Mobile m, WeaponAbility a )
{
if ( a == null )
return true;
if ( !m.Player )
return true;
BaseWeapon weapon = m.Weapon as BaseWeapon;
return ( weapon != null && (weapon.PrimaryAbility == a || weapon.SecondaryAbility == a) );
}
public virtual bool ValidatesDuringHit{ get { return true; } }
public static WeaponAbility GetCurrentAbility( Mobile m )
{
if ( !Core.AOS )
{
ClearCurrentAbility( m );
return null;
}
WeaponAbility a = (WeaponAbility)m_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 )
{
m_Table.Remove( m );
}
else
{
SpecialMove.ClearCurrentMove( m );
m_Table[m] = a;
}
return true;
}
public static void ClearCurrentAbility( Mobile m )
{
m_Table.Remove( m );
if ( Core.AOS && m.NetState != null )
m.Send( ClearWeaponAbility.Instance );
}
public static void Initialize()
{
EventSink.SetAbility += new SetAbilityEventHandler( 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 < m_Abilities.Length )
SetCurrentAbility( e.Mobile, m_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
{
private Timer m_Timer;
public Timer Timer{ get{ return m_Timer; } }
public WeaponAbilityContext( Timer timer )
{
m_Timer = timer;
}
}
}
}

View file

@ -0,0 +1,88 @@
using System;
using System.Collections;
using Server;
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()
{
}
public override int BaseMana{ get{ return 15; } }
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
if ( !Validate( attacker ) )
return;
ClearCurrentAbility( attacker );
Map map = attacker.Map;
if ( map == null )
return;
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
if ( weapon == null )
return;
if ( !CheckMana( attacker, true ) )
return;
attacker.FixedEffect( 0x3728, 10, 15 );
attacker.PlaySound( 0x2A1 );
ArrayList list = new ArrayList();
foreach ( Mobile m in attacker.GetMobilesInRange( 1 ) )
list.Add( m );
ArrayList targets = new ArrayList();
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 ( !attacker.InRange( m, weapon.MaxRange ) )
continue;
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 ( damageBonus > 2.0 )
damageBonus = 2.0;
attacker.RevealingAction();
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!
weapon.OnHit( attacker, m, damageBonus );
}
}
}
}
}