2173 lines
No EOL
56 KiB
C#
2173 lines
No EOL
56 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Server.Misc;
|
|
using Server.Items;
|
|
using Server.Gumps;
|
|
using Server.Multis;
|
|
using Server.Engines.Help;
|
|
using Server.ContextMenus;
|
|
using Server.Network;
|
|
using Server.Spells;
|
|
using Server.Spells.Fifth;
|
|
using Server.Spells.Seventh;
|
|
using Server.Targeting;
|
|
using Server.Regions;
|
|
using Server.Accounting;
|
|
using Server.Engines.Craft;
|
|
using Server.Engines.PartySystem;
|
|
|
|
namespace Server.Mobiles
|
|
{
|
|
#region Enums
|
|
[Flags]
|
|
public enum PlayerFlag // First 16 bits are reserved for default-distro use, start custom flags at 0x00010000
|
|
{
|
|
None = 0x00000001,
|
|
KarmaLocked = 0x00000002,
|
|
UseOwnFilter = 0x00000004,
|
|
PagingSquelched = 0x00000008,
|
|
AcceptGuildInvites = 0x00000010
|
|
}
|
|
|
|
public enum NpcGuild
|
|
{
|
|
None,
|
|
AssassinsGuild,
|
|
BardsGuild,
|
|
MagesGuild,
|
|
RangersGuild,
|
|
ThievesGuild,
|
|
WarriorsGuild,
|
|
AlchemistsGuild,
|
|
BlacksmithsGuild,
|
|
CarpentryGuild,
|
|
HealersGuild,
|
|
LibrariansGuild,
|
|
MarinersGuild,
|
|
TailorsGuild,
|
|
TinkersGuild
|
|
}
|
|
|
|
#endregion
|
|
|
|
public class PlayerMobile : Mobile
|
|
{
|
|
private class CountAndTimeStamp
|
|
{
|
|
private int m_Count;
|
|
private DateTime m_Stamp;
|
|
|
|
public CountAndTimeStamp()
|
|
{
|
|
}
|
|
|
|
public DateTime TimeStamp { get{ return m_Stamp; } }
|
|
public int Count
|
|
{
|
|
get { return m_Count; }
|
|
set { m_Count = value; m_Stamp = DateTime.Now; }
|
|
}
|
|
}
|
|
|
|
private DesignContext m_DesignContext;
|
|
|
|
private NpcGuild m_NpcGuild;
|
|
private DateTime m_NpcGuildJoinTime;
|
|
private TimeSpan m_NpcGuildGameTime;
|
|
private DateTime m_Camp;
|
|
private DateTime m_Bedroll;
|
|
private PlayerFlag m_Flags;
|
|
private int m_StepsTaken;
|
|
private int m_Profession;
|
|
private bool m_IsStealthing; // IsStealthing should be moved to Server.Mobiles
|
|
private bool m_IgnoreMobiles; // IgnoreMobiles should be moved to Server.Mobiles
|
|
/*
|
|
* a value of zero means, that the mobile is not executing the spell. Otherwise,
|
|
* the value should match the BaseMana required
|
|
*/
|
|
|
|
private DateTime m_LastOnline;
|
|
private Server.Guilds.RankDefinition m_GuildRank;
|
|
|
|
private int m_GuildMessageHue, m_AllianceMessageHue;
|
|
|
|
private List<Mobile> m_AllFollowers;
|
|
private List<Mobile> m_RecentlyReported;
|
|
|
|
private int m_QuestLevel;
|
|
private string m_MapMarkers;
|
|
|
|
#region Getters & Setters
|
|
|
|
public List<Mobile> RecentlyReported
|
|
{
|
|
get
|
|
{
|
|
return m_RecentlyReported;
|
|
}
|
|
set
|
|
{
|
|
m_RecentlyReported = value;
|
|
}
|
|
}
|
|
|
|
public List<Mobile> AllFollowers
|
|
{
|
|
get
|
|
{
|
|
if( m_AllFollowers == null )
|
|
m_AllFollowers = new List<Mobile>();
|
|
return m_AllFollowers;
|
|
}
|
|
}
|
|
|
|
public Server.Guilds.RankDefinition GuildRank
|
|
{
|
|
get
|
|
{
|
|
if( this.AccessLevel >= AccessLevel.GameMaster )
|
|
return Server.Guilds.RankDefinition.Leader;
|
|
else
|
|
return m_GuildRank;
|
|
}
|
|
set{ m_GuildRank = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int QuestLevel
|
|
{
|
|
get{ return m_QuestLevel; }
|
|
set{ m_QuestLevel = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public string MapMarkers
|
|
{
|
|
get{ return m_MapMarkers; }
|
|
set{ m_MapMarkers = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int GuildMessageHue
|
|
{
|
|
get{ return m_GuildMessageHue; }
|
|
set{ m_GuildMessageHue = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int AllianceMessageHue
|
|
{
|
|
get { return m_AllianceMessageHue; }
|
|
set { m_AllianceMessageHue = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int Profession
|
|
{
|
|
get{ return m_Profession; }
|
|
set{ m_Profession = value; }
|
|
}
|
|
|
|
public int StepsTaken
|
|
{
|
|
get{ return m_StepsTaken; }
|
|
set{ m_StepsTaken = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public bool IsStealthing // IsStealthing should be moved to Server.Mobiles
|
|
{
|
|
get { return m_IsStealthing; }
|
|
set { m_IsStealthing = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public bool IgnoreMobiles // IgnoreMobiles should be moved to Server.Mobiles
|
|
{
|
|
get
|
|
{
|
|
return m_IgnoreMobiles;
|
|
}
|
|
set
|
|
{
|
|
if( m_IgnoreMobiles != value )
|
|
{
|
|
m_IgnoreMobiles = value;
|
|
Delta( MobileDelta.Flags );
|
|
}
|
|
}
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public NpcGuild NpcGuild
|
|
{
|
|
get{ return m_NpcGuild; }
|
|
set{ m_NpcGuild = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public DateTime NpcGuildJoinTime
|
|
{
|
|
get{ return m_NpcGuildJoinTime; }
|
|
set{ m_NpcGuildJoinTime = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public DateTime LastOnline
|
|
{
|
|
get{ return m_LastOnline; }
|
|
set{ m_LastOnline = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public TimeSpan NpcGuildGameTime
|
|
{
|
|
get{ return m_NpcGuildGameTime; }
|
|
set{ m_NpcGuildGameTime = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public DateTime Camp
|
|
{
|
|
get{ return m_Camp; }
|
|
set{ m_Camp = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public DateTime Bedroll
|
|
{
|
|
get{ return m_Bedroll; }
|
|
set{ m_Bedroll = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PlayerFlags
|
|
public PlayerFlag Flags
|
|
{
|
|
get{ return m_Flags; }
|
|
set{ m_Flags = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public bool PagingSquelched
|
|
{
|
|
get{ return GetFlag( PlayerFlag.PagingSquelched ); }
|
|
set{ SetFlag( PlayerFlag.PagingSquelched, value ); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public bool KarmaLocked
|
|
{
|
|
get{ return GetFlag( PlayerFlag.KarmaLocked ); }
|
|
set{ SetFlag( PlayerFlag.KarmaLocked, value ); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public bool UseOwnFilter
|
|
{
|
|
get{ return GetFlag( PlayerFlag.UseOwnFilter ); }
|
|
set{ SetFlag( PlayerFlag.UseOwnFilter, value ); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public bool AcceptGuildInvites
|
|
{
|
|
get{ return GetFlag( PlayerFlag.AcceptGuildInvites ); }
|
|
set{ SetFlag( PlayerFlag.AcceptGuildInvites, value ); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Auto Arrow Recovery
|
|
private Dictionary<Type, int> m_RecoverableAmmo = new Dictionary<Type,int>();
|
|
|
|
public Dictionary<Type, int> RecoverableAmmo
|
|
{
|
|
get { return m_RecoverableAmmo; }
|
|
}
|
|
|
|
public void RecoverAmmo()
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
private DateTime m_AnkhNextUse;
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public DateTime AnkhNextUse
|
|
{
|
|
get{ return m_AnkhNextUse; }
|
|
set{ m_AnkhNextUse = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public TimeSpan DisguiseTimeLeft
|
|
{
|
|
get{ return DisguiseTimers.TimeRemaining( this ); }
|
|
}
|
|
|
|
private DateTime m_PeacedUntil;
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public DateTime PeacedUntil
|
|
{
|
|
get { return m_PeacedUntil; }
|
|
set { m_PeacedUntil = value; }
|
|
}
|
|
|
|
public static Direction GetDirection4( Point3D from, Point3D to )
|
|
{
|
|
int dx = from.X - to.X;
|
|
int dy = from.Y - to.Y;
|
|
|
|
int rx = dx - dy;
|
|
int ry = dx + dy;
|
|
|
|
Direction ret;
|
|
|
|
if ( rx >= 0 && ry >= 0 )
|
|
ret = Direction.West;
|
|
else if ( rx >= 0 && ry < 0 )
|
|
ret = Direction.South;
|
|
else if ( rx < 0 && ry < 0 )
|
|
ret = Direction.East;
|
|
else
|
|
ret = Direction.North;
|
|
|
|
return ret;
|
|
}
|
|
|
|
public override bool OnDroppedItemToWorld( Item item, Point3D location )
|
|
{
|
|
if ( !base.OnDroppedItemToWorld( item, location ) )
|
|
return false;
|
|
|
|
IPooledEnumerable mobiles = Map.GetMobilesInRange( location, 0 );
|
|
|
|
foreach ( Mobile m in mobiles )
|
|
{
|
|
if ( m.Z >= location.Z && m.Z < location.Z + 16 )
|
|
{
|
|
mobiles.Free();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
mobiles.Free();
|
|
|
|
BounceInfo bi = item.GetBounce();
|
|
|
|
if ( bi != null )
|
|
{
|
|
Type type = item.GetType();
|
|
|
|
if ( type.IsDefined( typeof( FurnitureAttribute ), true ) || type.IsDefined( typeof( DynamicFlipingAttribute ), true ) )
|
|
{
|
|
object[] objs = type.GetCustomAttributes( typeof( FlipableAttribute ), true );
|
|
|
|
if ( objs != null && objs.Length > 0 )
|
|
{
|
|
FlipableAttribute fp = objs[0] as FlipableAttribute;
|
|
|
|
if ( fp != null )
|
|
{
|
|
int[] itemIDs = fp.ItemIDs;
|
|
|
|
Point3D oldWorldLoc = bi.m_WorldLoc;
|
|
Point3D newWorldLoc = location;
|
|
|
|
if ( oldWorldLoc.X != newWorldLoc.X || oldWorldLoc.Y != newWorldLoc.Y )
|
|
{
|
|
Direction dir = GetDirection4( oldWorldLoc, newWorldLoc );
|
|
|
|
if ( itemIDs.Length == 2 )
|
|
{
|
|
switch ( dir )
|
|
{
|
|
case Direction.North:
|
|
case Direction.South: item.ItemID = itemIDs[0]; break;
|
|
case Direction.East:
|
|
case Direction.West: item.ItemID = itemIDs[1]; break;
|
|
}
|
|
}
|
|
else if ( itemIDs.Length == 4 )
|
|
{
|
|
switch ( dir )
|
|
{
|
|
case Direction.South: item.ItemID = itemIDs[0]; break;
|
|
case Direction.East: item.ItemID = itemIDs[1]; break;
|
|
case Direction.North: item.ItemID = itemIDs[2]; break;
|
|
case Direction.West: item.ItemID = itemIDs[3]; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override int GetPacketFlags()
|
|
{
|
|
int flags = base.GetPacketFlags();
|
|
|
|
if ( m_IgnoreMobiles )
|
|
flags |= 0x10;
|
|
|
|
return flags;
|
|
}
|
|
|
|
public override int GetOldPacketFlags()
|
|
{
|
|
int flags = base.GetOldPacketFlags();
|
|
|
|
if ( m_IgnoreMobiles )
|
|
flags |= 0x10;
|
|
|
|
return flags;
|
|
}
|
|
|
|
public bool GetFlag( PlayerFlag flag )
|
|
{
|
|
return ( (m_Flags & flag) != 0 );
|
|
}
|
|
|
|
public void SetFlag( PlayerFlag flag, bool value )
|
|
{
|
|
if ( value )
|
|
m_Flags |= flag;
|
|
else
|
|
m_Flags &= ~flag;
|
|
}
|
|
|
|
public DesignContext DesignContext
|
|
{
|
|
get{ return m_DesignContext; }
|
|
set{ m_DesignContext = value; }
|
|
}
|
|
|
|
public static void Initialize()
|
|
{
|
|
if ( FastwalkPrevention )
|
|
PacketHandlers.RegisterThrottler( 0x02, new ThrottlePacketCallback( MovementThrottle_Callback ) );
|
|
|
|
EventSink.Login += new LoginEventHandler( OnLogin );
|
|
EventSink.Logout += new LogoutEventHandler( OnLogout );
|
|
EventSink.Connected += new ConnectedEventHandler( EventSink_Connected );
|
|
EventSink.Disconnected += new DisconnectedEventHandler( EventSink_Disconnected );
|
|
}
|
|
|
|
protected override void OnRaceChange( Race oldRace )
|
|
{
|
|
ValidateEquipment();
|
|
}
|
|
|
|
public override int MaxWeight { get { return (40 + (int)(3.5 * this.Str)); } }
|
|
|
|
private int m_LastGlobalLight = -1, m_LastPersonalLight = -1;
|
|
|
|
public override void OnNetStateChanged()
|
|
{
|
|
m_LastGlobalLight = -1;
|
|
m_LastPersonalLight = -1;
|
|
}
|
|
|
|
public override void ComputeBaseLightLevels( out int global, out int personal )
|
|
{
|
|
global = LightCycle.ComputeLevelFor( this );
|
|
|
|
personal = this.LightLevel;
|
|
}
|
|
|
|
public override void CheckLightLevels( bool forceResend )
|
|
{
|
|
NetState ns = this.NetState;
|
|
|
|
if ( ns == null )
|
|
return;
|
|
|
|
int global, personal;
|
|
|
|
ComputeLightLevels( out global, out personal );
|
|
|
|
if ( !forceResend )
|
|
forceResend = ( global != m_LastGlobalLight || personal != m_LastPersonalLight );
|
|
|
|
if ( !forceResend )
|
|
return;
|
|
|
|
m_LastGlobalLight = global;
|
|
m_LastPersonalLight = personal;
|
|
|
|
ns.Send( GlobalLightLevel.Instantiate( global ) );
|
|
ns.Send( new PersonalLightLevel( this, personal ) );
|
|
}
|
|
|
|
private static void OnLogin( LoginEventArgs e )
|
|
{
|
|
Mobile from = e.Mobile;
|
|
|
|
if ( AccountHandler.LockdownLevel > AccessLevel.Player )
|
|
{
|
|
string notice;
|
|
|
|
Accounting.Account acct = from.Account as Accounting.Account;
|
|
|
|
if ( acct == null || !acct.HasAccess( from.NetState ) )
|
|
{
|
|
if ( from.AccessLevel == AccessLevel.Player )
|
|
notice = "The server is currently under lockdown. No players are allowed to log in at this time.";
|
|
else
|
|
notice = "The server is currently under lockdown. You do not have sufficient access level to connect.";
|
|
|
|
Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( Disconnect ), from );
|
|
}
|
|
else if ( from.AccessLevel >= AccessLevel.Administrator )
|
|
{
|
|
notice = "The server is currently under lockdown. As you are an administrator, you may change this from the [Admin gump.";
|
|
}
|
|
else
|
|
{
|
|
notice = "The server is currently under lockdown. You have sufficient access level to connect.";
|
|
}
|
|
|
|
from.SendGump( new NoticeGump( 1060637, 30720, notice, 0xFFC000, 300, 140, null, null ) );
|
|
return;
|
|
}
|
|
}
|
|
|
|
private bool m_NoDeltaRecursion;
|
|
|
|
public void ValidateEquipment()
|
|
{
|
|
if ( m_NoDeltaRecursion || Map == null || Map == Map.Internal )
|
|
return;
|
|
|
|
if ( this.Items == null )
|
|
return;
|
|
|
|
m_NoDeltaRecursion = true;
|
|
Timer.DelayCall( TimeSpan.Zero, new TimerCallback( ValidateEquipment_Sandbox ) );
|
|
}
|
|
|
|
private void ValidateEquipment_Sandbox()
|
|
{
|
|
try
|
|
{
|
|
if ( Map == null || Map == Map.Internal )
|
|
return;
|
|
|
|
List<Item> items = this.Items;
|
|
|
|
if ( items == null )
|
|
return;
|
|
|
|
bool moved = false;
|
|
|
|
int str = this.Str;
|
|
int dex = this.Dex;
|
|
int intel = this.Int;
|
|
|
|
Mobile from = this;
|
|
|
|
for ( int i = items.Count - 1; i >= 0; --i )
|
|
{
|
|
if ( i >= items.Count )
|
|
continue;
|
|
|
|
Item item = items[i];
|
|
|
|
if ( item is BaseWeapon )
|
|
{
|
|
BaseWeapon weapon = (BaseWeapon)item;
|
|
|
|
bool drop = false;
|
|
|
|
if( dex < weapon.DexRequirement )
|
|
drop = true;
|
|
else if( str < Ultima.Scale( weapon.StrRequirement, 100 - weapon.GetLowerStatReq() ) )
|
|
drop = true;
|
|
else if( intel < weapon.IntRequirement )
|
|
drop = true;
|
|
|
|
if ( drop )
|
|
{
|
|
string name = weapon.Name;
|
|
|
|
if ( name == null )
|
|
name = String.Format( "#{0}", weapon.LabelNumber );
|
|
|
|
from.SendLocalizedMessage( 1062001, name ); // You can no longer wield your ~1_WEAPON~
|
|
from.AddToBackpack( weapon );
|
|
moved = true;
|
|
}
|
|
}
|
|
else if ( item is BaseArmor )
|
|
{
|
|
BaseArmor armor = (BaseArmor)item;
|
|
|
|
bool drop = false;
|
|
|
|
if ( !armor.AllowMaleWearer && !from.Female && from.AccessLevel < AccessLevel.GameMaster )
|
|
{
|
|
drop = true;
|
|
}
|
|
else if ( !armor.AllowFemaleWearer && from.Female && from.AccessLevel < AccessLevel.GameMaster )
|
|
{
|
|
drop = true;
|
|
}
|
|
else
|
|
{
|
|
int strBonus = armor.ComputeStatBonus( StatType.Str ), strReq = armor.ComputeStatReq( StatType.Str );
|
|
int dexBonus = armor.ComputeStatBonus( StatType.Dex ), dexReq = armor.ComputeStatReq( StatType.Dex );
|
|
int intBonus = armor.ComputeStatBonus( StatType.Int ), intReq = armor.ComputeStatReq( StatType.Int );
|
|
|
|
if( dex < dexReq || (dex + dexBonus) < 1 )
|
|
drop = true;
|
|
else if( str < strReq || (str + strBonus) < 1 )
|
|
drop = true;
|
|
else if( intel < intReq || (intel + intBonus) < 1 )
|
|
drop = true;
|
|
}
|
|
|
|
if ( drop )
|
|
{
|
|
string name = armor.Name;
|
|
|
|
if ( name == null )
|
|
name = String.Format( "#{0}", armor.LabelNumber );
|
|
|
|
if ( armor is BaseShield )
|
|
from.SendLocalizedMessage( 1062003, name ); // You can no longer equip your ~1_SHIELD~
|
|
else
|
|
from.SendLocalizedMessage( 1062002, name ); // You can no longer wear your ~1_ARMOR~
|
|
|
|
from.AddToBackpack( armor );
|
|
moved = true;
|
|
}
|
|
}
|
|
else if ( item is BaseClothing )
|
|
{
|
|
BaseClothing clothing = (BaseClothing)item;
|
|
|
|
bool drop = false;
|
|
|
|
if ( !clothing.AllowMaleWearer && !from.Female && from.AccessLevel < AccessLevel.GameMaster )
|
|
{
|
|
drop = true;
|
|
}
|
|
else if ( !clothing.AllowFemaleWearer && from.Female && from.AccessLevel < AccessLevel.GameMaster )
|
|
{
|
|
drop = true;
|
|
}
|
|
|
|
if ( drop )
|
|
{
|
|
string name = clothing.Name;
|
|
|
|
if ( name == null )
|
|
name = String.Format( "#{0}", clothing.LabelNumber );
|
|
|
|
from.SendLocalizedMessage( 1062002, name ); // You can no longer wear your ~1_ARMOR~
|
|
|
|
from.AddToBackpack( clothing );
|
|
moved = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( moved )
|
|
from.SendLocalizedMessage( 500647 ); // Some equipment has been moved to your backpack.
|
|
}
|
|
catch ( Exception e )
|
|
{
|
|
Console.WriteLine( e );
|
|
}
|
|
finally
|
|
{
|
|
m_NoDeltaRecursion = false;
|
|
}
|
|
}
|
|
|
|
public override void Delta( MobileDelta flag )
|
|
{
|
|
base.Delta( flag );
|
|
|
|
if ( (flag & MobileDelta.Stat) != 0 )
|
|
ValidateEquipment();
|
|
}
|
|
|
|
private static void Disconnect( object state )
|
|
{
|
|
NetState ns = ((Mobile)state).NetState;
|
|
|
|
if ( ns != null )
|
|
ns.Dispose();
|
|
}
|
|
|
|
private static void OnLogout( LogoutEventArgs e )
|
|
{
|
|
}
|
|
|
|
private static void EventSink_Connected( ConnectedEventArgs e )
|
|
{
|
|
PlayerMobile pm = e.Mobile as PlayerMobile;
|
|
|
|
if ( pm != null )
|
|
{
|
|
pm.m_SessionStart = DateTime.Now;
|
|
pm.LastOnline = DateTime.Now;
|
|
}
|
|
|
|
DisguiseTimers.StartTimer( e.Mobile );
|
|
}
|
|
|
|
private static void EventSink_Disconnected( DisconnectedEventArgs e )
|
|
{
|
|
Mobile from = e.Mobile;
|
|
DesignContext context = DesignContext.Find( from );
|
|
|
|
if ( context != null )
|
|
{
|
|
/* Client disconnected
|
|
* - Remove design context
|
|
* - Eject all from house
|
|
* - Restore relocated entities
|
|
*/
|
|
|
|
// Remove design context
|
|
DesignContext.Remove( from );
|
|
|
|
// Eject all from house
|
|
from.RevealingAction();
|
|
|
|
foreach ( Item item in context.Foundation.GetItems() )
|
|
item.Location = context.Foundation.BanLocation;
|
|
|
|
foreach ( Mobile mobile in context.Foundation.GetMobiles() )
|
|
mobile.Location = context.Foundation.BanLocation;
|
|
|
|
// Restore relocated entities
|
|
context.Foundation.RestoreRelocatedEntities();
|
|
}
|
|
|
|
PlayerMobile pm = e.Mobile as PlayerMobile;
|
|
|
|
if ( pm != null )
|
|
{
|
|
pm.m_GameTime += (DateTime.Now - pm.m_SessionStart);
|
|
pm.m_SpeechLog = null;
|
|
pm.LastOnline = DateTime.Now;
|
|
}
|
|
|
|
DisguiseTimers.StopTimer( from );
|
|
|
|
if ( Server.Misc.Settings.LogoutSave() ){ World.Save( true, false ); }
|
|
}
|
|
|
|
public override void RevealingAction()
|
|
{
|
|
if ( m_DesignContext != null )
|
|
return;
|
|
|
|
Spells.Sixth.InvisibilitySpell.RemoveTimer( this );
|
|
|
|
base.RevealingAction();
|
|
|
|
m_IsStealthing = false; // IsStealthing should be moved to Server.Mobiles
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public override bool Hidden
|
|
{
|
|
get
|
|
{
|
|
return base.Hidden;
|
|
}
|
|
set
|
|
{
|
|
base.Hidden = value;
|
|
}
|
|
}
|
|
|
|
public override void OnSubItemAdded( Item item )
|
|
{
|
|
if ( AccessLevel < AccessLevel.GameMaster && item.IsChildOf( this.Backpack ) )
|
|
{
|
|
int maxWeight = WeightOverloading.GetMaxWeight( this );
|
|
int curWeight = Mobile.BodyWeight + this.TotalWeight;
|
|
|
|
if ( curWeight > maxWeight )
|
|
this.SendLocalizedMessage( 1019035, true, String.Format( " : {0} / {1}", curWeight, maxWeight ) );
|
|
}
|
|
}
|
|
|
|
public override bool CanBeHarmful( Mobile target, bool message, bool ignoreOurBlessedness )
|
|
{
|
|
if ( m_DesignContext != null || (target is PlayerMobile && ((PlayerMobile)target).m_DesignContext != null) )
|
|
return false;
|
|
|
|
if ( target.Invulnerable || 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 CanBeBeneficial( Mobile target, bool message, bool allowDead )
|
|
{
|
|
if ( m_DesignContext != null || (target is PlayerMobile && ((PlayerMobile)target).m_DesignContext != null) )
|
|
return false;
|
|
|
|
return base.CanBeBeneficial( target, message, allowDead );
|
|
}
|
|
|
|
public override bool CheckContextMenuDisplay( IEntity target )
|
|
{
|
|
return ( m_DesignContext == null );
|
|
}
|
|
|
|
public override void OnItemAdded( Item item )
|
|
{
|
|
base.OnItemAdded( item );
|
|
|
|
if ( item is BaseArmor || item is BaseWeapon )
|
|
{
|
|
Hits=Hits; Stam=Stam; Mana=Mana;
|
|
}
|
|
|
|
if ( this.NetState != null )
|
|
CheckLightLevels( false );
|
|
}
|
|
|
|
public override void OnItemRemoved( Item item )
|
|
{
|
|
base.OnItemRemoved( item );
|
|
|
|
if ( item is BaseArmor || item is BaseWeapon )
|
|
{
|
|
Hits=Hits; Stam=Stam; Mana=Mana;
|
|
}
|
|
|
|
if ( this.NetState != null )
|
|
CheckLightLevels( false );
|
|
}
|
|
|
|
public override double ArmorRating
|
|
{
|
|
get
|
|
{
|
|
//BaseArmor ar;
|
|
double rating = 0.0;
|
|
|
|
AddArmorRating( ref rating, NeckArmor );
|
|
AddArmorRating( ref rating, HandArmor );
|
|
AddArmorRating( ref rating, HeadArmor );
|
|
AddArmorRating( ref rating, ArmsArmor );
|
|
AddArmorRating( ref rating, LegsArmor );
|
|
AddArmorRating( ref rating, ChestArmor );
|
|
AddArmorRating( ref rating, ShieldArmor );
|
|
|
|
return VirtualArmor + VirtualArmorMod + rating;
|
|
}
|
|
}
|
|
|
|
private void AddArmorRating( ref double rating, Item armor )
|
|
{
|
|
if ( armor is BaseArmor )
|
|
{
|
|
BaseArmor ar = armor as BaseArmor;
|
|
rating += ar.ArmorRatingScaled;
|
|
}
|
|
}
|
|
|
|
#region [Stats]Max
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public override int HitsMax
|
|
{
|
|
get
|
|
{
|
|
int hits = this.RawStr;
|
|
int strOffs = GetStatOffset( StatType.Str );
|
|
hits = (hits / 2) + strOffs;
|
|
hits = (int)(hits * Server.Misc.Settings.HitPoints());
|
|
hits = hits + 50;
|
|
|
|
return hits;
|
|
}
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public override int StamMax
|
|
{
|
|
get{ return base.StamMax; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public override int ManaMax
|
|
{
|
|
get{ return base.ManaMax; }
|
|
}
|
|
#endregion
|
|
|
|
#region Stat Getters/Setters
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public override int Str
|
|
{
|
|
get
|
|
{
|
|
return base.Str;
|
|
}
|
|
set
|
|
{
|
|
base.Str = value;
|
|
}
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public override int Int
|
|
{
|
|
get
|
|
{
|
|
return base.Int;
|
|
}
|
|
set
|
|
{
|
|
base.Int = value;
|
|
}
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public override int Dex
|
|
{
|
|
get
|
|
{
|
|
return base.Dex;
|
|
}
|
|
set
|
|
{
|
|
base.Dex = value;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public override bool Move( Direction d )
|
|
{
|
|
NetState ns = this.NetState;
|
|
|
|
if ( ns != null )
|
|
{
|
|
if ( HasGump( typeof( ResurrectGump ) ) ) {
|
|
if ( Alive ) {
|
|
CloseGump( typeof( ResurrectGump ) );
|
|
} else {
|
|
SendLocalizedMessage( 500111 ); // You are frozen and cannot move.
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
TimeSpan speed = ComputeMovementSpeed( d );
|
|
|
|
bool res;
|
|
|
|
if ( !Alive )
|
|
Server.Movement.MovementImpl.IgnoreMovableImpassables = true;
|
|
|
|
res = base.Move( d );
|
|
|
|
Server.Movement.MovementImpl.IgnoreMovableImpassables = false;
|
|
|
|
if ( !res )
|
|
return false;
|
|
|
|
m_NextMovementTime += speed;
|
|
|
|
return true;
|
|
}
|
|
|
|
public override bool CheckMovement( Direction d, out int newZ )
|
|
{
|
|
DesignContext context = m_DesignContext;
|
|
|
|
if ( context == null )
|
|
return base.CheckMovement( d, out newZ );
|
|
|
|
HouseFoundation foundation = context.Foundation;
|
|
|
|
newZ = foundation.Z + HouseFoundation.GetLevelZ( context.Level, context.Foundation );
|
|
|
|
int newX = this.X, newY = this.Y;
|
|
Movement.Movement.Offset( d, ref newX, ref newY );
|
|
|
|
int startX = foundation.X + foundation.Components.Min.X + 1;
|
|
int startY = foundation.Y + foundation.Components.Min.Y + 1;
|
|
int endX = startX + foundation.Components.Width - 1;
|
|
int endY = startY + foundation.Components.Height - 2;
|
|
|
|
return ( newX >= startX && newY >= startY && newX < endX && newY < endY && Map == foundation.Map );
|
|
}
|
|
|
|
public override bool AllowItemUse( Item item )
|
|
{
|
|
return DesignContext.Check( this );
|
|
}
|
|
|
|
public override bool AllowSkillUse( SkillName skill )
|
|
{
|
|
return DesignContext.Check( this );
|
|
}
|
|
|
|
public override void SetLocation( Point3D loc, bool isTeleport )
|
|
{
|
|
if ( !isTeleport && AccessLevel == AccessLevel.Player )
|
|
{
|
|
// moving, not teleporting
|
|
int zDrop = ( this.Location.Z - loc.Z );
|
|
|
|
if ( zDrop > 20 ) // we fell more than one story
|
|
Hits -= ((zDrop / 20) * 10) - 5; // deal some damage; does not kill, disrupt, etc
|
|
}
|
|
|
|
base.SetLocation( loc, isTeleport );
|
|
}
|
|
|
|
public override void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
|
|
{
|
|
base.GetContextMenuEntries( from, list );
|
|
|
|
if ( from == this )
|
|
{
|
|
BaseHouse house = BaseHouse.FindHouseAt( this );
|
|
|
|
if ( house != null )
|
|
{
|
|
if ( Alive && house.InternalizedVendors.Count > 0 && house.IsOwner( this ) )
|
|
list.Add( new CallbackEntry( 6204, new ContextCallback( GetVendor ) ) );
|
|
|
|
if ( house.IsAosRules )
|
|
list.Add( new CallbackEntry( 6207, new ContextCallback( LeaveHouse ) ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GetVendor()
|
|
{
|
|
BaseHouse house = BaseHouse.FindHouseAt( this );
|
|
|
|
if ( CheckAlive() && house != null && house.IsOwner( this ) && house.InternalizedVendors.Count > 0 )
|
|
{
|
|
CloseGump( typeof( ReclaimVendorGump ) );
|
|
SendGump( new ReclaimVendorGump( house ) );
|
|
}
|
|
}
|
|
|
|
private void LeaveHouse()
|
|
{
|
|
BaseHouse house = BaseHouse.FindHouseAt( this );
|
|
|
|
if ( house != null )
|
|
this.Location = house.BanLocation;
|
|
}
|
|
|
|
private delegate void ContextCallback();
|
|
|
|
private class CallbackEntry : ContextMenuEntry
|
|
{
|
|
private ContextCallback m_Callback;
|
|
|
|
public CallbackEntry( int number, ContextCallback callback ) : this( number, -1, callback )
|
|
{
|
|
}
|
|
|
|
public CallbackEntry( int number, int range, ContextCallback callback ) : base( number, range )
|
|
{
|
|
m_Callback = callback;
|
|
}
|
|
|
|
public override void OnClick()
|
|
{
|
|
if ( m_Callback != null )
|
|
m_Callback();
|
|
}
|
|
}
|
|
|
|
public override void DisruptiveAction()
|
|
{
|
|
base.DisruptiveAction();
|
|
}
|
|
|
|
public override void OnDoubleClick( Mobile from )
|
|
{
|
|
if ( this == from && !Warmode )
|
|
{
|
|
IMount mount = Mount;
|
|
|
|
if ( mount != null && !DesignContext.Check( this ) )
|
|
return;
|
|
}
|
|
|
|
base.OnDoubleClick( from );
|
|
}
|
|
|
|
public override void DisplayPaperdollTo( Mobile to )
|
|
{
|
|
if ( DesignContext.Check( this ) )
|
|
base.DisplayPaperdollTo( to );
|
|
}
|
|
|
|
private static bool m_NoRecursion;
|
|
|
|
public override bool CheckEquip( Item item )
|
|
{
|
|
if ( !base.CheckEquip( item ) )
|
|
return false;
|
|
|
|
if ( this.AccessLevel < AccessLevel.GameMaster && item.Layer != Layer.Mount && this.HasTrade )
|
|
{
|
|
BounceInfo bounce = item.GetBounce();
|
|
|
|
if ( bounce != null )
|
|
{
|
|
if ( bounce.m_Parent is Item )
|
|
{
|
|
Item parent = (Item) bounce.m_Parent;
|
|
|
|
if ( parent == this.Backpack || parent.IsChildOf( this.Backpack ) )
|
|
return true;
|
|
}
|
|
else if ( bounce.m_Parent == this )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
SendLocalizedMessage( 1004042 ); // You can only equip what you are already carrying while you have a trade pending.
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override bool CheckTrade( Mobile to, Item item, SecureTradeContainer cont, bool message, bool checkItems, int plusItems, int plusWeight )
|
|
{
|
|
int msgNum = 0;
|
|
|
|
if ( cont == null )
|
|
{
|
|
if ( to.Holding != null )
|
|
msgNum = 1062727; // You cannot trade with someone who is dragging something.
|
|
else if ( this.HasTrade )
|
|
msgNum = 1062781; // You are already trading with someone else!
|
|
else if ( to.HasTrade )
|
|
msgNum = 1062779; // That person is already involved in a trade
|
|
}
|
|
|
|
if ( msgNum == 0 )
|
|
{
|
|
if ( cont != null )
|
|
{
|
|
plusItems += cont.TotalItems;
|
|
plusWeight += cont.TotalWeight;
|
|
}
|
|
|
|
if ( this.Backpack == null || !this.Backpack.CheckHold( this, item, false, checkItems, plusItems, plusWeight ) )
|
|
msgNum = 1004040; // You would not be able to hold this if the trade failed.
|
|
else if ( to.Backpack == null || !to.Backpack.CheckHold( to, item, false, checkItems, plusItems, plusWeight ) )
|
|
msgNum = 1004039; // The recipient of this trade would not be able to carry this.
|
|
else
|
|
msgNum = CheckContentForTrade( item );
|
|
}
|
|
|
|
if ( msgNum != 0 )
|
|
{
|
|
if ( message )
|
|
this.SendLocalizedMessage( msgNum );
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static int CheckContentForTrade( Item item )
|
|
{
|
|
if ( item is TrapableContainer && ((TrapableContainer)item).TrapType != TrapType.None )
|
|
return 1004044; // You may not trade trapped items.
|
|
|
|
if ( SkillHandlers.StolenItem.IsStolen( item ) )
|
|
return 1004043; // You may not trade recently stolen items.
|
|
|
|
if ( item is Container )
|
|
{
|
|
foreach ( Item subItem in item.Items )
|
|
{
|
|
int msg = CheckContentForTrade( subItem );
|
|
|
|
if ( msg != 0 )
|
|
return msg;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public override bool CheckNonlocalDrop( Mobile from, Item item, Item target )
|
|
{
|
|
if ( !base.CheckNonlocalDrop( from, item, target ) )
|
|
return false;
|
|
|
|
if ( from.AccessLevel >= AccessLevel.GameMaster )
|
|
return true;
|
|
|
|
Container pack = this.Backpack;
|
|
if ( from == this && this.HasTrade && ( target == pack || target.IsChildOf( pack ) ) )
|
|
{
|
|
BounceInfo bounce = item.GetBounce();
|
|
|
|
if ( bounce != null && bounce.m_Parent is Item )
|
|
{
|
|
Item parent = (Item) bounce.m_Parent;
|
|
|
|
if ( parent == pack || parent.IsChildOf( pack ) )
|
|
return true;
|
|
}
|
|
|
|
SendLocalizedMessage( 1004041 ); // You can't do that while you have a trade pending.
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected override void OnLocationChange( Point3D oldLocation )
|
|
{
|
|
Server.Misc.RegionMusic.MusicRegion( this, this.Map, this.Location, oldLocation );
|
|
|
|
CheckLightLevels( false );
|
|
|
|
DesignContext context = m_DesignContext;
|
|
|
|
if ( context == null || m_NoRecursion )
|
|
return;
|
|
|
|
m_NoRecursion = true;
|
|
|
|
HouseFoundation foundation = context.Foundation;
|
|
|
|
int newX = this.X, newY = this.Y;
|
|
int newZ = foundation.Z + HouseFoundation.GetLevelZ( context.Level, context.Foundation );
|
|
|
|
int startX = foundation.X + foundation.Components.Min.X + 1;
|
|
int startY = foundation.Y + foundation.Components.Min.Y + 1;
|
|
int endX = startX + foundation.Components.Width - 1;
|
|
int endY = startY + foundation.Components.Height - 2;
|
|
|
|
if ( newX >= startX && newY >= startY && newX < endX && newY < endY && Map == foundation.Map )
|
|
{
|
|
if ( Z != newZ )
|
|
Location = new Point3D( X, Y, newZ );
|
|
|
|
m_NoRecursion = false;
|
|
return;
|
|
}
|
|
|
|
Location = new Point3D( foundation.X, foundation.Y, newZ );
|
|
Map = foundation.Map;
|
|
|
|
m_NoRecursion = false;
|
|
}
|
|
|
|
public override void GetProperties( ObjectPropertyList list )
|
|
{
|
|
base.GetProperties( list );
|
|
|
|
//string sTitle = GetNPCGuild( this );
|
|
//list.Add( Utility.FixHtml( sTitle ) );
|
|
}
|
|
|
|
public static string GetNPCGuild( Mobile m )
|
|
{
|
|
string GuildTitle = "";
|
|
|
|
if ( m is PlayerMobile )
|
|
{
|
|
PlayerMobile pm = (PlayerMobile)m;
|
|
|
|
if ( pm.NpcGuild == NpcGuild.MagesGuild ){ GuildTitle = "Mages Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.WarriorsGuild ){ GuildTitle = "Warriors Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.ThievesGuild ){ GuildTitle = "Thieves Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.RangersGuild ){ GuildTitle = "Rangers Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.HealersGuild ){ GuildTitle = "Healers Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.TinkersGuild ){ GuildTitle = "Tinkers Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.TailorsGuild ){ GuildTitle = "Tailors Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.MarinersGuild ){ GuildTitle = "Mariners Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.BardsGuild ){ GuildTitle = "Bards Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.BlacksmithsGuild ){ GuildTitle = "Blacksmiths Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.AlchemistsGuild ){ GuildTitle = "Alchemists Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.CarpentryGuild ){ GuildTitle = "Carpenters Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.LibrariansGuild ){ GuildTitle = "Librarians Guild"; }
|
|
else if ( pm.NpcGuild == NpcGuild.AssassinsGuild ){ GuildTitle = "Assassins Guild"; }
|
|
}
|
|
return GuildTitle;
|
|
}
|
|
|
|
public override bool OnMoveOver( Mobile m )
|
|
{
|
|
if ( m is BaseCreature && !((BaseCreature)m).Controlled )
|
|
return ( !Alive || !m.Alive || IsDeadBondedPet || m.IsDeadBondedPet ) || ( Hidden && m.AccessLevel > AccessLevel.Player );
|
|
|
|
return base.OnMoveOver( m );
|
|
}
|
|
|
|
public override bool CheckShove( Mobile shoved )
|
|
{
|
|
if( m_IgnoreMobiles )
|
|
return true;
|
|
else
|
|
return base.CheckShove( shoved );
|
|
}
|
|
|
|
protected override void OnMapChange( Map oldMap )
|
|
{
|
|
InvalidateProperties();
|
|
|
|
Server.Misc.RegionMusic.MusicRegion( this, this.Map, this.Location, this.Location );
|
|
|
|
DesignContext context = m_DesignContext;
|
|
|
|
if ( context == null || m_NoRecursion )
|
|
return;
|
|
|
|
m_NoRecursion = true;
|
|
|
|
HouseFoundation foundation = context.Foundation;
|
|
|
|
if ( Map != foundation.Map )
|
|
Map = foundation.Map;
|
|
|
|
m_NoRecursion = false;
|
|
}
|
|
|
|
public override void OnDamage( int amount, Mobile from, bool willKill )
|
|
{
|
|
int disruptThreshold = 0;
|
|
|
|
if ( amount > disruptThreshold )
|
|
{
|
|
BandageContext c = BandageContext.GetContext( this );
|
|
|
|
if ( c != null )
|
|
c.Slip();
|
|
}
|
|
|
|
WeightOverloading.FatigueOnDamage( this, amount );
|
|
|
|
if ( willKill && from is PlayerMobile )
|
|
Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerCallback( ((PlayerMobile) from).RecoverAmmo ) );
|
|
|
|
base.OnDamage( amount, from, willKill );
|
|
}
|
|
|
|
public override void Resurrect()
|
|
{
|
|
bool wasAlive = this.Alive;
|
|
|
|
base.Resurrect();
|
|
|
|
if ( this.Alive && !wasAlive )
|
|
{
|
|
Item deathRobe = new DeathRobe();
|
|
|
|
Hits = HitsMax;
|
|
Stam = StamMax;
|
|
Mana = ManaMax;
|
|
Hunger = 20;
|
|
Thirst = 20;
|
|
|
|
if ( !EquipItem( deathRobe ) )
|
|
deathRobe.Delete();
|
|
}
|
|
}
|
|
|
|
public override double RacialSkillBonus
|
|
{
|
|
get
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public override void OnWarmodeChanged()
|
|
{
|
|
if ( !Warmode )
|
|
Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerCallback( RecoverAmmo ) );
|
|
}
|
|
|
|
private bool FindItems_Callback(Item item)
|
|
{
|
|
if (!item.Deleted && item.LootType == LootType.Blessed )
|
|
{
|
|
if (this.Backpack != item.ParentEntity)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static void RemoveMyClothes( Mobile m )
|
|
{
|
|
if ( m.FindItemOnLayer( Layer.OuterTorso ) != null && !(m.FindItemOnLayer( Layer.OuterTorso ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.OuterTorso ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.MiddleTorso ) != null && !(m.FindItemOnLayer( Layer.MiddleTorso ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.MiddleTorso ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.OneHanded ) != null && !(m.FindItemOnLayer( Layer.OneHanded ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.OneHanded ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.TwoHanded ) != null && !(m.FindItemOnLayer( Layer.TwoHanded ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.TwoHanded ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Bracelet ) != null && !(m.FindItemOnLayer( Layer.Bracelet ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Bracelet ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Ring ) != null && !(m.FindItemOnLayer( Layer.Ring ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Ring ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Helm ) != null && !(m.FindItemOnLayer( Layer.Helm ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Helm ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Arms ) != null && !(m.FindItemOnLayer( Layer.Arms ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Arms ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.OuterLegs ) != null && !(m.FindItemOnLayer( Layer.OuterLegs ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.OuterLegs ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Neck ) != null && !(m.FindItemOnLayer( Layer.Neck ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Neck ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Gloves ) != null && !(m.FindItemOnLayer( Layer.Gloves ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Gloves ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Talisman ) != null && !(m.FindItemOnLayer( Layer.Talisman ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Talisman ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Shoes ) != null && !(m.FindItemOnLayer( Layer.Shoes ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Shoes ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.FirstValid ) != null && !(m.FindItemOnLayer( Layer.FirstValid ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.FirstValid ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Waist ) != null && !(m.FindItemOnLayer( Layer.Waist ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Waist ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.InnerLegs ) != null && !(m.FindItemOnLayer( Layer.InnerLegs ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.InnerLegs ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.InnerTorso ) != null && !(m.FindItemOnLayer( Layer.InnerTorso ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.InnerTorso ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Pants ) != null && !(m.FindItemOnLayer( Layer.Pants ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Pants ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Shirt ) != null && !(m.FindItemOnLayer( Layer.Shirt ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Shirt ).Delete(); }
|
|
if ( m.FindItemOnLayer( Layer.Cloak ) != null && !(m.FindItemOnLayer( Layer.Cloak ).LootType == LootType.Blessed) ) { m.FindItemOnLayer( Layer.Cloak ).Delete(); }
|
|
}
|
|
|
|
public override bool OnBeforeDeath()
|
|
{
|
|
if ( this.LastKiller is Guard )
|
|
{
|
|
BaseCreature guard = (BaseCreature)(this.LastKiller);
|
|
|
|
Point3D p = new Point3D( 2002, 1494, -20 );
|
|
|
|
if ( Utility.RandomBool() )
|
|
{
|
|
switch ( Utility.Random( 12 ) )
|
|
{
|
|
case 0: p = new Point3D(985, 982, 0); break;
|
|
case 1: p = new Point3D(985, 976, 0); break;
|
|
case 2: p = new Point3D(985, 970, 0); break;
|
|
case 3: p = new Point3D(985, 964, 0); break;
|
|
case 4: p = new Point3D(985, 958, 0); break;
|
|
case 5: p = new Point3D(998, 951, 0); break;
|
|
case 6: p = new Point3D(1007, 951, 0); break;
|
|
case 7: p = new Point3D(1013, 951, 0); break;
|
|
case 8: p = new Point3D(1019, 964, 0); break;
|
|
case 9: p = new Point3D(1019, 970, 0); break;
|
|
case 10: p = new Point3D(1019, 976, 0); break;
|
|
case 11: p = new Point3D(1019, 982, 0); break;
|
|
};
|
|
}
|
|
else
|
|
{
|
|
switch ( Utility.Random( 5 ) )
|
|
{
|
|
case 0: p = new Point3D(2002, 1494, -20); break;
|
|
case 1: p = new Point3D(2002, 1488, -20); break;
|
|
case 2: p = new Point3D(2002, 1483, -20); break;
|
|
case 3: p = new Point3D(2014, 1483, -20); break;
|
|
case 4: p = new Point3D(2014, 1489, -20); break;
|
|
};
|
|
}
|
|
|
|
Map map = Map.Britannia;
|
|
|
|
this.Criminal = false;
|
|
if ( this.Kills > 4 ){ this.Kills = 4; }
|
|
|
|
Hits = HitsMax;
|
|
Stam = StamMax;
|
|
Mana = ManaMax;
|
|
Hunger = 20;
|
|
Thirst = 20;
|
|
|
|
List<Item> stuff = new List<Item>();
|
|
foreach( Item c in this.Backpack.Items )
|
|
{
|
|
if ( c.LootType != LootType.Blessed )
|
|
{
|
|
stuff.Add(c);
|
|
}
|
|
}
|
|
|
|
foreach ( Item item in stuff )
|
|
{
|
|
item.Delete();
|
|
}
|
|
|
|
RemoveMyClothes( this );
|
|
|
|
if ( this.Mounted )
|
|
{
|
|
Mobile horse = (Mobile)(this.Mount);
|
|
Server.Mobiles.BaseMount.Dismount( this );
|
|
horse.Delete();
|
|
}
|
|
|
|
if ( this.FindItemOnLayer( Layer.Shoes ) == null ) { this.AddItem( new Shoes( Utility.RandomNeutralHue() ) ); }
|
|
if ( this.FindItemOnLayer( Layer.Pants ) == null ) { this.AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); }
|
|
if ( this.FindItemOnLayer( Layer.Shirt ) == null ) { this.AddItem( new Shirt( Utility.RandomNeutralHue() ) ); }
|
|
|
|
this.SendMessage("You have been sent to prison!");
|
|
Server.Mobiles.BaseCreature.DeletePets( this );
|
|
this.MoveToWorld( p, map );
|
|
|
|
this.InvalidateProperties();
|
|
guard.Combatant = null;
|
|
guard.Warmode = false;
|
|
guard.InvalidateProperties();
|
|
|
|
return false;
|
|
}
|
|
|
|
NetState state = NetState;
|
|
|
|
if ( state != null )
|
|
state.CancelAllTrades();
|
|
|
|
DropHolding();
|
|
|
|
if (Backpack != null && !Backpack.Deleted)
|
|
{
|
|
List<Item> ilist = Backpack.FindItemsByType<Item>(FindItems_Callback);
|
|
|
|
for (int i = 0; i < ilist.Count; i++)
|
|
{
|
|
Backpack.AddItem(ilist[i]);
|
|
}
|
|
}
|
|
|
|
RecoverAmmo();
|
|
|
|
return base.OnBeforeDeath();
|
|
}
|
|
|
|
public override DeathMoveResult GetParentMoveResultFor( Item item )
|
|
{
|
|
DeathMoveResult res = base.GetParentMoveResultFor( item );
|
|
|
|
return res;
|
|
}
|
|
|
|
public override DeathMoveResult GetInventoryMoveResultFor( Item item )
|
|
{
|
|
DeathMoveResult res = base.GetInventoryMoveResultFor( item );
|
|
|
|
return res;
|
|
}
|
|
|
|
public override void OnDeath( Container c )
|
|
{
|
|
base.OnDeath(c);
|
|
|
|
HueMod = -1;
|
|
NameMod = null;
|
|
|
|
SetHairMods( -1, -1 );
|
|
|
|
PolymorphSpell.StopTimer( this );
|
|
IncognitoSpell.StopTimer( this );
|
|
DisguiseTimers.RemoveTimer( this );
|
|
|
|
EndAction( typeof( PolymorphSpell ) );
|
|
EndAction( typeof( IncognitoSpell ) );
|
|
|
|
SkillHandlers.StolenItem.ReturnOnDeath( this, c );
|
|
|
|
if ( m_PermaFlags.Count > 0 )
|
|
{
|
|
m_PermaFlags.Clear();
|
|
|
|
if ( c is Corpse )
|
|
((Corpse)c).Criminal = true;
|
|
|
|
if ( SkillHandlers.Stealing.ClassicMode )
|
|
Criminal = true;
|
|
}
|
|
|
|
Mobile killer = this.FindMostRecentDamager( true );
|
|
|
|
if ( killer is BaseCreature )
|
|
{
|
|
BaseCreature bc = (BaseCreature)killer;
|
|
|
|
Mobile master = bc.GetMaster();
|
|
if( master != null )
|
|
killer = master;
|
|
}
|
|
|
|
Server.Guilds.Guild.HandleDeath( this, killer );
|
|
}
|
|
|
|
private List<Mobile> m_PermaFlags;
|
|
private List<Mobile> m_VisList;
|
|
private Hashtable m_AntiMacroTable;
|
|
private TimeSpan m_GameTime;
|
|
private TimeSpan m_ShortTermElapse;
|
|
private TimeSpan m_LongTermElapse;
|
|
private DateTime m_SessionStart;
|
|
private SkillName m_Learning = (SkillName)(-1);
|
|
|
|
public SkillName Learning
|
|
{
|
|
get{ return m_Learning; }
|
|
set{ m_Learning = value; }
|
|
}
|
|
|
|
public PlayerMobile()
|
|
{
|
|
m_VisList = new List<Mobile>();
|
|
m_PermaFlags = new List<Mobile>();
|
|
m_AntiMacroTable = new Hashtable();
|
|
m_RecentlyReported = new List<Mobile>();
|
|
|
|
m_GameTime = TimeSpan.Zero;
|
|
m_ShortTermElapse = TimeSpan.FromHours( 8.0 );
|
|
m_LongTermElapse = TimeSpan.FromHours( 40.0 );
|
|
|
|
m_GuildRank = Guilds.RankDefinition.Lowest;
|
|
}
|
|
|
|
public override bool MutateSpeech( List<Mobile> hears, ref string text, ref object context )
|
|
{
|
|
if ( Alive )
|
|
return false;
|
|
|
|
return base.MutateSpeech( hears, ref text, ref context );
|
|
}
|
|
|
|
public override void DoSpeech( string text, int[] keywords, MessageType type, int hue )
|
|
{
|
|
if( Guilds.Guild.NewGuildSystem && (type == MessageType.Guild || type == MessageType.Alliance) )
|
|
{
|
|
Guilds.Guild g = this.Guild as Guilds.Guild;
|
|
if( g == null )
|
|
{
|
|
SendLocalizedMessage( 1063142 ); // You are not in a guild!
|
|
}
|
|
else if( type == MessageType.Alliance )
|
|
{
|
|
if( g.Alliance != null && g.Alliance.IsMember( g ) )
|
|
{
|
|
//g.Alliance.AllianceTextMessage( hue, "[Alliance][{0}]: {1}", this.Name, text );
|
|
g.Alliance.AllianceChat( this, text );
|
|
SendToStaffMessage( this, "[Alliance]: {0}", text );
|
|
|
|
m_AllianceMessageHue = hue;
|
|
}
|
|
else
|
|
{
|
|
SendLocalizedMessage( 1071020 ); // You are not in an alliance!
|
|
}
|
|
}
|
|
else //Type == MessageType.Guild
|
|
{
|
|
m_GuildMessageHue = hue;
|
|
|
|
g.GuildChat( this, text );
|
|
SendToStaffMessage( this, "[Guild]: {0}", text );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
base.DoSpeech( text, keywords, type, hue );
|
|
}
|
|
}
|
|
|
|
private static void SendToStaffMessage( Mobile from, string text )
|
|
{
|
|
Packet p = null;
|
|
|
|
foreach( NetState ns in from.GetClientsInRange( 8 ) )
|
|
{
|
|
Mobile mob = ns.Mobile;
|
|
|
|
if( mob != null && mob.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > from.AccessLevel )
|
|
{
|
|
if( p == null )
|
|
p = Packet.Acquire( new UnicodeMessage( from.Serial, from.Body, MessageType.Regular, from.SpeechHue, 3, from.Language, from.Name, text ) );
|
|
|
|
ns.Send( p );
|
|
}
|
|
}
|
|
|
|
Packet.Release( p );
|
|
}
|
|
|
|
private static void SendToStaffMessage( Mobile from, string format, params object[] args )
|
|
{
|
|
SendToStaffMessage( from, String.Format( format, args ) );
|
|
}
|
|
|
|
public override void Damage( int amount, Mobile from )
|
|
{
|
|
base.Damage( amount, from );
|
|
}
|
|
|
|
#region Poison
|
|
|
|
public override ApplyPoisonResult ApplyPoison( Mobile from, Poison poison )
|
|
{
|
|
if ( !Alive )
|
|
return ApplyPoisonResult.Immune;
|
|
|
|
ApplyPoisonResult result = base.ApplyPoison( from, poison );
|
|
|
|
if ( from != null && result == ApplyPoisonResult.Poisoned && PoisonTimer is PoisonImpl.PoisonTimer )
|
|
(PoisonTimer as PoisonImpl.PoisonTimer).From = from;
|
|
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public PlayerMobile( Serial s ) : base( s )
|
|
{
|
|
m_VisList = new List<Mobile>();
|
|
m_AntiMacroTable = new Hashtable();
|
|
}
|
|
|
|
public List<Mobile> VisibilityList
|
|
{
|
|
get{ return m_VisList; }
|
|
}
|
|
|
|
public List<Mobile> PermaFlags
|
|
{
|
|
get{ return m_PermaFlags; }
|
|
}
|
|
|
|
public override bool IsHarmfulCriminal( Mobile target )
|
|
{
|
|
if ( SkillHandlers.Stealing.ClassicMode && target is PlayerMobile && ((PlayerMobile)target).m_PermaFlags.Count > 0 )
|
|
{
|
|
int noto = Notoriety.Compute( this, target );
|
|
|
|
if ( noto == Notoriety.Innocent )
|
|
target.Delta( MobileDelta.Noto );
|
|
|
|
return false;
|
|
}
|
|
|
|
if ( target is BaseCreature && ((BaseCreature)target).InitialInnocent && !((BaseCreature)target).Controlled )
|
|
return false;
|
|
|
|
return base.IsHarmfulCriminal( target );
|
|
}
|
|
|
|
public bool AntiMacroCheck( Skill skill, object obj )
|
|
{
|
|
if ( obj == null || m_AntiMacroTable == null || this.AccessLevel != AccessLevel.Player )
|
|
return true;
|
|
|
|
Hashtable tbl = (Hashtable)m_AntiMacroTable[skill];
|
|
if ( tbl == null )
|
|
m_AntiMacroTable[skill] = tbl = new Hashtable();
|
|
|
|
CountAndTimeStamp count = (CountAndTimeStamp)tbl[obj];
|
|
if ( count != null )
|
|
{
|
|
if ( count.TimeStamp + SkillCheck.AntiMacroExpire <= DateTime.Now )
|
|
{
|
|
count.Count = 1;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
++count.Count;
|
|
if ( count.Count <= SkillCheck.Allowance )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tbl[obj] = count = new CountAndTimeStamp();
|
|
count.Count = 1;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private void RevertHair()
|
|
{
|
|
SetHairMods( -1, -1 );
|
|
}
|
|
|
|
public override void Deserialize( GenericReader reader )
|
|
{
|
|
base.Deserialize( reader );
|
|
int version = reader.ReadInt();
|
|
|
|
m_PeacedUntil = reader.ReadDateTime();
|
|
m_AnkhNextUse = reader.ReadDateTime();
|
|
m_AllianceMessageHue = reader.ReadEncodedInt();
|
|
m_GuildMessageHue = reader.ReadEncodedInt();
|
|
m_QuestLevel = reader.ReadInt();
|
|
m_MapMarkers = reader.ReadString();
|
|
|
|
int rank = reader.ReadEncodedInt();
|
|
int maxRank = Guilds.RankDefinition.Ranks.Length -1;
|
|
if( rank > maxRank )
|
|
rank = maxRank;
|
|
|
|
m_GuildRank = Guilds.RankDefinition.Ranks[rank];
|
|
m_LastOnline = reader.ReadDateTime();
|
|
m_Profession = reader.ReadEncodedInt();
|
|
|
|
if ( reader.ReadBool() )
|
|
{
|
|
m_HairModID = reader.ReadInt();
|
|
m_HairModHue = reader.ReadInt();
|
|
m_BeardModID = reader.ReadInt();
|
|
m_BeardModHue = reader.ReadInt();
|
|
}
|
|
|
|
m_NpcGuild = (NpcGuild)reader.ReadInt();
|
|
m_NpcGuildJoinTime = reader.ReadDateTime();
|
|
m_NpcGuildGameTime = reader.ReadTimeSpan();
|
|
m_Camp = reader.ReadDateTime();
|
|
m_Bedroll = reader.ReadDateTime();
|
|
m_PermaFlags = reader.ReadStrongMobileList();
|
|
m_Flags = (PlayerFlag)reader.ReadInt();
|
|
m_LongTermElapse = reader.ReadTimeSpan();
|
|
m_ShortTermElapse = reader.ReadTimeSpan();
|
|
m_GameTime = reader.ReadTimeSpan();
|
|
|
|
StatCap = 200;
|
|
Skills.Cap = 7000;
|
|
|
|
if (m_RecentlyReported == null)
|
|
m_RecentlyReported = new List<Mobile>();
|
|
|
|
if ( !CharacterCreation.VerifyProfession( m_Profession ) )
|
|
m_Profession = 0;
|
|
|
|
if ( m_PermaFlags == null )
|
|
m_PermaFlags = new List<Mobile>();
|
|
|
|
if( m_GuildRank == null )
|
|
m_GuildRank = Guilds.RankDefinition.Member; //Default to member if going from older verstion to new version (only time it should be null)
|
|
|
|
if( m_LastOnline == DateTime.MinValue && Account != null )
|
|
m_LastOnline = ((Account)Account).LastLogin;
|
|
|
|
if ( AccessLevel > AccessLevel.Player )
|
|
m_IgnoreMobiles = true;
|
|
|
|
List<Mobile> list = this.Stabled;
|
|
|
|
for ( int i = 0; i < list.Count; ++i )
|
|
{
|
|
BaseCreature bc = list[i] as BaseCreature;
|
|
|
|
if ( bc != null )
|
|
bc.IsStabled = true;
|
|
}
|
|
}
|
|
|
|
public override void Serialize( GenericWriter writer )
|
|
{
|
|
//cleanup our anti-macro table
|
|
foreach ( Hashtable t in m_AntiMacroTable.Values )
|
|
{
|
|
ArrayList remove = new ArrayList();
|
|
foreach ( CountAndTimeStamp time in t.Values )
|
|
{
|
|
if ( time.TimeStamp + SkillCheck.AntiMacroExpire <= DateTime.Now )
|
|
remove.Add( time );
|
|
}
|
|
|
|
for (int i=0;i<remove.Count;++i)
|
|
t.Remove( remove[i] );
|
|
}
|
|
|
|
CheckKillDecay();
|
|
|
|
base.Serialize( writer );
|
|
|
|
writer.Write( (int) 0 ); // version
|
|
|
|
writer.Write( (DateTime) m_PeacedUntil );
|
|
writer.Write( (DateTime) m_AnkhNextUse );
|
|
|
|
writer.WriteEncodedInt( m_AllianceMessageHue );
|
|
writer.WriteEncodedInt( m_GuildMessageHue );
|
|
writer.Write( m_QuestLevel );
|
|
writer.Write( m_MapMarkers );
|
|
|
|
writer.WriteEncodedInt( m_GuildRank.Rank );
|
|
writer.Write( m_LastOnline );
|
|
|
|
writer.WriteEncodedInt( (int) m_Profession );
|
|
|
|
bool useMods = ( m_HairModID != -1 || m_BeardModID != -1 );
|
|
|
|
writer.Write( useMods );
|
|
|
|
if ( useMods )
|
|
{
|
|
writer.Write( (int) m_HairModID );
|
|
writer.Write( (int) m_HairModHue );
|
|
writer.Write( (int) m_BeardModID );
|
|
writer.Write( (int) m_BeardModHue );
|
|
}
|
|
|
|
writer.Write( (int) m_NpcGuild );
|
|
writer.Write( (DateTime) m_NpcGuildJoinTime );
|
|
writer.Write( (TimeSpan) m_NpcGuildGameTime );
|
|
writer.Write( (DateTime) m_Camp );
|
|
writer.Write( (DateTime) m_Bedroll );
|
|
|
|
writer.Write( m_PermaFlags, true );
|
|
|
|
writer.Write( (int) m_Flags );
|
|
|
|
writer.Write( m_LongTermElapse );
|
|
writer.Write( m_ShortTermElapse );
|
|
writer.Write( this.GameTime );
|
|
}
|
|
|
|
public void CheckKillDecay()
|
|
{
|
|
if ( m_LongTermElapse < this.GameTime )
|
|
{
|
|
m_LongTermElapse += TimeSpan.FromHours( 8 );
|
|
if ( Kills > 0 )
|
|
--Kills;
|
|
}
|
|
}
|
|
|
|
public void ResetKillTime()
|
|
{
|
|
m_ShortTermElapse = this.GameTime + TimeSpan.FromHours( 8 );
|
|
m_LongTermElapse = this.GameTime + TimeSpan.FromHours( 40 );
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public DateTime SessionStart
|
|
{
|
|
get{ return m_SessionStart; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public TimeSpan GameTime
|
|
{
|
|
get
|
|
{
|
|
if ( NetState != null )
|
|
return m_GameTime + (DateTime.Now - m_SessionStart);
|
|
else
|
|
return m_GameTime;
|
|
}
|
|
}
|
|
|
|
public override bool CanSee( Mobile m )
|
|
{
|
|
if ( m is PlayerMobile && ((PlayerMobile)m).m_VisList.Contains( this ) )
|
|
return true;
|
|
|
|
return base.CanSee( m );
|
|
}
|
|
|
|
public override bool CanSee( Item item )
|
|
{
|
|
if ( m_DesignContext != null && m_DesignContext.Foundation.IsHiddenToCustomizer( item ) )
|
|
return false;
|
|
|
|
return base.CanSee( item );
|
|
}
|
|
|
|
public override void OnAfterDelete()
|
|
{
|
|
base.OnAfterDelete();
|
|
|
|
BaseHouse.HandleDeletion( this );
|
|
|
|
DisguiseTimers.RemoveTimer( this );
|
|
}
|
|
|
|
public override bool NewGuildDisplay { get { return Server.Guilds.Guild.NewGuildSystem; } }
|
|
|
|
protected override bool OnMove( Direction d )
|
|
{
|
|
return base.OnMove( d );
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public override bool Paralyzed
|
|
{
|
|
get
|
|
{
|
|
return base.Paralyzed;
|
|
}
|
|
set
|
|
{
|
|
base.Paralyzed = value;
|
|
}
|
|
}
|
|
|
|
#region Fastwalk Prevention
|
|
private static bool FastwalkPrevention = true; // Is fastwalk prevention enabled?
|
|
private static TimeSpan FastwalkThreshold = TimeSpan.FromSeconds( 0.4 ); // Fastwalk prevention will become active after 0.4 seconds
|
|
|
|
private DateTime m_NextMovementTime;
|
|
|
|
public virtual bool UsesFastwalkPrevention{ get{ return ( AccessLevel < AccessLevel.Counselor ); } }
|
|
|
|
public override TimeSpan ComputeMovementSpeed( Direction dir, bool checkTurning )
|
|
{
|
|
if ( checkTurning && (dir & Direction.Mask) != (this.Direction & Direction.Mask) )
|
|
return Mobile.RunMount; // We are NOT actually moving (just a direction change)
|
|
|
|
bool running = ( (dir & Direction.Running) != 0 );
|
|
|
|
bool onHorse = ( this.Mount != null );
|
|
|
|
if( onHorse )
|
|
return ( running ? Mobile.RunMount : Mobile.WalkMount );
|
|
|
|
return ( running ? Mobile.RunFoot : Mobile.WalkFoot );
|
|
}
|
|
|
|
public static bool MovementThrottle_Callback( NetState ns )
|
|
{
|
|
PlayerMobile pm = ns.Mobile as PlayerMobile;
|
|
|
|
if ( pm == null || !pm.UsesFastwalkPrevention )
|
|
return true;
|
|
|
|
if ( pm.m_NextMovementTime == DateTime.MinValue )
|
|
{
|
|
// has not yet moved
|
|
pm.m_NextMovementTime = DateTime.Now;
|
|
return true;
|
|
}
|
|
|
|
TimeSpan ts = pm.m_NextMovementTime - DateTime.Now;
|
|
|
|
if ( ts < TimeSpan.Zero )
|
|
{
|
|
// been a while since we've last moved
|
|
pm.m_NextMovementTime = DateTime.Now;
|
|
return true;
|
|
}
|
|
|
|
return ( ts < FastwalkThreshold );
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Hair and beard mods
|
|
private int m_HairModID = -1, m_HairModHue;
|
|
private int m_BeardModID = -1, m_BeardModHue;
|
|
|
|
public void SetHairMods( int hairID, int beardID )
|
|
{
|
|
if ( hairID == -1 )
|
|
InternalRestoreHair( true, ref m_HairModID, ref m_HairModHue );
|
|
else if ( hairID != -2 )
|
|
InternalChangeHair( true, hairID, ref m_HairModID, ref m_HairModHue );
|
|
|
|
if ( beardID == -1 )
|
|
InternalRestoreHair( false, ref m_BeardModID, ref m_BeardModHue );
|
|
else if ( beardID != -2 )
|
|
InternalChangeHair( false, beardID, ref m_BeardModID, ref m_BeardModHue );
|
|
}
|
|
|
|
private void CreateHair( bool hair, int id, int hue )
|
|
{
|
|
if( hair )
|
|
{
|
|
//TODO Verification?
|
|
HairItemID = id;
|
|
RecordHair = id;
|
|
HairHue = hue;
|
|
}
|
|
else
|
|
{
|
|
FacialHairItemID = id;
|
|
RecordBeard = id;
|
|
FacialHairHue = hue;
|
|
}
|
|
}
|
|
|
|
private void InternalRestoreHair( bool hair, ref int id, ref int hue )
|
|
{
|
|
if ( id == -1 )
|
|
return;
|
|
|
|
if ( hair )
|
|
{
|
|
HairItemID = 0;
|
|
RecordHair = 0;
|
|
}
|
|
else
|
|
{
|
|
FacialHairItemID = 0;
|
|
RecordBeard = 0;
|
|
}
|
|
|
|
//if( id != 0 )
|
|
CreateHair( hair, id, hue );
|
|
|
|
id = -1;
|
|
hue = 0;
|
|
}
|
|
|
|
private void InternalChangeHair( bool hair, int id, ref int storeID, ref int storeHue )
|
|
{
|
|
if ( storeID == -1 )
|
|
{
|
|
storeID = hair ? HairItemID : FacialHairItemID;
|
|
storeHue = hair ? HairHue : FacialHairHue;
|
|
}
|
|
CreateHair( hair, id, 0 );
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Speech log
|
|
private SpeechLog m_SpeechLog;
|
|
|
|
public SpeechLog SpeechLog{ get{ return m_SpeechLog; } }
|
|
|
|
public override void OnSpeech( SpeechEventArgs e )
|
|
{
|
|
if ( SpeechLog.Enabled && this.NetState != null )
|
|
{
|
|
if ( m_SpeechLog == null )
|
|
m_SpeechLog = new SpeechLog();
|
|
|
|
m_SpeechLog.Add( e.Mobile, e.Speech );
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |