diff --git a/ShiftOS.Objects/Shop.cs b/ShiftOS.Objects/Shop.cs
index 36c15a7..f91f086 100644
--- a/ShiftOS.Objects/Shop.cs
+++ b/ShiftOS.Objects/Shop.cs
@@ -14,7 +14,7 @@ namespace ShiftOS.Objects
         public string Owner { get; set; }
     }
 
-    public abstract class ShopItem
+    public class ShopItem
     {
         public string Name { get; set; }
         public string Description { get; set; }
diff --git a/ShiftOS.WinForms/Applications/MUDControlCentre.Designer.cs b/ShiftOS.WinForms/Applications/MUDControlCentre.Designer.cs
index ad8b042..40a7f56 100644
--- a/ShiftOS.WinForms/Applications/MUDControlCentre.Designer.cs
+++ b/ShiftOS.WinForms/Applications/MUDControlCentre.Designer.cs
@@ -138,7 +138,7 @@ namespace ShiftOS.WinForms.Applications
             this.btnsaveshop = new System.Windows.Forms.Button();
             this.label16 = new System.Windows.Forms.Label();
             this.panel9 = new System.Windows.Forms.Panel();
-            this.listBox1 = new System.Windows.Forms.ListBox();
+            this.lbeditingshopitems = new System.Windows.Forms.ListBox();
             this.flowLayoutPanel5 = new System.Windows.Forms.FlowLayoutPanel();
             this.btnaddshopitem = new System.Windows.Forms.Button();
             this.btnremoveitem = new System.Windows.Forms.Button();
@@ -1094,7 +1094,7 @@ namespace ShiftOS.WinForms.Applications
             // 
             // panel9
             // 
-            this.panel9.Controls.Add(this.listBox1);
+            this.panel9.Controls.Add(this.lbeditingshopitems);
             this.panel9.Controls.Add(this.txtshopname);
             this.panel9.Controls.Add(this.flowLayoutPanel5);
             this.panel9.Cursor = System.Windows.Forms.Cursors.Default;
@@ -1104,14 +1104,14 @@ namespace ShiftOS.WinForms.Applications
             this.panel9.Size = new System.Drawing.Size(389, 442);
             this.panel9.TabIndex = 0;
             // 
-            // listBox1
+            // lbeditingshopitems
             // 
-            this.listBox1.Dock = System.Windows.Forms.DockStyle.Fill;
-            this.listBox1.FormattingEnabled = true;
-            this.listBox1.Location = new System.Drawing.Point(0, 20);
-            this.listBox1.Name = "listBox1";
-            this.listBox1.Size = new System.Drawing.Size(389, 393);
-            this.listBox1.TabIndex = 2;
+            this.lbeditingshopitems.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.lbeditingshopitems.FormattingEnabled = true;
+            this.lbeditingshopitems.Location = new System.Drawing.Point(0, 20);
+            this.lbeditingshopitems.Name = "lbeditingshopitems";
+            this.lbeditingshopitems.Size = new System.Drawing.Size(389, 393);
+            this.lbeditingshopitems.TabIndex = 2;
             // 
             // flowLayoutPanel5
             // 
@@ -1150,6 +1150,7 @@ namespace ShiftOS.WinForms.Applications
             this.btnremoveitem.TabIndex = 2;
             this.btnremoveitem.Text = "Remove";
             this.btnremoveitem.UseVisualStyleBackColor = true;
+            this.btnremoveitem.Click += new System.EventHandler(this.btnremoveitem_Click);
             // 
             // btnedititem
             // 
@@ -1162,6 +1163,7 @@ namespace ShiftOS.WinForms.Applications
             this.btnedititem.TabIndex = 3;
             this.btnedititem.Text = "Edit";
             this.btnedititem.UseVisualStyleBackColor = true;
+            this.btnedititem.Click += new System.EventHandler(this.btnedititem_Click);
             // 
             // txtshopname
             // 
@@ -1339,7 +1341,7 @@ namespace ShiftOS.WinForms.Applications
         private System.Windows.Forms.Button btnsaveshop;
         private System.Windows.Forms.Label label16;
         private System.Windows.Forms.Panel panel9;
-        private System.Windows.Forms.ListBox listBox1;
+        private System.Windows.Forms.ListBox lbeditingshopitems;
         private System.Windows.Forms.TextBox txtshopname;
         private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel5;
         private System.Windows.Forms.Button btnaddshopitem;
diff --git a/ShiftOS.WinForms/Applications/MUDControlCentre.cs b/ShiftOS.WinForms/Applications/MUDControlCentre.cs
index 443d6cf..90c0021 100644
--- a/ShiftOS.WinForms/Applications/MUDControlCentre.cs
+++ b/ShiftOS.WinForms/Applications/MUDControlCentre.cs
@@ -683,7 +683,42 @@ Current legions: {legionname}";
 
         private void btnaddshopitem_Click(object sender, EventArgs e)
         {
+            AppearanceManager.SetupWindow(new ShopItemCreator(new ShopItem(), new Action<ShopItem>((item) =>
+            {
+                editingShop.Items.Add(item);
+            })));
+        }
 
+        private void btnremoveitem_Click(object sender, EventArgs e)
+        {
+            try
+            {
+                int i = lbeditingshopitems.SelectedIndex;
+                editingShop.Items.RemoveAt(i);
+                PopulateShopEditor();
+            }
+            catch
+            {
+
+            }
+        }
+
+        private void btnedititem_Click(object sender, EventArgs e)
+        {
+            try
+            {
+                int i = lbeditingshopitems.SelectedIndex;
+                AppearanceManager.SetupWindow(new ShopItemCreator(editingShop.Items[i], new Action<ShopItem>((item) =>
+                {
+                    editingShop.Items[i] = item;
+                })));
+
+                PopulateShopEditor();
+            }
+            catch
+            {
+
+            }
         }
     }
 }
diff --git a/ShiftOS.WinForms/Applications/ShopItemCreator.Designer.cs b/ShiftOS.WinForms/Applications/ShopItemCreator.Designer.cs
new file mode 100644
index 0000000..9939fca
--- /dev/null
+++ b/ShiftOS.WinForms/Applications/ShopItemCreator.Designer.cs
@@ -0,0 +1,173 @@
+namespace ShiftOS.WinForms.Applications
+{
+    partial class ShopItemCreator
+    {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        /// <summary> 
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.txtitemname = new System.Windows.Forms.TextBox();
+            this.txtfilename = new System.Windows.Forms.TextBox();
+            this.btnbrowse = new System.Windows.Forms.Button();
+            this.btndone = new System.Windows.Forms.Button();
+            this.txtdescription = new System.Windows.Forms.TextBox();
+            this.txtcost = new System.Windows.Forms.TextBox();
+            this.label1 = new System.Windows.Forms.Label();
+            this.label2 = new System.Windows.Forms.Label();
+            this.label3 = new System.Windows.Forms.Label();
+            this.label4 = new System.Windows.Forms.Label();
+            this.SuspendLayout();
+            // 
+            // txtitemname
+            // 
+            this.txtitemname.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtitemname.Location = new System.Drawing.Point(91, 21);
+            this.txtitemname.Name = "txtitemname";
+            this.txtitemname.Size = new System.Drawing.Size(421, 20);
+            this.txtitemname.TabIndex = 0;
+            // 
+            // txtfilename
+            // 
+            this.txtfilename.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtfilename.Location = new System.Drawing.Point(91, 47);
+            this.txtfilename.Name = "txtfilename";
+            this.txtfilename.ReadOnly = true;
+            this.txtfilename.Size = new System.Drawing.Size(334, 20);
+            this.txtfilename.TabIndex = 1;
+            // 
+            // btnbrowse
+            // 
+            this.btnbrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+            this.btnbrowse.Location = new System.Drawing.Point(431, 47);
+            this.btnbrowse.Name = "btnbrowse";
+            this.btnbrowse.Size = new System.Drawing.Size(75, 23);
+            this.btnbrowse.TabIndex = 2;
+            this.btnbrowse.Text = "Browse";
+            this.btnbrowse.UseVisualStyleBackColor = true;
+            this.btnbrowse.Click += new System.EventHandler(this.btnbrowse_Click);
+            // 
+            // btndone
+            // 
+            this.btndone.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.btndone.Location = new System.Drawing.Point(453, 324);
+            this.btndone.Name = "btndone";
+            this.btndone.Size = new System.Drawing.Size(75, 23);
+            this.btndone.TabIndex = 3;
+            this.btndone.Text = "Done";
+            this.btndone.UseVisualStyleBackColor = true;
+            this.btndone.Click += new System.EventHandler(this.btndone_Click);
+            // 
+            // txtdescription
+            // 
+            this.txtdescription.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtdescription.Location = new System.Drawing.Point(91, 86);
+            this.txtdescription.Multiline = true;
+            this.txtdescription.Name = "txtdescription";
+            this.txtdescription.Size = new System.Drawing.Size(421, 143);
+            this.txtdescription.TabIndex = 4;
+            // 
+            // txtcost
+            // 
+            this.txtcost.Location = new System.Drawing.Point(91, 255);
+            this.txtcost.Name = "txtcost";
+            this.txtcost.Size = new System.Drawing.Size(100, 20);
+            this.txtcost.TabIndex = 5;
+            this.txtcost.TextChanged += new System.EventHandler(this.txtcost_TextChanged);
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(14, 27);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(59, 13);
+            this.label1.TabIndex = 6;
+            this.label1.Text = "Item name:";
+            // 
+            // label2
+            // 
+            this.label2.AutoSize = true;
+            this.label2.Location = new System.Drawing.Point(14, 50);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(26, 13);
+            this.label2.TabIndex = 7;
+            this.label2.Text = "File:";
+            // 
+            // label3
+            // 
+            this.label3.AutoSize = true;
+            this.label3.Location = new System.Drawing.Point(14, 89);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(63, 13);
+            this.label3.TabIndex = 8;
+            this.label3.Text = "Description:";
+            // 
+            // label4
+            // 
+            this.label4.AutoSize = true;
+            this.label4.Location = new System.Drawing.Point(14, 258);
+            this.label4.Name = "label4";
+            this.label4.Size = new System.Drawing.Size(54, 13);
+            this.label4.TabIndex = 9;
+            this.label4.Text = "Cost (CP):";
+            // 
+            // ShopItemCreator
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.Controls.Add(this.label4);
+            this.Controls.Add(this.label3);
+            this.Controls.Add(this.label2);
+            this.Controls.Add(this.label1);
+            this.Controls.Add(this.txtcost);
+            this.Controls.Add(this.txtdescription);
+            this.Controls.Add(this.btndone);
+            this.Controls.Add(this.btnbrowse);
+            this.Controls.Add(this.txtfilename);
+            this.Controls.Add(this.txtitemname);
+            this.Name = "ShopItemCreator";
+            this.Size = new System.Drawing.Size(531, 350);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.TextBox txtitemname;
+        private System.Windows.Forms.TextBox txtfilename;
+        private System.Windows.Forms.Button btnbrowse;
+        private System.Windows.Forms.Button btndone;
+        private System.Windows.Forms.TextBox txtdescription;
+        private System.Windows.Forms.TextBox txtcost;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.Label label3;
+        private System.Windows.Forms.Label label4;
+    }
+}
diff --git a/ShiftOS.WinForms/Applications/ShopItemCreator.cs b/ShiftOS.WinForms/Applications/ShopItemCreator.cs
new file mode 100644
index 0000000..cc43cf7
--- /dev/null
+++ b/ShiftOS.WinForms/Applications/ShopItemCreator.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using ShiftOS.Engine;
+using ShiftOS.Objects;
+using ShiftOS.Objects.ShiftFS;
+
+namespace ShiftOS.WinForms.Applications
+{
+    [DefaultTitle("Shop item editor")]
+    [MultiplayerOnly]
+    [DefaultIcon("iconSysInfo")]
+    public partial class ShopItemCreator : UserControl, IShiftOSWindow
+    {
+        public ShopItemCreator(ShopItem item, Action<ShopItem> callback)
+        {
+            InitializeComponent();
+            Callback = callback;
+            Item = item;
+            txtitemname.Text = Item.Name;
+            txtdescription.Text = Item.Description;
+            txtcost.Text = Item.Cost.ToString();
+            txtfilename.Text = "Unselected";
+        }
+
+        private Action<ShopItem> Callback { get; set; }
+        public ShopItem Item { get; private set; }
+
+        private void btnbrowse_Click(object sender, EventArgs e)
+        {
+            FileSkimmerBackend.GetFile(new[] { "" }, FileOpenerStyle.Open, new Action<string>((result) =>
+            {
+                txtfilename.Text = result;
+                Item.MUDFile = Utils.ReadAllBytes(result);
+                Item.FileType = (int)FileSkimmerBackend.GetFileType(result);
+            }));
+        }
+
+        private void btndone_Click(object sender, EventArgs e)
+        {
+            if(Item.MUDFile == null)
+            {
+                Infobox.Show("No file chosen.", "Please select a file to sell.");
+                return;
+            }
+            Item.Cost = Convert.ToInt32(txtcost.Text);
+            Item.Description = txtdescription.Text;
+            Item.Name = txtitemname.Text;
+            Callback?.Invoke(Item);
+            AppearanceManager.Close(this);
+        }
+
+        public void OnLoad()
+        {
+        }
+
+        public void OnSkinLoad()
+        {
+        }
+
+        public bool OnUnload()
+        {
+            return true;
+        }
+
+        public void OnUpgrade()
+        {
+        }
+
+        private void txtcost_TextChanged(object sender, EventArgs e)
+        {
+            try
+            {
+                Item.Cost = Convert.ToInt32(txtcost.Text);
+            }
+            catch
+            {
+                txtcost.Text = Item.Cost.ToString();
+            }
+        }
+    }
+}
diff --git a/ShiftOS.WinForms/Applications/ShopItemCreator.resx b/ShiftOS.WinForms/Applications/ShopItemCreator.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/ShiftOS.WinForms/Applications/ShopItemCreator.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/ShiftOS.WinForms/ShiftOS.WinForms.csproj b/ShiftOS.WinForms/ShiftOS.WinForms.csproj
index e836119..266728a 100644
--- a/ShiftOS.WinForms/ShiftOS.WinForms.csproj
+++ b/ShiftOS.WinForms/ShiftOS.WinForms.csproj
@@ -147,6 +147,12 @@
     <Compile Include="Applications\ShiftoriumFrontend.Designer.cs">
       <DependentUpon>ShiftoriumFrontend.cs</DependentUpon>
     </Compile>
+    <Compile Include="Applications\ShopItemCreator.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Applications\ShopItemCreator.Designer.cs">
+      <DependentUpon>ShopItemCreator.cs</DependentUpon>
+    </Compile>
     <Compile Include="Applications\Skin Loader.cs">
       <SubType>UserControl</SubType>
     </Compile>
@@ -265,6 +271,9 @@
     <EmbeddedResource Include="Applications\ShiftoriumFrontend.resx">
       <DependentUpon>ShiftoriumFrontend.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="Applications\ShopItemCreator.resx">
+      <DependentUpon>ShopItemCreator.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="Applications\Skin Loader.resx">
       <DependentUpon>Skin Loader.cs</DependentUpon>
     </EmbeddedResource>