457 lines
No EOL
12 KiB
C#
457 lines
No EOL
12 KiB
C#
using System;
|
|
using Server;
|
|
using System.Collections;
|
|
using Server.Mobiles;
|
|
using Server.Targeting;
|
|
using Server.Items;
|
|
using Server.Network;
|
|
using Server.Spells.Seventh;
|
|
using Server.Spells.Fifth;
|
|
using Server.Spells;
|
|
using Server.Misc;
|
|
using Server.Regions;
|
|
|
|
namespace Server.SkillHandlers
|
|
{
|
|
public class Stealing
|
|
{
|
|
public static void Initialize()
|
|
{
|
|
SkillInfo.Table[22].Callback = new SkillUseCallback( OnUse );
|
|
}
|
|
|
|
public static readonly bool ClassicMode = true;
|
|
public static readonly bool SuspendOnMurder = false;
|
|
|
|
public static bool IsInGuild( Mobile m )
|
|
{
|
|
return ( m is PlayerMobile && ((PlayerMobile)m).NpcGuild == NpcGuild.ThievesGuild );
|
|
}
|
|
|
|
public static bool IsInnocentTo( Mobile from, Mobile to )
|
|
{
|
|
return ( Notoriety.Compute( from, (Mobile)to ) == Notoriety.Innocent );
|
|
}
|
|
|
|
private class StealingTarget : Target
|
|
{
|
|
private Mobile m_Thief;
|
|
|
|
public StealingTarget( Mobile thief ) : base ( 1, false, TargetFlags.None )
|
|
{
|
|
m_Thief = thief;
|
|
|
|
AllowNonlocal = true;
|
|
}
|
|
|
|
private Item TryStealItem( Item toSteal, ref bool caught )
|
|
{
|
|
Item stolen = null;
|
|
|
|
object root = toSteal.RootParent;
|
|
|
|
if ( !IsEmptyHanded( m_Thief ) )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 1005584 ); // Both hands must be free to steal.
|
|
}
|
|
else if ( root is Mobile && ((Mobile)root).Invulnerable )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 1005598 ); // You can't steal from them.
|
|
}
|
|
else if ( root is PlayerVendor )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 502709 ); // You can't steal from vendors.
|
|
}
|
|
else if ( !m_Thief.CanSee( toSteal ) )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 500237 ); // Target can not be seen.
|
|
}
|
|
else if ( m_Thief.Backpack == null || !m_Thief.Backpack.CheckHold( m_Thief, toSteal, false, true ) )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 1048147 ); // Your backpack can't hold anything else.
|
|
}
|
|
else if ( toSteal.Parent == null || !toSteal.Movable )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that!
|
|
}
|
|
else if ( !m_Thief.InRange( toSteal.GetWorldLocation(), 1 ) )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 502703 ); // You must be standing next to an item to steal it.
|
|
}
|
|
else if ( toSteal.Parent is Mobile )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 1005585 ); // You cannot steal items which are equiped.
|
|
}
|
|
else if ( root == m_Thief )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 502704 ); // You catch yourself red-handed.
|
|
}
|
|
else if ( root is Mobile && ((Mobile)root).AccessLevel > AccessLevel.Player )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that!
|
|
}
|
|
else if ( root is Mobile && !m_Thief.CanBeHarmful( (Mobile)root ) )
|
|
{
|
|
}
|
|
else if ( root is Corpse )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that!
|
|
}
|
|
else
|
|
{
|
|
double w = toSteal.Weight + toSteal.TotalWeight;
|
|
|
|
if ( w > 10 )
|
|
{
|
|
m_Thief.SendMessage( "That is too heavy to steal." );
|
|
}
|
|
else
|
|
{
|
|
if ( toSteal.Stackable && toSteal.Amount > 1 )
|
|
{
|
|
int maxAmount = (int)((m_Thief.Skills[SkillName.Stealing].Value / 10.0) / toSteal.Weight);
|
|
|
|
if ( maxAmount < 1 )
|
|
maxAmount = 1;
|
|
else if ( maxAmount > toSteal.Amount )
|
|
maxAmount = toSteal.Amount;
|
|
|
|
int amount = Utility.RandomMinMax( 1, maxAmount );
|
|
|
|
if ( amount >= toSteal.Amount )
|
|
{
|
|
int pileWeight = (int)Math.Ceiling( toSteal.Weight * toSteal.Amount );
|
|
pileWeight *= 10;
|
|
|
|
if ( m_Thief.CheckTargetSkill( SkillName.Stealing, toSteal, pileWeight - 22.5, pileWeight + 27.5 ) )
|
|
stolen = toSteal;
|
|
}
|
|
else
|
|
{
|
|
int pileWeight = (int)Math.Ceiling( toSteal.Weight * amount );
|
|
pileWeight *= 10;
|
|
|
|
if ( m_Thief.CheckTargetSkill( SkillName.Stealing, toSteal, pileWeight - 22.5, pileWeight + 27.5 ) )
|
|
{
|
|
stolen = Mobile.LiftItemDupe( toSteal, toSteal.Amount - amount );
|
|
|
|
if ( stolen == null )
|
|
stolen = toSteal;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int iw = (int)Math.Ceiling( w );
|
|
iw *= 10;
|
|
|
|
if ( m_Thief.CheckTargetSkill( SkillName.Stealing, toSteal, iw - 22.5, iw + 27.5 ) )
|
|
stolen = toSteal;
|
|
}
|
|
|
|
if ( stolen != null )
|
|
{
|
|
m_Thief.SendLocalizedMessage( 502724 ); // You succesfully steal the item.
|
|
}
|
|
else
|
|
{
|
|
m_Thief.SendLocalizedMessage( 502723 ); // You fail to steal the item.
|
|
}
|
|
|
|
caught = ( m_Thief.Skills[SkillName.Stealing].Value < Utility.Random( 150 ) );
|
|
}
|
|
}
|
|
|
|
return stolen;
|
|
}
|
|
|
|
protected override void OnTarget( Mobile from, object target )
|
|
{
|
|
from.RevealingAction();
|
|
|
|
Item stolen = null;
|
|
object root = null;
|
|
bool caught = false;
|
|
|
|
if ( target is Item )
|
|
{
|
|
root = ((Item)target).RootParent;
|
|
stolen = TryStealItem( (Item)target, ref caught );
|
|
}
|
|
else if ( target is Mobile )
|
|
{
|
|
Container pack = ((Mobile)target).Backpack;
|
|
|
|
if ( pack != null && pack.Items.Count > 0 )
|
|
{
|
|
int randomIndex = Utility.Random( pack.Items.Count );
|
|
|
|
root = target;
|
|
stolen = TryStealItem( pack.Items[randomIndex], ref caught );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that!
|
|
}
|
|
|
|
if ( stolen != null )
|
|
{
|
|
from.AddToBackpack( stolen );
|
|
|
|
StolenItem.Add( stolen, m_Thief, root as Mobile );
|
|
}
|
|
|
|
if ( caught )
|
|
{
|
|
if ( root == null )
|
|
{
|
|
m_Thief.CriminalAction( false );
|
|
}
|
|
else if ( root is Corpse && ((Corpse)root).IsCriminalAction( m_Thief ) )
|
|
{
|
|
m_Thief.CriminalAction( false );
|
|
}
|
|
else if ( root is Mobile )
|
|
{
|
|
Mobile mobRoot = (Mobile)root;
|
|
|
|
if ( !IsInGuild( mobRoot ) && IsInnocentTo( m_Thief, mobRoot ) )
|
|
m_Thief.CriminalAction( false );
|
|
|
|
string message = String.Format( "You notice {0} trying to steal from {1}.", m_Thief.Name, mobRoot.Name );
|
|
|
|
foreach ( NetState ns in m_Thief.GetClientsInRange( 8 ) )
|
|
{
|
|
if ( ns.Mobile != m_Thief )
|
|
ns.Mobile.SendMessage( message );
|
|
}
|
|
}
|
|
}
|
|
else if ( root is Corpse && ((Corpse)root).IsCriminalAction( m_Thief ) )
|
|
{
|
|
m_Thief.CriminalAction( false );
|
|
}
|
|
|
|
if ( root is Mobile && ((Mobile)root).Player && m_Thief is PlayerMobile && IsInnocentTo( m_Thief, (Mobile)root ) && !IsInGuild( (Mobile)root ) )
|
|
{
|
|
PlayerMobile pm = (PlayerMobile)m_Thief;
|
|
|
|
pm.PermaFlags.Add( (Mobile)root );
|
|
pm.Delta( MobileDelta.Noto );
|
|
}
|
|
}
|
|
}
|
|
|
|
public static bool IsEmptyHanded( Mobile from )
|
|
{
|
|
if ( Server.Misc.Settings.CanStealWhileHoldingThings() )
|
|
return true;
|
|
|
|
if ( from.FindItemOnLayer( Layer.OneHanded ) != null )
|
|
return false;
|
|
|
|
if ( from.FindItemOnLayer( Layer.TwoHanded ) != null )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public static TimeSpan OnUse( Mobile m )
|
|
{
|
|
if ( !IsEmptyHanded( m ) )
|
|
{
|
|
m.SendLocalizedMessage( 1005584 ); // Both hands must be free to steal.
|
|
}
|
|
else
|
|
{
|
|
m.Target = new Stealing.StealingTarget( m );
|
|
m.RevealingAction();
|
|
|
|
m.SendLocalizedMessage( 502698 ); // Which item do you want to steal?
|
|
}
|
|
|
|
return TimeSpan.FromSeconds( 10.0 );
|
|
}
|
|
}
|
|
|
|
public class StolenItem
|
|
{
|
|
public static readonly TimeSpan StealTime = TimeSpan.FromMinutes( 2.0 );
|
|
|
|
private Item m_Stolen;
|
|
private Mobile m_Thief;
|
|
private Mobile m_Victim;
|
|
private DateTime m_Expires;
|
|
|
|
public Item Stolen{ get{ return m_Stolen; } }
|
|
public Mobile Thief{ get{ return m_Thief; } }
|
|
public Mobile Victim{ get{ return m_Victim; } }
|
|
public DateTime Expires{ get{ return m_Expires; } }
|
|
|
|
public bool IsExpired{ get{ return ( DateTime.Now >= m_Expires ); } }
|
|
|
|
public StolenItem( Item stolen, Mobile thief, Mobile victim )
|
|
{
|
|
m_Stolen = stolen;
|
|
m_Thief = thief;
|
|
m_Victim = victim;
|
|
|
|
m_Expires = DateTime.Now + StealTime;
|
|
}
|
|
|
|
private static Queue m_Queue = new Queue();
|
|
|
|
public static void Add( Item item, Mobile thief, Mobile victim )
|
|
{
|
|
Clean();
|
|
|
|
m_Queue.Enqueue( new StolenItem( item, thief, victim ) );
|
|
}
|
|
|
|
public static bool IsStolen( Item item )
|
|
{
|
|
Mobile victim = null;
|
|
|
|
return IsStolen( item, ref victim );
|
|
}
|
|
|
|
public static bool IsStolen( Item item, ref Mobile victim )
|
|
{
|
|
Clean();
|
|
|
|
foreach ( StolenItem si in m_Queue )
|
|
{
|
|
if ( si.m_Stolen == item && !si.IsExpired )
|
|
{
|
|
victim = si.m_Victim;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static void ReturnOnDeath( Mobile killed, Container corpse )
|
|
{
|
|
Clean();
|
|
|
|
foreach ( StolenItem si in m_Queue )
|
|
{
|
|
if ( si.m_Stolen.RootParent == corpse && si.m_Victim != null && !si.IsExpired )
|
|
{
|
|
if ( si.m_Victim.AddToBackpack( si.m_Stolen ) )
|
|
si.m_Victim.SendLocalizedMessage( 1010464 ); // the item that was stolen is returned to you.
|
|
else
|
|
si.m_Victim.SendLocalizedMessage( 1010463 ); // the item that was stolen from you falls to the ground.
|
|
|
|
si.m_Expires = DateTime.Now; // such a hack
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void Clean()
|
|
{
|
|
while ( m_Queue.Count > 0 )
|
|
{
|
|
StolenItem si = (StolenItem) m_Queue.Peek();
|
|
|
|
if ( si.IsExpired )
|
|
m_Queue.Dequeue();
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class Snooping
|
|
{
|
|
public static void Configure()
|
|
{
|
|
Container.SnoopHandler = new ContainerSnoopHandler( Container_Snoop );
|
|
}
|
|
|
|
public static bool CheckSnoopAllowed( Mobile from, Mobile to )
|
|
{
|
|
Map map = from.Map;
|
|
|
|
if ( to.Player )
|
|
return from.CanBeHarmful( to, false, true ); // normal restrictions
|
|
|
|
if ( map != null && (map.Rules & MapRules.HarmfulRestrictions) == 0 )
|
|
return true;
|
|
|
|
BaseCreature cret = to as BaseCreature;
|
|
|
|
if ( to.Body.IsHuman && (cret == null || (!cret.AlwaysAttackable && !cret.AlwaysMurderer)) )
|
|
return false; // in town we cannot snoop blue human npcs
|
|
|
|
return true;
|
|
}
|
|
|
|
public static void Container_Snoop( Container cont, Mobile from )
|
|
{
|
|
if ( from.AccessLevel > AccessLevel.Player || from.InRange( cont.GetWorldLocation(), 1 ) )
|
|
{
|
|
Mobile root = cont.RootParent as Mobile;
|
|
|
|
if ( root != null && !root.Alive )
|
|
return;
|
|
|
|
if ( root != null && root.AccessLevel > AccessLevel.Player && from.AccessLevel == AccessLevel.Player )
|
|
{
|
|
from.SendLocalizedMessage( 500209 ); // You can not peek into the container.
|
|
return;
|
|
}
|
|
|
|
if ( root != null && from.AccessLevel == AccessLevel.Player && !CheckSnoopAllowed( from, root ) )
|
|
{
|
|
from.SendLocalizedMessage( 1001018 ); // You cannot perform negative acts on your target.
|
|
return;
|
|
}
|
|
|
|
if ( root != null && from.AccessLevel == AccessLevel.Player && from.Skills[SkillName.Stealing].Value < Utility.Random( 100 ) )
|
|
{
|
|
Map map = from.Map;
|
|
|
|
if ( map != null )
|
|
{
|
|
string message = String.Format( "You notice {0} attempting to peek into {1}'s belongings.", from.Name, root.Name );
|
|
|
|
IPooledEnumerable eable = map.GetClientsInRange( from.Location, 8 );
|
|
|
|
foreach ( NetState ns in eable )
|
|
{
|
|
if ( ns.Mobile != from )
|
|
ns.Mobile.SendMessage( message );
|
|
}
|
|
|
|
eable.Free();
|
|
}
|
|
}
|
|
|
|
if ( from.AccessLevel == AccessLevel.Player )
|
|
Titles.AwardKarma( from, -4, true );
|
|
|
|
if ( from.AccessLevel > AccessLevel.Player || from.CheckTargetSkill( SkillName.Stealing, cont, 0.0, 50.0 ) )
|
|
{
|
|
if ( cont is TrapableContainer && ((TrapableContainer)cont).ExecuteTrap( from ) )
|
|
return;
|
|
|
|
cont.DisplayTo( from );
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage( 500210 ); // You failed to peek into the container.
|
|
|
|
if ( from.Skills[SkillName.Hiding].Value / 2 < Utility.Random( 100 ) )
|
|
from.RevealingAction();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage( 500446 ); // That is too far away.
|
|
}
|
|
}
|
|
}
|
|
} |