public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
m_CurrentAI = (AIType)reader.ReadInt();
m_DefaultAI = (AIType)reader.ReadInt();
m_iRangePerception = reader.ReadInt();
m_iRangeFight = reader.ReadInt();
m_iTeam = reader.ReadInt();
m_dActiveSpeed = reader.ReadDouble();
m_dPassiveSpeed = reader.ReadDouble();
m_dCurrentSpeed = reader.ReadDouble();
double activeSpeed = m_dActiveSpeed;
double passiveSpeed = m_dPassiveSpeed;
SpeedInfo.GetSpeeds( this, ref activeSpeed, ref passiveSpeed );
bool isStandardActive = false;
for ( int i = 0; !isStandardActive && i < m_StandardActiveSpeeds.Length; ++i )
isStandardActive = ( m_dActiveSpeed == m_StandardActiveSpeeds[i] );
bool isStandardPassive = false;
for ( int i = 0; !isStandardPassive && i < m_StandardPassiveSpeeds.Length; ++i )
isStandardPassive = ( m_dPassiveSpeed == m_StandardPassiveSpeeds[i] );
if ( isStandardActive && m_dCurrentSpeed == m_dActiveSpeed )
m_dCurrentSpeed = activeSpeed;
else if ( isStandardPassive && m_dCurrentSpeed == m_dPassiveSpeed )
m_dCurrentSpeed = passiveSpeed;
if ( isStandardActive )
m_dActiveSpeed = activeSpeed;
if ( isStandardPassive )
m_dPassiveSpeed = passiveSpeed;
if ( m_iRangePerception == OldRangePerception )
m_iRangePerception = DefaultRangePerception;
m_pHome.X = reader.ReadInt();
m_pHome.Y = reader.ReadInt();
m_pHome.Z = reader.ReadInt();
if ( version >= 1 )
{
m_iRangeHome = reader.ReadInt();
int i, iCount;
iCount = reader.ReadInt();
for ( i=0; i< iCount; i++ )
{
string str = reader.ReadString();
Type type = Type.GetType( str );
if ( type != null )
{
m_arSpellAttack.Add( type );
}
}
iCount = reader.ReadInt();
for ( i=0; i< iCount; i++ )
{
string str = reader.ReadString();
Type type = Type.GetType( str );
if ( type != null )
{
m_arSpellDefense.Add( type );
}
}
}
else
{
m_iRangeHome = 0;
}
if ( version >= 2 )
{
m_FightMode = ( FightMode )reader.ReadInt();
m_bControled = reader.ReadBool();
m_ControlMaster = reader.ReadMobile();
m_ControlTarget = reader.ReadMobile();
m_ControlDest = reader.ReadPoint3D();
m_ControlOrder = (OrderType) reader.ReadInt();
m_dMinTameSkill = reader.ReadDouble();
if ( version < 9 )
reader.ReadDouble();
m_bTamable = reader.ReadBool();
m_bSummoned = reader.ReadBool();
if ( m_bSummoned )
{
m_SummonEnd = reader.ReadDeltaTime();
new UnsummonTimer( m_ControlMaster, this, m_SummonEnd - DateTime.Now ).Start();
}
m_iControlSlots = reader.ReadInt();
}
else
{
m_FightMode = FightMode.Closest;
m_bControled = false;
m_ControlMaster = null;
m_ControlTarget = null;
m_ControlOrder = OrderType.None;
}
if ( version >= 3 )
m_Loyalty = (PetLoyalty)reader.ReadInt();
else
m_Loyalty = PetLoyalty.WonderfullyHappy;
if ( version >= 4 )
m_CurrentWayPoint = reader.ReadItem() as WayPoint;
if ( version >= 5 )
m_SummonMaster = reader.ReadMobile();
if ( version >= 6 )
{
m_HitsMax = reader.ReadInt();
m_StamMax = reader.ReadInt();
m_ManaMax = reader.ReadInt();
m_DamageMin = reader.ReadInt();
m_DamageMax = reader.ReadInt();
}
if ( version >= 7 )
{
m_PhysicalResistance = reader.ReadInt();
m_PhysicalDamage = reader.ReadInt();
m_FireResistance = reader.ReadInt();
m_FireDamage = reader.ReadInt();
m_ColdResistance = reader.ReadInt();
m_ColdDamage = reader.ReadInt();
m_PoisonResistance = reader.ReadInt();
m_PoisonDamage = reader.ReadInt();
m_EnergyResistance = reader.ReadInt();
m_EnergyDamage = reader.ReadInt();
}
if ( version >= 8 )
m_Owners = reader.ReadMobileList();
else
m_Owners = new ArrayList();
if ( version >= 10 )
{
m_IsDeadPet = reader.ReadBool();
m_IsBonded = reader.ReadBool();
m_BondingBegin = reader.ReadDateTime();
m_OwnerAbandonTime = reader.ReadDateTime();
}
if ( version >= 11 )
m_HasGeneratedLoot = reader.ReadBool();
else
m_HasGeneratedLoot = true;
if ( version >= 12 )
m_Paragon = reader.ReadBool();
else
m_Paragon = false;
if ( version >= 13 && reader.ReadBool() )
m_Friends = reader.ReadMobileList();
else if ( version < 13 && m_ControlOrder >= OrderType.Unfriend )
++m_ControlOrder;
CheckStatTimers();
ChangeAIType(m_CurrentAI);
AddFollowers();
if ( IsAnimatedDead )
Spells.Necromancy.AnimateDeadSpell.Register( m_SummonMaster, this );
if ( version >= 14 )
{
m_IsMating = reader.ReadBool();
m_ABPoints = reader.ReadInt();
m_Exp = reader.ReadInt();
m_NextLevel = reader.ReadInt();
m_Level = reader.ReadInt();
m_MaxLevel = reader.ReadInt();
m_AllowMating = reader.ReadBool();
m_Evolves = reader.ReadBool();
m_Gen = reader.ReadInt();
m_MatingDelay = reader.ReadDateTime();
m_Form1 = reader.ReadInt();
m_Form2 = reader.ReadInt();
m_Form3 = reader.ReadInt();
m_Form4 = reader.ReadInt();
m_Form5 = reader.ReadInt();
m_Form6 = reader.ReadInt();
m_Form7 = reader.ReadInt();
m_Form8 = reader.ReadInt();
m_Form9 = reader.ReadInt();
m_Sound1 = reader.ReadInt();
m_Sound2 = reader.ReadInt();
m_Sound3 = reader.ReadInt();
m_Sound4 = reader.ReadInt();
m_Sound5 = reader.ReadInt();
m_Sound6 = reader.ReadInt();
m_Sound7 = reader.ReadInt();
m_Sound8 = reader.ReadInt();
m_Sound9 = reader.ReadInt();
m_UsesForm1 = reader.ReadBool();
m_UsesForm2 = reader.ReadBool();
m_UsesForm3 = reader.ReadBool();
m_UsesForm4 = reader.ReadBool();
m_UsesForm5 = reader.ReadBool();
m_UsesForm6 = reader.ReadBool();
m_UsesForm7 = reader.ReadBool();
m_UsesForm8 = reader.ReadBool();
m_UsesForm9 = reader.ReadBool();
m_F0 = reader.ReadBool();
m_F1 = reader.ReadBool();
m_F2 = reader.ReadBool();
m_F3 = reader.ReadBool();
m_F4 = reader.ReadBool();
m_F5 = reader.ReadBool();
m_F6 = reader.ReadBool();
m_F7 = reader.ReadBool();
m_F8 = reader.ReadBool();
m_F9 = reader.ReadBool();
}
}
public virtual bool IsHumanInTown()
{
return ( Body.IsHuman && Region is Regions.GuardedRegion );
}
public virtual bool CheckGold( Mobile from, Item dropped )
{
if ( dropped is Gold )
return OnGoldGiven( from, (Gold)dropped );
return false;
}
public virtual bool OnGoldGiven( Mobile from, Gold dropped )
{
if ( CheckTeachingMatch( from ) )
{
if ( Teach( m_Teaching, from, dropped.Amount, true ) )
{
dropped.Delete();
return true;
}
}
else if ( IsHumanInTown() )
{
Direction = GetDirectionTo( from );
int oldSpeechHue = this.SpeechHue;
this.SpeechHue = 0x23F;
SayTo( from, "Thou art giving me gold?" );
if ( dropped.Amount >= 400 )
SayTo( from, "'Tis a noble gift." );
else
SayTo( from, "Money is always welcome." );
this.SpeechHue = 0x3B2;
SayTo( from, 501548 ); // I thank thee.
this.SpeechHue = oldSpeechHue;
dropped.Delete();
return true;
}
return false;
}
public override bool ShouldCheckStatTimers{ get{ return false; } }
private static Type[] m_Eggs = new Type[]
{
typeof( FriedEggs ), typeof( Eggs )
};
private static Type[] m_Fish = new Type[]
{
typeof( FishSteak ), typeof( RawFishSteak )
};
private static Type[] m_GrainsAndHay = new Type[]
{
typeof( BreadLoaf ), typeof( FrenchBread )
};
private static Type[] m_Meat = new Type[]
{
/* Cooked */
typeof( Bacon ), typeof( CookedBird ), typeof( Sausage ),
typeof( Ham ), typeof( Ribs ), typeof( LambLeg ),
typeof( ChickenLeg ),
/* Uncooked */
typeof( RawBird ), typeof( RawRibs ), typeof( RawLambLeg ),
typeof( RawChickenLeg ),
/* Body Parts */
typeof( Head ), typeof( LeftArm ), typeof( LeftLeg ),
typeof( Torso ), typeof( RightArm ), typeof( RightLeg )
};
private static Type[] m_FruitsAndVegies = new Type[]
{
typeof( HoneydewMelon ), typeof( YellowGourd ), typeof( GreenGourd ),
typeof( Banana ), typeof( Bananas ), typeof( Lemon ), typeof( Lime ),
typeof( Dates ), typeof( Grapes ), typeof( Peach ), typeof( Pear ),
typeof( Apple ), typeof( Watermelon ), typeof( Squash ),
typeof( Cantaloupe ), typeof( Carrot ), typeof( Cabbage ),
typeof( Onion ), typeof( Lettuce ), typeof( Pumpkin )
};
private static Type[] m_Gold = new Type[]
{
// white wyrms eat gold..
typeof( Gold )
};
public virtual bool CheckFoodPreference( Item f )
{
if ( CheckFoodPreference( f, FoodType.Eggs, m_Eggs ) )
return true;
if ( CheckFoodPreference( f, FoodType.Fish, m_Fish ) )
return true;
if ( CheckFoodPreference( f, FoodType.GrainsAndHay, m_GrainsAndHay ) )
return true;
if ( CheckFoodPreference( f, FoodType.Meat, m_Meat ) )
return true;
if ( CheckFoodPreference( f, FoodType.FruitsAndVegies, m_FruitsAndVegies ) )
return true;
if ( CheckFoodPreference( f, FoodType.Gold, m_Gold ) )
return true;
return false;
}
public virtual bool CheckFoodPreference( Item fed, FoodType type, Type[] types )
{
if ( (FavoriteFood & type) == 0 )
return false;
Type fedType = fed.GetType();
bool contains = false;
for ( int i = 0; !contains && i < types.Length; ++i )
contains = ( fedType == types[i] );
return contains;
}
public virtual bool CheckFeed( Mobile from, Item dropped )
{
if ( !IsDeadPet && Controled && (ControlMaster == from || IsPetFriend( from )) && (dropped is Food || dropped is Gold || dropped is CookableFood || dropped is Head || dropped is LeftArm || dropped is LeftLeg || dropped is Torso || dropped is RightArm || dropped is RightLeg) )
{
Item f = dropped;
if ( CheckFoodPreference( f ) )
{
int amount = f.Amount;
if ( amount > 0 )
{
bool happier = false;
int stamGain;
if ( f is Gold )
stamGain = amount - 50;
else
stamGain = (amount * 15) - 50;
if ( stamGain > 0 )
Stam += stamGain;
for ( int i = 0; i < amount; ++i )
{
if ( m_Loyalty < PetLoyalty.WonderfullyHappy && 0.5 >= Utility.RandomDouble() )
{
++m_Loyalty;
happier = true;
}
}
if ( happier )
SayTo( from, 502060 ); // Your pet looks happier.
if ( Body.IsAnimal )
Animate( 3, 5, 1, true, false, 0 );
else if ( Body.IsMonster )
Animate( 17, 5, 1, true, false, 0 );
if ( IsBondable && !IsBonded )
{
Mobile master = m_ControlMaster;
if ( master != null )
{
if ( m_dMinTameSkill <= 29.1 || master.Skills[SkillName.AnimalTaming].Value >= m_dMinTameSkill || this is SwampDragon || this is Ridgeback || this is SavageRidgeback )
{
if ( BondingBegin == DateTime.MinValue )
{
BondingBegin = DateTime.Now;
}
else if ( (BondingBegin + BondingDelay) <= DateTime.Now )
{
IsBonded = true;
BondingBegin = DateTime.MinValue;
from.SendLocalizedMessage( 1049666 ); // Your pet has bonded with you!
}
}
}
}
dropped.Delete();
return true;
}
}
}
return false;
}
public virtual void OnActionWander()
{
}
public virtual void OnActionCombat()
{
}
public virtual void OnActionGuard()
{
}
public virtual void OnActionFlee()
{
}
public virtual void OnActionInteract()
{
}
public virtual void OnActionBackoff()
{
}
public override bool OnDragDrop( Mobile from, Item dropped )
{
if ( CheckFeed( from, dropped ) )
return true;
else if ( CheckGold( from, dropped ) )
return true;
return base.OnDragDrop( from, dropped );
}
public virtual void ChangeAIType(AIType NewAI)
{
if ( m_AI != null )
m_AI.m_Timer.Stop();
m_AI = null;
if ( this is BaseFactionGuard )
{
m_AI = new FactionGuardAI( (BaseFactionGuard) this );
return;
}
switch (NewAI)
{
case AIType.AI_Melee:
m_AI = new MeleeAI(this);
break;
case AIType.AI_Animal:
m_AI = new AnimalAI(this);
break;
case AIType.AI_Berserk:
m_AI = new BerserkAI(this);
break;
case AIType.AI_Archer:
m_AI = new ArcherAI(this);
break;
case AIType.AI_Healer:
m_AI = new HealerAI(this);
break;
case AIType.AI_Vendor:
m_AI = new VendorAI(this);
break;
case AIType.AI_Mage:
m_AI = new MageAI(this);
break;
case AIType.AI_Predator:
//m_AI = new PredatorAI(this);
m_AI = new MeleeAI(this);
break;
case AIType.AI_Thief:
m_AI = new ThiefAI(this);
break;
}
}
public virtual void ChangeAIToDefault()
{
ChangeAIType(m_DefaultAI);
}
[CommandProperty( AccessLevel.GameMaster )]
public AIType AI
{
get
{
return m_CurrentAI;
}
set
{
m_CurrentAI = value;
if (m_CurrentAI == AIType.AI_Use_Default)
{
m_CurrentAI = m_DefaultAI;
}
ChangeAIType(m_CurrentAI);
}
}
[CommandProperty( AccessLevel.Administrator )]
public bool Debug
{
get
{
return m_bDebugAI;
}
set
{
m_bDebugAI = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public int Team
{
get
{
return m_iTeam;
}
set
{
m_iTeam = value;
OnTeamChange();
}
}
public virtual void OnTeamChange()
{
}
[CommandProperty( AccessLevel.GameMaster )]
public Mobile FocusMob
{
get
{
return m_FocusMob;
}
set
{
m_FocusMob = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public FightMode FightMode
{
get
{
return m_FightMode;
}
set
{
m_FightMode = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public int RangePerception
{
get
{
return m_iRangePerception;
}
set
{
m_iRangePerception = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public int RangeFight
{
get
{
return m_iRangeFight;
}
set
{
m_iRangeFight = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public int RangeHome
{
get
{
return m_iRangeHome;
}
set
{
m_iRangeHome = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public double ActiveSpeed
{
get
{
return m_dActiveSpeed;
}
set
{
m_dActiveSpeed = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public double PassiveSpeed
{
get
{
return m_dPassiveSpeed;
}
set
{
m_dPassiveSpeed = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public double CurrentSpeed
{
get
{
return m_dCurrentSpeed;
}
set
{
if ( m_dCurrentSpeed != value )
{
m_dCurrentSpeed = value;
if (m_AI != null)
m_AI.OnCurrentSpeedChanged();
}
}
}
[CommandProperty( AccessLevel.GameMaster )]
public Point3D Home
{
get
{
return m_pHome;
}
set
{
m_pHome = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public bool Controled
{
get
{
return m_bControled;
}
set
{
if ( m_bControled == value )
return;
m_bControled = value;
Delta( MobileDelta.Noto );
InvalidateProperties();
}
}
public override void RevealingAction()
{
Spells.Sixth.InvisibilitySpell.RemoveTimer( this );
base.RevealingAction();
}
public void RemoveFollowers()
{
if ( m_ControlMaster != null )
m_ControlMaster.Followers -= ControlSlots;
else if ( m_SummonMaster != null )
m_SummonMaster.Followers -= ControlSlots;
if ( m_ControlMaster != null && m_ControlMaster.Followers < 0 )
m_ControlMaster.Followers = 0;
if ( m_SummonMaster != null && m_SummonMaster.Followers < 0 )
m_SummonMaster.Followers = 0;
}
public void AddFollowers()
{
if ( m_ControlMaster != null )
m_ControlMaster.Followers += ControlSlots;
else if ( m_SummonMaster != null )
m_SummonMaster.Followers += ControlSlots;
}
[CommandProperty( AccessLevel.GameMaster )]
public Mobile ControlMaster
{
get
{
return m_ControlMaster;
}
set
{
if ( m_ControlMaster == value )
return;
RemoveFollowers();
m_ControlMaster = value;
AddFollowers();
Delta( MobileDelta.Noto );
}
}
[CommandProperty( AccessLevel.GameMaster )]
public Mobile SummonMaster
{
get
{
return m_SummonMaster;
}
set
{
if ( m_SummonMaster == value )
return;
RemoveFollowers();
m_SummonMaster = value;
AddFollowers();
Delta( MobileDelta.Noto );
}
}
[CommandProperty( AccessLevel.GameMaster )]
public Mobile ControlTarget
{
get
{
return m_ControlTarget;
}
set
{
m_ControlTarget = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public Point3D ControlDest
{
get
{
return m_ControlDest;
}
set
{
m_ControlDest = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public OrderType ControlOrder
{
get
{
return m_ControlOrder;
}
set
{
m_ControlOrder = value;
if ( m_AI != null )
m_AI.OnCurrentOrderChanged();
}
}
[CommandProperty( AccessLevel.GameMaster )]
public bool BardProvoked
{
get
{
return m_bBardProvoked;
}
set
{
m_bBardProvoked = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public bool BardPacified
{
get
{
return m_bBardPacified;
}
set
{
m_bBardPacified = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public Mobile BardMaster
{
get
{
return m_bBardMaster;
}
set
{
m_bBardMaster = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public Mobile BardTarget
{
get
{
return m_bBardTarget;
}
set
{
m_bBardTarget = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public DateTime BardEndTime
{
get
{
return m_timeBardEnd;
}
set
{
m_timeBardEnd = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public double MinTameSkill
{
get
{
return m_dMinTameSkill;
}
set
{
m_dMinTameSkill = value;
}
}
[CommandProperty( AccessLevel.GameMaster )]
public bool Tamable
{
get
{
return m_bTamable && !m_Paragon;
}
set
{
m_bTamable = value;
}
}
[CommandProperty( AccessLevel.Administrator )]
public bool Summoned
{
get
{
return m_bSummoned;
}
set
{
if ( m_bSummoned == value )
return;
m_NextReaquireTime = DateTime.Now;
m_bSummoned = value;
Delta( MobileDelta.Noto );
InvalidateProperties();
}
}
[CommandProperty( AccessLevel.Administrator )]
public int ControlSlots
{
get
{
return m_iControlSlots;
}
set
{
m_iControlSlots = value;
}
}
public virtual bool NoHouseRestrictions{ get{ return false; } }
public virtual bool IsHouseSummonable{ get{ return false; } }
public virtual int Feathers{ get{ return 0; } }
public virtual int Wool{ get{ return 0; } }
public virtual MeatType MeatType{ get{ return MeatType.Ribs; } }
public virtual int Meat{ get{ return 0; } }
public virtual int Hides{ get{ return 0; } }
public virtual HideType HideType{ get{ return HideType.Regular; } }
public virtual int Scales{ get{ return 0; } }
public virtual ScaleType ScaleType{ get{ return ScaleType.Red; } }
public virtual bool AutoDispel{ get{ return false; } }
public virtual bool IsScaryToPets{ get{ return false; } }
public virtual bool IsScaredOfScaryThings{ get{ return true; } }
public virtual bool CanRummageCorpses{ get{ return false; } }
public virtual void OnGotMeleeAttack( Mobile attacker )
{
if ( AutoDispel && attacker is BaseCreature && ((BaseCreature)attacker).Summoned && !((BaseCreature)attacker).IsAnimatedDead )
Dispel( attacker );
}
public virtual void Dispel( Mobile m )
{
Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x3728, 8, 20, 5042 );
Effects.PlaySound( m, m.Map, 0x201 );
m.Delete();
}
public virtual bool DeleteOnRelease{ get{ return m_bSummoned; } }
//Advanced Pet System
public void DoDeathCheck()
{
Mobile cm = this.ControlMaster;
if ( cm != null && this.Controled == true && Tamable == true )
{
if ( this.IsBonded == true )
{
if ( this.AbilityPoints >= 0 && Utility.Random( 100 ) < 25 )
{
this.AbilityPoints = this.AbilityPoints / 2;
cm.SendMessage( 38, "Your pet has lost half of thier ability points due to its untimely death." );
}
else if ( this.Exp >= 0 && Utility.Random( 100 ) < 25 )
{
this.Exp = this.Exp / 2;
cm.SendMessage( 38, "Your pet has lost half of thier exp due to its untimely death." );
}
else if ( Utility.Random( 100 ) < 25 )
{
int strloss = this.Str / 20;
int dexloss = this.Dex / 20;
int intloss = this.Int / 20;
int hitsloss = this.Hits / 20;
int stamloss = this.Stam / 20;
int manaloss = this.Mana / 20;
int physloss = this.PhysicalResistance / 20;
int fireloss = this.FireResistance / 20;
int coldloss = this.ColdResistance / 20;
int energyloss = this.EnergyResistance / 20;
int poisonloss = this.PoisonResistance / 20;
int dminloss = this.DamageMin / 20;
int dmaxloss = this.DamageMax / 20;
this.Str -= strloss;
this.Dex -= dexloss;
this.Int -= intloss;
if ( this.HitsMaxSeed >= 0 )
this.HitsMaxSeed -= hitsloss;
if ( this.StamMaxSeed >= 0 )
this.StamMaxSeed -= stamloss;
if ( this.ManaMaxSeed >= 0 )
this.ManaMaxSeed -= manaloss;
if ( this.PhysicalResistanceSeed >= 0 )
this.PhysicalResistanceSeed -= physloss;
if ( this.FireResistSeed >= 0 )
this.FireResistSeed -= fireloss;
if ( this.ColdResistSeed >= 0 )
this.ColdResistSeed -= coldloss;
if ( this.EnergyResistSeed >= 0 )
this.EnergyResistSeed -= energyloss;
if ( this.PoisonResistSeed >= 0 )
this.PoisonResistSeed -= poisonloss;
this.DamageMin -= dminloss;
this.DamageMax -= dmaxloss;
cm.SendMessage( 38, "Your pet has suffered a 5% stat lose due to its untimely death." );
}
cm.SendMessage( 64, "Your pet has been killed!" );
}
else
{
cm.SendMessage( 64, "Your pet has been killed!" );
}
}
}
public void DoBioDeath()
{
Mobile cm = this.ControlMaster;
if ( cm != null && this.Controled == true && Tamable == true )
{
if ( this.IsBonded == true )
{
if ( Utility.Random( 100 ) < 25 )
{
int strloss = this.Str / 20;
int dexloss = this.Dex / 20;
int intloss = this.Int / 20;
int hitsloss = this.Hits / 20;
int stamloss = this.Stam / 20;
int manaloss = this.Mana / 20;
int physloss = this.PhysicalResistance / 20;
int fireloss = this.FireResistance / 20;
int coldloss = this.ColdResistance / 20;
int energyloss = this.EnergyResistance / 20;
int poisonloss = this.PoisonResistance / 20;
int dminloss = this.DamageMin / 20;
int dmaxloss = this.DamageMax / 20;
this.Str -= strloss;
this.Dex -= dexloss;
this.Int -= intloss;
if ( this.HitsMaxSeed >= 0 )
this.HitsMaxSeed -= hitsloss;
if ( this.StamMaxSeed >= 0 )
this.StamMaxSeed -= stamloss;
if ( this.ManaMaxSeed >= 0 )
this.ManaMaxSeed -= manaloss;
if ( this.PhysicalResistanceSeed >= 0 )
this.PhysicalResistanceSeed -= physloss;
if ( this.FireResistSeed >= 0 )
this.FireResistSeed -= fireloss;
if ( this.ColdResistSeed >= 0 )
this.ColdResistSeed -= coldloss;
if ( this.EnergyResistSeed >= 0 )
this.EnergyResistSeed -= energyloss;
if ( this.PoisonResistSeed >= 0 )
this.PoisonResistSeed -= poisonloss;
this.DamageMin -= dminloss;
this.DamageMax -= dmaxloss;
cm.SendMessage( 38, "Your pet has suffered a 5% stat lose due to its untimely death." );
}
cm.SendMessage( 64, "Your pet has been killed!" );
}
else
{
cm.SendMessage( 64, "Your pet has been killed!" );
}
}
}
public void CheckLevel( Mobile defender )
{
int expgainmin, expgainmax;
if ( this is BaseBioCreature )
{
}
else if ( defender is BaseCreature )
{
if ( this.Controled == true && this.ControlMaster != null && Summoned == false )
{
BaseCreature bc = (BaseCreature)defender;
expgainmin = 5 + ( bc.HitsMax ) / 10;
expgainmax = 5 + ( bc.HitsMax ) / 5;
if ( m_Level <= m_MaxLevel - 1 )
m_Exp += Utility.RandomList( expgainmin, expgainmax );
int nextLevel = m_NextLevel * m_Level;
if ( m_Exp >= nextLevel && m_Level <= m_MaxLevel - 1 )
{
Mobile cm = this.ControlMaster;
m_Level += 1;
m_Exp = 0;
this.FixedParticles( 0x373A, 10, 15, 5012, EffectLayer.Waist );
this.PlaySound( 503 );
cm.SendMessage( 38, "Your pets level has increased to {0}.", m_Level );
int gain = Utility.RandomList( 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6 );
int random = Utility.Random( 100 );
if ( random < 2 )
gain = gain * 10;
else if ( random < 4 )
gain = gain * 5;
else if ( random < 6 )
gain = gain * 4;
else if ( random < 8 )
gain = gain * 3;
else if ( random < 10 )
gain = gain * 2;
else
gain = gain;
this.AbilityPoints += gain;
if ( this.ControlMaster != null )
{
this.ControlMaster.SendMessage( 38, "Your pet {0} has gained some ability points, Goto your pets 'NPC Info' and click the red diamond to apply these points." );
//this.ControlMaster.CloseGump( typeof( LevelGump ) );
//this.ControlMaster.CloseGump( typeof( PetLevelGump ) );
//this.ControlMaster.SendGump( new LevelGump( this ) );
}
if ( m_Level == 9 )
{
m_AllowMating = true;
cm.SendMessage( 1161, "Your pet is now at the level to mate." );
}
if ( m_Evolves == true )
{
if ( UsesForm1 == true && F0 == true )
{
this.BodyValue = m_Form1;
this.BaseSoundID = m_Sound1;
m_F1 = true;
m_F2 = false;
m_F3 = false;
m_F4 = false;
m_F5 = false;
m_F6 = false;
m_F7 = false;
m_F8 = false;
m_F9 = false;
UsesForm1 = false;
cm.SendMessage( 64, "Your pet has evoloved." );
}
else if ( UsesForm2 == true && F1 == true )
{
this.BodyValue = m_Form2;
this.BaseSoundID = m_Sound2;
m_F1 = false;
m_F2 = true;
m_F3 = false;
m_F4 = false;
m_F5 = false;
m_F6 = false;
m_F7 = false;
m_F8 = false;
m_F9 = false;
UsesForm2 = false;
cm.SendMessage( 64, "Your pet has evoloved." );
}
else if ( UsesForm3 == true && F2 == true )
{
this.BodyValue = m_Form3;
this.BaseSoundID = m_Sound3;
m_F1 = false;
m_F2 = false;
m_F3 = true;
m_F4 = false;
m_F5 = false;
m_F6 = false;
m_F7 = false;
m_F8 = false;
m_F9 = false;
UsesForm3 = false;
cm.SendMessage( 64, "Your pet has evoloved." );
}
else if ( UsesForm4 == true && F3 == true )
{
this.BodyValue = m_Form4;
this.BaseSoundID = m_Sound4;
m_F1 = false;
m_F2 = false;
m_F3 = false;
m_F4 = true;
m_F5 = false;
m_F6 = false;
m_F7 = false;
m_F8 = false;
m_F9 = false;
UsesForm4 = false;
cm.SendMessage( 64, "Your pet has evoloved." );
}
else if ( UsesForm5 == true && F4 == true )
{
this.BodyValue = m_Form5;
this.BaseSoundID = m_Sound5;
m_F1 = false;
m_F2 = false;
m_F3 = false;
m_F4 = false;
m_F5 = true;
m_F6 = false;
m_F7 = false;
m_F8 = false;
m_F9 = false;
UsesForm5 = false;
cm.SendMessage( 64, "Your pet has evoloved." );
}
else if ( UsesForm6 == true && F5 == true )
{
this.BodyValue = m_Form6;
this.BaseSoundID = m_Sound6;
m_F1 = false;
m_F2 = false;
m_F3 = false;
m_F4 = false;
m_F5 = false;
m_F6 = true;
m_F7 = false;
m_F8 = false;
m_F9 = false;
UsesForm6 = false;
cm.SendMessage( 64, "Your pet has evoloved." );
}
else if ( UsesForm7 == true && F6 == true )
{
this.BodyValue = m_Form7;
this.BaseSoundID = m_Sound7;
m_F1 = false;
m_F2 = false;
m_F3 = false;
m_F4 = false;
m_F5 = false;
m_F6 = false;
m_F7 = true;
m_F8 = false;
m_F9 = false;
UsesForm7 = false;
cm.SendMessage( 64, "Your pet has evoloved." );
}
else if ( UsesForm8 == true && F7 == true )
{
this.BodyValue = m_Form8;
this.BaseSoundID = m_Sound8;
m_F1 = false;
m_F2 = false;
m_F3 = false;
m_F4 = false;
m_F5 = false;
m_F6 = false;
m_F7 = false;
m_F8 = true;
m_F9 = false;
UsesForm8 = false;
cm.SendMessage( 64, "Your pet has evoloved." );
}
else if ( UsesForm9 == true && F8 == true )
{
this.BodyValue = m_Form9;
this.BaseSoundID = m_Sound9;
m_F1 = false;
m_F2 = false;
m_F3 = false;
m_F4 = false;
m_F5 = false;
m_F6 = false;
m_F7 = false;
m_F8 = false;
m_F9 = true;
UsesForm9 = false;
cm.SendMessage( 64, "Your pet has evoloved." );
}
}
}
}
}
}
//End Advanced Pet System
public virtual void OnGaveMeleeAttack( Mobile defender )
{
Poison p = HitPoison;
if ( m_Paragon )
p = PoisonImpl.IncreaseLevel( p );
if ( p != null && HitPoisonChance >= Utility.RandomDouble() )
defender.ApplyPoison( this, p );
if ( AutoDispel && defender is BaseCreature && ((BaseCreature)defender).Summoned && !((BaseCreature)defender).IsAnimatedDead )
Dispel( defender );
if ( FSATS.EnablePetLeveling == true )
{
bool nolevel = false;
Type typ = this.GetType();
string nam = typ.Name;
foreach ( string check in FSATS.NoLevelCreatures )
{
if ( check == nam )
nolevel = true;
}
if ( nolevel != true )
CheckLevel( defender );
}
}
public override void OnAfterDelete()
{
if ( m_AI != null )
{
if ( m_AI.m_Timer != null )
m_AI.m_Timer.Stop();
m_AI = null;
}
FocusMob = null;
if ( IsAnimatedDead )
Spells.Necromancy.AnimateDeadSpell.Unregister( m_SummonMaster, this );
base.OnAfterDelete();
}
public void DebugSay( string text )
{
if ( m_bDebugAI )
this.PublicOverheadMessage( MessageType.Regular, 41, false, text );
}
public void DebugSay( string format, params object[] args )
{
if ( m_bDebugAI )
this.PublicOverheadMessage( MessageType.Regular, 41, false, String.Format( format, args ) );
}
/*
* Will need to be givent a better name
*
* This function can be overriden.. so a "Strongest" mobile, can have a different definition depending
* on who check for value
* -Could add a FightMode.Prefered
*
*/
public virtual double GetValueFrom( Mobile m, FightMode acqType, bool bPlayerOnly )
{
if ( ( bPlayerOnly && m.Player ) || !bPlayerOnly )
{
switch( acqType )
{
case FightMode.Strongest :
return (m.Skills[SkillName.Tactics].Value + m.Str); //returns strongest mobile
case FightMode.Weakest :
return -m.Hits; // returns weakest mobile
default :
return -GetDistanceToSqrt( m ); // returns closest mobile
}
}
else
{
return double.MinValue;
}
}
// Turn, - for let, + for right
// Basic for now, need works
public virtual void Turn(int iTurnSteps)
{
int v = (int)Direction;
Direction = (Direction)((((v & 0x7) + iTurnSteps) & 0x7) | (v & 0x80));
}
public virtual void TurnInternal(int iTurnSteps)
{
int v = (int)Direction;
SetDirection( (Direction)((((v & 0x7) + iTurnSteps) & 0x7) | (v & 0x80)) );
}
public bool IsHurt()
{
return ( Hits != HitsMax );
}
public double GetHomeDistance()
{
return GetDistanceToSqrt( m_pHome );
}
public virtual int GetTeamSize(int iRange)
{
int iCount = 0;
foreach ( Mobile m in this.GetMobilesInRange( iRange ) )
{
if (m is BaseCreature)
{
if ( ((BaseCreature)m).Team == Team )
{
if ( !m.Deleted )
{
if ( m != this )
{
if ( CanSee( m ) )
{
iCount++;
}
}
}
}
}
}
return iCount;
}
// Do my combatant is attaking me??
public bool IsCombatantAnAgressor()
{
if (Combatant != null)
{
if (Combatant.Combatant == this)
{
return true;
}
}
return false;
}
private class TameEntry : ContextMenuEntry
{
private BaseCreature m_Mobile;
public TameEntry( Mobile from, BaseCreature creature ) : base( 6130, 6 )
{
m_Mobile = creature;
Enabled = Enabled && ( from.Female ? creature.AllowFemaleTamer : creature.AllowMaleTamer );
}
public override void OnClick()
{
if ( !Owner.From.CheckAlive() )
return;
Owner.From.TargetLocked = true;
SkillHandlers.AnimalTaming.DisableMessage = true;
if ( Owner.From.UseSkill( SkillName.AnimalTaming ) )
Owner.From.Target.Invoke( Owner.From, m_Mobile );
SkillHandlers.AnimalTaming.DisableMessage = false;
Owner.From.TargetLocked = false;
}
}
public virtual bool CanTeach{ get{ return false; } }
public virtual bool CheckTeach( SkillName skill, Mobile from )
{
if ( !CanTeach )
return false;
if ( skill == SkillName.Stealth && from.Skills[SkillName.Hiding].Base < 80.0 )
return false;
if ( skill == SkillName.RemoveTrap && (from.Skills[SkillName.Lockpicking].Base < 50.0 || from.Skills[SkillName.DetectHidden].Base < 50.0) )
return false;
if ( !Core.AOS && (skill == SkillName.Focus || skill == SkillName.Chivalry || skill == SkillName.Necromancy) )
return false;
return true;
}
public enum TeachResult
{
Success,
Failure,
KnowsMoreThanMe,
KnowsWhatIKnow,
SkillNotRaisable,
NotEnoughFreePoints
}
public virtual TeachResult CheckTeachSkills( SkillName skill, Mobile m, int maxPointsToLearn, ref int pointsToLearn, bool doTeach )
{
if ( !CheckTeach( skill, m ) || !m.CheckAlive() )
return TeachResult.Failure;
Skill ourSkill = Skills[skill];
Skill theirSkill = m.Skills[skill];
if ( ourSkill == null || theirSkill == null )
return TeachResult.Failure;
int baseToSet = ourSkill.BaseFixedPoint / 3;
if ( baseToSet > 420 )
baseToSet = 420;
else if ( baseToSet < 200 )
return TeachResult.Failure;
if ( baseToSet > theirSkill.CapFixedPoint )
baseToSet = theirSkill.CapFixedPoint;
pointsToLearn = baseToSet - theirSkill.BaseFixedPoint;
if ( maxPointsToLearn > 0 && pointsToLearn > maxPointsToLearn )
{
pointsToLearn = maxPointsToLearn;
baseToSet = theirSkill.BaseFixedPoint + pointsToLearn;
}
if ( pointsToLearn < 0 )
return TeachResult.KnowsMoreThanMe;
if ( pointsToLearn == 0 )
return TeachResult.KnowsWhatIKnow;
if ( theirSkill.Lock != SkillLock.Up )
return TeachResult.SkillNotRaisable;
int freePoints = m.Skills.Cap - m.Skills.Total;
int freeablePoints = 0;
if ( freePoints < 0 )
freePoints = 0;
for ( int i = 0; (freePoints + freeablePoints) < pointsToLearn && i < m.Skills.Length; ++i )
{
Skill sk = m.Skills[i];
if ( sk == theirSkill || sk.Lock != SkillLock.Down )
continue;
freeablePoints += sk.BaseFixedPoint;
}
if ( (freePoints + freeablePoints) == 0 )
return TeachResult.NotEnoughFreePoints;
if ( (freePoints + freeablePoints) < pointsToLearn )
{
pointsToLearn = freePoints + freeablePoints;
baseToSet = theirSkill.BaseFixedPoint + pointsToLearn;
}
if ( doTeach )
{
int need = pointsToLearn - freePoints;
for ( int i = 0; need > 0 && i < m.Skills.Length; ++i )
{
Skill sk = m.Skills[i];
if ( sk == theirSkill || sk.Lock != SkillLock.Down )
continue;
if ( sk.BaseFixedPoint < need )
{
need -= sk.BaseFixedPoint;
sk.BaseFixedPoint = 0;
}
else
{
sk.BaseFixedPoint -= need;
need = 0;
}
}
/* Sanity check */
if ( baseToSet > theirSkill.CapFixedPoint || (m.Skills.Total - theirSkill.BaseFixedPoint + baseToSet) > m.Skills.Cap )
return TeachResult.NotEnoughFreePoints;
theirSkill.BaseFixedPoint = baseToSet;
}
return TeachResult.Success;
}
public virtual bool CheckTeachingMatch( Mobile m )
{
if ( m_Teaching == (SkillName)(-1) )
return false;
if ( m is PlayerMobile )
return ( ((PlayerMobile)m).Learning == m_Teaching );
return true;
}
private SkillName m_Teaching = (SkillName)(-1);
public virtual bool Teach( SkillName skill, Mobile m, int maxPointsToLearn, bool doTeach )
{
int pointsToLearn = 0;
TeachResult res = CheckTeachSkills( skill, m, maxPointsToLearn, ref pointsToLearn, doTeach );
switch ( res )
{
case TeachResult.KnowsMoreThanMe:
{
Say( 501508 ); // I cannot teach thee, for thou knowest more than I!
break;
}
case TeachResult.KnowsWhatIKnow:
{
Say( 501509 ); // I cannot teach thee, for thou knowest all I can teach!
break;
}
case TeachResult.NotEnoughFreePoints:
case TeachResult.SkillNotRaisable:
{
// Make sure this skill is marked to raise. If you are near the skill cap (700 points) you may need to lose some points in another skill first.
m.SendLocalizedMessage( 501510, "", 0x22 );
break;
}
case TeachResult.Success:
{
if ( doTeach )
{
Say( 501539 ); // Let me show thee something of how this is done.
m.SendLocalizedMessage( 501540 ); // Your skill level increases.
m_Teaching = (SkillName)(-1);
if ( m is PlayerMobile )
((PlayerMobile)m).Learning = (SkillName)(-1);
}
else
{
// I will teach thee all I know, if paid the amount in full. The price is:
Say( 1019077, AffixType.Append, String.Format( " {0}", pointsToLearn ), "" );
Say( 1043108 ); // For less I shall teach thee less.
m_Teaching = skill;
if ( m is PlayerMobile )
((PlayerMobile)m).Learning = skill;
}
return true;
}
}
return false;
}
public override void AggressiveAction( Mobile aggressor, bool criminal )
{
base.AggressiveAction( aggressor, criminal );
if ( m_AI != null )
m_AI.OnAggressiveAction( aggressor );
StopFlee();
ForceReaquire();
OrderType ct = m_ControlOrder;
if ( aggressor.ChangingCombatant && (m_bControled || m_bSummoned) && (ct == OrderType.Come || ct == OrderType.Stay || ct == OrderType.Stop || ct == OrderType.None || ct == OrderType.Follow) )
{
ControlTarget = aggressor;
ControlOrder = OrderType.Attack;
}
else if ( Combatant == null && !m_bBardPacified )
{
Warmode = true;
Combatant = aggressor;
}
}
public override bool OnMoveOver( Mobile m )
{
if ( m is BaseCreature && !((BaseCreature)m).Controled )
return false;
return base.OnMoveOver( m );
}
public virtual void AddCustomContextEntries( Mobile from, ArrayList list )
{
if ( this is BaseBioCreature )
{
}
else if ( from.Alive && this.Alive && this.Controled == true && this.Summoned == false && FSATS.EnablePetLeveling == true )
{
bool nolevel = false;
Type typ = this.GetType();
string nam = typ.Name;
foreach ( string check in FSATS.NoLevelCreatures )
{
if ( check == nam )
nolevel = true;
}
if ( nolevel != true )
list.Add( new ContextMenus.PetMenu( from, this ) );
}
}
public override void GetContextMenuEntries( Mobile from, ArrayList list )
{
base.GetContextMenuEntries( from, list );
if ( m_AI != null && Commandable )
m_AI.GetContextMenuEntries( from, list );
if ( m_bTamable && !m_bControled && from.Alive )
list.Add( new TameEntry( from, this ) );
AddCustomContextEntries( from, list );
if ( CanTeach && from.Alive )
{
Skills ourSkills = this.Skills;
Skills theirSkills = from.Skills;
for ( int i = 0; i < ourSkills.Length && i < theirSkills.Length; ++i )
{
Skill skill = ourSkills[i];
Skill theirSkill = theirSkills[i];
if ( skill != null && theirSkill != null && skill.Base >= 60.0 && CheckTeach( skill.SkillName, from ) )
{
double toTeach = skill.Base / 3.0;
if ( toTeach > 42.0 )
toTeach = 42.0;
list.Add( new TeachEntry( (SkillName)i, this, from, ( toTeach > theirSkill.Base ) ) );
}
}
}
}
public override bool HandlesOnSpeech( Mobile from )
{
InhumanSpeech speechType = this.SpeechType;
if ( speechType != null && (speechType.Flags & IHSFlags.OnSpeech) != 0 && from.InRange( this, 3 ) )
return true;
return ( m_AI != null && m_AI.HandlesOnSpeech( from ) && from.InRange( this, m_iRangePerception ) );
}
public override void OnSpeech( SpeechEventArgs e )
{
InhumanSpeech speechType = this.SpeechType;
if ( speechType != null && speechType.OnSpeech( this, e.Mobile, e.Speech ) )
e.Handled = true;
else if ( !e.Handled && m_AI != null && e.Mobile.InRange( this, m_iRangePerception ) )
m_AI.OnSpeech( e );
}
public override bool IsHarmfulCriminal( Mobile target )
{
if ( (Controled && target == m_ControlMaster) || (Summoned && target == m_SummonMaster) )
return false;
if ( target is BaseCreature && ((BaseCreature)target).InitialInnocent && !((BaseCreature)target).Controled )
return false;
if ( target is PlayerMobile && ((PlayerMobile)target).PermaFlags.Count > 0 )
return false;
return base.IsHarmfulCriminal( target );
}
public override void CriminalAction( bool message )
{
base.CriminalAction( message );
if ( (Controled || Summoned) )
{
if ( m_ControlMaster != null && m_ControlMaster.Player )
m_ControlMaster.CriminalAction( false );
else if ( m_SummonMaster != null && m_SummonMaster.Player )
m_SummonMaster.CriminalAction( false );
}
}
public override void DoHarmful( Mobile target, bool indirect )
{
base.DoHarmful( target, indirect );
if ( target == this || target == m_ControlMaster || target == m_SummonMaster || (!Controled && !Summoned) )
return;
ArrayList list = this.Aggressors;
for ( int i = 0; i < list.Count; ++i )
{
AggressorInfo ai = (AggressorInfo)list[i];
if ( ai.Attacker == target )
return;
}
list = this.Aggressed;
for ( int i = 0; i < list.Count; ++i )
{
AggressorInfo ai = (AggressorInfo)list[i];
if ( ai.Defender == target )
{
if ( m_ControlMaster != null && m_ControlMaster.Player && m_ControlMaster.CanBeHarmful( target, false ) )
m_ControlMaster.DoHarmful( target, true );
else if ( m_SummonMaster != null && m_SummonMaster.Player && m_SummonMaster.CanBeHarmful( target, false ) )
m_SummonMaster.DoHarmful( target, true );
return;
}
}
}
private static Mobile m_NoDupeGuards;
public void ReleaseGuardDupeLock()
{
m_NoDupeGuards = null;
}
public void ReleaseGuardLock()
{
EndAction( typeof( GuardedRegion ) );
}
private DateTime m_IdleReleaseTime;
public virtual bool CheckIdle()
{
if ( Combatant != null )
return false; // in combat.. not idling
if ( m_IdleReleaseTime > DateTime.MinValue )
{
// idling...
if ( DateTime.Now >= m_IdleReleaseTime )
{
m_IdleReleaseTime = DateTime.MinValue;
return false; // idle is over
}
return true; // still idling
}
if ( 95 > Utility.Random( 100 ) )
return false; // not idling, but don't want to enter idle state
m_IdleReleaseTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 15, 25 ) );
if ( Body.IsHuman )
{
switch ( Utility.Random( 2 ) )
{
case 0: Animate( 5, 5, 1, true, true, 1 ); break;
case 1: Animate( 6, 5, 1, true, false, 1 ); break;
}
}
else if ( Body.IsAnimal )
{
switch ( Utility.Random( 3 ) )
{
case 0: Animate( 3, 3, 1, true, false, 1 ); break;
case 1: Animate( 9, 5, 1, true, false, 1 ); break;
case 2: Animate( 10, 5, 1, true, false, 1 ); break;
}
}
else if ( Body.IsMonster )
{
switch ( Utility.Random( 2 ) )
{
case 0: Animate( 17, 5, 1, true, false, 1 ); break;
case 1: Animate( 18, 5, 1, true, false, 1 ); break;
}
}
PlaySound( GetIdleSound() );
return true; // entered idle state
}
public override void OnMovement( Mobile m, Point3D oldLocation )
{
base.OnMovement( m, oldLocation );
if ( ReaquireOnMovement || m_Paragon )
ForceReaquire();
InhumanSpeech speechType = this.SpeechType;
if ( speechType != null )
speechType.OnMovement( this, m, oldLocation );
/* Begin notice sound */
if ( (!m.Hidden || m.AccessLevel == AccessLevel.Player) && m.Player && m_FightMode != FightMode.Agressor && m_FightMode != FightMode.None && Combatant == null && !Controled && !Summoned )
{
// If this creature defends itself but doesn't actively attack (animal) or
// doesn't fight at all (vendor) then no notice sounds are played..
// So, players are only notified of agressive monsters
// Monsters that are currently fighting are ignored
// Controled or summoned creatures are ignored
if ( InRange( m.Location, 18 ) && !InRange( oldLocation, 18 ) )
{
if ( Body.IsMonster )
Animate( 11, 5, 1, true, false, 1 );
PlaySound( GetAngerSound() );
}
}
/* End notice sound */
if ( m_NoDupeGuards == m )
return;
if ( !Body.IsHuman || Kills >= 5 || AlwaysMurderer || AlwaysAttackable || m.Kills < 5 || !m.InRange( Location, 12 ) || !m.Alive )
return;
Region reg = this.Region;
if ( reg is GuardedRegion )
{
GuardedRegion guardedRegion = (GuardedRegion)reg;
if ( !guardedRegion.IsDisabled() && guardedRegion.IsGuardCandidate( m ) && BeginAction( typeof( GuardedRegion ) ) )
{
Say( 1013037 + Utility.Random( 16 ) );
guardedRegion.CallGuards( this.Location );
Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerCallback( ReleaseGuardLock ) );
m_NoDupeGuards = m;
Timer.DelayCall( TimeSpan.Zero, new TimerCallback( ReleaseGuardDupeLock ) );
}
}
}
public void AddSpellAttack( Type type )
{
m_arSpellAttack.Add ( type );
}
public void AddSpellDefense( Type type )
{
m_arSpellDefense.Add ( type );
}
public Spell GetAttackSpellRandom()
{
if ( m_arSpellAttack.Count > 0 )
{
Type type = (Type) m_arSpellAttack[Utility.Random(m_arSpellAttack.Count)];
object[] args = {this, null};
return Activator.CreateInstance( type, args ) as Spell;
}
else
{
return null;
}
}
public Spell GetDefenseSpellRandom()
{
if ( m_arSpellDefense.Count > 0 )
{
Type type = (Type) m_arSpellDefense[Utility.Random(m_arSpellDefense.Count)];
object[] args = {this, null};
return Activator.CreateInstance( type, args ) as Spell;
}
else
{
return null;
}
}
public Spell GetSpellSpecific( Type type )
{
int i;
for ( i=0; i< m_arSpellAttack.Count; i++ )
{
if ( m_arSpellAttack[i] == type )
{
object[] args = {this, null};
return Activator.CreateInstance( type, args ) as Spell;
}
}
for ( i=0; i< m_arSpellDefense.Count; i++ )
{
if ( m_arSpellDefense[i] == type )
{
object[] args = {this, null};
return Activator.CreateInstance( type, args ) as Spell;
}
}
return null;
}
public void SetDamage( int val )
{
m_DamageMin = val;
m_DamageMax = val;
}
public void SetDamage( int min, int max )
{
m_DamageMin = min;
m_DamageMax = max;
}
public void SetHits( int val )
{
if ( val < 1000 && !Core.AOS )
val = (val * 100) / 60;
m_HitsMax = val;
Hits = HitsMax;
}
public void SetHits( int min, int max )
{
if ( min < 1000 && !Core.AOS )
{
min = (min * 100) / 60;
max = (max * 100) / 60;
}
m_HitsMax = Utility.RandomMinMax( min, max );
Hits = HitsMax;
}
public void SetStam( int val )
{
m_StamMax = val;
Stam = StamMax;
}
public void SetStam( int min, int max )
{
m_StamMax = Utility.RandomMinMax( min, max );
Stam = StamMax;
}
public void SetMana( int val )
{
m_ManaMax = val;
Mana = ManaMax;
}
public void SetMana( int min, int max )
{
m_ManaMax = Utility.RandomMinMax( min, max );
Mana = ManaMax;
}
public void SetStr( int val )
{
RawStr = val;
Hits = HitsMax;
}
public void SetStr( int min, int max )
{
RawStr = Utility.RandomMinMax( min, max );
Hits = HitsMax;
}
public void SetDex( int val )
{
RawDex = val;
Stam = StamMax;
}
public void SetDex( int min, int max )
{
RawDex = Utility.RandomMinMax( min, max );
Stam = StamMax;
}
public void SetInt( int val )
{
RawInt = val;
Mana = ManaMax;
}
public void SetInt( int min, int max )
{
RawInt = Utility.RandomMinMax( min, max );
Mana = ManaMax;
}
public void SetDamageType( ResistanceType type, int min, int max )
{
SetDamageType( type, Utility.RandomMinMax( min, max ) );
}
public void SetDamageType( ResistanceType type, int val )
{
switch ( type )
{
case ResistanceType.Physical: m_PhysicalDamage = val; break;
case ResistanceType.Fire: m_FireDamage = val; break;
case ResistanceType.Cold: m_ColdDamage = val; break;
case ResistanceType.Poison: m_PoisonDamage = val; break;
case ResistanceType.Energy: m_EnergyDamage = val; break;
}
}
public void SetResistance( ResistanceType type, int min, int max )
{
SetResistance( type, Utility.RandomMinMax( min, max ) );
}
public void SetResistance( ResistanceType type, int val )
{
switch ( type )
{
case ResistanceType.Physical: m_PhysicalResistance = val; break;
case ResistanceType.Fire: m_FireResistance = val; break;
case ResistanceType.Cold: m_ColdResistance = val; break;
case ResistanceType.Poison: m_PoisonResistance = val; break;
case ResistanceType.Energy: m_EnergyResistance = val; break;
}
UpdateResistances();
}
public void SetSkill( SkillName name, double val )
{
Skills[name].BaseFixedPoint = (int)(val * 10);
}
public void SetSkill( SkillName name, double min, double max )
{
int minFixed = (int)(min * 10);
int maxFixed = (int)(max * 10);
Skills[name].BaseFixedPoint = Utility.RandomMinMax( minFixed, maxFixed );
}
public void SetFameLevel( int level )
{
switch ( level )
{
case 1: Fame = Utility.RandomMinMax( 0, 1249 ); break;
case 2: Fame = Utility.RandomMinMax( 1250, 2499 ); break;
case 3: Fame = Utility.RandomMinMax( 2500, 4999 ); break;
case 4: Fame = Utility.RandomMinMax( 5000, 9999 ); break;
case 5: Fame = Utility.RandomMinMax( 10000, 10000 ); break;
}
}
public void SetKarmaLevel( int level )
{
switch ( level )
{
case 0: Karma = -Utility.RandomMinMax( 0, 624 ); break;
case 1: Karma = -Utility.RandomMinMax( 625, 1249 ); break;
case 2: Karma = -Utility.RandomMinMax( 1250, 2499 ); break;
case 3: Karma = -Utility.RandomMinMax( 2500, 4999 ); break;
case 4: Karma = -Utility.RandomMinMax( 5000, 9999 ); break;
case 5: Karma = -Utility.RandomMinMax( 10000, 10000 ); break;
}
}
public static void Cap( ref int val, int min, int max )
{
if ( val < min )
val = min;
else if ( val > max )
val = max;
}
public void PackPotion()
{
PackItem( Loot.RandomPotion() );
}
public void PackNecroScroll( int index )
{
if ( !Core.AOS || 0.05 <= Utility.RandomDouble() )
return;
PackItem( Loot.Construct( Loot.NecromancyScrollTypes, index ) );
}
public void PackScroll( int minCircle, int maxCircle )
{
PackScroll( Utility.RandomMinMax( minCircle, maxCircle ) );
}
public void PackScroll( int circle )
{
int min = (circle - 1) * 8;
PackItem( Loot.RandomScroll( min, min + 7, SpellbookType.Regular ) );
}
public void PackMagicItems( int minLevel, int maxLevel )
{
PackMagicItems( minLevel, maxLevel, 0.30, 0.15 );
}
public void PackMagicItems( int minLevel, int maxLevel, double armorChance, double weaponChance )
{
if ( !PackArmor( minLevel, maxLevel, armorChance ) )
PackWeapon( minLevel, maxLevel, weaponChance );
}
protected bool m_Spawning;
protected int m_KillersLuck;
public virtual void GenerateLoot( bool spawning )
{
m_Spawning = spawning;
if ( !spawning )
m_KillersLuck = LootPack.GetLuckChanceForKiller( this );
GenerateLoot();
m_Spawning = false;
m_KillersLuck = 0;
}
public virtual void GenerateLoot()
{
}
public virtual void AddLoot( LootPack pack, int amount )
{
for ( int i = 0; i < amount; ++i )
AddLoot( pack );
}
public virtual void AddLoot( LootPack pack )
{
if ( Summoned )
return;
Container backpack = Backpack;
if ( backpack == null )
{
backpack = new Backpack();
backpack.Movable = false;
AddItem( backpack );
}
pack.Generate( this, backpack, m_Spawning, m_KillersLuck );
}
public bool PackArmor( int minLevel, int maxLevel )
{
return PackArmor( minLevel, maxLevel, 1.0 );
}
public bool PackArmor( int minLevel, int maxLevel, double chance )
{
if ( chance <= Utility.RandomDouble() )
return false;
Cap( ref minLevel, 0, 5 );
Cap( ref maxLevel, 0, 5 );
if ( Core.AOS )
{
Item item = Loot.RandomArmorOrShieldOrJewelry();
if ( item == null )
return false;
int attributeCount, min, max;
GetRandomAOSStats( minLevel, maxLevel, out attributeCount, out min, out max );
if ( item is BaseArmor )
BaseRunicTool.ApplyAttributesTo( (BaseArmor)item, attributeCount, min, max );
else if ( item is BaseJewel )
BaseRunicTool.ApplyAttributesTo( (BaseJewel)item, attributeCount, min, max );
PackItem( item );
}
else
{
BaseArmor armor = Loot.RandomArmorOrShield();
if ( armor == null )
return false;
armor.ProtectionLevel = (ArmorProtectionLevel)RandomMinMaxScaled( minLevel, maxLevel );
armor.Durability = (ArmorDurabilityLevel)RandomMinMaxScaled( minLevel, maxLevel );
PackItem( armor );
}
return true;
}
public static void GetRandomAOSStats( int minLevel, int maxLevel, out int attributeCount, out int min, out int max )
{
int v = RandomMinMaxScaled( minLevel, maxLevel );
if ( v >= 5 )
{
attributeCount = Utility.RandomMinMax( 2, 6 );
min = 20; max = 70;
}
else if ( v == 4 )
{
attributeCount = Utility.RandomMinMax( 2, 4 );
min = 20; max = 50;
}
else if ( v == 3 )
{
attributeCount = Utility.RandomMinMax( 2, 3 );
min = 20; max = 40;
}
else if ( v == 2 )
{
attributeCount = Utility.RandomMinMax( 1, 2 );
min = 10; max = 30;
}
else
{
attributeCount = 1;
min = 10; max = 20;
}
}
public static int RandomMinMaxScaled( int min, int max )
{
if ( min == max )
return min;
if ( min > max )
{
int hold = min;
min = max;
max = hold;
}
/* Example:
* min: 1
* max: 5
* count: 5
*
* total = (5*5) + (4*4) + (3*3) + (2*2) + (1*1) = 25 + 16 + 9 + 4 + 1 = 55
*
* chance for min+0 : 25/55 : 45.45%
* chance for min+1 : 16/55 : 29.09%
* chance for min+2 : 9/55 : 16.36%
* chance for min+3 : 4/55 : 7.27%
* chance for min+4 : 1/55 : 1.81%
*/
int count = max - min + 1;
int total = 0, toAdd = count;
for ( int i = 0; i < count; ++i, --toAdd )
total += toAdd*toAdd;
int rand = Utility.Random( total );
toAdd = count;
int val = min;
for ( int i = 0; i < count; ++i, --toAdd, ++val )
{
rand -= toAdd*toAdd;
if ( rand < 0 )
break;
}
return val;
}
public bool PackSlayer()
{
return PackSlayer( 0.05 );
}
public bool PackSlayer( double chance )
{
if ( chance <= Utility.RandomDouble() )
return false;
if ( Utility.RandomBool() )
{
BaseInstrument instrument = Loot.RandomInstrument();
if ( instrument != null )
{
instrument.Slayer = SlayerGroup.GetLootSlayerType( GetType() );
PackItem( instrument );
}
}
else if ( !Core.AOS )
{
BaseWeapon weapon = Loot.RandomWeapon();
if ( weapon != null )
{
weapon.Slayer = SlayerGroup.GetLootSlayerType( GetType() );
PackItem( weapon );
}
}
return true;
}
public bool PackWeapon( int minLevel, int maxLevel )
{
return PackWeapon( minLevel, maxLevel, 1.0 );
}
public bool PackWeapon( int minLevel, int maxLevel, double chance )
{
if ( chance <= Utility.RandomDouble() )
return false;
Cap( ref minLevel, 0, 5 );
Cap( ref maxLevel, 0, 5 );
if ( Core.AOS )
{
Item item = Loot.RandomWeaponOrJewelry();
if ( item == null )
return false;
int attributeCount, min, max;
GetRandomAOSStats( minLevel, maxLevel, out attributeCount, out min, out max );
if ( item is BaseWeapon )
BaseRunicTool.ApplyAttributesTo( (BaseWeapon)item, attributeCount, min, max );
else if ( item is BaseJewel )
BaseRunicTool.ApplyAttributesTo( (BaseJewel)item, attributeCount, min, max );
PackItem( item );
}
else
{
BaseWeapon weapon = Loot.RandomWeapon();
if ( weapon == null )
return false;
if ( 0.05 > Utility.RandomDouble() )
weapon.Slayer = SlayerName.Silver;
weapon.DamageLevel = (WeaponDamageLevel)RandomMinMaxScaled( minLevel, maxLevel );
weapon.AccuracyLevel = (WeaponAccuracyLevel)RandomMinMaxScaled( minLevel, maxLevel );
weapon.DurabilityLevel = (WeaponDurabilityLevel)RandomMinMaxScaled( minLevel, maxLevel );
PackItem( weapon );
}
return true;
}
public void PackGold( int amount )
{
if ( amount > 0 )
PackItem( new Gold( amount ) );
}
public void PackGold( int min, int max )
{
PackGold( Utility.RandomMinMax( min, max ) );
}
public void PackStatue( int min, int max )
{
PackStatue( Utility.RandomMinMax( min, max ) );
}
public void PackStatue( int amount )
{
for ( int i = 0; i < amount; ++i )
PackStatue();
}
public void PackStatue()
{
PackItem( Loot.RandomStatue() );
}
public void PackGem()
{
PackGem( 1 );
}
public void PackGem( int min, int max )
{
PackGem( Utility.RandomMinMax( min, max ) );
}
public void PackGem( int amount )
{
if ( amount <= 0 )
return;
Item gem = Loot.RandomGem();
gem.Amount = amount;
PackItem( gem );
}
public void PackNecroReg( int min, int max )
{
PackNecroReg( Utility.RandomMinMax( min, max ) );
}
public void PackNecroReg( int amount )
{
for ( int i = 0; i < amount; ++i )
PackNecroReg();
}
public void PackNecroReg()
{
if ( !Core.AOS )
return;
PackItem( Loot.RandomNecromancyReagent() );
}
public void PackReg( int min, int max )
{
PackReg( Utility.RandomMinMax( min, max ) );
}
public void PackReg( int amount )
{
if ( amount <= 0 )
return;
Item reg = Loot.RandomReagent();
reg.Amount = amount;
PackItem( reg );
}
public void PackItem( Item item )
{
if ( Summoned || item == null )
{
if ( item != null )
item.Delete();
return;
}
Container pack = Backpack;
if ( pack == null )
{
pack = new Backpack();
pack.Movable = false;
AddItem( pack );
}
if ( !item.Stackable || !pack.TryDropItem( this, item, false ) ) // try stack
pack.DropItem( item ); // failed, drop it anyway
}
public override void OnDoubleClick( Mobile from )
{
if ( from.AccessLevel >= AccessLevel.GameMaster && !Body.IsHuman )
{
Container pack = this.Backpack;
if ( pack != null )
pack.DisplayTo( from );
}
if ( this.DeathAdderCharmable && from.CanBeHarmful( this, false ) )
{
DeathAdder da = Spells.Necromancy.SummonFamiliarSpell.Table[from] as DeathAdder;
if ( da != null && !da.Deleted )
{
from.SendAsciiMessage( "You charm the snake. Select a target to attack." );
from.Target = new DeathAdderCharmTarget( this );
}
}
base.OnDoubleClick( from );
}
private class DeathAdderCharmTarget : Target
{
private BaseCreature m_Charmed;
public DeathAdderCharmTarget( BaseCreature charmed ) : base( -1, false, TargetFlags.Harmful )
{
m_Charmed = charmed;
}
protected override void OnTarget( Mobile from, object targeted )
{
if ( !m_Charmed.DeathAdderCharmable || m_Charmed.Combatant != null || !from.CanBeHarmful( m_Charmed, false ) )
return;
DeathAdder da = Spells.Necromancy.SummonFamiliarSpell.Table[from] as DeathAdder;
if ( da == null || da.Deleted )
return;
Mobile targ = targeted as Mobile;
if ( targ == null || !from.CanBeHarmful( targ, false ) )
return;
from.RevealingAction();
from.DoHarmful( targ, true );
m_Charmed.Combatant = targ;
if ( m_Charmed.AIObject != null )
m_Charmed.AIObject.Action = ActionType.Combat;
}
}
public override void AddNameProperties( ObjectPropertyList list )
{
base.AddNameProperties( list );
if ( this.Tamable == true && FSATS.EnablePetBreeding == true )
{
bool nolevel = false;
Type typ = this.GetType();
string nam = typ.Name;
foreach ( string check in FSATS.NoLevelCreatures )
{
if ( check == nam )
nolevel = true;
}
if ( nolevel != true )
{
if ( this.Female == true )
list.Add( 1060658, "Gender\tFemale" );
else
list.Add( 1060658, "Gender\tMale" );
}
}
if ( Controled && Commandable )
{
if ( Summoned )
list.Add( 1049646 ); // (summoned)
else if ( IsBonded )
list.Add( 1049608 ); // (bonded)
else
list.Add( 502006 ); // (tame)
}
}
public override void OnSingleClick( Mobile from )
{
if ( Controled && Commandable )
{
int number;
if ( Summoned )
number = 1049646; // (summoned)
else if ( IsBonded )
number = 1049608; // (bonded)
else
number = 502006; // (tame)
PrivateOverheadMessage( MessageType.Regular, 0x3B2, number, from.NetState );
}
base.OnSingleClick( from );
}
public virtual int TreasureMapLevel{ get{ return -1; } }
public virtual void OnBeforeTame()
{
}
public virtual void OnBeforeReTame()
{
}
public override bool OnBeforeDeath()
{
int treasureLevel = TreasureMapLevel;
if ( this is BaseBioCreature )
{
DoBioDeath();
}
else
{
if ( FSATS.EnablePetLeveling == true )
DoDeathCheck();
}
if ( treasureLevel == 1 && this.Map == Map.Trammel && TreasureMap.IsInHavenIsland( this ) )
{
Mobile killer = this.LastKiller;
if ( killer is BaseCreature )
killer = ((BaseCreature)killer).GetMaster();
if ( killer is PlayerMobile && ((PlayerMobile)killer).Young )
treasureLevel = 0;
}
if ( !Summoned && !NoKillAwards && !IsBonded && treasureLevel >= 0 )
{
if ( m_Paragon && Paragon.ChestChance > Utility.RandomDouble() )
PackItem( new ParagonChest( this.Name, treasureLevel ) );
else if ( (Map == Map.Felucca || Map == Map.Trammel) && TreasureMap.LootChance >= Utility.RandomDouble() )
PackItem( new TreasureMap( treasureLevel, Map ) );
}
if ( !Summoned && !NoKillAwards && !m_HasGeneratedLoot )
{
m_HasGeneratedLoot = true;
GenerateLoot( false );
}
if ( !NoKillAwards && Region.Name == "Doom" )
{
int bones = Engines.Quests.Doom.TheSummoningQuest.GetDaemonBonesFor( this );
if ( bones > 0 )
PackItem( new DaemonBone( bones ) );
}
if ( IsAnimatedDead )
Effects.SendLocationEffect( Location, Map, 0x3728, 13, 1, 0x461, 4 );
InhumanSpeech speechType = this.SpeechType;
if ( speechType != null )
speechType.OnDeath( this );
return base.OnBeforeDeath();
}
private bool m_NoKillAwards;
public bool NoKillAwards
{
get{ return m_NoKillAwards; }
set{ m_NoKillAwards = value; }
}
public int ComputeBonusDamage( ArrayList list, Mobile m )
{
int bonus = 0;
for ( int i = list.Count - 1; i >= 0; --i )
{
DamageEntry de = (DamageEntry)list[i];
if ( de.Damager == m || !(de.Damager is BaseCreature) )
continue;
BaseCreature bc = (BaseCreature)de.Damager;
Mobile master = null;
master = bc.GetMaster();
if ( master == m )
bonus += de.DamageGiven;
}
return bonus;
}
public Mobile GetMaster()
{
if ( Controled && ControlMaster != null )
return ControlMaster;
else if ( Summoned && SummonMaster != null )
return SummonMaster;
return null;
}
private class FKEntry
{
public Mobile m_Mobile;
public int m_Damage;
public FKEntry( Mobile m, int damage )
{
m_Mobile = m;
m_Damage = damage;
}
}
public static ArrayList GetLootingRights( ArrayList damageEntries, int hitsMax )
{
ArrayList rights = new ArrayList();
for ( int i = damageEntries.Count - 1; i >= 0; --i )
{
if ( i >= damageEntries.Count )
continue;
DamageEntry de = (DamageEntry)damageEntries[i];
if ( de.HasExpired )
{
damageEntries.RemoveAt( i );
continue;
}
int damage = de.DamageGiven;
ArrayList respList = de.Responsible;
if ( respList != null )
{
for ( int j = 0; j < respList.Count; ++j )
{
DamageEntry subEntry = (DamageEntry)respList[j];
Mobile master = subEntry.Damager;
if ( master == null || master.Deleted || !master.Player )
continue;
bool needNewSubEntry = true;
for ( int k = 0; needNewSubEntry && k < rights.Count; ++k )
{
DamageStore ds = (DamageStore)rights[k];
if ( ds.m_Mobile == master )
{
ds.m_Damage += subEntry.DamageGiven;
needNewSubEntry = false;
}
}
if ( needNewSubEntry )
rights.Add( new DamageStore( master, subEntry.DamageGiven ) );
damage -= subEntry.DamageGiven;
}
}
Mobile m = de.Damager;
if ( m == null || m.Deleted || !m.Player )
continue;
if ( damage <= 0 )
continue;
bool needNewEntry = true;
for ( int j = 0; needNewEntry && j < rights.Count; ++j )
{
DamageStore ds = (DamageStore)rights[j];
if ( ds.m_Mobile == m )
{
ds.m_Damage += damage;
needNewEntry = false;
}
}
if ( needNewEntry )
rights.Add( new DamageStore( m, damage ) );
}
if ( rights.Count > 0 )
{
if ( rights.Count > 1 )
rights.Sort();
int topDamage = ((DamageStore)rights[0]).m_Damage;
int minDamage;
if ( hitsMax >= 3000 )
minDamage = topDamage / 16;
else if ( hitsMax >= 1000 )
minDamage = topDamage / 8;
else if ( hitsMax >= 200 )
minDamage = topDamage / 4;
else
minDamage = topDamage / 2;
for ( int i = 0; i < rights.Count; ++i )
{
DamageStore ds = (DamageStore)rights[i];
ds.m_HasRight = ( ds.m_Damage >= minDamage );
}
}
return rights;
}
public override void OnDeath( Container c )
{
MeerMage.StopEffect( this, false );
if ( IsBonded )
{
int sound = this.GetDeathSound();
if ( sound >= 0 )
Effects.PlaySound( this, this.Map, sound );
Warmode = false;
Poison = null;
Combatant = null;
Hits = 0;
Stam = 0;
Mana = 0;
IsDeadPet = true;
ControlTarget = ControlMaster;
ControlOrder = OrderType.Follow;
ProcessDeltaQueue();
SendIncomingPacket();
SendIncomingPacket();
ArrayList aggressors = this.Aggressors;
for ( int i = 0; i < aggressors.Count; ++i )
{
AggressorInfo info = (AggressorInfo)aggressors[i];
if ( info.Attacker.Combatant == this )
info.Attacker.Combatant = null;
}
ArrayList aggressed = this.Aggressed;
for ( int i = 0; i < aggressed.Count; ++i )
{
AggressorInfo info = (AggressorInfo)aggressed[i];
if ( info.Defender.Combatant == this )
info.Defender.Combatant = null;
}
Mobile owner = this.ControlMaster;
if ( owner == null || owner.Deleted || owner.Map != this.Map || !owner.InRange( this, 12 ) || !this.CanSee( owner ) || !this.InLOS( owner ) )
{
if ( this.OwnerAbandonTime == DateTime.MinValue )
this.OwnerAbandonTime = DateTime.Now;
}
else
{
this.OwnerAbandonTime = DateTime.MinValue;
}
CheckStatTimers();
}
else
{
if ( !Summoned && !m_NoKillAwards )
{
int totalFame = Fame / 100;
int totalKarma = -Karma / 100;
ArrayList list = GetLootingRights( this.DamageEntries, this.HitsMax );
bool givenQuestKill = false;
bool givenFactionKill = false;
for ( int i = 0; i < list.Count; ++i )
{
DamageStore ds = (DamageStore)list[i];
if ( !ds.m_HasRight )
continue;
Titles.AwardFame( ds.m_Mobile, totalFame, true );
Titles.AwardKarma( ds.m_Mobile, totalKarma, true );
if ( m_Paragon )
if ( Paragon.CheckArtifactChance( ds.m_Mobile, this ) )
Paragon.GiveArtifactTo( ds.m_Mobile );
if ( !givenFactionKill )
{
givenFactionKill = true;
Faction.HandleDeath( this, ds.m_Mobile );
}
if ( givenQuestKill )
continue;
PlayerMobile pm = ds.m_Mobile as PlayerMobile;
if ( pm != null )
{
QuestSystem qs = pm.Quest;
if ( qs != null )
{
qs.OnKill( this, c );
givenQuestKill = true;
}
}
}
}
base.OnDeath( c );
if ( DeleteCorpseOnDeath )
c.Delete();
}
}
/* To save on cpu usage, RunUO creatures only reaquire creatures under the following circumstances:
* - 10 seconds have elapsed since the last time it tried
* - The creature was attacked
* - Some creatures, like dragons, will reaquire when they see someone move
*
* This functionality appears to be implemented on OSI as well
*/
private DateTime m_NextReaquireTime;
public DateTime NextReaquireTime{ get{ return m_NextReaquireTime; } set{ m_NextReaquireTime = value; } }
public virtual TimeSpan ReaquireDelay{ get{ return TimeSpan.FromSeconds( 10.0 ); } }
public virtual bool ReaquireOnMovement{ get{ return false; } }
public void ForceReaquire()
{
m_NextReaquireTime = DateTime.MinValue;
}
public override void OnDelete()
{
SetControlMaster( null );
SummonMaster = null;
base.OnDelete();
}
public override bool CanBeHarmful( Mobile target, bool message, bool ignoreOurBlessedness )
{
if ( target is BaseFactionGuard )
return false;
if ( (target is BaseVendor && ((BaseVendor)target).IsInvulnerable) || target is PlayerVendor || target is TownCrier )
{
if ( message )
{
if ( target.Title == null )
SendMessage( "{0} the vendor cannot be harmed.", target.Name );
else
SendMessage( "{0} {1} cannot be harmed.", target.Name, target.Title );
}
return false;
}
return base.CanBeHarmful( target, message, ignoreOurBlessedness );
}
public override bool CanBeRenamedBy( Mobile from )
{
bool ret = base.CanBeRenamedBy( from );
if ( Controled && from == ControlMaster )
ret = true;
return ret;
}
public bool SetControlMaster( Mobile m )
{
if ( m == null )
{
ControlMaster = null;
Controled = false;
ControlTarget = null;
ControlOrder = OrderType.None;
Guild = null;
Delta( MobileDelta.Noto );
}
else
{
if ( m.Followers + ControlSlots > m.FollowersMax )
{
m.SendLocalizedMessage( 1049607 ); // You have too many followers to control that creature.
return false;
}
CurrentWayPoint = null;//so tamed animals don't try to go back
ControlMaster = m;
Controled = true;
ControlTarget = null;
ControlOrder = OrderType.Come;
Guild = null;
Delta( MobileDelta.Noto );
}
return true;
}
private static bool m_Summoning;
public static bool Summoning
{
get{ return m_Summoning; }
set{ m_Summoning = value; }
}
public static bool Summon( BaseCreature creature, Mobile caster, Point3D p, int sound, TimeSpan duration )
{
return Summon( creature, true, caster, p, sound, duration );
}
public static bool Summon( BaseCreature creature, bool controled, Mobile caster, Point3D p, int sound, TimeSpan duration )
{
if ( caster.Followers + creature.ControlSlots > caster.FollowersMax )
{
caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
creature.Delete();
return false;
}
m_Summoning = true;
if ( controled )
creature.SetControlMaster( caster );
creature.RangeHome = 10;
creature.Summoned = true;
creature.SummonMaster = caster;
Container pack = creature.Backpack;
if ( pack != null )
{
for ( int i = pack.Items.Count - 1; i >= 0; --i )
{
if ( i >= pack.Items.Count )
continue;
((Item)pack.Items[i]).Delete();
}
}
new UnsummonTimer( caster, creature, duration ).Start();
creature.m_SummonEnd = DateTime.Now + duration;
creature.MoveToWorld( p, caster.Map );
Effects.PlaySound( p, creature.Map, sound );
m_Summoning = false;
return true;
}
private static bool EnableRummaging = true;
private const double ChanceToRummage = 0.5; // 50%
private const double MinutesToNextRummageMin = 1.0;
private const double MinutesToNextRummageMax = 4.0;
private const double MinutesToNextChanceMin = 0.25;
private const double MinutesToNextChanceMax = 0.75;
private DateTime m_NextRummageTime;
public virtual void OnThink()
{
if ( this.Tamable == true )
{
if ( this.NextLevel == 0 )
{
int totalstats = this.Str + this.Dex + this.Int + this.HitsMax + this.StamMax + this.ManaMax + this.PhysicalResistance + this.FireResistance + this.ColdResistance + this.EnergyResistance + this.PoisonResistance + this.DamageMin + this.DamageMax + this.VirtualArmor;
int nextlevel = totalstats * 10;
this.NextLevel = nextlevel;
}
if ( this.MaxLevel == 0 )
{
this.MaxLevel = Utility.RandomMinMax( 10, 30 );
}
}
if ( EnableRummaging && CanRummageCorpses && !Summoned && !Controled && DateTime.Now >= m_NextRummageTime )
{
double min, max;
if ( ChanceToRummage > Utility.RandomDouble() && Rummage() )
{
min = MinutesToNextRummageMin;
max = MinutesToNextRummageMax;
}
else
{
min = MinutesToNextChanceMin;
max = MinutesToNextChanceMax;
}
double delay = min + (Utility.RandomDouble() * (max - min));
m_NextRummageTime = DateTime.Now + TimeSpan.FromMinutes( delay );
}
if ( HasBreath && !Summoned && DateTime.Now >= m_NextBreathTime ) // tested: controled dragons do breath fire, what about summoned skeletal dragons?
{
Mobile target = this.Combatant;
if ( target != null && target.Alive && !target.IsDeadBondedPet && CanBeHarmful( target ) && target.Map == this.Map && !IsDeadBondedPet && target.InRange( this, BreathRange ) && InLOS( target ) && !BardPacified )
BreathStart( target );
m_NextBreathTime = DateTime.Now + TimeSpan.FromSeconds( BreathMinDelay + (Utility.RandomDouble() * BreathMaxDelay) );
}
}
public virtual bool Rummage()
{
Corpse toRummage = null;
foreach ( Item item in this.GetItemsInRange( 2 ) )
{
if ( item is Corpse && item.Items.Count > 0 )
{
toRummage = (Corpse)item;
break;
}
}
if ( toRummage == null )
return false;
Container pack = this.Backpack;
if ( pack == null )
return false;
ArrayList items = toRummage.Items;
bool rejected;
LRReason reason;
for ( int i = 0; i < items.Count; ++i )
{
Item item = (Item)items[Utility.Random( items.Count )];
Lift( item, item.Amount, out rejected, out reason );
if ( !rejected && Drop( this, new Point3D( -1, -1, 0 ) ) )
{
// *rummages through a corpse and takes an item*
PublicOverheadMessage( MessageType.Emote, 0x3B2, 1008086 );
return true;
}
}
return false;
}
public void Pacify( Mobile master, DateTime endtime )
{
BardPacified = true;
BardEndTime = endtime;
}
public override Mobile GetDamageMaster( Mobile damagee )
{
if ( m_bBardProvoked && damagee == m_bBardTarget )
return m_bBardMaster;
else if ( m_bControled && m_ControlMaster != null )
return m_ControlMaster;
else if ( m_bSummoned && m_SummonMaster != null )
return m_SummonMaster;
return base.GetDamageMaster( damagee );
}
public void Provoke( Mobile master, Mobile target, bool bSuccess )
{
BardProvoked = true;
this.PublicOverheadMessage( MessageType.Emote, EmoteHue, false, "*looks furious*" );
if ( bSuccess )
{
PlaySound( GetIdleSound() );
BardMaster = master;
BardTarget = target;
Combatant = target;
BardEndTime = DateTime.Now + TimeSpan.FromSeconds( 30.0 );
if ( target is BaseCreature )
{
BaseCreature t = (BaseCreature)target;
t.BardProvoked = true;
t.BardMaster = master;
t.BardTarget = this;
t.Combatant = this;
t.BardEndTime = DateTime.Now + TimeSpan.FromSeconds( 30.0 );
}
}
else
{
PlaySound( GetAngerSound() );
BardMaster = master;
BardTarget = target;
}
}
public bool FindMyName( string str, bool bWithAll )
{
int i, j;
string name = this.Name;
if( name == null || str.Length < name.Length )
return false;
string[] wordsString = str.Split(' ');
string[] wordsName = name.Split(' ');
for ( j=0 ; j < wordsName.Length; j++ )
{
string wordName = wordsName[j];
bool bFound = false;
for ( i=0 ; i < wordsString.Length; i++ )
{
string word = wordsString[i];
if ( Insensitive.Equals( word, wordName ) )
bFound = true;
if ( bWithAll && Insensitive.Equals( word, "all" ) )
return true;
}
if ( !bFound )
return false;
}
return true;
}
public static void TeleportPets( Mobile master, Point3D loc, Map map )
{
TeleportPets( master, loc, map, false );
}
public static void TeleportPets( Mobile master, Point3D loc, Map map, bool onlyBonded )
{
ArrayList move = new ArrayList();
foreach ( Mobile m in master.GetMobilesInRange( 3 ) )
{
if ( m is BaseCreature )
{
BaseCreature pet = (BaseCreature)m;
if ( pet.Controled && pet.ControlMaster == master )
{
if ( !onlyBonded || pet.IsBonded )
{
if ( pet.ControlOrder == OrderType.Guard || pet.ControlOrder == OrderType.Follow || pet.ControlOrder == OrderType.Come )
move.Add( pet );
}
}
}
}
foreach ( Mobile m in move )
m.MoveToWorld( loc, map );
}
public virtual void ResurrectPet()
{
if ( !IsDeadPet )
return;
OnBeforeResurrect();
Poison = null;
Warmode = false;
Hits = 10;
Stam = StamMax;
Mana = 0;
ProcessDeltaQueue();
IsDeadPet = false;
Effects.SendPacket( Location, Map, new BondedStatus( 0, this.Serial, 0 ) );
this.SendIncomingPacket();
this.SendIncomingPacket();
OnAfterResurrect();
Mobile owner = this.ControlMaster;
if ( owner == null || owner.Deleted || owner.Map != this.Map || !owner.InRange( this, 12 ) || !this.CanSee( owner ) || !this.InLOS( owner ) )
{
if ( this.OwnerAbandonTime == DateTime.MinValue )
this.OwnerAbandonTime = DateTime.Now;
}
else
{
this.OwnerAbandonTime = DateTime.MinValue;
}
CheckStatTimers();
}
public override bool CanBeDamaged()
{
if ( IsDeadPet )
return false;
return base.CanBeDamaged();
}
public virtual bool PlayerRangeSensitive{ get{ return true; } }
public override void OnSectorDeactivate()
{
if ( PlayerRangeSensitive && m_AI != null )
m_AI.Deactivate();
base.OnSectorDeactivate();
}
public override void OnSectorActivate()
{
if ( PlayerRangeSensitive && m_AI != null )
m_AI.Activate();
base.OnSectorActivate();
}
// used for deleting creatures in houses
private int m_RemoveStep;
[CommandProperty( AccessLevel.GameMaster )]
public int RemoveStep { get { return m_RemoveStep; } set { m_RemoveStep = value; } }
}
public class LoyaltyTimer : Timer
{
private static TimeSpan InternalDelay = TimeSpan.FromMinutes( 5.0 );
public static void Initialize()
{
new LoyaltyTimer().Start();
}
public LoyaltyTimer() : base( InternalDelay, InternalDelay )
{
m_NextHourlyCheck = DateTime.Now + TimeSpan.FromHours( 1.0 );
Priority = TimerPriority.FiveSeconds;
}
private DateTime m_NextHourlyCheck;
protected override void OnTick()
{
bool hasHourElapsed = ( DateTime.Now >= m_NextHourlyCheck );
if ( hasHourElapsed )
m_NextHourlyCheck = DateTime.Now + TimeSpan.FromHours( 1.0 );
ArrayList toRelease = new ArrayList();
// added array for wild creatures in house regions to be removed
ArrayList toRemove = new ArrayList();
foreach ( Mobile m in World.Mobiles.Values )
{
if ( m is BaseMount && ((BaseMount)m).Rider != null )
{
((BaseCreature)m).OwnerAbandonTime = DateTime.MinValue;
continue;
}
if ( m is BaseCreature )
{
BaseCreature c = (BaseCreature)m;
if ( c.IsDeadPet )
{
Mobile owner = c.ControlMaster;
if ( owner == null || owner.Deleted || owner.Map != c.Map || !owner.InRange( c, 12 ) || !c.CanSee( owner ) || !c.InLOS( owner ) )
{
if ( c.OwnerAbandonTime == DateTime.MinValue )
c.OwnerAbandonTime = DateTime.Now;
else if ( (c.OwnerAbandonTime + c.BondingAbandonDelay) <= DateTime.Now )
toRemove.Add( c );
}
else
{
c.OwnerAbandonTime = DateTime.MinValue;
}
}
else if ( c.Controled && c.Commandable && c.Loyalty > PetLoyalty.None && c.Map != Map.Internal )
{
Mobile owner = c.ControlMaster;
// changed loyalty decrement
if ( hasHourElapsed )
{
--c.Loyalty;
if ( c.Loyalty == PetLoyalty.Confused )
{
c.Say( 1043270, c.Name ); // * ~1_NAME~ looks around desperately *
c.PlaySound( c.GetIdleSound() );
}
}
c.OwnerAbandonTime = DateTime.MinValue;
if ( c.Loyalty == PetLoyalty.None )
toRelease.Add( c );
}
// added lines to check if a wild creature in a house region has to be removed or not
if ( !c.Controled && c.Region is HouseRegion && c.CanBeDamaged() )
{
c.RemoveStep++;
if ( c.RemoveStep >= 20 )
toRemove.Add( c );
}
else
{
c.RemoveStep = 0;
}
}
}
foreach ( BaseCreature c in toRelease )
{
c.Say( 1043255, c.Name ); // ~1_NAME~ appears to have decided that is better off without a master!
c.Loyalty = PetLoyalty.WonderfullyHappy;
c.IsBonded = false;
c.BondingBegin = DateTime.MinValue;
c.OwnerAbandonTime = DateTime.MinValue;
c.ControlTarget = null;
//c.ControlOrder = OrderType.Release;
c.AIObject.DoOrderRelease(); // this will prevent no release of creatures left alone with AI disabled (and consequent bug of Followers)
}
// added code to handle removing of wild creatures in house regions
foreach ( BaseCreature c in toRemove )
{
c.Delete();
}
}
}
}