RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

[RunUO ML SVN 120] Xml Quest Guilds

LordHogFred

Knight
[RunUO ML SVN 120] Xml Quest Guilds

Well it's been a long time since I have contributed to the community so I thought I what share with everyone my latest system I have been working on.

IMPORTANT: To use these scripts you NEED to have both Callandors Mondain's Legacy AND the XmlSpawner2 installed. In order to use this system to it's full extent you will need a reasonable level of manual set up.

XML Quest Guilds

The idea of the Xml Quest Guild was to make a way to replace the current BoD system so that the rewards were still obtainable by even a very small player base. Included with this initial release is the Blacksmith and Tailor guilds.
The way this system works is that players can recieve up to 3 quests every day from the relevant guild representatives. These quests are simple craft x of y quests. The rewards are reputation with the guild to further your rank and guild specific currency. The idea is that the ranks can be used as pre-requisites to buy increasingly better rewards, whereas the currency is what is used to actually buy them. This slow but sure progression means that it may take a character 6 months to gain enough rep and tokens to actually buy a valorite runic hammer but they can guarantee they will be able to get one instead of having to wait years for the correct BoDs.

The system has been designed in such a way that adding new guilds is incredibly easy, all that needs to be done is add the XmlQuestGuild attachment to a player and all gumps and vendors will automatically be able to detect the new guild. For example, if you wanted to add a Pirates guild just use:
Code:
[addatt XmlQuestGuild Pirate
This will add a Pirate guild to the player which will now show up on the guild info gump and will automatically be used by any BaseGuildQuester who's type is also set to "Pirate". Adding quest givers that will give kill x of y quests is very easy, in fact adding new quest givers that give any quest is now very easy and they will give rewards based on their guild if you use BaseGuildQuest as the inherited type.

To actually set up vendors that will use the various guild currency I highly recommend the Complete Customizable Vendor as it is what I use due to support for using XmlAttachment variables as currency so setting up vendors will be much easier than any other way I can think of.

To install the system a couple of edits are required to the Mondain's Legacy scripts. I have included my versions of the scripts for those who use WinMerge or just want to replace their old ones. Others who want to do the additions manually here is what you need to do:

QuestHelper.cs
Find:
Code:
                    if ( objective is ObtainObjective )
                    {
                        ObtainObjective obtain = (ObtainObjective) objective;
                        
                        if ( obtain.Update( item ) )
                        {
                            if ( quest.Completed )
                                quest.OnCompleted();
                            else if ( obtain.Completed )
                                player.PlaySound( quest.UpdateSound );
                                    
                            return true;
                        }
                    }

Add After:
Code:
                    #region New Objectives
                    else if (objective is CraftObjective)
                    {
                        CraftObjective craft = (CraftObjective)objective;

                        if (craft.Update(item))
                        {
                            if (quest.Completed)
                                quest.OnCompleted();
                            else if (craft.Completed)
                                player.PlaySound(quest.UpdateSound);

                            return true;
                        }
                    }
                    #endregion

MondainQuestGump.cs[/b[
Find:
Code:
                else if ( objective is ObtainObjective )
                {
                    ObtainObjective obtain = (ObtainObjective) objective;
                    
                    AddHtmlLocalized( 98, offset, 40, 16, 1072205, 0x15F90, false, false ); // Obtain                        
                    AddLabel( 143, offset, 0x481, obtain.MaxProgress + " " + obtain.Name ); // %count% + %name%
                    
                    if ( obtain.Image > 0 )
                        AddItem( 350, offset, obtain.Image ); // Image
                                        
                    offset += 16;    
                    
                    if ( m_Offer )
                    {
                        if ( obtain.Timed )
                        {
                            AddHtmlLocalized( 103, offset, 120, 16, 1062379, 0x15F90, false, false ); // Est. time remaining:
                            AddLabel( 223, offset, 0x481, FormatSeconds( obtain.Seconds ) ); // %est. time remaining%
                    
                            offset += 16;
                        }
                        else if ( obtain.Image > 0 )
                            offset += 16;
                        
                        continue;
                    }
                    AddHtmlLocalized(103, offset, 120, 16, 3000087, 0x15F90, false, false); // Total            
                    AddLabel(223, offset, 0x481, obtain.CurProgress.ToString());     // %current progress%
                    
                    offset += 16;
                    
                    if ( ReturnTo() != null )
                    {
                        AddHtmlLocalized( 103, offset, 120, 16, 1074782, 0x15F90, false, false ); // Return to    
                        AddLabel( 223, offset, 0x481, ReturnTo() );     // %return to%
                        
                        offset += 16;
                    }
                    
                    if ( obtain.Timed )
                    {
                        AddHtmlLocalized( 103, offset, 120, 16, 1062379, 0x15F90, false, false ); // Est. time remaining:
                        AddLabel( 223, offset, 0x481, FormatSeconds( obtain.Seconds ) ); // %est. time remaining%
                    
                        offset += 16;
                    }
                }

Add after:
Code:
                #region New Objectives
                else if (objective is CraftObjective)
                {
                    CraftObjective craft = (CraftObjective)objective;

                    AddHtmlLocalized(98, offset, 40, 16, 1072205, 0x15F90, false, false); // Obtain

                    string resource = null;

                    switch (craft.Resource)
                    {
                        case CraftResource.None:
                            resource = "none";
                            break;
                        case CraftResource.Iron:
                            resource = "iron";
                            break;
                        case CraftResource.DullCopper:
                            resource = "dull copper";
                            break;
                        case CraftResource.ShadowIron:
                            resource = "shadow iron";
                            break;
                        case CraftResource.Copper:
                            resource = "copper";
                            break;
                        case CraftResource.Bronze:
                            resource = "bronze";
                            break;
                        case CraftResource.Gold:
                            resource = "gold";
                            break;
                        case CraftResource.Agapite:
                            resource = "agapite";
                            break;
                        case CraftResource.Verite:
                            resource = "verite";
                            break;
                        case CraftResource.Valorite:
                            resource = "valorite";
                            break;
                        case CraftResource.RegularLeather:
                            resource = "leather";
                            break;
                        case CraftResource.SpinedLeather:
                            resource = "spined";
                            break;
                        case CraftResource.HornedLeather:
                            resource = "horned";
                            break;
                        case CraftResource.BarbedLeather:
                            resource = "barbed";
                            break;
                        case CraftResource.RedScales:
                            resource = "red scale";
                            break;
                        case CraftResource.YellowScales:
                            resource = "yellow scale";
                            break;
                        case CraftResource.BlackScales:
                            resource = "black scale";
                            break;
                        case CraftResource.WhiteScales:
                            resource = "white scale";
                            break;
                        case CraftResource.GreenScales:
                            resource = "green scale";
                            break;
                        case CraftResource.BlueScales:
                            resource = "blue scale";
                            break;
                        case CraftResource.RegularWood:
                            resource = "wooden";
                            break;
                        case CraftResource.OakWood:
                            resource = "oak";
                            break;
                        case CraftResource.AshWood:
                            resource = "ash";
                            break;
                        case CraftResource.YewWood:
                            resource = "yew";
                            break;
                        case CraftResource.Heartwood:
                            resource = "heartwood";
                            break;
                        case CraftResource.Bloodwood:
                            resource = "bloodwood";
                            break;
                        case CraftResource.Frostwood:
                            resource = "frostwood";
                            break;
                    }

                    if (craft.Exceptional && craft.Resource != CraftResource.None)
                    {
                        AddLabel(143, offset, 0x481, craft.MaxProgress + " exceptional " + resource + " " + craft.Name); // %count% + %name%
                    }
                    else if (craft.Exceptional && craft.Resource == CraftResource.None)
                    {
                        AddLabel(143, offset, 0x481, craft.MaxProgress + " exceptional " + craft.Name); // %count% + %name%
                    }
                    else if (!craft.Exceptional && craft.Resource != CraftResource.None)
                    {
                        AddLabel(143, offset, 0x481, craft.MaxProgress + " " + resource + " " + craft.Name); // %count% + %name%
                    }
                    else
                    {
                        AddLabel(143, offset, 0x481, craft.MaxProgress + " " + craft.Name); // %count% + %name%
                    }

                    if (craft.Image > 0)
                        AddItem(350, offset, craft.Image); // Image

                    offset += 16;

                    if (m_Offer)
                    {
                        if (craft.Timed)
                        {
                            AddHtmlLocalized(103, offset, 120, 16, 1062379, 0x15F90, false, false); // Est. time remaining:
                            AddLabel(223, offset, 0x481, FormatSeconds(craft.Seconds)); // %est. time remaining%

                            offset += 16;
                        }
                        else if (craft.Image > 0)
                            offset += 16;

                        continue;
                    }
                    AddHtmlLocalized(103, offset, 120, 16, 3000087, 0x15F90, false, false); // Total            
                    AddLabel(223, offset, 0x481, craft.CurProgress.ToString());     // %current progress%

                    offset += 16;

                    if (m_Quest is BaseGuildQuest)
                    {
                        AddHtmlLocalized(103, offset, 120, 16, 1074782, 0x15F90, false, false); // Return to
                        AddLabel(223, offset, 0x481, String.Format("{0} Guild", ((BaseGuildQuest)m_Quest).GuildType));

                        offset += 16;
                    }
                    else if (ReturnTo() != null)
                    {
                        AddHtmlLocalized(103, offset, 120, 16, 1074782, 0x15F90, false, false); // Return to
                        AddLabel(223, offset, 0x481, ReturnTo());     // %return to%

                        offset += 16;
                    }

                    if (craft.Timed)
                    {
                        AddHtmlLocalized(103, offset, 120, 16, 1062379, 0x15F90, false, false); // Est. time remaining:
                        AddLabel(223, offset, 0x481, FormatSeconds(craft.Seconds)); // %est. time remaining%

                        offset += 16;
                    }
                }
                #endregion

To check your current guilds information just use:
Code:
[CheckGuilds
 

Attachments

  • XmlQuestGuilds.zip
    29.9 KB · Views: 56
  • QuestGuildRewardStone.cs
    3 KB · Views: 48

LordHogFred

Knight
UPDATE 1: 16, Sept, 2010
- Removed the need to make any edits to questObjectives.cs by adding the new objective to it's own file.
- Added Guild boards, act like Guild reps except they're message boards.
- Any guild rep or board will now accept any same rank quest for their guild, this was done to avoid potential problems with having each board and rep giving their own quests.
- Tweaked the MondainQuestGump.cs to show the guild to return to.
- (Optional) Added a BaseQuestRewardStone.cs for those who have Complete Customizable Vendor. This will allow you to define a rank and guild requirement in order for it to be used.
 

Thilgon

Sorceror
Thanks Hogfred, this is a very coherent system, just like what i was planning to do...
You spared me the effort of scripting it lol :D
 

LordHogFred

Knight
Thilgon;850878 said:
Thanks Hogfred, this is a very coherent system, just like what i was planning to do...
You spared me the effort of scripting it lol :D

No problem :).
Not enough people use XmlAttachments for their scripts.
 

Nockar

Sorceror
Are the scripts missing BaseFurniture? I don’t see it anywhere.

Code:
[COLOR="DarkRed"]Errors:
 + Customs/Mondain's Legacy/Engines/Quests/QuestObjectives.cs:
    CS0246: Line 811: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)
    CS0246: Line 813: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)
    CS0246: Line 813: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)
    CS0246: Line 843: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)
    CS0246: Line 845: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)
    CS0246: Line 845: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)[/COLOR]
 

LordHogFred

Knight
Nockar;850913 said:
Are the scripts missing BaseFurniture? I don’t see it anywhere.

Code:
[COLOR="DarkRed"]Errors:
 + Customs/Mondain's Legacy/Engines/Quests/QuestObjectives.cs:
    CS0246: Line 811: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)
    CS0246: Line 813: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)
    CS0246: Line 813: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)
    CS0246: Line 843: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)
    CS0246: Line 845: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)
    CS0246: Line 845: The type or namespace name 'BaseFurniture' could not be fo
und (are you missing a using directive or an assembly reference?)[/COLOR]

Oops, you can just comment out the BaseFurniture references. Their a custom type for if I get around to adding carpenters guilds. I think Mondains Legacy comes with CraftableFurniture type. I'll reup the archive with it changed.

EDIT:: Reupped the archive. BaseObjective now has the BaseFurniture references commented out for the moment.
 

LordHogFred

Knight
New archive uploaded with new changes.
Also uploaded a reward stone based off the Customizable Vendor Stone for those who want to use it.
 

Nockar

Sorceror
Just did the update. Also just added The Complete Customizable Vendor.

Code:
[COLOR="Red"]Errors:
 + Customs/Xml Spawner/XmlQuestGuilds/QuestGuildRewardStone.cs:
    CS0234: Line 13: The type or namespace name 'CustomRewards' does not exist i
n the namespace 'Server.Engines' (are you missing an assembly reference?)
    CS0246: Line 17: The type or namespace name 'StoneCustomRewardVendor' could
not be found (are you missing a using directive or an assembly reference?)[/COLOR]
 

LordHogFred

Knight
Nockar;851055 said:
Just did the update. Also just added The Complete Customizable Vendor.

Code:
[COLOR="Red"]Errors:
 + Customs/Xml Spawner/XmlQuestGuilds/QuestGuildRewardStone.cs:
    CS0234: Line 13: The type or namespace name 'CustomRewards' does not exist i
n the namespace 'Server.Engines' (are you missing an assembly reference?)
    CS0246: Line 17: The type or namespace name 'StoneCustomRewardVendor' could
not be found (are you missing a using directive or an assembly reference?)[/COLOR]

Oh sorry, that's because I've changed the Customizable Vendor names on my server as it conflicted with some scripts I already had. Just go into the script and change any reference for CustomReward to Reward and it should work ok :eek:.

EDIT: Just reupped the QuestRewardStone.cs to use default names.
 

Nockar

Sorceror
Thanks for the info.

I tried the new .cs files you posted. It does not seem to work either.


Code:
[COLOR="Red"]Errors:
 + Customs/Xml Spawner/XmlQuestGuilds/QuestGuildRewardStone.cs:
    CS0234: Line 13: The type or namespace name 'Rewards' does not exist in the
namespace 'Server.Engines' (are you missing an assembly reference?)
    CS0246: Line 17: The type or namespace name 'StoneRewardVendor' could not be
 found (are you missing a using directive or an assembly reference?)[/COLOR]
 

LordHogFred

Knight
Nockar;851066 said:
Thanks for the info.

I tried the new .cs files you posted. It does not seem to work either.


Code:
[COLOR="Red"]Errors:
 + Customs/Xml Spawner/XmlQuestGuilds/QuestGuildRewardStone.cs:
    CS0234: Line 13: The type or namespace name 'Rewards' does not exist in the
namespace 'Server.Engines' (are you missing an assembly reference?)
    CS0246: Line 17: The type or namespace name 'StoneRewardVendor' could not be
 found (are you missing a using directive or an assembly reference?)[/COLOR]

Have you renamed any of your Customizable Vendor classes?
If so then just change the reward stone to use those as it's base class instead :).
 

Nockar

Sorceror
LordHogFred;851068 said:
Have you renamed any of your Customizable Vendor classes?
If so then just change the reward stone to use those as it's base class instead :).

Hi there, thanks for the speedy response!

I don’t think I have renamed anything. They are strait from the zip into the runuo dir. I checked with winmerge make sure nothing was getting removed and it didn’t.

So they are strait from the zip with no edits.
 

LordHogFred

Knight
Hmm, must be named differently then.
Did you get the XML version of the Customizable Vendor? If not then you need that one, either way just edit the QuestRewardStone to inheirt from whatever the vendor reward stone is.
 

Nockar

Sorceror
LordHogFred;851075 said:
Hmm, must be named differently then.
Did you get the XML version of the Customizable Vendor? If not then you need that one, either way just edit the QuestRewardStone to inheirt from whatever the vendor reward stone is.

The Complete Customizable Vendor
[RC2] Rewards System - XML Attachments .cs

\XmlQuestGuilds\New\ *all files*

QuestGuildRewardStone.cs

\Mondain's Legacy\Engines\Quests\ *All 3 edited files*

Where is the vendor reward stone that you are talking about? Maybe I don’t even have it.
I did fine StoneRewardVendor in the complete customizable vendor script. Its the same as in QuestGuildRewrdStone.cs StoneRewardVendor. But cant find anything about
using Server.Engines.Rewards;
 

LordHogFred

Knight
Nockar;851078 said:
The Complete Customizable Vendor
[RC2] Rewards System - XML Attachments .cs

\XmlQuestGuilds\New\ *all files*

QuestGuildRewardStone.cs

\Mondain's Legacy\Engines\Quests\ *All 3 edited files*

Where is the vendor reward stone that you are talking about? Maybe I don’t even have it.

It's in the reward vendor script itself. just search for stone see where it is.
 

Nockar

Sorceror
LordHogFred;851079 said:
It's in the reward vendor script itself. just search for stone see where it is.

What reward vendor script are you talking about? Are you talking about this ?
[RC2] Rewards System - XML Attachments .cs

Code:
//Author: krazeykow
//Version: 1.0.1

using System;
using Server;
using Server.Items;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Server.Gumps;
using Server.Network;
using Server.Targeting;
using Server.Mobiles;
using Server.ContextMenus;
using Server.Engines.XmlSpawner2;

namespace System.CustomizableVendor
{

public class Currency : Item
{

    private Payment m_Payment;
    private PropertyInfo m_PropertyInfo;
    private Type m_Payment_Type;
    private Type m_XML_Type;
    private int m_ItemID;
    private string m_Name;
    private int m_Hue;

    public Type XMLType { get { return m_XML_Type; } }
    public Type PaymentType { get { return m_Payment_Type; } }
    public string PayName { get { return m_Name; } }
    public int PayID { get { return m_ItemID; } }
    public int CurrHue { get { return m_Hue; } } 

    public enum Payment
    {
        ByGold,
        ByItem,
        ByProperty,
        ByXMLAttachment
    }
    //default
    public Currency()
    {
        m_Payment = Payment.ByGold;
        m_Payment_Type = typeof(Gold);
        m_PropertyInfo = null;
        m_ItemID = 3823;
        m_Name = "Gold";
    }
    public Currency(object bindedTo, Type attachType, PropertyInfo attachProp)
    {
        m_XML_Type = attachType;
        m_Payment = Payment.ByXMLAttachment;
        m_Payment_Type = bindedTo.GetType();
        m_PropertyInfo = attachProp;

        if (bindedTo is Mobile) {
            m_ItemID = 8461;
            m_Name = "Player " + attachProp.Name;
        }
        else if (bindedTo is Item) {
            m_ItemID = ((Item)bindedTo).ItemID;
            m_Name = GetName((Item)bindedTo) + "'s " + attachProp.Name;
            m_Hue = ((Item)bindedTo).Hue;
        }

    }
    //consume by item
    public Currency(Item i)
    {
        if ( i.GetType().Equals(typeof(Gold)) )
            m_Payment = Payment.ByGold;
        else
            m_Payment = Payment.ByItem;

        m_Payment_Type = i.GetType();
        m_PropertyInfo = null;
        m_ItemID = CoinID(i.ItemID);
        m_Name = GetName(i);
        m_Hue = i.Hue;
    }
    //consume property on player
    public Currency(Mobile m, PropertyInfo pi)
    {
        m_Payment = Payment.ByProperty;
        m_Payment_Type = m.GetType();
        m_PropertyInfo = pi;
        m_ItemID = 8461;
        m_Name = "Player " + pi.Name;
    }
    //consume by item's number based property
    public Currency(Item i, PropertyInfo pi)
    {
        m_Payment = Payment.ByProperty;
        m_Payment_Type = i.GetType();
        m_PropertyInfo = pi;
        m_ItemID = CoinID(i.ItemID);
        m_Name = GetName(i) + "'s " + pi.Name;
        m_Hue = i.Hue;
    }
    public void Modify(Type t, string append)
    {
        if ( (t.Equals(typeof(PlayerMobile)) || append == null ))
            return;

        Item i;
        
        i = (Item)Activator.CreateInstance(t, null);
        m_Name = GetName(i) + append;
        m_Hue = i.Hue;
        m_ItemID = CoinID(m_ItemID);
        
    }
    public int CoinID(int itemID)
    {
        if (itemID == 3821)
            return 3823;
        else if (itemID == 3824)
            return 3826;
        else
            return itemID;
    }
    public void VOneUpdate()
    {
        switch (m_Payment)
        {
            case Payment.ByGold:
            case Payment.ByItem:
                {
                    Modify(m_Payment_Type, "");
                    break;
                }
            case Payment.ByProperty:
                {
                    if (!(m_Payment_Type.Equals(typeof(PlayerMobile))))
                        Modify(m_Payment_Type, "'s " + m_PropertyInfo.Name);
                    break;
                }
        }

     }

    public string GetName(Item i)
    {
        if (String.IsNullOrEmpty(i.Name))
            return i.GetType().Name;
        else
            return i.Name;
    }
    public bool Purchase(Mobile m, int cost)
    {
        int remain = Value(m) - cost;

        if (remain < 0 || m.Backpack == null)
            return false;
        
        Charge(m, cost, remain);

        return true;
    }
    public void Charge(Container pack, Container bank, Type t, int cost)
    {
        if ( pack == null || bank == null )
            return;

        cost = cost - pack.ConsumeUpTo(t, cost);

        if ( cost > 0 )
            bank.ConsumeUpTo(t, cost);
    }
   
    public void Charge(Mobile m, Type t, PropertyInfo pi, int cost, int remain)
    {
        try
        {
            if (t.BaseType.Equals(typeof(Mobile)) || t.Equals(typeof(PlayerMobile)))
            {
                SetPropertyValue(m, remain);
            }
            else
            {
                if (m.Backpack == null || m.FindBankNoCreate() == null)
                    return;

                Item[] packItems = m.Backpack.FindItemsByType(t);
                Item[] bankItems = m.FindBankNoCreate().FindItemsByType(t);

                Item[] items = new Item[packItems.Length + bankItems.Length];
                packItems.CopyTo(items, 0);
                bankItems.CopyTo(items, packItems.Length);

                //none found in backpack
                if (items == null)
                    return;

                int i = 0, value = 0, dif = 0;

                //account for multiple objects
                while (cost > 0 && i < items.Length)
                {
                    value = GetPropertyValue(items[i]);

                    dif = value - cost;

                    //one item has enough
                    if (dif >= 0)
                    {
                        SetPropertyValue(items[i], dif);
                    }
                    //take what amount item has (the amount has already been confirmed by Value(m))
                    else // assert (dif < 0)
                    {
                        cost -= GetPropertyValue(items[i]);
                        SetPropertyValue(items[i], 0);
                    }
                    i++;
                }
            }
        }
        catch { }
    }
    public void Charge(Mobile m, Container pack, Container bank, int cost)
    {
        if ( pack == null || bank == null )
            return;

        cost = cost - pack.ConsumeUpTo(typeof(Gold), cost);

        if (cost > 0)
            Banker.Withdraw(m, cost);
    }
    public void Charge(Mobile m, int cost, int remain)
    {
        switch (m_Payment)
        {
            case Payment.ByGold:
                Charge(m, m.Backpack, m.FindBankNoCreate(), cost);
                break;
            case Payment.ByItem:
                Charge(m.Backpack, m.FindBankNoCreate(), m_Payment_Type, cost);
                break;
            case Payment.ByXMLAttachment:
            case Payment.ByProperty:
                Charge(m, m_Payment_Type, m_PropertyInfo, cost, remain);
                break;
        }
    }
    public int Value(Mobile m)
    {
        switch (m_Payment)
        {
            case Payment.ByGold:
                return ProcessByGold(m);
            case Payment.ByItem:
                return ProcessByItem(m, m_Payment_Type);
            case Payment.ByXMLAttachment:
            case Payment.ByProperty:
                return ProcessByProperty(m, m_Payment_Type, m_PropertyInfo);                       
        }
        return 0;
    }

    public int ProcessByGold(Mobile m)
    {
        if (m.Backpack == null)
            return 0;

        int totalGold = 0;

        totalGold += m.Backpack.GetAmount( typeof( Gold ) );
        totalGold += Banker.GetBalance( m );

        return totalGold;
    }
    public int ProcessByItem(Mobile m, Type t)
    {
        Container pack = m.Backpack;
        Container bank = m.FindBankNoCreate();

        if (pack == null || bank == null)
            return 0;

        int amount = (pack.GetAmount(t) + bank.GetAmount(t));

        return amount;
    }
    public int ProcessByProperty(Container pack, Container bank, Type t, PropertyInfo pi)
    {
        if (pack == null || bank == null)
            return 0;


        Item[] packItems = pack.FindItemsByType(t);
        Item[] bankItems = bank.FindItemsByType(t);

        Item[] items = new Item[packItems.Length + bankItems.Length];
        packItems.CopyTo(items, 0);
        bankItems.CopyTo(items, packItems.Length);
        
        int sum = 0;

        foreach (object o in items)
        {
            sum += GetPropertyValue(o);
        }

        return sum;
    }
    public int GetPropertyValue(object o)
    {
        int val = 0;

        if (m_Payment == Payment.ByXMLAttachment)
        {
            val = GetXMLValue(o);
        }
        else
        {
            val = (int)m_PropertyInfo.GetValue(o, null);
        }

        return val;
    }
    public void SetPropertyValue(object o, int val)
    {
        if (m_Payment == Payment.ByXMLAttachment)
        {
            SetXMLValue(o, val);
        }
        else
        {
            m_PropertyInfo.SetValue(o, val, null);
        }       
    }
    public int GetXMLValue(object o)
    {      
        int val = 0;

        if (m_XML_Type == null)
            return val;

        XmlAttachment attach = XmlAttach.FindAttachment(o, m_XML_Type);

        if (attach != null) {           
            val = (int)m_PropertyInfo.GetValue(attach, null);           
        }
        return val;
    }
    public void SetXMLValue(object o, int val)
    {
        if (m_XML_Type == null)
            return;

        XmlAttachment attach = XmlAttach.FindAttachment(o, m_XML_Type);

        if (attach != null) { 
            m_PropertyInfo.SetValue(attach, val, null);           
        }
    }
    //Master
    public int ProcessByProperty(Mobile m, Type t, PropertyInfo pi)
    {
        try
        { 

            if (t.BaseType.Equals(typeof(Mobile)) || t.Equals(typeof(Mobile)) )
            {
                return GetPropertyValue(m);
            }
            else
            {
                return ProcessByProperty(m.Backpack, m.FindBankNoCreate(), t, pi);
            }
        }
        catch {}
        
        return 0;
        
    }
   
    public Currency( Serial serial ) : base( serial )
	{
	}
	public override void Serialize( GenericWriter writer )
	{
		base.Serialize( writer );
		writer.Write( (int) 2 );

        //version 2
        writer.Write((string)(m_XML_Type == null ? "" : m_XML_Type.Name));

        //version 1
        writer.Write((int)m_Hue);
        
        //explicit casts are given for clarification        
        writer.Write((int)m_Payment);
        writer.Write((string)m_Payment_Type.Name);
        writer.Write((string)(m_PropertyInfo == null ? "" : m_PropertyInfo.Name));
        writer.Write((int)m_ItemID);
        writer.Write((string)m_Name);
        
	}
	
	public override void Deserialize(GenericReader reader)
	{
		base.Deserialize( reader );
		int version = reader.ReadInt();


        switch (version)
        {
            case 2:
                {
                    try
                    {
                        string name = reader.ReadString();
                        if (name.Equals(""))
                        {
                            m_XML_Type = null;
                        }
                        else
                        {
                            m_XML_Type = ScriptCompiler.FindTypeByName(name);
                        }
                    }
                    catch { }

                    goto case 1;
                }
            case 1:
                {
                    m_Hue = reader.ReadInt();
                    goto case 0;
                }
            case 0:
                {
                    m_Payment = (Payment)reader.ReadInt();

                    try { string name = reader.ReadString(); m_Payment_Type = ScriptCompiler.FindTypeByName(name); }
                    catch { }

                    try
                    {
                        string propName = reader.ReadString();
                        if (propName.Equals("")) //never set
                        {
                            m_PropertyInfo = null;
                        }
                        else if (m_Payment == Payment.ByXMLAttachment && m_XML_Type != null) //XML requires find property by the XML Class type (m_XML_Type)
                        {
                            m_PropertyInfo = m_XML_Type.GetProperty(propName);
                        }
                        else 
                        { 
                            m_PropertyInfo = m_Payment_Type.GetProperty(propName); 
                        }
                    }
                    catch { }

                    m_ItemID = reader.ReadInt();
                    m_Name = reader.ReadString();

                    break;
                }
        }
        if (version == 0)
        {
            try { VOneUpdate(); }
            catch {  }
        }
     }
}

public class Reward : Item, ICloneable
{      
    private Item m_Reward;
    private int m_Cost;
    private string m_Title;
    private string m_Description;

    private ObjectPropertyList m_Display;

    private RestockInfo m_RestockInfo;
    private int m_BuyCount;

    public int BuyCount { get { return m_BuyCount; } set { m_BuyCount = value; } }
    public RestockInfo Restock { get { return m_RestockInfo; } set { m_RestockInfo = value; } }

    public ObjectPropertyList Display
    {
        get
        {
            if (m_Display == null)
            {
                m_Display = new ObjectPropertyList(this);

                m_Reward.GetProperties(m_Display);
                m_Reward.AppendChildProperties(m_Display);

                m_Display.Terminate();
                m_Display.SetStatic();
            }

            return m_Display;
        }
    }

    public void Void_RestockInfo()
    {
        m_RestockInfo = null;
    }
    //returns ((-1) -> no restockInfo) or current count
    public int Try_Restock()
    {
        if (m_RestockInfo == null)
            return -1;        

        TimeSpan dif = DateTime.Now - m_RestockInfo.LastRestock;
        int cycles = 0;

        if (dif > (m_RestockInfo.RestockRate) && m_RestockInfo.RestockRate.TotalMinutes > 0)
        {
            cycles = (int)(dif.TotalMinutes / m_RestockInfo.RestockRate.TotalMinutes);

            for (int i = 0; i < cycles; ++i)
            {
                if (m_RestockInfo.Restock())
                    continue;
            }
        }

        return m_RestockInfo.Count;
    }
    public bool InStock(int amount)
    {
        return (m_RestockInfo == null ? true : (m_RestockInfo.Count - amount >= 0));       
    }
    public void RegisterBuy(int amount)
    {      
        if (m_RestockInfo != null && InStock(amount))
            m_RestockInfo.Count -= amount;

        this.m_BuyCount += amount;
    }

    //for retrieving information only
    public Item RewardInfo
    {
        get { return m_Reward; }
    }
    //use only when creating Reward for player
    public Item RewardCopy
    {
        get { return GetReward(); }
    }
    public int Cost
    {
        get { return m_Cost; }
        set { m_Cost = value; }
    }
    public string Title
    {
        get { return m_Title; }
        set { m_Title = value; }
    }
    public string Description
    {
        get { return m_Description; }
        set { m_Description = value; }
    }
    object ICloneable.Clone()
    {
        return new Reward(this);
    }
    public Reward()
    {
        m_Reward = new Item();
        m_Cost = 0;
        m_Title = "";
        m_Description = "";
        m_RestockInfo = null;
    }
    public Reward(Reward r)
    {
        m_Reward = r.RewardCopy;
        m_Cost = r.Cost;
        m_Title = r.Title;
        m_Description = r.Description;
        m_RestockInfo = null;
    }
    public Reward(Item i)
    {
        m_Reward = i;
        m_Cost = 0;
        m_Title = (i.Name == null ? i.GetType().Name : i.Name);
        m_Description = "None.";
        m_RestockInfo = null;

    }
    public Reward(Item i, int cost)
    {
        m_Reward = i;
        m_Cost = cost;
        m_Title = (i.Name == null ? i.GetType().Name : i.Name);
        m_Description = "None.";
        m_RestockInfo = null;
    }
    public Reward(Item i, int cost, string title)
    {
        m_Reward = i;
        m_Cost = cost;
        m_Title = title;
        m_Description = "None.";
        m_RestockInfo = null;
    }
    public Reward(Item i, int cost, string title, string desc)
    {
        m_Reward = i;
        m_Cost = cost;
        m_Title = title;
        m_Description = desc;
        m_RestockInfo = null;
    }

    public class RestockInfo 
    {
        private TimeSpan m_RestockRate;
        private DateTime m_LastRestock;

        private int m_RestockAmnt;
        private int m_Count;
        private int? m_Maximum;
        
        public TimeSpan RestockRate { get { return m_RestockRate; } }
        public DateTime LastRestock { get { return m_LastRestock; } }

        public int RestockAmnt { get { return m_RestockAmnt; } }
        public int Count { get { return m_Count; } set { m_Count = value; } }
        public int Maximum { get { return m_Maximum.GetValueOrDefault(-1); } }

        public int Hours { get { return (int)m_RestockRate.Hours; } }
        public int Minutes { get { return (int)m_RestockRate.Minutes; } }

        public RestockInfo()
        {
            m_RestockRate = new TimeSpan();
            m_RestockAmnt = 0;
            m_Count = 0;
            m_Maximum = null;
            m_LastRestock = DateTime.Now;

        }
        public RestockInfo(int count) : this()
        {
            m_Count = count;
        }
        public RestockInfo(int hour, int minute, int count, int RestockNum)
        {
            m_RestockRate = new TimeSpan(hour, minute, 0);
            m_Count = count;
            m_RestockAmnt = RestockNum;
            m_Maximum = null;
            m_LastRestock = DateTime.Now;

        }
        public RestockInfo(int hour, int minute, int count, int RestockNum, int maxNum) : this (hour, minute, count, RestockNum)
        {
            m_Maximum = maxNum;
        }
        public bool Equals(RestockInfo info)
        {
            return (this.m_RestockRate.Equals(info.RestockRate) && (this.m_RestockAmnt == info.RestockAmnt) && (this.m_Count == info.Count)
                && (this.m_Maximum == info.Maximum));
        }
        public bool Restock()
        {
            m_LastRestock = DateTime.Now;

            if (m_Maximum != null) //Restock to a limit
            {
                if ((m_Count + m_RestockAmnt) > m_Maximum)
                {
                    m_Count = m_Maximum.Value;
                    return false;
                }

                m_Count += m_RestockAmnt;
                return true;
            }
            
            m_Count += m_RestockAmnt;            
            return true;
        }

        public void Serialize( GenericWriter writer )
        {
            writer.Write((TimeSpan)m_RestockRate);           
            writer.Write((int)m_RestockAmnt);
            writer.Write((int)m_Count);
            writer.Write((int)m_Maximum.GetValueOrDefault(-1));
        }

        public RestockInfo( GenericReader reader )
        {
            m_RestockRate = reader.ReadTimeSpan();
            m_LastRestock = DateTime.Now;
            m_RestockAmnt = reader.ReadInt();
            m_Count = reader.ReadInt();
            
            int? max = reader.ReadInt();
         
            m_Maximum = ((max < 0) ? null : max);
        }
    }

