1826 lines
No EOL
40 KiB
C#
1826 lines
No EOL
40 KiB
C#
/***************************************************************************
|
|
* Container.cs
|
|
* -------------------
|
|
* begin : May 1, 2002
|
|
* copyright : (C) The RunUO Software Team
|
|
* email : info@runuo.com
|
|
*
|
|
* $Id$
|
|
*
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
***************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using Server.Network;
|
|
|
|
namespace Server.Items
|
|
{
|
|
public delegate void OnItemConsumed( Item item, int amount );
|
|
public delegate int CheckItemGroup( Item a, Item b );
|
|
|
|
public delegate void ContainerSnoopHandler( Container cont, Mobile from );
|
|
|
|
public class Container : Item
|
|
{
|
|
private static ContainerSnoopHandler m_SnoopHandler;
|
|
|
|
public static ContainerSnoopHandler SnoopHandler
|
|
{
|
|
get{ return m_SnoopHandler; }
|
|
set{ m_SnoopHandler = value; }
|
|
}
|
|
|
|
private ContainerData m_ContainerData;
|
|
|
|
private int m_DropSound;
|
|
private int m_GumpID;
|
|
private int m_MaxItems;
|
|
|
|
private int m_TotalItems;
|
|
private int m_TotalWeight;
|
|
private int m_TotalGold;
|
|
|
|
private bool m_LiftOverride;
|
|
|
|
internal List<Item> m_Items;
|
|
|
|
public ContainerData ContainerData
|
|
{
|
|
get
|
|
{
|
|
if ( m_ContainerData == null )
|
|
UpdateContainerData();
|
|
|
|
return m_ContainerData;
|
|
}
|
|
set{ m_ContainerData = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public override int ItemID
|
|
{
|
|
get{ return base.ItemID; }
|
|
set
|
|
{
|
|
int oldID = this.ItemID;
|
|
|
|
base.ItemID = value;
|
|
|
|
if ( this.ItemID != oldID )
|
|
UpdateContainerData();
|
|
}
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int GumpID
|
|
{
|
|
get{ return ( m_GumpID == -1 ? DefaultGumpID : m_GumpID ); }
|
|
set{ m_GumpID = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int DropSound
|
|
{
|
|
get{ return ( m_DropSound == -1 ? DefaultDropSound : m_DropSound ); }
|
|
set{ m_DropSound = value; }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public int MaxItems
|
|
{
|
|
get{ return ( m_MaxItems == -1 ? DefaultMaxItems : m_MaxItems ); }
|
|
set{ m_MaxItems = value; InvalidateProperties(); }
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public virtual int MaxWeight
|
|
{
|
|
get
|
|
{
|
|
if ( Parent is Container && ((Container)Parent).MaxWeight == 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return DefaultMaxWeight;
|
|
}
|
|
}
|
|
}
|
|
|
|
[CommandProperty( AccessLevel.GameMaster )]
|
|
public bool LiftOverride
|
|
{
|
|
get{ return m_LiftOverride; }
|
|
set{ m_LiftOverride = value; }
|
|
}
|
|
|
|
public virtual void UpdateContainerData()
|
|
{
|
|
this.ContainerData = ContainerData.GetData( this.ItemID );
|
|
}
|
|
|
|
public virtual Rectangle2D Bounds{ get{ return ContainerData.Bounds; } }
|
|
public virtual int DefaultGumpID{ get{ return ContainerData.GumpID; } }
|
|
public virtual int DefaultDropSound{ get{ return ContainerData.DropSound; } }
|
|
|
|
public virtual int DefaultMaxItems{ get{ return m_GlobalMaxItems; } }
|
|
public virtual int DefaultMaxWeight{ get{ return m_GlobalMaxWeight; } }
|
|
|
|
public virtual bool IsDecoContainer
|
|
{
|
|
get{ return !Movable && !IsLockedDown && !IsSecure && Parent == null && !m_LiftOverride; }
|
|
}
|
|
|
|
public virtual int GetDroppedSound( Item item )
|
|
{
|
|
int dropSound = item.GetDropSound();
|
|
|
|
return dropSound != -1 ? dropSound : DropSound;
|
|
}
|
|
|
|
public override void OnSnoop( Mobile from )
|
|
{
|
|
if ( m_SnoopHandler != null )
|
|
m_SnoopHandler( this, from );
|
|
}
|
|
|
|
public override bool CheckLift( Mobile from, Item item, ref LRReason reject )
|
|
{
|
|
if ( from.AccessLevel < AccessLevel.GameMaster && IsDecoContainer )
|
|
{
|
|
reject = LRReason.CannotLift;
|
|
return false;
|
|
}
|
|
|
|
return base.CheckLift( from, item, ref reject );
|
|
}
|
|
|
|
public override bool CheckItemUse( Mobile from, Item item )
|
|
{
|
|
if ( item != this && from.AccessLevel < AccessLevel.GameMaster && IsDecoContainer )
|
|
{
|
|
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
|
|
return false;
|
|
}
|
|
|
|
return base.CheckItemUse( from, item );
|
|
}
|
|
|
|
public bool CheckHold( Mobile m, Item item, bool message )
|
|
{
|
|
return CheckHold( m, item, message, true, 0, 0 );
|
|
}
|
|
|
|
public bool CheckHold( Mobile m, Item item, bool message, bool checkItems )
|
|
{
|
|
return CheckHold( m, item, message, checkItems, 0, 0 );
|
|
}
|
|
|
|
public virtual bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight )
|
|
{
|
|
if ( m.AccessLevel < AccessLevel.GameMaster )
|
|
{
|
|
if ( IsDecoContainer )
|
|
{
|
|
if ( message )
|
|
SendCantStoreMessage( m, item );
|
|
|
|
return false;
|
|
}
|
|
|
|
int maxItems = this.MaxItems;
|
|
|
|
if ( checkItems && maxItems != 0 && (this.TotalItems + plusItems + item.TotalItems + (item.IsVirtualItem ? 0 : 1)) > maxItems )
|
|
{
|
|
if ( message )
|
|
SendFullItemsMessage( m, item );
|
|
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
int maxWeight = this.MaxWeight;
|
|
|
|
if ( maxWeight != 0 && (this.TotalWeight + plusWeight + item.TotalWeight + item.PileWeight) > maxWeight )
|
|
{
|
|
if ( message )
|
|
SendFullWeightMessage( m, item );
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
object parent = this.Parent;
|
|
|
|
while ( parent != null )
|
|
{
|
|
if ( parent is Container )
|
|
return ((Container)parent).CheckHold( m, item, message, checkItems, plusItems, plusWeight );
|
|
else if ( parent is Item )
|
|
parent = ((Item)parent).Parent;
|
|
else
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public virtual void SendFullItemsMessage( Mobile to, Item item )
|
|
{
|
|
to.SendMessage( "That container cannot hold more items." );
|
|
}
|
|
|
|
public virtual void SendFullWeightMessage( Mobile to, Item item )
|
|
{
|
|
to.SendMessage( "That container cannot hold more weight." );
|
|
}
|
|
|
|
public virtual void SendCantStoreMessage( Mobile to, Item item )
|
|
{
|
|
to.SendLocalizedMessage( 500176 ); // That is not your container, you can't store things here.
|
|
}
|
|
|
|
public virtual bool OnDragDropInto( Mobile from, Item item, Point3D p )
|
|
{
|
|
if ( !CheckHold( from, item, true, true ) )
|
|
return false;
|
|
|
|
item.Location = new Point3D( p.m_X, p.m_Y, 0 );
|
|
AddItem( item );
|
|
|
|
from.SendSound( GetDroppedSound( item ), GetWorldLocation() );
|
|
|
|
return true;
|
|
}
|
|
|
|
private class GroupComparer : IComparer
|
|
{
|
|
private CheckItemGroup m_Grouper;
|
|
|
|
public GroupComparer( CheckItemGroup grouper )
|
|
{
|
|
m_Grouper = grouper;
|
|
}
|
|
|
|
public int Compare( object x, object y )
|
|
{
|
|
Item a = (Item)x;
|
|
Item b = (Item)y;
|
|
|
|
return m_Grouper( a, b );
|
|
}
|
|
}
|
|
|
|
#region Consume[...]
|
|
|
|
public bool ConsumeTotalGrouped( Type type, int amount, bool recurse, OnItemConsumed callback, CheckItemGroup grouper )
|
|
{
|
|
if ( grouper == null )
|
|
throw new ArgumentNullException();
|
|
|
|
Item[] typedItems = FindItemsByType( type, recurse );
|
|
|
|
List<List<Item>> groups = new List<List<Item>>();
|
|
int idx = 0;
|
|
|
|
while ( idx < typedItems.Length )
|
|
{
|
|
Item a = typedItems[idx++];
|
|
List<Item> group = new List<Item>();
|
|
|
|
group.Add( a );
|
|
|
|
while ( idx < typedItems.Length )
|
|
{
|
|
Item b = typedItems[idx];
|
|
int v = grouper( a, b );
|
|
|
|
if ( v == 0 )
|
|
group.Add( b );
|
|
else
|
|
break;
|
|
|
|
++idx;
|
|
}
|
|
|
|
groups.Add( group );
|
|
}
|
|
|
|
Item[][] items = new Item[groups.Count][];
|
|
int[] totals = new int[groups.Count];
|
|
|
|
bool hasEnough = false;
|
|
|
|
for ( int i = 0; i < groups.Count; ++i )
|
|
{
|
|
items[i] = groups[i].ToArray();
|
|
//items[i] = (Item[])(((ArrayList)groups[i]).ToArray( typeof( Item ) ));
|
|
|
|
for ( int j = 0; j < items[i].Length; ++j )
|
|
totals[i] += items[i][j].Amount;
|
|
|
|
if ( totals[i] >= amount )
|
|
hasEnough = true;
|
|
}
|
|
|
|
if ( !hasEnough )
|
|
return false;
|
|
|
|
for ( int i = 0; i < items.Length; ++i )
|
|
{
|
|
if ( totals[i] >= amount )
|
|
{
|
|
int need = amount;
|
|
|
|
for ( int j = 0; j < items[i].Length; ++j )
|
|
{
|
|
Item item = items[i][j];
|
|
|
|
int theirAmount = item.Amount;
|
|
|
|
if ( theirAmount < need )
|
|
{
|
|
if ( callback != null )
|
|
callback( item, theirAmount );
|
|
|
|
item.Delete();
|
|
need -= theirAmount;
|
|
}
|
|
else
|
|
{
|
|
if ( callback != null )
|
|
callback( item, need );
|
|
|
|
item.Consume( need );
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public int ConsumeTotalGrouped( Type[] types, int[] amounts, bool recurse, OnItemConsumed callback, CheckItemGroup grouper )
|
|
{
|
|
if ( types.Length != amounts.Length )
|
|
throw new ArgumentException();
|
|
else if ( grouper == null )
|
|
throw new ArgumentNullException();
|
|
|
|
Item[][][] items = new Item[types.Length][][];
|
|
int[][] totals = new int[types.Length][];
|
|
|
|
for ( int i = 0; i < types.Length; ++i )
|
|
{
|
|
Item[] typedItems = FindItemsByType( types[i], recurse );
|
|
|
|
List<List<Item>> groups = new List<List<Item>>();
|
|
int idx = 0;
|
|
|
|
while ( idx < typedItems.Length )
|
|
{
|
|
Item a = typedItems[idx++];
|
|
List<Item> group = new List<Item>();
|
|
|
|
group.Add( a );
|
|
|
|
while ( idx < typedItems.Length )
|
|
{
|
|
Item b = typedItems[idx];
|
|
int v = grouper( a, b );
|
|
|
|
if ( v == 0 )
|
|
group.Add( b );
|
|
else
|
|
break;
|
|
|
|
++idx;
|
|
}
|
|
|
|
groups.Add( group );
|
|
}
|
|
|
|
items[i] = new Item[groups.Count][];
|
|
totals[i] = new int[groups.Count];
|
|
|
|
bool hasEnough = false;
|
|
|
|
for ( int j = 0; j < groups.Count; ++j )
|
|
{
|
|
items[i][j] = groups[j].ToArray();
|
|
//items[i][j] = (Item[])(((ArrayList)groups[j]).ToArray( typeof( Item ) ));
|
|
|
|
for ( int k = 0; k < items[i][j].Length; ++k )
|
|
totals[i][j] += items[i][j][k].Amount;
|
|
|
|
if ( totals[i][j] >= amounts[i] )
|
|
hasEnough = true;
|
|
}
|
|
|
|
if ( !hasEnough )
|
|
return i;
|
|
}
|
|
|
|
for ( int i = 0; i < items.Length; ++i )
|
|
{
|
|
for ( int j = 0; j < items[i].Length; ++j )
|
|
{
|
|
if ( totals[i][j] >= amounts[i] )
|
|
{
|
|
int need = amounts[i];
|
|
|
|
for ( int k = 0; k < items[i][j].Length; ++k )
|
|
{
|
|
Item item = items[i][j][k];
|
|
|
|
int theirAmount = item.Amount;
|
|
|
|
if ( theirAmount < need )
|
|
{
|
|
if ( callback != null )
|
|
callback( item, theirAmount );
|
|
|
|
item.Delete();
|
|
need -= theirAmount;
|
|
}
|
|
else
|
|
{
|
|
if ( callback != null )
|
|
callback( item, need );
|
|
|
|
item.Consume( need );
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public int ConsumeTotalGrouped( Type[][] types, int[] amounts, bool recurse, OnItemConsumed callback, CheckItemGroup grouper )
|
|
{
|
|
if ( types.Length != amounts.Length )
|
|
throw new ArgumentException();
|
|
else if ( grouper == null )
|
|
throw new ArgumentNullException();
|
|
|
|
Item[][][] items = new Item[types.Length][][];
|
|
int[][] totals = new int[types.Length][];
|
|
|
|
for ( int i = 0; i < types.Length; ++i )
|
|
{
|
|
Item[] typedItems = FindItemsByType( types[i], recurse );
|
|
|
|
List<List<Item>> groups = new List<List<Item>>();
|
|
int idx = 0;
|
|
|
|
while ( idx < typedItems.Length )
|
|
{
|
|
Item a = typedItems[idx++];
|
|
List<Item> group = new List<Item>();
|
|
|
|
group.Add( a );
|
|
|
|
while ( idx < typedItems.Length )
|
|
{
|
|
Item b = typedItems[idx];
|
|
int v = grouper( a, b );
|
|
|
|
if ( v == 0 )
|
|
group.Add( b );
|
|
else
|
|
break;
|
|
|
|
++idx;
|
|
}
|
|
|
|
groups.Add( group );
|
|
}
|
|
|
|
items[i] = new Item[groups.Count][];
|
|
totals[i] = new int[groups.Count];
|
|
|
|
bool hasEnough = false;
|
|
|
|
for ( int j = 0; j < groups.Count; ++j )
|
|
{
|
|
items[i][j] = groups[j].ToArray();
|
|
|
|
for ( int k = 0; k < items[i][j].Length; ++k )
|
|
totals[i][j] += items[i][j][k].Amount;
|
|
|
|
if ( totals[i][j] >= amounts[i] )
|
|
hasEnough = true;
|
|
}
|
|
|
|
if ( !hasEnough )
|
|
return i;
|
|
}
|
|
|
|
for ( int i = 0; i < items.Length; ++i )
|
|
{
|
|
for ( int j = 0; j < items[i].Length; ++j )
|
|
{
|
|
if ( totals[i][j] >= amounts[i] )
|
|
{
|
|
int need = amounts[i];
|
|
|
|
for ( int k = 0; k < items[i][j].Length; ++k )
|
|
{
|
|
Item item = items[i][j][k];
|
|
|
|
int theirAmount = item.Amount;
|
|
|
|
if ( theirAmount < need )
|
|
{
|
|
if ( callback != null )
|
|
callback( item, theirAmount );
|
|
|
|
item.Delete();
|
|
need -= theirAmount;
|
|
}
|
|
else
|
|
{
|
|
if ( callback != null )
|
|
callback( item, need );
|
|
|
|
item.Consume( need );
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public int ConsumeTotal( Type[][] types, int[] amounts )
|
|
{
|
|
return ConsumeTotal( types, amounts, true, null );
|
|
}
|
|
|
|
public int ConsumeTotal( Type[][] types, int[] amounts, bool recurse )
|
|
{
|
|
return ConsumeTotal( types, amounts, recurse, null );
|
|
}
|
|
|
|
public int ConsumeTotal( Type[][] types, int[] amounts, bool recurse, OnItemConsumed callback )
|
|
{
|
|
if ( types.Length != amounts.Length )
|
|
throw new ArgumentException();
|
|
|
|
Item[][] items = new Item[types.Length][];
|
|
int[] totals = new int[types.Length];
|
|
|
|
for ( int i = 0; i < types.Length; ++i )
|
|
{
|
|
items[i] = FindItemsByType( types[i], recurse );
|
|
|
|
for ( int j = 0; j < items[i].Length; ++j )
|
|
totals[i] += items[i][j].Amount;
|
|
|
|
if ( totals[i] < amounts[i] )
|
|
return i;
|
|
}
|
|
|
|
for ( int i = 0; i < types.Length; ++i )
|
|
{
|
|
int need = amounts[i];
|
|
|
|
for ( int j = 0; j < items[i].Length; ++j )
|
|
{
|
|
Item item = items[i][j];
|
|
|
|
int theirAmount = item.Amount;
|
|
|
|
if ( theirAmount < need )
|
|
{
|
|
if ( callback != null )
|
|
callback( item, theirAmount );
|
|
|
|
item.Delete();
|
|
need -= theirAmount;
|
|
}
|
|
else
|
|
{
|
|
if ( callback != null )
|
|
callback( item, need );
|
|
|
|
item.Consume( need );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public int ConsumeTotal( Type[] types, int[] amounts )
|
|
{
|
|
return ConsumeTotal( types, amounts, true, null );
|
|
}
|
|
|
|
public int ConsumeTotal( Type[] types, int[] amounts, bool recurse )
|
|
{
|
|
return ConsumeTotal( types, amounts, recurse, null );
|
|
}
|
|
|
|
public int ConsumeTotal( Type[] types, int[] amounts, bool recurse, OnItemConsumed callback )
|
|
{
|
|
if ( types.Length != amounts.Length )
|
|
throw new ArgumentException();
|
|
|
|
Item[][] items = new Item[types.Length][];
|
|
int[] totals = new int[types.Length];
|
|
|
|
for ( int i = 0; i < types.Length; ++i )
|
|
{
|
|
items[i] = FindItemsByType( types[i], recurse );
|
|
|
|
for ( int j = 0; j < items[i].Length; ++j )
|
|
totals[i] += items[i][j].Amount;
|
|
|
|
if ( totals[i] < amounts[i] )
|
|
return i;
|
|
}
|
|
|
|
for ( int i = 0; i < types.Length; ++i )
|
|
{
|
|
int need = amounts[i];
|
|
|
|
for ( int j = 0; j < items[i].Length; ++j )
|
|
{
|
|
Item item = items[i][j];
|
|
|
|
int theirAmount = item.Amount;
|
|
|
|
if ( theirAmount < need )
|
|
{
|
|
if ( callback != null )
|
|
callback( item, theirAmount );
|
|
|
|
item.Delete();
|
|
need -= theirAmount;
|
|
}
|
|
else
|
|
{
|
|
if ( callback != null )
|
|
callback( item, need );
|
|
|
|
item.Consume( need );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public bool ConsumeTotal( Type type, int amount )
|
|
{
|
|
return ConsumeTotal( type, amount, true, null );
|
|
}
|
|
|
|
public bool ConsumeTotal( Type type, int amount, bool recurse )
|
|
{
|
|
return ConsumeTotal( type, amount, recurse, null );
|
|
}
|
|
|
|
public bool ConsumeTotal( Type type, int amount, bool recurse, OnItemConsumed callback )
|
|
{
|
|
Item[] items = FindItemsByType( type, recurse );
|
|
|
|
// First pass, compute total
|
|
int total = 0;
|
|
|
|
for( int i = 0; i < items.Length; ++i )
|
|
total += items[i].Amount;
|
|
|
|
if( total >= amount )
|
|
{
|
|
// We've enough, so consume it
|
|
|
|
int need = amount;
|
|
|
|
for( int i = 0; i < items.Length; ++i )
|
|
{
|
|
Item item = items[i];
|
|
|
|
int theirAmount = item.Amount;
|
|
|
|
if( theirAmount < need )
|
|
{
|
|
if( callback != null )
|
|
callback( item, theirAmount );
|
|
|
|
item.Delete();
|
|
need -= theirAmount;
|
|
}
|
|
else
|
|
{
|
|
if( callback != null )
|
|
callback( item, need );
|
|
|
|
item.Consume( need );
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public int ConsumeUpTo( Type type, int amount )
|
|
{
|
|
return ConsumeUpTo( type, amount, true );
|
|
}
|
|
|
|
public int ConsumeUpTo( Type type, int amount, bool recurse )
|
|
{
|
|
int consumed = 0;
|
|
|
|
Queue<Item> toDelete = new Queue<Item>();
|
|
|
|
RecurseConsumeUpTo( this, type, amount, recurse, ref consumed, toDelete );
|
|
|
|
while( toDelete.Count > 0 )
|
|
toDelete.Dequeue().Delete();
|
|
|
|
return consumed;
|
|
}
|
|
|
|
private static void RecurseConsumeUpTo( Item current, Type type, int amount, bool recurse, ref int consumed, Queue<Item> toDelete )
|
|
{
|
|
if( current != null && current.Items.Count > 0 )
|
|
{
|
|
List<Item> list = current.Items;
|
|
|
|
for( int i = 0; i < list.Count; ++i )
|
|
{
|
|
Item item = list[i];
|
|
|
|
if( type.IsAssignableFrom( item.GetType() ) )
|
|
{
|
|
int need = amount - consumed;
|
|
int theirAmount = item.Amount;
|
|
|
|
if( theirAmount <= need )
|
|
{
|
|
toDelete.Enqueue( item );
|
|
consumed += theirAmount;
|
|
}
|
|
else
|
|
{
|
|
item.Amount -= need;
|
|
consumed += need;
|
|
|
|
return;
|
|
}
|
|
}
|
|
else if( recurse && item is Container )
|
|
{
|
|
RecurseConsumeUpTo( item, type, amount, recurse, ref consumed, toDelete );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Get[BestGroup]Amount
|
|
public int GetBestGroupAmount( Type type, bool recurse, CheckItemGroup grouper )
|
|
{
|
|
if( grouper == null )
|
|
throw new ArgumentNullException();
|
|
|
|
int best = 0;
|
|
|
|
Item[] typedItems = FindItemsByType( type, recurse );
|
|
|
|
List<List<Item>> groups = new List<List<Item>>();
|
|
int idx = 0;
|
|
|
|
while( idx < typedItems.Length )
|
|
{
|
|
Item a = typedItems[idx++];
|
|
List<Item> group = new List<Item>();
|
|
|
|
group.Add( a );
|
|
|
|
while( idx < typedItems.Length )
|
|
{
|
|
Item b = typedItems[idx];
|
|
int v = grouper( a, b );
|
|
|
|
if( v == 0 )
|
|
group.Add( b );
|
|
else
|
|
break;
|
|
|
|
++idx;
|
|
}
|
|
|
|
groups.Add( group );
|
|
}
|
|
|
|
for( int i = 0; i < groups.Count; ++i )
|
|
{
|
|
Item[] items = groups[i].ToArray();
|
|
|
|
//Item[] items = (Item[])(((ArrayList)groups[i]).ToArray( typeof( Item ) ));
|
|
int total = 0;
|
|
|
|
for( int j = 0; j < items.Length; ++j )
|
|
total += items[j].Amount;
|
|
|
|
if( total >= best )
|
|
best = total;
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
public int GetBestGroupAmount( Type[] types, bool recurse, CheckItemGroup grouper )
|
|
{
|
|
if( grouper == null )
|
|
throw new ArgumentNullException();
|
|
|
|
int best = 0;
|
|
|
|
Item[] typedItems = FindItemsByType( types, recurse );
|
|
|
|
List<List<Item>> groups = new List<List<Item>>();
|
|
int idx = 0;
|
|
|
|
while( idx < typedItems.Length )
|
|
{
|
|
Item a = typedItems[idx++];
|
|
List<Item> group = new List<Item>();
|
|
|
|
group.Add( a );
|
|
|
|
while( idx < typedItems.Length )
|
|
{
|
|
Item b = typedItems[idx];
|
|
int v = grouper( a, b );
|
|
|
|
if( v == 0 )
|
|
group.Add( b );
|
|
else
|
|
break;
|
|
|
|
++idx;
|
|
}
|
|
|
|
groups.Add( group );
|
|
}
|
|
|
|
for( int j = 0; j < groups.Count; ++j )
|
|
{
|
|
Item[] items = groups[j].ToArray();
|
|
//Item[] items = (Item[])(((ArrayList)groups[j]).ToArray( typeof( Item ) ));
|
|
int total = 0;
|
|
|
|
for( int k = 0; k < items.Length; ++k )
|
|
total += items[k].Amount;
|
|
|
|
if( total >= best )
|
|
best = total;
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
public int GetBestGroupAmount( Type[][] types, bool recurse, CheckItemGroup grouper )
|
|
{
|
|
if( grouper == null )
|
|
throw new ArgumentNullException();
|
|
|
|
int best = 0;
|
|
|
|
for( int i = 0; i < types.Length; ++i )
|
|
{
|
|
Item[] typedItems = FindItemsByType( types[i], recurse );
|
|
|
|
List<List<Item>> groups = new List<List<Item>>();
|
|
int idx = 0;
|
|
|
|
while( idx < typedItems.Length )
|
|
{
|
|
Item a = typedItems[idx++];
|
|
List<Item> group = new List<Item>();
|
|
|
|
group.Add( a );
|
|
|
|
while( idx < typedItems.Length )
|
|
{
|
|
Item b = typedItems[idx];
|
|
int v = grouper( a, b );
|
|
|
|
if( v == 0 )
|
|
group.Add( b );
|
|
else
|
|
break;
|
|
|
|
++idx;
|
|
}
|
|
|
|
groups.Add( group );
|
|
}
|
|
|
|
for( int j = 0; j < groups.Count; ++j )
|
|
{
|
|
Item[] items = groups[j].ToArray();
|
|
//Item[] items = (Item[])(((ArrayList)groups[j]).ToArray( typeof( Item ) ));
|
|
int total = 0;
|
|
|
|
for( int k = 0; k < items.Length; ++k )
|
|
total += items[k].Amount;
|
|
|
|
if( total >= best )
|
|
best = total;
|
|
}
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
public int GetAmount( Type type )
|
|
{
|
|
return GetAmount( type, true );
|
|
}
|
|
|
|
public int GetAmount( Type type, bool recurse )
|
|
{
|
|
Item[] items = FindItemsByType( type, recurse );
|
|
|
|
int amount = 0;
|
|
|
|
for ( int i = 0; i < items.Length; ++i )
|
|
amount += items[i].Amount;
|
|
|
|
return amount;
|
|
}
|
|
|
|
public int GetAmount( Type[] types )
|
|
{
|
|
return GetAmount( types, true );
|
|
}
|
|
|
|
public int GetAmount( Type[] types, bool recurse )
|
|
{
|
|
Item[] items = FindItemsByType( types, recurse );
|
|
|
|
int amount = 0;
|
|
|
|
for ( int i = 0; i < items.Length; ++i )
|
|
amount += items[i].Amount;
|
|
|
|
return amount;
|
|
}
|
|
#endregion
|
|
|
|
private static List<Item> m_FindItemsList = new List<Item>();
|
|
|
|
#region Non-Generic FindItem[s] by Type
|
|
public Item[] FindItemsByType( Type type )
|
|
{
|
|
return FindItemsByType( type, true );
|
|
}
|
|
|
|
public Item[] FindItemsByType( Type type, bool recurse )
|
|
{
|
|
if ( m_FindItemsList.Count > 0 )
|
|
m_FindItemsList.Clear();
|
|
|
|
RecurseFindItemsByType( this, type, recurse, m_FindItemsList );
|
|
|
|
return m_FindItemsList.ToArray();
|
|
}
|
|
|
|
private static void RecurseFindItemsByType( Item current, Type type, bool recurse, List<Item> list )
|
|
{
|
|
if ( current != null && current.Items.Count > 0 )
|
|
{
|
|
List<Item> items = current.Items;
|
|
|
|
for ( int i = 0; i < items.Count; ++i )
|
|
{
|
|
Item item = items[i];
|
|
|
|
if ( type.IsAssignableFrom( item.GetType() ) )// item.GetType().IsAssignableFrom( type ) )
|
|
list.Add( item );
|
|
|
|
if ( recurse && item is Container )
|
|
RecurseFindItemsByType( item, type, recurse, list );
|
|
}
|
|
}
|
|
}
|
|
|
|
public Item[] FindItemsByType( Type[] types )
|
|
{
|
|
return FindItemsByType( types, true );
|
|
}
|
|
|
|
public Item[] FindItemsByType( Type[] types, bool recurse )
|
|
{
|
|
if( m_FindItemsList.Count > 0 )
|
|
m_FindItemsList.Clear();
|
|
|
|
RecurseFindItemsByType( this, types, recurse, m_FindItemsList );
|
|
|
|
return m_FindItemsList.ToArray();
|
|
}
|
|
|
|
private static void RecurseFindItemsByType( Item current, Type[] types, bool recurse, List<Item> list )
|
|
{
|
|
if( current != null && current.Items.Count > 0 )
|
|
{
|
|
List<Item> items = current.Items;
|
|
|
|
for( int i = 0; i < items.Count; ++i )
|
|
{
|
|
Item item = items[i];
|
|
|
|
if( InTypeList( item, types ) )
|
|
list.Add( item );
|
|
|
|
if( recurse && item is Container )
|
|
RecurseFindItemsByType( item, types, recurse, list );
|
|
}
|
|
}
|
|
}
|
|
|
|
public Item FindItemByType( Type type )
|
|
{
|
|
return FindItemByType( type, true );
|
|
}
|
|
|
|
public Item FindItemByType( Type type, bool recurse )
|
|
{
|
|
return RecurseFindItemByType( this, type, recurse );
|
|
}
|
|
|
|
private static Item RecurseFindItemByType( Item current, Type type, bool recurse )
|
|
{
|
|
if( current != null && current.Items.Count > 0 )
|
|
{
|
|
List<Item> list = current.Items;
|
|
|
|
for( int i = 0; i < list.Count; ++i )
|
|
{
|
|
Item item = list[i];
|
|
|
|
if( type.IsAssignableFrom( item.GetType() ) )
|
|
{
|
|
return item;
|
|
}
|
|
else if( recurse && item is Container )
|
|
{
|
|
Item check = RecurseFindItemByType( item, type, recurse );
|
|
|
|
if( check != null )
|
|
return check;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public Item FindItemByType( Type[] types )
|
|
{
|
|
return FindItemByType( types, true );
|
|
}
|
|
|
|
public Item FindItemByType( Type[] types, bool recurse )
|
|
{
|
|
return RecurseFindItemByType( this, types, recurse );
|
|
}
|
|
|
|
private static Item RecurseFindItemByType( Item current, Type[] types, bool recurse )
|
|
{
|
|
if( current != null && current.Items.Count > 0 )
|
|
{
|
|
List<Item> list = current.Items;
|
|
|
|
for( int i = 0; i < list.Count; ++i )
|
|
{
|
|
Item item = list[i];
|
|
|
|
if( InTypeList( item, types ) )
|
|
{
|
|
return item;
|
|
}
|
|
else if( recurse && item is Container )
|
|
{
|
|
Item check = RecurseFindItemByType( item, types, recurse );
|
|
|
|
if( check != null )
|
|
return check;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Generic FindItem[s] by Type
|
|
public List<T> FindItemsByType<T>() where T : Item
|
|
{
|
|
return FindItemsByType<T>( true, null );
|
|
}
|
|
|
|
public List<T> FindItemsByType<T>( bool recurse ) where T : Item
|
|
{
|
|
return FindItemsByType<T>( recurse, null );
|
|
}
|
|
|
|
public List<T> FindItemsByType<T>( Predicate<T> predicate ) where T : Item
|
|
{
|
|
return FindItemsByType<T>( true, predicate );
|
|
}
|
|
|
|
public List<T> FindItemsByType<T>( bool recurse, Predicate<T> predicate ) where T : Item
|
|
{
|
|
if( m_FindItemsList.Count > 0 )
|
|
m_FindItemsList.Clear();
|
|
|
|
List<T> list = new List<T>();
|
|
|
|
RecurseFindItemsByType<T>( this, recurse, list, predicate );
|
|
|
|
return list;
|
|
}
|
|
|
|
private static void RecurseFindItemsByType<T>( Item current, bool recurse, List<T> list, Predicate<T> predicate ) where T : Item
|
|
{
|
|
if( current != null && current.Items.Count > 0 )
|
|
{
|
|
List<Item> items = current.Items;
|
|
|
|
for( int i = 0; i < items.Count; ++i )
|
|
{
|
|
Item item = items[i];
|
|
|
|
if( typeof( T ).IsAssignableFrom( item.GetType() ) )
|
|
{
|
|
T typedItem = (T)item;
|
|
|
|
if( predicate == null || predicate( typedItem ) )
|
|
list.Add( typedItem );
|
|
}
|
|
|
|
if( recurse && item is Container )
|
|
RecurseFindItemsByType<T>( item, recurse, list, predicate );
|
|
}
|
|
}
|
|
}
|
|
|
|
public T FindItemByType<T>() where T : Item
|
|
{
|
|
return FindItemByType<T>( true );
|
|
}
|
|
|
|
|
|
public T FindItemByType<T>( Predicate<T> predicate ) where T : Item
|
|
{
|
|
return FindItemByType<T>( true, predicate );
|
|
}
|
|
|
|
public T FindItemByType<T>( bool recurse ) where T : Item
|
|
{
|
|
return FindItemByType<T>( recurse, null );
|
|
}
|
|
|
|
public T FindItemByType<T>( bool recurse, Predicate<T> predicate ) where T : Item
|
|
{
|
|
return RecurseFindItemByType<T>( this, recurse, predicate );
|
|
}
|
|
|
|
private static T RecurseFindItemByType<T>( Item current, bool recurse, Predicate<T> predicate ) where T : Item
|
|
{
|
|
if( current != null && current.Items.Count > 0 )
|
|
{
|
|
List<Item> list = current.Items;
|
|
|
|
for( int i = 0; i < list.Count; ++i )
|
|
{
|
|
Item item = list[i];
|
|
|
|
if( typeof( T ).IsAssignableFrom( item.GetType() ) )
|
|
{
|
|
T typedItem = (T)item;
|
|
|
|
if( predicate == null || predicate( typedItem ) )
|
|
return typedItem;
|
|
}
|
|
else if( recurse && item is Container )
|
|
{
|
|
T check = RecurseFindItemByType<T>( item, recurse, predicate );
|
|
|
|
if( check != null )
|
|
return check;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
#endregion
|
|
|
|
|
|
private static bool InTypeList( Item item, Type[] types )
|
|
{
|
|
Type t = item.GetType();
|
|
|
|
for ( int i = 0; i < types.Length; ++i )
|
|
if ( types[i].IsAssignableFrom( t ) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
private static void SetSaveFlag( ref SaveFlag flags, SaveFlag toSet, bool setIf )
|
|
{
|
|
if ( setIf )
|
|
flags |= toSet;
|
|
}
|
|
|
|
private static bool GetSaveFlag( SaveFlag flags, SaveFlag toGet )
|
|
{
|
|
return ( (flags & toGet) != 0 );
|
|
}
|
|
|
|
[Flags]
|
|
private enum SaveFlag : byte
|
|
{
|
|
None = 0x00000000,
|
|
MaxItems = 0x00000001,
|
|
GumpID = 0x00000002,
|
|
DropSound = 0x00000004,
|
|
LiftOverride = 0x00000008
|
|
}
|
|
|
|
public override void Serialize( GenericWriter writer )
|
|
{
|
|
base.Serialize( writer );
|
|
|
|
writer.Write( (int) 2 ); // version
|
|
|
|
SaveFlag flags = SaveFlag.None;
|
|
|
|
SetSaveFlag( ref flags, SaveFlag.MaxItems, m_MaxItems != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.GumpID, m_GumpID != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.DropSound, m_DropSound != -1 );
|
|
SetSaveFlag( ref flags, SaveFlag.LiftOverride, m_LiftOverride );
|
|
|
|
writer.Write( (byte) flags );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MaxItems ) )
|
|
writer.WriteEncodedInt( (int) m_MaxItems );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.GumpID ) )
|
|
writer.WriteEncodedInt( (int) m_GumpID );
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.DropSound ) )
|
|
writer.WriteEncodedInt( (int) m_DropSound );
|
|
}
|
|
|
|
public override void Deserialize( GenericReader reader )
|
|
{
|
|
base.Deserialize( reader );
|
|
|
|
int version = reader.ReadInt();
|
|
|
|
switch ( version )
|
|
{
|
|
case 2:
|
|
{
|
|
SaveFlag flags = (SaveFlag)reader.ReadByte();
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.MaxItems ) )
|
|
m_MaxItems = reader.ReadEncodedInt();
|
|
else
|
|
m_MaxItems = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.GumpID ) )
|
|
m_GumpID = reader.ReadEncodedInt();
|
|
else
|
|
m_GumpID = -1;
|
|
|
|
if ( GetSaveFlag( flags, SaveFlag.DropSound ) )
|
|
m_DropSound = reader.ReadEncodedInt();
|
|
else
|
|
m_DropSound = -1;
|
|
|
|
m_LiftOverride = GetSaveFlag( flags, SaveFlag.LiftOverride );
|
|
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
m_MaxItems = reader.ReadInt();
|
|
goto case 0;
|
|
}
|
|
case 0:
|
|
{
|
|
if ( version < 1 )
|
|
m_MaxItems = m_GlobalMaxItems;
|
|
|
|
m_GumpID = reader.ReadInt();
|
|
m_DropSound = reader.ReadInt();
|
|
|
|
if ( m_GumpID == DefaultGumpID )
|
|
m_GumpID = -1;
|
|
|
|
if ( m_DropSound == DefaultDropSound )
|
|
m_DropSound = -1;
|
|
|
|
if ( m_MaxItems == DefaultMaxItems )
|
|
m_MaxItems = -1;
|
|
|
|
//m_Bounds = new Rectangle2D( reader.ReadPoint2D(), reader.ReadPoint2D() );
|
|
reader.ReadPoint2D();
|
|
reader.ReadPoint2D();
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
UpdateContainerData();
|
|
}
|
|
|
|
private static int m_GlobalMaxItems = 125;
|
|
private static int m_GlobalMaxWeight = 400;
|
|
|
|
public static int GlobalMaxItems{ get{ return m_GlobalMaxItems; } set{ m_GlobalMaxItems = value; } }
|
|
public static int GlobalMaxWeight{ get{ return m_GlobalMaxWeight; } set{ m_GlobalMaxWeight = value; } }
|
|
|
|
public Container( int itemID ) : base( itemID )
|
|
{
|
|
m_GumpID = -1;
|
|
m_DropSound = -1;
|
|
m_MaxItems = -1;
|
|
|
|
UpdateContainerData();
|
|
}
|
|
|
|
public override int GetTotal( TotalType type )
|
|
{
|
|
switch ( type )
|
|
{
|
|
case TotalType.Gold:
|
|
return m_TotalGold;
|
|
|
|
case TotalType.Items:
|
|
return m_TotalItems;
|
|
|
|
case TotalType.Weight:
|
|
return m_TotalWeight;
|
|
}
|
|
|
|
return base.GetTotal( type );
|
|
}
|
|
|
|
public override void UpdateTotal( Item sender, TotalType type, int delta )
|
|
{
|
|
if ( sender != this && delta != 0 && !sender.IsVirtualItem )
|
|
{
|
|
switch ( type )
|
|
{
|
|
case TotalType.Gold:
|
|
m_TotalGold += delta;
|
|
break;
|
|
|
|
case TotalType.Items:
|
|
m_TotalItems += delta;
|
|
InvalidateProperties();
|
|
break;
|
|
|
|
case TotalType.Weight:
|
|
m_TotalWeight += delta;
|
|
InvalidateProperties();
|
|
break;
|
|
}
|
|
}
|
|
|
|
base.UpdateTotal( sender, type, delta );
|
|
}
|
|
|
|
public override void UpdateTotals()
|
|
{
|
|
m_TotalGold = 0;
|
|
m_TotalItems = 0;
|
|
m_TotalWeight = 0;
|
|
|
|
List<Item> items = m_Items;
|
|
|
|
if ( items == null )
|
|
return;
|
|
|
|
for ( int i = 0; i < items.Count; ++i )
|
|
{
|
|
Item item = items[i];
|
|
|
|
item.UpdateTotals();
|
|
|
|
if ( item.IsVirtualItem )
|
|
continue;
|
|
|
|
m_TotalGold += item.TotalGold;
|
|
m_TotalItems += item.TotalItems + 1;
|
|
m_TotalWeight += item.TotalWeight + item.PileWeight;
|
|
}
|
|
}
|
|
|
|
public Container( Serial serial ) : base( serial )
|
|
{
|
|
}
|
|
|
|
public virtual bool OnStackAttempt( Mobile from, Item stack, Item dropped )
|
|
{
|
|
if ( !CheckHold( from, dropped, true, false ) )
|
|
return false;
|
|
|
|
return stack.StackWith( from, dropped );
|
|
}
|
|
|
|
public override bool OnDragDrop( Mobile from, Item dropped )
|
|
{
|
|
if ( TryDropItem( from, dropped, true ) )
|
|
{
|
|
from.SendSound( GetDroppedSound( dropped ), GetWorldLocation() );
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public virtual bool TryDropItem( Mobile from, Item dropped, bool sendFullMessage )
|
|
{
|
|
if ( !CheckHold( from, dropped, sendFullMessage, true ) )
|
|
return false;
|
|
|
|
List<Item> list = this.Items;
|
|
|
|
for ( int i = 0; i < list.Count; ++i )
|
|
{
|
|
Item item = list[i];
|
|
|
|
if ( !(item is Container) && item.StackWith( from, dropped, false ) )
|
|
return true;
|
|
}
|
|
|
|
DropItem( dropped );
|
|
|
|
return true;
|
|
}
|
|
|
|
public virtual void Destroy()
|
|
{
|
|
Point3D loc = GetWorldLocation();
|
|
Map map = Map;
|
|
|
|
for ( int i = Items.Count - 1; i >= 0; --i )
|
|
{
|
|
if ( i < Items.Count )
|
|
{
|
|
Items[i].SetLastMoved();
|
|
Items[i].MoveToWorld( loc, map );
|
|
}
|
|
}
|
|
|
|
Delete();
|
|
}
|
|
|
|
public virtual void DropItem( Item dropped )
|
|
{
|
|
if ( dropped == null )
|
|
return;
|
|
|
|
AddItem( dropped );
|
|
|
|
Rectangle2D bounds = dropped.GetGraphicBounds();
|
|
Rectangle2D ourBounds = this.Bounds;
|
|
|
|
int x, y;
|
|
|
|
if ( bounds.Width >= ourBounds.Width )
|
|
x = (ourBounds.Width - bounds.Width) / 2;
|
|
else
|
|
x = Utility.Random( ourBounds.Width - bounds.Width );
|
|
|
|
if ( bounds.Height >= ourBounds.Height )
|
|
y = (ourBounds.Height - bounds.Height) / 2;
|
|
else
|
|
y = Utility.Random( ourBounds.Height - bounds.Height );
|
|
|
|
x += ourBounds.X;
|
|
x -= bounds.X;
|
|
|
|
y += ourBounds.Y;
|
|
y -= bounds.Y;
|
|
|
|
dropped.Location = new Point3D( x, y, 0 );
|
|
}
|
|
|
|
public override void OnDoubleClickSecureTrade( Mobile from )
|
|
{
|
|
if ( from.InRange( GetWorldLocation(), 2 ) )
|
|
{
|
|
DisplayTo( from );
|
|
|
|
SecureTradeContainer cont = GetSecureTradeCont();
|
|
|
|
if ( cont != null )
|
|
{
|
|
SecureTrade trade = cont.Trade;
|
|
|
|
if ( trade != null && trade.From.Mobile == from )
|
|
DisplayTo( trade.To.Mobile );
|
|
else if ( trade != null && trade.To.Mobile == from )
|
|
DisplayTo( trade.From.Mobile );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage( 500446 ); // That is too far away.
|
|
}
|
|
}
|
|
|
|
public virtual bool DisplaysContent{ get{ return true; } }
|
|
|
|
public virtual bool CheckContentDisplay( Mobile from )
|
|
{
|
|
if ( !DisplaysContent )
|
|
return false;
|
|
|
|
object root = this.RootParent;
|
|
|
|
if ( root == null || root is Item || root == from || from.AccessLevel > AccessLevel.Player )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
public override void OnSingleClick( Mobile from )
|
|
{
|
|
base.OnSingleClick( from );
|
|
|
|
if ( CheckContentDisplay( from ) )
|
|
LabelTo( from, "({0} items, {1} stones)", TotalItems, TotalWeight );
|
|
}
|
|
|
|
private List<Mobile> m_Openers;
|
|
|
|
public List<Mobile> Openers
|
|
{
|
|
get{ return m_Openers; }
|
|
set{ m_Openers = value; }
|
|
}
|
|
|
|
public virtual bool IsPublicContainer{ get{ return false; } }
|
|
|
|
public override void OnDelete()
|
|
{
|
|
base.OnDelete();
|
|
|
|
m_Openers = null;
|
|
}
|
|
|
|
public virtual void DisplayTo( Mobile to )
|
|
{
|
|
ProcessOpeners( to );
|
|
|
|
NetState ns = to.NetState;
|
|
|
|
if ( ns == null )
|
|
return;
|
|
|
|
if ( ns.HighSeas )
|
|
to.Send( new ContainerDisplayHS( this ) );
|
|
else
|
|
to.Send( new ContainerDisplay( this ) );
|
|
|
|
if ( ns.ContainerGridLines )
|
|
to.Send( new ContainerContent6017( to, this ) );
|
|
else
|
|
to.Send( new ContainerContent( to, this ) );
|
|
|
|
if ( ObjectPropertyList.Enabled )
|
|
{
|
|
List<Item> items = this.Items;
|
|
|
|
for ( int i = 0; i < items.Count; ++i )
|
|
to.Send( items[i].OPLPacket );
|
|
}
|
|
|
|
to.SendMessage( String.Format( "This container has {0} items, weighing {1} stones", TotalItems, TotalWeight ) );
|
|
}
|
|
|
|
public void ProcessOpeners( Mobile opener )
|
|
{
|
|
if ( !IsPublicContainer )
|
|
{
|
|
bool contains = false;
|
|
|
|
if ( m_Openers != null )
|
|
{
|
|
Point3D worldLoc = GetWorldLocation();
|
|
Map map = this.Map;
|
|
|
|
for ( int i = 0; i < m_Openers.Count; ++i )
|
|
{
|
|
Mobile mob = m_Openers[i];
|
|
|
|
if ( mob == opener )
|
|
{
|
|
contains = true;
|
|
}
|
|
else
|
|
{
|
|
int range = GetUpdateRange( mob );
|
|
|
|
if ( mob.Map != map || !mob.InRange( worldLoc, range ) )
|
|
m_Openers.RemoveAt( i-- );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !contains )
|
|
{
|
|
if ( m_Openers == null )
|
|
{
|
|
m_Openers = new List<Mobile>();
|
|
}
|
|
|
|
m_Openers.Add( opener );
|
|
}
|
|
else if ( m_Openers != null && m_Openers.Count == 0 )
|
|
{
|
|
m_Openers = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void GetProperties( ObjectPropertyList list )
|
|
{
|
|
base.GetProperties( list );
|
|
}
|
|
|
|
public override void OnDoubleClick( Mobile from )
|
|
{
|
|
if ( from.AccessLevel > AccessLevel.Player || from.InRange( this.GetWorldLocation(), 2 ) )
|
|
DisplayTo( from );
|
|
else
|
|
from.SendLocalizedMessage( 500446 ); // That is too far away.
|
|
}
|
|
}
|
|
|
|
public class ContainerData
|
|
{
|
|
static ContainerData()
|
|
{
|
|
m_Table = new Dictionary<int, ContainerData>();
|
|
|
|
string path = Path.Combine( Core.BaseDirectory, "Data/Config/containers.cfg" );
|
|
|
|
if ( !File.Exists( path ) )
|
|
{
|
|
m_Default = new ContainerData( 0x3C, new Rectangle2D( 44, 65, 142, 94 ), 0x48 );
|
|
return;
|
|
}
|
|
|
|
using ( StreamReader reader = new StreamReader( path ) )
|
|
{
|
|
string line;
|
|
|
|
while ( (line = reader.ReadLine()) != null )
|
|
{
|
|
line = line.Trim();
|
|
|
|
if ( line.Length == 0 || line.StartsWith( "#" ) )
|
|
continue;
|
|
|
|
try
|
|
{
|
|
string[] split = line.Split( '\t' );
|
|
|
|
if ( split.Length >= 3 )
|
|
{
|
|
int gumpID = Utility.ToInt32( split[0] );
|
|
|
|
string[] aRect = split[1].Split( ' ' );
|
|
if ( aRect.Length < 4 )
|
|
continue;
|
|
|
|
int x = Utility.ToInt32( aRect[0] );
|
|
int y = Utility.ToInt32( aRect[1] );
|
|
int width = Utility.ToInt32( aRect[2] );
|
|
int height = Utility.ToInt32( aRect[3] );
|
|
|
|
Rectangle2D bounds = new Rectangle2D( x, y, width, height );
|
|
|
|
int dropSound = Utility.ToInt32( split[2] );
|
|
|
|
ContainerData data = new ContainerData( gumpID, bounds, dropSound );
|
|
|
|
if ( m_Default == null )
|
|
m_Default = data;
|
|
|
|
if ( split.Length >= 4 )
|
|
{
|
|
string[] aIDs = split[3].Split( ',' );
|
|
|
|
for ( int i = 0; i < aIDs.Length; i++ )
|
|
{
|
|
int id = Utility.ToInt32( aIDs[i] );
|
|
|
|
if ( m_Table.ContainsKey( id ) )
|
|
{
|
|
Console.WriteLine( @"Warning: double ItemID entry in Data\Config\containers.cfg" );
|
|
}
|
|
else
|
|
{
|
|
m_Table[id] = data;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( m_Default == null )
|
|
m_Default = new ContainerData( 0x3C, new Rectangle2D( 44, 65, 142, 94 ), 0x48 );
|
|
}
|
|
|
|
private static ContainerData m_Default;
|
|
private static Dictionary<int, ContainerData> m_Table;
|
|
|
|
public static ContainerData Default
|
|
{
|
|
get{ return m_Default; }
|
|
set{ m_Default = value; }
|
|
}
|
|
|
|
public static ContainerData GetData( int itemID )
|
|
{
|
|
ContainerData data = null;
|
|
m_Table.TryGetValue( itemID, out data );
|
|
|
|
if ( data != null )
|
|
return data;
|
|
else
|
|
return m_Default;
|
|
}
|
|
|
|
private int m_GumpID;
|
|
private Rectangle2D m_Bounds;
|
|
private int m_DropSound;
|
|
|
|
public int GumpID{ get{ return m_GumpID; } }
|
|
public Rectangle2D Bounds{ get{ return m_Bounds; } }
|
|
public int DropSound{ get{ return m_DropSound; } }
|
|
|
|
public ContainerData( int gumpID, Rectangle2D bounds, int dropSound )
|
|
{
|
|
m_GumpID = gumpID;
|
|
m_Bounds = bounds;
|
|
m_DropSound = dropSound;
|
|
}
|
|
}
|
|
} |