1866 lines
51 KiB
C#
1866 lines
51 KiB
C#
using System;
|
|
using System.Text;
|
|
using System.Collections;
|
|
using Server.Network;
|
|
using Server.Targeting;
|
|
using Server.Mobiles;
|
|
using Server.Spells;
|
|
using Server.Engines.Craft;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Server.Items
|
|
{
|
|
public interface ISlayer
|
|
{
|
|
SlayerName Slayer { get; set; }
|
|
SlayerName Slayer2 { get; set; }
|
|
}
|
|
|
|
public abstract class BaseWeapon : Item, IWeapon, ICraftable, ISlayer, IDurability
|
|
{
|
|
/* Weapon internals work differently now (Mar 13 2003)
|
|
*
|
|
* The attributes defined below default to -1.
|
|
* If the value is -1, the corresponding virtual property is used.
|
|
* If not, the attribute value itself is used. Here's the list:
|
|
* - MinDamage
|
|
* - MaxDamage
|
|
* - Speed
|
|
* - HitSound
|
|
* - MissSound
|
|
* - StrRequirement, DexRequirement, IntRequirement
|
|
* - WeaponType
|
|
* - WeaponAnimation
|
|
* - MaxRange
|
|
*/
|
|
|
|
#region Var declarations
|
|
|
|
// Instance values. These values are unique to each weapon.
|
|
private WeaponDamageLevel m_DamageLevel;
|
|
private WeaponAccuracyLevel m_AccuracyLevel;
|
|
private WeaponDurabilityLevel m_DurabilityLevel;
|
|
private WeaponQuality m_Quality;
|
|
private Mobile m_Crafter;
|
|
private Poison m_Poison;
|
|
private int m_PoisonCharges;
|
|
private int m_Hits;
|
|
private int m_MaxHits;
|
|
private SlayerName m_Slayer;
|
|
private SlayerName m_Slayer2;
|
|
private SkillMod m_SkillMod, m_MageMod;
|
|
private CraftResource m_Resource;
|
|
private bool m_PlayerConstructed;
|
|
|
|
// Overridable values. These values are provided to override the defaults which get defined in the individual weapon scripts.
|
|
private int m_StrReq, m_DexReq, m_IntReq;
|
|
private int m_MinDamage, m_MaxDamage;
|
|
private int m_HitSound, m_MissSound;
|
|
private float m_Speed;
|
|
private int m_MaxRange;
|
|
private SkillName m_Skill;
|
|
private WeaponType m_Type;
|
|
private WeaponAnimation m_Animation;
|
|
#endregion
|
|
|
|
#region Virtual Properties
|
|
|
|
public virtual int DefMaxRange{ get{ return 1; } }
|
|
public virtual int DefHitSound{ get{ return 0; } }
|
|
public virtual int DefMissSound{ get{ return 0; } }
|
|
public virtual SkillName DefSkill{ get{ return SkillName.Swords; } }
|
|
public virtual WeaponType DefType{ get{ return WeaponType.Slashing; } }
|
|
public virtual WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Slash1H; } }
|
|
|
|
public virtual int UOStrengthReq{ get{ return 0; } }
|
|
public virtual int UODexterityReq{ get{ return 0; } }
|
|
public virtual int UOIntelligenceReq{ get{ return 0; } }
|
|
public virtual int UOMinDamage{ get{ return 0; } }
|
|
public virtual int UOMaxDamage{ get{ return 0; } }
|
|
public virtual int UOSpeed{ get{ return 0; } }
|
|
public virtual int UOMaxRange{ get{ return DefMaxRange; } }
|
|
public virtual int UOHitSound{ get{ return DefHitSound; } }
|
|
public virtual int UOMissSound{ get{ return DefMissSound; } }
|
|
public virtual SkillName UOSkill{ get{ return DefSkill; } }
|
|
public virtual WeaponType UOType{ get{ return DefType; } }
|
|
public virtual WeaponAnimation UOAnimation{ get{ return DefAnimation; } }
|
|
|
|
public virtual int InitMinHits{ get{ return 0; } }
|
|
public virtual int InitMaxHits{ get{ return 0; } }
|
|
|
|
public virtual SkillName AccuracySkill { get { return SkillName.Tactics; } }
|
|
#endregion
|
|
|
|
#region Getters & Setters
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int HitPoints
|
|
{
|
|
get{ return m_Hits; }
|
|
set
|
|
{
|
|
if ( m_Hits == value )
|
|
return;
|
|
|
|
if ( value > m_MaxHits )
|
|
value = m_MaxHits;
|
|
|
|
m_Hits = value;
|
|
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int MaxHitPoints
|
|
{
|
|
get{ return m_MaxHits; }
|
|
set{ m_MaxHits = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int PoisonCharges
|
|
{
|
|
get{ return m_PoisonCharges; }
|
|
set{ m_PoisonCharges = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public Poison Poison
|
|
{
|
|
get{ return m_Poison; }
|
|
set{ m_Poison = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public WeaponQuality Quality
|
|
{
|
|
get{ return m_Quality; }
|
|
set{ UnscaleDurability(); m_Quality = value; ScaleDurability(); InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public Mobile Crafter
|
|
{
|
|
get{ return m_Crafter; }
|
|
set{ m_Crafter = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public SlayerName Slayer
|
|
{
|
|
get{ return m_Slayer; }
|
|
set{ m_Slayer = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public SlayerName Slayer2
|
|
{
|
|
get { return m_Slayer2; }
|
|
set { m_Slayer2 = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public CraftResource Resource
|
|
{
|
|
get{ return m_Resource; }
|
|
set{ UnscaleDurability(); m_Resource = value; Hue = CraftResources.GetHue( m_Resource ); InvalidateProperties(); ScaleDurability(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public WeaponDamageLevel DamageLevel
|
|
{
|
|
get{ return m_DamageLevel; }
|
|
set{ m_DamageLevel = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public WeaponDurabilityLevel DurabilityLevel
|
|
{
|
|
get{ return m_DurabilityLevel; }
|
|
set{ UnscaleDurability(); m_DurabilityLevel = value; InvalidateProperties(); ScaleDurability(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public bool PlayerConstructed
|
|
{
|
|
get{ return m_PlayerConstructed; }
|
|
set{ m_PlayerConstructed = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int MaxRange
|
|
{
|
|
get{ return ( m_MaxRange == -1 ? UOMaxRange : m_MaxRange ); }
|
|
set{ m_MaxRange = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public WeaponAnimation Animation
|
|
{
|
|
get{ return ( m_Animation == (WeaponAnimation)(-1) ? UOAnimation : m_Animation ); }
|
|
set{ m_Animation = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public WeaponType Type
|
|
{
|
|
get{ return ( m_Type == (WeaponType)(-1) ? UOType : m_Type ); }
|
|
set{ m_Type = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public SkillName Skill
|
|
{
|
|
get{ return ( m_Skill == (SkillName)(-1) ? UOSkill : m_Skill ); }
|
|
set{ m_Skill = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int HitSound
|
|
{
|
|
get{ return ( m_HitSound == -1 ? UOHitSound : m_HitSound ); }
|
|
set{ m_HitSound = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int MissSound
|
|
{
|
|
get{ return ( m_MissSound == -1 ? UOMissSound : m_MissSound ); }
|
|
set{ m_MissSound = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int MinDamage
|
|
{
|
|
get{ return ( m_MinDamage == -1 ? UOMinDamage : m_MinDamage ); }
|
|
set{ m_MinDamage = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int MaxDamage
|
|
{
|
|
get{ return ( m_MaxDamage == -1 ? UOMaxDamage : m_MaxDamage ); }
|
|
set{ m_MaxDamage = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public float Speed
|
|
{
|
|
get
|
|
{
|
|
if ( m_Speed != -1 )
|
|
return m_Speed;
|
|
|
|
return UOSpeed;
|
|
}
|
|
set{ m_Speed = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int StrRequirement
|
|
{
|
|
get{ return ( m_StrReq == -1 ? UOStrengthReq : m_StrReq ); }
|
|
set{ m_StrReq = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int DexRequirement
|
|
{
|
|
get{ return ( m_DexReq == -1 ? UODexterityReq : m_DexReq ); }
|
|
set{ m_DexReq = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int IntRequirement
|
|
{
|
|
get{ return ( m_IntReq == -1 ? UOIntelligenceReq : m_IntReq ); }
|
|
set{ m_IntReq = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public WeaponAccuracyLevel AccuracyLevel
|
|
{
|
|
get
|
|
{
|
|
return m_AccuracyLevel;
|
|
}
|
|
set
|
|
{
|
|
if ( m_AccuracyLevel != value )
|
|
{
|
|
m_AccuracyLevel = value;
|
|
|
|
if ( UseSkillMod )
|
|
{
|
|
if ( m_AccuracyLevel == WeaponAccuracyLevel.Regular )
|
|
{
|
|
if ( m_SkillMod != null )
|
|
m_SkillMod.Remove();
|
|
|
|
m_SkillMod = null;
|
|
}
|
|
else if ( m_SkillMod == null && Parent is Mobile )
|
|
{
|
|
m_SkillMod = new DefaultSkillMod( AccuracySkill, true, (int)m_AccuracyLevel * 5 );
|
|
((Mobile)Parent).AddSkillMod( m_SkillMod );
|
|
}
|
|
else if ( m_SkillMod != null )
|
|
{
|
|
m_SkillMod.Value = (int)m_AccuracyLevel * 5;
|
|
}
|
|
}
|
|
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public override void OnAfterDuped( Item newItem )
|
|
{
|
|
BaseWeapon weap = newItem as BaseWeapon;
|
|
|
|
if ( weap == null )
|
|
return;
|
|
}
|
|
|
|
public virtual void UnscaleDurability()
|
|
{
|
|
int scale = 100 + GetDurabilityBonus();
|
|
|
|
m_Hits = ((m_Hits * 100) + (scale - 1)) / scale;
|
|
m_MaxHits = ((m_MaxHits * 100) + (scale - 1)) / scale;
|
|
InvalidateProperties();
|
|
}
|
|
|
|
public virtual void ScaleDurability()
|
|
{
|
|
int scale = 100 + GetDurabilityBonus();
|
|
|
|
m_Hits = ((m_Hits * scale) + 99) / 100;
|
|
m_MaxHits = ((m_MaxHits * scale) + 99) / 100;
|
|
InvalidateProperties();
|
|
}
|
|
|
|
public int GetDurabilityBonus()
|
|
{
|
|
int bonus = 0;
|
|
|
|
if ( m_Quality == WeaponQuality.Exceptional )
|
|
bonus += 20;
|
|
|
|
switch ( m_DurabilityLevel )
|
|
{
|
|
case WeaponDurabilityLevel.Durable: bonus += 20; break;
|
|
case WeaponDurabilityLevel.Substantial: bonus += 50; break;
|
|
case WeaponDurabilityLevel.Massive: bonus += 70; break;
|
|
case WeaponDurabilityLevel.Fortified: bonus += 100; break;
|
|
case WeaponDurabilityLevel.Indestructible: bonus += 120; break;
|
|
}
|
|
|
|
return bonus;
|
|
}
|
|
|
|
public int GetLowerStatReq()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public static void BlockEquip( Mobile m, TimeSpan duration )
|
|
{
|
|
if ( m.BeginAction( typeof( BaseWeapon ) ) )
|
|
new ResetEquipTimer( m, duration ).Start();
|
|
}
|
|
|
|
private class ResetEquipTimer : Timer
|
|
{
|
|
private Mobile m_Mobile;
|
|
|
|
public ResetEquipTimer( Mobile m, TimeSpan duration ) : base( duration )
|
|
{
|
|
m_Mobile = m;
|
|
}
|
|
|
|
protected override void OnTick()
|
|
{
|
|
m_Mobile.EndAction( typeof( BaseWeapon ) );
|
|
}
|
|
}
|
|
|
|
public override bool CheckConflictingLayer( Mobile m, Item item, Layer layer )
|
|
{
|
|
if ( base.CheckConflictingLayer( m, item, layer ) )
|
|
return true;
|
|
|
|
if ( this.Layer == Layer.TwoHanded && layer == Layer.OneHanded )
|
|
{
|
|
m.SendLocalizedMessage( 500214 ); // You already have something in both hands.
|
|
return true;
|
|
}
|
|
else if ( this.Layer == Layer.OneHanded && layer == Layer.TwoHanded && !(item is BaseShield) && !(item is BaseEquipableLight) )
|
|
{
|
|
m.SendLocalizedMessage( 500215 ); // You can only wield one weapon at a time.
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public override bool CanEquip( Mobile from )
|
|
{
|
|
if ( from.Dex < DexRequirement )
|
|
{
|
|
from.SendMessage( "You are not nimble enough to equip that." );
|
|
return false;
|
|
}
|
|
else if ( from.Str < Ultima.Scale( StrRequirement, 100 - GetLowerStatReq() ) )
|
|
{
|
|
from.SendLocalizedMessage( 500213 ); // You are not strong enough to equip that.
|
|
return false;
|
|
}
|
|
else if ( from.Int < IntRequirement )
|
|
{
|
|
from.SendMessage( "You are not smart enough to equip that." );
|
|
return false;
|
|
}
|
|
else if ( !from.CanBeginAction( typeof( BaseWeapon ) ) )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return base.CanEquip( from );
|
|
}
|
|
}
|
|
|
|
public virtual bool UseSkillMod{ get{ return true; } }
|
|
|
|
public override bool OnEquip( Mobile from )
|
|
{
|
|
from.NextCombatTime = DateTime.Now + GetDelay( from );
|
|
|
|
if ( UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular )
|
|
{
|
|
if ( m_SkillMod != null )
|
|
m_SkillMod.Remove();
|
|
|
|
m_SkillMod = new DefaultSkillMod( AccuracySkill, true, (int)m_AccuracyLevel * 5 );
|
|
from.AddSkillMod( m_SkillMod );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override void OnAdded( object parent )
|
|
{
|
|
base.OnAdded( parent );
|
|
|
|
if ( parent is Mobile )
|
|
{
|
|
Mobile from = (Mobile)parent;
|
|
|
|
from.CheckStatTimers();
|
|
from.Delta( MobileDelta.WeaponDamage );
|
|
}
|
|
}
|
|
|
|
public override void OnRemoved( object parent )
|
|
{
|
|
if ( parent is Mobile )
|
|
{
|
|
Mobile m = (Mobile)parent;
|
|
BaseWeapon weapon = m.Weapon as BaseWeapon;
|
|
|
|
string modName = this.Serial.ToString();
|
|
|
|
m.RemoveStatMod( modName + "Str" );
|
|
m.RemoveStatMod( modName + "Dex" );
|
|
m.RemoveStatMod( modName + "Int" );
|
|
|
|
if ( weapon != null )
|
|
m.NextCombatTime = DateTime.Now + weapon.GetDelay( m );
|
|
|
|
if ( UseSkillMod && m_SkillMod != null )
|
|
{
|
|
m_SkillMod.Remove();
|
|
m_SkillMod = null;
|
|
}
|
|
|
|
if ( m_MageMod != null )
|
|
{
|
|
m_MageMod.Remove();
|
|
m_MageMod = null;
|
|
}
|
|
|
|
m.CheckStatTimers();
|
|
|
|
m.Delta( MobileDelta.WeaponDamage );
|
|
}
|
|
}
|
|
|
|
public virtual SkillName GetUsedSkill( Mobile m, bool checkSkillAttrs )
|
|
{
|
|
SkillName sk;
|
|
|
|
sk = Skill;
|
|
|
|
if ( sk != SkillName.HandToHand && !m.Player && !m.Body.IsHuman && m.Skills[SkillName.HandToHand].Value > m.Skills[sk].Value )
|
|
sk = SkillName.HandToHand;
|
|
|
|
return sk;
|
|
}
|
|
|
|
public virtual double GetAttackSkillValue( Mobile attacker, Mobile defender )
|
|
{
|
|
return attacker.Skills[GetUsedSkill( attacker, true )].Value;
|
|
}
|
|
|
|
public virtual double GetDefendSkillValue( Mobile attacker, Mobile defender )
|
|
{
|
|
return defender.Skills[GetUsedSkill( defender, true )].Value;
|
|
}
|
|
|
|
public virtual bool CheckHit( Mobile attacker, Mobile defender )
|
|
{
|
|
BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon;
|
|
BaseWeapon defWeapon = defender.Weapon as BaseWeapon;
|
|
|
|
Skill atkSkill = attacker.Skills[atkWeapon.Skill];
|
|
Skill defSkill = defender.Skills[defWeapon.Skill];
|
|
|
|
double atkValue = atkWeapon.GetAttackSkillValue( attacker, defender );
|
|
double defValue = defWeapon.GetDefendSkillValue( attacker, defender );
|
|
|
|
double ourValue, theirValue;
|
|
|
|
int bonus = GetHitChanceBonus();
|
|
|
|
if ( atkValue <= -50.0 )
|
|
atkValue = -49.9;
|
|
|
|
if ( defValue <= -50.0 )
|
|
defValue = -49.9;
|
|
|
|
ourValue = (atkValue + 50.0);
|
|
theirValue = (defValue + 50.0);
|
|
|
|
double chance = ourValue / (theirValue * 2.0);
|
|
|
|
chance *= 1.0 + ((double)bonus / 100);
|
|
|
|
return attacker.CheckSkill( atkSkill.SkillName, chance );
|
|
}
|
|
|
|
public virtual TimeSpan GetDelay( Mobile m )
|
|
{
|
|
double speed = this.Speed;
|
|
|
|
if ( speed == 0 )
|
|
return TimeSpan.FromHours( 1.0 );
|
|
|
|
double delayInSeconds;
|
|
|
|
int v = (m.Stam + 100) * (int) speed;
|
|
|
|
if ( v <= 0 )
|
|
v = 1;
|
|
|
|
delayInSeconds = 15000.0 / v;
|
|
|
|
return TimeSpan.FromSeconds( delayInSeconds );
|
|
}
|
|
|
|
public virtual void OnBeforeSwing( Mobile attacker, Mobile defender )
|
|
{
|
|
}
|
|
|
|
public virtual TimeSpan OnSwing( Mobile attacker, Mobile defender )
|
|
{
|
|
return OnSwing( attacker, defender, 1.0 );
|
|
}
|
|
|
|
public virtual TimeSpan OnSwing( Mobile attacker, Mobile defender, double damageBonus )
|
|
{
|
|
bool canSwing = true;
|
|
|
|
if ( canSwing && attacker.HarmfulCheck( defender ) )
|
|
{
|
|
attacker.DisruptiveAction();
|
|
|
|
if ( attacker.NetState != null )
|
|
attacker.Send( new Swing( 0, attacker, defender ) );
|
|
|
|
if ( CheckHit( attacker, defender ) )
|
|
OnHit( attacker, defender, damageBonus );
|
|
else
|
|
OnMiss( attacker, defender );
|
|
}
|
|
|
|
return GetDelay( attacker );
|
|
}
|
|
|
|
#region Sounds
|
|
public virtual int GetHitAttackSound( Mobile attacker, Mobile defender )
|
|
{
|
|
int sound = attacker.GetAttackSound();
|
|
|
|
if ( sound == -1 )
|
|
sound = HitSound;
|
|
|
|
return sound;
|
|
}
|
|
|
|
public virtual int GetHitDefendSound( Mobile attacker, Mobile defender )
|
|
{
|
|
return defender.GetHurtSound();
|
|
}
|
|
|
|
public virtual int GetMissAttackSound( Mobile attacker, Mobile defender )
|
|
{
|
|
if ( attacker.GetAttackSound() == -1 )
|
|
return MissSound;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
public virtual int GetMissDefendSound( Mobile attacker, Mobile defender )
|
|
{
|
|
return -1;
|
|
}
|
|
#endregion
|
|
|
|
public static int DodgeArmor( Item item, int impact )
|
|
{
|
|
if ( item is BaseArmor )
|
|
{
|
|
CraftResource resource = ((BaseArmor)item).Resource;
|
|
|
|
if ( resource == CraftResource.Iron )
|
|
return ( impact * 6 );
|
|
else if ( resource == CraftResource.Wooden )
|
|
return ( impact * 4 );
|
|
else if ( resource == CraftResource.Leathered )
|
|
return ( impact * 2 );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public static int ArmorRating( Mobile defender )
|
|
{
|
|
int armorScore = 0;
|
|
|
|
if ( defender.FindItemOnLayer( Layer.Pants ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.Pants ), 3 ); }
|
|
if ( defender.FindItemOnLayer( Layer.Neck ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.Neck ), 1 ); }
|
|
if ( defender.FindItemOnLayer( Layer.InnerTorso ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.InnerTorso ), 4 ); }
|
|
if ( defender.FindItemOnLayer( Layer.Helm ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.Helm ), 2 ); }
|
|
if ( defender.FindItemOnLayer( Layer.Gloves ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.Gloves ), 1 ); }
|
|
if ( defender.FindItemOnLayer( Layer.MiddleTorso ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.MiddleTorso ), 4 ); }
|
|
if ( defender.FindItemOnLayer( Layer.Arms ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.Arms ), 2 ); }
|
|
if ( defender.FindItemOnLayer( Layer.OuterTorso ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.OuterTorso ), 4 ); }
|
|
if ( defender.FindItemOnLayer( Layer.OuterLegs ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.OuterLegs ), 3 ); }
|
|
if ( defender.FindItemOnLayer( Layer.InnerLegs ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.InnerLegs ), 3 ); }
|
|
if ( defender.FindItemOnLayer( Layer.TwoHanded ) != null ) { armorScore = armorScore + DodgeArmor( defender.FindItemOnLayer( Layer.TwoHanded ), 2 ); }
|
|
|
|
if ( armorScore > 0 )
|
|
armorScore = armorScore + 10;
|
|
|
|
return armorScore;
|
|
}
|
|
|
|
public static bool CheckDodge( Mobile defender, bool skillUp )
|
|
{
|
|
if ( defender == null )
|
|
return false;
|
|
|
|
int armorScore = ArmorRating( defender );
|
|
|
|
if ( armorScore > Utility.RandomMinMax(1,100) )
|
|
return false;
|
|
|
|
double dodge = defender.Skills[SkillName.Dodging].Value;
|
|
|
|
double chance = dodge / 400.0;
|
|
|
|
if ( chance < 0 ) // chance shouldn't go below 0
|
|
chance = 0;
|
|
|
|
// Dodge over 100 grants a 5% bonus.
|
|
if ( dodge >= 100.0 )
|
|
chance += 0.05;
|
|
|
|
// Low dexterity lowers the chance.
|
|
if ( defender.Dex < 80 )
|
|
chance = chance * (20 + defender.Dex) / 100;
|
|
|
|
if ( !skillUp )
|
|
{
|
|
if ( defender.Skills[SkillName.Dodging].Value >= Utility.RandomMinMax( 1, 100 ) )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
return defender.CheckSkill( SkillName.Dodging, chance );
|
|
}
|
|
|
|
public virtual int AbsorbDamage( Mobile attacker, Mobile defender, int damage )
|
|
{
|
|
if ( CheckDodge( defender, true ) )
|
|
{
|
|
defender.FixedEffect( 0x37B9, 10, 16 );
|
|
return 0;
|
|
}
|
|
|
|
double chance = Utility.RandomDouble();
|
|
|
|
Item armorItem;
|
|
|
|
if( chance < 0.07 )
|
|
armorItem = defender.NeckArmor;
|
|
else if( chance < 0.14 )
|
|
armorItem = defender.HandArmor;
|
|
else if( chance < 0.28 )
|
|
armorItem = defender.ArmsArmor;
|
|
else if( chance < 0.43 )
|
|
armorItem = defender.HeadArmor;
|
|
else if( chance < 0.65 )
|
|
armorItem = defender.LegsArmor;
|
|
else
|
|
armorItem = defender.ChestArmor;
|
|
|
|
IWearableDurability armor = armorItem as IWearableDurability;
|
|
|
|
if ( armor != null )
|
|
damage = armor.OnHit( this, damage );
|
|
|
|
BaseShield shield = defender.FindItemOnLayer( Layer.TwoHanded ) as BaseShield;
|
|
if ( shield != null )
|
|
damage = shield.OnHit( this, damage );
|
|
|
|
int virtualArmor = defender.VirtualArmor + defender.VirtualArmorMod;
|
|
|
|
if ( virtualArmor > 0 )
|
|
{
|
|
double scalar;
|
|
|
|
if ( chance < 0.14 )
|
|
scalar = 0.07;
|
|
else if ( chance < 0.28 )
|
|
scalar = 0.14;
|
|
else if ( chance < 0.43 )
|
|
scalar = 0.15;
|
|
else if ( chance < 0.65 )
|
|
scalar = 0.22;
|
|
else
|
|
scalar = 0.35;
|
|
|
|
int from = (int)(virtualArmor * scalar) / 2;
|
|
int to = (int)(virtualArmor * scalar);
|
|
|
|
damage -= Utility.Random( from, (to - from) + 1 );
|
|
}
|
|
|
|
return damage;
|
|
}
|
|
|
|
public void OnHit( Mobile attacker, Mobile defender )
|
|
{
|
|
OnHit( attacker, defender, 1.0 );
|
|
}
|
|
|
|
public virtual void OnHit( Mobile attacker, Mobile defender, double damageBonus )
|
|
{
|
|
PlaySwingAnimation( attacker );
|
|
PlayHurtAnimation( defender );
|
|
|
|
attacker.PlaySound( GetHitAttackSound( attacker, defender ) );
|
|
defender.PlaySound( GetHitDefendSound( attacker, defender ) );
|
|
|
|
int damage = ComputeDamage( attacker, defender );
|
|
|
|
#region Damage Multipliers
|
|
/*
|
|
* The following damage bonuses multiply damage by a factor.
|
|
* Capped at x3 (300%).
|
|
*/
|
|
//double factor = 1.0;
|
|
int percentageBonus = 0;
|
|
|
|
//factor *= damageBonus;
|
|
percentageBonus += (int)(damageBonus * 100) - 100;
|
|
|
|
CheckSlayerResult cs = CheckSlayers( attacker, defender );
|
|
|
|
if ( cs != CheckSlayerResult.None )
|
|
{
|
|
if ( cs == CheckSlayerResult.Slayer )
|
|
defender.FixedEffect( 0x37B9, 10, 5 );
|
|
|
|
//factor *= 2.0;
|
|
percentageBonus += 100;
|
|
}
|
|
|
|
percentageBonus = Math.Min( percentageBonus, 300 );
|
|
|
|
//damage = (int)(damage * factor);
|
|
damage = Ultima.Scale( damage, 100 + percentageBonus );
|
|
#endregion
|
|
|
|
if ( attacker is BaseCreature )
|
|
((BaseCreature)attacker).AlterMeleeDamageTo( defender, ref damage );
|
|
|
|
if ( defender is BaseCreature )
|
|
((BaseCreature)defender).AlterMeleeDamageFrom( attacker, ref damage );
|
|
|
|
damage = AbsorbDamage( attacker, defender, damage );
|
|
|
|
if ( damage < 1 )
|
|
damage = 1;
|
|
|
|
AddBlood( attacker, defender, damage );
|
|
|
|
int dmg = Ultima.Damage( defender, attacker, damage );
|
|
|
|
if ( m_MaxHits > 0 && ((MaxRange <= 1 && (defender is LargeSlime || defender is Slime || defender is AcidElemental)) || Utility.Random( 25 ) == 0) ) // Stratics says 50% chance, seems more like 4%..
|
|
{
|
|
if ( MaxRange <= 1 && (defender is LargeSlime || defender is Slime || defender is AcidElemental) )
|
|
attacker.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500263 ); // *Acid blood scars your weapon!*
|
|
|
|
if ( m_Hits > 0 )
|
|
{
|
|
--HitPoints;
|
|
}
|
|
else if ( m_MaxHits > 1 )
|
|
{
|
|
--MaxHitPoints;
|
|
|
|
if ( Parent is Mobile )
|
|
((Mobile)Parent).LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061121 ); // Your equipment is severely damaged.
|
|
}
|
|
else
|
|
{
|
|
Delete();
|
|
}
|
|
}
|
|
|
|
if ( attacker is BaseCreature )
|
|
((BaseCreature)attacker).OnGaveMeleeAttack( defender );
|
|
|
|
if ( defender is BaseCreature )
|
|
((BaseCreature)defender).OnGotMeleeAttack( attacker );
|
|
}
|
|
|
|
public virtual CheckSlayerResult CheckSlayers( Mobile attacker, Mobile defender )
|
|
{
|
|
BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon;
|
|
SlayerEntry atkSlayer = SlayerGroup.GetEntryByName( atkWeapon.Slayer );
|
|
SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName( atkWeapon.Slayer2 );
|
|
|
|
if ( atkSlayer != null && atkSlayer.Slays( defender ) || atkSlayer2 != null && atkSlayer2.Slays( defender ) )
|
|
return CheckSlayerResult.Slayer;
|
|
|
|
return CheckSlayerResult.None;
|
|
}
|
|
|
|
public virtual void AddBlood( Mobile attacker, Mobile defender, int damage )
|
|
{
|
|
if ( defender is BaseCreature && ((BaseCreature)defender).BleedImmune )
|
|
return;
|
|
|
|
if ( damage > 0 )
|
|
{
|
|
new Blood().MoveToWorld( defender.Location, defender.Map );
|
|
|
|
int extraBlood = Utility.RandomMinMax( 0, 1 );
|
|
|
|
for( int i = 0; i < extraBlood; i++ )
|
|
{
|
|
new Blood().MoveToWorld( new Point3D(
|
|
defender.X + Utility.RandomMinMax( -1, 1 ),
|
|
defender.Y + Utility.RandomMinMax( -1, 1 ),
|
|
defender.Z ), defender.Map );
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void OnMiss( Mobile attacker, Mobile defender )
|
|
{
|
|
PlaySwingAnimation( attacker );
|
|
attacker.PlaySound( GetMissAttackSound( attacker, defender ) );
|
|
defender.PlaySound( GetMissDefendSound( attacker, defender ) );
|
|
}
|
|
|
|
public virtual void GetBaseDamageRange( Mobile attacker, out int min, out int max )
|
|
{
|
|
if ( attacker is BaseCreature )
|
|
{
|
|
BaseCreature c = (BaseCreature)attacker;
|
|
|
|
if ( c.DamageMin >= 0 )
|
|
{
|
|
min = c.DamageMin;
|
|
max = c.DamageMax;
|
|
return;
|
|
}
|
|
|
|
if ( this is Fists && !attacker.Body.IsHuman )
|
|
{
|
|
min = attacker.Str / 28;
|
|
max = attacker.Str / 28;
|
|
return;
|
|
}
|
|
}
|
|
|
|
min = MinDamage;
|
|
max = MaxDamage;
|
|
}
|
|
|
|
public virtual double GetBaseDamage( Mobile attacker )
|
|
{
|
|
int min, max;
|
|
|
|
GetBaseDamageRange( attacker, out min, out max );
|
|
|
|
return Utility.RandomMinMax( min, max );
|
|
}
|
|
|
|
public virtual double GetBonus( double value, double scalar, double threshold, double offset )
|
|
{
|
|
double bonus = value * scalar;
|
|
|
|
if ( value >= threshold )
|
|
bonus += offset;
|
|
|
|
return bonus / 100;
|
|
}
|
|
|
|
public virtual int GetHitChanceBonus()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public virtual int GetDamageBonus()
|
|
{
|
|
int bonus = VirtualDamageBonus;
|
|
|
|
switch ( m_Quality )
|
|
{
|
|
case WeaponQuality.Low: bonus -= 20; break;
|
|
case WeaponQuality.Exceptional: bonus += 20; break;
|
|
}
|
|
|
|
switch ( m_DamageLevel )
|
|
{
|
|
case WeaponDamageLevel.Ruin: bonus += 15; break;
|
|
case WeaponDamageLevel.Might: bonus += 20; break;
|
|
case WeaponDamageLevel.Force: bonus += 25; break;
|
|
case WeaponDamageLevel.Power: bonus += 30; break;
|
|
case WeaponDamageLevel.Vanq: bonus += 35; break;
|
|
}
|
|
|
|
return bonus;
|
|
}
|
|
|
|
public virtual void GetStatusDamage( Mobile from, out int min, out int max )
|
|
{
|
|
int baseMin, baseMax;
|
|
|
|
GetBaseDamageRange( from, out baseMin, out baseMax );
|
|
|
|
min = Math.Max( (int)ScaleDamageOld( from, baseMin, false ), 1 );
|
|
max = Math.Max( (int)ScaleDamageOld( from, baseMax, false ), 1 );
|
|
}
|
|
|
|
public virtual int VirtualDamageBonus{ get{ return 0; } }
|
|
|
|
public virtual double ScaleDamageOld( Mobile attacker, double damage, bool checkSkills )
|
|
{
|
|
if ( checkSkills )
|
|
{
|
|
attacker.CheckSkill( SkillName.Tactics, 0.0, attacker.Skills[SkillName.Tactics].Cap ); // Passively check tactics for gain
|
|
}
|
|
|
|
/* Compute tactics modifier
|
|
* : 0.0 = 50% loss
|
|
* : 50.0 = unchanged
|
|
* : 100.0 = 50% bonus
|
|
*/
|
|
double tacticsBonus = (attacker.Skills[SkillName.Tactics].Value - 50.0) / 100.0;
|
|
|
|
/* Compute warrior modifier
|
|
* : 0.0 = 50% loss
|
|
* : 50.0 = unchanged
|
|
* : 100.0 = 50% bonus
|
|
*/
|
|
double warriorBonus = ( ( attacker.Skills[SkillName.Swords].Value + attacker.Skills[SkillName.Bludgeoning].Value + attacker.Skills[SkillName.Fencing].Value / 3 ) - 50.0 ) / 100.0;
|
|
if ( this is BaseRanged )
|
|
warriorBonus = 0;
|
|
|
|
/* Compute strength modifier
|
|
* : 1% bonus for every 5 strength
|
|
*/
|
|
double strBonus = (attacker.Str / 5.0) / 100.0;
|
|
|
|
/* Compute dex modifier
|
|
* : 1% bonus for every 5 points of dex
|
|
* : +10% bonus at 100
|
|
*/
|
|
double dexValue = attacker.Dex;
|
|
double dexBonus = (dexValue / 5.0) / 100.0;
|
|
|
|
if ( dexValue >= 100.0 )
|
|
dexBonus += 0.1;
|
|
|
|
// New quality bonus:
|
|
double qualityBonus = ((int)m_Quality - 1) * 0.2;
|
|
|
|
// Apply bonuses
|
|
damage += (damage * tacticsBonus) + (damage * strBonus) + (damage * warriorBonus) + (damage * dexBonus) + (damage * qualityBonus) + ((damage * VirtualDamageBonus) / 100);
|
|
|
|
// Old quality bonus:
|
|
#if false
|
|
/* Apply quality offset
|
|
* : Low : -4
|
|
* : Regular : 0
|
|
* : Exceptional : +4
|
|
*/
|
|
damage += ((int)m_Quality - 1) * 4.0;
|
|
#endif
|
|
|
|
/* Apply damage level offset
|
|
* : Regular : 0
|
|
* : Ruin : 1
|
|
* : Might : 3
|
|
* : Force : 5
|
|
* : Power : 7
|
|
* : Vanq : 9
|
|
*/
|
|
if ( m_DamageLevel != WeaponDamageLevel.Regular )
|
|
damage += (2.0 * (int)m_DamageLevel) - 1.0;
|
|
|
|
// Halve the computed damage and return
|
|
damage /= 2.0;
|
|
|
|
return ScaleDamageByDurability( (int)damage );
|
|
}
|
|
|
|
public virtual int ScaleDamageByDurability( int damage )
|
|
{
|
|
int scale = 100;
|
|
|
|
if ( m_MaxHits > 0 && m_Hits < m_MaxHits )
|
|
scale = 50 + ((50 * m_Hits) / m_MaxHits);
|
|
|
|
return Ultima.Scale( damage, scale );
|
|
}
|
|
|
|
public virtual int ComputeDamage( Mobile attacker, Mobile defender )
|
|
{
|
|
return (int)ScaleDamageOld( attacker, GetBaseDamage( attacker ), true );
|
|
}
|
|
|
|
public virtual void PlayHurtAnimation( Mobile from )
|
|
{
|
|
int action;
|
|
int frames;
|
|
|
|
switch ( from.Body.Type )
|
|
{
|
|
case BodyType.Sea:
|
|
case BodyType.Animal:
|
|
{
|
|
action = 7;
|
|
frames = 5;
|
|
break;
|
|
}
|
|
case BodyType.Monster:
|
|
{
|
|
action = 10;
|
|
frames = 4;
|
|
break;
|
|
}
|
|
case BodyType.Human:
|
|
{
|
|
action = 20;
|
|
frames = 5;
|
|
break;
|
|
}
|
|
default: return;
|
|
}
|
|
|
|
if ( from.Mounted )
|
|
return;
|
|
|
|
from.Animate( action, frames, 1, true, false, 0 );
|
|
}
|
|
|
|
public virtual void PlaySwingAnimation( Mobile from )
|
|
{
|
|
int action;
|
|
|
|
switch ( from.Body.Type )
|
|
{
|
|
case BodyType.Sea:
|
|
case BodyType.Animal:
|
|
{
|
|
action = Utility.Random( 5, 2 );
|
|
break;
|
|
}
|
|
case BodyType.Monster:
|
|
{
|
|
switch ( Animation )
|
|
{
|
|
default:
|
|
case WeaponAnimation.Wrestle:
|
|
case WeaponAnimation.Bash1H:
|
|
case WeaponAnimation.Pierce1H:
|
|
case WeaponAnimation.Slash1H:
|
|
case WeaponAnimation.Bash2H:
|
|
case WeaponAnimation.Pierce2H:
|
|
case WeaponAnimation.Slash2H: action = Utility.Random( 4, 3 ); break;
|
|
case WeaponAnimation.ShootBow: return; // 7
|
|
case WeaponAnimation.ShootXBow: return; // 8
|
|
}
|
|
|
|
break;
|
|
}
|
|
case BodyType.Human:
|
|
{
|
|
if ( !from.Mounted )
|
|
{
|
|
action = (int)Animation;
|
|
}
|
|
else
|
|
{
|
|
switch ( Animation )
|
|
{
|
|
default:
|
|
case WeaponAnimation.Wrestle:
|
|
case WeaponAnimation.Bash1H:
|
|
case WeaponAnimation.Pierce1H:
|
|
case WeaponAnimation.Slash1H: action = 26; break;
|
|
case WeaponAnimation.Bash2H:
|
|
case WeaponAnimation.Pierce2H:
|
|
case WeaponAnimation.Slash2H: action = 29; break;
|
|
case WeaponAnimation.ShootBow: action = 27; break;
|
|
case WeaponAnimation.ShootXBow: action = 28; break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
default: return;
|
|
}
|
|
|
|
from.Animate( action, 7, 1, true, false, 0 );
|
|
}
|
|
|
|
#region Serialization/Deserialization
|
|
private static void SetSaveFlag( ref SaveFlag flags, SaveFlag toSet, bool setIf )
|
|
{
|
|
if ( setIf )
|
|
flags |= toSet;
|
|
}
|
|
|
|
private static bool GetSaveFlag( SaveFlag flags, SaveFlag toGet )
|
|
{
|
|
return ( (flags & toGet) != 0 );
|
|
}
|
|
|
|
public override void Serialize( GenericWriter writer )
|
|
{
|
|
base.Serialize( writer );
|
|
|
|
writer.Write( (int) 9 ); // version
|
|
|
|
SaveFlag flags = SaveFlag.None;
|
|
|
|
SetSaveFlag( ref flags, SaveFlag.DamageLevel, m_DamageLevel != WeaponDamageLevel.Regular );
|
|
SetSaveFlag( ref flags, SaveFlag.AccuracyLevel, m_AccuracyLevel != WeaponAccuracyLevel.Regular );
|
|
SetSaveFlag( ref flags, SaveFlag.DurabilityLevel, m_DurabilityLevel != WeaponDurabilityLevel.Regular );
|
|
SetSaveFlag( ref flags, SaveFlag.Quality, m_Quality != WeaponQuality.Regular );
|
|
SetSaveFlag( ref flags, SaveFlag.Hits, m_Hits != 0 );
|
|
SetSaveFlag( ref flags, SaveFlag.MaxHits, m_MaxHits != 0 );
|
|
SetSaveFlag( ref flags, SaveFlag.Slayer, m_Slayer != SlayerName.None );
|
|
SetSaveFlag( ref flags, SaveFlag.Poison, m_Poison != null );
|
|
SetSaveFlag( ref flags, SaveFlag.PoisonCharges, m_PoisonCharges != 0 );
|
|
SetSaveFlag( ref flags, SaveFlag.Crafter, m_Crafter != null );
|
|
SetSaveFlag( ref flags, SaveFlag.StrReq, m_StrReq != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.DexReq, m_DexReq != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.IntReq, m_IntReq != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.MinDamage, m_MinDamage != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.MaxDamage, m_MaxDamage != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.HitSound, m_HitSound != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.MissSound, m_MissSound != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.Speed, m_Speed != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.MaxRange, m_MaxRange != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.Skill, m_Skill != (SkillName)(-1) );
|
|
SetSaveFlag( ref flags, SaveFlag.Type, m_Type != (WeaponType)(-1) );
|
|
SetSaveFlag( ref flags, SaveFlag.Animation, m_Animation != (WeaponAnimation)(-1) );
|
|
SetSaveFlag( ref flags, SaveFlag.Resource, m_Resource != CraftResource.Iron );
|
|
SetSaveFlag( ref flags, SaveFlag.PlayerConstructed, m_PlayerConstructed );
|
|
SetSaveFlag( ref flags, SaveFlag.Slayer2, m_Slayer2 != SlayerName.None );
|
|
|
|
writer.Write( (int) flags );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.DamageLevel ) )
|
|
writer.Write( (int) m_DamageLevel );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.AccuracyLevel ) )
|
|
writer.Write( (int) m_AccuracyLevel );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.DurabilityLevel ) )
|
|
writer.Write( (int) m_DurabilityLevel );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Quality ) )
|
|
writer.Write( (int) m_Quality );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Hits ) )
|
|
writer.Write( (int) m_Hits );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MaxHits ) )
|
|
writer.Write( (int) m_MaxHits );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Slayer ) )
|
|
writer.Write( (int) m_Slayer );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Poison ) )
|
|
Poison.Serialize( m_Poison, writer );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.PoisonCharges ) )
|
|
writer.Write( (int) m_PoisonCharges );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Crafter ) )
|
|
writer.Write( (Mobile) m_Crafter );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.StrReq ) )
|
|
writer.Write( (int) m_StrReq );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.DexReq ) )
|
|
writer.Write( (int) m_DexReq );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.IntReq ) )
|
|
writer.Write( (int) m_IntReq );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MinDamage ) )
|
|
writer.Write( (int) m_MinDamage );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MaxDamage ) )
|
|
writer.Write( (int) m_MaxDamage );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.HitSound ) )
|
|
writer.Write( (int) m_HitSound );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MissSound ) )
|
|
writer.Write( (int) m_MissSound );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Speed ) )
|
|
writer.Write( (float) m_Speed );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MaxRange ) )
|
|
writer.Write( (int) m_MaxRange );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Skill ) )
|
|
writer.Write( (int) m_Skill );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Type ) )
|
|
writer.Write( (int) m_Type );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Animation ) )
|
|
writer.Write( (int) m_Animation );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Resource ) )
|
|
writer.Write( (int) m_Resource );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Slayer2 ) )
|
|
writer.Write( (int)m_Slayer2 );
|
|
}
|
|
|
|
[Flags]
|
|
private enum SaveFlag
|
|
{
|
|
None = 0x00000000,
|
|
DamageLevel = 0x00000001,
|
|
AccuracyLevel = 0x00000002,
|
|
DurabilityLevel = 0x00000004,
|
|
Quality = 0x00000008,
|
|
Hits = 0x00000010,
|
|
MaxHits = 0x00000020,
|
|
Slayer = 0x00000040,
|
|
Poison = 0x00000080,
|
|
PoisonCharges = 0x00000100,
|
|
Crafter = 0x00000200,
|
|
StrReq = 0x00000400,
|
|
DexReq = 0x00000800,
|
|
IntReq = 0x00001000,
|
|
MinDamage = 0x00002000,
|
|
MaxDamage = 0x00004000,
|
|
HitSound = 0x00008000,
|
|
MissSound = 0x00010000,
|
|
Speed = 0x00020000,
|
|
MaxRange = 0x00040000,
|
|
Skill = 0x00080000,
|
|
Type = 0x00100000,
|
|
Animation = 0x00200000,
|
|
Resource = 0x00400000,
|
|
PlayerConstructed = 0x00800000,
|
|
Slayer2 = 0x01000000
|
|
}
|
|
|
|
public override void Deserialize( GenericReader reader )
|
|
{
|
|
base.Deserialize( reader );
|
|
|
|
int version = reader.ReadInt();
|
|
|
|
switch ( version )
|
|
{
|
|
case 9:
|
|
case 8:
|
|
case 7:
|
|
case 6:
|
|
case 5:
|
|
{
|
|
SaveFlag flags = (SaveFlag)reader.ReadInt();
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.DamageLevel ) )
|
|
{
|
|
m_DamageLevel = (WeaponDamageLevel)reader.ReadInt();
|
|
|
|
if ( m_DamageLevel > WeaponDamageLevel.Vanq )
|
|
m_DamageLevel = WeaponDamageLevel.Ruin;
|
|
}
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.AccuracyLevel ) )
|
|
{
|
|
m_AccuracyLevel = (WeaponAccuracyLevel)reader.ReadInt();
|
|
|
|
if ( m_AccuracyLevel > WeaponAccuracyLevel.Supremely )
|
|
m_AccuracyLevel = WeaponAccuracyLevel.Accurate;
|
|
}
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.DurabilityLevel ) )
|
|
{
|
|
m_DurabilityLevel = (WeaponDurabilityLevel)reader.ReadInt();
|
|
|
|
if ( m_DurabilityLevel > WeaponDurabilityLevel.Indestructible )
|
|
m_DurabilityLevel = WeaponDurabilityLevel.Durable;
|
|
}
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Quality ) )
|
|
m_Quality = (WeaponQuality)reader.ReadInt();
|
|
else
|
|
m_Quality = WeaponQuality.Regular;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Hits ) )
|
|
m_Hits = reader.ReadInt();
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MaxHits ) )
|
|
m_MaxHits = reader.ReadInt();
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Slayer ) )
|
|
m_Slayer = (SlayerName)reader.ReadInt();
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Poison ) )
|
|
m_Poison = Poison.Deserialize( reader );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.PoisonCharges ) )
|
|
m_PoisonCharges = reader.ReadInt();
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Crafter ) )
|
|
m_Crafter = reader.ReadMobile();
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.StrReq ) )
|
|
m_StrReq = reader.ReadInt();
|
|
else
|
|
m_StrReq = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.DexReq ) )
|
|
m_DexReq = reader.ReadInt();
|
|
else
|
|
m_DexReq = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.IntReq ) )
|
|
m_IntReq = reader.ReadInt();
|
|
else
|
|
m_IntReq = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MinDamage ) )
|
|
m_MinDamage = reader.ReadInt();
|
|
else
|
|
m_MinDamage = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MaxDamage ) )
|
|
m_MaxDamage = reader.ReadInt();
|
|
else
|
|
m_MaxDamage = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.HitSound ) )
|
|
m_HitSound = reader.ReadInt();
|
|
else
|
|
m_HitSound = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MissSound ) )
|
|
m_MissSound = reader.ReadInt();
|
|
else
|
|
m_MissSound = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Speed ) )
|
|
{
|
|
if ( version < 9 )
|
|
m_Speed = reader.ReadInt();
|
|
else
|
|
m_Speed = reader.ReadFloat();
|
|
}
|
|
else
|
|
m_Speed = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MaxRange ) )
|
|
m_MaxRange = reader.ReadInt();
|
|
else
|
|
m_MaxRange = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Skill ) )
|
|
m_Skill = (SkillName)reader.ReadInt();
|
|
else
|
|
m_Skill = (SkillName)(-1);
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Type ) )
|
|
m_Type = (WeaponType)reader.ReadInt();
|
|
else
|
|
m_Type = (WeaponType)(-1);
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Animation ) )
|
|
m_Animation = (WeaponAnimation)reader.ReadInt();
|
|
else
|
|
m_Animation = (WeaponAnimation)(-1);
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.Resource ) )
|
|
m_Resource = (CraftResource)reader.ReadInt();
|
|
else
|
|
m_Resource = CraftResource.Iron;
|
|
|
|
if ( UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular && Parent is Mobile )
|
|
{
|
|
m_SkillMod = new DefaultSkillMod( AccuracySkill, true, (int)m_AccuracyLevel * 5 );
|
|
((Mobile)Parent).AddSkillMod( m_SkillMod );
|
|
}
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.PlayerConstructed ) )
|
|
m_PlayerConstructed = true;
|
|
|
|
if( GetSaveFlag( flags, SaveFlag.Slayer2 ) )
|
|
m_Slayer2 = (SlayerName)reader.ReadInt();
|
|
|
|
break;
|
|
}
|
|
case 4:
|
|
{
|
|
m_Slayer = (SlayerName)reader.ReadInt();
|
|
|
|
goto case 3;
|
|
}
|
|
case 3:
|
|
{
|
|
m_StrReq = reader.ReadInt();
|
|
m_DexReq = reader.ReadInt();
|
|
m_IntReq = reader.ReadInt();
|
|
|
|
goto case 2;
|
|
}
|
|
case 2:
|
|
{
|
|
goto case 1;
|
|
}
|
|
case 1:
|
|
{
|
|
m_MaxRange = reader.ReadInt();
|
|
|
|
goto case 0;
|
|
}
|
|
case 0:
|
|
{
|
|
if ( version == 0 )
|
|
m_MaxRange = 1; // default
|
|
|
|
if ( version < 5 )
|
|
{
|
|
m_Resource = CraftResource.Iron;
|
|
}
|
|
|
|
m_MinDamage = reader.ReadInt();
|
|
m_MaxDamage = reader.ReadInt();
|
|
|
|
m_Speed = reader.ReadInt();
|
|
|
|
m_HitSound = reader.ReadInt();
|
|
m_MissSound = reader.ReadInt();
|
|
|
|
m_Skill = (SkillName)reader.ReadInt();
|
|
m_Type = (WeaponType)reader.ReadInt();
|
|
m_Animation = (WeaponAnimation)reader.ReadInt();
|
|
m_DamageLevel = (WeaponDamageLevel)reader.ReadInt();
|
|
m_AccuracyLevel = (WeaponAccuracyLevel)reader.ReadInt();
|
|
m_DurabilityLevel = (WeaponDurabilityLevel)reader.ReadInt();
|
|
m_Quality = (WeaponQuality)reader.ReadInt();
|
|
|
|
m_Crafter = reader.ReadMobile();
|
|
|
|
m_Poison = Poison.Deserialize( reader );
|
|
m_PoisonCharges = reader.ReadInt();
|
|
|
|
if ( m_StrReq == UOStrengthReq )
|
|
m_StrReq = -1;
|
|
|
|
if ( m_DexReq == UODexterityReq )
|
|
m_DexReq = -1;
|
|
|
|
if ( m_IntReq == UOIntelligenceReq )
|
|
m_IntReq = -1;
|
|
|
|
if ( m_MinDamage == UOMinDamage )
|
|
m_MinDamage = -1;
|
|
|
|
if ( m_MaxDamage == UOMaxDamage )
|
|
m_MaxDamage = -1;
|
|
|
|
if ( m_HitSound == UOHitSound )
|
|
m_HitSound = -1;
|
|
|
|
if ( m_MissSound == UOMissSound )
|
|
m_MissSound = -1;
|
|
|
|
if ( m_Speed == UOSpeed )
|
|
m_Speed = -1;
|
|
|
|
if ( m_MaxRange == UOMaxRange )
|
|
m_MaxRange = -1;
|
|
|
|
if ( m_Skill == UOSkill )
|
|
m_Skill = (SkillName)(-1);
|
|
|
|
if ( m_Type == UOType )
|
|
m_Type = (WeaponType)(-1);
|
|
|
|
if ( m_Animation == UOAnimation )
|
|
m_Animation = (WeaponAnimation)(-1);
|
|
|
|
if ( UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular && Parent is Mobile )
|
|
{
|
|
m_SkillMod = new DefaultSkillMod( AccuracySkill, true, (int)m_AccuracyLevel * 5);
|
|
((Mobile)Parent).AddSkillMod( m_SkillMod );
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( Parent is Mobile )
|
|
((Mobile)Parent).CheckStatTimers();
|
|
|
|
if ( m_Hits <= 0 && m_MaxHits <= 0 )
|
|
{
|
|
m_Hits = m_MaxHits = Utility.RandomMinMax( InitMinHits, InitMaxHits );
|
|
}
|
|
|
|
if ( version < 6 )
|
|
m_PlayerConstructed = true; // we don't know, so, assume it's crafted
|
|
}
|
|
#endregion
|
|
|
|
public BaseWeapon( int itemID ) : base( itemID )
|
|
{
|
|
Layer = (Layer)ItemData.Quality;
|
|
|
|
m_Quality = WeaponQuality.Regular;
|
|
m_StrReq = -1;
|
|
m_DexReq = -1;
|
|
m_IntReq = -1;
|
|
m_MinDamage = -1;
|
|
m_MaxDamage = -1;
|
|
m_HitSound = -1;
|
|
m_MissSound = -1;
|
|
m_Speed = -1;
|
|
m_MaxRange = -1;
|
|
m_Skill = (SkillName)(-1);
|
|
m_Type = (WeaponType)(-1);
|
|
m_Animation = (WeaponAnimation)(-1);
|
|
|
|
m_Hits = m_MaxHits = Utility.RandomMinMax( InitMinHits, InitMaxHits );
|
|
|
|
m_Resource = CraftResource.Iron;
|
|
}
|
|
|
|
public BaseWeapon( Serial serial ) : base( serial )
|
|
{
|
|
}
|
|
|
|
private string GetNameString()
|
|
{
|
|
string name = this.Name;
|
|
|
|
if ( name == null )
|
|
name = String.Format( "#{0}", LabelNumber );
|
|
|
|
return name;
|
|
}
|
|
|
|
[Hue, CommandProperty( AccessLevel.GameMaster )]
|
|
public override int Hue
|
|
{
|
|
get{ return base.Hue; }
|
|
set{ base.Hue = value; InvalidateProperties(); }
|
|
}
|
|
|
|
public override bool AllowEquipedCast( Mobile from )
|
|
{
|
|
if ( base.AllowEquipedCast( from ) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
public override void GetProperties( ObjectPropertyList list )
|
|
{
|
|
base.GetProperties( list );
|
|
|
|
if ( m_Crafter != null )
|
|
list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~
|
|
|
|
if ( m_Quality == WeaponQuality.Exceptional )
|
|
list.Add( 1060636 ); // exceptional
|
|
|
|
if ( m_DamageLevel == WeaponDamageLevel.Ruin )
|
|
list.Add( 1038022 ); // Ruin
|
|
else if ( m_DamageLevel == WeaponDamageLevel.Might )
|
|
list.Add( 1038023 ); // Might
|
|
else if ( m_DamageLevel == WeaponDamageLevel.Force )
|
|
list.Add( 1038024 ); // Force
|
|
else if ( m_DamageLevel == WeaponDamageLevel.Power )
|
|
list.Add( 1038025 ); // Power
|
|
else if ( m_DamageLevel == WeaponDamageLevel.Vanq )
|
|
list.Add( 1038026 ); // Vanquishing
|
|
|
|
if ( m_AccuracyLevel == WeaponAccuracyLevel.Accurate )
|
|
list.Add( 1038011 ); // Accurate
|
|
else if ( m_AccuracyLevel == WeaponAccuracyLevel.Surpassingly )
|
|
list.Add( 1038012 ); // Surpassingly Accurate
|
|
else if ( m_AccuracyLevel == WeaponAccuracyLevel.Eminently )
|
|
list.Add( 1038013 ); // Eminently Accurate
|
|
else if ( m_AccuracyLevel == WeaponAccuracyLevel.Exceedingly )
|
|
list.Add( 1038014 ); // Exceedingly Accurate
|
|
else if ( m_AccuracyLevel == WeaponAccuracyLevel.Supremely )
|
|
list.Add( 1038015 ); // Supremely Accurate
|
|
|
|
if ( m_DurabilityLevel == WeaponDurabilityLevel.Durable )
|
|
list.Add( 1036365 ); // Durable Material
|
|
else if ( m_DurabilityLevel == WeaponDurabilityLevel.Substantial )
|
|
list.Add( 1036366 ); // Substantial Material
|
|
else if ( m_DurabilityLevel == WeaponDurabilityLevel.Massive )
|
|
list.Add( 1036367 ); // Massive Material
|
|
else if ( m_DurabilityLevel == WeaponDurabilityLevel.Fortified )
|
|
list.Add( 1036368 ); // Fortified Material
|
|
else if ( m_DurabilityLevel == WeaponDurabilityLevel.Indestructible )
|
|
list.Add( 1036369 ); // Indestructible Material
|
|
|
|
if ( this is IUsesRemaining && ((IUsesRemaining)this).ShowUsesRemaining )
|
|
list.Add( 1060584, ((IUsesRemaining)this).UsesRemaining.ToString() ); // uses remaining: ~1_val~
|
|
|
|
if ( Magical > 0 && Uses > 0 )
|
|
{
|
|
list.Add( 1062520, "\t#{0}", Magical );
|
|
}
|
|
|
|
if ( Uses > 0 && Server.Misc.Settings.DisplayInfo() && !(this is BaseWand) )
|
|
{
|
|
if ( Uses > 1 )
|
|
list.Add( 1062516, "{0}", Uses );
|
|
else
|
|
list.Add( 1062517, "{0}", Uses );
|
|
}
|
|
else if ( Uses > 0 && !(this is BaseWand) )
|
|
{
|
|
double usage = (double)Uses / (double)UsesMax;
|
|
|
|
if ( usage > 0.95 )
|
|
list.Add( 1063269 ); // Fully Charged
|
|
else if ( usage > 0.75 )
|
|
list.Add( 1063270 ); // Mostly Charged
|
|
else if ( usage > 0.50 )
|
|
list.Add( 1063271 ); // Partially Charged
|
|
else if ( usage > 0.25 )
|
|
list.Add( 1063272 ); // Somewhat Charged
|
|
else if ( usage > 0.05 )
|
|
list.Add( 1063273 ); // Barely Charged
|
|
else
|
|
list.Add( 1063274 ); // Almost Drained
|
|
}
|
|
|
|
if( m_Slayer != SlayerName.None )
|
|
{
|
|
SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer );
|
|
if( entry != null )
|
|
list.Add( entry.Title );
|
|
}
|
|
|
|
if( m_Slayer2 != SlayerName.None )
|
|
{
|
|
SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer2 );
|
|
if( entry != null )
|
|
list.Add( entry.Title );
|
|
}
|
|
|
|
if ( m_Poison != null && m_PoisonCharges > 0 )
|
|
{
|
|
if ( Server.Misc.Settings.DisplayInfo() )
|
|
list.Add( 1062412 + m_Poison.Level, m_PoisonCharges.ToString() );
|
|
else
|
|
list.Add( 1017383 ); // Poisoned
|
|
}
|
|
|
|
if ( Server.Misc.Settings.DisplayInfo() )
|
|
{
|
|
list.Add( 1061168, "{0}\t{1}", MinDamage.ToString(), MaxDamage.ToString() ); // weapon damage ~1_val~ - ~2_val~
|
|
|
|
list.Add( 1061167, Speed.ToString() );
|
|
|
|
if ( MaxRange > 1 )
|
|
list.Add( 1061169, MaxRange.ToString() ); // range ~1_val~
|
|
|
|
int strReq = Ultima.Scale( StrRequirement, 100 - GetLowerStatReq() );
|
|
if ( strReq > 0 )
|
|
list.Add( 1061170, strReq.ToString() ); // strength requirement ~1_val~
|
|
|
|
if ( Layer == Layer.TwoHanded )
|
|
list.Add( 1036381 ); // two-handed weapon
|
|
else
|
|
list.Add( 1036380 ); // one-handed weapon
|
|
|
|
switch ( Skill )
|
|
{
|
|
case SkillName.Swords: list.Add( 1044063 ); break; // Swordsmanship
|
|
case SkillName.Bludgeoning: list.Add( 1044061 ); break; // Bludgeoning
|
|
case SkillName.Fencing: list.Add( 1044062 ); break; // Fencing
|
|
case SkillName.Archery: list.Add( 1044060 ); break; // Archery
|
|
}
|
|
|
|
if ( m_Hits >= 0 && m_MaxHits > 0 )
|
|
list.Add( 1060639, "{0}\t{1}", m_Hits, m_MaxHits ); // durability ~1_val~ / ~2_val~
|
|
}
|
|
else
|
|
{
|
|
double durable = (double)m_Hits / (double)m_MaxHits;
|
|
|
|
if ( durable > 0.95 ){}
|
|
// DO NOT SHOW YET
|
|
else if ( durable > 0.75 )
|
|
list.Add( 1036374 ); // Perfect Condition
|
|
else if ( durable > 0.50 )
|
|
list.Add( 1036373 ); // Good Condition
|
|
else if ( durable > 0.25 )
|
|
list.Add( 1036372 ); // Fair Condition
|
|
else if ( durable > 0.05 )
|
|
list.Add( 1036371 ); // Poor Condition
|
|
else
|
|
list.Add( 1036370 ); // Horrible Condition
|
|
}
|
|
}
|
|
|
|
public override void OnSingleClick( Mobile from )
|
|
{
|
|
List<EquipInfoAttribute> attrs = new List<EquipInfoAttribute>();
|
|
|
|
if ( DisplayLootType )
|
|
{
|
|
if ( LootType == LootType.Blessed )
|
|
attrs.Add( new EquipInfoAttribute( 1038021 ) ); // blessed
|
|
}
|
|
|
|
if ( m_Quality == WeaponQuality.Exceptional )
|
|
attrs.Add( new EquipInfoAttribute( 1018305 - (int)m_Quality ) );
|
|
|
|
if( m_Slayer != SlayerName.None )
|
|
{
|
|
SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer );
|
|
if( entry != null )
|
|
attrs.Add( new EquipInfoAttribute( entry.Title ) );
|
|
}
|
|
|
|
if( m_Slayer2 != SlayerName.None )
|
|
{
|
|
SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer2 );
|
|
if( entry != null )
|
|
attrs.Add( new EquipInfoAttribute( entry.Title ) );
|
|
}
|
|
|
|
if ( m_DurabilityLevel != WeaponDurabilityLevel.Regular )
|
|
attrs.Add( new EquipInfoAttribute( 1038000 + (int)m_DurabilityLevel ) );
|
|
|
|
if ( m_DamageLevel != WeaponDamageLevel.Regular )
|
|
attrs.Add( new EquipInfoAttribute( 1038015 + (int)m_DamageLevel ) );
|
|
|
|
if ( m_AccuracyLevel != WeaponAccuracyLevel.Regular )
|
|
attrs.Add( new EquipInfoAttribute( 1038010 + (int)m_AccuracyLevel ) );
|
|
|
|
if ( m_Poison != null && m_PoisonCharges > 0 )
|
|
attrs.Add( new EquipInfoAttribute( 1017383, m_PoisonCharges ) );
|
|
|
|
int number;
|
|
|
|
if ( Name == null )
|
|
{
|
|
number = LabelNumber;
|
|
}
|
|
else
|
|
{
|
|
this.LabelTo( from, Name );
|
|
number = 1041000;
|
|
}
|
|
|
|
if ( attrs.Count == 0 && Crafter == null && Name != null )
|
|
return;
|
|
|
|
EquipmentInfo eqInfo = new EquipmentInfo( number, m_Crafter, false, attrs.ToArray() );
|
|
|
|
from.Send( new DisplayEquipmentInfo( this, eqInfo ) );
|
|
}
|
|
|
|
private static BaseWeapon m_Fists; // This value holds the default--fist--weapon
|
|
|
|
public static BaseWeapon Fists
|
|
{
|
|
get{ return m_Fists; }
|
|
set{ m_Fists = value; }
|
|
}
|
|
|
|
#region ICraftable Members
|
|
|
|
public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue )
|
|
{
|
|
Quality = (WeaponQuality)quality;
|
|
|
|
if ( makersMark )
|
|
Crafter = from;
|
|
|
|
PlayerConstructed = true;
|
|
|
|
Type resourceType = typeRes;
|
|
|
|
if ( resourceType == null )
|
|
resourceType = craftItem.Resources.GetAt( 0 ).ItemType;
|
|
|
|
return quality;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
public enum CheckSlayerResult
|
|
{
|
|
None,
|
|
Slayer
|
|
}
|
|
}
|