    public void Edit(int cost, string title, string desc)
    {
        if (cost < 0 || title == null || desc == null)
            return;

        m_Cost = cost;
        m_Title = title;
        m_Description = desc;
    }
    public Item GetReward()
    {
        return ItemClone.Clone(m_Reward);
    }

    public Reward( Serial serial ) : base( serial )
	{
	}
	public override void Serialize( GenericWriter writer )
	{
		base.Serialize( writer );

		writer.Write( (int) 1 );

        writer.Write((int)m_BuyCount);

        if (m_RestockInfo == null)
        {
            writer.Write(false);
        }
        else
        {
            writer.Write(true);
            m_RestockInfo.Serialize(writer);
        }

        writer.WriteItem((Item)m_Reward);
        writer.Write((int)m_Cost);
        writer.Write((string)m_Title);
        writer.Write((string)m_Description);          
    }
	
	public override void Deserialize(GenericReader reader)
	{
		base.Deserialize( reader );
		int version = reader.ReadInt();

        switch (version)
        {
            case 1:
                {
                    m_BuyCount = reader.ReadInt();

                    if (reader.ReadBool())
                        m_RestockInfo = new RestockInfo(reader);

                    goto case 0;
                }
            case 0:
                {
                    m_Reward = (Item)reader.ReadItem();
                    m_Cost = reader.ReadInt();
                    m_Title = reader.ReadString();
                    m_Description = reader.ReadString();                  
                    
                    break;
                }
        }
    
	}

}
public class RewardCollection : List<Reward>, ICloneable
{
    

    object ICloneable.Clone()
    {
        RewardCollection clone = new RewardCollection();
        
        foreach (Reward r in this)
        {
            clone.Add(((Reward)(r as ICloneable).Clone()));
        }
        return clone;
    }
}

public static class WorldRewardVendors
{
    private static List<IRewardVendor> m_Vendors = new List<IRewardVendor>();

    public static List<IRewardVendor> Vendors { get { return m_Vendors; } }
   
    public static void RegisterVendor(IRewardVendor vendor)
    {
        m_Vendors.Add(vendor);
    }
    public static void RemoveVendor(IRewardVendor vendor)
    {
        m_Vendors.Remove(vendor);
    }
}

public class EditItemGump : Gump
{
    private IRewardVendor m_Vendor;
    private Reward m_Reward;

    private Reward.RestockInfo m_Restock;
    private bool m_RestockOpen;

    private bool m_IsAdd;

    private Storage m_Entries;

    public EditItemGump(IRewardVendor vendor, Reward r, Storage entries, bool openRestockInfo, bool addingItem) : base(0, 0)
    {
        m_Vendor = vendor;
        m_Reward = r;

        m_Restock = r.Restock;
        m_RestockOpen = openRestockInfo;
        m_IsAdd = addingItem;

        m_Entries = entries; 

        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        AddImageTiled(227, 46, 329, 518, 2702);
        AddImageTiled(252, 291, 280, 217, 5104);
        AddLabel(253, 266, 2124, @"Description:");
        AddImageTiled(334, 147, 192, 23, 5104);
        AddLabel(258, 150, 2124, @"Cost:");
        AddImageTiled(336, 107, 192, 23, 5104);
        AddLabel(258, 108, 2124, @"Name:");
        AddImage(354, 199, 2328);
        AddItem(373, 208, r.RewardInfo.ItemID, r.RewardInfo.Hue);
        AddImageTiled(330, 54, 138, 16, 5214);
        AddLabel(373, 51, 1324, @"Edit Item");
        AddButton(465, 222, 5601, 5605, 2, GumpButtonType.Reply, 0); //restock
        AddLabel(447, 198, 2120, @"Restock ");
        AddLabel(447, 246, 2120, @"(Optional)");
        AddButton(324, 523, 4023, 4024, 1, GumpButtonType.Reply, 0);//ok
        AddButton(421, 523, 4017, 4018, 0, GumpButtonType.Reply, 0); //cancel

        if (entries == null)
            InitialText();
        else
            PacketText();

        if (openRestockInfo || r.Restock != null)
        {
            AddRestockMenu();
            m_RestockOpen = true;
        }
    }
    public void InitialText()
    {
        AddTextEntry(252, 292, 277, 215, 1879, 0, m_Reward.Description);
        AddTextEntry(334, 148, 188, 20, 1879, 1, m_Reward.Cost.ToString());
        AddTextEntry(336, 108, 188, 20, 1879, 2, m_Reward.Title);    
    }
    public void PacketText()
    {
        AddTextEntry(252, 292, 277, 215, 1879, 0, m_Entries[0].ToString()); //desc
        AddTextEntry(334, 148, 188, 20, 1879, 1, m_Entries[1].ToString());  //cost 
        AddTextEntry(336, 108, 188, 20, 1879, 2, m_Entries[2].ToString());  //title
    }
    public void AddRestockMenu()
    {

        AddPage(1);

        AddImageTiled(601, 47, 181, 469, 2624);
        AddLabel(648, 60, 2129, @"Restock Info");
        AddLabel(637, 98, 1418, @"Available");
        AddImageTiled(633, 123, 120, 16, 5214);
        AddTextEntry(637, 121, 107, 20, 547, 3, (m_Restock == null ? "Enter." : m_Restock.Count.ToString())); //3 - beginning amount
        AddLabel(660, 161, 1418, @"Maximum");
        AddImageTiled(631, 186, 120, 16, 5214);
        AddTextEntry(635, 184, 107, 20, 547, 4, ((m_Restock == null || m_Restock.Maximum < 0) ? "None." : m_Restock.Maximum.ToString())); //4 - Maxinum
        AddLabel(648, 227, 1418, @"Restock Rate");
        AddImageTiled(635, 252, 72, 16, 5214);
        AddTextEntry(638, 250, 64, 20, 547, 5, (m_Restock == null ? "0" : m_Restock.Hours.ToString())); //5 - hour
        AddLabel(714, 250, 602, @"hours");
        AddImageTiled(635, 292, 72, 16, 5214);
        AddLabel(716, 290, 602, @"mins");
        AddLabel(632, 323, 602, @"amount to restock");
        AddImageTiled(636, 355, 72, 16, 5214);
        AddTextEntry(638, 290, 64, 20, 547, 6, (m_Restock == null ? "0" : m_Restock.Minutes.ToString())); //6 - minute
        AddTextEntry(639, 353, 64, 20, 547, 7, (m_Restock == null ? "0" : m_Restock.RestockAmnt.ToString())); //7 - Restock Amount      
        AddImage(655, 377, 109);
        AddButton(636, 474, 4022, 4021, 3, GumpButtonType.Reply, 0);
        AddLabel(679, 475, 132, @"Void Restock");
        
    }
    public Reward.RestockInfo GetRestockInfo(RelayInfo info)
    {
        if (m_RestockOpen)
        {
            int numMinutes = 0, numHours = 0;
            int numBegin, numMax, numRestockAmnt;

            TextRelay entry3 = info.GetTextEntry(3);
            string beginAmount = (entry3.Text.Trim());

            TextRelay entry4 = info.GetTextEntry(4);
            string max = (entry4.Text.Trim());

            TextRelay entry5 = info.GetTextEntry(5);
            string hour = (entry5.Text.Trim());

            TextRelay entry6 = info.GetTextEntry(6);
            string minute = (entry6.Text.Trim());

            TextRelay entry7 = info.GetTextEntry(7);
            string restockAmount = (entry7.Text.Trim());

            Int32.TryParse(hour, out numHours);
            Int32.TryParse(minute, out numMinutes);
            Int32.TryParse(beginAmount, out numBegin);
            Int32.TryParse(max, out numMax);
            Int32.TryParse(restockAmount, out numRestockAmnt);

            if (numBegin > 0)
            {
                if ((numMinutes + numHours) > 0 && numRestockAmnt > 0)
                {
                    if (numMax > 0)
                    {
                        return new Reward.RestockInfo(numHours, numMinutes, numBegin, numRestockAmnt, numMax);
                    }
                    else
                    {
                        return new Reward.RestockInfo(numHours, numMinutes, numBegin, numRestockAmnt);
                    }
                }

                return new Reward.RestockInfo(numBegin);
            }                   
        }
        return m_Restock; //default
    }
    public Storage GetEntries(RelayInfo info)
    {
        //Description
        TextRelay entry0 = info.GetTextEntry(0);
        string desc = (entry0 == null ? "None." : entry0.Text.Trim());

        //Cost
        TextRelay entry1 = info.GetTextEntry(1);
        string costtext = (entry1 == null ? "0" : entry1.Text.Trim());

        //Name
        TextRelay entry2 = info.GetTextEntry(2);
        string name = (entry2 == null ? "" : entry2.Text.Trim());

        return new Storage(desc, costtext, name);
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        switch (info.ButtonID)
        {
            case 0:
                {
                    //cancel
                    break;
                }
            case 1: //ok
                {
                    try
                    {
                        //Description
                        TextRelay entry0 = info.GetTextEntry(0);
                        string desc = (entry0 == null ? "None." : entry0.Text.Trim());

                        //Cost
                        TextRelay entry1 = info.GetTextEntry(1);
                        string costtext = (entry1 == null ? "%Error" : entry1.Text.Trim());
                        int cost = Int32.Parse(costtext);

                        //Name
                        TextRelay entry2 = info.GetTextEntry(2);
                        string name = (entry2 == null ? "" : entry2.Text.Trim());

                        if ( m_IsAdd )
                            m_Vendor.AddReward(m_Reward);
                        
                        m_Reward.Edit(cost, name, desc);

                        if (m_RestockOpen)
                        {
                            Reward.RestockInfo input = GetRestockInfo(info);

                            if (input != null)
                            {
                                if (m_Restock != null && !(m_Restock.Equals(input))) //do not reassign same object
                                {
                                    m_Reward.Restock = input;
                                }
                                else
                                {
                                    m_Reward.Restock = input;
                                }
                            }
                        }

                        m.SendMessage("{0} has been modified in {1}'s collection", name, m_Vendor.GetName());

                    }
                    catch { m.SendMessage("Please make sure all fields are filled correctly, and the title has not been previously used."); }

                    break;
                }
            case 2: //open restock options
                {                                  
                    m.SendGump(new EditItemGump(m_Vendor, m_Reward, GetEntries(info), true, m_IsAdd));
                    
                    return; //override display 
                }
            case 3: //delete restock options
                {                   
                    m_Reward.Void_RestockInfo();
                                    
                    m.SendGump(new EditItemGump(m_Vendor, m_Reward, GetEntries(info), false, m_IsAdd));
                    
                    return; //override display 
                }
        }
        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, true); //send back display
    }
}

public class Exhibit : Item
{
    private IRewardVendor m_Vendor;
    private Reward m_Reward;
    private ObjectPropertyList m_PropertyList;

    public Exhibit(IRewardVendor vendor, Reward r)
        : base()
    {
        m_Vendor = vendor;
        m_Reward = r;

        SetOPL(r);

        this.ItemID = r.RewardInfo.ItemID;
        this.Hue = r.RewardInfo.Hue;
    }
    public override void SendPropertiesTo(Mobile from)
    {
        if (m_PropertyList == null)
        {
            m_PropertyList = new ObjectPropertyList(this);
            m_PropertyList.Add("Display [Broken]");
        }

        from.Send(m_PropertyList);
    }
    public void SetOPL(Reward r)
    {
        Item i = r.RewardInfo;

        m_PropertyList = new ObjectPropertyList(this);

        m_PropertyList.Add("Cost: " + m_Reward.Cost.ToString() + " " + m_Vendor.Payment.PayName + " [Click for more]");

        i.GetProperties(m_PropertyList);
        i.AppendChildProperties(m_PropertyList);

        m_PropertyList.Terminate();
        m_PropertyList.SetStatic();

    }

    public override void OnDoubleClick(Mobile m)
    {
        if (m_Vendor == null || m_Vendor.IsRemoved() || m_Reward == null || !m_Vendor.Display.Contains(m_Reward))
        {
            m_Vendor = null; // free up resource
            m_Reward = null;
            m.SendMessage("This item is no longer available to purchase.");
        }
        else
            m.SendGump(new ViewItemGump(m, m_Vendor, m_Reward, false));
    }

    public Exhibit(Serial serial)
        : base(serial)
    {
    }
    public override void Deserialize(GenericReader reader)
    {
        base.Deserialize(reader);

        int version = reader.ReadInt();

        if (reader.ReadBool())
        {
            m_Reward = (Reward)reader.ReadItem();

            m_Vendor = (IRewardVendor)reader.ReadMobile();

            try { SetOPL(m_Reward); }
            catch { }
        }
    }

    public override void Serialize(GenericWriter writer)
    {
        base.Serialize(writer);

        writer.Write((int)0); // version  

        if (m_Vendor == null || m_Vendor.IsRemoved() || m_Reward == null || m_Reward.Deleted)
        {
            m_Vendor = null;
            m_Reward = null;

            writer.Write((bool)false); //do not deserialize
        }
        else
        {
            writer.Write((bool)true);

            writer.WriteItem((Reward)m_Reward);

            writer.Write((Mobile)m_Vendor.GetMobile());
        }
    }
}
public class ViewItemGump : Gump
{
    IRewardVendor m_Vendor;
    Reward m_Reward;

    public ViewItemGump(Mobile m, IRewardVendor vendor, Reward r, bool viewItem)
        : base(0, 0)
    {
        m_Vendor = vendor;
        m_Reward = r;

        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);
        AddImageTiled(149, 207, 548, 277, 2624);
        AddImage(184, 300, 2328);
        AddImage(101, 222, 10400);
        
        AddHtml(428, 290, 243, 140, r.Description, (bool)true, (bool)true);
        AddItem(201, 311, r.RewardInfo.ItemID, r.RewardInfo.Hue);
                
        AddLabel(430, 263, 2101, @"Description");
        AddButton(192, 442, 4029, 4030, 2, GumpButtonType.Reply, 0); //buy
        AddLabel(231, 444, 2125, "Buy (" + r.Cost +")");
        AddButton(366, 442, 4020, 4021, 0, GumpButtonType.Reply, 0); //cancel
        AddLabel(407, 444, 2116, @"Cancel");
        AddImageTiled(184, 239, 510, 8, 9201);

        AddItem(182, 376, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);
        AddLabel(248, 369, 83, @"Pay By: " + m_Vendor.Payment.PayName);
        AddLabel(184, 268, 43, @"Vendor: " + m_Vendor.GetName());
        AddLabel(363, 216, 2123, r.Title);

        if (m.AccessLevel > AccessLevel.GameMaster) //GM capabilities
        {
            if (!viewItem)
                AddLabel(363, 216, 2123, r.Title);
            else
            {
                AddLabel(336, 296, 2101, @"Edit Item");
                AddButton(294, 293, 4011, 4012, 4, GumpButtonType.Reply, 0); //edit item

                if (m_Vendor.GetMobile() != null)
                {
                    AddLabel(336, 348, 2101, @"Get Display");
                    AddButton(294, 345, 4011, 4012, 3, GumpButtonType.Reply, 0); //get display   
                }
            }
        }
        else
        {
            OpenDisplay(m); //prevent build up of box display during editing
        }

        //Edit gump for display object
        if (viewItem) //not display
        {
            AddLabel(336, 322, 2101, @"View Item");
            AddButton(294, 319, 4011, 4012, 1, GumpButtonType.Reply, 0); //view item
                    
        }
        else //display
        {
            AddLabel(279, 320, 38, @"Cost: " + m_Reward.Cost.ToString());
            AddLabel(249, 398, 69, @"You have: " + m_Vendor.Payment.Value(m));

            if (m_Reward.Restock != null)
            {
                m_Reward.Try_Restock();
                AddLabel(279, 340, 4, "In Stock: " + m_Reward.Restock.Count.ToString());
            }

            if (m_Reward.RewardInfo is Container)
                OpenDisplay(m); 
        }
    }
    public void OpenDisplay(Mobile m)
    {
        DisplayBox dbox = m_Vendor.Display;

        if (dbox != null)
            dbox.DisplayTo(m, m_Reward);
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (m_Vendor.IsRemoved())
            return;

        switch (info.ButtonID)
        {
            case 0:
                {
                    break;
                }
            case 1:
                {
                    try
                    {
                        OpenDisplay(m);
                        m.SendGump(this);
                    }
                    catch
                    {
                        m.SendMessage("This Reward can no longer be found.");
                    }
                    break;
                }
            case 2:
                {
                    Container bank = m.BankBox;
                    Container pack = m.Backpack;

                    if ( bank == null || pack == null )
                        break;

                    Currency curr = m_Vendor.Payment;

                    if (m_Reward.InStock(1))
                    {
                        if (curr.Purchase(m, m_Reward.Cost))
                        {
                            m_Reward.RegisterBuy(1);

                            Item i = m_Reward.RewardCopy;

                            if (!m.PlaceInBackpack(i))
                            {
                                bank.DropItem(i);
                                m.SendMessage("You are overweight, the Reward was added to your bank");
                            }

                            m.SendMessage("You bought {0} for {1} {2}.", m_Reward.Title, m_Reward.Cost, curr.PayName);

                        }
                        else
                            m.SendMessage("You cannot afford {0}", m_Reward.Title);
                    }                           
                    else
                        m.SendMessage("{0} is no longer in stock.", m_Reward.Title);  

                    break;
                }
            case 3:
                {
                    if (m.Backpack != null)
                        m.AddToBackpack(new Exhibit(m_Vendor, m_Reward));
                    break;
                }
            case 4:
                {
                    m.SendGump(new EditItemGump(m_Vendor, m_Reward, null, false, false));
                    break;
                }
        }
    }
}

//Created for the usage of Warning Gump delegate 
public class Storage
{
    object[] m_Objs;

    public object this[int index]
    {
        get { return m_Objs[index]; }
    }

    public Storage(params object[] input)
    {
        m_Objs = input;
    }
    
}


public class WorldVendorsGump : Gump
{
    IRewardVendor m_Vendor; //used in case of copy

    public WorldVendorsGump(IRewardVendor vendor) : base( 0, 0 )
    {
        m_Vendor = vendor;

        this.Closable=true;
		this.Disposable=true;
		this.Dragable=true;
		this.Resizable=false;

		AddPage(0);

        //background
        AddImageTiled(50, 3, 430, 556, 2702);
		AddImageTiled(93, 78, 387, 9, 10101);
		AddImage(33, 58, 10420);
		AddImageTiled(47, 2, 3, 556, 10004);
		AddImageTiled(0, 58, 82, 414, 10440);
		AddImageTiled(47, 558, 436, 3, 10001);
		AddImageTiled(47, 0, 435, 3, 10001);
		AddImageTiled(480, 2, 3, 556, 10004);

        AddPage(1);

        CreateVendors(); //fill out entries
    }
    
    public static void CopyVendor_Callback(Mobile from, bool okay, object state)
    {
        if (from.AccessLevel < AccessLevel.GameMaster)
            return;
                
        if (okay)
        {
            //indexes -> (vendor (0), vendor's copy target(1))
            Storage store = (Storage)state;

            IRewardVendor source = (IRewardVendor)store[0];
            IRewardVendor target = (IRewardVendor)store[1];

            try { source.CopyVendor(target); }
            catch { from.SendMessage("Error occured while copying, please insure backpack is on vendors."); return; }

            from.SendMessage("{0} has copied {1}'s Reward collection", source.GetName(), target.GetName());
        }
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
        {
            m.CloseGump(typeof(ControlPanelGump));
            return;
        }

        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);

        try
        {
            if (info.ButtonID % 2 == 0 ) //even ID: Copy Vendor
            {
                IRewardVendor selected = WorldRewardVendors.Vendors[(info.ButtonID / 2) - 1];

                if ( m_Vendor.GetName().Equals(selected.GetName()))
                {
                    m.SendMessage("A vendor cannot copy itself.");
                }
                else
                {
                    //params -> (vendor, vendor's copy target)
                    Storage store = new Storage(m_Vendor, selected);

                    m.SendGump(new WarningGump(1060635, 30720, "Warning: You will lose all saved items on " + m_Vendor.GetName(), 0xFFC000, 420, 400, new WarningGumpCallback(CopyVendor_Callback), store));
                }
            }
            else //assert odd ID: Goto 
            {
                IRewardVendor v = WorldRewardVendors.Vendors[((info.ButtonID + 1) / 2) - 1];

                m.Location = v.GetLocation();
                m.Map = v.GetMap();
            }
        }
        catch
        {
            m.SendMessage("Vendor cannot be found.");
        }
    }
    public void CreateVendors()
    {
        int yPos = 101, pageNum = 1, buttonNum = 0;
      
        for (int i = 0; i < WorldRewardVendors.Vendors.Count; ++i)
        {            
            AddButton(175, yPos + 38, 4005, 4006, ++buttonNum, GumpButtonType.Reply, pageNum); //goto button - odd ID
            AddButton(279, yPos + 38, 4011, 4012, ++buttonNum, GumpButtonType.Reply, pageNum); //copy vendor - even ID
            AddLabel(86, yPos, 1849, WorldRewardVendors.Vendors[i].GetName());
            AddImageTiled(86, yPos + 93, 359, 2, 96);

            if (WorldRewardVendors.Vendors[i].GetMobile() != null)
                AddItem(110, yPos + 27, 8461); // person
            else

                AddItem(110, yPos + 27, WorldRewardVendors.Vendors[i].GetItem().ItemID, WorldRewardVendors.Vendors[i].GetItem().Hue); //stone ID

            AddLabel(213, yPos + 43, 2209, @"Go To");
            AddLabel(318, yPos + 43, 2204, @"Copy Vendor");
            
            yPos += 99;

            //add new page every four entries
            if ((i + 1) % 4 == 0)
            {
                AddButton(417, 531, 9903, 248, -1, GumpButtonType.Page, (pageNum + 1));

                AddPage(++pageNum);

                AddButton(92, 532, 9909, 248, -1, GumpButtonType.Page, (pageNum - 1));

                //reset to top of page
                yPos = 101;
            }
        }
    }
}
public class InfoGump : Gump
{
    public InfoGump()
        : base(0, 0)
    {
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);
        
        AddImageTiled(0, 0, 452, 516, 2702);
        AddHtml(21, 78, 407, 105, @"Consume Item:  Vendor counts the number of the chosen item present in player's backpack.  

        Property(Item/Player):  Vendor takes the total of the given number based property (example: PlayerPoints, Charges)
        (Items): Adds up from every item present.
        (Player): Simply takes from what is present.
        ", (bool)true, (bool)true);

        AddLabel(23, 52, 2000, @"Choosing How Player Pays:");
        AddHtml(21, 242, 407, 105, @"You can create your own rewards in game, all properties will be copied over.  ", (bool)true, (bool)true);
        AddLabel(24, 216, 2000, @"Adding Items");
        AddLabel(239, 479, 37, @"Author: krazeykow1102");
        AddItem(391, 467, 8451);
        AddLabel(24, 368, 2000, @"How Displays Work");
        AddHtml(24, 394, 410, 78, @"Displays allow you to create your own interactive Reward room.  The display is a simple mirror to the item on the vendor.  Payment and cost will reflect what is on the vendor.  Vendor must stay in tact for display to function", (bool)true, (bool)true);
    }
}


public class ControlPanelGump : Gump
{
    private IRewardVendor m_Vendor;
   
    public ControlPanelGump(Mobile m, IRewardVendor vendor)
        : base(0, 0)
    {

        m_Vendor = vendor;
                
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        //background
        AddImageTiled(4, 3, 215, 571, 2702);
        AddImageTiled(3, 0, 217, 3, 10001);
        AddImageTiled(4, 572, 216, 3, 10001);
        AddImageTiled(3, 1, 3, 571, 10004);
        AddImageTiled(217, 1, 3, 574, 10004);

        AddImage(40, 8, 5214);
        AddLabel(41, 7, 47, @"Control Panel");

        AddLabel(109, 62, 55, @"Manage Rewards");
        AddButton(72, 60, 4008, 4009, 1, GumpButtonType.Reply, 0); //PlayerView
        AddItem(31, 63, 5366); //scope
        AddImageTiled(19, 160, 132, 2, 96);

        AddLabel(79, 123, 1324, @"Add Item or Container");
        AddButton(52, 126, 2117, 2118, 2, GumpButtonType.Reply, 0); //AddItem
        AddItem(0, 113, 8192); //box  
        
        AddLabel(11, 232, 55, @"Target Payment Source:");
        AddButton(170,232, 2117, 2118, 3, GumpButtonType.Reply, 0); //Payment
        AddLabel(12, 173, 55, @"Pay By: " + m_Vendor.Payment.PayName );
        AddItem(61, 197, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);

        AddLabel(12, 32, 55, @"Vendor: " + m_Vendor.GetName());
        AddButton(77, 533, 4026, 4027, 4, GumpButtonType.Reply, 0);
        AddLabel(78, 553, 104, @"Help");

        if (m_Vendor.GetMobile() != null)
        {
            AddButton(72, 91, 4011, 4012, 5, GumpButtonType.Reply, 0); //Displays
            AddLabel(109, 93, 55, @"Get All Displays");
        }
        else
            AddLabel(12, 93, 55, @"Use Mobile Vendor for displays.");

       
        AddLabel(51, 258, 43, @"XML Attachment");
        AddRadio(15, 258, 9720, 9724, false, 6);
        AddLabel(51, 303, 43, @"Consume Item");
        AddRadio(15, 300, 9720, 9724, false, 7);
        AddLabel(50, 349, 43, @"[props Name of Item/Player");
        AddRadio(15, 342, 9720, 9724, false, 8);
        AddImageTiled(12, 382, 156, 22, 5058);
        AddTextEntry(12, 382, 149, 20, 41, 0, @"[prop/XML Name Here");

        AddPage(1);

        CreateGumps(); //fill out entries
               
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (m_Vendor.IsRemoved())
        {
            m.SendMessage("This vendor has been deleted.");
            return;
        }

        switch (info.ButtonID)
        {
            case 0:
                {
                    m.CloseGump(typeof(WorldVendorsGump));

                    //close
                    break;
                }
            case 1: //PlayerView
                {
                    m.CloseGump(typeof(WorldVendorsGump));

                    MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, true);
                    break;
                }
            case 2: //AddItem
                {
                    m.CloseGump(typeof(WorldVendorsGump));

                    m.Target = new AddItemTarget(m_Vendor);
                    break;
                }
            case 3: //Payment
                { 
                    
                        try
                        {
                            if (info.IsSwitched(6))
                            {
                                m.SendMessage("Target the player or item you wish to get the XMLAttribute from.");
                                TextRelay entry0 = info.GetTextEntry(0);
                                string propName = (entry0 == null ? "" : entry0.Text.Trim());

                                m.Target = new PaymentTarget(m_Vendor, propName, true);
                            }
                            else if ( info.IsSwitched(7)) // Consume by item amount
                            {
                                m.SendMessage("Warning: payment will be taken as the unmodified created item.");
                                m.Target = new PaymentTarget(m_Vendor);
                            }
                            else if (info.IsSwitched(8)) //Consume by item's property
                            {
                                m.SendMessage("Target yourself or an item.");
                                TextRelay entry0 = info.GetTextEntry(0);
                                string propName = (entry0 == null ? "" : entry0.Text.Trim());

                                m.Target = new PaymentTarget(m_Vendor, propName, false);
                            }
                            else
                            {                                
                                MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);
                                m.SendMessage("Please select consume or property.");
                            }
                        }

                            catch { }

                            break;      
                  }
            case 4:
                {
                    MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);
                    m.SendGump(new InfoGump());
                    break;
                }
            case 5: //Displays
                {
                    if (m.Backpack == null)
                        return;

                    MetalBox c = new MetalBox();
                    c.Name = m_Vendor.GetName() + "'s Reward Displays";

                    foreach (Reward r in m_Vendor.Rewards)
                    {
                        c.DropItem(new Exhibit(m_Vendor, r));
                    }

                    m.AddToBackpack(c);

                    break;
                }

            default: //Set Menu - IDs are >= 7
                {
                    try
                    {
                        Type menuType = MenuUploader.Menus[info.ButtonID - 7];

                        if (m_Vendor.GetItem() != null && menuType.Equals(typeof(ClassicVendorGump)))
                            m.SendMessage("Only Mobile Reward Vendors can have classic menus.");
                        else
                        {
                            m_Vendor.Menu = menuType;
                            m.SendMessage("Display changed to " + menuType.Name);
                        }
                    }
                    catch { }

                    MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);

                    break;
                                      
                }
         }   
    }
    public void CreateGumps()
    {
        int yPos = 433, pageNum = 1;

        for (int i = 0; i < MenuUploader.Menus.Count; ++i )
        {

            AddLabel(50, yPos, 100, MenuUploader.Menus[i].Name);
            AddButton(12, yPos, 4005, 4006, (i + 7), GumpButtonType.Reply, pageNum);
            

            yPos += 26;

            //add new page every four entries
            if ((i + 1) % 4 == 0)
            {
                AddButton(144, 542, 9702, 9703, -1, GumpButtonType.Page, (pageNum + 1));

                AddPage(++pageNum);

                AddButton(10, 542, 9706, 9707, -1, GumpButtonType.Page, (pageNum - 1));

                //reset to top of page
                yPos = 433;
            }
        } 
    }
}
public static class MenuUploader 
{
    private static List<Type> m_Menus = new List<Type>(); 
    
    public static List<Type> Menus { get { return m_Menus; } }

    public static void RegisterMenu<G>(G menu) where G : Gump, IRewardVendorGump
    {
        m_Menus.Add(menu.GetType());
    }
    
    public static void Display(IRewardVendorGump menu, Mobile m, IRewardVendor vendor)
    {
        m.CloseGump(typeof(IRewardVendorGump));

        //create 'canvas'
        menu.CreateBackground();

        //create Reward displays
        foreach (Reward r in vendor.Rewards)
        {
            //refresh restock  
            if (r.Try_Restock() == 0 && !(menu is ManageItemsGump))
                continue;
            
            menu.AddEntry(r);
        }

        //send finished product
        menu.Send(m);
    }
    public static void Display(Type menu, Mobile m, IRewardVendor vendor, bool playerView)  //Note: Playerview is only relevant for Staff
    {
        try
        {
            if (m.AccessLevel > AccessLevel.GameMaster) 
            {
                if (playerView)
                    Display(new ManageItemsGump(vendor, m), m, vendor);
                else //control panel
                {
                    m.CloseGump(typeof(WorldVendorsGump));
                    m.CloseGump(typeof(ControlPanelGump));

                    m.SendGump(new WorldVendorsGump(vendor)); 
                    m.SendGump(new ControlPanelGump(m, vendor));
                }
            }
            else //player
            {
                Display((IRewardVendorGump)Activator.CreateInstance(menu, new object[] { vendor, m }), m, vendor); //create fresh instance
            }
        }
        catch
        {
            if ( m.AccessLevel > AccessLevel.GameMaster )
                m.SendMessage("The current display is invalid, try setting gump back to default, JewlRewardGump.");
            else
                m.SendMessage("The current display is invalid, please notify the staff.");
        }
    }
}
public class ManageItemsGump : JewlRewardGump
{
    private int m_ButtonNum;

    public ManageItemsGump(IRewardVendor vendor, Mobile m) : base(vendor, m)
    {
        m_ButtonNum = 0;
    }
    public override void AddEntryControl(Reward r)
    {
        ImageTileButtonInfo b = new ItemTileButtonInfo(r.RewardInfo);

        //begin time entries
        if (r.Restock != null)
        {
            if (r.Restock.RestockRate.TotalMinutes == 0)
                AddLabel(324, (PosY + 22), 5, "Limited");
            else
                AddLabel(324, (PosY + 22), 5, ((int)r.Restock.RestockRate.Hours).ToString() + " hours " + ((int)r.Restock.RestockRate.Minutes).ToString() + " min");

            if (r.Restock.Maximum > 0)
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString() + " / " + r.Restock.Maximum.ToString() + ", Purchased: " + r.BuyCount.ToString());
            else
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString() + ", Purchased: " + r.BuyCount.ToString());
        }
        else
        {
            AddLabel(324, (PosY + 68), 4, "Purchased: " + r.BuyCount.ToString());
        }
        //end 

        //create entry
        AddLabel(227, PosY, 2123, r.Title);
        AddLabel(324, (PosY + 45), 2115, "Cost: " + r.Cost);
        //odd numbers
        AddImageTiledButton(227, (PosY + 26), 2328, 2329, ++m_ButtonNum, GumpButtonType.Reply, PageNum, b.ItemID, b.Hue, 15, 10, r.Display.Header);
        AddImageTiled(215, (PosY + 95), 359, 2, 96);
        //odd numbers (same as above)
        AddButton(470, (PosY + 45), 4011, 4012, m_ButtonNum, GumpButtonType.Reply, PageNum);
        AddLabel(508, (PosY + 47), 1882, @"Options");
        //even numbers
        AddButton(470, (PosY + 19), 4020, 4021, ++m_ButtonNum, GumpButtonType.Reply, PageNum);
        AddLabel(509, (PosY + 21), 1882, @"Delete");
        PosY += 102;

        //add new page every four entries
        if (EntryNum % 4 == 0)
        {
            AddButton(546, 562, 9903, 9904, -1, GumpButtonType.Page, PageNum + 1);

            AddPage(++PageNum);

            AddButton(221, 563, 9909, 9910, -1, GumpButtonType.Page, PageNum - 1);

            //reset to top of page
            PosY = 130;
        }

        EntryNum++;
    }
    public static void DeleteReward_Callback(Mobile from, bool okay, object state)
    {
        if (from.AccessLevel < AccessLevel.GameMaster)
            return;

        if (okay)
        {
            //indexes -> (Vendor(0), Reward(1))
            Storage store = (Storage)state;

            IRewardVendor vendor = (IRewardVendor)store[0];
            Reward Reward = (Reward)store[1];

            try { vendor.RemoveReward(Reward); }
            catch { from.SendMessage("An error ocurred in the removal of this item."); }
            
            MenuUploader.Display(vendor.Menu, from, vendor, true);
        }
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
        {
            MenuUploader.Display(Vendor.Menu, m, Vendor, false);
            return;
        }
            
        if (info.ButtonID % 2 == 0) //even
        {
                try
                {
                    Reward r = Vendor.Rewards[(info.ButtonID / 2) - 1];

                    //params -> (vendor, Reward)
                    Storage store = new Storage(Vendor, r);

                    m.SendGump(new WarningGump(1060635, 30720, "Warning: Are you sure you want to remove " + r.Title, 0xFFC000, 420, 400, new WarningGumpCallback(DeleteReward_Callback), store));

                }
                catch { m.SendMessage("This item could not be found."); }
            
        }
        else //assert - odd
        {
            try
            {
                MenuUploader.Display(Vendor.Menu, m, Vendor, true);
                m.SendGump(new ViewItemGump(m, Vendor, Vendor.Rewards[((info.ButtonID + 1) / 2) - 1], true));
            }
            catch { m.SendMessage("Vendor could not be found"); }
        }
        
    }
    
}
public class XMLIntPropertyGump : Gump
{
    private Type m_XML_Type;
    private object m_Target;

    private IRewardVendor m_Vendor;
    private List<PropertyInfo> m_Props;

    private int m_PageNum;
    private  int m_PosY;
    private int m_EntryNum;

    public XMLIntPropertyGump(Type xmlType, object target, IRewardVendor vendor, List<PropertyInfo> props)
        : base(0, 0)
    {
        m_XML_Type = xmlType;
        m_Target = target;
        m_Vendor = vendor;
        m_Props = props;

        m_PageNum = 1;
        m_PosY = 134;
        m_EntryNum = 1;
      
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        AddImageTiled(284, 90, 168, 384, 2702);
        AddLabel(315, 99, 49, xmlType.Name);
        AddImageTiled(292, 123, 151, 3, 9151);

        AddPage(1);

        FillEntries();
    }
    public void FillEntries()
    {
        foreach (PropertyInfo pi in m_Props)
        {
            AddButton(295, m_PosY, 5601, 5605, m_EntryNum, GumpButtonType.Reply, 0);
            AddLabel(319, m_PosY, 43, pi.Name);

            m_PosY += 26;

            if (m_EntryNum % 10 == 0)
            {
                AddButton(423, 444, 9903, 9904, -1, GumpButtonType.Page, m_PageNum + 1);

                AddPage(++m_PageNum);

                AddButton(292, 444, 9909, 9910, -1, GumpButtonType.Page, m_PageNum - 1);

                //reset to top of page
                m_PosY = 134;
            }
            m_EntryNum++;
        }

       
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
            return;

        m_Vendor.Payment = new Currency(m_Target, m_XML_Type, m_Props[info.ButtonID - 1]);
        m.SendMessage("{0}'s payment method set to {1}.{2}", m_Vendor.GetName(), m_XML_Type.Name, m_Props[info.ButtonID-1].Name);
    }

}
public class JewlRewardGump : Gump, IRewardVendorGump
{
    private int m_PageNum;
    private int m_EntryNum;
    private int m_PosY;
    private IRewardVendor m_Vendor;
    private Mobile m_Mobile;
    private int m_CurrencyAmnt;
   
    public static void Initialize()
    {
        MenuUploader.RegisterMenu(new JewlRewardGump());
    }

    public JewlRewardGump()
        : base(0, 0)
    {
        m_PageNum = 1;
        m_EntryNum = 1;
        m_PosY = 130;
        m_Vendor = null;
        m_Mobile = null;
        m_CurrencyAmnt = 0;
    }
    public JewlRewardGump(IRewardVendor vendor, Mobile m) : this()
    {
        m_Vendor = vendor;
        m_Mobile = m;
        m_CurrencyAmnt = vendor.Payment.Value(m);
    }

    //Properties
    public int PageNum { get { return m_PageNum; } set { m_PageNum = value; } }
    public int EntryNum { get { return m_EntryNum; } set { m_EntryNum = value; } }
    public int PosY { get { return m_PosY; } set { m_PosY = value; } }
    public IRewardVendor Vendor { get { return m_Vendor; } set { m_Vendor = value; } }
    public Mobile Mobile { get { return m_Mobile; } set { m_Mobile = value; } }
    public int CurrencyAmnt { get { return m_CurrencyAmnt; } set { m_CurrencyAmnt = value; } }

    //Interface Explicit Implementation 
    void IRewardVendorGump.Send(Mobile m) { SendControl(m); }
    void IRewardVendorGump.CreateBackground() { CreateBackgroundControl(); } 
    void IRewardVendorGump.AddEntry(Reward r) { AddEntryControl(r); }

    public virtual void SendControl(Mobile m)
    {
        m.SendGump(this);
    }
    public virtual void CreateBackgroundControl()
    {
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        AddImageTiled(179, 34, 430, 556, 2702);
        AddImageTiled(222, 109, 387, 9, 10101);
        AddImage(162, 89, 10420);
        AddImageTiled(176, 33, 3, 556, 10004);
        AddImageTiled(129, 89, 82, 414, 10440);
        AddImageTiled(176, 589, 436, 3, 10001);
        AddImageTiled(176, 31, 435, 3, 10001);
        AddImageTiled(609, 33, 3, 556, 10004);
        AddLabel(348, 52, 2124, m_Vendor.GetName());
        AddImage(210, 52, 9818);
        AddImage(534, 52, 9818);
        AddLabel(404, 119, 2125, @"You have:");
        AddItem(348, 126, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);
        AddLabel(404, 137, 2125, (m_CurrencyAmnt.ToString() + " " + m_Vendor.Payment.PayName) );
        

        AddPage(1);
    }
      
    public virtual void AddEntryControl(Reward r)
    {
        ImageTileButtonInfo b = new ItemTileButtonInfo(r.RewardInfo);

        //create entry

        //begin time entries
        if (r.Restock != null)
        {
            if (r.Restock.RestockRate.TotalMinutes == 0)
                AddLabel(324, (PosY + 22), 5, "Limited");

            if (r.Restock.Maximum > 0)
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString());
            else
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString());
        }
        //end 

        AddLabel(227, m_PosY, 2123, r.Title);
        AddLabel(324, (m_PosY + 45), 2115, "Cost: " + r.Cost);
        AddImageTiledButton(227, (m_PosY + 26), 2328, 2329, (m_EntryNum), GumpButtonType.Reply, m_PageNum, b.ItemID, b.Hue, 15, 10, b.LocalizedTooltip);
        AddImageTiled(215, (m_PosY + 95), 359, 2, 96);
        AddButton(470, (PosY + 45), 4011, 4012, (m_EntryNum), GumpButtonType.Reply, m_PageNum);
        AddLabel(508, (PosY + 47), 745, @"View Item");
        m_PosY += 102;
        
        //add new page every four entries
        if (m_EntryNum % 4 == 0)
        {
            AddButton(546, 562, 9903, 9904, -1, GumpButtonType.Page, m_PageNum + 1);

            AddPage(++m_PageNum);

            AddButton(221, 563, 9909, 9910, -1, GumpButtonType.Page, m_PageNum - 1);

            //reset to top of page
            m_PosY = 130;
        }

        m_EntryNum++;
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
            return;

        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, true);

        try
        {
            m.SendGump(new ViewItemGump(m, m_Vendor, m_Vendor.Rewards[info.ButtonID - 1], true));
        }
        catch { m.SendMessage("Vendor could not be found"); }
    }
}

public class DisplayBox : LargeCrate, IEnumerable
{
    private Dictionary<Reward, MetalBox> m_Boxes;

    public override bool IsPublicContainer { get { return true; } }

    public MetalBox this[Reward r]
    {
        get
        {
            MetalBox box = null; //not found

            m_Boxes.TryGetValue(r, out box);

            return box;
        }
    }

    [Constructable]
    public DisplayBox()
        : base()
    {
        this.Name = "Display Box [DO NOT REMOVE]";
        this.LiftOverride = true;
        m_Boxes = new Dictionary<Reward, MetalBox>();
    }
    public DisplayBox(RewardCollection rc)
        : this()
    {
        CreateEntries(rc);
    }
    public bool Contains(Reward r)
    {
        return m_Boxes.ContainsKey(r);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return m_Boxes.GetEnumerator();
    }
    public override bool CheckLift(Mobile from, Item item, ref LRReason reject)
    {
        reject = 0;
        return false;
    }
    public void DisplayTo(Mobile m, Reward r)
    {
        string invalid = "This item can no longer be displayed.";
        bool staff = m.AccessLevel >= AccessLevel.GameMaster;

        try
        {
            Container[] containers = new Container[] { (Container)this.Parent, this }; //cast exception if parent isn't container

            foreach (Container c in containers)
            {
                if (m.NetState != null && m.NetState.IsPost6017)
                    m.Send(new ContainerContent6017(m, c));
                else
                    m.Send(new ContainerContent(m, c));
            }

            m_Boxes[r].DisplayTo(m); //throws null ref if not found

            m.SendMessage("A container has been opened for you to view the item.");
        }
        catch (NullReferenceException)
        {
            if (staff)
                m.SendMessage("Display error - please insure Reward is still on this vendor.");
            else
                m.SendMessage(invalid);
        }
        catch (InvalidCastException)
        {
            if (staff)
                m.SendMessage("Display error - the current vendor does not have a DisplayBox in backpack.");
            else
                m.SendMessage(invalid);
        }
        catch (Exception)
        {
            if (staff)
                m.SendMessage("Unknown error occured with display.");
            else
                m.SendMessage(invalid);
        }
            
    }
    //Warning: must catch exception in methods
    public void CreateEntries(RewardCollection rc)
    {
        foreach (Reward r in rc)
        {
            this.AddDisplay(r, r.RewardInfo);
        }
    }
    public void AddDisplay(Reward key, Item i)
    {
        if (m_Boxes.ContainsKey(key))
            throw new Exception("Key already in use.");

        MetalBox container = new MetalBox();
        
        container.DropItem(i);

        this.DropItem(container);

        m_Boxes.Add(key, container);    
    }
    public void AddDisplay(Reward r)
    {
        AddDisplay(r, r.RewardInfo);
    }
    public void RemoveDisplay(Reward r)
    {
        ((Item)m_Boxes[r]).Delete(); //remove from displaybox
        m_Boxes.Remove(r);   //remove from hashtable      
    }
    //End Warning

    public override bool OnDragDrop( Mobile from, Item dropped )
    {
        return false;//do nothing
    }

    public DisplayBox( Serial serial ) : base( serial )
	{
	}
    
	public override void Serialize( GenericWriter writer )
    {
		base.Serialize( writer );

		writer.Write( (int) 0 ); // version
        
        int count = 0;
        try
        {
            count = m_Boxes.Count;
        }
        catch
        {
            m_Boxes = new Dictionary<Reward, MetalBox>();
            m_Boxes.Add(new Reward(), new MetalBox());
            count = m_Boxes.Count;
        }
        writer.Write((int)count);

        foreach (KeyValuePair<Reward, MetalBox> kvp in m_Boxes)
        {
            writer.Write((Reward)kvp.Key);
            writer.WriteItem((MetalBox)kvp.Value);
        }
        
    }

	public override void Deserialize( GenericReader reader )
    {
		base.Deserialize( reader );
                
		int version = reader.ReadInt();

        
        int count = reader.ReadInt();
        
        m_Boxes = new Dictionary<Reward, MetalBox>();     
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                Reward r = (Reward)reader.ReadItem();
                MetalBox box = (MetalBox)reader.ReadItem();

                m_Boxes.Add(r, box);
            }
        }      
    }
}

public class LoadGumpEntry : ContextMenuEntry
{
    private IRewardVendor m_Vendor;
    private Mobile m_Mobile;

    public LoadGumpEntry(Mobile from, IRewardVendor vendor)
        : base(6103, 8)
    {
        m_Vendor = vendor;
        m_Mobile = from;
        Enabled = true;
    }

    public override void OnClick()
    {
        try
        {
            MenuUploader.Display((IRewardVendorGump)Activator.CreateInstance(m_Vendor.Menu, new object[] { m_Vendor, m_Mobile }), m_Mobile, m_Vendor); //create fresh instance
        }
        catch { m_Mobile.SendMessage("The current display is invalid.");  }
    }
}
public class ClassicVendorGump : Gump, IRewardVendorGump
{
    private IRewardVendor m_Vendor;
    private BaseVendor m_BVendor;

    private Mobile m_Mobile;   

    private List<ObjectPropertyList> m_Opls;
    private ArrayList m_List;

    public List<ObjectPropertyList> ObjPropLists { get { return m_Opls; } }
    public ArrayList RewardList { get { return m_List; } }

    public static void Initialize()
    {
        MenuUploader.RegisterMenu(new ClassicVendorGump());
    }

    public ClassicVendorGump()
        : base(0, 0)
    {
        m_Vendor = null;
        m_Mobile = null;
        m_BVendor = null;
        m_Opls = null;
        m_List = null;
    }
    public ClassicVendorGump(IRewardVendor vendor, Mobile m) : this()
    {
        m_Vendor = vendor;
        m_Mobile = m;
        m_BVendor = Parent(vendor);
        m_Opls = new List<ObjectPropertyList>();
        m_List = new ArrayList();
    }
    private BaseVendor Parent(IRewardVendor vendor)
    {
        BaseVendor validVendor = null;

        if (vendor != null) //only available on mobiles inherited from BaseVendor
            validVendor = vendor as BaseVendor;

        return validVendor;
    }
    void IRewardVendorGump.Send(Mobile m)
    {
        if ( !m_Vendor.Payment.PaymentType.Equals(typeof(Gold)) ) //need custom payment display
            m.SendGump(this);    

        if (m_BVendor != null)
        {

            if (m_List.Count > 0)
            {
                m_List.Sort(new BuyItemStateComparer());

                m_BVendor.SendPacksTo(m);

                if (m.NetState == null)
                    return;

                if (m.NetState.IsPost6017)
                    m.Send(new VendorBuyContent6017(m_List));
                else
                    m.Send(new VendorBuyContent(m_List));
                m.Send(new VendorBuyList(m_BVendor, m_List));
                m.Send(new DisplayBuyList(m_BVendor));

                m.Send(new MobileStatusExtended(m));//make sure their gold amount is sent

                if (m_Opls != null)
                {
                    for (int i = 0; i < m_Opls.Count; ++i)
                    {
                        m.Send(m_Opls[i]);
                    }
                }

                m_BVendor.SayTo(m, 500186); // Greetings.  Have a look around.
            }
        }               
    }   
    void IRewardVendorGump.AddEntry(Reward r)
    {
        m_List.Add(new BuyItemState(r.Title, m_BVendor.BuyPack.Serial, r.Serial, r.Cost, (r.Restock == null ? 20 : r.Restock.Count), r.RewardInfo.ItemID, r.RewardInfo.Hue));

        m_Opls.Add(r.Display);      
    }
    void IRewardVendorGump.CreateBackground()
    {
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);
        AddImage(36, 105, 2162);
        AddItem(111, 217, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);
        AddLabel(110, 172, 2122, @"Pay By:  " + m_Vendor.Payment.PayName);
        AddLabel(110, 299, 2120, @"You have: " + m_Vendor.Payment.Value(m_Mobile));
        AddImage(71, 302, 57);
        AddImage(71, 174, 57);
    }
}
public class MobileRewardVendor : Banker, IRewardVendor 
{
    private Currency m_Currency;
    private RewardCollection m_Rewards;
    private Type m_Menu;
    private DisplayBox m_Box;

    private bool m_IsBanker;

    [CommandProperty(AccessLevel.GameMaster)]
    public bool IsBanker
    {
        get { return m_IsBanker; }
        set { m_IsBanker = value; }     
    }
    Currency IRewardVendor.Payment
    {
        get { return m_Currency; }
        set { m_Currency = value; }
    }
    RewardCollection IRewardVendor.Rewards
    {
        get { return m_Rewards; }
        set { m_Rewards = value; }
    }
    Type IRewardVendor.Menu
    {
        get { return m_Menu; }
        set { m_Menu = value;  }
    }
    DisplayBox IRewardVendor.Display
    {
        get { return m_Box; }
    }
    [Constructable]
    public MobileRewardVendor() : base()
    {
        m_IsBanker = true;

        //default is Gold
        m_Currency = new Currency();
        m_Rewards = new RewardCollection();
        m_Menu = typeof(ClassicVendorGump);
        m_Box = new DisplayBox();

        //add to world collection
        WorldRewardVendors.RegisterVendor(this);
        //must be brought to world for client to view
        this.AddToBackpack(m_Box);

        this.Title = "";
    }
    public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
    {
        if (from.Alive)
        {
            list.Add(new LoadGumpEntry(from, this));

            if ( m_IsBanker)
                list.Add(new OpenBankEntry(from, this));
        }
    }
    Mobile IRewardVendor.GetMobile()
    {
        return this;
    }
    Item IRewardVendor.GetItem()
    {
        return null;
    }
   
    bool IRewardVendor.IsRemoved()
    {
        return this.Deleted;
    }
    Container IRewardVendor.GetContainer()
    {
        return this.Backpack;
    }
    string IRewardVendor.GetName()
    {
        return this.Name;
    }
    Map IRewardVendor.GetMap()
    {
        return this.Map;
    }
    Point3D IRewardVendor.GetLocation()
    {
        return this.Location;
    }
    //begin bank override
    public override bool HandlesOnSpeech(Mobile from)
    {
        if (!m_IsBanker)
            return false;

        base.HandlesOnSpeech(from);

        return true;
    }
    public override void OnSpeech(SpeechEventArgs e)
    {
        if (m_IsBanker)
            base.OnSpeech(e);
    }    
    //end

    //Warning: Following methods will throw Exceptions
    void IRewardVendor.AddReward(Reward r)
    {
        m_Box.AddDisplay(r);
        m_Rewards.Add(r);
    }
    void IRewardVendor.RemoveReward(Reward r)
    {
        m_Rewards.Remove(r);
        m_Box.RemoveDisplay(r);
    }
    
    void IRewardVendor.CopyVendor(IRewardVendor vendor)
    {
        Item currBox = this.Backpack.FindItemByType(typeof(DisplayBox));
        currBox.Delete();

        m_Currency = vendor.Payment;
        m_Menu = vendor.Menu;

        m_Rewards = (RewardCollection)((vendor.Rewards as ICloneable).Clone());
        m_Box = new DisplayBox(m_Rewards);

        this.AddToBackpack(m_Box);
    }
    //End Warning
    public override void OnDelete()
    {
        WorldRewardVendors.RemoveVendor(this);
        base.OnDelete();
    }
    //response to ClassicVendorGump - (must be inside BaseVendor)
    public override bool OnBuyItems(Mobile buyer, ArrayList list)
    {
        int totalCost = 0;
      
        Dictionary<Reward, int> purchases = new Dictionary<Reward, int>();

        Container bank = buyer.BankBox;
        Container pack = buyer.Backpack;

        if (pack == null || bank == null)
            return false;

        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;

                Reward r = item as Reward;

                if (r == null || !r.InStock(amount))
                    continue;

                totalCost += (r.Cost * amount);

                purchases.Add(r, amount);
            }
        }

        if (purchases.Count == 0)
        {
            SayTo(buyer, 500190); // Thou hast bought nothing! 
            return false;
        }                    
            if (!m_Currency.Purchase(buyer, totalCost)) //cannot afford
            {
                SayTo(buyer, 500192);//Begging thy pardon, but thou casnt afford that.
                return false;
            }

            foreach (KeyValuePair<Reward, int> kvp in purchases)
            {
                kvp.Key.RegisterBuy(kvp.Value);

                for (int index = 0; index < kvp.Value; index++)
                {                    
                    Item i = kvp.Key.RewardCopy;

                    if (!buyer.PlaceInBackpack(i))
                    {
                        bank.DropItem(i);
                        buyer.SendMessage("You are overweight, the Reward was added to your bank");
                    }
                }

                buyer.SendMessage("You bought {0} {1}", kvp.Value, kvp.Key.Title);
            }

            buyer.PlaySound(0x32);

            return true;  
             
    }
    //respone to 'vendor buy'
    public override void VendorBuy(Mobile from)
    {       
        MenuUploader.Display((IRewardVendorGump)Activator.CreateInstance(m_Menu, new object[] { (IRewardVendor)this, from }), from, (IRewardVendor)this ); //create fresh instance
    }
    //end edit
    public override void OnDoubleClick(Mobile m)
    {
        if (InRange(m, 4) && InLOS(m))
            MenuUploader.Display(m_Menu, m, this, false);
    }
    public MobileRewardVendor( Serial serial ) : base( serial )
	{
	}
    
	public override void Serialize( GenericWriter writer )
    {
		base.Serialize( writer );   

		writer.Write( (int) 1 ); // version

        writer.Write((bool)m_IsBanker);

        int count = m_Rewards.Count;
        writer.Write((int)count);

        if ( count > 0 )
        {
            for (int i = 0; i < count; i++)
            {
                writer.WriteItem((Reward)m_Rewards[i]);
            }
        }
        
        writer.WriteItem((Currency)m_Currency);
        writer.Write((string)m_Menu.Name);
        writer.WriteItem((DisplayBox)m_Box);       
    }
    
	public override void Deserialize( GenericReader reader )
    {
		base.Deserialize( reader );

        WorldRewardVendors.RegisterVendor(this);

		int version = reader.ReadInt();
        
        m_Rewards = new RewardCollection();

        m_IsBanker = true; //for conversion
               
        switch (version)
        {
            case 1:
                {
                    m_IsBanker = reader.ReadBool();

                    goto case 0;
                }
            case 0:
               {                   
                    int count = reader.ReadInt();
                    if (count > 0)
                    {
                        for (int i = 0; i < count; i++)
                        {
                            Reward r = (Reward)reader.ReadItem();
                            m_Rewards.Add(r);
                        }
                    }

                    m_Currency = (Currency)reader.ReadItem();

                    try { string name = reader.ReadString(); m_Menu = ScriptCompiler.FindTypeByName(name); }
                    catch { m_Menu = typeof(JewlRewardGump); }

                    m_Box = (DisplayBox)reader.ReadItem();

                    break;
                }
        }
	}
}
public class StoneRewardHolder : MetalBox
{
    private StoneRewardVendor m_S_Vendor;

    public StoneRewardHolder(StoneRewardVendor sv)
        : base()
    {
        m_S_Vendor = sv;
        this.Movable = false;
        this.Name = sv.Name + "'s Display Container [DO NOT DELETE]";
    }
    public override void OnItemLifted(Mobile m, Item item)
    {
        m.SendMessage("This item should not be moved away from the vendor.");
    }

    public void UpdateName()
    {
        if (m_S_Vendor == null)
            return;

        this.Name = m_S_Vendor.Name + "'s Display Container [DO NOT DELETE]";
    }
    public StoneRewardHolder(Serial serial)
        : base(serial)
	{
	}

	public override void Serialize( GenericWriter writer )
	{
		base.Serialize( writer );

		writer.Write( (int) 0 ); // version
	}

	public override void Deserialize( GenericReader reader )
	{
		base.Deserialize( reader );

		int version = reader.ReadInt();
    }
}
public class StoneRewardVendor : Item, IRewardVendor
{
    private Currency m_Currency;
    private RewardCollection m_Rewards;
    private Type m_Menu;
    private StoneRewardHolder m_Box_Holder;
    private DisplayBox m_Box;

    Currency IRewardVendor.Payment
    {
        get { return m_Currency; }
        set { m_Currency = value; }
    }
    RewardCollection IRewardVendor.Rewards
    {
        get { return m_Rewards; }
        set { m_Rewards = value; }
    }
    Type IRewardVendor.Menu
    {
        get { return m_Menu; }
        set { m_Menu = value; }
    }
    DisplayBox IRewardVendor.Display
    {
        get { return m_Box; }
    }

    [Constructable]
    public StoneRewardVendor()
        : base()
    {
        m_Currency = new Currency();
        m_Rewards = new RewardCollection();
        m_Menu = typeof(JewlRewardGump);
        m_Box = new DisplayBox();

        ItemID = 0xEDC;
        Name = "Stone Vendor";

        WorldRewardVendors.RegisterVendor(this);

        m_Box_Holder = new StoneRewardHolder(this);
        m_Box_Holder.DropItem(m_Box);      

        this.Movable = false;
    }
    public override void OnLocationChange( Point3D oldLocation )
    {
        base.OnLocationChange(oldLocation);

        if (m_Box_Holder != null)
        {
            m_Box_Holder.Location = this.Location;
            m_Box_Holder.Z = this.Z - 10;
        }
    }
    public override void OnMapChange()
    {
        base.OnMapChange();

        if ( m_Box_Holder != null )
            m_Box_Holder.Map = this.Map;
    }
    Mobile IRewardVendor.GetMobile()
    {
        return null;
    }
    Item IRewardVendor.GetItem()
    {
        return this;
    }

    bool IRewardVendor.IsRemoved()
    {
        return this.Deleted;
    }
    Container IRewardVendor.GetContainer()
    {
        return m_Box_Holder;
    }
    string IRewardVendor.GetName()
    {
        return this.Name;
    }
    Map IRewardVendor.GetMap()
    {
        return this.Map;
    }
    Point3D IRewardVendor.GetLocation()
    {
        return this.Location;
    }
    void IRewardVendor.AddReward(Reward r)
    {
        m_Box.AddDisplay(r);
        m_Rewards.Add(r);
    }
    void IRewardVendor.RemoveReward(Reward r)
    {
        m_Rewards.Remove(r);
        m_Box.RemoveDisplay(r);
    }

    void IRewardVendor.CopyVendor(IRewardVendor vendor)
    {
        Item currBox = m_Box_Holder.FindItemByType(typeof(DisplayBox));
        currBox.Delete();

        m_Currency = vendor.Payment;
        m_Menu = vendor.Menu;

        m_Rewards = (RewardCollection)((vendor.Rewards as ICloneable).Clone());
        m_Box = new DisplayBox(m_Rewards);

        m_Box_Holder.DropItem(m_Box);
    }
    //End Warning
    public override void OnDelete()
    {
        if ( m_Box_Holder != null)
            m_Box_Holder.Delete();

        WorldRewardVendors.RemoveVendor(this);
        base.OnDelete();
    }
    
    public override void OnDoubleClick(Mobile m)
    {
        if (m_Box_Holder != null)
        {
            m_Box_Holder.MoveToWorld(this.Location, this.Map);
            m_Box_Holder.Z = this.Z - 10;
            m_Box_Holder.UpdateName();
        }
        MenuUploader.Display(m_Menu, m, this, false);
    }
     
    public StoneRewardVendor(Serial serial)
        : base(serial)
    {
    }

    public override void Serialize(GenericWriter writer)
    {
        base.Serialize(writer);

        writer.Write((int)0); //Version 0

        int count = m_Rewards.Count;
        writer.Write((int)count);

        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                writer.WriteItem((Reward)m_Rewards[i]);
            }
        }

        writer.WriteItem((Currency)m_Currency);
        writer.Write((string)m_Menu.Name);
        writer.WriteItem((DisplayBox)m_Box);
        writer.WriteItem((StoneRewardHolder)m_Box_Holder);
    }

    public override void Deserialize(GenericReader reader)
    {
        base.Deserialize(reader);

        WorldRewardVendors.RegisterVendor(this);

        int version = reader.ReadInt();

        m_Rewards = new RewardCollection();

        int count = reader.ReadInt();
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                Reward r = (Reward)reader.ReadItem();
                m_Rewards.Add(r);
            }
        }

        m_Currency = (Currency)reader.ReadItem();

        try { string name = reader.ReadString(); m_Menu = ScriptCompiler.FindTypeByName(name); }
        catch { m_Menu = typeof(JewlRewardGump); }

        m_Box = (DisplayBox)reader.ReadItem();
        m_Box_Holder = (StoneRewardHolder)reader.ReadItem();
    }
}
public interface IRewardVendor
{
    //used to determine how player pays
    Currency Payment { get; set; }
    //to keep added items
    RewardCollection Rewards { get; set; }
    //to change gump
    Type Menu { get; set; }
    //to show player items
    DisplayBox Display { get; }
    //to return what holds 'DisplayBox' object
    Container GetContainer();
    //to return removal status
    bool IsRemoved();
   
    //serial /deserial
    Mobile GetMobile();
    Item GetItem();

    //used for 'world collection'
    string GetName();
    Point3D GetLocation();
    Map GetMap();

    //to manage RewardCollection
    void AddReward(Reward r);
    void RemoveReward(Reward r);
    
    //to create vendor clones
    void CopyVendor(IRewardVendor vendor);
}
public interface IRewardVendorGump
{
    void Send(Mobile m);
    void AddEntry(Reward r);
    void CreateBackground();
    
    //add entry || background || 
}


public class PaymentTarget : Target
{
    private string m_Name;
    private IRewardVendor m_Vendor;
    private bool m_Is_XML;

    public PaymentTarget()
        : base(2, false, TargetFlags.None)
    {
    }
    //by item
    public PaymentTarget(IRewardVendor vendor) : this ()
	{
        m_Vendor = vendor;
        m_Name = null;
        m_Is_XML = false;
    }
    //by item property
    public PaymentTarget(IRewardVendor vendor, string name, bool isXML) : this()
    {
        m_Vendor = vendor;
        m_Name = name;
        m_Is_XML = isXML;
    }
    protected override void OnTarget(Mobile m, object targeted)
    {
        if (m_Is_XML && !String.IsNullOrEmpty(m_Name))
        {
            Type attachType = ScriptCompiler.FindTypeByName(m_Name);

            if (attachType != null && attachType.BaseType.Equals(typeof(XmlAttachment)))
            {
                List<PropertyInfo> integerProps = new List<PropertyInfo>();

                foreach (PropertyInfo pi in attachType.GetProperties())
                {
                    if ((pi.CanRead && pi.CanWrite) && pi.PropertyType.Equals(typeof(System.Int32)))
                        integerProps.Add(pi);
                }

                if (integerProps.Count == 0)
                    m.SendMessage("{0} does not contain any integer based properties.", attachType.Name);
                else
                    m.SendGump(new XMLIntPropertyGump(attachType, targeted, m_Vendor, integerProps));
            }
            else
                m.SendMessage("The XML Attachment, {0}, could not be found, the search IS case sensitive", m_Name);
        }
        else if ( targeted is Item )
        {           
            //consume by item
            if (m_Name == null)
            {
                m_Vendor.Payment = new Currency((Item)targeted);
                m.SendMessage("{0} will now use {1} for payment.", m_Vendor.GetName(), targeted.GetType().Name);
            }
            //consume by item property
            else
            {
                SetByProperty(m, targeted);
            }
        }
        else if (targeted is PlayerMobile)
        {
            if (m_Name == null)
            {
                m.SendMessage("You can only use Property option for player.");

            }
            else
            {
                SetByProperty(m, null);
            }
        }
        else
        {
            m.SendMessage("Invalid, target must be Item or Player.");
        }

        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);
    }
    private void SetByProperty(Mobile m, object o)
    {
        string msg = "Please make sure you entered the name correctly, "
                        + "it IS case sensitive.";
        try
        {
            if (o != null)//Item
            {
                PropertyInfo pi = o.GetType().GetProperty(m_Name);

                if (pi != null && pi.PropertyType.Equals(typeof(Int32)))
                {
                    m_Vendor.Payment = new Currency((Item)o, pi);
                    m.SendMessage(m_Vendor.GetName() + "will now use {1}.{2} for payment.", m_Vendor.GetName(), o.GetType().Name, pi.Name);
                }
                else
                    m.SendMessage(msg);
            }
            else//Mobile
            {
                PropertyInfo pi = m.GetType().GetProperty(m_Name);

                if (pi != null && pi.PropertyType.Equals(typeof(Int32)))
                {
                    m_Vendor.Payment = new Currency(m, pi);
                    m.SendMessage("{0} will now use {1}.{2} for payment.", m_Vendor.GetName(), m.GetType().Name, pi.Name);
                }
                else
                    m.SendMessage(msg);
            }
        }
        catch { m.SendMessage(msg); }
    }
}
public class AddItemTarget : Target
{
    IRewardVendor m_Vendor;

    public AddItemTarget() : base( 2, false, TargetFlags.None )
	{
	}
    public AddItemTarget(IRewardVendor vendor)
        : this()
    {
        m_Vendor = vendor;
    }
    protected override void OnTarget(Mobile from, object targeted)
    {
        Item i = targeted as Item;

        if (m_Vendor == null || i == null)
            return;

        Item clone = ItemClone.Clone(i);

        if (clone != null) //copy did not fail
            from.SendGump(new EditItemGump(m_Vendor, new Reward(clone), null, false, true));
        else
            from.SendMessage("This item cannot be copied.");

    }
}

public class ItemClone
{
    public static Item Clone(Item item) 
    {
        try
        {
            if ( item is Container )
                return CloneBag(((Container)item).FindItemsByType(typeof(Item), false), (Container)item, (Container)Activator.CreateInstance(item.GetType(), null));
            else
                return Clone(item.GetType(), item, (Item)Activator.CreateInstance(item.GetType(), null));
        }
        catch {}
       
        return null;
    }
    public static Container CloneBag(Item[] contents, Container old, Container copy)
    {        
        //emtpy new container
        foreach (Item i in copy.FindItemsByType(typeof(Item)))
        {
            i.Delete();
        }

        //'old' contents into 'new'
        foreach (Item i in contents)
        {
            copy.DropItem(Clone(i));           
        }

        copy.Name = old.Name; //requires manual set

        return copy;
    }
    public static Item Clone(Type type, Item old, Item copy)
    {
        foreach (PropertyInfo pi in type.GetProperties())
        {
            if (pi.CanRead && pi.CanWrite && ValidProperty(pi.Name)) 
            {
                try
                {
                    if (pi.PropertyType.IsClass)
                        CloneInnerClass(pi.PropertyType, pi.GetValue(old, null), pi.GetValue(copy, null)); //found object property
                    else
                        pi.SetValue(copy, pi.GetValue(old, null), null); //found value property
                }
                catch {}
            }
        }

        copy.Name = old.Name; //requires manual set

        return copy;
    }
    public static void CloneInnerClass(Type type, object old, object copy)
    {
        if (old == null) //not defined
            return;
        
        foreach ( PropertyInfo pi in type.GetProperties() )
        {
            if ( pi.CanRead && pi.CanWrite ) 
            {
                try
                {
                    pi.SetValue(copy, pi.GetValue(old, null), null);
                }
                catch {}
            }
        }
    }
    public static bool ValidProperty(string str) 
    {
        return !( str.Equals("Parent") || str.Equals("TotalWeight") || str.Equals("TotalItems") || str.Equals("TotalGold") );
    }
   
}

}
 

LordHogFred

Knight
Nockar;851080 said:
What reward vendor script are you talking about? Are you talking about this ?
[RC2] Rewards System - XML Attachments .cs

Code:
//Author: krazeykow
//Version: 1.0.1

using System;
using Server;
using Server.Items;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Server.Gumps;
using Server.Network;
using Server.Targeting;
using Server.Mobiles;
using Server.ContextMenus;
using Server.Engines.XmlSpawner2;

namespace System.CustomizableVendor
{

public class Currency : Item
{

    private Payment m_Payment;
    private PropertyInfo m_PropertyInfo;
    private Type m_Payment_Type;
    private Type m_XML_Type;
    private int m_ItemID;
    private string m_Name;
    private int m_Hue;

    public Type XMLType { get { return m_XML_Type; } }
    public Type PaymentType { get { return m_Payment_Type; } }
    public string PayName { get { return m_Name; } }
    public int PayID { get { return m_ItemID; } }
    public int CurrHue { get { return m_Hue; } } 

