This commit is contained in:
commit
47711d616e
2644 changed files with 479454 additions and 0 deletions
33
Scripts/Items/Weapons/Abilities/ArmorIgnore.cs
Normal file
33
Scripts/Items/Weapons/Abilities/ArmorIgnore.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Scripts/Items/Weapons/Abilities/ArmorPierce.cs
Normal file
44
Scripts/Items/Weapons/Abilities/ArmorPierce.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
133
Scripts/Items/Weapons/Abilities/BleedAttack.cs
Normal file
133
Scripts/Items/Weapons/Abilities/BleedAttack.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
111
Scripts/Items/Weapons/Abilities/Block.cs
Normal file
111
Scripts/Items/Weapons/Abilities/Block.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Scripts/Items/Weapons/Abilities/ConcussionBlow.cs
Normal file
52
Scripts/Items/Weapons/Abilities/ConcussionBlow.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Scripts/Items/Weapons/Abilities/CrushingBlow.cs
Normal file
34
Scripts/Items/Weapons/Abilities/CrushingBlow.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
103
Scripts/Items/Weapons/Abilities/DefenseMastery.cs
Normal file
103
Scripts/Items/Weapons/Abilities/DefenseMastery.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
74
Scripts/Items/Weapons/Abilities/Disarm.cs
Normal file
74
Scripts/Items/Weapons/Abilities/Disarm.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
77
Scripts/Items/Weapons/Abilities/Dismount.cs
Normal file
77
Scripts/Items/Weapons/Abilities/Dismount.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
69
Scripts/Items/Weapons/Abilities/DoubleShot.cs
Normal file
69
Scripts/Items/Weapons/Abilities/DoubleShot.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Scripts/Items/Weapons/Abilities/DoubleStrike.cs
Normal file
57
Scripts/Items/Weapons/Abilities/DoubleStrike.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Scripts/Items/Weapons/Abilities/DualWield.cs
Normal file
78
Scripts/Items/Weapons/Abilities/DualWield.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Scripts/Items/Weapons/Abilities/Feint.cs
Normal file
79
Scripts/Items/Weapons/Abilities/Feint.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
167
Scripts/Items/Weapons/Abilities/FrenziedWhirlwind.cs
Normal file
167
Scripts/Items/Weapons/Abilities/FrenziedWhirlwind.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
77
Scripts/Items/Weapons/Abilities/InfectiousStrike.cs
Normal file
77
Scripts/Items/Weapons/Abilities/InfectiousStrike.cs
Normal 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!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Scripts/Items/Weapons/Abilities/MortalStrike.cs
Normal file
91
Scripts/Items/Weapons/Abilities/MortalStrike.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
Scripts/Items/Weapons/Abilities/MovingShot.cs
Normal file
43
Scripts/Items/Weapons/Abilities/MovingShot.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Scripts/Items/Weapons/Abilities/NerveStrike.cs
Normal file
66
Scripts/Items/Weapons/Abilities/NerveStrike.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
126
Scripts/Items/Weapons/Abilities/ParalyzingBlow.cs
Normal file
126
Scripts/Items/Weapons/Abilities/ParalyzingBlow.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Scripts/Items/Weapons/Abilities/RidingSwipe.cs
Normal file
72
Scripts/Items/Weapons/Abilities/RidingSwipe.cs
Normal 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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Scripts/Items/Weapons/Abilities/ShadowStrike.cs
Normal file
54
Scripts/Items/Weapons/Abilities/ShadowStrike.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Scripts/Items/Weapons/Abilities/TalonStrike.cs
Normal file
106
Scripts/Items/Weapons/Abilities/TalonStrike.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
398
Scripts/Items/Weapons/Abilities/WeaponAbility.cs
Normal file
398
Scripts/Items/Weapons/Abilities/WeaponAbility.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Scripts/Items/Weapons/Abilities/WhirlwindAttack.cs
Normal file
88
Scripts/Items/Weapons/Abilities/WhirlwindAttack.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue