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!

[RunU O 2.0 RC1& RC2] The Complete Customizable Vendor

Hawkins

Sorceror
krazeykow;784297 said:
Hah, I don't mind the edit at all, thanks for putting in the time to help. :)

But, as far as the improvement on this script goes, I really need some input to what needs to be improved... or if there are any bugs (Which I am not aware of).

I haven't gotten that much feed back.. only of which was about the display of the payment by customized coin (i.e. tokens).. which I've been working on.

So far the script works perfectly for me.

Hmm..the only problem could be that the vendors walk too far away that I have to lock the them up in a closed area. :p

So I think that it may be an improvement to add in the home range setting with a controller similar to the premiumspawners. So that the vendors are managed on a controller by controller basis, with a gump showing all the names and locations of all the controllers (more or less like how Knives' Townhouses are managed).

Something like that. Hope that it won't go way too complicated. :eek:
 

nadious

Sorceror
Agreed. If they are on spawners and they respawn... POOF. You lose everything configured on them.

The walking problem can be solved by using a props tag of [set frozen true on them. At least, it works for me. Not sure if that's the best solution at this point, but is seems to be working.

This script is awesome. You have no idea how much this is going to help the launch of our new shard. On our old shard, we had somethings I wanted to implement and it was going to require me to script mobiles (which I'm not good at...) and lay out a plan... and this one simple vendor script has addresses just about ALL of it.

One neat feature would be if you could have a GUMP launch when you go to buy (or an area in the sales gump) in where you could input some text, to give them a little speech. You could then use them for quests, or add some personality to them. I'd love to stick on in my casino area and sell some casino related items on them, but give the vendor a chance to talk and some some things, to lend to the whole 'bartender' feel. :D

Kudos on this script. It's very, very, very, awesome.
 

krazeykow

Sorceror
Good ideas, if I am to call it the 'complete' customizable vendor... adding interaction variables would be a great idea.

As far as the spawning goes... is it not possible to set a range on the spawner itself??? I always thought it could be done that way.
 

nadious

Sorceror
No, you can... but if the spawner were to respawn the vendor (for whatever the reason), all the items and config of the mobile starts from scratch.

Edit: Also, the ability to dress the vendor, maybe alter the name (and give a title... which can be done through props right now...) would be really cool too. IE: You have an vendor that trades boards for ingots... maybe dress him as a miner to complete the look.)
 

nadious

Sorceror
Also,

My GM and I had a thought the other day:

Is there any way to script it so that you could ADD negative attributes upon purchase? Example: Taking murder count(s) at the cost of a good item, or increasing negative karma when purchasing? Of course, if the system does that already and I'm unaware, please enlight'n me. :D
 

Cyndrz

Wanderer
I found a small problem, I added weapons to one of the vendors to sell, the weapons where scripted to have no durability but when a player buys one it comes out with a 0/66 durability rating on it.
I also am using a scripted hued token and no the hue isn't showing up in the menu.
Other then the weapon issue I love the vendors for everything else.
 

Macil

Sorceror
Code:
RunUO - [www.runuo.com] Version 2.0, Build 2357.32527
Core: Running on .NET Framework Version 2.0.50727
Scripts: Compiling C# scripts...failed (1 errors, 10 warnings)
Warnings:
 + !Custom Scripts/Player Government System 2.04/Regions/PlayerCityRegion.cs:
    CS0105: Line 8: The using directive for 'Server.Spells' appeared previously
in this namespace
 + !Custom Scripts/Monsters & Mobiles/GiantEarth.cs:
    CS0114: Line 141: 'Server.Mobiles.GiantEarthElemental.OnBeforeDeath()' hides
 inherited member 'Server.Mobiles.BaseCreature.OnBeforeDeath()'. To make the cur
rent member override that implementation, add the override keyword. Otherwise ad
d the new keyword.
    CS0162: Line 95: Unreachable code detected
 + !Custom Scripts/Player Government System 2.04/Vendor/CityPlayerVendor.cs:
    CS0108: Line 225: 'Server.Mobiles.CityPlayerVendor.Dismiss(Server.Mobile)' h
ides inherited member 'Server.Mobiles.PlayerVendor.Dismiss(Server.Mobile)'. Use
the new keyword if hiding was intended.
 + !Custom Scripts/Town Houses v2.0/Items/TownHouse.cs:
    CS0114: Line 46: 'Knives.TownHouses.TownHouse.BaseBanLocation' hides inherit
ed member 'Knives.TownHouses.VersionHouse.BaseBanLocation'. To make the current
member override that implementation, add the override keyword. Otherwise add the
 new keyword.
 + !Custom Scripts/Custom Items/Holiday Gifts/Crystal & Shadow Stuff/ShadowBanne
rAddon.cs:
    CS0168: Line 22: The variable 'ac' is declared but never used
    CS0168: Line 91: The variable 'ac' is declared but never used
 + !Custom Scripts/Player Government System 2.04/Vendor/CityContractOfEmployment
.cs:
    CS0642: Line 72: Possible mistaken empty statement
 + !Custom Scripts/Player Government System 2.04/PlayerGovernmentSystem.cs:
    CS0162: Line 560: Unreachable code detected
 + Multis/BaseHouse.cs:
    CS0429: Line 58: Unreachable expression code detected
    CS0162: Line 61: Unreachable code detected
 + !Custom Scripts/SawmillAddon.cs:
    CS0162: Line 208: Unreachable code detected
 + Multis/HouseSign.cs:
    CS0429: Line 103: Unreachable expression code detected
    CS0162: Line 105: Unreachable code detected
Errors:
 + !Custom Scripts/[RC2] Rewards System.cs:
    CS0117: Line 1856: 'Server.Network.NetState' does not contain a definition f
or 'IsPost6017'
    CS0246: Line 1857: The type or namespace name 'ContainerContent6017' could n
ot be found (are you missing a using directive or an assembly reference?)
    CS1502: Line 1857: The best overloaded method match for 'Server.Mobile.Send(
Server.Network.Packet)' has some invalid arguments
    CS1503: Line 1857: Argument '1': cannot convert from 'ContainerContent6017'
to 'Server.Network.Packet'
    CS0117: Line 2063: 'Server.Network.NetState' does not contain a definition f
or 'IsPost6017'
    CS0246: Line 2064: The type or namespace name 'VendorBuyContent6017' could n
ot be found (are you missing a using directive or an assembly reference?)
    CS1502: Line 2064: The best overloaded method match for 'Server.Mobile.Send(
Server.Network.Packet)' has some invalid arguments
    CS1503: Line 2064: Argument '1': cannot convert from 'VendorBuyContent6017'
to 'Server.Network.Packet'
Scripts: One or more scripts failed to compile or no script files were found.
 - Press return to exit, or R to try again.
 

LordHogFred

Knight
Awesome system, nice work dude.
Just thought of a decent addon for the system, you could make it so that each item could have a requirement to buy on top of the charge. For example, to buy a sword you need a minimum of 500 fame and 100 in swordsmanship.
Again, great system :),
 

krazeykow

Sorceror
@Macil, you downloaded the wrong version of the script.. please double check to what version of RUO you have and which you downloaded; however, the only portion of my script causing the errors are the last few lines.

@LordHogFred, genius idea.. wish I had the time to implement it now but in about 6 weeks it's summer break ;)
 

wlrdwawoolard

Sorceror
dont have errors with this but it gave errors for my other files

Errors:
+ Engines/Chat/Knives Chat v2.02 for RunUO 2.0/Gumps/ListGump.cs:
CS1501: Line 575: No overload for method 'SendTo' takes '5' arguments
+ Engines/Chat/Knives Chat v2.02 for RunUO 2.0/Gumps/OptionsGump.cs:
CS1501: Line 447: No overload for method 'SendTo' takes '5' arguments
CS1501: Line 496: No overload for method 'SendTo' takes '5' arguments
+ Engines/Chat/Knives Chat v2.02 for RunUO 2.0/Gumps/PmGump.cs:
CS1501: Line 147: No overload for method 'SendTo' takes '5' arguments
+ Engines/Chat/Knives Chat v2.02 for RunUO 2.0/Gumps/ProfileGump.cs:
CS1501: Line 136: No overload for method 'SendTo' takes '5' arguments
Scripts: One or more scripts failed to compile or no script files were found.
- Press return to exit, or R to try again.

i did nothin to this if i take out ur file it goes back to normal. i downloaded the [RC2] Rewards System
 

krazeykow

Sorceror
Edit for post below: I've attached a version that takes the required methods from the basehealer.cs ... I haven't compiled it so it may have errors.

I always appreciate comments left by the downloader, I script simply for the enjoyment and do not actively work on a server.
 

wlrdwawoolard

Sorceror
thx man it works :) also what if we can make it res people to make it have more value :) like vendor/healer/banker could this be possiable
 

Thilgon

Sorceror
i really like this, it's very versatile... gonna use it in many ways, as soon as i learn how to :p

as for now, i'd like to make a feedback... Reward on my server is already used by ML Quest Engine, so i simply renamed it to "CustomReward" (just for the moment, until i don't get a better name :p)... Since ML is a system used by many people in here, it would be nice to rename the class on the downloadable .cs... not absolutely needed, just suggesting :p

keep up the good work ;)
 

krazeykow

Sorceror
Minor update 4/23/09, I have corrected the payment displays for all vendors to include color and the actual name (if one exists). Gold/Silver will now display as a pile instead of single coin.

I realize this has been an issue for quite a long time; I am sorry I could not get this update to you quicker.
I've tested both versions extensively but PLEASE post any errors.
 

nadious

Sorceror
I've tried to take the minor changes update and merge it with the one that Hawkins has provided for me (2nd page of this thread), but I've done something wrong. Everytime I try to restart the server with a vendor that is present, I get the following error:

Code:
World: Loading...An error was encountered while loading a saved object
 - Type: Currency
 - Serial: 0x400002F1
Delete the object? (y/n)

If I nuke it out and delete the vendor, I have no problems restarting. I've done something wrong in the merge. Can anyone take a look here and see what I've messed up that is causing this issue?

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;


public class Currency : Item
{

    private Payment m_PaymentType;
    private PropertyInfo m_PropertyInfo;
    private Type m_Type;
    private int m_ItemID;
    private string m_Name;
    private int m_Hue;

    public Type PaymentType { get { return m_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
    }
    //default
    public Currency()
    {
        m_PaymentType = Payment.ByGold;
        m_Type = typeof(Gold);
        m_PropertyInfo = null;
        m_ItemID = 3823;
        m_Name = "Gold";
    }
    //consume by item
    public Currency(Item i)
    {
        if ( i.GetType().Equals(typeof(Gold)) )
            m_PaymentType = Payment.ByGold;
        else
            m_PaymentType = Payment.ByItem;

        m_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_PaymentType = Payment.ByProperty;
        m_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_PaymentType = Payment.ByProperty;
        m_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 is Mobile) || 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_PaymentType)
        {
            case Payment.ByGold:
            case Payment.ByItem:
                {
                    Modify(m_Type, "");
                    break;
                }
            case Payment.ByProperty:
                {
                    if (!(m_Type is Mobile))
                        Modify(m_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)))
            {
                pi.SetValue(m, remain, null);
            }
            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 = (int)pi.GetValue(items[i], null);
                    dif = value - cost;

                    //one item has enough
                    if (dif >= 0)
                    {
                        pi.SetValue(items[i], dif, null);
                    }
                    //take what amount item has (the amount has already been confirmed by Value(m))
                    else // assert (dif < 0)
                    {
                        cost -= (int)pi.GetValue(items[i], null);
                        pi.SetValue(items[i], 0, null);
                    }
                    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_PaymentType)
        {
            case Payment.ByGold:
                Charge(m, m.Backpack, m.FindBankNoCreate(), cost);
                break;
            case Payment.ByItem:
                Charge(m.Backpack, m.FindBankNoCreate(), m_Type, cost);
                break;

            case Payment.ByProperty:
                Charge(m, m_Type, m_PropertyInfo, cost, remain);
                break;
        }
    }
    public int Value(Mobile m)
    {
        switch (m_PaymentType)
        {
            case Payment.ByGold:
                return ProcessByGold(m);
            case Payment.ByItem:
                return ProcessByItem(m, m_Type);

            case Payment.ByProperty:
                return ProcessByProperty(m, m_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 += ((int)pi.GetValue(o, null));
        }

        return sum;
    }
    public int ProcessByProperty(Mobile m, Type t, PropertyInfo pi)
    {
        try
        {
            if (t.BaseType.Equals(typeof(Mobile)) || t.Equals(typeof(Mobile)) )
            {
                return (int)pi.GetValue(m, null);
            }
            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) 1 );

        //version 1
        writer.Write((int)m_Hue);
        
        //explicit casts are given for clarification        
        writer.Write((int)m_PaymentType);
        writer.Write((string)m_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();

        
        m_PaymentType = (Payment)reader.ReadInt();

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

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

                    try { string propName = reader.ReadString(); if (propName.Equals("")) { m_PropertyInfo = null; } else { m_PropertyInfo = m_Type.GetProperty(propName); } }
                    catch { }

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

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

public class MyReward : Item, ICloneable
{      
    private Item m_MyReward;
    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_MyReward.GetProperties(m_Display);
                m_MyReward.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 MyRewardInfo
    {
        get { return m_MyReward; }
    }
    //use only when creating reward for player
    public Item MyRewardCopy
    {
        get { return GetMyReward(); }
    }
    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 MyReward(this);
    }
    public MyReward()
    {
        m_MyReward = new Item();
        m_Cost = 0;
        m_Title = "";
        m_Description = "";
        m_RestockInfo = null;
    }
    public MyReward(MyReward r)
    {
        m_MyReward = r.MyRewardCopy;
        m_Cost = r.Cost;
        m_Title = r.Title;
        m_Description = r.Description;
        m_RestockInfo = null;
    }
    public MyReward(Item i)
    {
        m_MyReward = i;
        m_Cost = 0;
        m_Title = (i.Name == null ? i.GetType().Name : i.Name);
        m_Description = "None.";
        m_RestockInfo = null;

    }
    public MyReward(Item i, int cost)
    {
        m_MyReward = i;
        m_Cost = cost;
        m_Title = (i.Name == null ? i.GetType().Name : i.Name);
        m_Description = "None.";
        m_RestockInfo = null;
    }
    public MyReward(Item i, int cost, string title)
    {
        m_MyReward = i;
        m_Cost = cost;
        m_Title = title;
        m_Description = "None.";
        m_RestockInfo = null;
    }
    public MyReward(Item i, int cost, string title, string desc)
    {
        m_MyReward = 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 GetMyReward()
    {
        return ItemClone.Clone(m_MyReward);
    }

    public MyReward( 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_MyReward);
        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_MyReward = (Item)reader.ReadItem();
                    m_Cost = reader.ReadInt();
                    m_Title = reader.ReadString();
                    m_Description = reader.ReadString();                  
                    
                    break;
                }
        }
    
	}

}
public class MyRewardCollection : List<MyReward>, ICloneable
{
    

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

public static class WorldMyRewardVendors
{
    private static List<IMyRewardVendor> m_Vendors = new List<IMyRewardVendor>();

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

public class EditItemGump : Gump
{
    private IMyRewardVendor m_Vendor;
    private MyReward m_MyReward;

    private MyReward.RestockInfo m_Restock;
    private bool m_RestockOpen;

    private bool m_IsAdd;

    private Storage m_Entries;

    public EditItemGump(IMyRewardVendor vendor, MyReward r, Storage entries, bool openRestockInfo, bool addingItem) : base(0, 0)
    {
        m_Vendor = vendor;
        m_MyReward = 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.MyRewardInfo.ItemID, r.MyRewardInfo.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_MyReward.Description);
        AddTextEntry(334, 148, 188, 20, 1879, 1, m_MyReward.Cost.ToString());
        AddTextEntry(336, 108, 188, 20, 1879, 2, m_MyReward.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 MyReward.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 MyReward.RestockInfo(numHours, numMinutes, numBegin, numRestockAmnt, numMax);
                    }
                    else
                    {
                        return new MyReward.RestockInfo(numHours, numMinutes, numBegin, numRestockAmnt);
                    }
                }

                return new MyReward.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.AddMyReward(m_MyReward);
                        
                        m_MyReward.Edit(cost, name, desc);

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

                            if (input != null)
                            {
                                if (m_Restock != null && !(m_Restock.Equals(input))) //do not reassign same object
                                {
                                    m_MyReward.Restock = input;
                                }
                                else
                                {
                                    m_MyReward.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_MyReward, GetEntries(info), true, m_IsAdd));
                    
                    return; //override display 
                }
            case 3: //delete restock options
                {                   
                    m_MyReward.Void_RestockInfo();
                                    
                    m.SendGump(new EditItemGump(m_Vendor, m_MyReward, 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 IMyRewardVendor m_Vendor;
    private MyReward m_MyReward;
    private ObjectPropertyList m_PropertyList;

    public Exhibit(IMyRewardVendor vendor, MyReward r) : base()
    {
        m_Vendor = vendor;
        m_MyReward = r;
               
        SetOPL(r);
        
        this.ItemID = r.MyRewardInfo.ItemID;
        this.Hue = r.MyRewardInfo.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(MyReward r)
    {
        Item i = r.MyRewardInfo;

        m_PropertyList = new ObjectPropertyList(this);

        m_PropertyList.Add("Cost: " + m_MyReward.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_MyReward == null || !m_Vendor.Display.Contains(m_MyReward))
        {
            m_Vendor = null; // free up resource
            m_MyReward = null; 
            m.SendMessage("This item is no longer available to purchase.");
        }        
        else
            m.SendGump(new ViewItemGump(m, m_Vendor, m_MyReward, false));
    }
  
    public Exhibit(Serial serial)
        : base(serial)
	{
	}
	public override void Deserialize( GenericReader reader )
	{
		base.Deserialize( reader );

		int version = reader.ReadInt();

        if (reader.ReadBool())
        {
            m_MyReward = (MyReward)reader.ReadItem();

            m_Vendor = (IMyRewardVendor)reader.ReadMobile(); 
            
            try { SetOPL(m_MyReward); } 
            catch { }
        }                       
	}

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

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

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

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

            writer.WriteItem((MyReward)m_MyReward);
           
            writer.Write((Mobile)m_Vendor.GetMobile());
        }       
	}
}
public class ViewItemGump : Gump
{
    IMyRewardVendor m_Vendor;
    MyReward m_MyReward;

    public ViewItemGump(Mobile m, IMyRewardVendor vendor, MyReward r, bool viewItem)
        : base(0, 0)
    {
        m_Vendor = vendor;
        m_MyReward = 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.MyRewardInfo.ItemID, r.MyRewardInfo.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
                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_MyReward.Cost.ToString());
            AddLabel(249, 398, 69, @"You have: " + m_Vendor.Payment.Value(m));

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

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

        if (dbox != null)
            dbox.DisplayTo(m, m_MyReward);
    }
    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_MyReward.InStock(1))
                    {
                        if (curr.Purchase(m, m_MyReward.Cost))
                        {
                            m_MyReward.RegisterBuy(1);

                            Item i = m_MyReward.MyRewardCopy;

                            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_MyReward.Title, m_MyReward.Cost, curr.PayName);

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

                    break;
                }
            case 3:
                {
                    if (m.Backpack != null)
                        m.AddToBackpack(new Exhibit(m_Vendor, m_MyReward));
                    break;
                }
            case 4:
                {
                    m.SendGump(new EditItemGump(m_Vendor, m_MyReward, 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
{
    IMyRewardVendor m_Vendor; //used in case of copy

    public WorldVendorsGump(IMyRewardVendor 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;

            IMyRewardVendor source = (IMyRewardVendor)store[0];
            IMyRewardVendor target = (IMyRewardVendor)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
            {
                IMyRewardVendor selected = WorldMyRewardVendors.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 
            {
                IMyRewardVendor v = WorldMyRewardVendors.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 < WorldMyRewardVendors.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, WorldMyRewardVendors.Vendors[i].GetName());
            AddImageTiled(86, yPos + 93, 359, 2, 96);
            AddItem(110, yPos + 27, 8461);
            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 IMyRewardVendor m_Vendor;
   
    public ControlPanelGump(Mobile m, IMyRewardVendor 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(73, 259, 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");

        AddButton(72, 91, 4011, 4012, 5, GumpButtonType.Reply, 0); //Displays
        AddLabel(109, 93, 55, @"Get All Displays");
       
        AddLabel(51, 303, 43, @"Consume Item");
        AddRadio(15, 300, 9720, 9724, false, 6);
        AddLabel(50, 349, 43, @"[props of (Item/Player)");
        AddRadio(15, 342, 9720, 9724, false, 7);
        AddImageTiled(12, 382, 156, 22, 5058);
        AddTextEntry(12, 382, 149, 20, 41, 0, @"[prop 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)) // 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(7)) //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);
                            }
                            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 (MyReward r in m_Vendor.MyRewards)
                    {
                        c.DropItem(new Exhibit(m_Vendor, r));
                    }

                    m.AddToBackpack(c);

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

                        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 + 6), 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, IMyRewardVendorGump
    {
        m_Menus.Add(menu.GetType());
    }
    
    public static void Display(IMyRewardVendorGump menu, Mobile m, IMyRewardVendor vendor)
    {
        m.CloseGump(typeof(IMyRewardVendorGump));

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

        //create reward displays
        foreach (MyReward r in vendor.MyRewards)
        {
            //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, IMyRewardVendor 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((IMyRewardVendorGump)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 : JewlMyRewardGump
{
    private int m_ButtonNum;

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

        //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 DeleteMyReward_Callback(Mobile from, bool okay, object state)
    {
        if (from.AccessLevel < AccessLevel.GameMaster)
            return;

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

            IMyRewardVendor vendor = (IMyRewardVendor)store[0];
            MyReward MyReward = (MyReward)store[1];

            try { vendor.RemoveMyReward(MyReward); }
            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
                {
                    MyReward r = Vendor.MyRewards[(info.ButtonID / 2) - 1];

                    //params -> (vendor, MyReward)
                    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(DeleteMyReward_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.MyRewards[((info.ButtonID + 1) / 2) - 1], true));
            }
            catch { m.SendMessage("Vendor could not be found"); }
        }
        
    }
    
}
public class JewlMyRewardGump : Gump, IMyRewardVendorGump
{
    private int m_PageNum;
    private int m_EntryNum;
    private int m_PosY;
    private IMyRewardVendor m_Vendor;
    private Mobile m_Mobile;
    private int m_CurrencyAmnt;
   
    public static void Initialize()
    {
        MenuUploader.RegisterMenu(new JewlMyRewardGump());
    }

    public JewlMyRewardGump()
        : base(0, 0)
    {
        m_PageNum = 1;
        m_EntryNum = 1;
        m_PosY = 130;
        m_Vendor = null;
        m_Mobile = null;
        m_CurrencyAmnt = 0;
    }
    public JewlMyRewardGump(IMyRewardVendor 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 IMyRewardVendor 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 IMyRewardVendorGump.Send(Mobile m) { SendControl(m); }
    void IMyRewardVendorGump.CreateBackground() { CreateBackgroundControl(); } 
    void IMyRewardVendorGump.AddEntry(MyReward 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(MyReward r)
    {
        ImageTileButtonInfo b = new ItemTileButtonInfo(r.MyRewardInfo);

        //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, r.Display.Header);
        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.MyRewards[info.ButtonID - 1], true));
        }
        catch { m.SendMessage("Vendor could not be found"); }
    }
}

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

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

    public MetalBox this[MyReward 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<MyReward, MetalBox>();
    }
    public DisplayBox(MyRewardCollection rc)
        : this()
    {
        CreateEntries(rc);
    }
    public bool Contains(MyReward 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, MyReward 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(MyRewardCollection rc)
    {
        foreach (MyReward r in rc)
        {
            this.AddDisplay(r, r.MyRewardInfo);
        }
    }
    public void AddDisplay(MyReward 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(MyReward r)
    {
        AddDisplay(r, r.MyRewardInfo);
    }
    public void RemoveDisplay(MyReward 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<MyReward, MetalBox>();
            m_Boxes.Add(new MyReward(), new MetalBox());
            count = m_Boxes.Count;
        }
        writer.Write((int)count);

        foreach (KeyValuePair<MyReward, MetalBox> kvp in m_Boxes)
        {
            writer.Write((MyReward)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<MyReward, MetalBox>();     
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                MyReward r = (MyReward)reader.ReadItem();
                MetalBox box = (MetalBox)reader.ReadItem();

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

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

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

    public override void OnClick()
    {
        try
        {
            MenuUploader.Display((IMyRewardVendorGump)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, IMyRewardVendorGump
{
    private IMyRewardVendor 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 MyRewardList { 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(IMyRewardVendor 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(IMyRewardVendor vendor)
    {
        BaseVendor validVendor = null;

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

        return validVendor;
    }
    void IMyRewardVendorGump.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 IMyRewardVendorGump.AddEntry(MyReward r)
    {
        m_List.Add(new BuyItemState(r.Title, m_BVendor.BuyPack.Serial, r.Serial, r.Cost, (r.Restock == null ? 20 : r.Restock.Count), r.MyRewardInfo.ItemID, r.MyRewardInfo.Hue));

        m_Opls.Add(r.Display);      
    }
    void IMyRewardVendorGump.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 MobileMyRewardVendor : Banker, IMyRewardVendor 
{
    private Currency m_Currency;
    private MyRewardCollection m_MyRewards;
    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 IMyRewardVendor.Payment
    {
        get { return m_Currency; }
        set { m_Currency = value; }
    }
    MyRewardCollection IMyRewardVendor.MyRewards
    {
        get { return m_MyRewards; }
        set { m_MyRewards = value; }
    }
    Type IMyRewardVendor.Menu
    {
        get { return m_Menu; }
        set { m_Menu = value;  }
    }
    DisplayBox IMyRewardVendor.Display
    {
        get { return m_Box; }
    }
    [Constructable]
    public MobileMyRewardVendor() : base()
    {
        m_IsBanker = true;

        //default is Gold
        m_Currency = new Currency();
        m_MyRewards = new MyRewardCollection();
        m_Menu = typeof(JewlMyRewardGump);
        m_Box = new DisplayBox();

        //add to world collection
        WorldMyRewardVendors.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 IMyRewardVendor.GetMobile()
    {
        return this;
    }
    Item IMyRewardVendor.GetItem()
    {
        return null;
    }
   
    bool IMyRewardVendor.IsRemoved()
    {
        return this.Deleted;
    }
    Container IMyRewardVendor.GetContainer()
    {
        return this.Backpack;
    }
    string IMyRewardVendor.GetName()
    {
        return this.Name;
    }
    Map IMyRewardVendor.GetMap()
    {
        return this.Map;
    }
    Point3D IMyRewardVendor.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 IMyRewardVendor.AddMyReward(MyReward r)
    {
        m_Box.AddDisplay(r);
        m_MyRewards.Add(r);
    }
    void IMyRewardVendor.RemoveMyReward(MyReward r)
    {
        m_MyRewards.Remove(r);
        m_Box.RemoveDisplay(r);
    }
    
    void IMyRewardVendor.CopyVendor(IMyRewardVendor vendor)
    {
        Item currBox = this.Backpack.FindItemByType(typeof(DisplayBox));
        currBox.Delete();

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

        m_MyRewards = (MyRewardCollection)((vendor.MyRewards as ICloneable).Clone());
        m_Box = new DisplayBox(m_MyRewards);

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

                MyReward r = item as MyReward;

                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<MyReward, int> kvp in purchases)
            {
                kvp.Key.RegisterBuy(kvp.Value);

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

                    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((IMyRewardVendorGump)Activator.CreateInstance(m_Menu, new object[] { (IMyRewardVendor)this, from }), from, (IMyRewardVendor)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 MobileMyRewardVendor( 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_MyRewards.Count;
        writer.Write((int)count);

        if ( count > 0 )
        {
            for (int i = 0; i < count; i++)
            {
                writer.WriteItem((MyReward)m_MyRewards[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 );

        WorldMyRewardVendors.RegisterVendor(this);

		int version = reader.ReadInt();
        
        m_MyRewards = new MyRewardCollection();

        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++)
                        {
                            MyReward r = (MyReward)reader.ReadItem();
                            m_MyRewards.Add(r);
                        }
                    }

                    m_Currency = (Currency)reader.ReadItem();

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

                    m_Box = (DisplayBox)reader.ReadItem();

                    break;
                }
        }
	}
}
public class StoneMyRewardVendor : DisplayBox
{
    [Constructable]
    public StoneMyRewardVendor()
        : base()
    {
        this.Movable = false;
    }

    public override void OnDoubleClick(Mobile m)
    {
    }
    public StoneMyRewardVendor(Serial serial)
        : base(serial)
    {
    }

    public override void Serialize(GenericWriter writer)
    {
        writer.Write((int)0); //Version 0
    }

    public override void Deserialize(GenericReader reader)
    {
        int version = reader.ReadInt();
    }
}
public interface IMyRewardVendor
{
    //used to determine how player pays
    Currency Payment { get; set; }
    //to keep added items
    MyRewardCollection MyRewards { 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 AddMyReward(MyReward r);
    void RemoveMyReward(MyReward r);
    
    //to create vendor clones
    void CopyVendor(IMyRewardVendor vendor);
}
public interface IMyRewardVendorGump
{
    void Send(Mobile m);
    void AddEntry(MyReward r);
    void CreateBackground();
    
    //add entry || background || 
}


public class PaymentTarget : Target
{
    private string m_PropertyName;
    private IMyRewardVendor m_Vendor;

    public PaymentTarget()
        : base(2, false, TargetFlags.None)
    {
    }
    //by item
    public PaymentTarget(IMyRewardVendor vendor) : this ()
	{
        m_Vendor = vendor;
        m_PropertyName = null;
    }
    //by item property
    public PaymentTarget(IMyRewardVendor vendor, string propName) : this()
    {
        m_Vendor = vendor;
        m_PropertyName = propName;
    }
    protected override void OnTarget(Mobile m, object targeted)
    {
        if ( targeted is Item )
        {
            //consume by item
            if (m_PropertyName == 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_PropertyName == 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 Property's name correctly, "
                        + "it IS case sensitive.";
        try
        {
            if (o != null)//Item
            {
                PropertyInfo pi = o.GetType().GetProperty(m_PropertyName);

                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_PropertyName);

                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
{
    IMyRewardVendor m_Vendor;

    public AddItemTarget() : base( 2, false, TargetFlags.None )
	{
	}
    public AddItemTarget(IMyRewardVendor 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 MyReward(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") );
    }
   
}

Sorry for bringing up an old thread. Trying to start another shard and doing so, updating a few scripts that have been modified since I've been gone.
 
Top