    public enum Payment
    {
        ByGold,
        ByItem,
        ByProperty,
        ByXMLAttachment
    }
    //default
    public Currency()
    {
        m_Payment = Payment.ByGold;
        m_Payment_Type = typeof(Gold);
        m_PropertyInfo = null;
        m_ItemID = 3823;
        m_Name = "Gold";
    }
    public Currency(object bindedTo, Type attachType, PropertyInfo attachProp)
    {
        m_XML_Type = attachType;
        m_Payment = Payment.ByXMLAttachment;
        m_Payment_Type = bindedTo.GetType();
        m_PropertyInfo = attachProp;

        if (bindedTo is Mobile) {
            m_ItemID = 8461;
            m_Name = "Player " + attachProp.Name;
        }
        else if (bindedTo is Item) {
            m_ItemID = ((Item)bindedTo).ItemID;
            m_Name = GetName((Item)bindedTo) + "'s " + attachProp.Name;
            m_Hue = ((Item)bindedTo).Hue;
        }

    }
    //consume by item
    public Currency(Item i)
    {
        if ( i.GetType().Equals(typeof(Gold)) )
            m_Payment = Payment.ByGold;
        else
            m_Payment = Payment.ByItem;

        m_Payment_Type = i.GetType();
        m_PropertyInfo = null;
        m_ItemID = CoinID(i.ItemID);
        m_Name = GetName(i);
        m_Hue = i.Hue;
    }
    //consume property on player
    public Currency(Mobile m, PropertyInfo pi)
    {
        m_Payment = Payment.ByProperty;
        m_Payment_Type = m.GetType();
        m_PropertyInfo = pi;
        m_ItemID = 8461;
        m_Name = "Player " + pi.Name;
    }
    //consume by item's number based property
    public Currency(Item i, PropertyInfo pi)
    {
        m_Payment = Payment.ByProperty;
        m_Payment_Type = i.GetType();
        m_PropertyInfo = pi;
        m_ItemID = CoinID(i.ItemID);
        m_Name = GetName(i) + "'s " + pi.Name;
        m_Hue = i.Hue;
    }
    public void Modify(Type t, string append)
    {
        if ( (t.Equals(typeof(PlayerMobile)) || append == null ))
            return;

        Item i;
        
        i = (Item)Activator.CreateInstance(t, null);
        m_Name = GetName(i) + append;
        m_Hue = i.Hue;
        m_ItemID = CoinID(m_ItemID);
        
    }
    public int CoinID(int itemID)
    {
        if (itemID == 3821)
            return 3823;
        else if (itemID == 3824)
            return 3826;
        else
            return itemID;
    }
    public void VOneUpdate()
    {
        switch (m_Payment)
        {
            case Payment.ByGold:
            case Payment.ByItem:
                {
                    Modify(m_Payment_Type, "");
                    break;
                }
            case Payment.ByProperty:
                {
                    if (!(m_Payment_Type.Equals(typeof(PlayerMobile))))
                        Modify(m_Payment_Type, "'s " + m_PropertyInfo.Name);
                    break;
                }
        }

     }

    public string GetName(Item i)
    {
        if (String.IsNullOrEmpty(i.Name))
            return i.GetType().Name;
        else
            return i.Name;
    }
    public bool Purchase(Mobile m, int cost)
    {
        int remain = Value(m) - cost;

        if (remain < 0 || m.Backpack == null)
            return false;
        
        Charge(m, cost, remain);

        return true;
    }
    public void Charge(Container pack, Container bank, Type t, int cost)
    {
        if ( pack == null || bank == null )
            return;

        cost = cost - pack.ConsumeUpTo(t, cost);

        if ( cost > 0 )
            bank.ConsumeUpTo(t, cost);
    }
   
    public void Charge(Mobile m, Type t, PropertyInfo pi, int cost, int remain)
    {
        try
        {
            if (t.BaseType.Equals(typeof(Mobile)) || t.Equals(typeof(PlayerMobile)))
            {
                SetPropertyValue(m, remain);
            }
            else
            {
                if (m.Backpack == null || m.FindBankNoCreate() == null)
                    return;

                Item[] packItems = m.Backpack.FindItemsByType(t);
                Item[] bankItems = m.FindBankNoCreate().FindItemsByType(t);

                Item[] items = new Item[packItems.Length + bankItems.Length];
                packItems.CopyTo(items, 0);
                bankItems.CopyTo(items, packItems.Length);

                //none found in backpack
                if (items == null)
                    return;

                int i = 0, value = 0, dif = 0;

                //account for multiple objects
                while (cost > 0 && i < items.Length)
                {
                    value = GetPropertyValue(items[i]);

                    dif = value - cost;

                    //one item has enough
                    if (dif >= 0)
                    {
                        SetPropertyValue(items[i], dif);
                    }
                    //take what amount item has (the amount has already been confirmed by Value(m))
                    else // assert (dif < 0)
                    {
                        cost -= GetPropertyValue(items[i]);
                        SetPropertyValue(items[i], 0);
                    }
                    i++;
                }
            }
        }
        catch { }
    }
    public void Charge(Mobile m, Container pack, Container bank, int cost)
    {
        if ( pack == null || bank == null )
            return;

        cost = cost - pack.ConsumeUpTo(typeof(Gold), cost);

        if (cost > 0)
            Banker.Withdraw(m, cost);
    }
    public void Charge(Mobile m, int cost, int remain)
    {
        switch (m_Payment)
        {
            case Payment.ByGold:
                Charge(m, m.Backpack, m.FindBankNoCreate(), cost);
                break;
            case Payment.ByItem:
                Charge(m.Backpack, m.FindBankNoCreate(), m_Payment_Type, cost);
                break;
            case Payment.ByXMLAttachment:
            case Payment.ByProperty:
                Charge(m, m_Payment_Type, m_PropertyInfo, cost, remain);
                break;
        }
    }
    public int Value(Mobile m)
    {
        switch (m_Payment)
        {
            case Payment.ByGold:
                return ProcessByGold(m);
            case Payment.ByItem:
                return ProcessByItem(m, m_Payment_Type);
            case Payment.ByXMLAttachment:
            case Payment.ByProperty:
                return ProcessByProperty(m, m_Payment_Type, m_PropertyInfo);                       
        }
        return 0;
    }

    public int ProcessByGold(Mobile m)
    {
        if (m.Backpack == null)
            return 0;

        int totalGold = 0;

        totalGold += m.Backpack.GetAmount( typeof( Gold ) );
        totalGold += Banker.GetBalance( m );

        return totalGold;
    }
    public int ProcessByItem(Mobile m, Type t)
    {
        Container pack = m.Backpack;
        Container bank = m.FindBankNoCreate();

        if (pack == null || bank == null)
            return 0;

        int amount = (pack.GetAmount(t) + bank.GetAmount(t));

        return amount;
    }
    public int ProcessByProperty(Container pack, Container bank, Type t, PropertyInfo pi)
    {
        if (pack == null || bank == null)
            return 0;


        Item[] packItems = pack.FindItemsByType(t);
        Item[] bankItems = bank.FindItemsByType(t);

        Item[] items = new Item[packItems.Length + bankItems.Length];
        packItems.CopyTo(items, 0);
        bankItems.CopyTo(items, packItems.Length);
        
        int sum = 0;

        foreach (object o in items)
        {
            sum += GetPropertyValue(o);
        }

        return sum;
    }
    public int GetPropertyValue(object o)
    {
        int val = 0;

        if (m_Payment == Payment.ByXMLAttachment)
        {
            val = GetXMLValue(o);
        }
        else
        {
            val = (int)m_PropertyInfo.GetValue(o, null);
        }

        return val;
    }
    public void SetPropertyValue(object o, int val)
    {
        if (m_Payment == Payment.ByXMLAttachment)
        {
            SetXMLValue(o, val);
        }
        else
        {
            m_PropertyInfo.SetValue(o, val, null);
        }       
    }
    public int GetXMLValue(object o)
    {      
        int val = 0;

        if (m_XML_Type == null)
            return val;

        XmlAttachment attach = XmlAttach.FindAttachment(o, m_XML_Type);

        if (attach != null) {           
            val = (int)m_PropertyInfo.GetValue(attach, null);           
        }
        return val;
    }
    public void SetXMLValue(object o, int val)
    {
        if (m_XML_Type == null)
            return;

        XmlAttachment attach = XmlAttach.FindAttachment(o, m_XML_Type);

        if (attach != null) { 
            m_PropertyInfo.SetValue(attach, val, null);           
        }
    }
    //Master
    public int ProcessByProperty(Mobile m, Type t, PropertyInfo pi)
    {
        try
        { 

            if (t.BaseType.Equals(typeof(Mobile)) || t.Equals(typeof(Mobile)) )
            {
                return GetPropertyValue(m);
            }
            else
            {
                return ProcessByProperty(m.Backpack, m.FindBankNoCreate(), t, pi);
            }
        }
        catch {}
        
        return 0;
        
    }
   
    public Currency( Serial serial ) : base( serial )
	{
	}
	public override void Serialize( GenericWriter writer )
	{
		base.Serialize( writer );
		writer.Write( (int) 2 );

        //version 2
        writer.Write((string)(m_XML_Type == null ? "" : m_XML_Type.Name));

        //version 1
        writer.Write((int)m_Hue);
        
        //explicit casts are given for clarification        
        writer.Write((int)m_Payment);
        writer.Write((string)m_Payment_Type.Name);
        writer.Write((string)(m_PropertyInfo == null ? "" : m_PropertyInfo.Name));
        writer.Write((int)m_ItemID);
        writer.Write((string)m_Name);
        
	}
	
	public override void Deserialize(GenericReader reader)
	{
		base.Deserialize( reader );
		int version = reader.ReadInt();


        switch (version)
        {
            case 2:
                {
                    try
                    {
                        string name = reader.ReadString();
                        if (name.Equals(""))
                        {
                            m_XML_Type = null;
                        }
                        else
                        {
                            m_XML_Type = ScriptCompiler.FindTypeByName(name);
                        }
                    }
                    catch { }

                    goto case 1;
                }
            case 1:
                {
                    m_Hue = reader.ReadInt();
                    goto case 0;
                }
            case 0:
                {
                    m_Payment = (Payment)reader.ReadInt();

                    try { string name = reader.ReadString(); m_Payment_Type = ScriptCompiler.FindTypeByName(name); }
                    catch { }

                    try
                    {
                        string propName = reader.ReadString();
                        if (propName.Equals("")) //never set
                        {
                            m_PropertyInfo = null;
                        }
                        else if (m_Payment == Payment.ByXMLAttachment && m_XML_Type != null) //XML requires find property by the XML Class type (m_XML_Type)
                        {
                            m_PropertyInfo = m_XML_Type.GetProperty(propName);
                        }
                        else 
                        { 
                            m_PropertyInfo = m_Payment_Type.GetProperty(propName); 
                        }
                    }
                    catch { }

                    m_ItemID = reader.ReadInt();
                    m_Name = reader.ReadString();

                    break;
                }
        }
        if (version == 0)
        {
            try { VOneUpdate(); }
            catch {  }
        }
     }
}

public class Reward : Item, ICloneable
{      
    private Item m_Reward;
    private int m_Cost;
    private string m_Title;
    private string m_Description;

    private ObjectPropertyList m_Display;

    private RestockInfo m_RestockInfo;
    private int m_BuyCount;

    public int BuyCount { get { return m_BuyCount; } set { m_BuyCount = value; } }
    public RestockInfo Restock { get { return m_RestockInfo; } set { m_RestockInfo = value; } }

    public ObjectPropertyList Display
    {
        get
        {
            if (m_Display == null)
            {
                m_Display = new ObjectPropertyList(this);

                m_Reward.GetProperties(m_Display);
                m_Reward.AppendChildProperties(m_Display);

                m_Display.Terminate();
                m_Display.SetStatic();
            }

            return m_Display;
        }
    }

    public void Void_RestockInfo()
    {
        m_RestockInfo = null;
    }
    //returns ((-1) -> no restockInfo) or current count
    public int Try_Restock()
    {
        if (m_RestockInfo == null)
            return -1;        

        TimeSpan dif = DateTime.Now - m_RestockInfo.LastRestock;
        int cycles = 0;

        if (dif > (m_RestockInfo.RestockRate) && m_RestockInfo.RestockRate.TotalMinutes > 0)
        {
            cycles = (int)(dif.TotalMinutes / m_RestockInfo.RestockRate.TotalMinutes);

            for (int i = 0; i < cycles; ++i)
            {
                if (m_RestockInfo.Restock())
                    continue;
            }
        }

        return m_RestockInfo.Count;
    }
    public bool InStock(int amount)
    {
        return (m_RestockInfo == null ? true : (m_RestockInfo.Count - amount >= 0));       
    }
    public void RegisterBuy(int amount)
    {      
        if (m_RestockInfo != null && InStock(amount))
            m_RestockInfo.Count -= amount;

        this.m_BuyCount += amount;
    }

    //for retrieving information only
    public Item RewardInfo
    {
        get { return m_Reward; }
    }
    //use only when creating Reward for player
    public Item RewardCopy
    {
        get { return GetReward(); }
    }
    public int Cost
    {
        get { return m_Cost; }
        set { m_Cost = value; }
    }
    public string Title
    {
        get { return m_Title; }
        set { m_Title = value; }
    }
    public string Description
    {
        get { return m_Description; }
        set { m_Description = value; }
    }
    object ICloneable.Clone()
    {
        return new Reward(this);
    }
    public Reward()
    {
        m_Reward = new Item();
        m_Cost = 0;
        m_Title = "";
        m_Description = "";
        m_RestockInfo = null;
    }
    public Reward(Reward r)
    {
        m_Reward = r.RewardCopy;
        m_Cost = r.Cost;
        m_Title = r.Title;
        m_Description = r.Description;
        m_RestockInfo = null;
    }
    public Reward(Item i)
    {
        m_Reward = i;
        m_Cost = 0;
        m_Title = (i.Name == null ? i.GetType().Name : i.Name);
        m_Description = "None.";
        m_RestockInfo = null;

    }
    public Reward(Item i, int cost)
    {
        m_Reward = i;
        m_Cost = cost;
        m_Title = (i.Name == null ? i.GetType().Name : i.Name);
        m_Description = "None.";
        m_RestockInfo = null;
    }
    public Reward(Item i, int cost, string title)
    {
        m_Reward = i;
        m_Cost = cost;
        m_Title = title;
        m_Description = "None.";
        m_RestockInfo = null;
    }
    public Reward(Item i, int cost, string title, string desc)
    {
        m_Reward = i;
        m_Cost = cost;
        m_Title = title;
        m_Description = desc;
        m_RestockInfo = null;
    }

    public class RestockInfo 
    {
        private TimeSpan m_RestockRate;
        private DateTime m_LastRestock;

        private int m_RestockAmnt;
        private int m_Count;
        private int? m_Maximum;
        
        public TimeSpan RestockRate { get { return m_RestockRate; } }
        public DateTime LastRestock { get { return m_LastRestock; } }

        public int RestockAmnt { get { return m_RestockAmnt; } }
        public int Count { get { return m_Count; } set { m_Count = value; } }
        public int Maximum { get { return m_Maximum.GetValueOrDefault(-1); } }

        public int Hours { get { return (int)m_RestockRate.Hours; } }
        public int Minutes { get { return (int)m_RestockRate.Minutes; } }

        public RestockInfo()
        {
            m_RestockRate = new TimeSpan();
            m_RestockAmnt = 0;
            m_Count = 0;
            m_Maximum = null;
            m_LastRestock = DateTime.Now;

        }
        public RestockInfo(int count) : this()
        {
            m_Count = count;
        }
        public RestockInfo(int hour, int minute, int count, int RestockNum)
        {
            m_RestockRate = new TimeSpan(hour, minute, 0);
            m_Count = count;
            m_RestockAmnt = RestockNum;
            m_Maximum = null;
            m_LastRestock = DateTime.Now;

        }
        public RestockInfo(int hour, int minute, int count, int RestockNum, int maxNum) : this (hour, minute, count, RestockNum)
        {
            m_Maximum = maxNum;
        }
        public bool Equals(RestockInfo info)
        {
            return (this.m_RestockRate.Equals(info.RestockRate) && (this.m_RestockAmnt == info.RestockAmnt) && (this.m_Count == info.Count)
                && (this.m_Maximum == info.Maximum));
        }
        public bool Restock()
        {
            m_LastRestock = DateTime.Now;

            if (m_Maximum != null) //Restock to a limit
            {
                if ((m_Count + m_RestockAmnt) > m_Maximum)
                {
                    m_Count = m_Maximum.Value;
                    return false;
                }

                m_Count += m_RestockAmnt;
                return true;
            }
            
            m_Count += m_RestockAmnt;            
            return true;
        }

        public void Serialize( GenericWriter writer )
        {
            writer.Write((TimeSpan)m_RestockRate);           
            writer.Write((int)m_RestockAmnt);
            writer.Write((int)m_Count);
            writer.Write((int)m_Maximum.GetValueOrDefault(-1));
        }

        public RestockInfo( GenericReader reader )
        {
            m_RestockRate = reader.ReadTimeSpan();
            m_LastRestock = DateTime.Now;
            m_RestockAmnt = reader.ReadInt();
            m_Count = reader.ReadInt();
            
            int? max = reader.ReadInt();
         
            m_Maximum = ((max < 0) ? null : max);
        }
    }

    public void Edit(int cost, string title, string desc)
    {
        if (cost < 0 || title == null || desc == null)
            return;

        m_Cost = cost;
        m_Title = title;
        m_Description = desc;
    }
    public Item GetReward()
    {
        return ItemClone.Clone(m_Reward);
    }

    public Reward( Serial serial ) : base( serial )
	{
	}
	public override void Serialize( GenericWriter writer )
	{
		base.Serialize( writer );

		writer.Write( (int) 1 );

        writer.Write((int)m_BuyCount);

        if (m_RestockInfo == null)
        {
            writer.Write(false);
        }
        else
        {
            writer.Write(true);
            m_RestockInfo.Serialize(writer);
        }

        writer.WriteItem((Item)m_Reward);
        writer.Write((int)m_Cost);
        writer.Write((string)m_Title);
        writer.Write((string)m_Description);          
    }
	
	public override void Deserialize(GenericReader reader)
	{
		base.Deserialize( reader );
		int version = reader.ReadInt();

        switch (version)
        {
            case 1:
                {
                    m_BuyCount = reader.ReadInt();

                    if (reader.ReadBool())
                        m_RestockInfo = new RestockInfo(reader);

                    goto case 0;
                }
            case 0:
                {
                    m_Reward = (Item)reader.ReadItem();
                    m_Cost = reader.ReadInt();
                    m_Title = reader.ReadString();
                    m_Description = reader.ReadString();                  
                    
                    break;
                }
        }
    
	}

}
public class RewardCollection : List<Reward>, ICloneable
{
    

    object ICloneable.Clone()
    {
        RewardCollection clone = new RewardCollection();
        
        foreach (Reward r in this)
        {
            clone.Add(((Reward)(r as ICloneable).Clone()));
        }
        return clone;
    }
}

public static class WorldRewardVendors
{
    private static List<IRewardVendor> m_Vendors = new List<IRewardVendor>();

    public static List<IRewardVendor> Vendors { get { return m_Vendors; } }
   
    public static void RegisterVendor(IRewardVendor vendor)
    {
        m_Vendors.Add(vendor);
    }
    public static void RemoveVendor(IRewardVendor vendor)
    {
        m_Vendors.Remove(vendor);
    }
}

public class EditItemGump : Gump
{
    private IRewardVendor m_Vendor;
    private Reward m_Reward;

    private Reward.RestockInfo m_Restock;
    private bool m_RestockOpen;

    private bool m_IsAdd;

    private Storage m_Entries;

    public EditItemGump(IRewardVendor vendor, Reward r, Storage entries, bool openRestockInfo, bool addingItem) : base(0, 0)
    {
        m_Vendor = vendor;
        m_Reward = r;

        m_Restock = r.Restock;
        m_RestockOpen = openRestockInfo;
        m_IsAdd = addingItem;

        m_Entries = entries; 

        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        AddImageTiled(227, 46, 329, 518, 2702);
        AddImageTiled(252, 291, 280, 217, 5104);
        AddLabel(253, 266, 2124, @"Description:");
        AddImageTiled(334, 147, 192, 23, 5104);
        AddLabel(258, 150, 2124, @"Cost:");
        AddImageTiled(336, 107, 192, 23, 5104);
        AddLabel(258, 108, 2124, @"Name:");
        AddImage(354, 199, 2328);
        AddItem(373, 208, r.RewardInfo.ItemID, r.RewardInfo.Hue);
        AddImageTiled(330, 54, 138, 16, 5214);
        AddLabel(373, 51, 1324, @"Edit Item");
        AddButton(465, 222, 5601, 5605, 2, GumpButtonType.Reply, 0); //restock
        AddLabel(447, 198, 2120, @"Restock ");
        AddLabel(447, 246, 2120, @"(Optional)");
        AddButton(324, 523, 4023, 4024, 1, GumpButtonType.Reply, 0);//ok
        AddButton(421, 523, 4017, 4018, 0, GumpButtonType.Reply, 0); //cancel

        if (entries == null)
            InitialText();
        else
            PacketText();

        if (openRestockInfo || r.Restock != null)
        {
            AddRestockMenu();
            m_RestockOpen = true;
        }
    }
    public void InitialText()
    {
        AddTextEntry(252, 292, 277, 215, 1879, 0, m_Reward.Description);
        AddTextEntry(334, 148, 188, 20, 1879, 1, m_Reward.Cost.ToString());
        AddTextEntry(336, 108, 188, 20, 1879, 2, m_Reward.Title);    
    }
    public void PacketText()
    {
        AddTextEntry(252, 292, 277, 215, 1879, 0, m_Entries[0].ToString()); //desc
        AddTextEntry(334, 148, 188, 20, 1879, 1, m_Entries[1].ToString());  //cost 
        AddTextEntry(336, 108, 188, 20, 1879, 2, m_Entries[2].ToString());  //title
    }
    public void AddRestockMenu()
    {

        AddPage(1);

        AddImageTiled(601, 47, 181, 469, 2624);
        AddLabel(648, 60, 2129, @"Restock Info");
        AddLabel(637, 98, 1418, @"Available");
        AddImageTiled(633, 123, 120, 16, 5214);
        AddTextEntry(637, 121, 107, 20, 547, 3, (m_Restock == null ? "Enter." : m_Restock.Count.ToString())); //3 - beginning amount
        AddLabel(660, 161, 1418, @"Maximum");
        AddImageTiled(631, 186, 120, 16, 5214);
        AddTextEntry(635, 184, 107, 20, 547, 4, ((m_Restock == null || m_Restock.Maximum < 0) ? "None." : m_Restock.Maximum.ToString())); //4 - Maxinum
        AddLabel(648, 227, 1418, @"Restock Rate");
        AddImageTiled(635, 252, 72, 16, 5214);
        AddTextEntry(638, 250, 64, 20, 547, 5, (m_Restock == null ? "0" : m_Restock.Hours.ToString())); //5 - hour
        AddLabel(714, 250, 602, @"hours");
        AddImageTiled(635, 292, 72, 16, 5214);
        AddLabel(716, 290, 602, @"mins");
        AddLabel(632, 323, 602, @"amount to restock");
        AddImageTiled(636, 355, 72, 16, 5214);
        AddTextEntry(638, 290, 64, 20, 547, 6, (m_Restock == null ? "0" : m_Restock.Minutes.ToString())); //6 - minute
        AddTextEntry(639, 353, 64, 20, 547, 7, (m_Restock == null ? "0" : m_Restock.RestockAmnt.ToString())); //7 - Restock Amount      
        AddImage(655, 377, 109);
        AddButton(636, 474, 4022, 4021, 3, GumpButtonType.Reply, 0);
        AddLabel(679, 475, 132, @"Void Restock");
        
    }
    public Reward.RestockInfo GetRestockInfo(RelayInfo info)
    {
        if (m_RestockOpen)
        {
            int numMinutes = 0, numHours = 0;
            int numBegin, numMax, numRestockAmnt;

            TextRelay entry3 = info.GetTextEntry(3);
            string beginAmount = (entry3.Text.Trim());

            TextRelay entry4 = info.GetTextEntry(4);
            string max = (entry4.Text.Trim());

            TextRelay entry5 = info.GetTextEntry(5);
            string hour = (entry5.Text.Trim());

            TextRelay entry6 = info.GetTextEntry(6);
            string minute = (entry6.Text.Trim());

            TextRelay entry7 = info.GetTextEntry(7);
            string restockAmount = (entry7.Text.Trim());

            Int32.TryParse(hour, out numHours);
            Int32.TryParse(minute, out numMinutes);
            Int32.TryParse(beginAmount, out numBegin);
            Int32.TryParse(max, out numMax);
            Int32.TryParse(restockAmount, out numRestockAmnt);

            if (numBegin > 0)
            {
                if ((numMinutes + numHours) > 0 && numRestockAmnt > 0)
                {
                    if (numMax > 0)
                    {
                        return new Reward.RestockInfo(numHours, numMinutes, numBegin, numRestockAmnt, numMax);
                    }
                    else
                    {
                        return new Reward.RestockInfo(numHours, numMinutes, numBegin, numRestockAmnt);
                    }
                }

                return new Reward.RestockInfo(numBegin);
            }                   
        }
        return m_Restock; //default
    }
    public Storage GetEntries(RelayInfo info)
    {
        //Description
        TextRelay entry0 = info.GetTextEntry(0);
        string desc = (entry0 == null ? "None." : entry0.Text.Trim());

        //Cost
        TextRelay entry1 = info.GetTextEntry(1);
        string costtext = (entry1 == null ? "0" : entry1.Text.Trim());

        //Name
        TextRelay entry2 = info.GetTextEntry(2);
        string name = (entry2 == null ? "" : entry2.Text.Trim());

        return new Storage(desc, costtext, name);
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        switch (info.ButtonID)
        {
            case 0:
                {
                    //cancel
                    break;
                }
            case 1: //ok
                {
                    try
                    {
                        //Description
                        TextRelay entry0 = info.GetTextEntry(0);
                        string desc = (entry0 == null ? "None." : entry0.Text.Trim());

                        //Cost
                        TextRelay entry1 = info.GetTextEntry(1);
                        string costtext = (entry1 == null ? "%Error" : entry1.Text.Trim());
                        int cost = Int32.Parse(costtext);

                        //Name
                        TextRelay entry2 = info.GetTextEntry(2);
                        string name = (entry2 == null ? "" : entry2.Text.Trim());

                        if ( m_IsAdd )
                            m_Vendor.AddReward(m_Reward);
                        
                        m_Reward.Edit(cost, name, desc);

                        if (m_RestockOpen)
                        {
                            Reward.RestockInfo input = GetRestockInfo(info);

                            if (input != null)
                            {
                                if (m_Restock != null && !(m_Restock.Equals(input))) //do not reassign same object
                                {
                                    m_Reward.Restock = input;
                                }
                                else
                                {
                                    m_Reward.Restock = input;
                                }
                            }
                        }

                        m.SendMessage("{0} has been modified in {1}'s collection", name, m_Vendor.GetName());

                    }
                    catch { m.SendMessage("Please make sure all fields are filled correctly, and the title has not been previously used."); }

                    break;
                }
            case 2: //open restock options
                {                                  
                    m.SendGump(new EditItemGump(m_Vendor, m_Reward, GetEntries(info), true, m_IsAdd));
                    
                    return; //override display 
                }
            case 3: //delete restock options
                {                   
                    m_Reward.Void_RestockInfo();
                                    
                    m.SendGump(new EditItemGump(m_Vendor, m_Reward, GetEntries(info), false, m_IsAdd));
                    
                    return; //override display 
                }
        }
        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, true); //send back display
    }
}

public class Exhibit : Item
{
    private IRewardVendor m_Vendor;
    private Reward m_Reward;
    private ObjectPropertyList m_PropertyList;

    public Exhibit(IRewardVendor vendor, Reward r)
        : base()
    {
        m_Vendor = vendor;
        m_Reward = r;

        SetOPL(r);

        this.ItemID = r.RewardInfo.ItemID;
        this.Hue = r.RewardInfo.Hue;
    }
    public override void SendPropertiesTo(Mobile from)
    {
        if (m_PropertyList == null)
        {
            m_PropertyList = new ObjectPropertyList(this);
            m_PropertyList.Add("Display [Broken]");
        }

        from.Send(m_PropertyList);
    }
    public void SetOPL(Reward r)
    {
        Item i = r.RewardInfo;

        m_PropertyList = new ObjectPropertyList(this);

        m_PropertyList.Add("Cost: " + m_Reward.Cost.ToString() + " " + m_Vendor.Payment.PayName + " [Click for more]");

        i.GetProperties(m_PropertyList);
        i.AppendChildProperties(m_PropertyList);

        m_PropertyList.Terminate();
        m_PropertyList.SetStatic();

    }

    public override void OnDoubleClick(Mobile m)
    {
        if (m_Vendor == null || m_Vendor.IsRemoved() || m_Reward == null || !m_Vendor.Display.Contains(m_Reward))
        {
            m_Vendor = null; // free up resource
            m_Reward = null;
            m.SendMessage("This item is no longer available to purchase.");
        }
        else
            m.SendGump(new ViewItemGump(m, m_Vendor, m_Reward, false));
    }

    public Exhibit(Serial serial)
        : base(serial)
    {
    }
    public override void Deserialize(GenericReader reader)
    {
        base.Deserialize(reader);

        int version = reader.ReadInt();

        if (reader.ReadBool())
        {
            m_Reward = (Reward)reader.ReadItem();

            m_Vendor = (IRewardVendor)reader.ReadMobile();

            try { SetOPL(m_Reward); }
            catch { }
        }
    }

    public override void Serialize(GenericWriter writer)
    {
        base.Serialize(writer);

        writer.Write((int)0); // version  

        if (m_Vendor == null || m_Vendor.IsRemoved() || m_Reward == null || m_Reward.Deleted)
        {
            m_Vendor = null;
            m_Reward = null;

            writer.Write((bool)false); //do not deserialize
        }
        else
        {
            writer.Write((bool)true);

            writer.WriteItem((Reward)m_Reward);

            writer.Write((Mobile)m_Vendor.GetMobile());
        }
    }
}
public class ViewItemGump : Gump
{
    IRewardVendor m_Vendor;
    Reward m_Reward;

    public ViewItemGump(Mobile m, IRewardVendor vendor, Reward r, bool viewItem)
        : base(0, 0)
    {
        m_Vendor = vendor;
        m_Reward = r;

        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);
        AddImageTiled(149, 207, 548, 277, 2624);
        AddImage(184, 300, 2328);
        AddImage(101, 222, 10400);
        
        AddHtml(428, 290, 243, 140, r.Description, (bool)true, (bool)true);
        AddItem(201, 311, r.RewardInfo.ItemID, r.RewardInfo.Hue);
                
        AddLabel(430, 263, 2101, @"Description");
        AddButton(192, 442, 4029, 4030, 2, GumpButtonType.Reply, 0); //buy
        AddLabel(231, 444, 2125, "Buy (" + r.Cost +")");
        AddButton(366, 442, 4020, 4021, 0, GumpButtonType.Reply, 0); //cancel
        AddLabel(407, 444, 2116, @"Cancel");
        AddImageTiled(184, 239, 510, 8, 9201);

        AddItem(182, 376, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);
        AddLabel(248, 369, 83, @"Pay By: " + m_Vendor.Payment.PayName);
        AddLabel(184, 268, 43, @"Vendor: " + m_Vendor.GetName());
        AddLabel(363, 216, 2123, r.Title);

        if (m.AccessLevel > AccessLevel.GameMaster) //GM capabilities
        {
            if (!viewItem)
                AddLabel(363, 216, 2123, r.Title);
            else
            {
                AddLabel(336, 296, 2101, @"Edit Item");
                AddButton(294, 293, 4011, 4012, 4, GumpButtonType.Reply, 0); //edit item

                if (m_Vendor.GetMobile() != null)
                {
                    AddLabel(336, 348, 2101, @"Get Display");
                    AddButton(294, 345, 4011, 4012, 3, GumpButtonType.Reply, 0); //get display   
                }
            }
        }
        else
        {
            OpenDisplay(m); //prevent build up of box display during editing
        }

        //Edit gump for display object
        if (viewItem) //not display
        {
            AddLabel(336, 322, 2101, @"View Item");
            AddButton(294, 319, 4011, 4012, 1, GumpButtonType.Reply, 0); //view item
                    
        }
        else //display
        {
            AddLabel(279, 320, 38, @"Cost: " + m_Reward.Cost.ToString());
            AddLabel(249, 398, 69, @"You have: " + m_Vendor.Payment.Value(m));

            if (m_Reward.Restock != null)
            {
                m_Reward.Try_Restock();
                AddLabel(279, 340, 4, "In Stock: " + m_Reward.Restock.Count.ToString());
            }

            if (m_Reward.RewardInfo is Container)
                OpenDisplay(m); 
        }
    }
    public void OpenDisplay(Mobile m)
    {
        DisplayBox dbox = m_Vendor.Display;

        if (dbox != null)
            dbox.DisplayTo(m, m_Reward);
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (m_Vendor.IsRemoved())
            return;

        switch (info.ButtonID)
        {
            case 0:
                {
                    break;
                }
            case 1:
                {
                    try
                    {
                        OpenDisplay(m);
                        m.SendGump(this);
                    }
                    catch
                    {
                        m.SendMessage("This Reward can no longer be found.");
                    }
                    break;
                }
            case 2:
                {
                    Container bank = m.BankBox;
                    Container pack = m.Backpack;

                    if ( bank == null || pack == null )
                        break;

                    Currency curr = m_Vendor.Payment;

                    if (m_Reward.InStock(1))
                    {
                        if (curr.Purchase(m, m_Reward.Cost))
                        {
                            m_Reward.RegisterBuy(1);

                            Item i = m_Reward.RewardCopy;

                            if (!m.PlaceInBackpack(i))
                            {
                                bank.DropItem(i);
                                m.SendMessage("You are overweight, the Reward was added to your bank");
                            }

                            m.SendMessage("You bought {0} for {1} {2}.", m_Reward.Title, m_Reward.Cost, curr.PayName);

                        }
                        else
                            m.SendMessage("You cannot afford {0}", m_Reward.Title);
                    }                           
                    else
                        m.SendMessage("{0} is no longer in stock.", m_Reward.Title);  

                    break;
                }
            case 3:
                {
                    if (m.Backpack != null)
                        m.AddToBackpack(new Exhibit(m_Vendor, m_Reward));
                    break;
                }
            case 4:
                {
                    m.SendGump(new EditItemGump(m_Vendor, m_Reward, null, false, false));
                    break;
                }
        }
    }
}

//Created for the usage of Warning Gump delegate 
public class Storage
{
    object[] m_Objs;

    public object this[int index]
    {
        get { return m_Objs[index]; }
    }

    public Storage(params object[] input)
    {
        m_Objs = input;
    }
    
}


public class WorldVendorsGump : Gump
{
    IRewardVendor m_Vendor; //used in case of copy

    public WorldVendorsGump(IRewardVendor vendor) : base( 0, 0 )
    {
        m_Vendor = vendor;

        this.Closable=true;
		this.Disposable=true;
		this.Dragable=true;
		this.Resizable=false;

		AddPage(0);

        //background
        AddImageTiled(50, 3, 430, 556, 2702);
		AddImageTiled(93, 78, 387, 9, 10101);
		AddImage(33, 58, 10420);
		AddImageTiled(47, 2, 3, 556, 10004);
		AddImageTiled(0, 58, 82, 414, 10440);
		AddImageTiled(47, 558, 436, 3, 10001);
		AddImageTiled(47, 0, 435, 3, 10001);
		AddImageTiled(480, 2, 3, 556, 10004);

        AddPage(1);

        CreateVendors(); //fill out entries
    }
    
