AvatarsConquest/Scripts/Mobiles/Base/BaseVendor.cs

1375 lines
No EOL
35 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Collections.Generic;
using Server.Items;
using Server.Network;
using Server.ContextMenus;
using Server.Mobiles;
using Server.Misc;
using Server.Regions;
namespace Server.Mobiles
{
public abstract class BaseVendor : BaseCreature, IVendor
{
public DateTime m_NextAction;
public DateTime NextAction{ get{ return m_NextAction; } set{ m_NextAction = value; } }
private const int MaxSell = 500;
protected abstract List<SBInfo> SBInfos { get; }
private ArrayList m_ArmorBuyInfo = new ArrayList();
private ArrayList m_ArmorSellInfo = new ArrayList();
private DateTime m_LastRestock;
public override bool CanTeach { get { return true; } }
public override bool BardImmune { get { return true; } }
public override bool PlayerRangeSensitive { get { return true; } }
public virtual bool IsActiveVendor { get { return true; } }
public virtual bool IsActiveBuyer { get { return IsActiveVendor; } } // response to vendor SELL
public virtual bool IsActiveSeller { get { return IsActiveVendor; } } // repsonse to vendor BUY
public virtual NpcGuild NpcGuild { get { return NpcGuild.None; } }
public override bool ShowFameTitle { get { return false; } }
public BaseVendor( string title ): base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 )
{
LoadSBInfo();
Invulnerable = true;
Clan = Clan.Citizen;
SetStr( 100 );
SetDex( 100 );
SetInt( 100 );
this.Title = title;
SpeechHue = Utility.RandomSpeechHue();
InitBody();
InitOutfit();
Container pack;
//these packs MUST exist, or the client will crash when the packets are sent
pack = new Backpack();
pack.Layer = Layer.ShopBuy;
pack.Movable = false;
pack.Visible = false;
AddItem( pack );
pack = new Backpack();
pack.Layer = Layer.ShopResale;
pack.Movable = false;
pack.Visible = false;
AddItem( pack );
m_LastRestock = DateTime.Now;
}
public BaseVendor( Serial serial ): base( serial )
{
}
public DateTime LastRestock
{
get
{
return m_LastRestock;
}
set
{
m_LastRestock = value;
}
}
public virtual TimeSpan RestockDelay
{
get
{
return TimeSpan.FromHours( 1 );
}
}
public Container BuyPack
{
get
{
Container pack = FindItemOnLayer( Layer.ShopBuy ) as Container;
if ( pack == null )
{
pack = new Backpack();
pack.Layer = Layer.ShopBuy;
pack.Visible = false;
AddItem( pack );
}
return pack;
}
}
public abstract void InitSBInfo();
protected void LoadSBInfo()
{
m_LastRestock = DateTime.Now;
for ( int i = 0; i < m_ArmorBuyInfo.Count; ++i )
{
GenericBuyInfo buy = m_ArmorBuyInfo[i] as GenericBuyInfo;
if ( buy != null )
buy.DeleteDisplayEntity();
}
SBInfos.Clear();
InitSBInfo();
m_ArmorBuyInfo.Clear();
m_ArmorSellInfo.Clear();
for ( int i = 0; i < SBInfos.Count; i++ )
{
SBInfo sbInfo = (SBInfo)SBInfos[i];
m_ArmorBuyInfo.AddRange( sbInfo.BuyInfo );
m_ArmorSellInfo.Add( sbInfo.SellInfo );
}
}
public virtual bool GetGender()
{
return Utility.RandomBool();
}
public virtual void InitBody()
{
InitStats( 100, 100, 25 );
SpeechHue = Utility.RandomSpeechHue();
Hue = Utility.RandomSkinHue();
if ( Invulnerable )
NameHue = 0x35;
int hair = Utility.RandomHairHue();
if ( this.Female = Utility.RandomBool() || this is Gypsy )
{
Female = true;
Body = 0x191;
Name = NameList.RandomName( "female" );
}
else
{
Body = 0x190;
Name = NameList.RandomName( "male" );
if ( Utility.RandomBool() ){ Utility.AssignRandomFacialHair( this, hair ); }
}
Utility.AssignRandomHair( this, hair );
}
public static void DoJokes( Mobile m )
{
int act = Utility.Random( 28 );
if ( m is PlayerMobile ){ act = Utility.Random( 22 ); }
switch ( act )
{
case 0: m.Say("Why did the king go to the dentist? To get his teeth crowned."); break;
case 1: m.Say("When a knight in armor was killed in battle, what sign did they put on his grave? Rust in peace!"); break;
case 2: m.Say("What do you call a mosquito in a tin suit? A bite in shining armor."); break;
case 3: m.Say("There are many castles in the world, but who is strong enough to move one? Any chess player"); break;
case 4: m.Say("What king was famous because he spent so many nights at his Round Table writing books? King Author!"); break;
case 5: m.Say("How do you find a princess? You follow the foot prince."); break;
case 6: m.Say("Why were the early days called the dark ages? Because there were so many knights!"); break;
case 7: m.Say("Why did Arthur have a round table? So no one could corner him!"); break;
case 8: m.Say("Who invented King Arthur's round table? Sir Cumference!"); break;
case 9: m.Say("Why did the knight run about shouting for a tin opener? He had a bee in his suit of armor!"); break;
case 10: m.Say("What was Camelot famous for? It's knight life!"); break;
case 11: m.Say("What did the toad say when the princess would not kiss him? Warts the matter with you?"); break;
case 12: m.Say("What do you call the young royal who keeps falling down? Prince Harming!"); break;
case 13: m.Say("What do you call a cat that flies over the castle wall? A cat-a-pult!"); break;
case 14: m.Say("What game do the fish play in the moat? Trout or dare!"); break;
case 15: m.Say("What did the fish say to the other when the horse fell in the moat? See horse!"); break;
case 16: m.Say("What do you call an angry princess just awakened from a long sleep? Slapping beauty!"); break;
case 17: m.Say("How did the prince get into the castle when the drawbridge was broken? He used a rowmoat!"); break;
case 18: m.Say("How did the girl dragon win the beauty contest? She was the beast of the show!"); break;
case 19: m.Say("Why did the dinosaur live longer than the dragon? Because it didnt smoke!"); break;
case 20: m.Say("What did the dragon say when it saw the Knight? 'Not more tinned food!'"); break;
case 21: m.Say("What do you do with a green dragon? Wait until it ripens!"); break;
case 22: m.PlaySound( m.Female ? 780 : 1051 ); m.Say( "*claps*" ); break;
case 23: m.Say( "*bows*" ); m.Animate( 32, 5, 1, true, false, 0 ); break;
case 24: m.PlaySound( m.Female ? 794 : 1066 ); m.Say( "*giggles*" ); break;
case 25: m.PlaySound( m.Female ? 801 : 1073 ); m.Say( "*laughs*" ); break;
case 26: m.PlaySound( 792 ); m.Say( "*sticks out tongue*" ); break;
case 27: m.PlaySound( m.Female ? 783 : 1054 ); m.Say( "*woohoo!*" ); break;
};
if ( act < 22 && Utility.RandomBool() )
{
switch ( Utility.Random( 6 ))
{
case 0: m.PlaySound( m.Female ? 780 : 1051 ); break;
case 1: m.Animate( 32, 5, 1, true, false, 0 ); break;
case 2: m.PlaySound( m.Female ? 794 : 1066 ); break;
case 3: m.PlaySound( m.Female ? 801 : 1073 ); break;
case 4: m.PlaySound( 792 ); break;
case 5: m.PlaySound( m.Female ? 783 : 1054 ); break;
};
}
}
public override void OnThink()
{
bool ran = false;
if ( DateTime.Now >= m_NextAction && ( this is Jester || ( this.Location == this.Home && this.RangeHome == 0 ) ) )
{
int range = 1;
if ( this is Fisherman || this is Ranger || this is Bowyer )
range = 7;
m_NextAction = (DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 5, 15 ) ) );
if ( this is Jester )
{
DoJokes( this );
m_NextAction = (DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 25, 35 ) ) );
ran = true;
}
else
{
foreach ( Item act in this.GetItemsInRange( range ) )
{
if ( act.Map == this.Map && act is ArcheryButte && ( this is Ranger || this is Bowyer ) && ( act.X == X || act.Y == Y ) )
{
Server.Items.Actions.EquipVendor( this, "bow" );
ran = true;
if ( this is Bowyer ){ this.Title = "the archer"; }
act.OnDoubleClick( this );
}
else if ( act.Map == this.Map && act is TrainingDummy && this is Fighter )
{
ran = true;
act.OnDoubleClick( this );
}
else if ( act.Map == this.Map && act is Actions )
{
int z = Z - act.Z;
if ( z < 0 )
z = act.Z - Z;
if ( z < 15 )
{
ran = true;
act.OnDoubleClick( this );
}
}
}
}
if ( !ran )
m_NextAction = (DateTime.Now).AddYears(1);
}
base.OnThink();
}
public override void OnAfterSpawn()
{
}
protected override void OnMapChange( Map oldMap )
{
base.OnMapChange( oldMap );
LoadSBInfo();
}
public virtual void CapitalizeTitle()
{
string title = this.Title;
if ( title == null )
return;
string[] split = title.Split( ' ' );
for ( int i = 0; i < split.Length; ++i )
{
if ( Insensitive.Equals( split[i], "the" ) )
continue;
if ( split[i].Length > 1 )
split[i] = Char.ToUpper( split[i][0] ) + split[i].Substring( 1 );
else if ( split[i].Length > 0 )
split[i] = Char.ToUpper( split[i][0] ).ToString();
}
this.Title = String.Join( " ", split );
}
public virtual void InitOutfit()
{
switch ( Utility.Random( 5 ) )
{
case 0: AddItem( new FancyShirt( Utility.RandomHue() ) ); break;
case 1: AddItem( new Doublet( Utility.RandomHue() ) ); break;
case 2: AddItem( new Shirt( Utility.RandomHue() ) ); break;
case 3: AddItem( new Tunic( Utility.RandomHue() ) ); break;
case 4: AddItem( new Surcoat( Utility.RandomHue() ) ); break;
}
switch ( Utility.Random( 4 ) )
{
case 0: AddItem( new Shoes( Utility.RandomNeutralHue() ) ); break;
case 1: AddItem( new Boots( Utility.RandomNeutralHue() ) ); break;
case 2: AddItem( new Sandals( Utility.RandomNeutralHue() ) ); break;
case 3: AddItem( new ThighBoots( Utility.RandomNeutralHue() ) ); break;
}
int hairHue = Utility.RandomHairHue();
Utility.AssignRandomHair( this, hairHue );
Utility.AssignRandomFacialHair( this, hairHue );
if ( Female )
{
switch ( Utility.Random( 4 ) )
{
case 0: AddItem( new LongPants( Utility.RandomNeutralHue() ) ); break;
case 1: AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); break;
case 2: AddItem( new Kilt( Utility.RandomNeutralHue() ) ); break;
case 3: AddItem( new Skirt( Utility.RandomHue() ) ); break;
}
}
else
{
switch ( Utility.Random( 3 ) )
{
case 0: AddItem( new LongPants( Utility.RandomNeutralHue() ) ); break;
case 1: AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); break;
case 2: AddItem( new Kilt( Utility.RandomNeutralHue() ) ); break;
}
}
int robeHue = Utility.RandomHue();
if ( this is BaseHealer ||
this is Mage ||
this is Scribe ||
this is Alchemist ||
this is MageGuildmaster ||
this is LibraryGuildmaster ||
this is HealerGuildmaster ||
this is AlchemistGuildmaster ||
Utility.RandomMinMax(1,10) == 1 )
{
if ( Female )
{
switch ( Utility.Random( 3 ) )
{
case 0: AddItem( new Robe( robeHue ) ); break;
case 1: AddItem( new PlainDress( robeHue ) ); break;
case 2: AddItem( new FancyDress( robeHue ) ); break;
}
}
else
{
AddItem( new Robe( robeHue ) );
}
}
if ( this is Mage || this is MageGuildmaster )
AddItem( new WizardsHat( robeHue ) );
else if ( this is Farmer && Utility.RandomBool() )
{
switch ( Utility.Random( 4 ) )
{
case 0: AddItem( new WideBrimHat( Utility.RandomHue() ) ); break;
case 1: AddItem( new FloppyHat( Utility.RandomHue() ) ); break;
case 2: AddItem( new StrawHat() ); break;
case 3: AddItem( new TallStrawHat() ); break;
}
}
else if ( this is Blacksmith || this is Carpenter || this is IronWorker || this is Armorer || this is Weaponsmith || this is CarpentryGuildmaster || this is BlacksmithGuildmaster || this is Bowyer )
{
switch ( Utility.Random( 2 ) )
{
case 0: AddItem( new Bandana( Utility.RandomHue() ) ); break;
case 1: AddItem( new SkullCap( Utility.RandomHue() ) ); break;
}
}
}
public virtual void Restock()
{
m_LastRestock = DateTime.Now;
IBuyItemInfo[] buyInfo = this.GetBuyInfo();
foreach ( IBuyItemInfo bii in buyInfo )
bii.OnRestock();
}
private static TimeSpan InventoryDecayTime = TimeSpan.FromHours( 1.0 );
public virtual void VendorBuy( Mobile from )
{
if ( !IsActiveSeller )
return;
if ( !from.CheckAlive() )
return;
if ( !CheckVendorAccess( from ) )
{
Say( 501522 ); // I shall not deal with scum like thee!
return;
}
if ( DateTime.Now - m_LastRestock > RestockDelay )
Restock();
int count = 0;
List<BuyItemState> list;
IBuyItemInfo[] buyInfo = this.GetBuyInfo();
IShopSellInfo[] sellInfo = this.GetSellInfo();
list = new List<BuyItemState>( buyInfo.Length );
Container cont = this.BuyPack;
List<ObjectPropertyList> opls = null;
for ( int idx = 0; idx < buyInfo.Length; idx++ )
{
IBuyItemInfo buyItem = (IBuyItemInfo)buyInfo[idx];
if ( buyItem.Amount <= 0 || list.Count >= 250 )
continue;
// NOTE: Only GBI supported; if you use another implementation of IBuyItemInfo, this will crash
GenericBuyInfo gbi = (GenericBuyInfo)buyItem;
IEntity disp = gbi.GetDisplayEntity();
list.Add( new BuyItemState( buyItem.Name, cont.Serial, disp == null ? (Serial)0x7FC0FFEE : disp.Serial, buyItem.Price, buyItem.Amount, buyItem.ItemID, buyItem.Hue ) );
count++;
if ( opls == null ) {
opls = new List<ObjectPropertyList>();
}
if ( disp is Item ) {
opls.Add( ( ( Item ) disp ).PropertyList );
} else if ( disp is Mobile ) {
opls.Add( ( ( Mobile ) disp ).PropertyList );
}
}
List<Item> playerItems = cont.Items;
for ( int i = playerItems.Count - 1; i >= 0; --i )
{
if ( i >= playerItems.Count )
continue;
Item item = playerItems[i];
if ( ( item.LastMoved + InventoryDecayTime ) <= DateTime.Now )
item.Delete();
}
for ( int i = 0; i < playerItems.Count; ++i )
{
Item item = playerItems[i];
int price = 0;
string name = null;
foreach ( IShopSellInfo ssi in sellInfo )
{
if ( ssi.IsSellable( item ) )
{
price = ssi.GetBuyPriceFor( item );
name = ssi.GetNameFor( item );
break;
}
}
if ( name != null && list.Count < 250 )
{
list.Add( new BuyItemState( name, cont.Serial, item.Serial, price, item.Amount, item.ItemID, item.Hue ) );
count++;
if ( opls == null ) {
opls = new List<ObjectPropertyList>();
}
opls.Add( item.PropertyList );
}
}
//one (not all) of the packets uses a byte to describe number of items in the list. Osi = dumb.
//if ( list.Count > 255 )
// Console.WriteLine( "Vendor Warning: Vendor {0} has more than 255 buy items, may cause client errors!", this );
if ( list.Count > 0 )
{
list.Sort( new BuyItemStateComparer() );
SendPacksTo( from );
NetState ns = from.NetState;
if ( ns == null )
return;
if ( ns.ContainerGridLines )
from.Send( new VendorBuyContent6017( list ) );
else
from.Send( new VendorBuyContent( list ) );
from.Send( new VendorBuyList( this, list ) );
if ( ns.HighSeas )
from.Send( new DisplayBuyListHS( this ) );
else
from.Send( new DisplayBuyList( this ) );
from.Send( new MobileStatusExtended( from ) );//make sure their gold amount is sent
if ( opls != null ) {
for ( int i = 0; i < opls.Count; ++i ) {
from.Send( opls[i] );
}
}
SayTo( from, 500186 ); // Greetings. Have a look around.
}
}
public virtual void SendPacksTo( Mobile from )
{
Item pack = FindItemOnLayer( Layer.ShopBuy );
if ( pack == null )
{
pack = new Backpack();
pack.Layer = Layer.ShopBuy;
pack.Movable = false;
pack.Visible = false;
AddItem( pack );
}
from.Send( new EquipUpdate( pack ) );
pack = FindItemOnLayer( Layer.ShopSell );
if ( pack != null )
from.Send( new EquipUpdate( pack ) );
pack = FindItemOnLayer( Layer.ShopResale );
if ( pack == null )
{
pack = new Backpack();
pack.Layer = Layer.ShopResale;
pack.Movable = false;
pack.Visible = false;
AddItem( pack );
}
from.Send( new EquipUpdate( pack ) );
}
public virtual void VendorSell( Mobile from )
{
if ( !IsActiveBuyer )
return;
if ( !from.CheckAlive() )
return;
if ( !CheckVendorAccess( from ) )
{
Say( 501522 ); // I shall not deal with scum like thee!
return;
}
Container pack = from.Backpack;
if ( pack != null )
{
IShopSellInfo[] info = GetSellInfo();
Hashtable table = new Hashtable();
foreach ( IShopSellInfo ssi in info )
{
Item[] items = pack.FindItemsByType( ssi.Types );
foreach ( Item item in items )
{
if ( item is Container && ( (Container)item ).Items.Count != 0 )
continue;
if ( item.IsStandardLoot() && item.Movable && ssi.IsSellable( item ) )
table[item] = new SellItemState( item, ssi.GetSellPriceFor( item ), ssi.GetNameFor( item ) );
}
}
if ( table.Count > 0 )
{
SendPacksTo( from );
from.Send( new VendorSellList( this, table ) );
}
else
{
Say( true, "You have nothing I would be interested in." );
}
}
}
private GenericBuyInfo LookupDisplayObject( object obj )
{
IBuyItemInfo[] buyInfo = this.GetBuyInfo();
for ( int i = 0; i < buyInfo.Length; ++i ) {
GenericBuyInfo gbi = (GenericBuyInfo)buyInfo[i];
if ( gbi.GetDisplayEntity() == obj )
return gbi;
}
return null;
}
private void ProcessSinglePurchase( BuyItemResponse buy, IBuyItemInfo bii, List<BuyItemResponse> validBuy, ref int controlSlots, ref bool fullPurchase, ref int totalCost )
{
int amount = buy.Amount;
if ( amount > bii.Amount )
amount = bii.Amount;
if ( amount <= 0 )
return;
int slots = bii.ControlSlots * amount;
if ( controlSlots >= slots )
{
controlSlots -= slots;
}
else
{
fullPurchase = false;
return;
}
totalCost += bii.Price * amount;
validBuy.Add( buy );
}
public void GemSet( Item item )
{
if ( item is BaseJewel )
((BaseJewel)item).GemType = GemType.None;
}
private void ProcessValidPurchase( int amount, IBuyItemInfo bii, Mobile buyer, Container cont )
{
if ( amount > bii.Amount )
amount = bii.Amount;
if ( amount < 1 )
return;
bii.Amount -= amount;
IEntity o = bii.GetEntity();
if ( o is Item )
{
Item item = (Item)o;
if ( item.Stackable )
{
item.Amount = amount;
GemSet( item );
if ( cont == null || !cont.TryDropItem( buyer, item, false ) )
item.MoveToWorld( buyer.Location, buyer.Map );
}
else
{
item.Amount = 1;
GemSet( item );
if ( cont == null || !cont.TryDropItem( buyer, item, false ) )
item.MoveToWorld( buyer.Location, buyer.Map );
for ( int i = 1; i < amount; i++ )
{
item = bii.GetEntity() as Item;
if ( item != null )
{
item.Amount = 1;
GemSet( item );
if ( cont == null || !cont.TryDropItem( buyer, item, false ) )
item.MoveToWorld( buyer.Location, buyer.Map );
}
}
}
}
else if ( o is Mobile )
{
Mobile m = (Mobile)o;
m.Direction = (Direction)Utility.Random( 8 );
m.MoveToWorld( buyer.Location, buyer.Map );
m.PlaySound( m.GetIdleSound() );
if ( m is BaseCreature )
( (BaseCreature)m ).SetControlMaster( buyer );
for ( int i = 1; i < amount; ++i )
{
m = bii.GetEntity() as Mobile;
if ( m != null )
{
m.Direction = (Direction)Utility.Random( 8 );
m.MoveToWorld( buyer.Location, buyer.Map );
if ( m is BaseCreature )
( (BaseCreature)m ).SetControlMaster( buyer );
}
}
}
}
public virtual bool OnBuyItems( Mobile buyer, List<BuyItemResponse> list )
{
if ( !IsActiveSeller )
return false;
if ( !buyer.CheckAlive() )
return false;
if ( !CheckVendorAccess( buyer ) )
{
Say( 501522 ); // I shall not deal with scum like thee!
return false;
}
IBuyItemInfo[] buyInfo = this.GetBuyInfo();
IShopSellInfo[] info = GetSellInfo();
int totalCost = 0;
List<BuyItemResponse> validBuy = new List<BuyItemResponse>( list.Count );
Container cont;
bool bought = false;
bool fromInn = false;
bool fullPurchase = true;
int controlSlots = buyer.FollowersMax - buyer.Followers;
foreach ( BuyItemResponse buy in list )
{
Serial ser = buy.Serial;
int amount = buy.Amount;
if ( ser.IsItem )
{
Item item = World.FindItem( ser );
if ( item == null )
continue;
GenericBuyInfo gbi = LookupDisplayObject( item );
if ( gbi != null )
{
ProcessSinglePurchase( buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost );
}
else if ( item != this.BuyPack && item.IsChildOf( this.BuyPack ) )
{
if ( amount > item.Amount )
amount = item.Amount;
if ( amount <= 0 )
continue;
foreach ( IShopSellInfo ssi in info )
{
if ( ssi.IsSellable( item ) )
{
if ( ssi.IsResellable( item ) )
{
totalCost += ssi.GetBuyPriceFor( item ) * amount;
validBuy.Add( buy );
break;
}
}
}
}
}
else if ( ser.IsMobile )
{
Mobile mob = World.FindMobile( ser );
if ( mob == null )
continue;
GenericBuyInfo gbi = LookupDisplayObject( mob );
if ( gbi != null )
ProcessSinglePurchase( buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost );
}
}//foreach
if ( fullPurchase && validBuy.Count == 0 )
SayTo( buyer, 500190 ); // Thou hast bought nothing!
else if ( validBuy.Count == 0 )
SayTo( buyer, 500187 ); // Your order cannot be fulfilled, please try again.
if ( validBuy.Count == 0 )
return false;
bought = ( buyer.AccessLevel >= AccessLevel.GameMaster );
cont = buyer.Backpack;
if ( !bought && cont != null )
{
if ( cont.ConsumeTotal( typeof( Gold ), totalCost ) )
bought = true;
else if ( totalCost < 2000 )
SayTo( buyer, 500192 );//Begging thy pardon, but thou casnt afford that.
}
if ( !bought && totalCost >= 2000 )
{
cont = buyer.FindInnNoCreate();
if ( cont != null && cont.ConsumeTotal( typeof( Gold ), totalCost ) )
{
bought = true;
fromInn = true;
}
else
{
SayTo( buyer, 500191 ); //Begging thy pardon, but thy inn chest lacks these funds.
}
}
if ( !bought )
return false;
else
buyer.PlaySound( 0x32 );
cont = buyer.Backpack;
if ( cont == null )
cont = buyer.InnBox;
foreach ( BuyItemResponse buy in validBuy )
{
Serial ser = buy.Serial;
int amount = buy.Amount;
if ( amount < 1 )
continue;
if ( ser.IsItem )
{
Item item = World.FindItem( ser );
if ( item == null )
continue;
GenericBuyInfo gbi = LookupDisplayObject( item );
if ( gbi != null )
{
ProcessValidPurchase( amount, gbi, buyer, cont );
}
else
{
if ( amount > item.Amount )
amount = item.Amount;
foreach ( IShopSellInfo ssi in info )
{
if ( ssi.IsSellable( item ) )
{
if ( ssi.IsResellable( item ) )
{
Item buyItem;
if ( amount >= item.Amount )
{
buyItem = item;
}
else
{
buyItem = Mobile.LiftItemDupe( item, item.Amount - amount );
if ( buyItem == null )
buyItem = item;
}
GemSet( buyItem );
if ( cont == null || !cont.TryDropItem( buyer, buyItem, false ) )
buyItem.MoveToWorld( buyer.Location, buyer.Map );
break;
}
}
}
}
}
else if ( ser.IsMobile )
{
Mobile mob = World.FindMobile( ser );
if ( mob == null )
continue;
GenericBuyInfo gbi = LookupDisplayObject( mob );
if ( gbi != null )
ProcessValidPurchase( amount, gbi, buyer, cont );
}
}//foreach
if ( fullPurchase )
{
if ( buyer.AccessLevel >= AccessLevel.GameMaster )
SayTo( buyer, true, "I would not presume to charge thee anything. Here are the goods you requested." );
else if ( fromInn )
SayTo( buyer, true, "The total of thy purchase is {0} gold, which has been withdrawn from your inn chest. My thanks for the patronage.", totalCost );
else
SayTo( buyer, true, "The total of thy purchase is {0} gold. My thanks for the patronage.", totalCost );
}
else
{
if ( buyer.AccessLevel >= AccessLevel.GameMaster )
SayTo( buyer, true, "I would not presume to charge thee anything. Unfortunately, I could not sell you all the goods you requested." );
else if ( fromInn )
SayTo( buyer, true, "The total of thy purchase is {0} gold, which has been withdrawn from your inn chest. My thanks for the patronage. Unfortunately, I could not sell you all the goods you requested.", totalCost );
else
SayTo( buyer, true, "The total of thy purchase is {0} gold. My thanks for the patronage. Unfortunately, I could not sell you all the goods you requested.", totalCost );
}
return true;
}
public virtual bool CheckVendorAccess( Mobile from )
{
PlayerMobile pm = (PlayerMobile)from;
if ( this is BaseGuildmaster && this.NpcGuild == pm.NpcGuild && ( this.NpcGuild == NpcGuild.AssassinsGuild || this.NpcGuild == NpcGuild.ThievesGuild ) ) // THESE GUILDS DEAL WITH GUILD MEMBERS NO MATTER WHAT
return true;
if ( from.Criminal && !Server.Misc.NotorietyHandlers.CriminalTolerated( from ) )
return false;
if ( from.Kills >= 5 && !Server.Misc.NotorietyHandlers.CriminalTolerated( from ) )
return false;
if ( this is BaseGuildmaster && this.NpcGuild != pm.NpcGuild ) // ONLY GUILD MEMBERS CAN BUY FROM GUILD MASTERS
return false;
return true;
}
public virtual bool OnSellItems( Mobile seller, List<SellItemResponse> list )
{
if ( !IsActiveBuyer )
return false;
if ( !seller.CheckAlive() )
return false;
if ( !CheckVendorAccess( seller ) )
{
Say( 501522 ); // I shall not deal with scum like thee!
return false;
}
seller.PlaySound( 0x32 );
IShopSellInfo[] info = GetSellInfo();
IBuyItemInfo[] buyInfo = this.GetBuyInfo();
int GiveGold = 0;
int Sold = 0;
Container cont;
foreach ( SellItemResponse resp in list )
{
if ( resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || !resp.Item.Movable || ( resp.Item is Container && ( (Container)resp.Item ).Items.Count != 0 ) )
continue;
foreach ( IShopSellInfo ssi in info )
{
if ( ssi.IsSellable( resp.Item ) )
{
Sold++;
break;
}
}
}
if ( Sold > MaxSell )
{
SayTo( seller, true, "You may only sell {0} items at a time!", MaxSell );
return false;
}
else if ( Sold == 0 )
{
return true;
}
foreach ( SellItemResponse resp in list )
{
if ( resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || !resp.Item.Movable || ( resp.Item is Container && ( (Container)resp.Item ).Items.Count != 0 ) )
continue;
foreach ( IShopSellInfo ssi in info )
{
if ( ssi.IsSellable( resp.Item ) )
{
int amount = resp.Amount;
if ( amount > resp.Item.Amount )
amount = resp.Item.Amount;
if ( ssi.IsResellable( resp.Item ) )
{
bool found = false;
foreach ( IBuyItemInfo bii in buyInfo )
{
if ( bii.Restock( resp.Item, amount ) )
{
resp.Item.Consume( amount );
found = true;
break;
}
}
if ( !found )
{
cont = this.BuyPack;
if ( amount < resp.Item.Amount )
{
Item item = Mobile.LiftItemDupe( resp.Item, resp.Item.Amount - amount );
if ( item != null )
{
item.SetLastMoved();
cont.DropItem( item );
}
else
{
resp.Item.SetLastMoved();
cont.DropItem( resp.Item );
}
}
else
{
resp.Item.SetLastMoved();
cont.DropItem( resp.Item );
}
}
}
else
{
if ( amount < resp.Item.Amount )
resp.Item.Amount -= amount;
else
resp.Item.Delete();
}
GiveGold += ssi.GetSellPriceFor( resp.Item ) * amount;
break;
}
}
}
if ( GiveGold > 0 )
{
while ( GiveGold > 60000 )
{
seller.AddToBackpack( new Gold( 60000 ) );
GiveGold -= 60000;
}
seller.AddToBackpack( new Gold( GiveGold ) );
seller.PlaySound( 0x0037 );//Gold dropping sound
}
return true;
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int)1 ); // version
List<SBInfo> sbInfos = this.SBInfos;
for ( int i = 0; sbInfos != null && i < sbInfos.Count; ++i )
{
SBInfo sbInfo = sbInfos[i];
List<GenericBuyInfo> buyInfo = sbInfo.BuyInfo;
for ( int j = 0; buyInfo != null && j < buyInfo.Count; ++j )
{
GenericBuyInfo gbi = (GenericBuyInfo)buyInfo[j];
int maxAmount = gbi.MaxAmount;
int doubled = 0;
switch ( maxAmount )
{
case 40: doubled = 1; break;
case 80: doubled = 2; break;
case 160: doubled = 3; break;
case 320: doubled = 4; break;
case 640: doubled = 5; break;
case 999: doubled = 6; break;
}
if ( doubled > 0 )
{
writer.WriteEncodedInt( 1 + ( ( j * sbInfos.Count ) + i ) );
writer.WriteEncodedInt( doubled );
}
}
}
writer.WriteEncodedInt( 0 );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
LoadSBInfo();
List<SBInfo> sbInfos = this.SBInfos;
switch ( version )
{
case 1:
{
int index;
while ( ( index = reader.ReadEncodedInt() ) > 0 )
{
int doubled = reader.ReadEncodedInt();
if ( sbInfos != null )
{
index -= 1;
int sbInfoIndex = index % sbInfos.Count;
int buyInfoIndex = index / sbInfos.Count;
if ( sbInfoIndex >= 0 && sbInfoIndex < sbInfos.Count )
{
SBInfo sbInfo = sbInfos[sbInfoIndex];
List<GenericBuyInfo> buyInfo = sbInfo.BuyInfo;
if ( buyInfo != null && buyInfoIndex >= 0 && buyInfoIndex < buyInfo.Count )
{
GenericBuyInfo gbi = (GenericBuyInfo)buyInfo[buyInfoIndex];
int amount = 20;
switch ( doubled )
{
case 1: amount = 40; break;
case 2: amount = 80; break;
case 3: amount = 160; break;
case 4: amount = 320; break;
case 5: amount = 640; break;
case 6: amount = 999; break;
}
gbi.Amount = gbi.MaxAmount = amount;
}
}
}
}
break;
}
}
}
public void Speak()
{
switch( Utility.Random( 8 ) )
{
case 0:
PlaySound( Female ? 797 : 1069 );
// hey
break;
case 1:
PlaySound( Female ? 778 : 1049 );
// ah
break;
case 2:
PlaySound( Female ? 799 : 1071 );
// huh
break;
case 3:
PlaySound( Female ? 803 : 1075 );
// oh
break;
case 4:
PlaySound( Female ? 811 : 1085 );
// oooh
break;
case 5:
PlaySound( Female ? 816 : 1090 );
// sigh
break;
}
}
public override void AddCustomContextEntries( Mobile from, List<ContextMenuEntry> list )
{
if ( from.Alive && IsActiveVendor )
{
if ( IsActiveSeller )
list.Add( new VendorBuyEntry( from, this ) );
if ( IsActiveBuyer )
list.Add( new VendorSellEntry( from, this ) );
}
base.AddCustomContextEntries( from, list );
}
public virtual IShopSellInfo[] GetSellInfo()
{
return (IShopSellInfo[])m_ArmorSellInfo.ToArray( typeof( IShopSellInfo ) );
}
public virtual IBuyItemInfo[] GetBuyInfo()
{
return (IBuyItemInfo[])m_ArmorBuyInfo.ToArray( typeof( IBuyItemInfo ) );
}
}
}
namespace Server.ContextMenus
{
public class VendorBuyEntry : ContextMenuEntry
{
private BaseVendor m_Vendor;
public VendorBuyEntry( Mobile from, BaseVendor vendor )
: base( 6103, 8 )
{
m_Vendor = vendor;
Enabled = vendor.CheckVendorAccess( from );
}
public override void OnClick()
{
m_Vendor.Speak();
m_Vendor.VendorBuy( this.Owner.From );
}
}
public class VendorSellEntry : ContextMenuEntry
{
private BaseVendor m_Vendor;
public VendorSellEntry( Mobile from, BaseVendor vendor )
: base( 6104, 8 )
{
m_Vendor = vendor;
Enabled = vendor.CheckVendorAccess( from );
}
public override void OnClick()
{
m_Vendor.VendorSell( this.Owner.From );
}
}
}
namespace Server
{
public interface IShopSellInfo
{
//get display name for an item
string GetNameFor( Item item );
//get price for an item which the player is selling
int GetSellPriceFor( Item item );
//get price for an item which the player is buying
int GetBuyPriceFor( Item item );
//can we sell this item to this vendor?
bool IsSellable( Item item );
//What do we sell?
Type[] Types { get; }
//does the vendor resell this item?
bool IsResellable( Item item );
}
public interface IBuyItemInfo
{
//get a new instance of an object (we just bought it)
IEntity GetEntity();
int ControlSlots { get; }
int PriceScalar { get; set; }
//display price of the item
int Price { get; }
//display name of the item
string Name { get; }
//display hue
int Hue { get; }
//display id
int ItemID { get; }
//amount in stock
int Amount { get; set; }
//max amount in stock
int MaxAmount { get; }
//Attempt to restock with item, (return true if restock sucessful)
bool Restock( Item item, int amount );
//called when its time for the whole shop to restock
void OnRestock();
}
}