    public static void CopyVendor_Callback(Mobile from, bool okay, object state)
    {
        if (from.AccessLevel < AccessLevel.GameMaster)
            return;
                
        if (okay)
        {
            //indexes -> (vendor (0), vendor's copy target(1))
            Storage store = (Storage)state;

            IRewardVendor source = (IRewardVendor)store[0];
            IRewardVendor target = (IRewardVendor)store[1];

            try { source.CopyVendor(target); }
            catch { from.SendMessage("Error occured while copying, please insure backpack is on vendors."); return; }

            from.SendMessage("{0} has copied {1}'s Reward collection", source.GetName(), target.GetName());
        }
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
        {
            m.CloseGump(typeof(ControlPanelGump));
            return;
        }

        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);

        try
        {
            if (info.ButtonID % 2 == 0 ) //even ID: Copy Vendor
            {
                IRewardVendor selected = WorldRewardVendors.Vendors[(info.ButtonID / 2) - 1];

                if ( m_Vendor.GetName().Equals(selected.GetName()))
                {
                    m.SendMessage("A vendor cannot copy itself.");
                }
                else
                {
                    //params -> (vendor, vendor's copy target)
                    Storage store = new Storage(m_Vendor, selected);

                    m.SendGump(new WarningGump(1060635, 30720, "Warning: You will lose all saved items on " + m_Vendor.GetName(), 0xFFC000, 420, 400, new WarningGumpCallback(CopyVendor_Callback), store));
                }
            }
            else //assert odd ID: Goto 
            {
                IRewardVendor v = WorldRewardVendors.Vendors[((info.ButtonID + 1) / 2) - 1];

                m.Location = v.GetLocation();
                m.Map = v.GetMap();
            }
        }
        catch
        {
            m.SendMessage("Vendor cannot be found.");
        }
    }
    public void CreateVendors()
    {
        int yPos = 101, pageNum = 1, buttonNum = 0;
      
        for (int i = 0; i < WorldRewardVendors.Vendors.Count; ++i)
        {            
            AddButton(175, yPos + 38, 4005, 4006, ++buttonNum, GumpButtonType.Reply, pageNum); //goto button - odd ID
            AddButton(279, yPos + 38, 4011, 4012, ++buttonNum, GumpButtonType.Reply, pageNum); //copy vendor - even ID
            AddLabel(86, yPos, 1849, WorldRewardVendors.Vendors[i].GetName());
            AddImageTiled(86, yPos + 93, 359, 2, 96);

            if (WorldRewardVendors.Vendors[i].GetMobile() != null)
                AddItem(110, yPos + 27, 8461); // person
            else

                AddItem(110, yPos + 27, WorldRewardVendors.Vendors[i].GetItem().ItemID, WorldRewardVendors.Vendors[i].GetItem().Hue); //stone ID

            AddLabel(213, yPos + 43, 2209, @"Go To");
            AddLabel(318, yPos + 43, 2204, @"Copy Vendor");
            
            yPos += 99;

            //add new page every four entries
            if ((i + 1) % 4 == 0)
            {
                AddButton(417, 531, 9903, 248, -1, GumpButtonType.Page, (pageNum + 1));

                AddPage(++pageNum);

                AddButton(92, 532, 9909, 248, -1, GumpButtonType.Page, (pageNum - 1));

                //reset to top of page
                yPos = 101;
            }
        }
    }
}
public class InfoGump : Gump
{
    public InfoGump()
        : base(0, 0)
    {
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);
        
        AddImageTiled(0, 0, 452, 516, 2702);
        AddHtml(21, 78, 407, 105, @"Consume Item:  Vendor counts the number of the chosen item present in player's backpack.  

        Property(Item/Player):  Vendor takes the total of the given number based property (example: PlayerPoints, Charges)
        (Items): Adds up from every item present.
        (Player): Simply takes from what is present.
        ", (bool)true, (bool)true);

        AddLabel(23, 52, 2000, @"Choosing How Player Pays:");
        AddHtml(21, 242, 407, 105, @"You can create your own rewards in game, all properties will be copied over.  ", (bool)true, (bool)true);
        AddLabel(24, 216, 2000, @"Adding Items");
        AddLabel(239, 479, 37, @"Author: krazeykow1102");
        AddItem(391, 467, 8451);
        AddLabel(24, 368, 2000, @"How Displays Work");
        AddHtml(24, 394, 410, 78, @"Displays allow you to create your own interactive Reward room.  The display is a simple mirror to the item on the vendor.  Payment and cost will reflect what is on the vendor.  Vendor must stay in tact for display to function", (bool)true, (bool)true);
    }
}


public class ControlPanelGump : Gump
{
    private IRewardVendor m_Vendor;
   
    public ControlPanelGump(Mobile m, IRewardVendor vendor)
        : base(0, 0)
    {

        m_Vendor = vendor;
                
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        //background
        AddImageTiled(4, 3, 215, 571, 2702);
        AddImageTiled(3, 0, 217, 3, 10001);
        AddImageTiled(4, 572, 216, 3, 10001);
        AddImageTiled(3, 1, 3, 571, 10004);
        AddImageTiled(217, 1, 3, 574, 10004);

        AddImage(40, 8, 5214);
        AddLabel(41, 7, 47, @"Control Panel");

        AddLabel(109, 62, 55, @"Manage Rewards");
        AddButton(72, 60, 4008, 4009, 1, GumpButtonType.Reply, 0); //PlayerView
        AddItem(31, 63, 5366); //scope
        AddImageTiled(19, 160, 132, 2, 96);

        AddLabel(79, 123, 1324, @"Add Item or Container");
        AddButton(52, 126, 2117, 2118, 2, GumpButtonType.Reply, 0); //AddItem
        AddItem(0, 113, 8192); //box  
        
        AddLabel(11, 232, 55, @"Target Payment Source:");
        AddButton(170,232, 2117, 2118, 3, GumpButtonType.Reply, 0); //Payment
        AddLabel(12, 173, 55, @"Pay By: " + m_Vendor.Payment.PayName );
        AddItem(61, 197, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);

        AddLabel(12, 32, 55, @"Vendor: " + m_Vendor.GetName());
        AddButton(77, 533, 4026, 4027, 4, GumpButtonType.Reply, 0);
        AddLabel(78, 553, 104, @"Help");

        if (m_Vendor.GetMobile() != null)
        {
            AddButton(72, 91, 4011, 4012, 5, GumpButtonType.Reply, 0); //Displays
            AddLabel(109, 93, 55, @"Get All Displays");
        }
        else
            AddLabel(12, 93, 55, @"Use Mobile Vendor for displays.");

       
        AddLabel(51, 258, 43, @"XML Attachment");
        AddRadio(15, 258, 9720, 9724, false, 6);
        AddLabel(51, 303, 43, @"Consume Item");
        AddRadio(15, 300, 9720, 9724, false, 7);
        AddLabel(50, 349, 43, @"[props Name of Item/Player");
        AddRadio(15, 342, 9720, 9724, false, 8);
        AddImageTiled(12, 382, 156, 22, 5058);
        AddTextEntry(12, 382, 149, 20, 41, 0, @"[prop/XML Name Here");

        AddPage(1);

        CreateGumps(); //fill out entries
               
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (m_Vendor.IsRemoved())
        {
            m.SendMessage("This vendor has been deleted.");
            return;
        }

        switch (info.ButtonID)
        {
            case 0:
                {
                    m.CloseGump(typeof(WorldVendorsGump));

                    //close
                    break;
                }
            case 1: //PlayerView
                {
                    m.CloseGump(typeof(WorldVendorsGump));

                    MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, true);
                    break;
                }
            case 2: //AddItem
                {
                    m.CloseGump(typeof(WorldVendorsGump));

                    m.Target = new AddItemTarget(m_Vendor);
                    break;
                }
            case 3: //Payment
                { 
                    
                        try
                        {
                            if (info.IsSwitched(6))
                            {
                                m.SendMessage("Target the player or item you wish to get the XMLAttribute from.");
                                TextRelay entry0 = info.GetTextEntry(0);
                                string propName = (entry0 == null ? "" : entry0.Text.Trim());

                                m.Target = new PaymentTarget(m_Vendor, propName, true);
                            }
                            else if ( info.IsSwitched(7)) // Consume by item amount
                            {
                                m.SendMessage("Warning: payment will be taken as the unmodified created item.");
                                m.Target = new PaymentTarget(m_Vendor);
                            }
                            else if (info.IsSwitched(8)) //Consume by item's property
                            {
                                m.SendMessage("Target yourself or an item.");
                                TextRelay entry0 = info.GetTextEntry(0);
                                string propName = (entry0 == null ? "" : entry0.Text.Trim());

                                m.Target = new PaymentTarget(m_Vendor, propName, false);
                            }
                            else
                            {                                
                                MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);
                                m.SendMessage("Please select consume or property.");
                            }
                        }

                            catch { }

                            break;      
                  }
            case 4:
                {
                    MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);
                    m.SendGump(new InfoGump());
                    break;
                }
            case 5: //Displays
                {
                    if (m.Backpack == null)
                        return;

                    MetalBox c = new MetalBox();
                    c.Name = m_Vendor.GetName() + "'s Reward Displays";

                    foreach (Reward r in m_Vendor.Rewards)
                    {
                        c.DropItem(new Exhibit(m_Vendor, r));
                    }

                    m.AddToBackpack(c);

                    break;
                }

            default: //Set Menu - IDs are >= 7
                {
                    try
                    {
                        Type menuType = MenuUploader.Menus[info.ButtonID - 7];

                        if (m_Vendor.GetItem() != null && menuType.Equals(typeof(ClassicVendorGump)))
                            m.SendMessage("Only Mobile Reward Vendors can have classic menus.");
                        else
                        {
                            m_Vendor.Menu = menuType;
                            m.SendMessage("Display changed to " + menuType.Name);
                        }
                    }
                    catch { }

                    MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);

                    break;
                                      
                }
         }   
    }
    public void CreateGumps()
    {
        int yPos = 433, pageNum = 1;

        for (int i = 0; i < MenuUploader.Menus.Count; ++i )
        {

            AddLabel(50, yPos, 100, MenuUploader.Menus[i].Name);
            AddButton(12, yPos, 4005, 4006, (i + 7), GumpButtonType.Reply, pageNum);
            

            yPos += 26;

            //add new page every four entries
            if ((i + 1) % 4 == 0)
            {
                AddButton(144, 542, 9702, 9703, -1, GumpButtonType.Page, (pageNum + 1));

                AddPage(++pageNum);

                AddButton(10, 542, 9706, 9707, -1, GumpButtonType.Page, (pageNum - 1));

                //reset to top of page
                yPos = 433;
            }
        } 
    }
}
public static class MenuUploader 
{
    private static List<Type> m_Menus = new List<Type>(); 
    
    public static List<Type> Menus { get { return m_Menus; } }

    public static void RegisterMenu<G>(G menu) where G : Gump, IRewardVendorGump
    {
        m_Menus.Add(menu.GetType());
    }
    
    public static void Display(IRewardVendorGump menu, Mobile m, IRewardVendor vendor)
    {
        m.CloseGump(typeof(IRewardVendorGump));

        //create 'canvas'
        menu.CreateBackground();

        //create Reward displays
        foreach (Reward r in vendor.Rewards)
        {
            //refresh restock  
            if (r.Try_Restock() == 0 && !(menu is ManageItemsGump))
                continue;
            
            menu.AddEntry(r);
        }

        //send finished product
        menu.Send(m);
    }
    public static void Display(Type menu, Mobile m, IRewardVendor vendor, bool playerView)  //Note: Playerview is only relevant for Staff
    {
        try
        {
            if (m.AccessLevel > AccessLevel.GameMaster) 
            {
                if (playerView)
                    Display(new ManageItemsGump(vendor, m), m, vendor);
                else //control panel
                {
                    m.CloseGump(typeof(WorldVendorsGump));
                    m.CloseGump(typeof(ControlPanelGump));

                    m.SendGump(new WorldVendorsGump(vendor)); 
                    m.SendGump(new ControlPanelGump(m, vendor));
                }
            }
            else //player
            {
                Display((IRewardVendorGump)Activator.CreateInstance(menu, new object[] { vendor, m }), m, vendor); //create fresh instance
            }
        }
        catch
        {
            if ( m.AccessLevel > AccessLevel.GameMaster )
                m.SendMessage("The current display is invalid, try setting gump back to default, JewlRewardGump.");
            else
                m.SendMessage("The current display is invalid, please notify the staff.");
        }
    }
}
public class ManageItemsGump : JewlRewardGump
{
    private int m_ButtonNum;

    public ManageItemsGump(IRewardVendor vendor, Mobile m) : base(vendor, m)
    {
        m_ButtonNum = 0;
    }
    public override void AddEntryControl(Reward r)
    {
        ImageTileButtonInfo b = new ItemTileButtonInfo(r.RewardInfo);

        //begin time entries
        if (r.Restock != null)
        {
            if (r.Restock.RestockRate.TotalMinutes == 0)
                AddLabel(324, (PosY + 22), 5, "Limited");
            else
                AddLabel(324, (PosY + 22), 5, ((int)r.Restock.RestockRate.Hours).ToString() + " hours " + ((int)r.Restock.RestockRate.Minutes).ToString() + " min");

            if (r.Restock.Maximum > 0)
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString() + " / " + r.Restock.Maximum.ToString() + ", Purchased: " + r.BuyCount.ToString());
            else
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString() + ", Purchased: " + r.BuyCount.ToString());
        }
        else
        {
            AddLabel(324, (PosY + 68), 4, "Purchased: " + r.BuyCount.ToString());
        }
        //end 

        //create entry
        AddLabel(227, PosY, 2123, r.Title);
        AddLabel(324, (PosY + 45), 2115, "Cost: " + r.Cost);
        //odd numbers
        AddImageTiledButton(227, (PosY + 26), 2328, 2329, ++m_ButtonNum, GumpButtonType.Reply, PageNum, b.ItemID, b.Hue, 15, 10, r.Display.Header);
        AddImageTiled(215, (PosY + 95), 359, 2, 96);
        //odd numbers (same as above)
        AddButton(470, (PosY + 45), 4011, 4012, m_ButtonNum, GumpButtonType.Reply, PageNum);
        AddLabel(508, (PosY + 47), 1882, @"Options");
        //even numbers
        AddButton(470, (PosY + 19), 4020, 4021, ++m_ButtonNum, GumpButtonType.Reply, PageNum);
        AddLabel(509, (PosY + 21), 1882, @"Delete");
        PosY += 102;

        //add new page every four entries
        if (EntryNum % 4 == 0)
        {
            AddButton(546, 562, 9903, 9904, -1, GumpButtonType.Page, PageNum + 1);

            AddPage(++PageNum);

            AddButton(221, 563, 9909, 9910, -1, GumpButtonType.Page, PageNum - 1);

            //reset to top of page
            PosY = 130;
        }

        EntryNum++;
    }
    public static void DeleteReward_Callback(Mobile from, bool okay, object state)
    {
        if (from.AccessLevel < AccessLevel.GameMaster)
            return;

        if (okay)
        {
            //indexes -> (Vendor(0), Reward(1))
            Storage store = (Storage)state;

            IRewardVendor vendor = (IRewardVendor)store[0];
            Reward Reward = (Reward)store[1];

            try { vendor.RemoveReward(Reward); }
            catch { from.SendMessage("An error ocurred in the removal of this item."); }
            
            MenuUploader.Display(vendor.Menu, from, vendor, true);
        }
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
        {
            MenuUploader.Display(Vendor.Menu, m, Vendor, false);
            return;
        }
            
        if (info.ButtonID % 2 == 0) //even
        {
                try
                {
                    Reward r = Vendor.Rewards[(info.ButtonID / 2) - 1];

                    //params -> (vendor, Reward)
                    Storage store = new Storage(Vendor, r);

                    m.SendGump(new WarningGump(1060635, 30720, "Warning: Are you sure you want to remove " + r.Title, 0xFFC000, 420, 400, new WarningGumpCallback(DeleteReward_Callback), store));

                }
                catch { m.SendMessage("This item could not be found."); }
            
        }
        else //assert - odd
        {
            try
            {
                MenuUploader.Display(Vendor.Menu, m, Vendor, true);
                m.SendGump(new ViewItemGump(m, Vendor, Vendor.Rewards[((info.ButtonID + 1) / 2) - 1], true));
            }
            catch { m.SendMessage("Vendor could not be found"); }
        }
        
    }
    
}
public class XMLIntPropertyGump : Gump
{
    private Type m_XML_Type;
    private object m_Target;

    private IRewardVendor m_Vendor;
    private List<PropertyInfo> m_Props;

    private int m_PageNum;
    private  int m_PosY;
    private int m_EntryNum;

    public XMLIntPropertyGump(Type xmlType, object target, IRewardVendor vendor, List<PropertyInfo> props)
        : base(0, 0)
    {
        m_XML_Type = xmlType;
        m_Target = target;
        m_Vendor = vendor;
        m_Props = props;

        m_PageNum = 1;
        m_PosY = 134;
        m_EntryNum = 1;
      
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        AddImageTiled(284, 90, 168, 384, 2702);
        AddLabel(315, 99, 49, xmlType.Name);
        AddImageTiled(292, 123, 151, 3, 9151);

        AddPage(1);

        FillEntries();
    }
    public void FillEntries()
    {
        foreach (PropertyInfo pi in m_Props)
        {
            AddButton(295, m_PosY, 5601, 5605, m_EntryNum, GumpButtonType.Reply, 0);
            AddLabel(319, m_PosY, 43, pi.Name);

            m_PosY += 26;

            if (m_EntryNum % 10 == 0)
            {
                AddButton(423, 444, 9903, 9904, -1, GumpButtonType.Page, m_PageNum + 1);

                AddPage(++m_PageNum);

                AddButton(292, 444, 9909, 9910, -1, GumpButtonType.Page, m_PageNum - 1);

                //reset to top of page
                m_PosY = 134;
            }
            m_EntryNum++;
        }

       
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
            return;

        m_Vendor.Payment = new Currency(m_Target, m_XML_Type, m_Props[info.ButtonID - 1]);
        m.SendMessage("{0}'s payment method set to {1}.{2}", m_Vendor.GetName(), m_XML_Type.Name, m_Props[info.ButtonID-1].Name);
    }

}
public class JewlRewardGump : Gump, IRewardVendorGump
{
    private int m_PageNum;
    private int m_EntryNum;
    private int m_PosY;
    private IRewardVendor m_Vendor;
    private Mobile m_Mobile;
    private int m_CurrencyAmnt;
   
    public static void Initialize()
    {
        MenuUploader.RegisterMenu(new JewlRewardGump());
    }

    public JewlRewardGump()
        : base(0, 0)
    {
        m_PageNum = 1;
        m_EntryNum = 1;
        m_PosY = 130;
        m_Vendor = null;
        m_Mobile = null;
        m_CurrencyAmnt = 0;
    }
    public JewlRewardGump(IRewardVendor vendor, Mobile m) : this()
    {
        m_Vendor = vendor;
        m_Mobile = m;
        m_CurrencyAmnt = vendor.Payment.Value(m);
    }

    //Properties
    public int PageNum { get { return m_PageNum; } set { m_PageNum = value; } }
    public int EntryNum { get { return m_EntryNum; } set { m_EntryNum = value; } }
    public int PosY { get { return m_PosY; } set { m_PosY = value; } }
    public IRewardVendor Vendor { get { return m_Vendor; } set { m_Vendor = value; } }
    public Mobile Mobile { get { return m_Mobile; } set { m_Mobile = value; } }
    public int CurrencyAmnt { get { return m_CurrencyAmnt; } set { m_CurrencyAmnt = value; } }

    //Interface Explicit Implementation 
    void IRewardVendorGump.Send(Mobile m) { SendControl(m); }
    void IRewardVendorGump.CreateBackground() { CreateBackgroundControl(); } 
    void IRewardVendorGump.AddEntry(Reward r) { AddEntryControl(r); }

    public virtual void SendControl(Mobile m)
    {
        m.SendGump(this);
    }
    public virtual void CreateBackgroundControl()
    {
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        AddImageTiled(179, 34, 430, 556, 2702);
        AddImageTiled(222, 109, 387, 9, 10101);
        AddImage(162, 89, 10420);
        AddImageTiled(176, 33, 3, 556, 10004);
        AddImageTiled(129, 89, 82, 414, 10440);
        AddImageTiled(176, 589, 436, 3, 10001);
        AddImageTiled(176, 31, 435, 3, 10001);
        AddImageTiled(609, 33, 3, 556, 10004);
        AddLabel(348, 52, 2124, m_Vendor.GetName());
        AddImage(210, 52, 9818);
        AddImage(534, 52, 9818);
        AddLabel(404, 119, 2125, @"You have:");
        AddItem(348, 126, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);
        AddLabel(404, 137, 2125, (m_CurrencyAmnt.ToString() + " " + m_Vendor.Payment.PayName) );
        

        AddPage(1);
    }
      
    public virtual void AddEntryControl(Reward r)
    {
        ImageTileButtonInfo b = new ItemTileButtonInfo(r.RewardInfo);

        //create entry

        //begin time entries
        if (r.Restock != null)
        {
            if (r.Restock.RestockRate.TotalMinutes == 0)
                AddLabel(324, (PosY + 22), 5, "Limited");

            if (r.Restock.Maximum > 0)
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString());
            else
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString());
        }
        //end 

        AddLabel(227, m_PosY, 2123, r.Title);
        AddLabel(324, (m_PosY + 45), 2115, "Cost: " + r.Cost);
        AddImageTiledButton(227, (m_PosY + 26), 2328, 2329, (m_EntryNum), GumpButtonType.Reply, m_PageNum, b.ItemID, b.Hue, 15, 10, b.LocalizedTooltip);
        AddImageTiled(215, (m_PosY + 95), 359, 2, 96);
        AddButton(470, (PosY + 45), 4011, 4012, (m_EntryNum), GumpButtonType.Reply, m_PageNum);
        AddLabel(508, (PosY + 47), 745, @"View Item");
        m_PosY += 102;
        
        //add new page every four entries
        if (m_EntryNum % 4 == 0)
        {
            AddButton(546, 562, 9903, 9904, -1, GumpButtonType.Page, m_PageNum + 1);

            AddPage(++m_PageNum);

            AddButton(221, 563, 9909, 9910, -1, GumpButtonType.Page, m_PageNum - 1);

            //reset to top of page
            m_PosY = 130;
        }

        m_EntryNum++;
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
            return;

        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, true);

        try
        {
            m.SendGump(new ViewItemGump(m, m_Vendor, m_Vendor.Rewards[info.ButtonID - 1], true));
        }
        catch { m.SendMessage("Vendor could not be found"); }
    }
}

public class DisplayBox : LargeCrate, IEnumerable
{
    private Dictionary<Reward, MetalBox> m_Boxes;

    public override bool IsPublicContainer { get { return true; } }

    public MetalBox this[Reward r]
    {
        get
        {
            MetalBox box = null; //not found

            m_Boxes.TryGetValue(r, out box);

            return box;
        }
    }

    [Constructable]
    public DisplayBox()
        : base()
    {
        this.Name = "Display Box [DO NOT REMOVE]";
        this.LiftOverride = true;
        m_Boxes = new Dictionary<Reward, MetalBox>();
    }
    public DisplayBox(RewardCollection rc)
        : this()
    {
        CreateEntries(rc);
    }
    public bool Contains(Reward r)
    {
        return m_Boxes.ContainsKey(r);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return m_Boxes.GetEnumerator();
    }
    public override bool CheckLift(Mobile from, Item item, ref LRReason reject)
    {
        reject = 0;
        return false;
    }
    public void DisplayTo(Mobile m, Reward r)
    {
        string invalid = "This item can no longer be displayed.";
        bool staff = m.AccessLevel >= AccessLevel.GameMaster;

        try
        {
            Container[] containers = new Container[] { (Container)this.Parent, this }; //cast exception if parent isn't container

            foreach (Container c in containers)
            {
                if (m.NetState != null && m.NetState.IsPost6017)
                    m.Send(new ContainerContent6017(m, c));
                else
                    m.Send(new ContainerContent(m, c));
            }

            m_Boxes[r].DisplayTo(m); //throws null ref if not found

            m.SendMessage("A container has been opened for you to view the item.");
        }
        catch (NullReferenceException)
        {
            if (staff)
                m.SendMessage("Display error - please insure Reward is still on this vendor.");
            else
                m.SendMessage(invalid);
        }
        catch (InvalidCastException)
        {
            if (staff)
                m.SendMessage("Display error - the current vendor does not have a DisplayBox in backpack.");
            else
                m.SendMessage(invalid);
        }
        catch (Exception)
        {
            if (staff)
                m.SendMessage("Unknown error occured with display.");
            else
                m.SendMessage(invalid);
        }
            
    }
    //Warning: must catch exception in methods
    public void CreateEntries(RewardCollection rc)
    {
        foreach (Reward r in rc)
        {
            this.AddDisplay(r, r.RewardInfo);
        }
    }
    public void AddDisplay(Reward key, Item i)
    {
        if (m_Boxes.ContainsKey(key))
            throw new Exception("Key already in use.");

        MetalBox container = new MetalBox();
        
        container.DropItem(i);

        this.DropItem(container);

        m_Boxes.Add(key, container);    
    }
    public void AddDisplay(Reward r)
    {
        AddDisplay(r, r.RewardInfo);
    }
    public void RemoveDisplay(Reward r)
    {
        ((Item)m_Boxes[r]).Delete(); //remove from displaybox
        m_Boxes.Remove(r);   //remove from hashtable      
    }
    //End Warning

    public override bool OnDragDrop( Mobile from, Item dropped )
    {
        return false;//do nothing
    }

    public DisplayBox( Serial serial ) : base( serial )
	{
	}
    
	public override void Serialize( GenericWriter writer )
    {
		base.Serialize( writer );

		writer.Write( (int) 0 ); // version
        
        int count = 0;
        try
        {
            count = m_Boxes.Count;
        }
        catch
        {
            m_Boxes = new Dictionary<Reward, MetalBox>();
            m_Boxes.Add(new Reward(), new MetalBox());
            count = m_Boxes.Count;
        }
        writer.Write((int)count);

        foreach (KeyValuePair<Reward, MetalBox> kvp in m_Boxes)
        {
            writer.Write((Reward)kvp.Key);
            writer.WriteItem((MetalBox)kvp.Value);
        }
        
    }

	public override void Deserialize( GenericReader reader )
    {
		base.Deserialize( reader );
                
		int version = reader.ReadInt();

        
        int count = reader.ReadInt();
        
        m_Boxes = new Dictionary<Reward, MetalBox>();     
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                Reward r = (Reward)reader.ReadItem();
                MetalBox box = (MetalBox)reader.ReadItem();

                m_Boxes.Add(r, box);
            }
        }      
    }
}

public class LoadGumpEntry : ContextMenuEntry
{
    private IRewardVendor m_Vendor;
    private Mobile m_Mobile;

    public LoadGumpEntry(Mobile from, IRewardVendor vendor)
        : base(6103, 8)
    {
        m_Vendor = vendor;
        m_Mobile = from;
        Enabled = true;
    }

    public override void OnClick()
    {
        try
        {
            MenuUploader.Display((IRewardVendorGump)Activator.CreateInstance(m_Vendor.Menu, new object[] { m_Vendor, m_Mobile }), m_Mobile, m_Vendor); //create fresh instance
        }
        catch { m_Mobile.SendMessage("The current display is invalid.");  }
    }
}
public class ClassicVendorGump : Gump, IRewardVendorGump
{
    private IRewardVendor m_Vendor;
    private BaseVendor m_BVendor;

    private Mobile m_Mobile;   

    private List<ObjectPropertyList> m_Opls;
    private ArrayList m_List;

    public List<ObjectPropertyList> ObjPropLists { get { return m_Opls; } }
    public ArrayList RewardList { get { return m_List; } }

    public static void Initialize()
    {
        MenuUploader.RegisterMenu(new ClassicVendorGump());
    }

    public ClassicVendorGump()
        : base(0, 0)
    {
        m_Vendor = null;
        m_Mobile = null;
        m_BVendor = null;
        m_Opls = null;
        m_List = null;
    }
    public ClassicVendorGump(IRewardVendor vendor, Mobile m) : this()
    {
        m_Vendor = vendor;
        m_Mobile = m;
        m_BVendor = Parent(vendor);
        m_Opls = new List<ObjectPropertyList>();
        m_List = new ArrayList();
    }
    private BaseVendor Parent(IRewardVendor vendor)
    {
        BaseVendor validVendor = null;

        if (vendor != null) //only available on mobiles inherited from BaseVendor
            validVendor = vendor as BaseVendor;

        return validVendor;
    }
    void IRewardVendorGump.Send(Mobile m)
    {
        if ( !m_Vendor.Payment.PaymentType.Equals(typeof(Gold)) ) //need custom payment display
            m.SendGump(this);    

        if (m_BVendor != null)
        {

            if (m_List.Count > 0)
            {
                m_List.Sort(new BuyItemStateComparer());

                m_BVendor.SendPacksTo(m);

                if (m.NetState == null)
                    return;

                if (m.NetState.IsPost6017)
                    m.Send(new VendorBuyContent6017(m_List));
                else
                    m.Send(new VendorBuyContent(m_List));
                m.Send(new VendorBuyList(m_BVendor, m_List));
                m.Send(new DisplayBuyList(m_BVendor));

                m.Send(new MobileStatusExtended(m));//make sure their gold amount is sent

                if (m_Opls != null)
                {
                    for (int i = 0; i < m_Opls.Count; ++i)
                    {
                        m.Send(m_Opls[i]);
                    }
                }

                m_BVendor.SayTo(m, 500186); // Greetings.  Have a look around.
            }
        }               
    }   
    void IRewardVendorGump.AddEntry(Reward r)
    {
        m_List.Add(new BuyItemState(r.Title, m_BVendor.BuyPack.Serial, r.Serial, r.Cost, (r.Restock == null ? 20 : r.Restock.Count), r.RewardInfo.ItemID, r.RewardInfo.Hue));

        m_Opls.Add(r.Display);      
    }
    void IRewardVendorGump.CreateBackground()
    {
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);
        AddImage(36, 105, 2162);
        AddItem(111, 217, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);
        AddLabel(110, 172, 2122, @"Pay By:  " + m_Vendor.Payment.PayName);
        AddLabel(110, 299, 2120, @"You have: " + m_Vendor.Payment.Value(m_Mobile));
        AddImage(71, 302, 57);
        AddImage(71, 174, 57);
    }
}
public class MobileRewardVendor : Banker, IRewardVendor 
{
    private Currency m_Currency;
    private RewardCollection m_Rewards;
    private Type m_Menu;
    private DisplayBox m_Box;

    private bool m_IsBanker;

    [CommandProperty(AccessLevel.GameMaster)]
    public bool IsBanker
    {
        get { return m_IsBanker; }
        set { m_IsBanker = value; }     
    }
    Currency IRewardVendor.Payment
    {
        get { return m_Currency; }
        set { m_Currency = value; }
    }
    RewardCollection IRewardVendor.Rewards
    {
        get { return m_Rewards; }
        set { m_Rewards = value; }
    }
    Type IRewardVendor.Menu
    {
        get { return m_Menu; }
        set { m_Menu = value;  }
    }
    DisplayBox IRewardVendor.Display
    {
        get { return m_Box; }
    }
    [Constructable]
    public MobileRewardVendor() : base()
    {
        m_IsBanker = true;

        //default is Gold
        m_Currency = new Currency();
        m_Rewards = new RewardCollection();
        m_Menu = typeof(ClassicVendorGump);
        m_Box = new DisplayBox();

        //add to world collection
        WorldRewardVendors.RegisterVendor(this);
        //must be brought to world for client to view
        this.AddToBackpack(m_Box);

        this.Title = "";
    }
    public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
    {
        if (from.Alive)
        {
            list.Add(new LoadGumpEntry(from, this));

            if ( m_IsBanker)
                list.Add(new OpenBankEntry(from, this));
        }
    }
    Mobile IRewardVendor.GetMobile()
    {
        return this;
    }
    Item IRewardVendor.GetItem()
    {
        return null;
    }
   
    bool IRewardVendor.IsRemoved()
    {
        return this.Deleted;
    }
    Container IRewardVendor.GetContainer()
    {
        return this.Backpack;
    }
    string IRewardVendor.GetName()
    {
        return this.Name;
    }
    Map IRewardVendor.GetMap()
    {
        return this.Map;
    }
    Point3D IRewardVendor.GetLocation()
    {
        return this.Location;
    }
    //begin bank override
    public override bool HandlesOnSpeech(Mobile from)
    {
        if (!m_IsBanker)
            return false;

        base.HandlesOnSpeech(from);

        return true;
    }
    public override void OnSpeech(SpeechEventArgs e)
    {
        if (m_IsBanker)
            base.OnSpeech(e);
    }    
    //end

    //Warning: Following methods will throw Exceptions
    void IRewardVendor.AddReward(Reward r)
    {
        m_Box.AddDisplay(r);
        m_Rewards.Add(r);
    }
    void IRewardVendor.RemoveReward(Reward r)
    {
        m_Rewards.Remove(r);
        m_Box.RemoveDisplay(r);
    }
    
    void IRewardVendor.CopyVendor(IRewardVendor vendor)
    {
        Item currBox = this.Backpack.FindItemByType(typeof(DisplayBox));
        currBox.Delete();

        m_Currency = vendor.Payment;
        m_Menu = vendor.Menu;

        m_Rewards = (RewardCollection)((vendor.Rewards as ICloneable).Clone());
        m_Box = new DisplayBox(m_Rewards);

        this.AddToBackpack(m_Box);
    }
    //End Warning
    public override void OnDelete()
    {
        WorldRewardVendors.RemoveVendor(this);
        base.OnDelete();
    }
    //response to ClassicVendorGump - (must be inside BaseVendor)
    public override bool OnBuyItems(Mobile buyer, ArrayList list)
    {
        int totalCost = 0;
      
        Dictionary<Reward, int> purchases = new Dictionary<Reward, int>();

        Container bank = buyer.BankBox;
        Container pack = buyer.Backpack;

        if (pack == null || bank == null)
            return false;

        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;

                Reward r = item as Reward;

                if (r == null || !r.InStock(amount))
                    continue;

                totalCost += (r.Cost * amount);

                purchases.Add(r, amount);
            }
        }

        if (purchases.Count == 0)
        {
            SayTo(buyer, 500190); // Thou hast bought nothing! 
            return false;
        }                    
            if (!m_Currency.Purchase(buyer, totalCost)) //cannot afford
            {
                SayTo(buyer, 500192);//Begging thy pardon, but thou casnt afford that.
                return false;
            }

            foreach (KeyValuePair<Reward, int> kvp in purchases)
            {
                kvp.Key.RegisterBuy(kvp.Value);

                for (int index = 0; index < kvp.Value; index++)
                {                    
                    Item i = kvp.Key.RewardCopy;

                    if (!buyer.PlaceInBackpack(i))
                    {
                        bank.DropItem(i);
                        buyer.SendMessage("You are overweight, the Reward was added to your bank");
                    }
                }

                buyer.SendMessage("You bought {0} {1}", kvp.Value, kvp.Key.Title);
            }

            buyer.PlaySound(0x32);

            return true;  
             
    }
    //respone to 'vendor buy'
    public override void VendorBuy(Mobile from)
    {       
        MenuUploader.Display((IRewardVendorGump)Activator.CreateInstance(m_Menu, new object[] { (IRewardVendor)this, from }), from, (IRewardVendor)this ); //create fresh instance
    }
    //end edit
    public override void OnDoubleClick(Mobile m)
    {
        if (InRange(m, 4) && InLOS(m))
            MenuUploader.Display(m_Menu, m, this, false);
    }
    public MobileRewardVendor( Serial serial ) : base( serial )
	{
	}
    
	public override void Serialize( GenericWriter writer )
    {
		base.Serialize( writer );   

		writer.Write( (int) 1 ); // version

        writer.Write((bool)m_IsBanker);

        int count = m_Rewards.Count;
        writer.Write((int)count);

        if ( count > 0 )
        {
            for (int i = 0; i < count; i++)
            {
                writer.WriteItem((Reward)m_Rewards[i]);
            }
        }
        
        writer.WriteItem((Currency)m_Currency);
        writer.Write((string)m_Menu.Name);
        writer.WriteItem((DisplayBox)m_Box);       
    }
    
	public override void Deserialize( GenericReader reader )
    {
		base.Deserialize( reader );

        WorldRewardVendors.RegisterVendor(this);

		int version = reader.ReadInt();
        
        m_Rewards = new RewardCollection();

        m_IsBanker = true; //for conversion
               
        switch (version)
        {
            case 1:
                {
                    m_IsBanker = reader.ReadBool();

                    goto case 0;
                }
            case 0:
               {                   
                    int count = reader.ReadInt();
                    if (count > 0)
                    {
                        for (int i = 0; i < count; i++)
                        {
                            Reward r = (Reward)reader.ReadItem();
                            m_Rewards.Add(r);
                        }
                    }

                    m_Currency = (Currency)reader.ReadItem();

                    try { string name = reader.ReadString(); m_Menu = ScriptCompiler.FindTypeByName(name); }
                    catch { m_Menu = typeof(JewlRewardGump); }

                    m_Box = (DisplayBox)reader.ReadItem();

                    break;
                }
        }
	}
}
public class StoneRewardHolder : MetalBox
{
    private StoneRewardVendor m_S_Vendor;

    public StoneRewardHolder(StoneRewardVendor sv)
        : base()
    {
        m_S_Vendor = sv;
        this.Movable = false;
        this.Name = sv.Name + "'s Display Container [DO NOT DELETE]";
    }
    public override void OnItemLifted(Mobile m, Item item)
    {
        m.SendMessage("This item should not be moved away from the vendor.");
    }

    public void UpdateName()
    {
        if (m_S_Vendor == null)
            return;

        this.Name = m_S_Vendor.Name + "'s Display Container [DO NOT DELETE]";
    }
    public StoneRewardHolder(Serial serial)
        : base(serial)
	{
	}

	public override void Serialize( GenericWriter writer )
	{
		base.Serialize( writer );

		writer.Write( (int) 0 ); // version
	}

	public override void Deserialize( GenericReader reader )
	{
		base.Deserialize( reader );

		int version = reader.ReadInt();
    }
}
public class StoneRewardVendor : Item, IRewardVendor
{
    private Currency m_Currency;
    private RewardCollection m_Rewards;
    private Type m_Menu;
    private StoneRewardHolder m_Box_Holder;
    private DisplayBox m_Box;

    Currency IRewardVendor.Payment
    {
        get { return m_Currency; }
        set { m_Currency = value; }
    }
    RewardCollection IRewardVendor.Rewards
    {
        get { return m_Rewards; }
        set { m_Rewards = value; }
    }
    Type IRewardVendor.Menu
    {
        get { return m_Menu; }
        set { m_Menu = value; }
    }
    DisplayBox IRewardVendor.Display
    {
        get { return m_Box; }
    }

    [Constructable]
    public StoneRewardVendor()
        : base()
    {
        m_Currency = new Currency();
        m_Rewards = new RewardCollection();
        m_Menu = typeof(JewlRewardGump);
        m_Box = new DisplayBox();

        ItemID = 0xEDC;
        Name = "Stone Vendor";

        WorldRewardVendors.RegisterVendor(this);

        m_Box_Holder = new StoneRewardHolder(this);
        m_Box_Holder.DropItem(m_Box);      

        this.Movable = false;
    }
    public override void OnLocationChange( Point3D oldLocation )
    {
        base.OnLocationChange(oldLocation);

        if (m_Box_Holder != null)
        {
            m_Box_Holder.Location = this.Location;
            m_Box_Holder.Z = this.Z - 10;
        }
    }
    public override void OnMapChange()
    {
        base.OnMapChange();

        if ( m_Box_Holder != null )
            m_Box_Holder.Map = this.Map;
    }
    Mobile IRewardVendor.GetMobile()
    {
        return null;
    }
    Item IRewardVendor.GetItem()
    {
        return this;
    }

    bool IRewardVendor.IsRemoved()
    {
        return this.Deleted;
    }
    Container IRewardVendor.GetContainer()
    {
        return m_Box_Holder;
    }
    string IRewardVendor.GetName()
    {
        return this.Name;
    }
    Map IRewardVendor.GetMap()
    {
        return this.Map;
    }
    Point3D IRewardVendor.GetLocation()
    {
        return this.Location;
    }
    void IRewardVendor.AddReward(Reward r)
    {
        m_Box.AddDisplay(r);
        m_Rewards.Add(r);
    }
    void IRewardVendor.RemoveReward(Reward r)
    {
        m_Rewards.Remove(r);
        m_Box.RemoveDisplay(r);
    }

    void IRewardVendor.CopyVendor(IRewardVendor vendor)
    {
        Item currBox = m_Box_Holder.FindItemByType(typeof(DisplayBox));
        currBox.Delete();

        m_Currency = vendor.Payment;
        m_Menu = vendor.Menu;

        m_Rewards = (RewardCollection)((vendor.Rewards as ICloneable).Clone());
        m_Box = new DisplayBox(m_Rewards);

        m_Box_Holder.DropItem(m_Box);
    }
    //End Warning
    public override void OnDelete()
    {
        if ( m_Box_Holder != null)
            m_Box_Holder.Delete();

        WorldRewardVendors.RemoveVendor(this);
        base.OnDelete();
    }
    
    public override void OnDoubleClick(Mobile m)
    {
        if (m_Box_Holder != null)
        {
            m_Box_Holder.MoveToWorld(this.Location, this.Map);
            m_Box_Holder.Z = this.Z - 10;
            m_Box_Holder.UpdateName();
        }
        MenuUploader.Display(m_Menu, m, this, false);
    }
     
    public StoneRewardVendor(Serial serial)
        : base(serial)
    {
    }

    public override void Serialize(GenericWriter writer)
    {
        base.Serialize(writer);

        writer.Write((int)0); //Version 0

        int count = m_Rewards.Count;
        writer.Write((int)count);

        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                writer.WriteItem((Reward)m_Rewards[i]);
            }
        }

        writer.WriteItem((Currency)m_Currency);
        writer.Write((string)m_Menu.Name);
        writer.WriteItem((DisplayBox)m_Box);
        writer.WriteItem((StoneRewardHolder)m_Box_Holder);
    }

    public override void Deserialize(GenericReader reader)
    {
        base.Deserialize(reader);

        WorldRewardVendors.RegisterVendor(this);

        int version = reader.ReadInt();

        m_Rewards = new RewardCollection();

        int count = reader.ReadInt();
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                Reward r = (Reward)reader.ReadItem();
                m_Rewards.Add(r);
            }
        }

        m_Currency = (Currency)reader.ReadItem();

        try { string name = reader.ReadString(); m_Menu = ScriptCompiler.FindTypeByName(name); }
        catch { m_Menu = typeof(JewlRewardGump); }

        m_Box = (DisplayBox)reader.ReadItem();
        m_Box_Holder = (StoneRewardHolder)reader.ReadItem();
    }
}
public interface IRewardVendor
{
    //used to determine how player pays
    Currency Payment { get; set; }
    //to keep added items
    RewardCollection Rewards { get; set; }
    //to change gump
    Type Menu { get; set; }
    //to show player items
    DisplayBox Display { get; }
    //to return what holds 'DisplayBox' object
    Container GetContainer();
    //to return removal status
    bool IsRemoved();
   
    //serial /deserial
    Mobile GetMobile();
    Item GetItem();

    //used for 'world collection'
    string GetName();
    Point3D GetLocation();
    Map GetMap();

    //to manage RewardCollection
    void AddReward(Reward r);
    void RemoveReward(Reward r);
    
    //to create vendor clones
    void CopyVendor(IRewardVendor vendor);
}
public interface IRewardVendorGump
{
    void Send(Mobile m);
    void AddEntry(Reward r);
    void CreateBackground();
    
    //add entry || background || 
}


public class PaymentTarget : Target
{
    private string m_Name;
    private IRewardVendor m_Vendor;
    private bool m_Is_XML;

    public PaymentTarget()
        : base(2, false, TargetFlags.None)
    {
    }
    //by item
    public PaymentTarget(IRewardVendor vendor) : this ()
	{
        m_Vendor = vendor;
        m_Name = null;
        m_Is_XML = false;
    }
    //by item property
    public PaymentTarget(IRewardVendor vendor, string name, bool isXML) : this()
    {
        m_Vendor = vendor;
        m_Name = name;
        m_Is_XML = isXML;
    }
    protected override void OnTarget(Mobile m, object targeted)
    {
        if (m_Is_XML && !String.IsNullOrEmpty(m_Name))
        {
            Type attachType = ScriptCompiler.FindTypeByName(m_Name);

            if (attachType != null && attachType.BaseType.Equals(typeof(XmlAttachment)))
            {
                List<PropertyInfo> integerProps = new List<PropertyInfo>();

                foreach (PropertyInfo pi in attachType.GetProperties())
                {
                    if ((pi.CanRead && pi.CanWrite) && pi.PropertyType.Equals(typeof(System.Int32)))
                        integerProps.Add(pi);
                }

                if (integerProps.Count == 0)
                    m.SendMessage("{0} does not contain any integer based properties.", attachType.Name);
                else
                    m.SendGump(new XMLIntPropertyGump(attachType, targeted, m_Vendor, integerProps));
            }
            else
                m.SendMessage("The XML Attachment, {0}, could not be found, the search IS case sensitive", m_Name);
        }
        else if ( targeted is Item )
        {           
            //consume by item
            if (m_Name == null)
            {
                m_Vendor.Payment = new Currency((Item)targeted);
                m.SendMessage("{0} will now use {1} for payment.", m_Vendor.GetName(), targeted.GetType().Name);
            }
            //consume by item property
            else
            {
                SetByProperty(m, targeted);
            }
        }
        else if (targeted is PlayerMobile)
        {
            if (m_Name == null)
            {
                m.SendMessage("You can only use Property option for player.");

            }
            else
            {
                SetByProperty(m, null);
            }
        }
        else
        {
            m.SendMessage("Invalid, target must be Item or Player.");
        }

        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);
    }
    private void SetByProperty(Mobile m, object o)
    {
        string msg = "Please make sure you entered the name correctly, "
                        + "it IS case sensitive.";
        try
        {
            if (o != null)//Item
            {
                PropertyInfo pi = o.GetType().GetProperty(m_Name);

                if (pi != null && pi.PropertyType.Equals(typeof(Int32)))
                {
                    m_Vendor.Payment = new Currency((Item)o, pi);
                    m.SendMessage(m_Vendor.GetName() + "will now use {1}.{2} for payment.", m_Vendor.GetName(), o.GetType().Name, pi.Name);
                }
                else
                    m.SendMessage(msg);
            }
            else//Mobile
            {
                PropertyInfo pi = m.GetType().GetProperty(m_Name);

                if (pi != null && pi.PropertyType.Equals(typeof(Int32)))
                {
                    m_Vendor.Payment = new Currency(m, pi);
                    m.SendMessage("{0} will now use {1}.{2} for payment.", m_Vendor.GetName(), m.GetType().Name, pi.Name);
                }
                else
                    m.SendMessage(msg);
            }
        }
        catch { m.SendMessage(msg); }
    }
}
public class AddItemTarget : Target
{
    IRewardVendor m_Vendor;

    public AddItemTarget() : base( 2, false, TargetFlags.None )
	{
	}
    public AddItemTarget(IRewardVendor vendor)
        : this()
    {
        m_Vendor = vendor;
    }
    protected override void OnTarget(Mobile from, object targeted)
    {
        Item i = targeted as Item;

        if (m_Vendor == null || i == null)
            return;

        Item clone = ItemClone.Clone(i);

        if (clone != null) //copy did not fail
            from.SendGump(new EditItemGump(m_Vendor, new Reward(clone), null, false, true));
        else
            from.SendMessage("This item cannot be copied.");

    }
}

public class ItemClone
{
    public static Item Clone(Item item) 
    {
        try
        {
            if ( item is Container )
                return CloneBag(((Container)item).FindItemsByType(typeof(Item), false), (Container)item, (Container)Activator.CreateInstance(item.GetType(), null));
            else
                return Clone(item.GetType(), item, (Item)Activator.CreateInstance(item.GetType(), null));
        }
        catch {}
       
        return null;
    }
    public static Container CloneBag(Item[] contents, Container old, Container copy)
    {        
        //emtpy new container
        foreach (Item i in copy.FindItemsByType(typeof(Item)))
        {
            i.Delete();
        }

        //'old' contents into 'new'
        foreach (Item i in contents)
        {
            copy.DropItem(Clone(i));           
        }

        copy.Name = old.Name; //requires manual set

        return copy;
    }
    public static Item Clone(Type type, Item old, Item copy)
    {
        foreach (PropertyInfo pi in type.GetProperties())
        {
            if (pi.CanRead && pi.CanWrite && ValidProperty(pi.Name)) 
            {
                try
                {
                    if (pi.PropertyType.IsClass)
                        CloneInnerClass(pi.PropertyType, pi.GetValue(old, null), pi.GetValue(copy, null)); //found object property
                    else
                        pi.SetValue(copy, pi.GetValue(old, null), null); //found value property
                }
                catch {}
            }
        }

        copy.Name = old.Name; //requires manual set

        return copy;
    }
    public static void CloneInnerClass(Type type, object old, object copy)
    {
        if (old == null) //not defined
            return;
        
        foreach ( PropertyInfo pi in type.GetProperties() )
        {
            if ( pi.CanRead && pi.CanWrite ) 
            {
                try
                {
                    pi.SetValue(copy, pi.GetValue(old, null), null);
                }
                catch {}
            }
        }
    }
    public static bool ValidProperty(string str) 
    {
        return !( str.Equals("Parent") || str.Equals("TotalWeight") || str.Equals("TotalItems") || str.Equals("TotalGold") );
    }
   
}

}

Yeah that's the one, the class you want is StoneRewardVendor :).
I'll update the file in the first post.

EDIT: Reupped QuestRewardStone.cs to use the vanilla Customizable Vendor names.
 

Nockar

Sorceror
HAHAHAHH
I thought for sure that last change you made was going to fix it.

Code:
[COLOR="Red"]Errors:
 + Customs/Xml Spawner/XmlQuestGuilds/QuestGuildRewardStone.cs:
    CS0234: Line 13: The type or namespace name 'CustomizableVendor' does not ex
ist in the namespace 'Server.Engines' (are you missing an assembly reference?)
    CS0246: Line 17: The type or namespace name 'StoneRewardVendor' could not be
 found (are you missing a using directive or an assembly reference?)[/COLOR]

QuestGuildRewardStone.cs
Code:
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.Engines.BulkOrders;
using Server.Regions;
using Server.Factions;
using Server.Engines.XmlSpawner2;
using Server.Engines.CustomizableVendor;

namespace Server.Engines.Quests
{
    public class QuestGuildRewardStone : StoneRewardVendor
    {
        private string m_GuildType;
        private int m_Rank;

        [CommandProperty(AccessLevel.GameMaster)]
        public string GuildType { get { return m_GuildType; } set { m_GuildType = value; InvalidateProperties(); } }

        [CommandProperty(AccessLevel.GameMaster)]
        public int Rank { get { return m_Rank; } set { m_Rank = value; InvalidateProperties(); } }

        [Constructable]
        public QuestGuildRewardStone()
            : base()
        {
        }

        public QuestGuildRewardStone( Serial serial ) : base( serial )
		{
		}

        public override void OnDoubleClick(Mobile m)
        {
            ArrayList aList = XmlAttach.FindAttachments(m, typeof(XmlQuestGuild));
            List<XmlQuestGuild> list = new List<XmlQuestGuild>();

            if (aList.Count > 0)
            {
                foreach (XmlQuestGuild questGuild in aList)
                    list.Add(questGuild);
            }

            if (list.Count > 0)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    if (m_GuildType == list[i].GuildType)
                    {
                        if (list[i].Rank >= m_Rank)
                            base.OnDoubleClick(m);
                        else
                            m.SendMessage("You require to be at least a {0} in the {1} Guild to purhcase any of these rewards.", XmlQuestGuild.GetRepTitle(m_Rank), m_GuildType);
                    }
                }
            }
            else
                m.SendMessage("You require to be at least a {0} in the {1} Guild to purhcase any of these rewards.", XmlQuestGuild.GetRepTitle(m_Rank), m_GuildType);
        }

        public override void GetProperties(ObjectPropertyList list)
        {
            base.GetProperties(list);

            list.Add(1070722, "Requires: " + XmlQuestGuild.GetRepTitle(m_Rank) + " rank with " + m_GuildType + " Guild.");
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);

            writer.Write((int)0);
            // version 0
            writer.Write((string)m_GuildType);
            writer.Write((int)m_Rank);
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            int version = reader.ReadInt();
            // version 0
            m_GuildType = reader.ReadString();
            m_Rank = reader.ReadInt();
        }
    }
}

[RC2] Rewards System - XML Attachments .cs
Code:
//Author: krazeykow
//Version: 1.0.1

using System;
using Server;
using Server.Items;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Server.Gumps;
using Server.Network;
using Server.Targeting;
using Server.Mobiles;
using Server.ContextMenus;
using Server.Engines.XmlSpawner2;

namespace System.CustomizableVendor
{

public class Currency : Item
{

    private Payment m_Payment;
    private PropertyInfo m_PropertyInfo;
    private Type m_Payment_Type;
    private Type m_XML_Type;
    private int m_ItemID;
    private string m_Name;
    private int m_Hue;

    public Type XMLType { get { return m_XML_Type; } }
    public Type PaymentType { get { return m_Payment_Type; } }
    public string PayName { get { return m_Name; } }
    public int PayID { get { return m_ItemID; } }
    public int CurrHue { get { return m_Hue; } } 

    public enum Payment
    {
        ByGold,
        ByItem,
        ByProperty,
        ByXMLAttachment
    }
    //default
    public Currency()
    {
        m_Payment = Payment.ByGold;
        m_Payment_Type = typeof(Gold);
        m_PropertyInfo = null;
        m_ItemID = 3823;
        m_Name = "Gold";
    }
    public Currency(object bindedTo, Type attachType, PropertyInfo attachProp)
    {
        m_XML_Type = attachType;
        m_Payment = Payment.ByXMLAttachment;
        m_Payment_Type = bindedTo.GetType();
        m_PropertyInfo = attachProp;

        if (bindedTo is Mobile) {
            m_ItemID = 8461;
            m_Name = "Player " + attachProp.Name;
        }
        else if (bindedTo is Item) {
            m_ItemID = ((Item)bindedTo).ItemID;
            m_Name = GetName((Item)bindedTo) + "'s " + attachProp.Name;
            m_Hue = ((Item)bindedTo).Hue;
        }

    }
    //consume by item
    public Currency(Item i)
    {
        if ( i.GetType().Equals(typeof(Gold)) )
            m_Payment = Payment.ByGold;
        else
            m_Payment = Payment.ByItem;

        m_Payment_Type = i.GetType();
        m_PropertyInfo = null;
        m_ItemID = CoinID(i.ItemID);
        m_Name = GetName(i);
        m_Hue = i.Hue;
    }
    //consume property on player
    public Currency(Mobile m, PropertyInfo pi)
    {
        m_Payment = Payment.ByProperty;
        m_Payment_Type = m.GetType();
        m_PropertyInfo = pi;
        m_ItemID = 8461;
        m_Name = "Player " + pi.Name;
    }
    //consume by item's number based property
    public Currency(Item i, PropertyInfo pi)
    {
        m_Payment = Payment.ByProperty;
        m_Payment_Type = i.GetType();
        m_PropertyInfo = pi;
        m_ItemID = CoinID(i.ItemID);
        m_Name = GetName(i) + "'s " + pi.Name;
        m_Hue = i.Hue;
    }
    public void Modify(Type t, string append)
    {
        if ( (t.Equals(typeof(PlayerMobile)) || append == null ))
            return;

        Item i;
        
        i = (Item)Activator.CreateInstance(t, null);
        m_Name = GetName(i) + append;
        m_Hue = i.Hue;
        m_ItemID = CoinID(m_ItemID);
        
    }
    public int CoinID(int itemID)
    {
        if (itemID == 3821)
            return 3823;
        else if (itemID == 3824)
            return 3826;
        else
            return itemID;
    }
    public void VOneUpdate()
    {
        switch (m_Payment)
        {
            case Payment.ByGold:
            case Payment.ByItem:
                {
                    Modify(m_Payment_Type, "");
                    break;
                }
            case Payment.ByProperty:
                {
                    if (!(m_Payment_Type.Equals(typeof(PlayerMobile))))
                        Modify(m_Payment_Type, "'s " + m_PropertyInfo.Name);
                    break;
                }
        }

     }

    public string GetName(Item i)
    {
        if (String.IsNullOrEmpty(i.Name))
            return i.GetType().Name;
        else
            return i.Name;
    }
    public bool Purchase(Mobile m, int cost)
    {
        int remain = Value(m) - cost;

        if (remain < 0 || m.Backpack == null)
            return false;
        
        Charge(m, cost, remain);

        return true;
    }
    public void Charge(Container pack, Container bank, Type t, int cost)
    {
        if ( pack == null || bank == null )
            return;

        cost = cost - pack.ConsumeUpTo(t, cost);

        if ( cost > 0 )
            bank.ConsumeUpTo(t, cost);
    }
   
    public void Charge(Mobile m, Type t, PropertyInfo pi, int cost, int remain)
    {
        try
        {
            if (t.BaseType.Equals(typeof(Mobile)) || t.Equals(typeof(PlayerMobile)))
            {
                SetPropertyValue(m, remain);
            }
            else
            {
                if (m.Backpack == null || m.FindBankNoCreate() == null)
                    return;

                Item[] packItems = m.Backpack.FindItemsByType(t);
                Item[] bankItems = m.FindBankNoCreate().FindItemsByType(t);

                Item[] items = new Item[packItems.Length + bankItems.Length];
                packItems.CopyTo(items, 0);
                bankItems.CopyTo(items, packItems.Length);

                //none found in backpack
                if (items == null)
                    return;

                int i = 0, value = 0, dif = 0;

                //account for multiple objects
                while (cost > 0 && i < items.Length)
                {
                    value = GetPropertyValue(items[i]);

                    dif = value - cost;

                    //one item has enough
                    if (dif >= 0)
                    {
                        SetPropertyValue(items[i], dif);
                    }
                    //take what amount item has (the amount has already been confirmed by Value(m))
                    else // assert (dif < 0)
                    {
                        cost -= GetPropertyValue(items[i]);
                        SetPropertyValue(items[i], 0);
                    }
                    i++;
                }
            }
        }
        catch { }
    }
    public void Charge(Mobile m, Container pack, Container bank, int cost)
    {
        if ( pack == null || bank == null )
            return;

        cost = cost - pack.ConsumeUpTo(typeof(Gold), cost);

        if (cost > 0)
            Banker.Withdraw(m, cost);
    }
    public void Charge(Mobile m, int cost, int remain)
    {
        switch (m_Payment)
        {
            case Payment.ByGold:
                Charge(m, m.Backpack, m.FindBankNoCreate(), cost);
                break;
            case Payment.ByItem:
                Charge(m.Backpack, m.FindBankNoCreate(), m_Payment_Type, cost);
                break;
            case Payment.ByXMLAttachment:
            case Payment.ByProperty:
                Charge(m, m_Payment_Type, m_PropertyInfo, cost, remain);
                break;
        }
    }
    public int Value(Mobile m)
    {
        switch (m_Payment)
        {
            case Payment.ByGold:
                return ProcessByGold(m);
            case Payment.ByItem:
                return ProcessByItem(m, m_Payment_Type);
            case Payment.ByXMLAttachment:
            case Payment.ByProperty:
                return ProcessByProperty(m, m_Payment_Type, m_PropertyInfo);                       
        }
        return 0;
    }

    public int ProcessByGold(Mobile m)
    {
        if (m.Backpack == null)
            return 0;

        int totalGold = 0;

        totalGold += m.Backpack.GetAmount( typeof( Gold ) );
        totalGold += Banker.GetBalance( m );

        return totalGold;
    }
    public int ProcessByItem(Mobile m, Type t)
    {
        Container pack = m.Backpack;
        Container bank = m.FindBankNoCreate();

        if (pack == null || bank == null)
            return 0;

        int amount = (pack.GetAmount(t) + bank.GetAmount(t));

        return amount;
    }
    public int ProcessByProperty(Container pack, Container bank, Type t, PropertyInfo pi)
    {
        if (pack == null || bank == null)
            return 0;


        Item[] packItems = pack.FindItemsByType(t);
        Item[] bankItems = bank.FindItemsByType(t);

        Item[] items = new Item[packItems.Length + bankItems.Length];
        packItems.CopyTo(items, 0);
        bankItems.CopyTo(items, packItems.Length);
        
        int sum = 0;

        foreach (object o in items)
        {
            sum += GetPropertyValue(o);
        }

        return sum;
    }
    public int GetPropertyValue(object o)
    {
        int val = 0;

        if (m_Payment == Payment.ByXMLAttachment)
        {
            val = GetXMLValue(o);
        }
        else
        {
            val = (int)m_PropertyInfo.GetValue(o, null);
        }

        return val;
    }
    public void SetPropertyValue(object o, int val)
    {
        if (m_Payment == Payment.ByXMLAttachment)
        {
            SetXMLValue(o, val);
        }
        else
        {
            m_PropertyInfo.SetValue(o, val, null);
        }       
    }
    public int GetXMLValue(object o)
    {      
        int val = 0;

        if (m_XML_Type == null)
            return val;

        XmlAttachment attach = XmlAttach.FindAttachment(o, m_XML_Type);

        if (attach != null) {           
            val = (int)m_PropertyInfo.GetValue(attach, null);           
        }
        return val;
    }
    public void SetXMLValue(object o, int val)
    {
        if (m_XML_Type == null)
            return;

        XmlAttachment attach = XmlAttach.FindAttachment(o, m_XML_Type);

        if (attach != null) { 
            m_PropertyInfo.SetValue(attach, val, null);           
        }
    }
    //Master
    public int ProcessByProperty(Mobile m, Type t, PropertyInfo pi)
    {
        try
        { 

            if (t.BaseType.Equals(typeof(Mobile)) || t.Equals(typeof(Mobile)) )
            {
                return GetPropertyValue(m);
            }
            else
            {
                return ProcessByProperty(m.Backpack, m.FindBankNoCreate(), t, pi);
            }
        }
        catch {}
        
        return 0;
        
    }
   
    public Currency( Serial serial ) : base( serial )
	{
	}
	public override void Serialize( GenericWriter writer )
	{
		base.Serialize( writer );
		writer.Write( (int) 2 );

        //version 2
        writer.Write((string)(m_XML_Type == null ? "" : m_XML_Type.Name));

        //version 1
        writer.Write((int)m_Hue);
        
        //explicit casts are given for clarification        
        writer.Write((int)m_Payment);
        writer.Write((string)m_Payment_Type.Name);
        writer.Write((string)(m_PropertyInfo == null ? "" : m_PropertyInfo.Name));
        writer.Write((int)m_ItemID);
        writer.Write((string)m_Name);
        
	}
	
	public override void Deserialize(GenericReader reader)
	{
		base.Deserialize( reader );
		int version = reader.ReadInt();


        switch (version)
        {
            case 2:
                {
                    try
                    {
                        string name = reader.ReadString();
                        if (name.Equals(""))
                        {
                            m_XML_Type = null;
                        }
                        else
                        {
                            m_XML_Type = ScriptCompiler.FindTypeByName(name);
                        }
                    }
                    catch { }

                    goto case 1;
                }
            case 1:
                {
                    m_Hue = reader.ReadInt();
                    goto case 0;
                }
            case 0:
                {
                    m_Payment = (Payment)reader.ReadInt();

                    try { string name = reader.ReadString(); m_Payment_Type = ScriptCompiler.FindTypeByName(name); }
                    catch { }

                    try
                    {
                        string propName = reader.ReadString();
                        if (propName.Equals("")) //never set
                        {
                            m_PropertyInfo = null;
                        }
                        else if (m_Payment == Payment.ByXMLAttachment && m_XML_Type != null) //XML requires find property by the XML Class type (m_XML_Type)
                        {
                            m_PropertyInfo = m_XML_Type.GetProperty(propName);
                        }
                        else 
                        { 
                            m_PropertyInfo = m_Payment_Type.GetProperty(propName); 
                        }
                    }
                    catch { }

                    m_ItemID = reader.ReadInt();
                    m_Name = reader.ReadString();

                    break;
                }
        }
        if (version == 0)
        {
            try { VOneUpdate(); }
            catch {  }
        }
     }
}

public class Reward : Item, ICloneable
{      
    private Item m_Reward;
    private int m_Cost;
    private string m_Title;
    private string m_Description;

    private ObjectPropertyList m_Display;

    private RestockInfo m_RestockInfo;
    private int m_BuyCount;

    public int BuyCount { get { return m_BuyCount; } set { m_BuyCount = value; } }
    public RestockInfo Restock { get { return m_RestockInfo; } set { m_RestockInfo = value; } }

    public ObjectPropertyList Display
    {
        get
        {
            if (m_Display == null)
            {
                m_Display = new ObjectPropertyList(this);

                m_Reward.GetProperties(m_Display);
                m_Reward.AppendChildProperties(m_Display);

                m_Display.Terminate();
                m_Display.SetStatic();
            }

            return m_Display;
        }
    }

    public void Void_RestockInfo()
    {
        m_RestockInfo = null;
    }
    //returns ((-1) -> no restockInfo) or current count
    public int Try_Restock()
    {
        if (m_RestockInfo == null)
            return -1;        

        TimeSpan dif = DateTime.Now - m_RestockInfo.LastRestock;
        int cycles = 0;

        if (dif > (m_RestockInfo.RestockRate) && m_RestockInfo.RestockRate.TotalMinutes > 0)
        {
            cycles = (int)(dif.TotalMinutes / m_RestockInfo.RestockRate.TotalMinutes);

            for (int i = 0; i < cycles; ++i)
            {
                if (m_RestockInfo.Restock())
                    continue;
            }
        }

        return m_RestockInfo.Count;
    }
    public bool InStock(int amount)
    {
        return (m_RestockInfo == null ? true : (m_RestockInfo.Count - amount >= 0));       
    }
    public void RegisterBuy(int amount)
    {      
        if (m_RestockInfo != null && InStock(amount))
            m_RestockInfo.Count -= amount;

        this.m_BuyCount += amount;
    }

    //for retrieving information only
    public Item RewardInfo
    {
        get { return m_Reward; }
    }
    //use only when creating Reward for player
    public Item RewardCopy
    {
        get { return GetReward(); }
    }
    public int Cost
    {
        get { return m_Cost; }
        set { m_Cost = value; }
    }
    public string Title
    {
        get { return m_Title; }
        set { m_Title = value; }
    }
    public string Description
    {
        get { return m_Description; }
        set { m_Description = value; }
    }
    object ICloneable.Clone()
    {
        return new Reward(this);
    }
    public Reward()
    {
        m_Reward = new Item();
        m_Cost = 0;
        m_Title = "";
        m_Description = "";
        m_RestockInfo = null;
    }
    public Reward(Reward r)
    {
        m_Reward = r.RewardCopy;
        m_Cost = r.Cost;
        m_Title = r.Title;
        m_Description = r.Description;
        m_RestockInfo = null;
    }
    public Reward(Item i)
    {
        m_Reward = i;
        m_Cost = 0;
        m_Title = (i.Name == null ? i.GetType().Name : i.Name);
        m_Description = "None.";
        m_RestockInfo = null;

    }
    public Reward(Item i, int cost)
    {
        m_Reward = i;
        m_Cost = cost;
        m_Title = (i.Name == null ? i.GetType().Name : i.Name);
        m_Description = "None.";
        m_RestockInfo = null;
    }
    public Reward(Item i, int cost, string title)
    {
        m_Reward = i;
        m_Cost = cost;
        m_Title = title;
        m_Description = "None.";
        m_RestockInfo = null;
    }
    public Reward(Item i, int cost, string title, string desc)
    {
        m_Reward = i;
        m_Cost = cost;
        m_Title = title;
        m_Description = desc;
        m_RestockInfo = null;
    }

    public class RestockInfo 
    {
        private TimeSpan m_RestockRate;
        private DateTime m_LastRestock;

        private int m_RestockAmnt;
        private int m_Count;
        private int? m_Maximum;
        
        public TimeSpan RestockRate { get { return m_RestockRate; } }
        public DateTime LastRestock { get { return m_LastRestock; } }

        public int RestockAmnt { get { return m_RestockAmnt; } }
        public int Count { get { return m_Count; } set { m_Count = value; } }
        public int Maximum { get { return m_Maximum.GetValueOrDefault(-1); } }

        public int Hours { get { return (int)m_RestockRate.Hours; } }
        public int Minutes { get { return (int)m_RestockRate.Minutes; } }

        public RestockInfo()
        {
            m_RestockRate = new TimeSpan();
            m_RestockAmnt = 0;
            m_Count = 0;
            m_Maximum = null;
            m_LastRestock = DateTime.Now;

        }
        public RestockInfo(int count) : this()
        {
            m_Count = count;
        }
        public RestockInfo(int hour, int minute, int count, int RestockNum)
        {
            m_RestockRate = new TimeSpan(hour, minute, 0);
            m_Count = count;
            m_RestockAmnt = RestockNum;
            m_Maximum = null;
            m_LastRestock = DateTime.Now;

        }
        public RestockInfo(int hour, int minute, int count, int RestockNum, int maxNum) : this (hour, minute, count, RestockNum)
        {
            m_Maximum = maxNum;
        }
        public bool Equals(RestockInfo info)
        {
            return (this.m_RestockRate.Equals(info.RestockRate) && (this.m_RestockAmnt == info.RestockAmnt) && (this.m_Count == info.Count)
                && (this.m_Maximum == info.Maximum));
        }
        public bool Restock()
        {
            m_LastRestock = DateTime.Now;

            if (m_Maximum != null) //Restock to a limit
            {
                if ((m_Count + m_RestockAmnt) > m_Maximum)
                {
                    m_Count = m_Maximum.Value;
                    return false;
                }

                m_Count += m_RestockAmnt;
                return true;
            }
            
            m_Count += m_RestockAmnt;            
            return true;
        }

        public void Serialize( GenericWriter writer )
        {
            writer.Write((TimeSpan)m_RestockRate);           
            writer.Write((int)m_RestockAmnt);
            writer.Write((int)m_Count);
            writer.Write((int)m_Maximum.GetValueOrDefault(-1));
        }

        public RestockInfo( GenericReader reader )
        {
            m_RestockRate = reader.ReadTimeSpan();
            m_LastRestock = DateTime.Now;
            m_RestockAmnt = reader.ReadInt();
            m_Count = reader.ReadInt();
            
            int? max = reader.ReadInt();
         
            m_Maximum = ((max < 0) ? null : max);
        }
    }

    public void Edit(int cost, string title, string desc)
    {
        if (cost < 0 || title == null || desc == null)
            return;

        m_Cost = cost;
        m_Title = title;
        m_Description = desc;
    }
    public Item GetReward()
    {
        return ItemClone.Clone(m_Reward);
    }

    public Reward( Serial serial ) : base( serial )
	{
	}
	public override void Serialize( GenericWriter writer )
	{
		base.Serialize( writer );

		writer.Write( (int) 1 );

        writer.Write((int)m_BuyCount);

        if (m_RestockInfo == null)
        {
            writer.Write(false);
        }
        else
        {
            writer.Write(true);
            m_RestockInfo.Serialize(writer);
        }

        writer.WriteItem((Item)m_Reward);
        writer.Write((int)m_Cost);
        writer.Write((string)m_Title);
        writer.Write((string)m_Description);          
    }
	
	public override void Deserialize(GenericReader reader)
	{
		base.Deserialize( reader );
		int version = reader.ReadInt();

        switch (version)
        {
            case 1:
                {
                    m_BuyCount = reader.ReadInt();

                    if (reader.ReadBool())
                        m_RestockInfo = new RestockInfo(reader);

                    goto case 0;
                }
            case 0:
                {
                    m_Reward = (Item)reader.ReadItem();
                    m_Cost = reader.ReadInt();
                    m_Title = reader.ReadString();
                    m_Description = reader.ReadString();                  
                    
                    break;
                }
        }
    
	}

}
public class RewardCollection : List<Reward>, ICloneable
{
    

    object ICloneable.Clone()
    {
        RewardCollection clone = new RewardCollection();
        
        foreach (Reward r in this)
        {
            clone.Add(((Reward)(r as ICloneable).Clone()));
        }
        return clone;
    }
}

public static class WorldRewardVendors
{
    private static List<IRewardVendor> m_Vendors = new List<IRewardVendor>();

    public static List<IRewardVendor> Vendors { get { return m_Vendors; } }
   
    public static void RegisterVendor(IRewardVendor vendor)
    {
        m_Vendors.Add(vendor);
    }
    public static void RemoveVendor(IRewardVendor vendor)
    {
        m_Vendors.Remove(vendor);
    }
}

public class EditItemGump : Gump
{
    private IRewardVendor m_Vendor;
    private Reward m_Reward;

    private Reward.RestockInfo m_Restock;
    private bool m_RestockOpen;

    private bool m_IsAdd;

    private Storage m_Entries;

    public EditItemGump(IRewardVendor vendor, Reward r, Storage entries, bool openRestockInfo, bool addingItem) : base(0, 0)
    {
        m_Vendor = vendor;
        m_Reward = r;

        m_Restock = r.Restock;
        m_RestockOpen = openRestockInfo;
        m_IsAdd = addingItem;

        m_Entries = entries; 

        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        AddImageTiled(227, 46, 329, 518, 2702);
        AddImageTiled(252, 291, 280, 217, 5104);
        AddLabel(253, 266, 2124, @"Description:");
        AddImageTiled(334, 147, 192, 23, 5104);
        AddLabel(258, 150, 2124, @"Cost:");
        AddImageTiled(336, 107, 192, 23, 5104);
        AddLabel(258, 108, 2124, @"Name:");
        AddImage(354, 199, 2328);
        AddItem(373, 208, r.RewardInfo.ItemID, r.RewardInfo.Hue);
        AddImageTiled(330, 54, 138, 16, 5214);
        AddLabel(373, 51, 1324, @"Edit Item");
        AddButton(465, 222, 5601, 5605, 2, GumpButtonType.Reply, 0); //restock
        AddLabel(447, 198, 2120, @"Restock ");
        AddLabel(447, 246, 2120, @"(Optional)");
        AddButton(324, 523, 4023, 4024, 1, GumpButtonType.Reply, 0);//ok
        AddButton(421, 523, 4017, 4018, 0, GumpButtonType.Reply, 0); //cancel

        if (entries == null)
            InitialText();
        else
            PacketText();

        if (openRestockInfo || r.Restock != null)
        {
            AddRestockMenu();
            m_RestockOpen = true;
        }
    }
    public void InitialText()
    {
        AddTextEntry(252, 292, 277, 215, 1879, 0, m_Reward.Description);
        AddTextEntry(334, 148, 188, 20, 1879, 1, m_Reward.Cost.ToString());
        AddTextEntry(336, 108, 188, 20, 1879, 2, m_Reward.Title);    
    }
    public void PacketText()
    {
        AddTextEntry(252, 292, 277, 215, 1879, 0, m_Entries[0].ToString()); //desc
        AddTextEntry(334, 148, 188, 20, 1879, 1, m_Entries[1].ToString());  //cost 
        AddTextEntry(336, 108, 188, 20, 1879, 2, m_Entries[2].ToString());  //title
    }
    public void AddRestockMenu()
    {

        AddPage(1);

        AddImageTiled(601, 47, 181, 469, 2624);
        AddLabel(648, 60, 2129, @"Restock Info");
        AddLabel(637, 98, 1418, @"Available");
        AddImageTiled(633, 123, 120, 16, 5214);
        AddTextEntry(637, 121, 107, 20, 547, 3, (m_Restock == null ? "Enter." : m_Restock.Count.ToString())); //3 - beginning amount
        AddLabel(660, 161, 1418, @"Maximum");
        AddImageTiled(631, 186, 120, 16, 5214);
        AddTextEntry(635, 184, 107, 20, 547, 4, ((m_Restock == null || m_Restock.Maximum < 0) ? "None." : m_Restock.Maximum.ToString())); //4 - Maxinum
        AddLabel(648, 227, 1418, @"Restock Rate");
        AddImageTiled(635, 252, 72, 16, 5214);
        AddTextEntry(638, 250, 64, 20, 547, 5, (m_Restock == null ? "0" : m_Restock.Hours.ToString())); //5 - hour
        AddLabel(714, 250, 602, @"hours");
        AddImageTiled(635, 292, 72, 16, 5214);
        AddLabel(716, 290, 602, @"mins");
        AddLabel(632, 323, 602, @"amount to restock");
        AddImageTiled(636, 355, 72, 16, 5214);
        AddTextEntry(638, 290, 64, 20, 547, 6, (m_Restock == null ? "0" : m_Restock.Minutes.ToString())); //6 - minute
        AddTextEntry(639, 353, 64, 20, 547, 7, (m_Restock == null ? "0" : m_Restock.RestockAmnt.ToString())); //7 - Restock Amount      
        AddImage(655, 377, 109);
        AddButton(636, 474, 4022, 4021, 3, GumpButtonType.Reply, 0);
        AddLabel(679, 475, 132, @"Void Restock");
        
    }
    public Reward.RestockInfo GetRestockInfo(RelayInfo info)
    {
        if (m_RestockOpen)
        {
            int numMinutes = 0, numHours = 0;
            int numBegin, numMax, numRestockAmnt;

            TextRelay entry3 = info.GetTextEntry(3);
            string beginAmount = (entry3.Text.Trim());

            TextRelay entry4 = info.GetTextEntry(4);
            string max = (entry4.Text.Trim());

            TextRelay entry5 = info.GetTextEntry(5);
            string hour = (entry5.Text.Trim());

            TextRelay entry6 = info.GetTextEntry(6);
            string minute = (entry6.Text.Trim());

            TextRelay entry7 = info.GetTextEntry(7);
            string restockAmount = (entry7.Text.Trim());

            Int32.TryParse(hour, out numHours);
            Int32.TryParse(minute, out numMinutes);
            Int32.TryParse(beginAmount, out numBegin);
            Int32.TryParse(max, out numMax);
            Int32.TryParse(restockAmount, out numRestockAmnt);

            if (numBegin > 0)
            {
                if ((numMinutes + numHours) > 0 && numRestockAmnt > 0)
                {
                    if (numMax > 0)
                    {
                        return new Reward.RestockInfo(numHours, numMinutes, numBegin, numRestockAmnt, numMax);
                    }
                    else
                    {
                        return new Reward.RestockInfo(numHours, numMinutes, numBegin, numRestockAmnt);
                    }
                }

                return new Reward.RestockInfo(numBegin);
            }                   
        }
        return m_Restock; //default
    }
    public Storage GetEntries(RelayInfo info)
    {
        //Description
        TextRelay entry0 = info.GetTextEntry(0);
        string desc = (entry0 == null ? "None." : entry0.Text.Trim());

        //Cost
        TextRelay entry1 = info.GetTextEntry(1);
        string costtext = (entry1 == null ? "0" : entry1.Text.Trim());

        //Name
        TextRelay entry2 = info.GetTextEntry(2);
        string name = (entry2 == null ? "" : entry2.Text.Trim());

        return new Storage(desc, costtext, name);
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        switch (info.ButtonID)
        {
            case 0:
                {
                    //cancel
                    break;
                }
            case 1: //ok
                {
                    try
                    {
                        //Description
                        TextRelay entry0 = info.GetTextEntry(0);
                        string desc = (entry0 == null ? "None." : entry0.Text.Trim());

                        //Cost
                        TextRelay entry1 = info.GetTextEntry(1);
                        string costtext = (entry1 == null ? "%Error" : entry1.Text.Trim());
                        int cost = Int32.Parse(costtext);

                        //Name
                        TextRelay entry2 = info.GetTextEntry(2);
                        string name = (entry2 == null ? "" : entry2.Text.Trim());

                        if ( m_IsAdd )
                            m_Vendor.AddReward(m_Reward);
                        
                        m_Reward.Edit(cost, name, desc);

                        if (m_RestockOpen)
                        {
                            Reward.RestockInfo input = GetRestockInfo(info);

                            if (input != null)
                            {
                                if (m_Restock != null && !(m_Restock.Equals(input))) //do not reassign same object
                                {
                                    m_Reward.Restock = input;
                                }
                                else
                                {
                                    m_Reward.Restock = input;
                                }
                            }
                        }

                        m.SendMessage("{0} has been modified in {1}'s collection", name, m_Vendor.GetName());

                    }
                    catch { m.SendMessage("Please make sure all fields are filled correctly, and the title has not been previously used."); }

                    break;
                }
            case 2: //open restock options
                {                                  
                    m.SendGump(new EditItemGump(m_Vendor, m_Reward, GetEntries(info), true, m_IsAdd));
                    
                    return; //override display 
                }
            case 3: //delete restock options
                {                   
                    m_Reward.Void_RestockInfo();
                                    
                    m.SendGump(new EditItemGump(m_Vendor, m_Reward, GetEntries(info), false, m_IsAdd));
                    
                    return; //override display 
                }
        }
        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, true); //send back display
    }
}

public class Exhibit : Item
{
    private IRewardVendor m_Vendor;
    private Reward m_Reward;
    private ObjectPropertyList m_PropertyList;

    public Exhibit(IRewardVendor vendor, Reward r)
        : base()
    {
        m_Vendor = vendor;
        m_Reward = r;

        SetOPL(r);

        this.ItemID = r.RewardInfo.ItemID;
        this.Hue = r.RewardInfo.Hue;
    }
    public override void SendPropertiesTo(Mobile from)
    {
        if (m_PropertyList == null)
        {
            m_PropertyList = new ObjectPropertyList(this);
            m_PropertyList.Add("Display [Broken]");
        }

        from.Send(m_PropertyList);
    }
    public void SetOPL(Reward r)
    {
        Item i = r.RewardInfo;

        m_PropertyList = new ObjectPropertyList(this);

        m_PropertyList.Add("Cost: " + m_Reward.Cost.ToString() + " " + m_Vendor.Payment.PayName + " [Click for more]");

        i.GetProperties(m_PropertyList);
        i.AppendChildProperties(m_PropertyList);

        m_PropertyList.Terminate();
        m_PropertyList.SetStatic();

    }

    public override void OnDoubleClick(Mobile m)
    {
        if (m_Vendor == null || m_Vendor.IsRemoved() || m_Reward == null || !m_Vendor.Display.Contains(m_Reward))
        {
            m_Vendor = null; // free up resource
            m_Reward = null;
            m.SendMessage("This item is no longer available to purchase.");
        }
        else
            m.SendGump(new ViewItemGump(m, m_Vendor, m_Reward, false));
    }

    public Exhibit(Serial serial)
        : base(serial)
    {
    }
    public override void Deserialize(GenericReader reader)
    {
        base.Deserialize(reader);

        int version = reader.ReadInt();

        if (reader.ReadBool())
        {
            m_Reward = (Reward)reader.ReadItem();

            m_Vendor = (IRewardVendor)reader.ReadMobile();

            try { SetOPL(m_Reward); }
            catch { }
        }
    }

    public override void Serialize(GenericWriter writer)
    {
        base.Serialize(writer);

        writer.Write((int)0); // version  

        if (m_Vendor == null || m_Vendor.IsRemoved() || m_Reward == null || m_Reward.Deleted)
        {
            m_Vendor = null;
            m_Reward = null;

            writer.Write((bool)false); //do not deserialize
        }
        else
        {
            writer.Write((bool)true);

            writer.WriteItem((Reward)m_Reward);

            writer.Write((Mobile)m_Vendor.GetMobile());
        }
    }
}
public class ViewItemGump : Gump
{
    IRewardVendor m_Vendor;
    Reward m_Reward;

    public ViewItemGump(Mobile m, IRewardVendor vendor, Reward r, bool viewItem)
        : base(0, 0)
    {
        m_Vendor = vendor;
        m_Reward = r;

        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);
        AddImageTiled(149, 207, 548, 277, 2624);
        AddImage(184, 300, 2328);
        AddImage(101, 222, 10400);
        
        AddHtml(428, 290, 243, 140, r.Description, (bool)true, (bool)true);
        AddItem(201, 311, r.RewardInfo.ItemID, r.RewardInfo.Hue);
                
        AddLabel(430, 263, 2101, @"Description");
        AddButton(192, 442, 4029, 4030, 2, GumpButtonType.Reply, 0); //buy
        AddLabel(231, 444, 2125, "Buy (" + r.Cost +")");
        AddButton(366, 442, 4020, 4021, 0, GumpButtonType.Reply, 0); //cancel
        AddLabel(407, 444, 2116, @"Cancel");
        AddImageTiled(184, 239, 510, 8, 9201);

        AddItem(182, 376, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);
        AddLabel(248, 369, 83, @"Pay By: " + m_Vendor.Payment.PayName);
        AddLabel(184, 268, 43, @"Vendor: " + m_Vendor.GetName());
        AddLabel(363, 216, 2123, r.Title);

        if (m.AccessLevel > AccessLevel.GameMaster) //GM capabilities
        {
            if (!viewItem)
                AddLabel(363, 216, 2123, r.Title);
            else
            {
                AddLabel(336, 296, 2101, @"Edit Item");
                AddButton(294, 293, 4011, 4012, 4, GumpButtonType.Reply, 0); //edit item

                if (m_Vendor.GetMobile() != null)
                {
                    AddLabel(336, 348, 2101, @"Get Display");
                    AddButton(294, 345, 4011, 4012, 3, GumpButtonType.Reply, 0); //get display   
                }
            }
        }
        else
        {
            OpenDisplay(m); //prevent build up of box display during editing
        }

        //Edit gump for display object
        if (viewItem) //not display
        {
            AddLabel(336, 322, 2101, @"View Item");
            AddButton(294, 319, 4011, 4012, 1, GumpButtonType.Reply, 0); //view item
                    
        }
        else //display
        {
            AddLabel(279, 320, 38, @"Cost: " + m_Reward.Cost.ToString());
            AddLabel(249, 398, 69, @"You have: " + m_Vendor.Payment.Value(m));

            if (m_Reward.Restock != null)
            {
                m_Reward.Try_Restock();
                AddLabel(279, 340, 4, "In Stock: " + m_Reward.Restock.Count.ToString());
            }

            if (m_Reward.RewardInfo is Container)
                OpenDisplay(m); 
        }
    }
    public void OpenDisplay(Mobile m)
    {
        DisplayBox dbox = m_Vendor.Display;

        if (dbox != null)
            dbox.DisplayTo(m, m_Reward);
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (m_Vendor.IsRemoved())
            return;

        switch (info.ButtonID)
        {
            case 0:
                {
                    break;
                }
            case 1:
                {
                    try
                    {
                        OpenDisplay(m);
                        m.SendGump(this);
                    }
                    catch
                    {
                        m.SendMessage("This Reward can no longer be found.");
                    }
                    break;
                }
            case 2:
                {
                    Container bank = m.BankBox;
                    Container pack = m.Backpack;

                    if ( bank == null || pack == null )
                        break;

                    Currency curr = m_Vendor.Payment;

                    if (m_Reward.InStock(1))
                    {
                        if (curr.Purchase(m, m_Reward.Cost))
                        {
                            m_Reward.RegisterBuy(1);

                            Item i = m_Reward.RewardCopy;

                            if (!m.PlaceInBackpack(i))
                            {
                                bank.DropItem(i);
                                m.SendMessage("You are overweight, the Reward was added to your bank");
                            }

                            m.SendMessage("You bought {0} for {1} {2}.", m_Reward.Title, m_Reward.Cost, curr.PayName);

                        }
                        else
                            m.SendMessage("You cannot afford {0}", m_Reward.Title);
                    }                           
                    else
                        m.SendMessage("{0} is no longer in stock.", m_Reward.Title);  

                    break;
                }
            case 3:
                {
                    if (m.Backpack != null)
                        m.AddToBackpack(new Exhibit(m_Vendor, m_Reward));
                    break;
                }
            case 4:
                {
                    m.SendGump(new EditItemGump(m_Vendor, m_Reward, null, false, false));
                    break;
                }
        }
    }
}

//Created for the usage of Warning Gump delegate 
public class Storage
{
    object[] m_Objs;

    public object this[int index]
    {
        get { return m_Objs[index]; }
    }

    public Storage(params object[] input)
    {
        m_Objs = input;
    }
    
}


public class WorldVendorsGump : Gump
{
    IRewardVendor m_Vendor; //used in case of copy

    public WorldVendorsGump(IRewardVendor vendor) : base( 0, 0 )
    {
        m_Vendor = vendor;

        this.Closable=true;
		this.Disposable=true;
		this.Dragable=true;
		this.Resizable=false;

		AddPage(0);

        //background
        AddImageTiled(50, 3, 430, 556, 2702);
		AddImageTiled(93, 78, 387, 9, 10101);
		AddImage(33, 58, 10420);
		AddImageTiled(47, 2, 3, 556, 10004);
		AddImageTiled(0, 58, 82, 414, 10440);
		AddImageTiled(47, 558, 436, 3, 10001);
		AddImageTiled(47, 0, 435, 3, 10001);
		AddImageTiled(480, 2, 3, 556, 10004);

        AddPage(1);

        CreateVendors(); //fill out entries
    }
    
    public static void CopyVendor_Callback(Mobile from, bool okay, object state)
    {
        if (from.AccessLevel < AccessLevel.GameMaster)
            return;
                
        if (okay)
        {
            //indexes -> (vendor (0), vendor's copy target(1))
            Storage store = (Storage)state;

            IRewardVendor source = (IRewardVendor)store[0];
            IRewardVendor target = (IRewardVendor)store[1];

            try { source.CopyVendor(target); }
            catch { from.SendMessage("Error occured while copying, please insure backpack is on vendors."); return; }

            from.SendMessage("{0} has copied {1}'s Reward collection", source.GetName(), target.GetName());
        }
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
        {
            m.CloseGump(typeof(ControlPanelGump));
            return;
        }

        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);

        try
        {
            if (info.ButtonID % 2 == 0 ) //even ID: Copy Vendor
            {
                IRewardVendor selected = WorldRewardVendors.Vendors[(info.ButtonID / 2) - 1];

                if ( m_Vendor.GetName().Equals(selected.GetName()))
                {
                    m.SendMessage("A vendor cannot copy itself.");
                }
                else
                {
                    //params -> (vendor, vendor's copy target)
                    Storage store = new Storage(m_Vendor, selected);

                    m.SendGump(new WarningGump(1060635, 30720, "Warning: You will lose all saved items on " + m_Vendor.GetName(), 0xFFC000, 420, 400, new WarningGumpCallback(CopyVendor_Callback), store));
                }
            }
            else //assert odd ID: Goto 
            {
                IRewardVendor v = WorldRewardVendors.Vendors[((info.ButtonID + 1) / 2) - 1];

                m.Location = v.GetLocation();
                m.Map = v.GetMap();
            }
        }
        catch
        {
            m.SendMessage("Vendor cannot be found.");
        }
    }
    public void CreateVendors()
    {
        int yPos = 101, pageNum = 1, buttonNum = 0;
      
        for (int i = 0; i < WorldRewardVendors.Vendors.Count; ++i)
        {            
            AddButton(175, yPos + 38, 4005, 4006, ++buttonNum, GumpButtonType.Reply, pageNum); //goto button - odd ID
            AddButton(279, yPos + 38, 4011, 4012, ++buttonNum, GumpButtonType.Reply, pageNum); //copy vendor - even ID
            AddLabel(86, yPos, 1849, WorldRewardVendors.Vendors[i].GetName());
            AddImageTiled(86, yPos + 93, 359, 2, 96);

            if (WorldRewardVendors.Vendors[i].GetMobile() != null)
                AddItem(110, yPos + 27, 8461); // person
            else

                AddItem(110, yPos + 27, WorldRewardVendors.Vendors[i].GetItem().ItemID, WorldRewardVendors.Vendors[i].GetItem().Hue); //stone ID

            AddLabel(213, yPos + 43, 2209, @"Go To");
            AddLabel(318, yPos + 43, 2204, @"Copy Vendor");
            
            yPos += 99;

            //add new page every four entries
            if ((i + 1) % 4 == 0)
            {
                AddButton(417, 531, 9903, 248, -1, GumpButtonType.Page, (pageNum + 1));

                AddPage(++pageNum);

                AddButton(92, 532, 9909, 248, -1, GumpButtonType.Page, (pageNum - 1));

                //reset to top of page
                yPos = 101;
            }
        }
    }
}
public class InfoGump : Gump
{
    public InfoGump()
        : base(0, 0)
    {
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);
        
        AddImageTiled(0, 0, 452, 516, 2702);
        AddHtml(21, 78, 407, 105, @"Consume Item:  Vendor counts the number of the chosen item present in player's backpack.  

        Property(Item/Player):  Vendor takes the total of the given number based property (example: PlayerPoints, Charges)
        (Items): Adds up from every item present.
        (Player): Simply takes from what is present.
        ", (bool)true, (bool)true);

        AddLabel(23, 52, 2000, @"Choosing How Player Pays:");
        AddHtml(21, 242, 407, 105, @"You can create your own rewards in game, all properties will be copied over.  ", (bool)true, (bool)true);
        AddLabel(24, 216, 2000, @"Adding Items");
        AddLabel(239, 479, 37, @"Author: krazeykow1102");
        AddItem(391, 467, 8451);
        AddLabel(24, 368, 2000, @"How Displays Work");
        AddHtml(24, 394, 410, 78, @"Displays allow you to create your own interactive Reward room.  The display is a simple mirror to the item on the vendor.  Payment and cost will reflect what is on the vendor.  Vendor must stay in tact for display to function", (bool)true, (bool)true);
    }
}


public class ControlPanelGump : Gump
{
    private IRewardVendor m_Vendor;
   
    public ControlPanelGump(Mobile m, IRewardVendor vendor)
        : base(0, 0)
    {

        m_Vendor = vendor;
                
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        //background
        AddImageTiled(4, 3, 215, 571, 2702);
        AddImageTiled(3, 0, 217, 3, 10001);
        AddImageTiled(4, 572, 216, 3, 10001);
        AddImageTiled(3, 1, 3, 571, 10004);
        AddImageTiled(217, 1, 3, 574, 10004);

        AddImage(40, 8, 5214);
        AddLabel(41, 7, 47, @"Control Panel");

        AddLabel(109, 62, 55, @"Manage Rewards");
        AddButton(72, 60, 4008, 4009, 1, GumpButtonType.Reply, 0); //PlayerView
        AddItem(31, 63, 5366); //scope
        AddImageTiled(19, 160, 132, 2, 96);

        AddLabel(79, 123, 1324, @"Add Item or Container");
        AddButton(52, 126, 2117, 2118, 2, GumpButtonType.Reply, 0); //AddItem
        AddItem(0, 113, 8192); //box  
        
        AddLabel(11, 232, 55, @"Target Payment Source:");
        AddButton(170,232, 2117, 2118, 3, GumpButtonType.Reply, 0); //Payment
        AddLabel(12, 173, 55, @"Pay By: " + m_Vendor.Payment.PayName );
        AddItem(61, 197, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);

        AddLabel(12, 32, 55, @"Vendor: " + m_Vendor.GetName());
        AddButton(77, 533, 4026, 4027, 4, GumpButtonType.Reply, 0);
        AddLabel(78, 553, 104, @"Help");

        if (m_Vendor.GetMobile() != null)
        {
            AddButton(72, 91, 4011, 4012, 5, GumpButtonType.Reply, 0); //Displays
            AddLabel(109, 93, 55, @"Get All Displays");
        }
        else
            AddLabel(12, 93, 55, @"Use Mobile Vendor for displays.");

       
        AddLabel(51, 258, 43, @"XML Attachment");
        AddRadio(15, 258, 9720, 9724, false, 6);
        AddLabel(51, 303, 43, @"Consume Item");
        AddRadio(15, 300, 9720, 9724, false, 7);
        AddLabel(50, 349, 43, @"[props Name of Item/Player");
        AddRadio(15, 342, 9720, 9724, false, 8);
        AddImageTiled(12, 382, 156, 22, 5058);
        AddTextEntry(12, 382, 149, 20, 41, 0, @"[prop/XML Name Here");

        AddPage(1);

        CreateGumps(); //fill out entries
               
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (m_Vendor.IsRemoved())
        {
            m.SendMessage("This vendor has been deleted.");
            return;
        }

        switch (info.ButtonID)
        {
            case 0:
                {
                    m.CloseGump(typeof(WorldVendorsGump));

                    //close
                    break;
                }
            case 1: //PlayerView
                {
                    m.CloseGump(typeof(WorldVendorsGump));

                    MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, true);
                    break;
                }
            case 2: //AddItem
                {
                    m.CloseGump(typeof(WorldVendorsGump));

                    m.Target = new AddItemTarget(m_Vendor);
                    break;
                }
            case 3: //Payment
                { 
                    
                        try
                        {
                            if (info.IsSwitched(6))
                            {
                                m.SendMessage("Target the player or item you wish to get the XMLAttribute from.");
                                TextRelay entry0 = info.GetTextEntry(0);
                                string propName = (entry0 == null ? "" : entry0.Text.Trim());

                                m.Target = new PaymentTarget(m_Vendor, propName, true);
                            }
                            else if ( info.IsSwitched(7)) // Consume by item amount
                            {
                                m.SendMessage("Warning: payment will be taken as the unmodified created item.");
                                m.Target = new PaymentTarget(m_Vendor);
                            }
                            else if (info.IsSwitched(8)) //Consume by item's property
                            {
                                m.SendMessage("Target yourself or an item.");
                                TextRelay entry0 = info.GetTextEntry(0);
                                string propName = (entry0 == null ? "" : entry0.Text.Trim());

                                m.Target = new PaymentTarget(m_Vendor, propName, false);
                            }
                            else
                            {                                
                                MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);
                                m.SendMessage("Please select consume or property.");
                            }
                        }

                            catch { }

                            break;      
                  }
            case 4:
                {
                    MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);
                    m.SendGump(new InfoGump());
                    break;
                }
            case 5: //Displays
                {
                    if (m.Backpack == null)
                        return;

                    MetalBox c = new MetalBox();
                    c.Name = m_Vendor.GetName() + "'s Reward Displays";

                    foreach (Reward r in m_Vendor.Rewards)
                    {
                        c.DropItem(new Exhibit(m_Vendor, r));
                    }

                    m.AddToBackpack(c);

                    break;
                }

            default: //Set Menu - IDs are >= 7
                {
                    try
                    {
                        Type menuType = MenuUploader.Menus[info.ButtonID - 7];

                        if (m_Vendor.GetItem() != null && menuType.Equals(typeof(ClassicVendorGump)))
                            m.SendMessage("Only Mobile Reward Vendors can have classic menus.");
                        else
                        {
                            m_Vendor.Menu = menuType;
                            m.SendMessage("Display changed to " + menuType.Name);
                        }
                    }
                    catch { }

                    MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);

                    break;
                                      
                }
         }   
    }
    public void CreateGumps()
    {
        int yPos = 433, pageNum = 1;

        for (int i = 0; i < MenuUploader.Menus.Count; ++i )
        {

            AddLabel(50, yPos, 100, MenuUploader.Menus[i].Name);
            AddButton(12, yPos, 4005, 4006, (i + 7), GumpButtonType.Reply, pageNum);
            

            yPos += 26;

            //add new page every four entries
            if ((i + 1) % 4 == 0)
            {
                AddButton(144, 542, 9702, 9703, -1, GumpButtonType.Page, (pageNum + 1));

                AddPage(++pageNum);

                AddButton(10, 542, 9706, 9707, -1, GumpButtonType.Page, (pageNum - 1));

                //reset to top of page
                yPos = 433;
            }
        } 
    }
}
public static class MenuUploader 
{
    private static List<Type> m_Menus = new List<Type>(); 
    
    public static List<Type> Menus { get { return m_Menus; } }

    public static void RegisterMenu<G>(G menu) where G : Gump, IRewardVendorGump
    {
        m_Menus.Add(menu.GetType());
    }
    
    public static void Display(IRewardVendorGump menu, Mobile m, IRewardVendor vendor)
    {
        m.CloseGump(typeof(IRewardVendorGump));

        //create 'canvas'
        menu.CreateBackground();

        //create Reward displays
        foreach (Reward r in vendor.Rewards)
        {
            //refresh restock  
            if (r.Try_Restock() == 0 && !(menu is ManageItemsGump))
                continue;
            
            menu.AddEntry(r);
        }

        //send finished product
        menu.Send(m);
    }
    public static void Display(Type menu, Mobile m, IRewardVendor vendor, bool playerView)  //Note: Playerview is only relevant for Staff
    {
        try
        {
            if (m.AccessLevel > AccessLevel.GameMaster) 
            {
                if (playerView)
                    Display(new ManageItemsGump(vendor, m), m, vendor);
                else //control panel
                {
                    m.CloseGump(typeof(WorldVendorsGump));
                    m.CloseGump(typeof(ControlPanelGump));

                    m.SendGump(new WorldVendorsGump(vendor)); 
                    m.SendGump(new ControlPanelGump(m, vendor));
                }
            }
            else //player
            {
                Display((IRewardVendorGump)Activator.CreateInstance(menu, new object[] { vendor, m }), m, vendor); //create fresh instance
            }
        }
        catch
        {
            if ( m.AccessLevel > AccessLevel.GameMaster )
                m.SendMessage("The current display is invalid, try setting gump back to default, JewlRewardGump.");
            else
                m.SendMessage("The current display is invalid, please notify the staff.");
        }
    }
}
public class ManageItemsGump : JewlRewardGump
{
    private int m_ButtonNum;

    public ManageItemsGump(IRewardVendor vendor, Mobile m) : base(vendor, m)
    {
        m_ButtonNum = 0;
    }
    public override void AddEntryControl(Reward r)
    {
        ImageTileButtonInfo b = new ItemTileButtonInfo(r.RewardInfo);

        //begin time entries
        if (r.Restock != null)
        {
            if (r.Restock.RestockRate.TotalMinutes == 0)
                AddLabel(324, (PosY + 22), 5, "Limited");
            else
                AddLabel(324, (PosY + 22), 5, ((int)r.Restock.RestockRate.Hours).ToString() + " hours " + ((int)r.Restock.RestockRate.Minutes).ToString() + " min");

            if (r.Restock.Maximum > 0)
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString() + " / " + r.Restock.Maximum.ToString() + ", Purchased: " + r.BuyCount.ToString());
            else
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString() + ", Purchased: " + r.BuyCount.ToString());
        }
        else
        {
            AddLabel(324, (PosY + 68), 4, "Purchased: " + r.BuyCount.ToString());
        }
        //end 

        //create entry
        AddLabel(227, PosY, 2123, r.Title);
        AddLabel(324, (PosY + 45), 2115, "Cost: " + r.Cost);
        //odd numbers
        AddImageTiledButton(227, (PosY + 26), 2328, 2329, ++m_ButtonNum, GumpButtonType.Reply, PageNum, b.ItemID, b.Hue, 15, 10, r.Display.Header);
        AddImageTiled(215, (PosY + 95), 359, 2, 96);
        //odd numbers (same as above)
        AddButton(470, (PosY + 45), 4011, 4012, m_ButtonNum, GumpButtonType.Reply, PageNum);
        AddLabel(508, (PosY + 47), 1882, @"Options");
        //even numbers
        AddButton(470, (PosY + 19), 4020, 4021, ++m_ButtonNum, GumpButtonType.Reply, PageNum);
        AddLabel(509, (PosY + 21), 1882, @"Delete");
        PosY += 102;

        //add new page every four entries
        if (EntryNum % 4 == 0)
        {
            AddButton(546, 562, 9903, 9904, -1, GumpButtonType.Page, PageNum + 1);

            AddPage(++PageNum);

            AddButton(221, 563, 9909, 9910, -1, GumpButtonType.Page, PageNum - 1);

            //reset to top of page
            PosY = 130;
        }

        EntryNum++;
    }
    public static void DeleteReward_Callback(Mobile from, bool okay, object state)
    {
        if (from.AccessLevel < AccessLevel.GameMaster)
            return;

        if (okay)
        {
            //indexes -> (Vendor(0), Reward(1))
            Storage store = (Storage)state;

            IRewardVendor vendor = (IRewardVendor)store[0];
            Reward Reward = (Reward)store[1];

            try { vendor.RemoveReward(Reward); }
            catch { from.SendMessage("An error ocurred in the removal of this item."); }
            
            MenuUploader.Display(vendor.Menu, from, vendor, true);
        }
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
        {
            MenuUploader.Display(Vendor.Menu, m, Vendor, false);
            return;
        }
            
        if (info.ButtonID % 2 == 0) //even
        {
                try
                {
                    Reward r = Vendor.Rewards[(info.ButtonID / 2) - 1];

                    //params -> (vendor, Reward)
                    Storage store = new Storage(Vendor, r);

                    m.SendGump(new WarningGump(1060635, 30720, "Warning: Are you sure you want to remove " + r.Title, 0xFFC000, 420, 400, new WarningGumpCallback(DeleteReward_Callback), store));

                }
                catch { m.SendMessage("This item could not be found."); }
            
        }
        else //assert - odd
        {
            try
            {
                MenuUploader.Display(Vendor.Menu, m, Vendor, true);
                m.SendGump(new ViewItemGump(m, Vendor, Vendor.Rewards[((info.ButtonID + 1) / 2) - 1], true));
            }
            catch { m.SendMessage("Vendor could not be found"); }
        }
        
    }
    
}
public class XMLIntPropertyGump : Gump
{
    private Type m_XML_Type;
    private object m_Target;

    private IRewardVendor m_Vendor;
    private List<PropertyInfo> m_Props;

    private int m_PageNum;
    private  int m_PosY;
    private int m_EntryNum;

    public XMLIntPropertyGump(Type xmlType, object target, IRewardVendor vendor, List<PropertyInfo> props)
        : base(0, 0)
    {
        m_XML_Type = xmlType;
        m_Target = target;
        m_Vendor = vendor;
        m_Props = props;

        m_PageNum = 1;
        m_PosY = 134;
        m_EntryNum = 1;
      
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        AddImageTiled(284, 90, 168, 384, 2702);
        AddLabel(315, 99, 49, xmlType.Name);
        AddImageTiled(292, 123, 151, 3, 9151);

        AddPage(1);

        FillEntries();
    }
    public void FillEntries()
    {
        foreach (PropertyInfo pi in m_Props)
        {
            AddButton(295, m_PosY, 5601, 5605, m_EntryNum, GumpButtonType.Reply, 0);
            AddLabel(319, m_PosY, 43, pi.Name);

            m_PosY += 26;

            if (m_EntryNum % 10 == 0)
            {
                AddButton(423, 444, 9903, 9904, -1, GumpButtonType.Page, m_PageNum + 1);

                AddPage(++m_PageNum);

                AddButton(292, 444, 9909, 9910, -1, GumpButtonType.Page, m_PageNum - 1);

                //reset to top of page
                m_PosY = 134;
            }
            m_EntryNum++;
        }

       
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
            return;

        m_Vendor.Payment = new Currency(m_Target, m_XML_Type, m_Props[info.ButtonID - 1]);
        m.SendMessage("{0}'s payment method set to {1}.{2}", m_Vendor.GetName(), m_XML_Type.Name, m_Props[info.ButtonID-1].Name);
    }

}
public class JewlRewardGump : Gump, IRewardVendorGump
{
    private int m_PageNum;
    private int m_EntryNum;
    private int m_PosY;
    private IRewardVendor m_Vendor;
    private Mobile m_Mobile;
    private int m_CurrencyAmnt;
   
    public static void Initialize()
    {
        MenuUploader.RegisterMenu(new JewlRewardGump());
    }

    public JewlRewardGump()
        : base(0, 0)
    {
        m_PageNum = 1;
        m_EntryNum = 1;
        m_PosY = 130;
        m_Vendor = null;
        m_Mobile = null;
        m_CurrencyAmnt = 0;
    }
    public JewlRewardGump(IRewardVendor vendor, Mobile m) : this()
    {
        m_Vendor = vendor;
        m_Mobile = m;
        m_CurrencyAmnt = vendor.Payment.Value(m);
    }

    //Properties
    public int PageNum { get { return m_PageNum; } set { m_PageNum = value; } }
    public int EntryNum { get { return m_EntryNum; } set { m_EntryNum = value; } }
    public int PosY { get { return m_PosY; } set { m_PosY = value; } }
    public IRewardVendor Vendor { get { return m_Vendor; } set { m_Vendor = value; } }
    public Mobile Mobile { get { return m_Mobile; } set { m_Mobile = value; } }
    public int CurrencyAmnt { get { return m_CurrencyAmnt; } set { m_CurrencyAmnt = value; } }

    //Interface Explicit Implementation 
    void IRewardVendorGump.Send(Mobile m) { SendControl(m); }
    void IRewardVendorGump.CreateBackground() { CreateBackgroundControl(); } 
    void IRewardVendorGump.AddEntry(Reward r) { AddEntryControl(r); }

    public virtual void SendControl(Mobile m)
    {
        m.SendGump(this);
    }
    public virtual void CreateBackgroundControl()
    {
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);

        AddImageTiled(179, 34, 430, 556, 2702);
        AddImageTiled(222, 109, 387, 9, 10101);
        AddImage(162, 89, 10420);
        AddImageTiled(176, 33, 3, 556, 10004);
        AddImageTiled(129, 89, 82, 414, 10440);
        AddImageTiled(176, 589, 436, 3, 10001);
        AddImageTiled(176, 31, 435, 3, 10001);
        AddImageTiled(609, 33, 3, 556, 10004);
        AddLabel(348, 52, 2124, m_Vendor.GetName());
        AddImage(210, 52, 9818);
        AddImage(534, 52, 9818);
        AddLabel(404, 119, 2125, @"You have:");
        AddItem(348, 126, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);
        AddLabel(404, 137, 2125, (m_CurrencyAmnt.ToString() + " " + m_Vendor.Payment.PayName) );
        

        AddPage(1);
    }
      
    public virtual void AddEntryControl(Reward r)
    {
        ImageTileButtonInfo b = new ItemTileButtonInfo(r.RewardInfo);

        //create entry

        //begin time entries
        if (r.Restock != null)
        {
            if (r.Restock.RestockRate.TotalMinutes == 0)
                AddLabel(324, (PosY + 22), 5, "Limited");

            if (r.Restock.Maximum > 0)
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString());
            else
                AddLabel(324, (PosY + 68), 4, "In Stock: " + r.Restock.Count.ToString());
        }
        //end 

        AddLabel(227, m_PosY, 2123, r.Title);
        AddLabel(324, (m_PosY + 45), 2115, "Cost: " + r.Cost);
        AddImageTiledButton(227, (m_PosY + 26), 2328, 2329, (m_EntryNum), GumpButtonType.Reply, m_PageNum, b.ItemID, b.Hue, 15, 10, b.LocalizedTooltip);
        AddImageTiled(215, (m_PosY + 95), 359, 2, 96);
        AddButton(470, (PosY + 45), 4011, 4012, (m_EntryNum), GumpButtonType.Reply, m_PageNum);
        AddLabel(508, (PosY + 47), 745, @"View Item");
        m_PosY += 102;
        
        //add new page every four entries
        if (m_EntryNum % 4 == 0)
        {
            AddButton(546, 562, 9903, 9904, -1, GumpButtonType.Page, m_PageNum + 1);

            AddPage(++m_PageNum);

            AddButton(221, 563, 9909, 9910, -1, GumpButtonType.Page, m_PageNum - 1);

            //reset to top of page
            m_PosY = 130;
        }

        m_EntryNum++;
    }
    public override void OnResponse(NetState sender, RelayInfo info)
    {
        Mobile m = sender.Mobile;

        if (info.ButtonID == 0)
            return;

        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, true);

        try
        {
            m.SendGump(new ViewItemGump(m, m_Vendor, m_Vendor.Rewards[info.ButtonID - 1], true));
        }
        catch { m.SendMessage("Vendor could not be found"); }
    }
}

public class DisplayBox : LargeCrate, IEnumerable
{
    private Dictionary<Reward, MetalBox> m_Boxes;

    public override bool IsPublicContainer { get { return true; } }

    public MetalBox this[Reward r]
    {
        get
        {
            MetalBox box = null; //not found

            m_Boxes.TryGetValue(r, out box);

            return box;
        }
    }

    [Constructable]
    public DisplayBox()
        : base()
    {
        this.Name = "Display Box [DO NOT REMOVE]";
        this.LiftOverride = true;
        m_Boxes = new Dictionary<Reward, MetalBox>();
    }
    public DisplayBox(RewardCollection rc)
        : this()
    {
        CreateEntries(rc);
    }
    public bool Contains(Reward r)
    {
        return m_Boxes.ContainsKey(r);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return m_Boxes.GetEnumerator();
    }
    public override bool CheckLift(Mobile from, Item item, ref LRReason reject)
    {
        reject = 0;
        return false;
    }
    public void DisplayTo(Mobile m, Reward r)
    {
        string invalid = "This item can no longer be displayed.";
        bool staff = m.AccessLevel >= AccessLevel.GameMaster;

        try
        {
            Container[] containers = new Container[] { (Container)this.Parent, this }; //cast exception if parent isn't container

            foreach (Container c in containers)
            {
                if (m.NetState != null && m.NetState.IsPost6017)
                    m.Send(new ContainerContent6017(m, c));
                else
                    m.Send(new ContainerContent(m, c));
            }

            m_Boxes[r].DisplayTo(m); //throws null ref if not found

            m.SendMessage("A container has been opened for you to view the item.");
        }
        catch (NullReferenceException)
        {
            if (staff)
                m.SendMessage("Display error - please insure Reward is still on this vendor.");
            else
                m.SendMessage(invalid);
        }
        catch (InvalidCastException)
        {
            if (staff)
                m.SendMessage("Display error - the current vendor does not have a DisplayBox in backpack.");
            else
                m.SendMessage(invalid);
        }
        catch (Exception)
        {
            if (staff)
                m.SendMessage("Unknown error occured with display.");
            else
                m.SendMessage(invalid);
        }
            
    }
    //Warning: must catch exception in methods
    public void CreateEntries(RewardCollection rc)
    {
        foreach (Reward r in rc)
        {
            this.AddDisplay(r, r.RewardInfo);
        }
    }
    public void AddDisplay(Reward key, Item i)
    {
        if (m_Boxes.ContainsKey(key))
            throw new Exception("Key already in use.");

        MetalBox container = new MetalBox();
        
        container.DropItem(i);

        this.DropItem(container);

        m_Boxes.Add(key, container);    
    }
    public void AddDisplay(Reward r)
    {
        AddDisplay(r, r.RewardInfo);
    }
    public void RemoveDisplay(Reward r)
    {
        ((Item)m_Boxes[r]).Delete(); //remove from displaybox
        m_Boxes.Remove(r);   //remove from hashtable      
    }
    //End Warning

    public override bool OnDragDrop( Mobile from, Item dropped )
    {
        return false;//do nothing
    }

    public DisplayBox( Serial serial ) : base( serial )
	{
	}
    
	public override void Serialize( GenericWriter writer )
    {
		base.Serialize( writer );

		writer.Write( (int) 0 ); // version
        
        int count = 0;
        try
        {
            count = m_Boxes.Count;
        }
        catch
        {
            m_Boxes = new Dictionary<Reward, MetalBox>();
            m_Boxes.Add(new Reward(), new MetalBox());
            count = m_Boxes.Count;
        }
        writer.Write((int)count);

        foreach (KeyValuePair<Reward, MetalBox> kvp in m_Boxes)
        {
            writer.Write((Reward)kvp.Key);
            writer.WriteItem((MetalBox)kvp.Value);
        }
        
    }

	public override void Deserialize( GenericReader reader )
    {
		base.Deserialize( reader );
                
		int version = reader.ReadInt();

        
        int count = reader.ReadInt();
        
        m_Boxes = new Dictionary<Reward, MetalBox>();     
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                Reward r = (Reward)reader.ReadItem();
                MetalBox box = (MetalBox)reader.ReadItem();

                m_Boxes.Add(r, box);
            }
        }      
    }
}

public class LoadGumpEntry : ContextMenuEntry
{
    private IRewardVendor m_Vendor;
    private Mobile m_Mobile;

    public LoadGumpEntry(Mobile from, IRewardVendor vendor)
        : base(6103, 8)
    {
        m_Vendor = vendor;
        m_Mobile = from;
        Enabled = true;
    }

    public override void OnClick()
    {
        try
        {
            MenuUploader.Display((IRewardVendorGump)Activator.CreateInstance(m_Vendor.Menu, new object[] { m_Vendor, m_Mobile }), m_Mobile, m_Vendor); //create fresh instance
        }
        catch { m_Mobile.SendMessage("The current display is invalid.");  }
    }
}
public class ClassicVendorGump : Gump, IRewardVendorGump
{
    private IRewardVendor m_Vendor;
    private BaseVendor m_BVendor;

    private Mobile m_Mobile;   

    private List<ObjectPropertyList> m_Opls;
    private ArrayList m_List;

    public List<ObjectPropertyList> ObjPropLists { get { return m_Opls; } }
    public ArrayList RewardList { get { return m_List; } }

    public static void Initialize()
    {
        MenuUploader.RegisterMenu(new ClassicVendorGump());
    }

    public ClassicVendorGump()
        : base(0, 0)
    {
        m_Vendor = null;
        m_Mobile = null;
        m_BVendor = null;
        m_Opls = null;
        m_List = null;
    }
    public ClassicVendorGump(IRewardVendor vendor, Mobile m) : this()
    {
        m_Vendor = vendor;
        m_Mobile = m;
        m_BVendor = Parent(vendor);
        m_Opls = new List<ObjectPropertyList>();
        m_List = new ArrayList();
    }
    private BaseVendor Parent(IRewardVendor vendor)
    {
        BaseVendor validVendor = null;

        if (vendor != null) //only available on mobiles inherited from BaseVendor
            validVendor = vendor as BaseVendor;

        return validVendor;
    }
    void IRewardVendorGump.Send(Mobile m)
    {
        if ( !m_Vendor.Payment.PaymentType.Equals(typeof(Gold)) ) //need custom payment display
            m.SendGump(this);    

        if (m_BVendor != null)
        {

            if (m_List.Count > 0)
            {
                m_List.Sort(new BuyItemStateComparer());

                m_BVendor.SendPacksTo(m);

                if (m.NetState == null)
                    return;

                if (m.NetState.IsPost6017)
                    m.Send(new VendorBuyContent6017(m_List));
                else
                    m.Send(new VendorBuyContent(m_List));
                m.Send(new VendorBuyList(m_BVendor, m_List));
                m.Send(new DisplayBuyList(m_BVendor));

                m.Send(new MobileStatusExtended(m));//make sure their gold amount is sent

                if (m_Opls != null)
                {
                    for (int i = 0; i < m_Opls.Count; ++i)
                    {
                        m.Send(m_Opls[i]);
                    }
                }

                m_BVendor.SayTo(m, 500186); // Greetings.  Have a look around.
            }
        }               
    }   
    void IRewardVendorGump.AddEntry(Reward r)
    {
        m_List.Add(new BuyItemState(r.Title, m_BVendor.BuyPack.Serial, r.Serial, r.Cost, (r.Restock == null ? 20 : r.Restock.Count), r.RewardInfo.ItemID, r.RewardInfo.Hue));

        m_Opls.Add(r.Display);      
    }
    void IRewardVendorGump.CreateBackground()
    {
        this.Closable = true;
        this.Disposable = true;
        this.Dragable = true;
        this.Resizable = false;

        AddPage(0);
        AddImage(36, 105, 2162);
        AddItem(111, 217, m_Vendor.Payment.PayID, m_Vendor.Payment.CurrHue);
        AddLabel(110, 172, 2122, @"Pay By:  " + m_Vendor.Payment.PayName);
        AddLabel(110, 299, 2120, @"You have: " + m_Vendor.Payment.Value(m_Mobile));
        AddImage(71, 302, 57);
        AddImage(71, 174, 57);
    }
}
public class MobileRewardVendor : Banker, IRewardVendor 
{
    private Currency m_Currency;
    private RewardCollection m_Rewards;
    private Type m_Menu;
    private DisplayBox m_Box;

    private bool m_IsBanker;

    [CommandProperty(AccessLevel.GameMaster)]
    public bool IsBanker
    {
        get { return m_IsBanker; }
        set { m_IsBanker = value; }     
    }
    Currency IRewardVendor.Payment
    {
        get { return m_Currency; }
        set { m_Currency = value; }
    }
    RewardCollection IRewardVendor.Rewards
    {
        get { return m_Rewards; }
        set { m_Rewards = value; }
    }
    Type IRewardVendor.Menu
    {
        get { return m_Menu; }
        set { m_Menu = value;  }
    }
    DisplayBox IRewardVendor.Display
    {
        get { return m_Box; }
    }
    [Constructable]
    public MobileRewardVendor() : base()
    {
        m_IsBanker = true;

        //default is Gold
        m_Currency = new Currency();
        m_Rewards = new RewardCollection();
        m_Menu = typeof(ClassicVendorGump);
        m_Box = new DisplayBox();

        //add to world collection
        WorldRewardVendors.RegisterVendor(this);
        //must be brought to world for client to view
        this.AddToBackpack(m_Box);

        this.Title = "";
    }
    public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
    {
        if (from.Alive)
        {
            list.Add(new LoadGumpEntry(from, this));

            if ( m_IsBanker)
                list.Add(new OpenBankEntry(from, this));
        }
    }
    Mobile IRewardVendor.GetMobile()
    {
        return this;
    }
    Item IRewardVendor.GetItem()
    {
        return null;
    }
   
    bool IRewardVendor.IsRemoved()
    {
        return this.Deleted;
    }
    Container IRewardVendor.GetContainer()
    {
        return this.Backpack;
    }
    string IRewardVendor.GetName()
    {
        return this.Name;
    }
    Map IRewardVendor.GetMap()
    {
        return this.Map;
    }
    Point3D IRewardVendor.GetLocation()
    {
        return this.Location;
    }
    //begin bank override
    public override bool HandlesOnSpeech(Mobile from)
    {
        if (!m_IsBanker)
            return false;

        base.HandlesOnSpeech(from);

        return true;
    }
    public override void OnSpeech(SpeechEventArgs e)
    {
        if (m_IsBanker)
            base.OnSpeech(e);
    }    
    //end

    //Warning: Following methods will throw Exceptions
    void IRewardVendor.AddReward(Reward r)
    {
        m_Box.AddDisplay(r);
        m_Rewards.Add(r);
    }
    void IRewardVendor.RemoveReward(Reward r)
    {
        m_Rewards.Remove(r);
        m_Box.RemoveDisplay(r);
    }
    
    void IRewardVendor.CopyVendor(IRewardVendor vendor)
    {
        Item currBox = this.Backpack.FindItemByType(typeof(DisplayBox));
        currBox.Delete();

        m_Currency = vendor.Payment;
        m_Menu = vendor.Menu;

        m_Rewards = (RewardCollection)((vendor.Rewards as ICloneable).Clone());
        m_Box = new DisplayBox(m_Rewards);

        this.AddToBackpack(m_Box);
    }
    //End Warning
    public override void OnDelete()
    {
        WorldRewardVendors.RemoveVendor(this);
        base.OnDelete();
    }
    //response to ClassicVendorGump - (must be inside BaseVendor)
    public override bool OnBuyItems(Mobile buyer, ArrayList list)
    {
        int totalCost = 0;
      
        Dictionary<Reward, int> purchases = new Dictionary<Reward, int>();

        Container bank = buyer.BankBox;
        Container pack = buyer.Backpack;

        if (pack == null || bank == null)
            return false;

        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;

                Reward r = item as Reward;

                if (r == null || !r.InStock(amount))
                    continue;

                totalCost += (r.Cost * amount);

                purchases.Add(r, amount);
            }
        }

        if (purchases.Count == 0)
        {
            SayTo(buyer, 500190); // Thou hast bought nothing! 
            return false;
        }                    
            if (!m_Currency.Purchase(buyer, totalCost)) //cannot afford
            {
                SayTo(buyer, 500192);//Begging thy pardon, but thou casnt afford that.
                return false;
            }

            foreach (KeyValuePair<Reward, int> kvp in purchases)
            {
                kvp.Key.RegisterBuy(kvp.Value);

                for (int index = 0; index < kvp.Value; index++)
                {                    
                    Item i = kvp.Key.RewardCopy;

                    if (!buyer.PlaceInBackpack(i))
                    {
                        bank.DropItem(i);
                        buyer.SendMessage("You are overweight, the Reward was added to your bank");
                    }
                }

                buyer.SendMessage("You bought {0} {1}", kvp.Value, kvp.Key.Title);
            }

            buyer.PlaySound(0x32);

            return true;  
             
    }
    //respone to 'vendor buy'
    public override void VendorBuy(Mobile from)
    {       
        MenuUploader.Display((IRewardVendorGump)Activator.CreateInstance(m_Menu, new object[] { (IRewardVendor)this, from }), from, (IRewardVendor)this ); //create fresh instance
    }
    //end edit
    public override void OnDoubleClick(Mobile m)
    {
        if (InRange(m, 4) && InLOS(m))
            MenuUploader.Display(m_Menu, m, this, false);
    }
    public MobileRewardVendor( Serial serial ) : base( serial )
	{
	}
    
	public override void Serialize( GenericWriter writer )
    {
		base.Serialize( writer );   

		writer.Write( (int) 1 ); // version

        writer.Write((bool)m_IsBanker);

        int count = m_Rewards.Count;
        writer.Write((int)count);

        if ( count > 0 )
        {
            for (int i = 0; i < count; i++)
            {
                writer.WriteItem((Reward)m_Rewards[i]);
            }
        }
        
        writer.WriteItem((Currency)m_Currency);
        writer.Write((string)m_Menu.Name);
        writer.WriteItem((DisplayBox)m_Box);       
    }
    
	public override void Deserialize( GenericReader reader )
    {
		base.Deserialize( reader );

        WorldRewardVendors.RegisterVendor(this);

		int version = reader.ReadInt();
        
        m_Rewards = new RewardCollection();

        m_IsBanker = true; //for conversion
               
        switch (version)
        {
            case 1:
                {
                    m_IsBanker = reader.ReadBool();

                    goto case 0;
                }
            case 0:
               {                   
                    int count = reader.ReadInt();
                    if (count > 0)
                    {
                        for (int i = 0; i < count; i++)
                        {
                            Reward r = (Reward)reader.ReadItem();
                            m_Rewards.Add(r);
                        }
                    }

                    m_Currency = (Currency)reader.ReadItem();

                    try { string name = reader.ReadString(); m_Menu = ScriptCompiler.FindTypeByName(name); }
                    catch { m_Menu = typeof(JewlRewardGump); }

                    m_Box = (DisplayBox)reader.ReadItem();

                    break;
                }
        }
	}
}
public class StoneRewardHolder : MetalBox
{
    private StoneRewardVendor m_S_Vendor;

    public StoneRewardHolder(StoneRewardVendor sv)
        : base()
    {
        m_S_Vendor = sv;
        this.Movable = false;
        this.Name = sv.Name + "'s Display Container [DO NOT DELETE]";
    }
    public override void OnItemLifted(Mobile m, Item item)
    {
        m.SendMessage("This item should not be moved away from the vendor.");
    }

    public void UpdateName()
    {
        if (m_S_Vendor == null)
            return;

        this.Name = m_S_Vendor.Name + "'s Display Container [DO NOT DELETE]";
    }
    public StoneRewardHolder(Serial serial)
        : base(serial)
	{
	}

	public override void Serialize( GenericWriter writer )
	{
		base.Serialize( writer );

		writer.Write( (int) 0 ); // version
	}

	public override void Deserialize( GenericReader reader )
	{
		base.Deserialize( reader );

		int version = reader.ReadInt();
    }
}
public class StoneRewardVendor : Item, IRewardVendor
{
    private Currency m_Currency;
    private RewardCollection m_Rewards;
    private Type m_Menu;
    private StoneRewardHolder m_Box_Holder;
    private DisplayBox m_Box;

    Currency IRewardVendor.Payment
    {
        get { return m_Currency; }
        set { m_Currency = value; }
    }
    RewardCollection IRewardVendor.Rewards
    {
        get { return m_Rewards; }
        set { m_Rewards = value; }
    }
    Type IRewardVendor.Menu
    {
        get { return m_Menu; }
        set { m_Menu = value; }
    }
    DisplayBox IRewardVendor.Display
    {
        get { return m_Box; }
    }

    [Constructable]
    public StoneRewardVendor()
        : base()
    {
        m_Currency = new Currency();
        m_Rewards = new RewardCollection();
        m_Menu = typeof(JewlRewardGump);
        m_Box = new DisplayBox();

        ItemID = 0xEDC;
        Name = "Stone Vendor";

        WorldRewardVendors.RegisterVendor(this);

        m_Box_Holder = new StoneRewardHolder(this);
        m_Box_Holder.DropItem(m_Box);      

        this.Movable = false;
    }
    public override void OnLocationChange( Point3D oldLocation )
    {
        base.OnLocationChange(oldLocation);

        if (m_Box_Holder != null)
        {
            m_Box_Holder.Location = this.Location;
            m_Box_Holder.Z = this.Z - 10;
        }
    }
    public override void OnMapChange()
    {
        base.OnMapChange();

        if ( m_Box_Holder != null )
            m_Box_Holder.Map = this.Map;
    }
    Mobile IRewardVendor.GetMobile()
    {
        return null;
    }
    Item IRewardVendor.GetItem()
    {
        return this;
    }

    bool IRewardVendor.IsRemoved()
    {
        return this.Deleted;
    }
    Container IRewardVendor.GetContainer()
    {
        return m_Box_Holder;
    }
    string IRewardVendor.GetName()
    {
        return this.Name;
    }
    Map IRewardVendor.GetMap()
    {
        return this.Map;
    }
    Point3D IRewardVendor.GetLocation()
    {
        return this.Location;
    }
    void IRewardVendor.AddReward(Reward r)
    {
        m_Box.AddDisplay(r);
        m_Rewards.Add(r);
    }
    void IRewardVendor.RemoveReward(Reward r)
    {
        m_Rewards.Remove(r);
        m_Box.RemoveDisplay(r);
    }

    void IRewardVendor.CopyVendor(IRewardVendor vendor)
    {
        Item currBox = m_Box_Holder.FindItemByType(typeof(DisplayBox));
        currBox.Delete();

        m_Currency = vendor.Payment;
        m_Menu = vendor.Menu;

        m_Rewards = (RewardCollection)((vendor.Rewards as ICloneable).Clone());
        m_Box = new DisplayBox(m_Rewards);

        m_Box_Holder.DropItem(m_Box);
    }
    //End Warning
    public override void OnDelete()
    {
        if ( m_Box_Holder != null)
            m_Box_Holder.Delete();

        WorldRewardVendors.RemoveVendor(this);
        base.OnDelete();
    }
    
    public override void OnDoubleClick(Mobile m)
    {
        if (m_Box_Holder != null)
        {
            m_Box_Holder.MoveToWorld(this.Location, this.Map);
            m_Box_Holder.Z = this.Z - 10;
            m_Box_Holder.UpdateName();
        }
        MenuUploader.Display(m_Menu, m, this, false);
    }
     
    public StoneRewardVendor(Serial serial)
        : base(serial)
    {
    }

    public override void Serialize(GenericWriter writer)
    {
        base.Serialize(writer);

        writer.Write((int)0); //Version 0

        int count = m_Rewards.Count;
        writer.Write((int)count);

        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                writer.WriteItem((Reward)m_Rewards[i]);
            }
        }

        writer.WriteItem((Currency)m_Currency);
        writer.Write((string)m_Menu.Name);
        writer.WriteItem((DisplayBox)m_Box);
        writer.WriteItem((StoneRewardHolder)m_Box_Holder);
    }

    public override void Deserialize(GenericReader reader)
    {
        base.Deserialize(reader);

        WorldRewardVendors.RegisterVendor(this);

        int version = reader.ReadInt();

        m_Rewards = new RewardCollection();

        int count = reader.ReadInt();
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                Reward r = (Reward)reader.ReadItem();
                m_Rewards.Add(r);
            }
        }

        m_Currency = (Currency)reader.ReadItem();

        try { string name = reader.ReadString(); m_Menu = ScriptCompiler.FindTypeByName(name); }
        catch { m_Menu = typeof(JewlRewardGump); }

        m_Box = (DisplayBox)reader.ReadItem();
        m_Box_Holder = (StoneRewardHolder)reader.ReadItem();
    }
}
public interface IRewardVendor
{
    //used to determine how player pays
    Currency Payment { get; set; }
    //to keep added items
    RewardCollection Rewards { get; set; }
    //to change gump
    Type Menu { get; set; }
    //to show player items
    DisplayBox Display { get; }
    //to return what holds 'DisplayBox' object
    Container GetContainer();
    //to return removal status
    bool IsRemoved();
   
    //serial /deserial
    Mobile GetMobile();
    Item GetItem();

    //used for 'world collection'
    string GetName();
    Point3D GetLocation();
    Map GetMap();

    //to manage RewardCollection
    void AddReward(Reward r);
    void RemoveReward(Reward r);
    
    //to create vendor clones
    void CopyVendor(IRewardVendor vendor);
}
public interface IRewardVendorGump
{
    void Send(Mobile m);
    void AddEntry(Reward r);
    void CreateBackground();
    
    //add entry || background || 
}


public class PaymentTarget : Target
{
    private string m_Name;
    private IRewardVendor m_Vendor;
    private bool m_Is_XML;

    public PaymentTarget()
        : base(2, false, TargetFlags.None)
    {
    }
    //by item
    public PaymentTarget(IRewardVendor vendor) : this ()
	{
        m_Vendor = vendor;
        m_Name = null;
        m_Is_XML = false;
    }
    //by item property
    public PaymentTarget(IRewardVendor vendor, string name, bool isXML) : this()
    {
        m_Vendor = vendor;
        m_Name = name;
        m_Is_XML = isXML;
    }
    protected override void OnTarget(Mobile m, object targeted)
    {
        if (m_Is_XML && !String.IsNullOrEmpty(m_Name))
        {
            Type attachType = ScriptCompiler.FindTypeByName(m_Name);

            if (attachType != null && attachType.BaseType.Equals(typeof(XmlAttachment)))
            {
                List<PropertyInfo> integerProps = new List<PropertyInfo>();

                foreach (PropertyInfo pi in attachType.GetProperties())
                {
                    if ((pi.CanRead && pi.CanWrite) && pi.PropertyType.Equals(typeof(System.Int32)))
                        integerProps.Add(pi);
                }

                if (integerProps.Count == 0)
                    m.SendMessage("{0} does not contain any integer based properties.", attachType.Name);
                else
                    m.SendGump(new XMLIntPropertyGump(attachType, targeted, m_Vendor, integerProps));
            }
            else
                m.SendMessage("The XML Attachment, {0}, could not be found, the search IS case sensitive", m_Name);
        }
        else if ( targeted is Item )
        {           
            //consume by item
            if (m_Name == null)
            {
                m_Vendor.Payment = new Currency((Item)targeted);
                m.SendMessage("{0} will now use {1} for payment.", m_Vendor.GetName(), targeted.GetType().Name);
            }
            //consume by item property
            else
            {
                SetByProperty(m, targeted);
            }
        }
        else if (targeted is PlayerMobile)
        {
            if (m_Name == null)
            {
                m.SendMessage("You can only use Property option for player.");

            }
            else
            {
                SetByProperty(m, null);
            }
        }
        else
        {
            m.SendMessage("Invalid, target must be Item or Player.");
        }

        MenuUploader.Display(m_Vendor.Menu, m, m_Vendor, false);
    }
    private void SetByProperty(Mobile m, object o)
    {
        string msg = "Please make sure you entered the name correctly, "
                        + "it IS case sensitive.";
        try
        {
            if (o != null)//Item
            {
                PropertyInfo pi = o.GetType().GetProperty(m_Name);

                if (pi != null && pi.PropertyType.Equals(typeof(Int32)))
                {
                    m_Vendor.Payment = new Currency((Item)o, pi);
                    m.SendMessage(m_Vendor.GetName() + "will now use {1}.{2} for payment.", m_Vendor.GetName(), o.GetType().Name, pi.Name);
                }
                else
                    m.SendMessage(msg);
            }
            else//Mobile
            {
                PropertyInfo pi = m.GetType().GetProperty(m_Name);

                if (pi != null && pi.PropertyType.Equals(typeof(Int32)))
                {
                    m_Vendor.Payment = new Currency(m, pi);
                    m.SendMessage("{0} will now use {1}.{2} for payment.", m_Vendor.GetName(), m.GetType().Name, pi.Name);
                }
                else
                    m.SendMessage(msg);
            }
        }
        catch { m.SendMessage(msg); }
    }
}
public class AddItemTarget : Target
{
    IRewardVendor m_Vendor;

    public AddItemTarget() : base( 2, false, TargetFlags.None )
	{
	}
    public AddItemTarget(IRewardVendor vendor)
        : this()
    {
        m_Vendor = vendor;
    }
    protected override void OnTarget(Mobile from, object targeted)
    {
        Item i = targeted as Item;

        if (m_Vendor == null || i == null)
            return;

        Item clone = ItemClone.Clone(i);

        if (clone != null) //copy did not fail
            from.SendGump(new EditItemGump(m_Vendor, new Reward(clone), null, false, true));
        else
            from.SendMessage("This item cannot be copied.");

    }
}

public class ItemClone
{
    public static Item Clone(Item item) 
    {
        try
        {
            if ( item is Container )
                return CloneBag(((Container)item).FindItemsByType(typeof(Item), false), (Container)item, (Container)Activator.CreateInstance(item.GetType(), null));
            else
                return Clone(item.GetType(), item, (Item)Activator.CreateInstance(item.GetType(), null));
        }
        catch {}
       
        return null;
    }
    public static Container CloneBag(Item[] contents, Container old, Container copy)
    {        
        //emtpy new container
        foreach (Item i in copy.FindItemsByType(typeof(Item)))
        {
            i.Delete();
        }

        //'old' contents into 'new'
        foreach (Item i in contents)
        {
            copy.DropItem(Clone(i));           
        }

        copy.Name = old.Name; //requires manual set

        return copy;
    }
    public static Item Clone(Type type, Item old, Item copy)
    {
        foreach (PropertyInfo pi in type.GetProperties())
        {
            if (pi.CanRead && pi.CanWrite && ValidProperty(pi.Name)) 
            {
                try
                {
                    if (pi.PropertyType.IsClass)
                        CloneInnerClass(pi.PropertyType, pi.GetValue(old, null), pi.GetValue(copy, null)); //found object property
                    else
                        pi.SetValue(copy, pi.GetValue(old, null), null); //found value property
                }
                catch {}
            }
        }

        copy.Name = old.Name; //requires manual set

        return copy;
    }
    public static void CloneInnerClass(Type type, object old, object copy)
    {
        if (old == null) //not defined
            return;
        
        foreach ( PropertyInfo pi in type.GetProperties() )
        {
            if ( pi.CanRead && pi.CanWrite ) 
            {
                try
                {
                    pi.SetValue(copy, pi.GetValue(old, null), null);
                }
                catch {}
            }
        }
    }
    public static bool ValidProperty(string str) 
    {
        return !( str.Equals("Parent") || str.Equals("TotalWeight") || str.Equals("TotalItems") || str.Equals("TotalGold") );
    }
   
}

}
 
Top