diff --git a/src/main/java/com/comandante/creeper/command/commands/LootCommand.java b/src/main/java/com/comandante/creeper/command/commands/LootCommand.java
index eddfc026f4e4c32619edec0c8e6c8e1d0ee0d588..2543a967acafdce8e40ba6d57b681f7ae48cb36a 100644
--- a/src/main/java/com/comandante/creeper/command/commands/LootCommand.java
+++ b/src/main/java/com/comandante/creeper/command/commands/LootCommand.java
@@ -28,7 +28,7 @@ public class LootCommand extends Command {
         execCommand(ctx, e, () -> {
             if (originalMessageParts.size() > 1) {
                 for (Item item : player.getInventory()) {
-                    if (item.getItemTypeId() == Item.CORPSE_ID_RESERVED) {
+                    if (item.getInternalItemName().equals(Item.CORPSE_INTENAL_NAME)) {
                         Loot loot = item.getLoot();
                         if (loot != null) {
                             long gold = lootManager.lootGoldAmountReturn(loot);
diff --git a/src/main/java/com/comandante/creeper/command/commands/MovementCommand.java b/src/main/java/com/comandante/creeper/command/commands/MovementCommand.java
index 0fcd8f9f2df401b97e87d2741a1a3e31d878fc33..db8fe77f02034e83473182c4c5a1ef281cbb4b4d 100644
--- a/src/main/java/com/comandante/creeper/command/commands/MovementCommand.java
+++ b/src/main/java/com/comandante/creeper/command/commands/MovementCommand.java
@@ -1,7 +1,7 @@
 package com.comandante.creeper.command.commands;
 
-import com.comandante.creeper.items.Effect;
 import com.comandante.creeper.core_game.GameManager;
+import com.comandante.creeper.items.Effect;
 import com.comandante.creeper.player.CoolDownType;
 import com.comandante.creeper.player.PlayerMetadata;
 import com.comandante.creeper.player.PlayerMovement;
@@ -53,12 +53,7 @@ public class MovementCommand extends Command {
             if (!playerMetadataOptional.isPresent()) {
                 return;
             }
-            for (String effectId : playerMetadataOptional.get().getEffects()) {
-                java.util.Optional<Effect> effectOptional = gameManager.getEntityManager().getEffectEntity(effectId);
-                if (!effectOptional.isPresent()) {
-                    continue;
-                }
-                Effect effect = effectOptional.get();
+            for (Effect effect : playerMetadataOptional.get().getEffects()) {
                 if (effect.isFrozenMovement()) {
                     MovementCommand.this.write("You are frozen and can not move.");
                     return;
diff --git a/src/main/java/com/comandante/creeper/command/commands/admin/LoadItemCommand.java b/src/main/java/com/comandante/creeper/command/commands/admin/LoadItemCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a4e1719cbb27c2a8506f81af78de347dd801502
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/command/commands/admin/LoadItemCommand.java
@@ -0,0 +1,99 @@
+package com.comandante.creeper.command.commands.admin;
+
+import com.comandante.creeper.command.commands.Command;
+import com.comandante.creeper.core_game.GameManager;
+import com.comandante.creeper.items.ItemMetadata;
+import com.comandante.creeper.player.PlayerRole;
+import com.google.common.collect.Sets;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.util.EntityUtils;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.MessageEvent;
+
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+public class LoadItemCommand extends Command {
+
+    final static List<String> validTriggers = Arrays.asList("loaditem");
+    final static String description = "Load an Item using JSON over http.";
+    final static String correctUsage = "loaditem <http url with json for item>";
+    final static Set<PlayerRole> roles = Sets.newHashSet(PlayerRole.ADMIN);
+
+    public LoadItemCommand(GameManager gameManager) {
+        super(gameManager, validTriggers, description, correctUsage, roles);
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        execCommand(ctx, e, () -> {
+
+            if (originalMessageParts.size() <= 1) {
+                write("Please specify a http url." + "\r\n");
+                return;
+            }
+
+            originalMessageParts.remove(0);
+
+
+            String itemJsonUrl = originalMessageParts.get(0);
+            if (!isValidURL(itemJsonUrl)) {
+                write("Invalid HTTP address." + "\r\n");
+                return;
+            }
+
+            HttpGet httpGet = new HttpGet(itemJsonUrl);
+
+            HttpClient httpclient = gameManager.getHttpclient();
+
+            HttpResponse httpResponse = httpclient.execute(httpGet);
+
+            HttpEntity entity = httpResponse.getEntity();
+
+            if (entity == null) {
+                write("Error retrieving JSON url." + "\r\n");
+                return;
+            }
+
+            String npcJson = EntityUtils.toString(entity);
+
+            ItemMetadata itemMetadata = null;
+            try {
+                itemMetadata = gameManager.getGson().fromJson(npcJson, ItemMetadata.class);
+            } catch (Exception ex) {
+                write("Retrieved JSON file is malformed. " + ex.getLocalizedMessage() + "\r\n");
+                return;
+            }
+            httpGet.reset();
+
+            gameManager.getItemStorage().saveItemMetadata(itemMetadata);
+            write("Item Saved. - " + itemMetadata.getInternalItemName() + "\r\n");
+
+        });
+    }
+
+    public boolean isValidURL(String url) {
+        URL u = null;
+        try {
+            u = new URL(url);
+        } catch (MalformedURLException e) {
+            return false;
+        }
+        try {
+            u.toURI();
+        } catch (URISyntaxException e) {
+            return false;
+        }
+        return true;
+    }
+
+}
+
+
diff --git a/src/main/java/com/comandante/creeper/command/commands/admin/LoadMerchantCommand.java b/src/main/java/com/comandante/creeper/command/commands/admin/LoadMerchantCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3cb14f96c833ec3b60aedd902b536412f94d2bf
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/command/commands/admin/LoadMerchantCommand.java
@@ -0,0 +1,98 @@
+package com.comandante.creeper.command.commands.admin;
+
+import com.comandante.creeper.command.commands.Command;
+import com.comandante.creeper.core_game.GameManager;
+import com.comandante.creeper.merchant.MerchantMetadata;
+import com.comandante.creeper.player.PlayerRole;
+import com.google.common.collect.Sets;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.util.EntityUtils;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.MessageEvent;
+
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+public class LoadMerchantCommand extends Command {
+
+    final static List<String> validTriggers = Arrays.asList("loadmerchant");
+    final static String description = "Load a Merchant using JSON over http";
+    final static String correctUsage = "loadmerchant <http url with json for npc>";
+    final static Set<PlayerRole> roles = Sets.newHashSet(PlayerRole.ADMIN);
+
+    public LoadMerchantCommand(GameManager gameManager) {
+        super(gameManager, validTriggers, description, correctUsage, roles);
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        execCommand(ctx, e, () -> {
+
+            if (originalMessageParts.size() <= 1) {
+                write("Please specify a http url." + "\r\n");
+                return;
+            }
+
+            originalMessageParts.remove(0);
+
+
+            String npcJsonHttpUrl = originalMessageParts.get(0);
+            if (!isValidURL(npcJsonHttpUrl)) {
+                write("Invalid HTTP address." + "\r\n");
+                return;
+            }
+
+            HttpGet httpGet = new HttpGet(npcJsonHttpUrl);
+
+            HttpClient httpclient = gameManager.getHttpclient();
+
+            HttpResponse httpResponse = httpclient.execute(httpGet);
+
+            HttpEntity entity = httpResponse.getEntity();
+
+            if (entity == null) {
+                write("Error retrieving JSON url." + "\r\n");
+                return;
+            }
+
+            String npcJson = EntityUtils.toString(entity);
+
+            MerchantMetadata merchantMetadata = null;
+            try {
+                merchantMetadata = gameManager.getGson().fromJson(npcJson, MerchantMetadata.class);
+            } catch (Exception ex) {
+                write("Retrieved JSON file is malformed. " + ex.getLocalizedMessage() + "\r\n");
+                return;
+            }
+            httpGet.reset();
+
+            gameManager.getMerchantStorage().saveMerchantMetadata(merchantMetadata);
+            write("Merchant Saved. - " + merchantMetadata.getInternalName() + "\r\n");
+
+        });
+    }
+
+    public boolean isValidURL(String url) {
+        URL u = null;
+        try {
+            u = new URL(url);
+        } catch (MalformedURLException e) {
+            return false;
+        }
+        try {
+            u.toURI();
+        } catch (URISyntaxException e) {
+            return false;
+        }
+        return true;
+    }
+
+}
+
diff --git a/src/main/java/com/comandante/creeper/command/commands/admin/LoadNpcCommand.java b/src/main/java/com/comandante/creeper/command/commands/admin/LoadNpcCommand.java
index ea4aff802ae538e74d9e5ceaf5b0c152e95878e0..f9c13be5060326c2742e8483542f168d592aed12 100644
--- a/src/main/java/com/comandante/creeper/command/commands/admin/LoadNpcCommand.java
+++ b/src/main/java/com/comandante/creeper/command/commands/admin/LoadNpcCommand.java
@@ -23,8 +23,8 @@ import java.util.Set;
 public class LoadNpcCommand extends Command {
 
     final static List<String> validTriggers = Arrays.asList("loadnpc");
-    final static String description = "Load an NPC using JSON.";
-    final static String correctUsage = "loadjpc <http url with json for npc>";
+    final static String description = "Load a NPC using JSON over http";
+    final static String correctUsage = "loadnpc <http url with json for npc>";
     final static Set<PlayerRole> roles = Sets.newHashSet(PlayerRole.ADMIN);
 
     public LoadNpcCommand(GameManager gameManager) {
@@ -45,7 +45,7 @@ public class LoadNpcCommand extends Command {
 
             String npcJsonHttpUrl = originalMessageParts.get(0);
             if (!isValidURL(npcJsonHttpUrl)) {
-                write("Inavlid HTTP address." + "\r\n");
+                write("Invalid HTTP address." + "\r\n");
                 return;
             }
 
diff --git a/src/main/java/com/comandante/creeper/command/commands/admin/SpawnCommand.java b/src/main/java/com/comandante/creeper/command/commands/admin/SpawnCommand.java
index 56efeb85d0f0e640cfb1a4109557772b5b55f566..d14ec2c72b540b1a365310f038b4a630704710f0 100644
--- a/src/main/java/com/comandante/creeper/command/commands/admin/SpawnCommand.java
+++ b/src/main/java/com/comandante/creeper/command/commands/admin/SpawnCommand.java
@@ -2,7 +2,6 @@ package com.comandante.creeper.command.commands.admin;
 
 import com.comandante.creeper.command.commands.Command;
 import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.items.ItemType;
 import com.comandante.creeper.items.Loot;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.npc.NpcBuilder;
@@ -42,7 +41,7 @@ public class SpawnCommand  extends Command {
                 String targetNpc = Joiner.on(" ").join(originalMessageParts);
                 for (Npc npc: npcsFromFile) {
                     if (targetNpc.equals(npc.getName())) {
-                        Loot loot = new Loot(0,0,Sets.<ItemType>newHashSet());
+                        Loot loot = new Loot(0,0, Sets.newHashSet());
                         Npc modifiedNpc = new NpcBuilder(npc).setSpawnRules(null).setLoot(loot).createNpc();
                         modifiedNpc.getStats().setExperience(0);
                         modifiedNpc.setCurrentRoom(currentRoom);
diff --git a/src/main/java/com/comandante/creeper/command/commands/admin/TeleportCommand.java b/src/main/java/com/comandante/creeper/command/commands/admin/TeleportCommand.java
index 8e1d9e28a6c40b13d1ca1992e5945f59ebcd5d84..b6b9b6eaa8f00f9b144ae05883046d449c8717b8 100644
--- a/src/main/java/com/comandante/creeper/command/commands/admin/TeleportCommand.java
+++ b/src/main/java/com/comandante/creeper/command/commands/admin/TeleportCommand.java
@@ -1,9 +1,9 @@
 package com.comandante.creeper.command.commands.admin;
 
 
-import com.comandante.creeper.items.Effect;
 import com.comandante.creeper.command.commands.Command;
 import com.comandante.creeper.core_game.GameManager;
+import com.comandante.creeper.items.Effect;
 import com.comandante.creeper.player.*;
 import com.comandante.creeper.server.player_communication.Color;
 import com.comandante.creeper.world.model.Room;
@@ -45,12 +45,7 @@ public class TeleportCommand extends Command {
                 return;
             }
             PlayerMetadata playerMetadata = playerMetadataOptional.get();
-            for (String effectId : playerMetadata.getEffects()) {
-                Optional<Effect> effectOptional = gameManager.getEntityManager().getEffectEntity(effectId);
-                if (!effectOptional.isPresent()) {
-                    continue;
-                }
-                Effect effect = effectOptional.get();
+            for (Effect effect : playerMetadata.getEffects()) {
                 if (effect.isFrozenMovement()) {
                     write("You are frozen and can not move.");
                     return;
diff --git a/src/main/java/com/comandante/creeper/configuration/ConfigureCommands.java b/src/main/java/com/comandante/creeper/configuration/ConfigureCommands.java
index 82de27fccb8ff5341dfe9237e7f352fcf7a0ed69..1c4b1e0e156ec9bdca9d9afc0ad753fcbf8cdda7 100644
--- a/src/main/java/com/comandante/creeper/configuration/ConfigureCommands.java
+++ b/src/main/java/com/comandante/creeper/configuration/ConfigureCommands.java
@@ -102,5 +102,7 @@ public class ConfigureCommands {
         creeperCommandRegistry.addCommand(new RecallCommand(gameManager));
         creeperCommandRegistry.addCommand(new ToggleChatCommand(gameManager));
         creeperCommandRegistry.addCommand(new LoadNpcCommand(gameManager));
+        creeperCommandRegistry.addCommand(new LoadItemCommand(gameManager));
+        creeperCommandRegistry.addCommand(new LoadMerchantCommand(gameManager));
     }
 }
diff --git a/src/main/java/com/comandante/creeper/configuration/ConfigureNpc.java b/src/main/java/com/comandante/creeper/configuration/ConfigureNpc.java
index 8ee9a597c39157d447783fd9cc0418436bf4398d..4460c42b6e593619558a3cc92c5ad3eabff4c92a 100644
--- a/src/main/java/com/comandante/creeper/configuration/ConfigureNpc.java
+++ b/src/main/java/com/comandante/creeper/configuration/ConfigureNpc.java
@@ -4,22 +4,16 @@ package com.comandante.creeper.configuration;
 import com.comandante.creeper.Main;
 import com.comandante.creeper.core_game.GameManager;
 import com.comandante.creeper.entity.EntityManager;
-import com.comandante.creeper.items.ForageBuilder;
-import com.comandante.creeper.items.ItemType;
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.merchant.*;
+import com.comandante.creeper.items.Forage;
+import com.comandante.creeper.items.ItemMetadata;
+import com.comandante.creeper.merchant.Merchant;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.spawner.ItemSpawner;
 import com.comandante.creeper.spawner.NpcSpawner;
 import com.comandante.creeper.spawner.SpawnRule;
-import com.comandante.creeper.spawner.SpawnRuleBuilder;
-import com.comandante.creeper.world.model.Area;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 
 import java.io.IOException;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 public class ConfigureNpc {
@@ -28,7 +22,7 @@ public class ConfigureNpc {
         EntityManager entityManager = gameManager.getEntityManager();
         List<Npc> npcsFromFile = gameManager.getNpcStorage().getAllNpcs();
         for (Npc npc : npcsFromFile) {
-            Main.startUpMessage("Added " + npc.getName());
+            Main.startUpMessage("Adding npc spawn: " + npc.getName());
             entityManager.addEntity(npc);
             Set<SpawnRule> spawnRules = npc.getSpawnRules();
             for (SpawnRule spawnRule : spawnRules) {
@@ -41,70 +35,28 @@ public class ConfigureNpc {
 
         configureAllNpcs(gameManager);
 
-        Main.startUpMessage("Adding beer");
-        ItemSpawner itemSpawner = new ItemSpawner(ItemType.SMALL_HEALTH_POTION, new SpawnRuleBuilder().setArea(Area.NEWBIE_ZONE).setSpawnIntervalTicks(600).setMaxInstances(100).setMaxPerRoom(5).setRandomPercent(40).createSpawnRule(), gameManager);
-        ItemSpawner itemSpawner1 = new ItemSpawner(ItemType.SMALL_HEALTH_POTION, new SpawnRuleBuilder().setArea(Area.FANCYHOUSE_ZONE).setSpawnIntervalTicks(600).setMaxInstances(12).setMaxPerRoom(2).setRandomPercent(50).createSpawnRule(), gameManager);
-        ItemSpawner itemSpawner2 = new ItemSpawner(ItemType.SMALL_HEALTH_POTION, new SpawnRuleBuilder().setArea(Area.HOUSE_ZONE).setSpawnIntervalTicks(600).setMaxInstances(12).setMaxPerRoom(2).setRandomPercent(50).createSpawnRule(), gameManager);
-        ItemSpawner itemSpawner5 = new ItemSpawner(ItemType.KEY, new SpawnRuleBuilder().setArea(Area.LOBBY).setSpawnIntervalTicks(600).setMaxInstances(1).setMaxPerRoom(1).setRandomPercent(5).createSpawnRule(), gameManager);
+        List<ItemMetadata> allItemMetadata = gameManager.getItemStorage().getAllItemMetadata();
 
-        entityManager.addEntity(itemSpawner);
-        entityManager.addEntity(itemSpawner1);
-        entityManager.addEntity(itemSpawner2);
-        entityManager.addEntity(itemSpawner5);
-
-        Map<Integer, MerchantItemForSale> itemsForSale = Maps.newLinkedHashMap();
-        itemsForSale.put(1, new MerchantItemForSale(ItemType.SMALL_HEALTH_POTION, 8));
-        itemsForSale.put(2, new MerchantItemForSale(ItemType.PURPLE_DRANK, 80));
-        itemsForSale.put(3, new MerchantItemForSale(ItemType.BIGGERS_SKIN_SATCHEL, 25000));
-
-        LloydBartender lloydBartender = new LloydBartender(gameManager, new Loot(18, 26, Sets.<ItemType>newHashSet()), itemsForSale);
-        gameManager.getRoomManager().addMerchant(64, lloydBartender);
-
-        Map<Integer, MerchantItemForSale> nigelForSale = Maps.newLinkedHashMap();
-        nigelForSale.put(1, new MerchantItemForSale(ItemType.SMALL_HEALTH_POTION, 6));
-
-        NigelBartender nigelBartender = new NigelBartender(gameManager, new Loot(18, 26, Sets.<ItemType>newHashSet()), nigelForSale);
-        gameManager.getRoomManager().addMerchant(377, nigelBartender);
-
-        Map<Integer, MerchantItemForSale> blacksmithItems = Maps.newHashMap();
-        blacksmithItems.put(1, new MerchantItemForSale(ItemType.BERSERKER_BATON, 10000));
-        blacksmithItems.put(2, new MerchantItemForSale(ItemType.BERSEKER_BOOTS, 3500));
-        blacksmithItems.put(3, new MerchantItemForSale(ItemType.BERSERKER_BRACERS, 3500));
-        blacksmithItems.put(4, new MerchantItemForSale(ItemType.BERSEKER_HELM, 3500));
-        blacksmithItems.put(5, new MerchantItemForSale(ItemType.BERSERKER_CHEST, 7000));
-        blacksmithItems.put(6, new MerchantItemForSale(ItemType.BERSEKER_SHORTS, 8500));
-        blacksmithItems.put(7, new MerchantItemForSale(ItemType.LEATHER_SATCHEL, 600));
-
-        Blacksmith blacksmith = new Blacksmith(gameManager, new Loot(18, 26, Sets.<ItemType>newHashSet()), blacksmithItems);
-        gameManager.getRoomManager().addMerchant(66, blacksmith);
-        gameManager.getRoomManager().addMerchant(253, blacksmith);
-
-        Map<Integer, MerchantItemForSale> wizarditems = Maps.newHashMap();
-        wizarditems.put(1, new MerchantItemForSale(ItemType.LIGHTNING_SPELLBOOKNG, 50000));
-
-        Wizard wizard = new Wizard(gameManager, new Loot(18, 26, Sets.<ItemType>newHashSet()), wizarditems);
-        gameManager.getRoomManager().addMerchant(98, wizard);
-
-        JimBanker jimBanker = new JimBanker(gameManager, new Loot(18, 26, Sets.<ItemType>newHashSet()), null);
-        gameManager.getRoomManager().addMerchant(65, jimBanker);
-        gameManager.getRoomManager().addMerchant(209, jimBanker);
+        for (ItemMetadata itemMetadata : allItemMetadata) {
+            for (SpawnRule spawnRule : itemMetadata.getSpawnRules()) {
+                Main.startUpMessage("Adding item spawn: " + itemMetadata.getInternalItemName());
+                ItemSpawner itemSpawner = new ItemSpawner(itemMetadata, spawnRule, gameManager);
+                entityManager.addEntity(itemSpawner);
+            }
+        }
 
-        OldWiseMan oldWiseMan = new OldWiseMan(gameManager, new Loot(18, 26, Sets.<ItemType>newHashSet()), null);
-        gameManager.getRoomManager().addMerchant(2, oldWiseMan);
+        for (ItemMetadata itemMetadata : allItemMetadata) {
+            for (Forage forage : itemMetadata.getForages()) {
+                Main.startUpMessage("Adding forage: " + itemMetadata.getInternalItemName());
+                gameManager.getForageManager().addForage(itemMetadata.getInternalItemName(), forage);
+            }
+        }
 
-        LockerRoomGuy lockerRoomGuy = new LockerRoomGuy(gameManager, new Loot(18, 26, Sets.<ItemType>newHashSet()), null);
-        gameManager.getRoomManager().addMerchant(63, lockerRoomGuy);
+        List<Merchant> allMerchantMetadatas = gameManager.getMerchantStorage().getAllMerchants();
+        for (Merchant merchant : allMerchantMetadatas) {
+            Main.startUpMessage("Adding merchant: " + merchant.getInternalName());
+            gameManager.getRoomManager().addMerchant(merchant);
+        }
 
-        ForageBuilder marijuanaForageBuilder = new ForageBuilder();
-        marijuanaForageBuilder.setItemType(ItemType.MARIJUANA);
-        marijuanaForageBuilder.setMinAmt(1);
-        marijuanaForageBuilder.setMaxAmt(3);
-        marijuanaForageBuilder.setPctOfSuccess(40);
-        marijuanaForageBuilder.setForageExperience(4);
-        marijuanaForageBuilder.setCoolDownTicks(600);
-        gameManager.getForageManager().addForageToArea(Area.WESTERN9_ZONE, marijuanaForageBuilder);
-        gameManager.getForageManager().addForageToArea(Area.NORTH3_ZONE, marijuanaForageBuilder);
-        gameManager.getForageManager().addForageToArea(Area.BLOODRIDGE2_ZONE, marijuanaForageBuilder);
-        gameManager.getForageManager().addForageToArea(Area.BLOODRIDGE1_ZONE, marijuanaForageBuilder);
     }
 }
diff --git a/src/main/java/com/comandante/creeper/core_game/GameManager.java b/src/main/java/com/comandante/creeper/core_game/GameManager.java
index 3b4574454a8deb84785faa477da64fd4586b5387..6fb4ea6bb4c6f1e300f468ecd356f45d161309ab 100644
--- a/src/main/java/com/comandante/creeper/core_game/GameManager.java
+++ b/src/main/java/com/comandante/creeper/core_game/GameManager.java
@@ -26,6 +26,9 @@ import com.comandante.creeper.stats.Levels;
 import com.comandante.creeper.stats.Stats;
 import com.comandante.creeper.stats.StatsBuilder;
 import com.comandante.creeper.stats.modifier.StatsModifierFactory;
+import com.comandante.creeper.storage.FilebasedJsonStorage;
+import com.comandante.creeper.storage.ItemStorage;
+import com.comandante.creeper.storage.MerchantStorage;
 import com.comandante.creeper.storage.NpcStorage;
 import com.comandante.creeper.world.FloorManager;
 import com.comandante.creeper.world.MapsManager;
@@ -85,8 +88,17 @@ public class GameManager {
     private final MultiThreadedEventProcessor eventProcessor = new MultiThreadedEventProcessor(new ArrayBlockingQueue<>(10000));
     private final Room detainmentRoom;
     private final NpcStorage npcStorage;
+    private final ItemStorage itemStorage;
     private final HttpClient httpclient;
     private final Gson gson;
+    private final FilebasedJsonStorage filebasedJsonStorage;
+
+    public MerchantStorage getMerchantStorage() {
+        return merchantStorage;
+    }
+
+    private final MerchantStorage merchantStorage;
+
 
     public GameManager(CreeperConfiguration creeperConfiguration, RoomManager roomManager, PlayerManager playerManager, EntityManager entityManager, MapsManager mapsManager, ChannelCommunicationUtils channelUtils, HttpClient httpClient) {
         this.roomManager = roomManager;
@@ -116,7 +128,10 @@ public class GameManager {
         this.eventProcessor.startAsync();
         this.detainmentRoom = buildDetainmentRoom();
         this.gson = new GsonBuilder().setPrettyPrinting().create();
-        this.npcStorage = new NpcStorage(this, gson);
+        this.filebasedJsonStorage = new FilebasedJsonStorage(gson);
+        this.npcStorage = new NpcStorage(this, filebasedJsonStorage);
+        this.itemStorage = new ItemStorage(filebasedJsonStorage);
+        this.merchantStorage = new MerchantStorage(this, filebasedJsonStorage);
         this.httpclient = httpClient;
     }
 
@@ -124,6 +139,10 @@ public class GameManager {
         return gson;
     }
 
+    public ItemStorage getItemStorage() {
+        return itemStorage;
+    }
+
     private Room buildDetainmentRoom() {
         BasicRoomBuilder basicRoomBuilder = new BasicRoomBuilder(this);
 
diff --git a/src/main/java/com/comandante/creeper/entity/EntityManager.java b/src/main/java/com/comandante/creeper/entity/EntityManager.java
index 896602ada7d57b08c7f78284a018dbcdf2e1acf9..885913d4837b3c79b65750ac6460ab986b50d9fa 100644
--- a/src/main/java/com/comandante/creeper/entity/EntityManager.java
+++ b/src/main/java/com/comandante/creeper/entity/EntityManager.java
@@ -2,31 +2,22 @@ package com.comandante.creeper.entity;
 
 import com.comandante.creeper.Main;
 import com.comandante.creeper.core_game.SentryManager;
-import com.comandante.creeper.items.Effect;
-import com.comandante.creeper.player.PlayerMetadata;
-import com.comandante.creeper.stats.Stats;
-import com.comandante.creeper.storage.CreeperStorage;
-import com.comandante.creeper.storage.EffectSerializer;
 import com.comandante.creeper.items.Item;
-import com.comandante.creeper.storage.ItemSerializer;
+import com.comandante.creeper.items.ItemBuilder;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.player.PlayerManager;
+import com.comandante.creeper.storage.CreeperStorage;
 import com.comandante.creeper.world.RoomManager;
 import com.comandante.creeper.world.model.Room;
 import org.apache.log4j.Logger;
-import org.mapdb.DB;
-import org.mapdb.HTreeMap;
-import org.mapdb.Serializer;
 
-import javax.swing.text.html.Option;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.function.Function;
 
 import static com.codahale.metrics.MetricRegistry.name;
 
@@ -84,22 +75,9 @@ public class EntityManager {
         creeperStorage.removeItem(itemId);
     }
 
-    public void saveEffect(Effect effect) {
-        creeperStorage.saveEffect(effect);
-    }
-
-    public void removeEffect(Effect effect) {
-        creeperStorage.removeEffect(effect.getEntityId());
-    }
-
     public Optional<Item> getItemEntity(String itemId) {
         Optional<Item> item = creeperStorage.getItemEntity(itemId);
-        return item.map(Item::new);
-    }
-
-    public Optional<Effect> getEffectEntity(String effectId) {
-        Optional<Effect> effect = creeperStorage.getEffectEntity(effectId);
-        return effect.map(Effect::new);
+        return item.map(itemName -> new ItemBuilder().from(itemName).create());
     }
 
     public void deleteNpcEntity(String npcId) {
diff --git a/src/main/java/com/comandante/creeper/items/Effect.java b/src/main/java/com/comandante/creeper/items/Effect.java
index 995815bb04254e9ec408dc908c9c9c826629a87e..96ebd80f90f014c2e59f5fd74a57244c3ddced77 100644
--- a/src/main/java/com/comandante/creeper/items/Effect.java
+++ b/src/main/java/com/comandante/creeper/items/Effect.java
@@ -1,12 +1,11 @@
 package com.comandante.creeper.items;
 
 
-import com.comandante.creeper.entity.CreeperEntity;
 import com.comandante.creeper.stats.Stats;
 
 import java.util.List;
 
-public class Effect extends CreeperEntity {
+public class Effect {
 
     private final String effectName;
     private final String effectDescription;
@@ -29,11 +28,10 @@ public class Effect extends CreeperEntity {
         this.effectApplications = 0;
     }
 
-        public Effect(Effect effect) {
-            this.setEntityId(effect.getEntityId());
-            this.effectName = effect.effectName;
-            this.effectDescription = effect.effectDescription;
-            this.effectApplyMessages = effect.effectApplyMessages;
+    public Effect(Effect effect) {
+        this.effectName = effect.effectName;
+        this.effectDescription = effect.effectDescription;
+        this.effectApplyMessages = effect.effectApplyMessages;
         this.applyStatsOnTick = effect.applyStatsOnTick;
         this.durationStats = effect.durationStats;
         this.maxEffectApplications = effect.maxEffectApplications;
@@ -41,10 +39,6 @@ public class Effect extends CreeperEntity {
         this.effectApplications = effect.effectApplications;
     }
 
-    @Override
-    public void run() {
-
-    }
 
     public String getEffectName() {
         return effectName;
diff --git a/src/main/java/com/comandante/creeper/items/EffectsManager.java b/src/main/java/com/comandante/creeper/items/EffectsManager.java
index e33dfada7f782795da98ac135e462a7c17ba917c..0d032e2c68556d87b84640c3e4ce920ffd751176 100644
--- a/src/main/java/com/comandante/creeper/items/EffectsManager.java
+++ b/src/main/java/com/comandante/creeper/items/EffectsManager.java
@@ -45,13 +45,12 @@ public class EffectsManager {
         for (Effect effect : effects) {
             Effect nEffect = new Effect(effect);
             nEffect.setPlayerId(player.getPlayerId());
-            gameManager.getEntityManager().saveEffect(nEffect);
             if (effect.getDurationStats().getCurrentHealth() < 0) {
                 log.error("ERROR! Someone added an effect with a health modifier which won't work for various reasons.");
                 continue;
             }
             String effectApplyMessage;
-            if (destinationPlayer.addEffect(effect.getEntityId())) {
+            if (destinationPlayer.addEffect(effect)) {
                 effectApplyMessage = Color.BOLD_ON + Color.GREEN + "[effect] " + Color.RESET + nEffect.getEffectName() + " applied!" + "\r\n";
                 gameManager.getChannelUtils().write(destinationPlayer.getPlayerId(), effectApplyMessage);
             } else {
diff --git a/src/main/java/com/comandante/creeper/items/Equipment.java b/src/main/java/com/comandante/creeper/items/Equipment.java
index 6d7463a8c4abac6640e1c3ea2dee136be8d6a50e..3fecc2aa8091cf7216dce93e96b87ab13f65eeb0 100644
--- a/src/main/java/com/comandante/creeper/items/Equipment.java
+++ b/src/main/java/com/comandante/creeper/items/Equipment.java
@@ -6,16 +6,16 @@ import com.comandante.creeper.stats.Stats;
 public class Equipment {
 
     private final EquipmentSlotType equipmentSlotType;
-    private final Stats stats;
+    private final Stats statsIncreaseWhileEquipped;
 
-    public Equipment(EquipmentSlotType equipmentSlotType, Stats stats) {
+    public Equipment(EquipmentSlotType equipmentSlotType, Stats statsIncreaseWhileEquipped) {
         this.equipmentSlotType = equipmentSlotType;
-        this.stats = stats;
+        this.statsIncreaseWhileEquipped = statsIncreaseWhileEquipped;
     }
 
     public Equipment(Equipment equipment) {
         this.equipmentSlotType = equipment.equipmentSlotType;
-        this.stats = equipment.stats;
+        this.statsIncreaseWhileEquipped = equipment.statsIncreaseWhileEquipped;
     }
 
     public EquipmentSlotType getEquipmentSlotType() {
@@ -23,6 +23,6 @@ public class Equipment {
     }
 
     public Stats getStats() {
-        return stats;
+        return statsIncreaseWhileEquipped;
     }
 }
diff --git a/src/main/java/com/comandante/creeper/items/EquipmentBuilder.java b/src/main/java/com/comandante/creeper/items/EquipmentBuilder.java
deleted file mode 100644
index e51e95b3f33531ad905fc4c243fb132f09421362..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/items/EquipmentBuilder.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.comandante.creeper.items;
-
-
-import com.comandante.creeper.stats.Stats;
-import com.comandante.creeper.stats.StatsBuilder;
-
-public class EquipmentBuilder {
-
-    public static Item build(Item item) {
-        ItemType itemType = ItemType.itemTypeFromCode(item.getItemTypeId());
-        if (itemType != null) {
-            switch (itemType) {
-                case BERSERKER_BATON:
-                    return getBerserkerBaton(item);
-                case BERSEKER_BOOTS:
-                    return getBerserkerBoots(item);
-                case BERSERKER_CHEST:
-                    return getBerserkerChest(item);
-                case BERSEKER_SHORTS:
-                    return getBerserkerShorts(item);
-                case BERSERKER_BRACERS:
-                    return getBerserkerBracers(item);
-                case BERSEKER_HELM:
-                    return getBerserkerHelm(item);
-                case LEATHER_SATCHEL:
-                    return getLeatherSatchel(item);
-                case BIGGERS_SKIN_SATCHEL:
-                    return getBiggersSkinSatchel(item);
-                case RED_CLAW_BEANIE:
-                    return getRedClawBeanie(item);
-                case RED_CLAW_HOODIE:
-                    return getRedClawHoodie(item);
-                case RED_CLAW_PANTS:
-                    return getRedClawPants(item);
-            }
-        }
-        return null;
-    }
-
-    public static Item getBerserkerBaton(Item item) {
-        Stats stats = new StatsBuilder().setWeaponRatingMin(4).setWeaponRatingMax(6).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.HAND, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-
-    public static Item getBerserkerBoots(Item item) {
-        Stats stats = new StatsBuilder().setArmorRating(3).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.FEET, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-
-    public static Item getBerserkerChest(Item item) {
-        Stats stats = new StatsBuilder().setArmorRating(6).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.CHEST, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-
-    public static Item getBerserkerShorts(Item item) {
-        Stats stats = new StatsBuilder().setArmorRating(4).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.LEGS, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-
-    public static Item getBerserkerBracers(Item item) {
-        Stats stats = new StatsBuilder().setArmorRating(4).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.WRISTS, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-
-    public static Item getBerserkerHelm(Item item) {
-        Stats stats = new StatsBuilder().setArmorRating(3).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.HEAD, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-
-    public static Item getLeatherSatchel(Item item) {
-        Stats stats = new StatsBuilder().setInventorySize(15).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.BAG, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-
-    public static Item getBiggersSkinSatchel(Item item) {
-        Stats stats = new StatsBuilder().setInventorySize(100).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.BAG, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-
-    public static Item getRedClawBeanie(Item item) {
-        Stats stats = new StatsBuilder().setArmorRating(8).setStrength(4).setMaxHealth(50).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.HEAD, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-
-    public static Item getRedClawHoodie(Item item) {
-        Stats stats = new StatsBuilder().setArmorRating(15).setStrength(7).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.CHEST, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-
-    public static Item getRedClawPants(Item item) {
-        Stats stats = new StatsBuilder().setAgile(7).setForaging(6).createStats();
-        final Equipment equipment = new Equipment(EquipmentSlotType.LEGS, stats);
-        item.setEquipment(equipment);
-        return item;
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/items/Forage.java b/src/main/java/com/comandante/creeper/items/Forage.java
index d0d7833d289505a9b99b1331f8e04f4079be4e18..a5467b84d71fb4d608450fea99f1af01dab45cc7 100644
--- a/src/main/java/com/comandante/creeper/items/Forage.java
+++ b/src/main/java/com/comandante/creeper/items/Forage.java
@@ -2,10 +2,13 @@ package com.comandante.creeper.items;
 
 
 import com.comandante.creeper.entity.CreeperEntity;
+import com.comandante.creeper.world.model.Area;
+
+import java.util.Set;
 
 public class Forage extends CreeperEntity {
 
-    private final ItemType itemType;
+    private final String internalItemName;
     private final int minLevel;
     private final double pctOfSuccess;
     private final int minAmt;
@@ -13,9 +16,10 @@ public class Forage extends CreeperEntity {
     private final int forageExperience;
     private final int coolDownTicks;
     private int coolDownTicksLeft;
+    private final Set<Area> forageAreas;
 
-    public Forage(ItemType itemType, int minLevel, double pctOfSuccess, int minAmt, int maxAmt, int forageExperience, int coolDownTicks) {
-        this.itemType = itemType;
+    protected Forage(String internalItemName, int minLevel, double pctOfSuccess, int minAmt, int maxAmt, int forageExperience, int coolDownTicks, Set<Area> forageAreas) {
+        this.internalItemName = internalItemName;
         this.minLevel = minLevel;
         this.pctOfSuccess = pctOfSuccess;
         this.minAmt = minAmt;
@@ -23,21 +27,15 @@ public class Forage extends CreeperEntity {
         this.coolDownTicksLeft = 0;
         this.forageExperience = forageExperience;
         this.coolDownTicks = coolDownTicks;
+        this.forageAreas = forageAreas;
     }
 
-    public Forage(Forage forage) {
-        this.itemType = forage.itemType;
-        this.minLevel = new Integer(forage.getMinLevel());
-        this.pctOfSuccess = new Double(forage.getPctOfSuccess());
-        this.minAmt = new Integer(forage.getMinAmt());
-        this.maxAmt = new Integer(forage.getMaxAmt());
-        this.coolDownTicks = new Integer(forage.getCoolDownTicks());
-        this.coolDownTicksLeft = new Integer(0);
-        this.forageExperience = new Integer(forage.getForageExperience());
+    public Set<Area> getForageAreas() {
+        return forageAreas;
     }
 
-    public ItemType getItemType() {
-        return itemType;
+    public String getInternalItemName() {
+        return internalItemName;
     }
 
     public int getMinLevel() {
diff --git a/src/main/java/com/comandante/creeper/items/ForageBuilder.java b/src/main/java/com/comandante/creeper/items/ForageBuilder.java
index 58a2be8b34453b4e0e34c441e294ea83c3a2e6f8..3fd1963144e954f50410e27368088b7cb00c5f22 100644
--- a/src/main/java/com/comandante/creeper/items/ForageBuilder.java
+++ b/src/main/java/com/comandante/creeper/items/ForageBuilder.java
@@ -1,16 +1,40 @@
 package com.comandante.creeper.items;
 
+import com.comandante.creeper.world.model.Area;
+
+import java.util.Set;
+
 public class ForageBuilder {
-    private ItemType itemType;
+    private String internalItemName;
     private int minLevel;
     private double pctOfSuccess;
     private int minAmt;
     private int maxAmt;
     private int forageExperience;
     private int coolDownTicks;
+    private Set<Area> forageAreas;
+
+
+    public ForageBuilder from(Forage forage) {
+        this.internalItemName = forage.getInternalItemName();
+        this.minLevel = new Integer(forage.getMinLevel());
+        this.pctOfSuccess = new Double(forage.getPctOfSuccess());
+        this.minAmt = new Integer(forage.getMinAmt());
+        this.maxAmt = new Integer(forage.getMaxAmt());
+        this.coolDownTicks = new Integer(forage.getCoolDownTicks());
+        //this.coolDownTicksLeft = new Integer(0);
+        this.forageExperience = new Integer(forage.getForageExperience());
+        this.forageAreas = forage.getForageAreas();
+        return this;
+    }
+
+    public ForageBuilder setAreas(Set<Area> forageAreas) {
+        this.forageAreas = forageAreas;
+        return this;
+    }
 
-    public ForageBuilder setItemType(ItemType itemType) {
-        this.itemType = itemType;
+    public ForageBuilder setInternalItemName(String internalItemName) {
+        this.internalItemName = internalItemName;
         return this;
     }
 
@@ -45,6 +69,6 @@ public class ForageBuilder {
     }
 
     public Forage createForage() {
-        return new Forage(itemType, minLevel, pctOfSuccess, minAmt, maxAmt, forageExperience, coolDownTicks);
+        return new Forage(internalItemName, minLevel, pctOfSuccess, minAmt, maxAmt, forageExperience, coolDownTicks, forageAreas);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/items/ForageManager.java b/src/main/java/com/comandante/creeper/items/ForageManager.java
index d24e1f65e75e1ab7357349be151eba3f8e404783..9931b5834bdb20b642d8bc8e2c3cd2fbef3a63a5 100644
--- a/src/main/java/com/comandante/creeper/items/ForageManager.java
+++ b/src/main/java/com/comandante/creeper/items/ForageManager.java
@@ -10,6 +10,7 @@ import com.comandante.creeper.world.model.Area;
 import com.comandante.creeper.world.model.Room;
 import org.apache.log4j.Logger;
 
+import java.util.Optional;
 import java.util.Random;
 import java.util.Set;
 
@@ -26,12 +27,16 @@ public class ForageManager {
         this.gameManager = gameManager;
     }
 
-    public void addForageToArea(Area area, ForageBuilder forageBuilder) {
-        Set<Room> roomsByArea = gameManager.getRoomManager().getRoomsByArea(area);
-        for (Room room : roomsByArea) {
-            Forage newForage = forageBuilder.createForage();
-            room.addForage(newForage);
-            gameManager.getEntityManager().addEntity(newForage);
+    public void addForage(String internalItemName, Forage forage) {
+        for (Area area: forage.getForageAreas()) {
+            Set<Room> roomsByArea = gameManager.getRoomManager().getRoomsByArea(area);
+            for (Room room : roomsByArea) {
+                ForageBuilder forageBuiler = new ForageBuilder().from(forage);
+                forageBuiler.setInternalItemName(internalItemName);
+                Forage newForage = forageBuiler.createForage();
+                room.addForage(newForage);
+                gameManager.getEntityManager().addEntity(newForage);
+            }
         }
     }
 
@@ -62,19 +67,24 @@ public class ForageManager {
                 //System.out.prlongln("you get a boost of " + pctSuccessBoostForLevel);
                 foragePctOfSuccess = (foragePctOfSuccess * pctSuccessBoostForLevel) + foragePctOfSuccess;
                 //System.out.prlongln("final pct of success for forage: " + foragePctOfSuccess);
+                Optional<ItemMetadata> itemMetadataOptional = gameManager.getItemStorage().get(forage.getInternalItemName());
+                if (!itemMetadataOptional.isPresent()) {
+                    continue;
+                }
+                ItemMetadata itemMetadata = itemMetadataOptional.get();
                 if (getRandPercent(foragePctOfSuccess)) {
                     player.updatePlayerForageExperience(forage.getForageExperience());
                     long numberToHarvest = randInt(forage.getMinAmt(), forage.getMaxAmt());
                     totalForageXp += forage.getForageExperience();
                     for (long i = 0; i < numberToHarvest; i++) {
                         countOfForagesFound++;
-                        Item item = forage.getItemType().create();
+                        Item item = new ItemBuilder().from(itemMetadata).create();
                         gameManager.getEntityManager().saveItem(item);
                         gameManager.acquireItem(player, item.getItemId());
                     }
-                    gameManager.writeToRoom(room.getRoomId(), player.getPlayerName() + " foraged (" + numberToHarvest + ") " + forage.getItemType().getItemName() + "\r\n");
+                    gameManager.writeToRoom(room.getRoomId(), player.getPlayerName() + " foraged (" + numberToHarvest + ") " + itemMetadata.getItemName() + "\r\n");
                 } else {
-                    gameManager.getChannelUtils().write(player.getPlayerId(), "Attempt to forage " + forage.getItemType().getItemName() + " failed.\r\n");
+                    gameManager.getChannelUtils().write(player.getPlayerId(), "Attempt to forage " + itemMetadata.getItemName() + " failed.\r\n");
                     //System.out.prlongln("failed to obtain forage, random pctsuccess failed.");
                 }
             }
diff --git a/src/main/java/com/comandante/creeper/items/Item.java b/src/main/java/com/comandante/creeper/items/Item.java
index bd974e2310f80ba41be9371849a960cee6f2b682..26433fcabed1644508ee00487bc9e556024528c2 100644
--- a/src/main/java/com/comandante/creeper/items/Item.java
+++ b/src/main/java/com/comandante/creeper/items/Item.java
@@ -1,18 +1,23 @@
 package com.comandante.creeper.items;
 
 
+import com.comandante.creeper.core_game.service.TimeTracker;
+import com.comandante.creeper.stats.Stats;
+import com.google.common.collect.Lists;
+
 import java.io.Serializable;
 import java.util.List;
 import java.util.Set;
+import java.util.UUID;
 
 public class Item implements Serializable {
 
     private final String itemName;
     private final String itemDescription;
+    private final String internalItemName;
     private final List<String> itemTriggers;
     private final String restingName;
     private final String itemId;
-    private final Integer itemTypeId;
     private int numberOfUses;
     private boolean isWithPlayer;
     private final Loot loot;
@@ -22,58 +27,49 @@ public class Item implements Serializable {
     private final int valueInGold;
     private Set<Effect> effects;
     private boolean hasBeenWithPlayer;
+    private final int maxUses;
+    private final boolean isDisposable;
+    private Set<TimeTracker.TimeOfDay> validTimeOfDays;
+    private final Stats itemApplyStats;
 
-    public static final int CORPSE_ID_RESERVED = 100;
-
-    public Item(String itemName, String itemDescription, List<String> itemTriggers, String restingName, String itemId, Integer itemTypeId, int numberOfUses, boolean isWithPlayer, int itemHalfLifeTicks, Rarity rarity, int valueInGold) {
-        this.itemName = itemName;
-        this.itemDescription = itemDescription;
-        this.itemTriggers = itemTriggers;
-        this.restingName = restingName;
-        this.itemId = itemId;
-        this.itemTypeId = itemTypeId;
-        this.numberOfUses = numberOfUses;
-        this.loot = null;
-        this.itemHalfLifeTicks = itemHalfLifeTicks;
-        this.isWithPlayer = isWithPlayer;
-        this.rarity = rarity;
-        this.valueInGold = valueInGold;
-    }
+    public static final String CORPSE_INTENAL_NAME = "corpse";
 
-    public Item(String itemName, String itemDescription, List<String> itemTriggers, String restingName, String itemId, Integer itemTypeId, int numberOfUses, boolean isWithPlayer, int itemHalfLifeTicks, Rarity rarity, int valueInGold, Loot loot) {
+    protected Item(String itemName, String itemDescription, String internalItemName, List<String> itemTriggers, String restingName, String itemId, int numberOfUses, boolean isWithPlayer, Loot loot, int itemHalfLifeTicks, Equipment equipment, Rarity rarity, int valueInGold, Set<Effect> effects, boolean hasBeenWithPlayer, int maxUses, boolean isDisposable, Set<TimeTracker.TimeOfDay> validTimeOfDays, Stats itemApplyStats) {
         this.itemName = itemName;
         this.itemDescription = itemDescription;
+        this.internalItemName = internalItemName;
         this.itemTriggers = itemTriggers;
         this.restingName = restingName;
         this.itemId = itemId;
-        this.itemTypeId = itemTypeId;
         this.numberOfUses = numberOfUses;
         this.isWithPlayer = isWithPlayer;
         this.loot = loot;
         this.itemHalfLifeTicks = itemHalfLifeTicks;
+        this.equipment = equipment;
         this.rarity = rarity;
         this.valueInGold = valueInGold;
+        this.effects = effects;
+        this.hasBeenWithPlayer = hasBeenWithPlayer;
+        this.maxUses = maxUses;
+        this.isDisposable = isDisposable;
+        this.validTimeOfDays = validTimeOfDays;
+        this.itemApplyStats = itemApplyStats;
+    }
 
+    public Stats getItemApplyStats() {
+        return itemApplyStats;
     }
 
-    public Item(Item origItem) {
-        this.itemName = origItem.getItemName();
-        this.itemDescription = origItem.itemDescription;
-        this.itemTriggers = origItem.itemTriggers;
-        this.restingName = origItem.restingName;
-        this.itemId = origItem.itemId;
-        this.itemTypeId = origItem.itemTypeId;
-        this.numberOfUses = new Integer(origItem.numberOfUses);
-        this.loot = origItem.loot;
-        this.itemHalfLifeTicks = origItem.itemHalfLifeTicks;
-        this.isWithPlayer = new Boolean(origItem.isWithPlayer);
-        if (origItem.equipment != null) {
-            this.equipment = new Equipment(origItem.equipment);
-        }
-        this.rarity = origItem.rarity;
-        this.valueInGold = origItem.valueInGold;
-        this.effects = origItem.effects;
-        this.hasBeenWithPlayer = new Boolean(origItem.hasBeenWithPlayer);
+    public Set<TimeTracker.TimeOfDay> getValidTimeOfDays() {
+        return validTimeOfDays;
+    }
+
+    public boolean isDisposable() {
+        return isDisposable;
+    }
+
+    public int getMaxUses() {
+        return maxUses;
     }
 
     public boolean isWithPlayer() {
@@ -99,8 +95,9 @@ public class Item implements Serializable {
         return itemId;
     }
 
-    public Integer getItemTypeId() {
-        return itemTypeId;
+
+    public String getInternalItemName() {
+        return internalItemName;
     }
 
     public String getItemName() {
@@ -159,24 +156,23 @@ public class Item implements Serializable {
         return hasBeenWithPlayer;
     }
 
-    @Override
-    public String toString() {
-        return "Item{" +
-                "itemName='" + itemName + '\'' +
-                ", itemDescription='" + itemDescription + '\'' +
-                ", itemTriggers=" + itemTriggers +
-                ", restingName='" + restingName + '\'' +
-                ", itemId='" + itemId + '\'' +
-                ", itemTypeId=" + itemTypeId +
-                ", numberOfUses=" + numberOfUses +
-                ", isWithPlayer=" + isWithPlayer +
-                ", loot=" + loot +
-                ", itemHalfLifeTicks=" + itemHalfLifeTicks +
-                ", equipment=" + equipment +
-                ", rarity=" + rarity +
-                ", valueInGold=" + valueInGold +
-                ", effects=" + effects +
-                ", hasBeenWithPlayer=" + hasBeenWithPlayer +
-                '}';
+    public static Item createCorpseItem(String name, Loot loot) {
+
+        Item item = new ItemBuilder()
+                .internalItemName(Item.CORPSE_INTENAL_NAME)
+                .itemName(name + " corpse")
+                .itemDescription("a bloody corpse")
+                .itemTriggers(Lists.newArrayList("corpse", "c", name, name + " corpse"))
+                .itemId(UUID.randomUUID().toString())
+                .itemHalfLifeTicks(120)
+                .rarity(Rarity.BASIC)
+                .valueInGold(5)
+                .isDisposable(false)
+                .restingName("a corpse lies on the ground.")
+                .loot(loot)
+                .create();
+
+        return item;
+
     }
 }
diff --git a/src/main/java/com/comandante/creeper/items/ItemBuilder.java b/src/main/java/com/comandante/creeper/items/ItemBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..8d0a70fdd174ea31934c3a04b0083f08bfe745b6
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/items/ItemBuilder.java
@@ -0,0 +1,181 @@
+package com.comandante.creeper.items;
+
+
+import com.comandante.creeper.core_game.service.TimeTracker;
+import com.comandante.creeper.stats.Stats;
+
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+public class ItemBuilder {
+
+    private String itemName;
+    private String itemDescription;
+    private String internalItemName;
+    private List<String> itemTriggers;
+    private String restingName;
+    private String itemId;
+    private int numberOfUses;
+    private boolean isWithPlayer;
+    private Loot loot;
+    private int itemHalfLifeTicks;
+    private Equipment equipment;
+    private Rarity rarity;
+    private int valueInGold;
+    private Set<Effect> effects;
+    private boolean hasBeenWithPlayer;
+    private int maxUses;
+    private boolean isDisposable;
+    private Set<TimeTracker.TimeOfDay> validTimeOfDays;
+    private Stats itemApplyStats;
+
+    public ItemBuilder from(ItemMetadata itemMetadata) {
+        this.internalItemName = itemMetadata.getInternalItemName();
+        this.itemName = itemMetadata.getItemName();
+        this.itemDescription = itemMetadata.getItemDescription();
+        this.itemTriggers = itemMetadata.getItemTriggers();
+        this.restingName = itemMetadata.getRestingName();
+        this.itemId = UUID.randomUUID().toString();
+        // zero uses, its new.
+        this.numberOfUses = 0;
+        this.isWithPlayer = false;
+        this.itemHalfLifeTicks = itemMetadata.getItemHalfLifeTicks();
+        this.rarity = itemMetadata.getRarity();
+        this.valueInGold = itemMetadata.getValueInGold();
+        this.maxUses = itemMetadata.getMaxUses();
+        this.loot = null;
+        this.isDisposable = itemMetadata.isDisposable();
+        this.equipment = itemMetadata.getEquipment();
+        this.validTimeOfDays = itemMetadata.getValidTimeOfDays();
+        this.effects = itemMetadata.getEffects();
+        this.itemApplyStats = itemMetadata.getItemApplyStats();
+        return this;
+    }
+
+    public ItemBuilder from(Item origItem) {
+        this.internalItemName = origItem.getInternalItemName();
+        this.itemName = origItem.getItemName();
+        this.itemDescription = origItem.getItemDescription();
+        this.itemTriggers = origItem.getItemTriggers();
+        this.restingName = origItem.getRestingName();
+        this.itemId = origItem.getItemId();
+        this.numberOfUses = new Integer(origItem.getNumberOfUses());
+        this.loot = origItem.getLoot();
+        this.itemHalfLifeTicks = origItem.getItemHalfLifeTicks();
+        this.isWithPlayer = new Boolean(origItem.isWithPlayer());
+        if (origItem.getEquipment() != null) {
+            this.equipment = new Equipment(origItem.getEquipment());
+        }
+        this.rarity = origItem.getRarity();
+        this.valueInGold = origItem.getValueInGold();
+        this.effects = origItem.getEffects();
+        this.hasBeenWithPlayer = new Boolean(origItem.isHasBeenWithPlayer());
+        this.maxUses = origItem.getMaxUses();
+        this.isDisposable = origItem.isDisposable();
+        this.validTimeOfDays = origItem.getValidTimeOfDays();
+        this.itemApplyStats = origItem.getItemApplyStats();
+        return this;
+    }
+
+    public ItemBuilder itemName(String itemName) {
+        this.itemName = itemName;
+        return this;
+    }
+
+    public ItemBuilder itemDescription(String itemDescription) {
+        this.itemDescription = itemDescription;
+        return this;
+    }
+
+    public ItemBuilder internalItemName(String internalItemName) {
+        this.internalItemName = internalItemName;
+        return this;
+    }
+
+    public ItemBuilder itemTriggers(List<String> itemTriggers) {
+        this.itemTriggers = itemTriggers;
+        return this;
+    }
+
+    public ItemBuilder restingName(String restingName) {
+        this.restingName = restingName;
+        return this;
+    }
+
+    public ItemBuilder itemId(String itemId) {
+        this.itemId = itemId;
+        return this;
+    }
+
+    public ItemBuilder numberOfUses(int numberOfUses) {
+        this.numberOfUses = numberOfUses;
+        return this;
+    }
+
+    public ItemBuilder isWithPlayer(boolean isWithPlayer) {
+        this.isWithPlayer = isWithPlayer;
+        return this;
+    }
+
+    public ItemBuilder loot(Loot loot) {
+        this.loot = loot;
+        return this;
+    }
+
+    public ItemBuilder itemHalfLifeTicks(int itemHalfLifeTicks) {
+        this.itemHalfLifeTicks = itemHalfLifeTicks;
+        return this;
+    }
+
+    public ItemBuilder equipment(Equipment equipment) {
+        this.equipment = equipment;
+        return this;
+    }
+
+    public ItemBuilder rarity(Rarity rarity) {
+        this.rarity = rarity;
+        return this;
+    }
+
+    public ItemBuilder valueInGold(int valueInGold) {
+        this.valueInGold = valueInGold;
+        return this;
+    }
+
+    public ItemBuilder effects(Set<Effect> effects) {
+        this.effects = effects;
+        return this;
+    }
+
+    public ItemBuilder hasBeenWithPlayer(boolean hasBeenWithPlayer) {
+        this.hasBeenWithPlayer = hasBeenWithPlayer;
+        return this;
+    }
+
+    public ItemBuilder maxUses(int maxUses) {
+        this.maxUses = maxUses;
+        return this;
+    }
+
+    public ItemBuilder isDisposable(boolean isDisposable) {
+        this.isDisposable = isDisposable;
+        return this;
+    }
+
+    public ItemBuilder validTimeOfDays(Set<TimeTracker.TimeOfDay> validTimeOfDays) {
+        this.validTimeOfDays = validTimeOfDays;
+        return this;
+    }
+
+    public ItemBuilder itemApplyStats(Stats itemApplyStats) {
+        this.itemApplyStats = itemApplyStats;
+        return this;
+    }
+
+    public Item create() {
+            return new Item(itemName, itemDescription, internalItemName, itemTriggers, restingName, itemId, numberOfUses, isWithPlayer, loot, itemHalfLifeTicks, equipment, rarity, valueInGold, effects, hasBeenWithPlayer, maxUses, isDisposable, validTimeOfDays, itemApplyStats);
+    }
+
+
+}
diff --git a/src/main/java/com/comandante/creeper/items/ItemMetadata.java b/src/main/java/com/comandante/creeper/items/ItemMetadata.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd3519a1b9eb62f7e4ce33c505320ba95747ea09
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/items/ItemMetadata.java
@@ -0,0 +1,169 @@
+package com.comandante.creeper.items;
+
+
+import com.comandante.creeper.core_game.service.TimeTracker;
+import com.comandante.creeper.spawner.SpawnRule;
+import com.comandante.creeper.stats.Stats;
+import com.google.common.collect.Sets;
+
+import java.util.List;
+import java.util.Set;
+
+public class ItemMetadata {
+
+    // Used for persisting to disk (file-name)
+    // Spaces become underscores.
+    // Needs to be unique across all itemmetadata's.
+    // is essentially serving as the item "type".
+    private String internalItemName;
+    // This is the unique identifier to represent this itemmetadata (which drives itemtype)
+    private String itemName;
+    private String itemDescription;
+    private String restingName;
+    private int valueInGold;
+    private int itemHalfLifeTicks;
+    private Rarity rarity;
+    private Equipment equipment;
+    private Set<Effect> effects;
+    private List<String> itemTriggers;
+    private Set<TimeTracker.TimeOfDay> validTimeOfDays;
+    private boolean isDisposable;
+    private int maxUses;
+    private Set<SpawnRule> spawnRules;
+    private Stats itemApplyStats;
+    private Set<Forage> forages;
+
+    public Set<Forage> getForages() {
+        if (forages == null) {
+            return Sets.newHashSet();
+        }
+        return forages;
+    }
+
+    public void setForages(Set<Forage> forages) {
+        this.forages = forages;
+    }
+
+    public Stats getItemApplyStats() {
+        return itemApplyStats;
+    }
+
+    public void setItemApplyStats(Stats itemApplyStats) {
+        this.itemApplyStats = itemApplyStats;
+    }
+
+    public String getItemName() {
+        return itemName;
+    }
+
+    public void setItemName(String itemName) {
+        this.itemName = itemName;
+    }
+
+    public String getItemDescription() {
+        return itemDescription;
+    }
+
+    public void setItemDescription(String itemDescription) {
+        this.itemDescription = itemDescription;
+    }
+
+    public String getRestingName() {
+        return restingName;
+    }
+
+    public void setRestingName(String restingName) {
+        this.restingName = restingName;
+    }
+
+    public int getValueInGold() {
+        return valueInGold;
+    }
+
+    public void setValueInGold(int valueInGold) {
+        this.valueInGold = valueInGold;
+    }
+
+    public int getItemHalfLifeTicks() {
+        return itemHalfLifeTicks;
+    }
+
+    public void setItemHalfLifeTicks(int itemHalfLifeTicks) {
+        this.itemHalfLifeTicks = itemHalfLifeTicks;
+    }
+
+    public Rarity getRarity() {
+        return rarity;
+    }
+
+    public void setRarity(Rarity rarity) {
+        this.rarity = rarity;
+    }
+
+    public Equipment getEquipment() {
+        return equipment;
+    }
+
+    public void setEquipment(Equipment equipment) {
+        this.equipment = equipment;
+    }
+
+    public Set<Effect> getEffects() {
+        return effects;
+    }
+
+    public void setEffects(Set<Effect> effects) {
+        this.effects = effects;
+    }
+
+    public String getInternalItemName() {
+        return internalItemName;
+    }
+
+    public List<String> getItemTriggers() {
+        return itemTriggers;
+    }
+
+    public void setItemTriggers(List<String> itemTriggers) {
+        this.itemTriggers = itemTriggers;
+    }
+
+    public void setInternalItemName(String internalItemName) {
+        this.internalItemName = internalItemName;
+    }
+
+    public Set<TimeTracker.TimeOfDay> getValidTimeOfDays() {
+        return validTimeOfDays;
+    }
+
+    public void setValidTimeOfDays(Set<TimeTracker.TimeOfDay> validTimeOfDays) {
+        this.validTimeOfDays = validTimeOfDays;
+    }
+
+    public int getMaxUses() {
+        return maxUses;
+    }
+
+    public boolean isDisposable() {
+        return isDisposable;
+    }
+
+    public void setDisposable(boolean disposable) {
+        isDisposable = disposable;
+    }
+
+    public Set<SpawnRule> getSpawnRules() {
+        if (spawnRules == null) {
+            return Sets.newHashSet();
+        }
+        return spawnRules;
+    }
+
+    public void setSpawnRules(Set<SpawnRule> spawnRules) {
+        this.spawnRules = spawnRules;
+    }
+
+    public void setMaxUses(int maxUses) {
+        this.maxUses = maxUses;
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/items/ItemType.java b/src/main/java/com/comandante/creeper/items/ItemType.java
deleted file mode 100644
index 69622512cc46d15dba5e9a4ef1709fe63b96e5ca..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/items/ItemType.java
+++ /dev/null
@@ -1,357 +0,0 @@
-package com.comandante.creeper.items;
-
-import com.comandante.creeper.core_game.service.TimeTracker;
-import com.comandante.creeper.server.player_communication.Color;
-import com.google.common.collect.Sets;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-
-import static com.comandante.creeper.server.player_communication.Color.*;
-
-public enum ItemType {
-
-    UNKNOWN(0, Arrays.asList(""), "", "", "", false, 0, 0, false, com.comandante.creeper.items.Rarity.RARE, 0, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-    KEY(1, Arrays.asList("key", "gold key", "shiny gold key"),
-            "a shiny " + YELLOW + "gold key" + RESET,
-            "a shiny " + YELLOW + "gold key" + RESET + " catches your eye.",
-            "A basic key with nothing really remarkable other than its made of gold.",
-            false,
-            0,
-            60,
-            false,
-            Rarity.BASIC,
-            10, Sets.<TimeTracker.TimeOfDay>newHashSet(TimeTracker.TimeOfDay.NIGHT)),
-
-    SMALL_HEALTH_POTION(2, Arrays.asList("potion", "health potion", "vial", "small vial of health potion", "p"),
-            "a small vial of " + RED + "health potion" + RESET,
-            "a small vial of " + RED + "health potion" + RESET + " rests on the ground.",
-            "a small vial of " + RED + "health potion" + RESET + " that restores 50 health" + RESET,
-            true,
-            0,
-            60,
-            false,
-            Rarity.OFTEN,
-            1, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    BERSERKER_BATON(3, Arrays.asList("baton", "a berserker baton", "b"),
-            Color.CYAN + "a berserker baton" + Color.RESET,
-            "a berserker baton rests upon the ground.",
-            "a berserker baton",
-            false,
-            0,
-            60,
-            true,
-            Rarity.BASIC,
-            100, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    BERSEKER_BOOTS(4, Arrays.asList("boots", "boot", "berserker boots", "b"),
-            Color.CYAN + "berserker boots" + Color.RESET,
-            "a pair of berserker boots are here on the ground.",
-            "a pair of berserker boots",
-            false,
-            0,
-            60,
-            true,
-            Rarity.BASIC,
-            50, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    BERSERKER_CHEST(5, Arrays.asList("chest", "berserker chest", "c"),
-            Color.CYAN + "berserker chest" + Color.RESET,
-            "a berserker chest is on the ground.",
-            "a berserker chest",
-            false,
-            0,
-            60,
-            true,
-            Rarity.BASIC,
-            70, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    BERSEKER_SHORTS(6, Arrays.asList("shorts", "berserker shorts", "s"),
-            Color.CYAN + "berserker shorts" + Color.RESET,
-            "a pair of berserker shorts are here on the ground.",
-            "a pair of berserker shorts",
-            false,
-            0,
-            60,
-            true,
-            Rarity.BASIC,
-            80, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    BERSERKER_BRACERS(7, Arrays.asList("bracers", "berserker bracers", "b"),
-            Color.CYAN + "berserker bracers" + Color.RESET,
-            "a pair of berserker bracers are here on the ground.",
-            "a pair of berserker bracers",
-            false,
-            0,
-            60,
-            true,
-            Rarity.BASIC,
-            40, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    BERSEKER_HELM(8, Arrays.asList("helm", "berserker helm", "h"),
-            Color.CYAN + "berserker helm" + Color.RESET,
-            "a berserker helm is on the ground.",
-            "a berserker helm",
-            false,
-            0,
-            60,
-            true,
-            Rarity.BASIC,
-            40, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    MARIJUANA(9, Arrays.asList("marijuana", "weed", "m", "w", "f", "flowers"),
-            Color.GREEN + "marijuana" + Color.RESET + " flowers" + Color.RESET,
-            "some " + Color.GREEN + "marijuana" + Color.RESET + " flowers" + Color.RESET + " are here on the ground.",
-            "some " + Color.GREEN + "marijuana" + Color.RESET + " flowers" + Color.RESET,
-            true,
-            0,
-            60,
-            false,
-            Rarity.BASIC,
-            10, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    PURPLE_DRANK(10, Arrays.asList("drank", "purple drank", "p", "purple", "lean", "sizzurp"),
-            "a double cup of " + MAGENTA + "purple" + RESET + " drank",
-            "a double cup of " + MAGENTA + "purple" + RESET + " drank rests on the ground.",
-            "a tonic called " + MAGENTA + "purple" + RESET + " drank that restores health" + RESET,
-            true,
-            0,
-            60,
-            false,
-            Rarity.BASIC,
-            30, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    LEATHER_SATCHEL(11, Arrays.asList("leather satchel", "satchel"),
-            "a " + Color.GREEN + "leather satchel" + Color.RESET,
-            "a " + Color.GREEN + "leather satchel" + Color.RESET,
-            "a " + Color.GREEN + "leather satchel" + Color.RESET + " (15 items)",
-            false,
-            0,
-            60,
-            true,
-            Rarity.BASIC,
-            800, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    BIGGERS_SKIN_SATCHEL(12, Arrays.asList("biggers skin satchel", "skin satchel"),
-            "a " + Color.GREEN + "biggers skin satchel" + Color.RESET,
-            "a " + Color.GREEN + "biggers skin satchel" + Color.RESET,
-            "a " + Color.GREEN + "biggers skin satchel" + Color.RESET + " with room to store 100 items.",
-            false,
-            0,
-            60,
-            true,
-            Rarity.BASIC,
-            3000, Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    LIGHTNING_SPELLBOOKNG(
-            // itemTypeCode
-            13,
-            // triggers
-            Arrays.asList("lightning book", "lightning spell book", "book", "spell book"),
-            // name
-            "a " + Color.YELLOW + "lightning" + Color.RESET + " spell book." + Color.RESET,
-            // resting name
-            "a " + Color.YELLOW + "lightning" + Color.RESET + " spell book." + Color.RESET,
-            // description
-            "a " + Color.YELLOW + "lightning" + Color.RESET + " spell book." + Color.RESET,
-            // disposable?
-            true,
-            // max uses
-            0,
-            // half life ticks
-            60,
-            // equipment/can you wear it?
-            false,
-            // controls how often it will spawn (if configured in a spawn)
-            Rarity.RARE,
-            // default sell value (gold)
-            3000,
-            // Some items have time of days where they are "valid" and times when they are not.  If they are not valid for MORNING (for example) they will turn to dust as soon as the world switches to morning.
-            Sets.<TimeTracker.TimeOfDay>newHashSet()),
-    STICK_OF_JUSTICE(
-            // itemTypeCode
-            14,
-            // triggers
-            Arrays.asList("stick of justice", "justice", "stick"),
-            // name
-            "a " + Color.BOLD_ON + Color.MAGENTA + "stick" + Color.BOLD_OFF + Color.GREEN + " of " + Color.BOLD_ON + Color.BLUE + "justice" + Color.RESET,
-            // resting name
-            "a " + Color.BOLD_ON + Color.MAGENTA + "stick" + Color.BOLD_OFF + Color.GREEN + " of " + Color.BOLD_ON + Color.BLUE + "justice" + Color.RESET,
-            // description
-            "a " + Color.BOLD_ON + Color.MAGENTA + "stick" + Color.BOLD_OFF + Color.GREEN + " of " + Color.BOLD_ON + Color.BLUE + "justice" + Color.RESET,
-            // disposable?
-            true,
-            // max uses
-            0,
-            // half life ticks
-            60,
-            // equipment/can you wear it?
-            false,
-            // controls how often it will spawn (if configured in a spawn)
-            Rarity.RARE,
-            // default sell value (gold)
-            3000,
-            // Some items have time of days where they are "valid" and times when they are not.  If they are not valid for MORNING (for example) they will turn to dust as soon as the world switches to morning.
-            Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    RED_CLAW_BEANIE(
-            // itemTypeCode
-            15,
-            // triggers
-            Arrays.asList("beanie", "red-claw beanie", "b"),
-            // name
-            Color.RED + "red-claw " + Color.RESET + "beanie" + Color.RESET,
-            // resting name
-            "a " + Color.RED + "red-claw " + Color.RESET + "beanie is on the ground.",
-            // description
-            "a red-claw beanie",
-            // disposable?
-            false,
-            // max uses
-            0,
-            // half life ticks
-            60,
-            // equipment?
-            true,
-            Rarity.LEGENDARY,
-            // default sell value (gold)
-            3500,
-            Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    RED_CLAW_HOODIE(
-            // itemTypeCode
-            16,
-            // triggers
-            Arrays.asList("hoodie", "red-claw hoodie", "h"),
-            // name
-            Color.RED + "red-claw " + Color.RESET + "hoodie" + Color.RESET,
-            // resting name
-            "a " + Color.RED + "red-claw " + Color.RESET + "hoodie is on the ground.",
-            // description
-            "a red-claw hoodie",
-            // disposable?
-            false,
-            // max uses
-            0,
-            // half life ticks
-            60,
-            // equipment?
-            true,
-            Rarity.LEGENDARY,
-            // default sell value (gold)
-            3500,
-            Sets.<TimeTracker.TimeOfDay>newHashSet()),
-
-    RED_CLAW_PANTS(
-            // itemTypeCode
-            17,
-            // triggers
-            Arrays.asList("pants", "red-claw pants", "p"),
-            // name
-            Color.RED + "red-claw " + Color.RESET + "pants" + Color.RESET,
-            // resting name
-            "a " + Color.RED + "red-claw " + Color.RESET + "pants is on the ground.",
-            // description
-            "a red-claw pants",
-            // disposable?
-            false,
-            // max uses
-            0,
-            // half life ticks
-            60,
-            // equipment?
-            true,
-            Rarity.LEGENDARY,
-            // default sell value (gold)
-            3500,
-            Sets.<TimeTracker.TimeOfDay>newHashSet()),;
-
-    private final Integer itemTypeCode;
-    private final List<String> itemTriggers;
-    private final String restingName;
-    private final String itemName;
-    private final String itemDescription;
-    private final boolean isDisposable;
-    private final int maxUses;
-    private final int itemHalfLifeTicks;
-    private final boolean isEquipment;
-    private final Rarity rarity;
-    private final int valueInGold;
-    private final Set<TimeTracker.TimeOfDay> validTimeOfDays;
-
-    ItemType(Integer itemTypeCode, List<String> itemTriggers, String itemName, String restingName, String itemDescription, boolean isDisposable, int maxUses, int itemHalfLifeTicks, boolean isEquipment, Rarity rarity, int valueInGold, Set<TimeTracker.TimeOfDay> validTimeOfDays) {
-        this.itemTypeCode = itemTypeCode;
-        this.itemTriggers = itemTriggers;
-        this.itemName = itemName;
-        this.restingName = restingName;
-        this.itemDescription = itemDescription;
-        this.maxUses = maxUses;
-        this.isDisposable = maxUses > 0 || isDisposable;
-        this.itemHalfLifeTicks = itemHalfLifeTicks;
-        this.isEquipment = isEquipment;
-        this.rarity = rarity;
-        this.valueInGold = valueInGold;
-        this.validTimeOfDays = validTimeOfDays;
-    }
-
-    public Item create() {
-        Item newItem = new Item(getItemName(), getItemDescription(), getItemTriggers(), getRestingName(), UUID.randomUUID().toString(), getItemTypeCode(), 0, false, itemHalfLifeTicks, getRarity(), getValueInGold());
-        if (isEquipment) {
-            return EquipmentBuilder.build(newItem);
-        }
-        return newItem;
-    }
-
-    public Rarity getRarity() {
-        return rarity;
-    }
-
-    public String getRestingName() {
-        return restingName;
-    }
-
-    public Integer getItemTypeCode() {
-        return itemTypeCode;
-    }
-
-    public List<String> getItemTriggers() {
-        return itemTriggers;
-    }
-
-    public String getItemName() {
-        return itemName;
-    }
-
-    public String getItemDescription() {
-        return itemDescription;
-    }
-
-    public boolean isDisposable() {
-        return isDisposable;
-    }
-
-    public int getMaxUses() {
-        return maxUses;
-    }
-
-    public int getValueInGold() {
-        return valueInGold;
-    }
-
-    public Set<TimeTracker.TimeOfDay> getValidTimeOfDays() {
-        return validTimeOfDays;
-    }
-
-    public static ItemType itemTypeFromCode(Integer code) {
-        ItemType[] values = values();
-        for (ItemType type : values) {
-            if (type.getItemTypeCode().equals(code)) {
-                return type;
-            }
-        }
-        return ItemType.UNKNOWN;
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/items/ItemUseAction.java b/src/main/java/com/comandante/creeper/items/ItemUseAction.java
index b68dbcd38ecdb32ecb2884c3de41ffe9e0269e92..18eae3872d949faa359052b1fa3f535825bcae64 100644
--- a/src/main/java/com/comandante/creeper/items/ItemUseAction.java
+++ b/src/main/java/com/comandante/creeper/items/ItemUseAction.java
@@ -7,7 +7,7 @@ import com.comandante.creeper.player.Player;
 import java.util.Set;
 
 public interface ItemUseAction {
-    Integer getItemTypeId();
+    String getInternalItemName();
 
     void executeAction(GameManager gameManager, Player player, Item item, UseCommand.UseItemOn useItemOn);
 
diff --git a/src/main/java/com/comandante/creeper/items/ItemUseHandler.java b/src/main/java/com/comandante/creeper/items/ItemUseHandler.java
index 0b2d7ff188c0ac0886a1efbfbc91316b92e9bdd5..b32308de1866c562697de78c045c16d54ecd53df 100644
--- a/src/main/java/com/comandante/creeper/items/ItemUseHandler.java
+++ b/src/main/java/com/comandante/creeper/items/ItemUseHandler.java
@@ -3,15 +3,14 @@ package com.comandante.creeper.items;
 
 import com.comandante.creeper.command.commands.UseCommand;
 import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.items.use.DefaultApplyStatsAction;
+import com.comandante.creeper.items.use.DefaultApplyEffectsStats;
 import com.comandante.creeper.items.use.LightningSpellBookUseAction;
 import com.comandante.creeper.items.use.StickOfJusticeUseAction;
 import com.comandante.creeper.player.Player;
-import com.comandante.creeper.stats.Stats;
-import com.comandante.creeper.stats.StatsBuilder;
-import com.google.common.collect.Sets;
 import org.apache.log4j.Logger;
 
+import java.util.Optional;
+
 public class ItemUseHandler {
 
     private static final Logger log = Logger.getLogger(ItemUseHandler.class);
@@ -23,21 +22,23 @@ public class ItemUseHandler {
 
     public void handle(Player player, Item item, UseCommand.UseItemOn useItemOn) {
         ItemUseAction itemUseAction = null;
-        switch (ItemType.itemTypeFromCode(item.getItemTypeId())) {
-            case LIGHTNING_SPELLBOOKNG:
-                itemUseAction = new LightningSpellBookUseAction(ItemType.LIGHTNING_SPELLBOOKNG);
-                break;
-            case PURPLE_DRANK:
-                itemUseAction = new DefaultApplyStatsAction(ItemType.PURPLE_DRANK, buildStats(120, 0), Sets.newHashSet());
+        Optional<ItemMetadata> itemMetadataOptional = gameManager.getItemStorage().get(item.getInternalItemName());
+        if (!itemMetadataOptional.isPresent()) {
+            return;
+        }
+        ItemMetadata itemMetadata = itemMetadataOptional.get();
+        switch (itemMetadata.getInternalItemName()) {
+            case "lightning spellbook":
+                itemUseAction = new LightningSpellBookUseAction(itemMetadata);
                 break;
-            case MARIJUANA:
-                itemUseAction = new DefaultApplyStatsAction(ItemType.MARIJUANA, buildStats(50, 50), Sets.newHashSet());
+            case "stick of justice":
+                itemUseAction = new StickOfJusticeUseAction(itemMetadata);
                 break;
-            case SMALL_HEALTH_POTION:
-                itemUseAction = new DefaultApplyStatsAction(ItemType.SMALL_HEALTH_POTION, buildStats(25, 0), Sets.newHashSet());
+            default:
+                if ((item.getEffects() != null && item.getEffects().size() > 0) || (item.getItemApplyStats() != null)) {
+                    itemUseAction = new DefaultApplyEffectsStats(itemMetadata);
+                }
                 break;
-            case STICK_OF_JUSTICE:
-                itemUseAction = new StickOfJusticeUseAction(ItemType.STICK_OF_JUSTICE);
         }
         if (itemUseAction != null) {
             itemUseAction.executeAction(gameManager, player, item, useItemOn);
@@ -45,13 +46,6 @@ public class ItemUseHandler {
         }
     }
 
-    private static Stats buildStats(int health, int mana) {
-        StatsBuilder statsBuilder = new StatsBuilder();
-        statsBuilder.setCurrentHealth(health);
-        statsBuilder.setCurrentMana(mana);
-        return statsBuilder.createStats();
-    }
-
     public static void incrementUses(Item item) {
         item.setNumberOfUses(item.getNumberOfUses() + 1);
     }
diff --git a/src/main/java/com/comandante/creeper/items/Loot.java b/src/main/java/com/comandante/creeper/items/Loot.java
index db5dc610b418c318a9e1f46249370acae9d79437..0c046a18ab8caf0450624a896cd1b293f636e7e9 100644
--- a/src/main/java/com/comandante/creeper/items/Loot.java
+++ b/src/main/java/com/comandante/creeper/items/Loot.java
@@ -2,19 +2,20 @@ package com.comandante.creeper.items;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.Sets;
 
 import java.io.Serializable;
 import java.util.Set;
 
 public class Loot implements Serializable {
 
-    private Set<ItemType> items;
+    private Set<String> internalItemNames;
     private long lootGoldMax;
     private long lootGoldMin;
 
     @JsonCreator
-    public Loot(@JsonProperty("lootGoldMin") long lootGoldMin, @JsonProperty("lootGoldMax") long lootGoldMax, @JsonProperty("items") Set<ItemType> items) {
-        this.items = items;
+    public Loot(@JsonProperty("lootGoldMin") long lootGoldMin, @JsonProperty("lootGoldMax") long lootGoldMax, @JsonProperty("items") Set<String> internalItemNames) {
+        this.internalItemNames = internalItemNames;
         this.lootGoldMax = lootGoldMax;
         this.lootGoldMin = lootGoldMin;
     }
@@ -22,8 +23,11 @@ public class Loot implements Serializable {
     public Loot() {
     }
 
-    public Set<ItemType> getItems() {
-        return items;
+    public Set<String> getInternalItemNames() {
+        if (internalItemNames == null) {
+            internalItemNames = Sets.newHashSet();
+        }
+        return internalItemNames;
     }
 
     public long getLootGoldMax() {
@@ -34,8 +38,8 @@ public class Loot implements Serializable {
         return lootGoldMin;
     }
 
-    public void setItems(Set<ItemType> items) {
-        this.items = items;
+    public void setItems(Set<String> items) {
+        this.internalItemNames = items;
     }
 
     public void setLootGoldMax(long lootGoldMax) {
diff --git a/src/main/java/com/comandante/creeper/items/LootManager.java b/src/main/java/com/comandante/creeper/items/LootManager.java
index 1b8c89b6e147ca5b790ed21805b62885122608a4..6ca8bbb618c191ac8ea8ff7c0038b3a19cf33148 100644
--- a/src/main/java/com/comandante/creeper/items/LootManager.java
+++ b/src/main/java/com/comandante/creeper/items/LootManager.java
@@ -4,6 +4,7 @@ import com.comandante.creeper.core_game.GameManager;
 import com.google.common.collect.Sets;
 import org.apache.commons.lang.math.JVMRandom;
 
+import java.util.Optional;
 import java.util.Random;
 import java.util.Set;
 
@@ -34,9 +35,14 @@ public class LootManager {
 
     public Set<Item> lootItemsReturn(Loot loot) {
         Set<Item> lootItems = Sets.newHashSet();
-        for (ItemType item: loot.getItems()) {
-            if (lootDropSuccess(item.getRarity().getPercentToLoot())) {
-                Item i = item.create();
+        for (String internalItemName: loot.getInternalItemNames()) {
+            Optional<ItemMetadata> itemMetadataOptional = gameManager.getItemStorage().get(internalItemName);
+            if (!itemMetadataOptional.isPresent()) {
+                continue;
+            }
+            ItemMetadata itemMetadata = itemMetadataOptional.get();
+            if (lootDropSuccess(itemMetadata.getRarity().getPercentToLoot())) {
+                Item i = new ItemBuilder().from(itemMetadata).create();
                 gameManager.getEntityManager().saveItem(i);
                 lootItems.add(i);
             }
diff --git a/src/main/java/com/comandante/creeper/items/use/DefaultApplyStatsAction.java b/src/main/java/com/comandante/creeper/items/use/DefaultApplyEffectsStats.java
similarity index 65%
rename from src/main/java/com/comandante/creeper/items/use/DefaultApplyStatsAction.java
rename to src/main/java/com/comandante/creeper/items/use/DefaultApplyEffectsStats.java
index 067776d62d33d0cf7e4b1a6e48a3f4d7d4db9750..292a70b892c19b6545535a443c89631e91dc42c0 100644
--- a/src/main/java/com/comandante/creeper/items/use/DefaultApplyStatsAction.java
+++ b/src/main/java/com/comandante/creeper/items/use/DefaultApplyEffectsStats.java
@@ -1,53 +1,54 @@
 package com.comandante.creeper.items.use;
 
-import com.comandante.creeper.items.*;
 import com.comandante.creeper.command.commands.UseCommand;
 import com.comandante.creeper.core_game.GameManager;
+import com.comandante.creeper.items.*;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.stats.Stats;
 import org.apache.log4j.Logger;
 
 import java.util.Set;
 
-public class DefaultApplyStatsAction implements ItemUseAction {
+public class DefaultApplyEffectsStats implements ItemUseAction {
 
-    private final Integer itemTypeId;
-    private final Stats stats;
+    private final String internalItemName;
     private final Set<Effect> effectSet;
-    private static final Logger log = Logger.getLogger(DefaultApplyStatsAction.class);
+    private final Stats itemApplyStats;
+    private static final Logger log = Logger.getLogger(DefaultApplyEffectsStats.class);
 
-    public DefaultApplyStatsAction(ItemType itemType, Stats stats, Set<Effect> effects) {
-        this.itemTypeId = itemType.getItemTypeCode();
-        this.stats = stats;
-        this.effectSet = effects;
+    public DefaultApplyEffectsStats(ItemMetadata itemMetadata) {
+        this.internalItemName = itemMetadata.getInternalItemName();
+        this.effectSet = itemMetadata.getEffects();
+        this.itemApplyStats = itemMetadata.getItemApplyStats();
     }
 
     @Override
-    public Integer getItemTypeId() {
-        return itemTypeId;
+    public String getInternalItemName() {
+        return internalItemName;
     }
 
     @Override
     public void executeAction(GameManager gameManager, Player player, Item item, UseCommand.UseItemOn useItemOn) {
         String playerName = player.getPlayerName();
-        ItemType itemType = ItemType.itemTypeFromCode(item.getItemTypeId());
-        gameManager.writeToPlayerCurrentRoom(player.getPlayerId(), playerName + " uses " + itemType.getItemName() + ".\r\n");
-        if (stats.getCurrentMana() > 0) {
-            gameManager.getChannelUtils().write(player.getPlayerId(), stats.getCurrentMana() + " mana is restored." + "\r\n");
+
+        gameManager.writeToPlayerCurrentRoom(player.getPlayerId(), playerName + " uses " + item.getItemName() + ".\r\n");
+        if (itemApplyStats.getCurrentMana() > 0) {
+            gameManager.getChannelUtils().write(player.getPlayerId(), itemApplyStats.getCurrentMana() + " mana is restored." + "\r\n");
         }
-        if (stats.getCurrentHealth() > 0) {
-            gameManager.getChannelUtils().write(player.getPlayerId(), stats.getCurrentHealth() + " health is restored." + "\r\n");
+        if (itemApplyStats.getCurrentHealth() > 0) {
+            gameManager.getChannelUtils().write(player.getPlayerId(), itemApplyStats.getCurrentHealth() + " health is restored." + "\r\n");
         }
-        player.addMana(stats.getCurrentMana());
-        player.updatePlayerHealth(stats.getCurrentHealth(), null);
+        player.addMana(itemApplyStats.getCurrentMana());
+        player.updatePlayerHealth(itemApplyStats.getCurrentHealth(), null);
+
         processEffects(gameManager, player, effectSet);
     }
 
     @Override
     public void postExecuteAction(GameManager gameManager, Player player, Item item) {
         ItemUseHandler.incrementUses(item);
-        if (ItemType.itemTypeFromCode(item.getItemTypeId()).isDisposable()) {
-            if (item.getNumberOfUses() < ItemType.itemTypeFromCode(item.getItemTypeId()).getMaxUses()) {
+        if (item.isDisposable()) {
+            if (item.getNumberOfUses() < item.getMaxUses()) {
                 gameManager.getEntityManager().saveItem(item);
             } else {
                 player.removeInventoryId(item.getItemId());
@@ -68,8 +69,7 @@ public class DefaultApplyStatsAction implements ItemUseAction {
         for (Effect effect : effects) {
             Effect nEffect = new Effect(effect);
             nEffect.setPlayerId(player.getPlayerId());
-            gameManager.getEntityManager().saveEffect(nEffect);
-            boolean effectResult = player.addEffect(nEffect.getEntityId());
+            boolean effectResult = player.addEffect(nEffect);
             if (effect.getDurationStats() != null) {
                 if (effect.getDurationStats().getCurrentHealth() < 0) {
                     log.error("ERROR! Someone added an effect with a health modifier which won't work for various reasons.");
diff --git a/src/main/java/com/comandante/creeper/items/use/DirtyBombUseAction.java b/src/main/java/com/comandante/creeper/items/use/DirtyBombUseAction.java
index 38f41f7e8db380f08d7e27fa7429d4e274f3408b..37d1864237201b987ed4d14ceea29aea57fd91ab 100644
--- a/src/main/java/com/comandante/creeper/items/use/DirtyBombUseAction.java
+++ b/src/main/java/com/comandante/creeper/items/use/DirtyBombUseAction.java
@@ -1,8 +1,8 @@
 package com.comandante.creeper.items.use;
 
-import com.comandante.creeper.items.*;
 import com.comandante.creeper.command.commands.UseCommand;
 import com.comandante.creeper.core_game.GameManager;
+import com.comandante.creeper.items.*;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.npc.NpcStatsChangeBuilder;
 import com.comandante.creeper.player.Player;
@@ -17,15 +17,15 @@ import java.util.Set;
 
 public class DirtyBombUseAction implements ItemUseAction {
 
-    private final ItemType itemType;
+    private final ItemMetadata itemMetadata;
 
-    public DirtyBombUseAction(ItemType itemType) {
-        this.itemType = itemType;
+    public DirtyBombUseAction(ItemMetadata itemMetadata) {
+        this.itemMetadata = itemMetadata;
     }
 
     @Override
-    public Integer getItemTypeId() {
-        return itemType.getItemTypeCode();
+    public String getInternalItemName() {
+        return itemMetadata.getInternalItemName();
     }
 
     @Override
@@ -61,8 +61,8 @@ public class DirtyBombUseAction implements ItemUseAction {
     @Override
     public void postExecuteAction(GameManager gameManager, Player player, Item item) {
         ItemUseHandler.incrementUses(item);
-        if (ItemType.itemTypeFromCode(item.getItemTypeId()).isDisposable()) {
-            if (item.getNumberOfUses() < ItemType.itemTypeFromCode(item.getItemTypeId()).getMaxUses()) {
+        if (item.isDisposable()) {
+            if (item.getNumberOfUses() < item.getMaxUses()) {
                 gameManager.getEntityManager().saveItem(item);
             } else {
                 player.removeInventoryId(item.getItemId());
diff --git a/src/main/java/com/comandante/creeper/items/use/LightningSpellBookUseAction.java b/src/main/java/com/comandante/creeper/items/use/LightningSpellBookUseAction.java
index 9faefdfa89706ba09bc7091dbecd27b32ba2cd9e..c2037614f2814d03ef8a575278d358b2e52f4bd7 100644
--- a/src/main/java/com/comandante/creeper/items/use/LightningSpellBookUseAction.java
+++ b/src/main/java/com/comandante/creeper/items/use/LightningSpellBookUseAction.java
@@ -1,11 +1,11 @@
 package com.comandante.creeper.items.use;
 
+import com.comandante.creeper.command.commands.UseCommand;
+import com.comandante.creeper.core_game.GameManager;
 import com.comandante.creeper.items.Effect;
 import com.comandante.creeper.items.Item;
-import com.comandante.creeper.items.ItemType;
+import com.comandante.creeper.items.ItemMetadata;
 import com.comandante.creeper.items.ItemUseAction;
-import com.comandante.creeper.command.commands.UseCommand;
-import com.comandante.creeper.core_game.GameManager;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.spells.LightningSpell;
 
@@ -13,17 +13,17 @@ import java.util.Set;
 
 public class LightningSpellBookUseAction implements ItemUseAction {
 
-    private final ItemType itemType;
+    private final ItemMetadata itemMetadata;
 
-    public LightningSpellBookUseAction(ItemType itemType) {
-        this.itemType = itemType;
+    public LightningSpellBookUseAction(ItemMetadata itemMetadata) {
+        this.itemMetadata = itemMetadata;
     }
 
     private Boolean dontDelete = Boolean.FALSE;
 
     @Override
-    public Integer getItemTypeId() {
-        return itemType.getItemTypeCode();
+    public String getInternalItemName() {
+        return itemMetadata.getInternalItemName();
     }
 
     @Override
diff --git a/src/main/java/com/comandante/creeper/items/use/ResetAllEffectsUseAction.java b/src/main/java/com/comandante/creeper/items/use/ResetAllEffectsUseAction.java
index f2b42885ab6cea5f299fa20b2ffb3c82bb58c202..d6bb783691d6546d2c9449f66b4dbacc9d349db3 100644
--- a/src/main/java/com/comandante/creeper/items/use/ResetAllEffectsUseAction.java
+++ b/src/main/java/com/comandante/creeper/items/use/ResetAllEffectsUseAction.java
@@ -1,26 +1,25 @@
 package com.comandante.creeper.items.use;
 
-import com.comandante.creeper.items.*;
 import com.comandante.creeper.command.commands.UseCommand;
 import com.comandante.creeper.core_game.GameManager;
+import com.comandante.creeper.items.*;
 import com.comandante.creeper.player.Player;
 
 import java.util.Set;
 
 public class ResetAllEffectsUseAction implements ItemUseAction {
 
-    private final ItemType itemType;
+    private final ItemMetadata itemMetadata;
 
-    public ResetAllEffectsUseAction(ItemType itemType) {
-        this.itemType = itemType;
+    public ResetAllEffectsUseAction(ItemMetadata itemMetadata) {
+        this.itemMetadata = itemMetadata;
     }
 
     @Override
-    public Integer getItemTypeId() {
-        return itemType.getItemTypeCode();
+    public String getInternalItemName() {
+        return itemMetadata.getInternalItemName();
     }
 
-
     @Override
     public void executeAction(GameManager gameManager, Player player, Item item, UseCommand.UseItemOn useItemOn) {
         player.resetEffects();
@@ -30,8 +29,8 @@ public class ResetAllEffectsUseAction implements ItemUseAction {
     @Override
     public void postExecuteAction(GameManager gameManager, Player player, Item item) {
         ItemUseHandler.incrementUses(item);
-        if (ItemType.itemTypeFromCode(item.getItemTypeId()).isDisposable()) {
-            if (item.getNumberOfUses() < ItemType.itemTypeFromCode(item.getItemTypeId()).getMaxUses()) {
+        if (item.isDisposable()) {
+            if (item.getNumberOfUses() < item.getMaxUses()) {
                 gameManager.getEntityManager().saveItem(item);
             } else {
                 player.removeInventoryId(item.getItemId());
diff --git a/src/main/java/com/comandante/creeper/items/use/StickOfJusticeUseAction.java b/src/main/java/com/comandante/creeper/items/use/StickOfJusticeUseAction.java
index f510773fbde90620856d2a28db766875505d1b1a..7a48baca74efc11e900110f51e53d6a766c27306 100644
--- a/src/main/java/com/comandante/creeper/items/use/StickOfJusticeUseAction.java
+++ b/src/main/java/com/comandante/creeper/items/use/StickOfJusticeUseAction.java
@@ -4,7 +4,7 @@ import com.comandante.creeper.command.commands.UseCommand;
 import com.comandante.creeper.core_game.GameManager;
 import com.comandante.creeper.items.Effect;
 import com.comandante.creeper.items.Item;
-import com.comandante.creeper.items.ItemType;
+import com.comandante.creeper.items.ItemMetadata;
 import com.comandante.creeper.items.ItemUseAction;
 import com.comandante.creeper.player.Player;
 
@@ -13,17 +13,18 @@ import java.util.Set;
 
 public class StickOfJusticeUseAction implements ItemUseAction {
 
-    private final ItemType itemType;
+    private final ItemMetadata itemMetadata;
 
-    public StickOfJusticeUseAction(ItemType itemType) {
-        this.itemType = itemType;
+    public StickOfJusticeUseAction(ItemMetadata itemMetadata) {
+        this.itemMetadata = itemMetadata;
     }
 
     @Override
-    public Integer getItemTypeId() {
-        return itemType.getItemTypeCode();
+    public String getInternalItemName() {
+        return itemMetadata.getInternalItemName();
     }
 
+
     @Override
     public void executeAction(GameManager gameManager, Player player, Item item, UseCommand.UseItemOn useItemOn) {
 
diff --git a/src/main/java/com/comandante/creeper/merchant/BlackbeardRogue.java b/src/main/java/com/comandante/creeper/merchant/BlackbeardRogue.java
deleted file mode 100644
index dbf9f53ab69d7f725fbb5d37415dd95047427370..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/BlackbeardRogue.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.comandante.creeper.merchant;
-
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class BlackbeardRogue extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "blackbeard";
-    private final static String welcomeMessage = "Welcome to Blackbeard's Rogue Shop.\r\n";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"blackbeard", "b", "rogue", "r", NAME}
-    ));
-
-    private final static String colorName = BOLD_ON + Color.CYAN + NAME  + Color.RESET ;
-
-    public BlackbeardRogue(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/merchant/Blacksmith.java b/src/main/java/com/comandante/creeper/merchant/Blacksmith.java
deleted file mode 100644
index 7ff02d084fa141a52620c6a4029795ae41e31b04..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/Blacksmith.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.comandante.creeper.merchant;
-
-
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class Blacksmith extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "biggers the blacksmith";
-    private final static String welcomeMessage = "  ____  _                                              \r\n" +
-            " | __ )(_) __ _  __ _  ___ _ __ ___                    \r\n" +
-            " |  _ \\| |/ _` |/ _` |/ _ \\ '__/ __|                   \r\n" +
-            " | |_) | | (_| | (_| |  __/ |  \\__ \\                   \r\n" +
-            " |____/|_|\\__, |\\__, |\\___|_|  |___/                   \r\n" +
-            "     ____ |___/ |___/   _                  _ _   _     \r\n" +
-            "    | __ )| | __ _  ___| | _____ _ __ ___ (_) |_| |__  \r\n" +
-            "    |  _ \\| |/ _` |/ __| |/ / __| '_ ` _ \\| | __| '_ \\ \r\n" +
-            "    | |_) | | (_| | (__|   <\\__ \\ | | | | | | |_| | | |\r\n" +
-            "    |____/|_|\\__,_|\\___|_|\\_\\___/_| |_| |_|_|\\__|_| |_|\r\n" +
-            "                                                       ";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"blacksmith", "biggers the blacksmith", "biggers", NAME}
-    ));
-
-    private final static String colorName = BOLD_ON + Color.CYAN + NAME  + Color.RESET ;
-
-    public Blacksmith(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/merchant/GrimulfWizard.java b/src/main/java/com/comandante/creeper/merchant/GrimulfWizard.java
deleted file mode 100644
index 3b61d19540cd3ce0c18ad2fa0e62a651fac93dc1..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/GrimulfWizard.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.comandante.creeper.merchant;
-
-
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class GrimulfWizard extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "grimulf the wizard";
-    private final static String welcomeMessage = "Welcome to my den.\r\n";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"grimulf", "g", "wizard", "w", NAME}
-    ));
-
-    private final static String colorName = BOLD_ON + Color.CYAN + NAME  + Color.RESET ;
-
-    public GrimulfWizard(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/merchant/JimBanker.java b/src/main/java/com/comandante/creeper/merchant/JimBanker.java
deleted file mode 100644
index 8db155e516f674d66092f22f6995548c5bfc813a..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/JimBanker.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.comandante.creeper.merchant;
-
-
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class JimBanker extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "jim the banker";
-    private final static String welcomeMessage = "Welcome to the First National Bank of Creeper.";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"bank", "banker", "jim the banker", "jim", "j", NAME}
-    ));
-
-    private final static String colorName = BOLD_ON + Color.CYAN + NAME + Color.RESET;
-
-    public JimBanker(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage, MerchantType.BANK);
-    }
-
-    @Override
-    public String getMenu() {
-        return null;
-    }
-}
-
diff --git a/src/main/java/com/comandante/creeper/merchant/KetilCommissary.java b/src/main/java/com/comandante/creeper/merchant/KetilCommissary.java
deleted file mode 100644
index 13a32292f50e054ca8afad2a09f4fcef816beca9..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/KetilCommissary.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.comandante.creeper.merchant;
-
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class KetilCommissary extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "ketil";
-    private final static String welcomeMessage = "Welcome to the Ketil Commissary.\r\n";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"ketil", "k", "commissary", "c", NAME}
-    ));
-
-    private final static String colorName = BOLD_ON + Color.CYAN + NAME  + Color.RESET ;
-
-    public KetilCommissary(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/merchant/LloydBartender.java b/src/main/java/com/comandante/creeper/merchant/LloydBartender.java
deleted file mode 100644
index 7af2274ea5662e750f86902c2c99e1725d28a1c5..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/LloydBartender.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.comandante.creeper.merchant;
-
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class LloydBartender extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "lloyd the bartender";
-    private final static String welcomeMessage = " _        _        _______           ______   _  _______ \r\n" +
-            "( \\      ( \\      (  ___  )|\\     /|(  __  \\ ( )(  ____ \\\r\n" +
-            "| (      | (      | (   ) |( \\   / )| (  \\  )|/ | (    \\/\r\n" +
-            "| |      | |      | |   | | \\ (_) / | |   ) |   | (_____ \r\n" +
-            "| |      | |      | |   | |  \\   /  | |   | |   (_____  )\r\n" +
-            "| |      | |      | |   | |   ) (   | |   ) |         ) |\r\n" +
-            "| (____/\\| (____/\\| (___) |   | |   | (__/  )   /\\____) |\r\n" +
-            "(_______/(_______/(_______)   \\_/   (______/    \\_______)\r\n" +
-            "                                                         ";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"lloyd", "bartender", "barkeep", "Lloyd", "LLOYD", NAME}
-    ));
-
-    private final static String colorName = BOLD_ON + Color.CYAN + NAME  + Color.RESET ;
-
-    public LloydBartender(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/merchant/LockerRoomGuy.java b/src/main/java/com/comandante/creeper/merchant/LockerRoomGuy.java
deleted file mode 100644
index 952e64595e96278b90486d78c2b508dc419a48f8..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/LockerRoomGuy.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.comandante.creeper.merchant;
-
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class LockerRoomGuy extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "a bank of lockers";
-    private final static String welcomeMessage = "Locker opened.";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"lockers", "locker", "l", NAME}
-    ));
-
-    private final static String colorName = BOLD_ON + Color.RED + NAME + Color.RESET;
-
-    public LockerRoomGuy(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage, MerchantType.LOCKER);
-    }
-
-    @Override
-    public String getMenu() {
-        return null;
-    }
-}
-
diff --git a/src/main/java/com/comandante/creeper/merchant/Merchant.java b/src/main/java/com/comandante/creeper/merchant/Merchant.java
index 1335704720d49d8ef9cdea0b0e165ec2447f324a..cb0ebc2e7441260f869d3ff037ebf30e4b856288 100644
--- a/src/main/java/com/comandante/creeper/merchant/Merchant.java
+++ b/src/main/java/com/comandante/creeper/merchant/Merchant.java
@@ -1,33 +1,31 @@
 package com.comandante.creeper.merchant;
 
 import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.entity.CreeperEntity;
+import com.comandante.creeper.items.ItemMetadata;
 import org.nocrala.tools.texttablefmt.BorderStyle;
 import org.nocrala.tools.texttablefmt.ShownBorders;
 import org.nocrala.tools.texttablefmt.Table;
 
 import java.text.NumberFormat;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
-public abstract class Merchant extends CreeperEntity {
+public class Merchant {
 
-    private long lastPhraseTimestamp;
     private final GameManager gameManager;
+    private final String internalName;
     private final String name;
     private final String colorName;
     private final Set<String> validTriggers;
-    private final Map<Integer, MerchantItemForSale> merchantItemForSales;
+    private final List<MerchantItemForSale> merchantItemForSales;
     private final String welcomeMessage;
     private final MerchantType merchantType;
+    private final Set<Integer> roomIds;
 
-    public Merchant(GameManager gameManager, String name, String colorName, Set<String> validTriggers, Map<Integer, MerchantItemForSale> merchantItemForSales, String welcomeMessage) {
-        this(gameManager, name, colorName, validTriggers, merchantItemForSales, welcomeMessage, MerchantType.BASIC);
+    public Merchant(GameManager gameManager, String internalName, String name, String colorName, Set<String> validTriggers, List<MerchantItemForSale> merchantItemForSales, String welcomeMessage, Set<Integer> roomIds) {
+        this(gameManager, internalName, name, colorName, validTriggers, merchantItemForSales, welcomeMessage, roomIds, MerchantType.BASIC);
     }
 
-    public Merchant(GameManager gameManager, String name, String colorName, Set<String> validTriggers, Map<Integer, MerchantItemForSale> merchantItemForSales, String welcomeMessage, MerchantType merchantType) {
+    public Merchant(GameManager gameManager, String internalName, String name, String colorName, Set<String> validTriggers, List<MerchantItemForSale> merchantItemForSales, String welcomeMessage, Set<Integer> roomIds, MerchantType merchantType) {
         this.gameManager = gameManager;
         this.name = name;
         this.colorName = colorName;
@@ -35,6 +33,13 @@ public abstract class Merchant extends CreeperEntity {
         this.merchantItemForSales = merchantItemForSales;
         this.welcomeMessage = welcomeMessage;
         this.merchantType = merchantType;
+        this.roomIds = roomIds;
+        this.internalName = internalName;
+
+    }
+
+    public String getInternalName() {
+        return internalName;
     }
 
     public String getMenu() {
@@ -46,31 +51,31 @@ public abstract class Merchant extends CreeperEntity {
         t.addCell("#");
         t.addCell("price");
         t.addCell("description");
-        int i = 1;
-        Iterator<Map.Entry<Integer, MerchantItemForSale>> entries = merchantItemForSales.entrySet().iterator();
-        while (entries.hasNext()) {
-            Map.Entry<Integer, MerchantItemForSale> next = entries.next();
-            t.addCell(String.valueOf(next.getKey()));
-            t.addCell(NumberFormat.getNumberInstance(Locale.US).format(next.getValue().getCost()));
-            t.addCell(next.getValue().getItem().getItemDescription());
+        int i = 0;
+        Iterator<MerchantItemForSale> iterator = merchantItemForSales.iterator();
+        while (iterator.hasNext()) {
             i++;
+            MerchantItemForSale merchantItemForSale = iterator.next();
+            Optional<ItemMetadata> itemMetadataOptional = gameManager.getItemStorage().get(merchantItemForSale.getInternalItemName());
+            if (!itemMetadataOptional.isPresent()) {
+                continue;
+            }
+            ItemMetadata itemMetadata = itemMetadataOptional.get();
+            t.addCell(String.valueOf(i));
+            t.addCell(NumberFormat.getNumberInstance(Locale.US).format(merchantItemForSale.getCost()));
+            t.addCell(itemMetadata.getItemDescription());
         }
         return t.render();
     }
 
-    @Override
-    public void run() {
-
-    }
-
-    public long getLastPhraseTimestamp() {
-        return lastPhraseTimestamp;
-    }
-
     public GameManager getGameManager() {
         return gameManager;
     }
 
+    public Set<Integer> getRoomIds() {
+        return roomIds;
+    }
+
     public String getName() {
         return name;
     }
@@ -83,7 +88,7 @@ public abstract class Merchant extends CreeperEntity {
         return validTriggers;
     }
 
-    public Map<Integer, MerchantItemForSale> getMerchantItemForSales() {
+    public List<MerchantItemForSale> merchantItemForSales() {
         return merchantItemForSales;
     }
 
@@ -95,6 +100,10 @@ public abstract class Merchant extends CreeperEntity {
         return merchantType;
     }
 
+    public List<MerchantItemForSale> getMerchantItemForSales() {
+        return merchantItemForSales;
+    }
+
     public enum MerchantType {
         BANK,
         LOCKER,
diff --git a/src/main/java/com/comandante/creeper/merchant/MerchantCommandHandler.java b/src/main/java/com/comandante/creeper/merchant/MerchantCommandHandler.java
index 5ffffb67407b6119d83b1cfa5b02a387f26f5134..5c5f29202787503faa7ad13732e0b3a6ce5bd106 100644
--- a/src/main/java/com/comandante/creeper/merchant/MerchantCommandHandler.java
+++ b/src/main/java/com/comandante/creeper/merchant/MerchantCommandHandler.java
@@ -1,9 +1,8 @@
 package com.comandante.creeper.merchant;
 
-import com.comandante.creeper.items.Item;
-import com.comandante.creeper.items.ItemType;
 import com.comandante.creeper.command.commands.CommandAuditLog;
 import com.comandante.creeper.core_game.GameManager;
+import com.comandante.creeper.items.Item;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.server.model.CreeperSession;
 import com.comandante.creeper.server.player_communication.Color;
@@ -94,7 +93,7 @@ public class MerchantCommandHandler extends SimpleChannelUpstreamHandler {
         for (Item itemEntity : inventory) {
             int valueInGold = itemEntity.getValueInGold();
             if (valueInGold == 0) {
-                valueInGold = ItemType.itemTypeFromCode(itemEntity.getItemTypeId()).getValueInGold();
+                valueInGold = itemEntity.getValueInGold();
             }
             if (valueInGold > 0) {
                 inventoryItemsForSale.put(inv, new InventoryItemForSale(valueInGold, itemEntity));
diff --git a/src/main/java/com/comandante/creeper/merchant/MerchantItemForSale.java b/src/main/java/com/comandante/creeper/merchant/MerchantItemForSale.java
index 2acb8b7a20f587718630de8e278a4619ce66f051..f47ddafbe3a435ee409ad12a58f715ba0cc2bc45 100644
--- a/src/main/java/com/comandante/creeper/merchant/MerchantItemForSale.java
+++ b/src/main/java/com/comandante/creeper/merchant/MerchantItemForSale.java
@@ -1,19 +1,16 @@
 package com.comandante.creeper.merchant;
 
-import com.comandante.creeper.items.ItemType;
-
-
 public class MerchantItemForSale {
-    private final ItemType itemType;
+    private final String internalItemName;
     private final int cost;
 
-    public MerchantItemForSale(ItemType itemType, int cost) {
-        this.itemType = itemType;
+    public MerchantItemForSale(String internalItemName, int cost) {
+        this.internalItemName = internalItemName;
         this.cost = cost;
     }
 
-    public ItemType getItem() {
-        return itemType;
+    public String getInternalItemName() {
+        return internalItemName;
     }
 
     public int getCost() {
diff --git a/src/main/java/com/comandante/creeper/merchant/MerchantManager.java b/src/main/java/com/comandante/creeper/merchant/MerchantManager.java
index 8616388996775148c14a5d8833dd2c8923d02874..927b20dbe1fdc66744118752721ac40e6f11bdb8 100644
--- a/src/main/java/com/comandante/creeper/merchant/MerchantManager.java
+++ b/src/main/java/com/comandante/creeper/merchant/MerchantManager.java
@@ -2,14 +2,14 @@ package com.comandante.creeper.merchant;
 
 
 import com.codahale.metrics.Timer;
-import com.comandante.creeper.items.Item;
 import com.comandante.creeper.Main;
 import com.comandante.creeper.core_game.GameManager;
+import com.comandante.creeper.items.Item;
+import com.comandante.creeper.items.ItemBuilder;
+import com.comandante.creeper.items.ItemMetadata;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.player.PlayerMetadata;
 
-import java.util.Iterator;
-import java.util.Map;
 import java.util.Optional;
 
 import static com.codahale.metrics.MetricRegistry.name;
@@ -27,16 +27,22 @@ public class MerchantManager {
     public void purchaseItem(Merchant merchant, int itemNo, Player player) {
         final Timer.Context context = responses.time();
         try {
-            Iterator<Map.Entry<Integer, MerchantItemForSale>> merchantItemForSales = merchant.getMerchantItemForSales().entrySet().iterator();
-            while (merchantItemForSales.hasNext()) {
-                Map.Entry<Integer, MerchantItemForSale> next = merchantItemForSales.next();
-                if (next.getKey().equals(itemNo)) {
+            int i = 0;
+            for (MerchantItemForSale merchantItemForSale : merchant.getMerchantItemForSales()) {
+                i++;
+                if (i == itemNo) {
+                    String internalItemName = merchantItemForSale.getInternalItemName();
+                    Optional<ItemMetadata> itemMetadataOptional = gameManager.getItemStorage().get(internalItemName);
+                    if (!itemMetadataOptional.isPresent()) {
+                        continue;
+                    }
+                    ItemMetadata itemMetadata = itemMetadataOptional.get();
                     long maxInventorySize = player.getPlayerStatsWithEquipmentAndLevel().getInventorySize();
                     if (player.getInventory().size() >= maxInventorySize) {
                         gameManager.getChannelUtils().write(player.getPlayerId(), "Your inventory is full, drop some items and come back.\r\n");
                         return;
                     }
-                    int price = next.getValue().getCost();
+                    int price = merchantItemForSale.getCost();
                     Optional<PlayerMetadata> playerMetadataOptional = gameManager.getPlayerManager().getPlayerMetadata(player.getPlayerId());
                     if (!playerMetadataOptional.isPresent()) {
                         continue;
@@ -44,13 +50,13 @@ public class MerchantManager {
                     PlayerMetadata playerMetadata = playerMetadataOptional.get();
                     long availableGold = playerMetadata.getGold();
                     if (availableGold >= price) {
-                        Item item = next.getValue().getItem().create();
+                        Item item = new ItemBuilder().from(itemMetadata).create();
                         gameManager.getEntityManager().saveItem(item);
                         gameManager.acquireItem(player, item.getItemId());
                         player.incrementGold(-price);
                         gameManager.getChannelUtils().write(player.getPlayerId(), "You have purchased: " + item.getItemName() + "\r\n");
                     } else {
-                        gameManager.getChannelUtils().write(player.getPlayerId(), "You can't afford: " + next.getValue().getItem().getItemName() + "\r\n");
+                        gameManager.getChannelUtils().write(player.getPlayerId(), "You can't afford: " + itemMetadata.getItemName() + "\r\n");
                     }
                 }
             }
diff --git a/src/main/java/com/comandante/creeper/merchant/MerchantMetadata.java b/src/main/java/com/comandante/creeper/merchant/MerchantMetadata.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba4dc8f59854d2905187b65d52575797e080481e
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/merchant/MerchantMetadata.java
@@ -0,0 +1,86 @@
+package com.comandante.creeper.merchant;
+
+import java.util.List;
+import java.util.Set;
+
+public class MerchantMetadata {
+
+    private String internalName;
+    private Set<Integer> roomIds;
+    private String name;
+    private String colorName;
+    private Set<String> validTriggers;
+    private List<MerchantItemForSale> merchantItemForSales;
+    private String welcomeMessage;
+    private Merchant.MerchantType merchantType;
+
+    public void setMerchantType(Merchant.MerchantType merchantType) {
+        this.merchantType = merchantType;
+    }
+
+    public Set<Integer> getRoomIds() {
+
+        return roomIds;
+    }
+
+    public Merchant.MerchantType getMerchantType() {
+        return merchantType;
+    }
+
+    public String getInternalName() {
+        return internalName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getColorName() {
+        return colorName;
+    }
+
+    public void setColorName(String colorName) {
+        this.colorName = colorName;
+    }
+
+    public Set<String> getValidTriggers() {
+        return validTriggers;
+    }
+
+    public void setValidTriggers(Set<String> validTriggers) {
+        this.validTriggers = validTriggers;
+    }
+
+    public List<MerchantItemForSale> getMerchantItemForSales() {
+        return merchantItemForSales;
+    }
+
+    public void setInternalName(String internalName) {
+        this.internalName = internalName;
+    }
+
+    public Set<Integer> getRoomId() {
+        return roomIds;
+    }
+
+    public void setRoomIds(Set<Integer> roomIds) {
+        this.roomIds = roomIds;
+    }
+
+    public void setMerchantItemForSales(List<MerchantItemForSale> merchantItemForSales) {
+        this.merchantItemForSales = merchantItemForSales;
+
+    }
+
+    public String getWelcomeMessage() {
+        return welcomeMessage;
+    }
+
+    public void setWelcomeMessage(String welcomeMessage) {
+        this.welcomeMessage = welcomeMessage;
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/merchant/NigelBartender.java b/src/main/java/com/comandante/creeper/merchant/NigelBartender.java
deleted file mode 100644
index aae4efe11eb9caba522b07074aaca70b7ccc2ffc..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/NigelBartender.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.comandante.creeper.merchant;
-
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class NigelBartender extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "nigel the bartender";
-    private final static String welcomeMessage = "\r\n N I G E L 'S   B A R \r\n";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"nigel", "bartender", "barkeep", "Nigel", "NIGEL", NAME}
-    ));
-
-    private final static String colorName = BOLD_ON + Color.CYAN + NAME  + Color.RESET ;
-
-    public NigelBartender(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/merchant/OldWiseMan.java b/src/main/java/com/comandante/creeper/merchant/OldWiseMan.java
deleted file mode 100644
index eed1aefc44d90fa80a21dae7be28377a71ada8c7..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/OldWiseMan.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.comandante.creeper.merchant;
-
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class OldWiseMan extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "old wise man";
-    private final static String colorName = BOLD_ON + Color.CYAN + NAME + Color.RESET;
-    private final static String welcomeMessage = "The "+ colorName +" can assist you in choosing a character class.\r\n";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-            {"wise", "man", "old", "old wise man", "m", "w", NAME}
-    ));
-
-
-    public OldWiseMan(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage, MerchantType.PLAYERCLASS_SELECTOR);
-    }
-
-    @Override
-    public String getMenu() {
-        return null;
-    }
-}
-
diff --git a/src/main/java/com/comandante/creeper/merchant/WentworthTailor.java b/src/main/java/com/comandante/creeper/merchant/WentworthTailor.java
deleted file mode 100644
index 3183a08a3e40ff9c2e6295f1d692bcd5025cfc10..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/WentworthTailor.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.comandante.creeper.merchant;
-
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class WentworthTailor extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "wentworth";
-    private final static String welcomeMessage = "Welcome to WENTWORTH's TAILOR SHOP.\r\n";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"wentworth", "w", "tailor", "t", NAME}
-    ));
-
-    private final static String colorName = BOLD_ON + Color.CYAN + NAME  + Color.RESET ;
-
-    public WentworthTailor(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/merchant/Wizard.java b/src/main/java/com/comandante/creeper/merchant/Wizard.java
deleted file mode 100644
index 14a9fc5d5a5b500b201e1d4596e056ce4b311a91..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/merchant/Wizard.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.comandante.creeper.merchant;
-
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.core_game.GameManager;
-import com.comandante.creeper.server.player_communication.Color;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
-
-public class Wizard extends Merchant {
-    private final static long phraseIntervalMs = 300000;
-    private final static String NAME = "willy the wizard";
-    private final static String welcomeMessage = "  ____                                        \n" +
-            " 6MMMMb\\                                      \n" +
-            "6M'    `   /                                  \n" +
-            "MM        /M       _____     _____   __ ____  \n" +
-            "YM.      /MMMMM   6MMMMMb   6MMMMMb  `M6MMMMb \n" +
-            " YMMMMb   MM     6M'   `Mb 6M'   `Mb  MM'  `Mb\n" +
-            "     `Mb  MM     MM     MM MM     MM  MM    MM\n" +
-            "      MM  MM     MM     MM MM     MM  MM    MM\n" +
-            "      MM  MM     MM     MM MM     MM  MM    MM\n" +
-            "L    ,M9  YM.  , YM.   ,M9 YM.   ,M9  MM.  ,M9\n" +
-            "MYMMMM9    YMMM9  YMMMMM9   YMMMMM9   MMYMMM9 \n" +
-            "                                      MM      \n" +
-            "                                      MM      \n" +
-            "                                     _MM_     \n" +
-            "\n";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-            {"wizard", "willy the wizard", "willy", NAME}
-    ));
-
-    private final static String colorName = BOLD_ON + Color.BLUE + NAME  + Color.RESET ;
-
-    public Wizard(GameManager gameManager, Loot loot, Map<Integer, MerchantItemForSale> merchantItemForSales) {
-        super(gameManager, NAME, colorName, validTriggers, merchantItemForSales, welcomeMessage);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/npc/Npc.java b/src/main/java/com/comandante/creeper/npc/Npc.java
index d00e7d76914d1e04aba3263e449d67ed3f784527..d6c524547f3a4f2639d58d03680669cb95b3d4d9 100644
--- a/src/main/java/com/comandante/creeper/npc/Npc.java
+++ b/src/main/java/com/comandante/creeper/npc/Npc.java
@@ -1,13 +1,12 @@
 package com.comandante.creeper.npc;
 
 
-import com.comandante.creeper.items.Effect;
-import com.comandante.creeper.items.Item;
-import com.comandante.creeper.items.Loot;
-import com.comandante.creeper.items.Rarity;
 import com.comandante.creeper.core_game.GameManager;
 import com.comandante.creeper.core_game.SentryManager;
 import com.comandante.creeper.entity.CreeperEntity;
+import com.comandante.creeper.items.Effect;
+import com.comandante.creeper.items.Item;
+import com.comandante.creeper.items.Loot;
 import com.comandante.creeper.player.CoolDown;
 import com.comandante.creeper.player.CoolDownType;
 import com.comandante.creeper.player.DamageProcessor;
@@ -87,7 +86,9 @@ public class Npc extends CreeperEntity {
                     if (effectsTickBucket == 5) {
 
                         // START Process NPC Effects
-                        for (Effect effect : effects) {
+                        Iterator<Effect> iterator = effects.iterator();
+                        while (iterator.hasNext()) {
+                            Effect effect = iterator.next();
                             if (effect.getEffectApplications() >= effect.getMaxEffectApplications()) {
                                 Optional<Room> npcCurrentRoom = gameManager.getRoomManager().getNpcCurrentRoom(this);
                                 if (npcCurrentRoom.isPresent()) {
@@ -95,13 +96,11 @@ public class Npc extends CreeperEntity {
                                     gameManager.writeToRoom(room.getRoomId(), Color.BOLD_ON + Color.GREEN + "[effect] " + Color.RESET + effect.getEffectName() + " has worn off of " + getName() + "\r\n");
                                 }
                                 gameManager.getEffectsManager().removeDurationStats(effect, this);
-                                gameManager.getEntityManager().removeEffect(effect);
-                                effects.remove(effect);
+                                iterator.remove();
                             } else {
                                 effect.setEffectApplications(effect.getEffectApplications() + 1);
                                 effectsTickBucket = effectsTickBucket + 1;
                                 gameManager.getEffectsManager().application(effect, this);
-                                gameManager.getEntityManager().saveEffect(effect);
                             }
                         }
                         // END Process Npc Effects
@@ -221,11 +220,14 @@ public class Npc extends CreeperEntity {
         playerDamageMap.put(playerId, amt);
     }
 
+
+
+
     private void killNpc(Player player) {
         isAlive.set(false);
         player.removeActiveAlertStatus(this);
         Map<String, Double> damagePercents;
-        Item corpse = new Item(getName() + " corpse", "a bloody corpse.", Arrays.asList("corpse", "c"), "a corpse lies on the ground.", UUID.randomUUID().toString(), Item.CORPSE_ID_RESERVED, 0, false, 120, Rarity.BASIC, 0, getLoot());
+        Item corpse = Item.createCorpseItem(getName(), getLoot());
         if (!player.isActive(CoolDownType.DEATH)) {
             gameManager.writeToPlayerCurrentRoom(player.getPlayerId(), getDieMessage() + "\r\n");
         }
@@ -308,7 +310,6 @@ public class Npc extends CreeperEntity {
     }
 
 
-
     public String getColorName() {
         return colorName;
     }
@@ -421,21 +422,21 @@ public class Npc extends CreeperEntity {
 
     public enum NpcLevelColor {
 
-    RED(Color.RED + "Red"),
-    ORANGE(Color.CYAN + "Cyan"),
-    YELLOW(Color.YELLOW + "Yellow"),
-    GREEN(Color.GREEN + "Green"),
-    WHITE(Color.WHITE + "White");
+        RED(Color.RED + "Red"),
+        ORANGE(Color.CYAN + "Cyan"),
+        YELLOW(Color.YELLOW + "Yellow"),
+        GREEN(Color.GREEN + "Green"),
+        WHITE(Color.WHITE + "White");
 
-    private final String color;
+        private final String color;
 
-    NpcLevelColor(String color) {
-        this.color = color;
-    }
+        NpcLevelColor(String color) {
+            this.color = color;
+        }
 
-    public String getColor() {
-        return "(" + Color.BOLD_ON + color + Color.RESET + ")";
+        public String getColor() {
+            return "(" + Color.BOLD_ON + color + Color.RESET + ")";
+        }
     }
-}
 
 }
diff --git a/src/main/java/com/comandante/creeper/player/Player.java b/src/main/java/com/comandante/creeper/player/Player.java
index 805ffaa8dca37a78838eb5475ba515992c7a646d..f58812c3006719ae4d35a8e7fbb90f5404dc9631 100644
--- a/src/main/java/com/comandante/creeper/player/Player.java
+++ b/src/main/java/com/comandante/creeper/player/Player.java
@@ -143,30 +143,20 @@ public class Player extends CreeperEntity {
                 return;
             }
             PlayerMetadata playerMetadata = playerMetadataOptional.get();
-            Iterator<String> iterator = playerMetadata.getEffects().iterator();
-            List<String> effectIdsToRemove = Lists.newArrayList();
-            while (iterator.hasNext()) {
-                String effectId = iterator.next();
-                Optional<Effect> effectOptional = gameManager.getEntityManager().getEffectEntity(playerId);
-                if (!effectOptional.isPresent()) {
-                    effectIdsToRemove.add(effectId);
+            List<Effect> effectsToRemove = Lists.newArrayList();
+            for (Effect effect : playerMetadata.getEffects()) {
+                if (effect.getEffectApplications() >= effect.getMaxEffectApplications()) {
+                    gameManager.getChannelUtils().write(playerId, Color.BOLD_ON + Color.GREEN + "[effect] " + Color.RESET + effect.getEffectName() + " has worn off.\r\n", true);
+                    effectsToRemove.add(effect);
                     continue;
                 } else {
-                    Effect effect = effectOptional.get();
-                    if (effect.getEffectApplications() >= effect.getMaxEffectApplications()) {
-                        gameManager.getChannelUtils().write(playerId, Color.BOLD_ON + Color.GREEN + "[effect] " + Color.RESET + effect.getEffectName() + " has worn off.\r\n", true);
-                        gameManager.getEntityManager().removeEffect(effect);
-                        effectIdsToRemove.add(effectId);
-                        continue;
-                    } else {
-                        effect.setEffectApplications(effect.getEffectApplications() + 1);
-                        gameManager.getEffectsManager().application(effect, this);
-                        gameManager.getEntityManager().saveEffect(effect);
-                    }
+                    effect.setEffectApplications(effect.getEffectApplications() + 1);
+                    gameManager.getEffectsManager().application(effect, this);
                 }
+
             }
-            for (String effectId : effectIdsToRemove) {
-                playerMetadata.removeEffectID(effectId);
+            for (Effect effect : effectsToRemove) {
+                playerMetadata.removeEffect(effect);
             }
             savePlayerMetadata(playerMetadata);
         }
@@ -365,7 +355,7 @@ public class Player extends CreeperEntity {
         }
     }
 
-    public boolean addEffect(String effectId) {
+    public boolean addEffect(Effect effect) {
         synchronized (interner.intern(playerId)) {
             Optional<PlayerMetadata> playerMetadataOptional = getPlayerMetadata();
             if (!playerMetadataOptional.isPresent()) {
@@ -375,7 +365,7 @@ public class Player extends CreeperEntity {
             if (playerMetadata.getEffects() != null && (playerMetadata.getEffects().size() >= playerMetadata.getStats().getMaxEffects())) {
                 return false;
             }
-            playerMetadata.addEffectId(effectId);
+            playerMetadata.addEffect(effect);
             savePlayerMetadata(playerMetadata);
             return true;
         }
@@ -866,8 +856,8 @@ public class Player extends CreeperEntity {
                 for (Item item : inventory) {
                     StringBuilder invItem = new StringBuilder();
                     invItem.append(item.getItemName());
-                    int maxUses = ItemType.itemTypeFromCode(item.getItemTypeId()).getMaxUses();
-                    if (maxUses > 0) {
+                    int maxUses = item.getMaxUses();
+                    if (item.getMaxUses() > 0) {
                         int remainingUses = maxUses - item.getNumberOfUses();
                         invItem.append(" - ").append(remainingUses);
                         if (remainingUses == 1) {
@@ -931,7 +921,7 @@ public class Player extends CreeperEntity {
                 for (Item item : inventory) {
                     StringBuilder invItem = new StringBuilder();
                     invItem.append(item.getItemName());
-                    int maxUses = ItemType.itemTypeFromCode(item.getItemTypeId()).getMaxUses();
+                    int maxUses = item.getMaxUses();
                     if (maxUses > 0) {
                         int remainingUses = maxUses - item.getNumberOfUses();
                         invItem.append(" - ").append(remainingUses);
@@ -1143,9 +1133,8 @@ public class Player extends CreeperEntity {
                 StatsHelper.combineStats(newStats, stats);
             }
             if (playerMetadata.getEffects() != null) {
-                for (String effectId : playerMetadata.getEffects()) {
-                    Optional<Effect> effectOptional = gameManager.getEntityManager().getEffectEntity(effectId);
-                    effectOptional.ifPresent(effect -> StatsHelper.combineStats(newStats, effect.getDurationStats()));
+                for (Effect effect : playerMetadata.getEffects()) {
+                    StatsHelper.combineStats(newStats, effect.getDurationStats());
                 }
             }
             return newStats;
@@ -1205,13 +1194,7 @@ public class Player extends CreeperEntity {
             return "";
         }
         PlayerMetadata playerMetadata = playerMetadataOptional.get();
-        List<Effect> effects = Lists.newArrayList();
-        if (playerMetadata.getEffects() != null) {
-            for (String effectId : playerMetadata.getEffects()) {
-                Optional<Effect> effectOptional = gameManager.getEntityManager().getEffectEntity(effectId);
-                effectOptional.ifPresent(effects::add);
-            }
-        }
+        List<Effect> effects = playerMetadata.getEffects();
         return gameManager.renderEffectsString(effects);
     }
 
diff --git a/src/main/java/com/comandante/creeper/player/PlayerManagement.java b/src/main/java/com/comandante/creeper/player/PlayerManagement.java
index 55d93bc4920362d4e29d652d4fec8ad073237dd2..49e61f15ee410f557ef59bca84cd2384d1f8cdc2 100644
--- a/src/main/java/com/comandante/creeper/player/PlayerManagement.java
+++ b/src/main/java/com/comandante/creeper/player/PlayerManagement.java
@@ -2,7 +2,8 @@ package com.comandante.creeper.player;
 
 import com.comandante.creeper.core_game.GameManager;
 import com.comandante.creeper.items.Item;
-import com.comandante.creeper.items.ItemType;
+import com.comandante.creeper.items.ItemBuilder;
+import com.comandante.creeper.items.ItemMetadata;
 import com.comandante.creeper.server.player_communication.Color;
 import com.google.api.client.util.Lists;
 import com.google.api.client.util.Maps;
@@ -278,12 +279,12 @@ public class PlayerManagement implements PlayerManagementMBean {
     }
 
     @Override
-    public String createItemInInventory(int itemTypeId){
-        ItemType itemType = ItemType.itemTypeFromCode(itemTypeId);
-        if (itemType.equals(ItemType.UNKNOWN)) {
-            return "No such item exists with id: " + itemTypeId;
+    public String createItemInInventory(String internalItemName){
+        Optional<ItemMetadata> itemMetadata = gameManager.getItemStorage().get(internalItemName);
+        if (!itemMetadata.isPresent()) {
+            return "No such item exists with internal name: " + internalItemName;
         }
-        Item item = itemType.create();
+        Item item = new ItemBuilder().from(itemMetadata.get()).create();
         gameManager.getEntityManager().saveItem(item);
         synchronized (findInterner().intern(playerId)) {
             Optional<PlayerMetadata> playerMetadataOptional = gameManager.getPlayerManager().getPlayerMetadata(playerId);
diff --git a/src/main/java/com/comandante/creeper/player/PlayerManagementMBean.java b/src/main/java/com/comandante/creeper/player/PlayerManagementMBean.java
index 08ab33b376f1f56574d89cc675463b179fd8c7c4..04b8df640b1cfd15705b227df04e8b7799829151 100644
--- a/src/main/java/com/comandante/creeper/player/PlayerManagementMBean.java
+++ b/src/main/java/com/comandante/creeper/player/PlayerManagementMBean.java
@@ -42,7 +42,7 @@ public interface PlayerManagementMBean {
 
     Map<String, String> getLockerInventory();
 
-    String createItemInInventory(int itemTypeId);
+    String createItemInInventory(String internalItemName);
 
     void setPlayerClass(String playerClassName);
 
diff --git a/src/main/java/com/comandante/creeper/player/PlayerManager.java b/src/main/java/com/comandante/creeper/player/PlayerManager.java
index 6492bd460f0e6f9d390bfdffee4d51b3e4708572..e5ae8db3b691ddfd466a79ade9bf019343f7f8c9 100644
--- a/src/main/java/com/comandante/creeper/player/PlayerManager.java
+++ b/src/main/java/com/comandante/creeper/player/PlayerManager.java
@@ -6,13 +6,8 @@ import com.comandante.creeper.Main;
 import com.comandante.creeper.core_game.SessionManager;
 import com.comandante.creeper.stats.Stats;
 import com.comandante.creeper.storage.CreeperStorage;
-import com.comandante.creeper.storage.MapDbAutoCommitService;
 import com.comandante.creeper.world.model.Room;
-import com.google.gson.Gson;
 import org.apache.commons.codec.binary.Base64;
-import org.mapdb.DB;
-import org.mapdb.HTreeMap;
-import org.mapdb.Serializer;
 
 import java.util.Iterator;
 import java.util.Map;
@@ -93,11 +88,8 @@ public class PlayerManager {
     }
 
     public Optional<PlayerMetadata> getPlayerMetadata(String playerId) {
-        Optional<PlayerMetadata> playerMetadata = creeperStorage.getPlayerMetadata(playerId);
-        if (playerMetadata.isPresent()) {
-            return playerMetadata;
-        }
-        return Optional.of(new PlayerMetadata(playerMetadata.get()));
+        Optional<PlayerMetadata> playerMetadataOptional = creeperStorage.getPlayerMetadata(playerId);
+        return playerMetadataOptional.map(PlayerMetadata::new);
     }
 
     public boolean hasAnyOfRoles(Player player, Set<PlayerRole> checkRoles) {
diff --git a/src/main/java/com/comandante/creeper/player/PlayerMetadata.java b/src/main/java/com/comandante/creeper/player/PlayerMetadata.java
index 9ef91e135a75f389fc7e0dff4858c8e868fd865e..7edd8a72982574e7737f76e82f6378a560ad2344 100644
--- a/src/main/java/com/comandante/creeper/player/PlayerMetadata.java
+++ b/src/main/java/com/comandante/creeper/player/PlayerMetadata.java
@@ -1,6 +1,7 @@
 package com.comandante.creeper.player;
 
 
+import com.comandante.creeper.items.Effect;
 import com.comandante.creeper.stats.Stats;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -22,7 +23,7 @@ public class PlayerMetadata implements Serializable {
     private long goldInBank;
     private Set<PlayerRole> playerRoleSet;
     private String[] playerEquipment;
-    private List<String> effects;
+    private List<Effect> effects;
     private boolean isMarkedForDelete;
     private Map<String, String> playerSettings;
     private String[] learnedSpells;
@@ -201,11 +202,11 @@ public class PlayerMetadata implements Serializable {
         this.playerEquipment = newItems;
     }
 
-    protected void addEffectId(String effectId) {
+    protected void addEffect(Effect effect) {
         if (effects == null) {
             effects = Lists.newArrayList();
         }
-        effects.add(effectId);
+        effects.add(effect);
     }
 
     public Integer getCurrentRoomId() {
@@ -216,8 +217,8 @@ public class PlayerMetadata implements Serializable {
         this.currentRoomId = currentRoomId;
     }
 
-    protected void removeEffectID(String effectId) {
-        effects.remove(effectId);
+    protected void removeEffect(Effect effect) {
+        effects.remove(effect);
     }
 
     public String getPlayerName() {
@@ -297,14 +298,14 @@ public class PlayerMetadata implements Serializable {
     }
 
     public void resetCoolDowns() {
-        Maps.newConcurrentMap();
+        this.coolDowns = Maps.newConcurrentMap();
     }
 
     public String[] getPlayerEquipment() {
         return playerEquipment;
     }
 
-    public List<String> getEffects() {
+    public List<Effect> getEffects() {
         if (effects==null) {
             effects = Lists.newArrayList();
         }
diff --git a/src/main/java/com/comandante/creeper/spawner/ItemSpawner.java b/src/main/java/com/comandante/creeper/spawner/ItemSpawner.java
index 17e5faabe44b5532f3e0b5b868c2279c445188ea..de09eddf7603f5f1f23c0a7cbc5edd09d7d8b3a8 100644
--- a/src/main/java/com/comandante/creeper/spawner/ItemSpawner.java
+++ b/src/main/java/com/comandante/creeper/spawner/ItemSpawner.java
@@ -1,11 +1,12 @@
 package com.comandante.creeper.spawner;
 
 import com.codahale.metrics.MetricRegistry;
-import com.comandante.creeper.items.Item;
-import com.comandante.creeper.items.ItemType;
 import com.comandante.creeper.Main;
 import com.comandante.creeper.core_game.GameManager;
 import com.comandante.creeper.entity.CreeperEntity;
+import com.comandante.creeper.items.Item;
+import com.comandante.creeper.items.ItemBuilder;
+import com.comandante.creeper.items.ItemMetadata;
 import com.comandante.creeper.world.model.Area;
 import com.comandante.creeper.world.model.Room;
 import com.google.common.base.Predicate;
@@ -19,7 +20,7 @@ import java.util.Set;
 
 public class ItemSpawner extends CreeperEntity {
 
-    private final ItemType spawnItemType;
+    private final ItemMetadata itemMetadata;
     private final SpawnRule spawnRule;
     private final GameManager gameManager;
     private Integer roomId;
@@ -28,8 +29,8 @@ public class ItemSpawner extends CreeperEntity {
     private final Area spawnArea;
 
 
-    public ItemSpawner(ItemType spawnItemType, SpawnRule spawnRule, GameManager gameManager) {
-        this.spawnItemType = spawnItemType;
+    public ItemSpawner(ItemMetadata itemMetadata, SpawnRule spawnRule, GameManager gameManager) {
+        this.itemMetadata = itemMetadata;
         this.spawnRule = spawnRule;
         this.gameManager = gameManager;
         this.noTicks = spawnRule.getSpawnIntervalTicks();
@@ -48,8 +49,8 @@ public class ItemSpawner extends CreeperEntity {
             int numberOfAttempts = spawnRule.getMaxInstances() - counterNumberInArea();
             for (int i = 0; i < numberOfAttempts; i++) {
                 if (random.nextInt(100) < randomPercentage || randomPercentage == 100) {
-                    if (spawnItemType.getValidTimeOfDays().size() > 0) {
-                        if (spawnItemType.getValidTimeOfDays().contains(gameManager.getTimeTracker().getTimeOfDay())) {
+                    if (itemMetadata.getValidTimeOfDays() != null && itemMetadata.getValidTimeOfDays().size() > 0) {
+                        if (itemMetadata.getValidTimeOfDays().contains(gameManager.getTimeTracker().getTimeOfDay())) {
                             createAndAddItem();
                         }
                     } else {
@@ -64,7 +65,7 @@ public class ItemSpawner extends CreeperEntity {
     private void createAndAddItem() {
         ArrayList<Room> rooms = Lists.newArrayList(Iterators.filter(gameManager.getRoomManager().getRoomsByArea(spawnArea).iterator(), getRoomsWithRoom()));
         Room room = rooms.get(random.nextInt(rooms.size()));
-        Item item = spawnItemType.create();
+        Item item = new ItemBuilder().from(itemMetadata).create();
         gameManager.getEntityManager().saveItem(item);
         gameManager.placeItemInRoom(room.getRoomId(), item.getItemId());
         Main.metrics.counter(MetricRegistry.name(ItemSpawner.class, item.getItemName() + "-spawn")).inc();
@@ -81,7 +82,7 @@ public class ItemSpawner extends CreeperEntity {
                         continue;
                     }
                     Item currentItem = currentItemOptional.get();
-                    if (currentItem.getItemTypeId().equals(spawnItemType.getItemTypeCode())) {
+                    if (currentItem.getInternalItemName().equals(itemMetadata.getInternalItemName())) {
                         numberCurrentlyInArea++;
                     }
                 }
@@ -102,7 +103,7 @@ public class ItemSpawner extends CreeperEntity {
                         continue;
                     }
                     Item item = itemOptional.get();
-                    if (item.getItemTypeId().equals(spawnItemType.getItemTypeCode())) {
+                    if (item.getInternalItemName().equals(itemMetadata.getInternalItemName())) {
                         count++;
                     }
                 }
diff --git a/src/main/java/com/comandante/creeper/storage/CreeperStorage.java b/src/main/java/com/comandante/creeper/storage/CreeperStorage.java
index 14933c60408d8a5c62a57427a5e69d16df691aa2..a857701f0f65f44bec94a014da8528d9f661da94 100644
--- a/src/main/java/com/comandante/creeper/storage/CreeperStorage.java
+++ b/src/main/java/com/comandante/creeper/storage/CreeperStorage.java
@@ -1,7 +1,6 @@
 package com.comandante.creeper.storage;
 
 
-import com.comandante.creeper.items.Effect;
 import com.comandante.creeper.items.Item;
 import com.comandante.creeper.player.PlayerMetadata;
 
@@ -23,10 +22,4 @@ public interface CreeperStorage {
     Optional<Item> getItemEntity(String itemId);
 
     void removeItem(String itemId);
-
-    Optional<Effect> getEffectEntity(String effectId);
-
-    void saveEffect(Effect effect);
-
-    void removeEffect(String effectId);
 }
diff --git a/src/main/java/com/comandante/creeper/storage/FilebasedJsonStorage.java b/src/main/java/com/comandante/creeper/storage/FilebasedJsonStorage.java
new file mode 100644
index 0000000000000000000000000000000000000000..887f258faae5c6cf9f82286ad6d9e2b9007c1e7a
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/storage/FilebasedJsonStorage.java
@@ -0,0 +1,69 @@
+package com.comandante.creeper.storage;
+
+import com.comandante.creeper.Main;
+import com.google.gson.Gson;
+import org.apache.commons.io.FileUtils;
+import org.apache.log4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+public class FilebasedJsonStorage {
+
+
+    private final Gson gson;
+    private static final Logger log = Logger.getLogger(FilebasedJsonStorage.class);
+
+    public FilebasedJsonStorage(Gson gson) {
+        this.gson = gson;
+    }
+
+    public <E> List<E> readAllMetadatas(String storageDirectory, boolean recursive, E a) {
+        List<String> jsonStrings = getAllJsonStrings(storageDirectory, recursive);
+        List<Object> list = jsonStrings.stream()
+                .map(s -> {
+                    try {
+                        return gson.fromJson(s, a.getClass());
+                    } catch (Exception e) {
+                        log.error("Unable to read NpcMetaData from Json!", e);
+                    }
+                    return null;
+                })
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        return (List<E>) list;
+    }
+
+    public void saveMetadata(String name, String storageDirectory, Object metadata) throws IOException {
+        new File(storageDirectory).mkdirs();
+        File file = new File(storageDirectory + name.replaceAll("\\s", "_") + ".json");
+        org.apache.commons.io.FileUtils.writeStringToFile(file, gson.toJson(metadata));
+    }
+
+    private List<String> getAllJsonStrings(String storageDirectory, boolean recursive) {
+        new File(storageDirectory).mkdirs();
+        Iterator<File> iterator = FileUtils.iterateFiles(new File(storageDirectory), new String[]{"json"}, recursive);
+        return toListOfJsonStrings(iterator);
+    }
+
+    private List<String> toListOfJsonStrings(final Iterator<File> iterator) {
+        return StreamSupport
+                .stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
+                .map(f -> {
+                    try {
+                        Main.startUpMessage("Reading: " + f.getAbsolutePath());
+                        return new String(Files.readAllBytes(f.toPath()));
+                    } catch (IOException e) {
+                        log.error("Unable to read: " + f.getAbsolutePath(), e);
+                    }
+                    return null;
+                })
+                .filter(Objects::nonNull)
+                .collect(Collectors.toCollection(ArrayList::new));
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/storage/ItemStorage.java b/src/main/java/com/comandante/creeper/storage/ItemStorage.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ad24419f4568d74dc7023180d446c7de86c8061
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/storage/ItemStorage.java
@@ -0,0 +1,37 @@
+package com.comandante.creeper.storage;
+
+import com.comandante.creeper.items.ItemMetadata;
+import org.apache.log4j.Logger;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Optional;
+
+public class ItemStorage {
+
+    public final static String LOCAL_ITEM_DIRECTORY = "world/items/";
+
+    private static final Logger log = Logger.getLogger(NpcStorage.class);
+    private final FilebasedJsonStorage filebasedJsonStorage;
+
+    private final List<ItemMetadata> itemMetadatas;
+
+    public ItemStorage(FilebasedJsonStorage filebasedJsonStorage) {
+        this.filebasedJsonStorage = filebasedJsonStorage;
+        this.itemMetadatas = filebasedJsonStorage.readAllMetadatas(LOCAL_ITEM_DIRECTORY, true, new ItemMetadata());
+    }
+
+    public List<ItemMetadata> getAllItemMetadata() {
+        return itemMetadatas;
+    }
+
+    public void saveItemMetadata(ItemMetadata itemMetadata) throws IOException {
+        filebasedJsonStorage.saveMetadata(itemMetadata.getInternalItemName(), LOCAL_ITEM_DIRECTORY, itemMetadata);
+    }
+
+    public Optional<ItemMetadata> get(String internalItemName) {
+        return itemMetadatas.stream()
+                .filter(itemMetadata -> itemMetadata.getInternalItemName().equals(internalItemName))
+                .findFirst();
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/storage/MapDBCreeperStorage.java b/src/main/java/com/comandante/creeper/storage/MapDBCreeperStorage.java
index bbd5e96650bef7bb898db5bd18cdf17e87754a48..ae40129b01d0aec403089c9a72867d849073a1ee 100644
--- a/src/main/java/com/comandante/creeper/storage/MapDBCreeperStorage.java
+++ b/src/main/java/com/comandante/creeper/storage/MapDBCreeperStorage.java
@@ -81,21 +81,6 @@ public class MapDBCreeperStorage extends AbstractIdleService implements CreeperS
         this.items.remove(itemId);
     }
 
-    @Override
-    public Optional<Effect> getEffectEntity(String effectId) {
-        return Optional.ofNullable(this.effects.get(effectId));
-    }
-
-    @Override
-    public void saveEffect(Effect effect) {
-        this.effects.put(effect.getEntityId(), effect);
-    }
-
-    @Override
-    public void removeEffect(String effectId) {
-        this.effects.remove(effectId);
-    }
-
     @Override
     protected void startUp() throws Exception {
         mapDbAutoCommitService.startAsync();
diff --git a/src/main/java/com/comandante/creeper/storage/MerchantStorage.java b/src/main/java/com/comandante/creeper/storage/MerchantStorage.java
new file mode 100644
index 0000000000000000000000000000000000000000..00e4db471522bb8cf4753d0b6bfbfe2b5a2dc919
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/storage/MerchantStorage.java
@@ -0,0 +1,68 @@
+package com.comandante.creeper.storage;
+
+import com.comandante.creeper.core_game.GameManager;
+import com.comandante.creeper.merchant.Merchant;
+import com.comandante.creeper.merchant.MerchantMetadata;
+import org.apache.log4j.Logger;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class MerchantStorage {
+
+    public final static String LOCAL_MERCHANT_DIRECTORY = "world/merchants/";
+
+    private static final Logger log = Logger.getLogger(MerchantStorage.class);
+    private final FilebasedJsonStorage filebasedJsonStorage;
+    private final GameManager gameManager;
+    private final List<MerchantMetadata> merchantMetadatas;
+
+    public MerchantStorage(GameManager gameManager, FilebasedJsonStorage filebasedJsonStorage) {
+        this.gameManager = gameManager;
+        this.filebasedJsonStorage = filebasedJsonStorage;
+        this.merchantMetadatas = filebasedJsonStorage.readAllMetadatas(LOCAL_MERCHANT_DIRECTORY, true, new MerchantMetadata());
+    }
+
+    public List<Merchant> getAllMerchants() {
+        return merchantMetadatas.stream()
+                .map(this::create)
+                .collect(Collectors.toList());
+    }
+
+    public Merchant create(MerchantMetadata merchantMetadata) {
+
+        if (merchantMetadata.getMerchantType() != null) {
+            return new Merchant(gameManager,
+                    merchantMetadata.getInternalName(),
+                    merchantMetadata.getName(),
+                    merchantMetadata.getColorName(),
+                    merchantMetadata.getValidTriggers(),
+                    merchantMetadata.getMerchantItemForSales(),
+                    merchantMetadata.getWelcomeMessage(),
+                    merchantMetadata.getRoomId(),
+                    merchantMetadata.getMerchantType());
+        }
+
+        return new Merchant(gameManager,
+                merchantMetadata.getInternalName(),
+                merchantMetadata.getName(),
+                merchantMetadata.getColorName(),
+                merchantMetadata.getValidTriggers(),
+                merchantMetadata.getMerchantItemForSales(),
+                merchantMetadata.getWelcomeMessage(),
+                merchantMetadata.getRoomId());
+    }
+
+    public void saveMerchantMetadata(MerchantMetadata merchantMetadata) throws IOException {
+        filebasedJsonStorage.saveMetadata(merchantMetadata.getInternalName(), LOCAL_MERCHANT_DIRECTORY, merchantMetadata);
+    }
+
+    public Optional<MerchantMetadata> get(String internalName) {
+        return merchantMetadatas.stream()
+                .filter(merchantMetadata -> merchantMetadata.getInternalName().equals(internalName))
+                .findFirst();
+    }
+
+}
diff --git a/src/main/java/com/comandante/creeper/storage/NpcStorage.java b/src/main/java/com/comandante/creeper/storage/NpcStorage.java
index 4a980bc570add19a50bc04dbc07208046a420090..75c41a954bf9c45375b2affa5c0de0ab09822e66 100644
--- a/src/main/java/com/comandante/creeper/storage/NpcStorage.java
+++ b/src/main/java/com/comandante/creeper/storage/NpcStorage.java
@@ -1,34 +1,28 @@
 package com.comandante.creeper.storage;
 
 
-import com.comandante.creeper.Main;
 import com.comandante.creeper.core_game.GameManager;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.npc.NpcBuilder;
-import com.google.gson.Gson;
-import org.apache.commons.io.FileUtils;
 import org.apache.log4j.Logger;
 
-import java.io.File;
 import java.io.IOException;
-import java.nio.file.Files;
-import java.util.*;
+import java.util.List;
 import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
 
 public class NpcStorage {
 
     private final GameManager gameManager;
-    private final Gson gson;
     private final static String LOCAL_NPC_DIRECTORY = "world/npcs/";
     private static final Logger log = Logger.getLogger(NpcStorage.class);
+    private final FilebasedJsonStorage filebasedJsonStorage;
 
-    public NpcStorage(GameManager gameManager, Gson gson) {
-        this.gson = gson;
+    public NpcStorage(GameManager gameManager, FilebasedJsonStorage filebasedJsonStorage) {
         this.gameManager = gameManager;
+        this.filebasedJsonStorage = filebasedJsonStorage;
     }
 
-    public List<Npc> getAllNpcs()  {
+    public List<Npc> getAllNpcs() {
         List<NpcMetadata> npcMetadata = readAlLNpcs();
         return npcMetadata.stream()
                 .map(metadata -> new NpcBuilder(metadata).setGameManager(gameManager).createNpc())
@@ -36,48 +30,10 @@ public class NpcStorage {
     }
 
     public void saveNpcMetadata(NpcMetadata npcMetadata) throws IOException {
-        File npcFile = new File(LOCAL_NPC_DIRECTORY + npcMetadata.getName().replaceAll("\\s", "_") + ".json");
-        org.apache.commons.io.FileUtils.writeStringToFile(npcFile, gson.toJson(npcMetadata));
+       filebasedJsonStorage.saveMetadata(npcMetadata.getName(), LOCAL_NPC_DIRECTORY, npcMetadata);
     }
 
-    protected List<NpcMetadata> readAlLNpcs() {
-        return readAlLNpcs(getAllJsonStrings());
+    private List<NpcMetadata> readAlLNpcs() {
+        return filebasedJsonStorage.readAllMetadatas(LOCAL_NPC_DIRECTORY, true, new NpcMetadata());
     }
-
-    protected List<NpcMetadata> readAlLNpcs(List<String> jsonStrings) {
-        List<NpcMetadata> npcMetadatas = jsonStrings.stream()
-                .map(s -> {
-                    try {
-                        return gson.fromJson(s, NpcMetadata.class);
-                    } catch (Exception e) {
-                        log.error("Unable to read NpcMetaData from Json!", e);
-                    }
-                    return null;
-                })
-                .filter(Objects::nonNull)
-                .collect(Collectors.toList());
-        return npcMetadatas;
-    }
-
-    protected List<String> getAllJsonStrings() {
-        Iterator<File> iterator = FileUtils.iterateFiles(new File(LOCAL_NPC_DIRECTORY), new String[]{"json"}, false);
-        return toListOfJsonStrings(iterator);
-    }
-
-    protected List<String> toListOfJsonStrings(final Iterator<File> iterator) {
-        return StreamSupport
-                .stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
-                .map(f -> {
-                    try {
-                        Main.startUpMessage("Reading npc: " + f.getAbsolutePath());
-                        return new String(Files.readAllBytes(f.toPath()));
-                    } catch (IOException e) {
-                        log.error("Unable to read: " + f.getAbsolutePath(), e);
-                    }
-                    return null;
-                })
-                .filter(Objects::nonNull)
-                .collect(Collectors.toCollection(ArrayList::new));
-    }
-
 }
diff --git a/src/main/java/com/comandante/creeper/world/RoomManager.java b/src/main/java/com/comandante/creeper/world/RoomManager.java
index bcfa0cbab8c585ffaf9c4c67f7b3d62ccef3c85a..ddb6b3464d8c22d47ad937c65f00d4ddc88ff27f 100644
--- a/src/main/java/com/comandante/creeper/world/RoomManager.java
+++ b/src/main/java/com/comandante/creeper/world/RoomManager.java
@@ -43,8 +43,10 @@ public class RoomManager {
         return rooms.entrySet().iterator();
     }
 
-    public void addMerchant(Integer roomId, Merchant merchant) {
-        getRoom(roomId).addMerchant(merchant);
+    public void addMerchant(Merchant merchant) {
+        for (Integer roomId: merchant.getRoomIds()) {
+            getRoom(roomId).addMerchant(merchant);
+        };
     }
 
     public Room getRoom(Integer roomId) {
diff --git a/src/main/java/com/comandante/creeper/world/model/Room.java b/src/main/java/com/comandante/creeper/world/model/Room.java
index aef277ff32e3355d2c508a577a8bad1c18f90399..f1686a578cb622179742bb0533a7d58e14e6e89e 100644
--- a/src/main/java/com/comandante/creeper/world/model/Room.java
+++ b/src/main/java/com/comandante/creeper/world/model/Room.java
@@ -5,7 +5,6 @@ import com.comandante.creeper.core_game.service.TimeTracker;
 import com.comandante.creeper.entity.CreeperEntity;
 import com.comandante.creeper.items.Forage;
 import com.comandante.creeper.items.Item;
-import com.comandante.creeper.items.ItemType;
 import com.comandante.creeper.merchant.Merchant;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.player.Player;
@@ -51,7 +50,7 @@ public abstract class Room extends CreeperEntity {
     private Optional<String> mapData = Optional.empty();
     private final Set<String> roomTags;
     private final Set<Merchant> merchants = Sets.newConcurrentHashSet();
-    private Map<ItemType, Forage> forages = Maps.newHashMap();
+    private Map<String, Forage> forages = Maps.newHashMap();
     private final Map<String, String> notables;
     private final GameManager gameManager;
 
@@ -254,12 +253,12 @@ public abstract class Room extends CreeperEntity {
         itemSpawners.add(itemSpawner);
     }
 
-    public Map<ItemType, Forage> getForages() {
+    public Map<String, Forage> getForages() {
         return forages;
     }
 
     public void addForage(Forage forage) {
-        this.forages.put(forage.getItemType(), forage);
+        this.forages.put(forage.getInternalItemName(), forage);
     }
 
     public Map<String, String> getNotables() {
@@ -290,9 +289,7 @@ public abstract class Room extends CreeperEntity {
             if (itemEntity.isHasBeenWithPlayer()) {
                 continue;
             }
-            Integer itemTypeId = itemEntity.getItemTypeId();
-            ItemType itemType = ItemType.itemTypeFromCode(itemTypeId);
-            Set<TimeTracker.TimeOfDay> itemValidTimeOfDays = itemType.getValidTimeOfDays();
+            Set<TimeTracker.TimeOfDay> itemValidTimeOfDays = itemEntity.getValidTimeOfDays();
             TimeTracker.TimeOfDay timeOfDay = gameManager.getTimeTracker().getTimeOfDay();
             if (itemValidTimeOfDays.size() > 0 && !itemValidTimeOfDays.contains(timeOfDay)) {
                 gameManager.getEntityManager().removeItem(itemId);
diff --git a/src/test/com/comandante/creeper/CreeperUtilsTest.java b/src/test/com/comandante/creeper/CreeperUtilsTest.java
index 820bc4f55e23946f98f0f4db0165db370a7d9506..8149a0379d0981705c2cd03a29743c459c214f09 100644
--- a/src/test/com/comandante/creeper/CreeperUtilsTest.java
+++ b/src/test/com/comandante/creeper/CreeperUtilsTest.java
@@ -6,7 +6,6 @@ import com.comandante.creeper.blackjack.Hand;
 import com.comandante.creeper.common.CreeperUtils;
 import com.comandante.creeper.core_game.GameManager;
 import com.comandante.creeper.entity.EntityManager;
-import com.comandante.creeper.items.ItemType;
 import com.comandante.creeper.player.*;
 import com.comandante.creeper.stats.DefaultStats;
 import com.comandante.creeper.stats.modifier.StatsModifierFactory;
@@ -54,8 +53,8 @@ public class CreeperUtilsTest {
         when(playerManager.getPlayerMetadata(Matchers.any())).thenReturn(java.util.Optional.ofNullable(playerMetadata));
         when(gameManager.getPlayerManager()).thenReturn(playerManager);
         EntityManager entityManager = mock(EntityManager.class);
-        when(entityManager.getItemEntity(Matchers.startsWith("feet"))).thenReturn(java.util.Optional.ofNullable(ItemType.BERSEKER_BOOTS.create()));
-        when(entityManager.getItemEntity(Matchers.startsWith("hand"))).thenReturn(java.util.Optional.ofNullable(ItemType.BERSERKER_BATON.create()));
+//        when(entityManager.getItemEntity(Matchers.startsWith("feet"))).thenReturn(java.util.Optional.ofNullable(ItemType.BERSEKER_BOOTS.create()));
+//        when(entityManager.getItemEntity(Matchers.startsWith("hand"))).thenReturn(java.util.Optional.ofNullable(ItemType.BERSERKER_BATON.create()));
         when(gameManager.getEntityManager()).thenReturn(entityManager);
         Player usertest = new Player("usertest", gameManager);
 
diff --git a/src/test/com/comandante/creeper/items/ItemMetadataTest.java b/src/test/com/comandante/creeper/items/ItemMetadataTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb52dd36a1e7f2d882f07ff2e019fcbf6f97fff0
--- /dev/null
+++ b/src/test/com/comandante/creeper/items/ItemMetadataTest.java
@@ -0,0 +1,504 @@
+/*
+package com.comandante.creeper.items;
+
+import com.comandante.creeper.merchant.Merchant;
+import com.comandante.creeper.merchant.MerchantItemForSale;
+import com.comandante.creeper.merchant.MerchantMetadata;
+import com.comandante.creeper.server.player_communication.Color;
+import com.comandante.creeper.spawner.SpawnRule;
+import com.comandante.creeper.spawner.SpawnRuleBuilder;
+import com.comandante.creeper.stats.Stats;
+import com.comandante.creeper.stats.StatsBuilder;
+import com.comandante.creeper.storage.FilebasedJsonStorage;
+import com.comandante.creeper.storage.ItemStorage;
+import com.comandante.creeper.storage.MerchantStorage;
+import com.comandante.creeper.world.model.Area;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static com.comandante.creeper.server.player_communication.Color.BOLD_ON;
+
+
+public class ItemMetadataTest {
+
+    private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
+
+    @Test
+    public void testSerialization() throws Exception {
+//
+//        private String itemName;
+//        private String itemDescription;
+//        private String restingName;
+//        private int numberOfUses;
+//        private int valueInGold;
+//        private int itemHalfLifeTicks;
+//        private Rarity rarity;
+//        private Equipment equipment;
+//        private Set<Effect> effects;
+//        private List<String> itemTriggers;
+//
+//
+//        ItemMetadata itemMetadata = new ItemMetadata();
+//        itemMetadata.setInternalItemName("little potion");
+//        itemMetadata.setItemName("a " + Color.RED + "little potion" + Color.RESET);
+//        itemMetadata.setItemDescription("a " + Color.RED + "little potion" + Color.RESET);
+//        itemMetadata.setRestingName("a " + Color.GREEN + "little potion" + Color.RESET);
+//        itemMetadata.setMaxUses(1);
+//        itemMetadata.setDisposable(true);
+//        itemMetadata.setValueInGold(30);
+//        itemMetadata.setItemHalfLifeTicks(60);
+//        itemMetadata.setRarity(Rarity.BASIC);
+//         itemMetadata.setValidTimeOfDays(Sets.newHashSet(TimeTracker.TimeOfDay.MORNING, TimeTracker.TimeOfDay.NIGHT));
+//
+//        SpawnRule spawnRule1 = new SpawnRuleBuilder().setArea(Area.NEWBIE_ZONE).setSpawnIntervalTicks(600).setMaxInstances(100).setMaxPerRoom(5).setRandomPercent(40).createSpawnRule();
+//        SpawnRule spawnRule2 = new SpawnRuleBuilder().setArea(Area.FANCYHOUSE_ZONE).setSpawnIntervalTicks(600).setMaxInstances(12).setMaxPerRoom(2).setRandomPercent(50).createSpawnRule();
+//        SpawnRule spawnRule3 = new SpawnRuleBuilder().setArea(Area.HOUSE_ZONE).setSpawnIntervalTicks(600).setMaxInstances(12).setMaxPerRoom(2).setRandomPercent(50).createSpawnRule();
+//        itemMetadata.setSpawnRules(Sets.newHashSet(spawnRule1, spawnRule2, spawnRule3));
+//
+//        Stats stats = new StatsBuilder().setInventorySize(100).createStats();
+//          final Equipment equipment = new Equipment(EquipmentSlotType.BAG, stats);
+//
+//           itemMetadata.setEquipment(equipment);
+//        itemMetadata.setItemTriggers(Lists.newArrayList("p", "little potion", "potion"));
+//
+//
+//        EffectBuilder effectBuilder = new EffectBuilder()
+//                .setDurationStats(new StatsBuilder().setCurrentHealth(25).createStats())
+//                .setEffectApplyMessages(Lists.newArrayList("You start to feel a healing effect."))
+//                .setEffectDescription("Little healing.")
+//                .setEffectName("Little Potion Heal")
+//                .setFrozenMovement(false)
+//                .setLifeSpanTicks(0);
+//
+//
+//        itemMetadata.setEffects(Sets.newHashSet(effectBuilder.createEffect()));
+//
+//
+//        ItemStorage itemStorage = new ItemStorage(gson);
+//        itemStorage.saveItemMetadata(itemMetadata);
+//
+//
+//        String s = gson.toJson(itemMetadata);
+//        System.out.println(s);
+
+    }
+
+    @Test
+    public void generator() throws Exception {
+
+        FilebasedJsonStorage filebasedJsonStorage = new FilebasedJsonStorage(new GsonBuilder().setPrettyPrinting().create());
+        ItemStorage itemStorage = new ItemStorage(filebasedJsonStorage);
+
+         //BERSERKER BOOTS
+        {
+            ItemMetadata itemMetadata = metadataFrom(ItemType.BERSEKER_BOOTS);
+            Stats stats = new StatsBuilder().setArmorRating(3).createStats();
+            final Equipment equipment = new Equipment(EquipmentSlotType.FEET, stats);
+            itemMetadata.setEquipment(equipment);
+            itemMetadata.setInternalItemName("beserker boots");
+            itemStorage.saveItemMetadata(itemMetadata);
+        }
+
+        // BERSERKER HELM
+        {
+            ItemMetadata itemMetadataHelm = metadataFrom(ItemType.BERSEKER_HELM);
+            Stats statsHelm = new StatsBuilder().setArmorRating(3).createStats();
+            final Equipment equipmentHeml = new Equipment(EquipmentSlotType.HEAD, statsHelm);
+            itemMetadataHelm.setEquipment(equipmentHeml);
+            itemMetadataHelm.setInternalItemName("beserker helm");
+            itemStorage.saveItemMetadata(itemMetadataHelm);
+        }
+
+
+         //BERSERKER SHORTS
+        {
+            ItemMetadata itemMetadataShorts = metadataFrom(ItemType.BERSEKER_SHORTS);
+            Stats statsShorts = new StatsBuilder().setArmorRating(4).createStats();
+            final Equipment equipmentShorts = new Equipment(EquipmentSlotType.LEGS, statsShorts);
+            itemMetadataShorts.setEquipment(equipmentShorts);
+            itemMetadataShorts.setInternalItemName("beserker shorts");
+            itemStorage.saveItemMetadata(itemMetadataShorts);
+        }
+
+
+       //  BERSERKER BATON
+        {
+            ItemMetadata itemMetadataBaton = metadataFrom(ItemType.BERSERKER_BATON);
+            Stats statsBaton = new StatsBuilder().setWeaponRatingMin(4).setWeaponRatingMax(6).createStats();
+            final Equipment equipmentBaton = new Equipment(EquipmentSlotType.HAND, statsBaton);
+            itemMetadataBaton.setEquipment(equipmentBaton);
+            itemMetadataBaton.setInternalItemName("beserker baton");
+            itemStorage.saveItemMetadata(itemMetadataBaton);
+        }
+
+        // BERSERKER BATON
+        {
+            ItemMetadata itemMetadataBracers = metadataFrom(ItemType.BERSERKER_BRACERS);
+            Stats statsBracers = new StatsBuilder().setArmorRating(4).createStats();
+            final Equipment equipmentBracers = new Equipment(EquipmentSlotType.WRISTS, statsBracers);
+            itemMetadataBracers.setEquipment(equipmentBracers);
+            itemMetadataBracers.setInternalItemName("beserker bracers");
+            itemStorage.saveItemMetadata(itemMetadataBracers);
+        }
+
+
+        // BERSERKER BATON
+        {
+            ItemMetadata itemMetadataChest = metadataFrom(ItemType.BERSERKER_CHEST);
+            Stats statsChest = new StatsBuilder().setArmorRating(6).createStats();
+            final Equipment equipmentChest = new Equipment(EquipmentSlotType.CHEST, statsChest);
+            itemMetadataChest.setEquipment(equipmentChest);
+            itemMetadataChest.setInternalItemName("beserker chest");
+            itemStorage.saveItemMetadata(itemMetadataChest);
+        }
+
+        // BIGGERS SKIN SATCHEL
+        {
+            ItemMetadata itemMetadataBiggersSkinSatchel = metadataFrom(ItemType.BIGGERS_SKIN_SATCHEL);
+            Stats statsBiggersSkinSatchel = new StatsBuilder().setInventorySize(100).createStats();
+            final Equipment equipmentBiggersSkinSatchel = new Equipment(EquipmentSlotType.BAG, statsBiggersSkinSatchel);
+            itemMetadataBiggersSkinSatchel.setEquipment(equipmentBiggersSkinSatchel);
+            itemMetadataBiggersSkinSatchel.setInternalItemName("biggers skin satchel");
+            itemStorage.saveItemMetadata(itemMetadataBiggersSkinSatchel);
+        }
+
+         //Key
+        {
+            ItemMetadata itemMetadataKey = metadataFrom(ItemType.KEY);
+            itemMetadataKey.setInternalItemName("basic key");
+            SpawnRule spawnRule = new SpawnRuleBuilder().setArea(Area.LOBBY).setSpawnIntervalTicks(600).setMaxInstances(1).setMaxPerRoom(1).setRandomPercent(5).createSpawnRule();
+            itemMetadataKey.setSpawnRules(Sets.newHashSet(spawnRule));
+            itemStorage.saveItemMetadata(itemMetadataKey);
+        }
+
+
+        // Marijuana
+        {
+            ItemMetadata itemMetadataMarijuana = metadataFrom(ItemType.MARIJUANA);
+            itemMetadataMarijuana.setInternalItemName("marijuana");
+            ForageBuilder marijuanaForageBuilder = new ForageBuilder();
+            marijuanaForageBuilder.setMinAmt(1);
+            marijuanaForageBuilder.setMaxAmt(3);
+            marijuanaForageBuilder.setPctOfSuccess(40);
+            marijuanaForageBuilder.setForageExperience(4);
+            marijuanaForageBuilder.setCoolDownTicks(600);
+            marijuanaForageBuilder.setAreas(Sets.newHashSet(Area.WESTERN9_ZONE, Area.NORTH3_ZONE, Area.BLOODRIDGE2_ZONE, Area.BLOODRIDGE1_ZONE));
+            itemMetadataMarijuana.setForages(Sets.newHashSet(marijuanaForageBuilder.createForage()));
+            itemStorage.saveItemMetadata(itemMetadataMarijuana);
+        }
+
+        // Drank
+        {
+            ItemMetadata itemMetadataDrank = metadataFrom(ItemType.PURPLE_DRANK);
+            itemMetadataDrank.setInternalItemName("purple drank");
+            Stats statsDrank = new StatsBuilder().setCurrentHealth(50).createStats();
+            itemMetadataDrank.setItemApplyStats(statsDrank);
+            itemStorage.saveItemMetadata(itemMetadataDrank);
+        }
+
+        // Smell Health Potion
+        {
+            Set<SpawnRule> spawnRulesHealthPotion = Sets.newHashSet(
+                    new SpawnRuleBuilder().setArea(Area.NEWBIE_ZONE).setSpawnIntervalTicks(600).setMaxInstances(100).setMaxPerRoom(5).setRandomPercent(40).createSpawnRule(),
+                    new SpawnRuleBuilder().setArea(Area.FANCYHOUSE_ZONE).setSpawnIntervalTicks(600).setMaxInstances(12).setMaxPerRoom(2).setRandomPercent(50).createSpawnRule(),
+                    new SpawnRuleBuilder().setArea(Area.HOUSE_ZONE).setSpawnIntervalTicks(600).setMaxInstances(12).setMaxPerRoom(2).setRandomPercent(50).createSpawnRule()
+            );
+            ItemMetadata itemMetadataHealthPotion = metadataFrom(ItemType.SMALL_HEALTH_POTION);
+            itemMetadataHealthPotion.setInternalItemName("small health potion");
+            Stats statsHealthPotion = new StatsBuilder().setCurrentHealth(20).createStats();
+            itemMetadataHealthPotion.setSpawnRules(spawnRulesHealthPotion);
+            itemMetadataHealthPotion.setItemApplyStats(statsHealthPotion);
+            itemStorage.saveItemMetadata(itemMetadataHealthPotion);
+        }
+
+        {
+
+            //  BIGGERS SKIN SATCHEL
+            ItemMetadata itemMetadataSpellbook = metadataFrom(ItemType.LIGHTNING_SPELLBOOKNG);
+            itemMetadataSpellbook.setInternalItemName("lightning spellbook");
+            itemStorage.saveItemMetadata(itemMetadataSpellbook);
+        }
+
+        {
+            // Stick OF Justice
+            ItemMetadata itemMetadataStickOfJustice = metadataFrom(ItemType.STICK_OF_JUSTICE);
+            itemMetadataStickOfJustice.setInternalItemName("stick of justice");
+            itemStorage.saveItemMetadata(itemMetadataStickOfJustice);
+        }
+
+
+        {
+            // RED CLAW BEANIE
+            ItemMetadata itemMetadataBeanie = metadataFrom(ItemType.RED_CLAW_BEANIE);
+            Stats statsBeanie = new StatsBuilder().setArmorRating(8).setStrength(4).setMaxHealth(50).createStats();
+            final Equipment equipmentBeanie = new Equipment(EquipmentSlotType.HEAD, statsBeanie);
+            itemMetadataBeanie.setEquipment(equipmentBeanie);
+            itemMetadataBeanie.setInternalItemName("red claw beanie");
+            itemStorage.saveItemMetadata(itemMetadataBeanie);
+        }
+
+        {
+            // RED CLAW Hoodie
+            ItemMetadata itemMetadataHoodie = metadataFrom(ItemType.RED_CLAW_HOODIE);
+            Stats statsHoodie = new StatsBuilder().setArmorRating(15).setStrength(7).createStats();
+            final Equipment equipmentHoodie = new Equipment(EquipmentSlotType.CHEST, statsHoodie);
+            itemMetadataHoodie.setEquipment(equipmentHoodie);
+            itemMetadataHoodie.setInternalItemName("rad claw hoodie");
+            itemStorage.saveItemMetadata(itemMetadataHoodie);
+        }
+
+        {
+            //   RED CLAW PANTS
+            ItemMetadata itemMetadataPants = metadataFrom(ItemType.RED_CLAW_PANTS);
+            Stats statsPants = new StatsBuilder().setArmorRating(15).setStrength(7).createStats();
+            final Equipment equipmentPants = new Equipment(EquipmentSlotType.LEGS, statsPants);
+            itemMetadataPants.setEquipment(equipmentPants);
+            itemMetadataPants.setInternalItemName("rad claw pants");
+            itemStorage.saveItemMetadata(itemMetadataPants);
+            //Lether Satchel
+        }
+
+        {
+            ItemMetadata itemMetadataPants = metadataFrom(ItemType.LEATHER_SATCHEL);
+            Stats stats = new StatsBuilder().setInventorySize(15).createStats();
+            final Equipment equipment = new Equipment(EquipmentSlotType.BAG, stats);
+            itemMetadataPants.setEquipment(equipment);
+            itemMetadataPants.setInternalItemName("leather satchel");
+            itemStorage.saveItemMetadata(itemMetadataPants);
+        }
+    }
+
+
+    private ItemMetadata metadataFrom(ItemType itemType) {
+        ItemMetadata itemMetadata = new ItemMetadata();
+        itemMetadata.setInternalItemName(null);
+        itemMetadata.setItemName(itemType.getItemName());
+        itemMetadata.setRestingName(itemType.getRestingName());
+        itemMetadata.setItemDescription(itemType.getItemDescription());
+        itemMetadata.setItemHalfLifeTicks(itemType.getItemHalfLifeTicks());
+        itemMetadata.setItemTriggers(itemType.getItemTriggers());
+        itemMetadata.setMaxUses(itemType.getMaxUses());
+        itemMetadata.setRarity(itemType.getRarity());
+        itemMetadata.setSpawnRules(null);
+        itemMetadata.setValidTimeOfDays(itemType.getValidTimeOfDays());
+        itemMetadata.setValueInGold(itemType.getValueInGold());
+        itemMetadata.setItemApplyStats(null);
+        itemMetadata.setEquipment(null);
+        itemMetadata.setEffects(null);
+        itemMetadata.setDisposable(itemType.isDisposable());
+        return itemMetadata;
+    }
+
+
+    @Test
+    public void generateMerchants() throws Exception {
+
+        // LLOYD BARTENDER
+        {
+            final String welcomeMessage = " _        _        _______           ______   _  _______ \r\n" +
+                    "( \\      ( \\      (  ___  )|\\     /|(  __  \\ ( )(  ____ \\\r\n" +
+                    "| (      | (      | (   ) |( \\   / )| (  \\  )|/ | (    \\/\r\n" +
+                    "| |      | |      | |   | | \\ (_) / | |   ) |   | (_____ \r\n" +
+                    "| |      | |      | |   | |  \\   /  | |   | |   (_____  )\r\n" +
+                    "| |      | |      | |   | |   ) (   | |   ) |         ) |\r\n" +
+                    "| (____/\\| (____/\\| (___) |   | |   | (__/  )   /\\____) |\r\n" +
+                    "(_______/(_______/(_______)   \\_/   (______/    \\_______)\r\n" +
+                    "                                                         ";
+
+
+            String name = "lloyd the bartender";
+            String colorName = BOLD_ON + Color.CYAN + name + Color.RESET;
+            Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"lloyd", "bartender", "barkeep", "Lloyd", "LLOYD", name}));
+
+            List<MerchantItemForSale> itemsForSale = Lists.newArrayList();
+            itemsForSale.add(new MerchantItemForSale("small health potion", 8));
+            itemsForSale.add(new MerchantItemForSale("purple drank", 80));
+            itemsForSale.add(new MerchantItemForSale("biggers skin satchel", 25000));
+            MerchantMetadata merchantMetadata = new MerchantMetadata();
+            merchantMetadata.setName(name);
+            merchantMetadata.setInternalName(name);
+            merchantMetadata.setColorName(colorName);
+            merchantMetadata.setMerchantItemForSales(itemsForSale);
+            merchantMetadata.setRoomIds(Sets.newHashSet(64));
+            merchantMetadata.setValidTriggers(validTriggers);
+            merchantMetadata.setWelcomeMessage(welcomeMessage);
+
+            FilebasedJsonStorage filebasedJsonStorage = new FilebasedJsonStorage(new GsonBuilder().setPrettyPrinting().create());
+            MerchantStorage merchantStorage = new MerchantStorage(null, filebasedJsonStorage);
+            merchantStorage.saveMerchantMetadata(merchantMetadata);
+
+        }
+
+        // BIGGER BLACKSMITH
+        {
+            final String welcomeMessage = "  ____  _                                              \n" +
+                    "\" +\n" +
+                    "                    \" | __ )(_) __ _  __ _  ___ _ __ ___                    \\r\\n\" +\n" +
+                    "                    \" |  _ \\\\| |/ _` |/ _` |/ _ \\\\ '__/ __|                   \\r\\n\" +\n" +
+                    "                    \" | |_) | | (_| | (_| |  __/ |  \\\\__ \\\\                   \\r\\n\" +\n" +
+                    "                    \" |____/|_|\\\\__, |\\\\__, |\\\\___|_|  |___/                   \\r\\n\" +\n" +
+                    "                    \"     ____ |___/ |___/   _                  _ _   _     \\r\\n\" +\n" +
+                    "                    \"    | __ )| | __ _  ___| | _____ _ __ ___ (_) |_| |__  \\r\\n\" +\n" +
+                    "                    \"    |  _ \\\\| |/ _` |/ __| |/ / __| '_ ` _ \\\\| | __| '_ \\\\ \\r\\n\" +\n" +
+                    "                    \"    | |_) | | (_| | (__|   <\\\\__ \\\\ | | | | | | |_| | | |\\r\\n\" +\n" +
+                    "                    \"    |____/|_|\\__,_|\\___|_|\\_\\___/_| |_| |_|_|\\__|_| |_|\n";
+
+
+            String name = "biggers the blacksmith";
+            String colorName = BOLD_ON + Color.CYAN + name + Color.RESET;
+            Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"blacksmith", "biggers the blacksmith", "biggers", name}));
+
+            List<MerchantItemForSale> blacksmithItems = Lists.newArrayList();
+            blacksmithItems.add(new MerchantItemForSale("berserker baton", 10000));
+            blacksmithItems.add(new MerchantItemForSale("berserker boots", 3500));
+            blacksmithItems.add(new MerchantItemForSale("berserker bracers", 3500));
+            blacksmithItems.add(new MerchantItemForSale("berserker helm", 3500));
+            blacksmithItems.add(new MerchantItemForSale("berserker chest", 7000));
+            blacksmithItems.add(new MerchantItemForSale("berserker shorts", 8500));
+            blacksmithItems.add(new MerchantItemForSale("leather satchel", 600));
+            MerchantMetadata merchantMetadata = new MerchantMetadata();
+            merchantMetadata.setName(name);
+            merchantMetadata.setInternalName(name);
+            merchantMetadata.setColorName(colorName);
+            merchantMetadata.setMerchantItemForSales(blacksmithItems);
+            merchantMetadata.setRoomIds(Sets.newHashSet(66, 253));
+            merchantMetadata.setValidTriggers(validTriggers);
+            merchantMetadata.setWelcomeMessage(welcomeMessage);
+            FilebasedJsonStorage filebasedJsonStorage = new FilebasedJsonStorage(new GsonBuilder().setPrettyPrinting().create());
+            MerchantStorage merchantStorage = new MerchantStorage(null, filebasedJsonStorage);
+            merchantStorage.saveMerchantMetadata(merchantMetadata);
+        }
+
+        {
+            String name = "nigel the bartender";
+            String colorName = BOLD_ON + Color.CYAN + name + Color.RESET;
+            Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"nigel", "bartender", "barkeep", "Nigel", "NIGEL", name}));
+
+            List<MerchantItemForSale> blacksmithItems = Lists.newArrayList();
+            blacksmithItems.add(new MerchantItemForSale("small health potion", 6));
+            MerchantMetadata merchantMetadata = new MerchantMetadata();
+            merchantMetadata.setName(name);
+            merchantMetadata.setInternalName(name);
+            merchantMetadata.setColorName(colorName);
+            merchantMetadata.setMerchantItemForSales(blacksmithItems);
+            merchantMetadata.setRoomIds(Sets.newHashSet(377));
+            merchantMetadata.setValidTriggers(validTriggers);
+            merchantMetadata.setWelcomeMessage("\r\n N I G E L 'S   B A R \r\n");
+            FilebasedJsonStorage filebasedJsonStorage = new FilebasedJsonStorage(new GsonBuilder().setPrettyPrinting().create());
+            MerchantStorage merchantStorage = new MerchantStorage(null, filebasedJsonStorage);
+            merchantStorage.saveMerchantMetadata(merchantMetadata);
+
+        }
+
+        {
+        String name = "willy the wizard";
+        String colorName = BOLD_ON + Color.CYAN + name + Color.RESET;
+        Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                {"wizard", "willy the wizard", "willy", name}));
+
+        List<MerchantItemForSale> items = Lists.newArrayList();
+        items.add(new MerchantItemForSale("lightning spellbook", 50000));
+        MerchantMetadata merchantMetadata = new MerchantMetadata();
+        merchantMetadata.setName(name);
+        merchantMetadata.setInternalName(name);
+        merchantMetadata.setColorName(colorName);
+        merchantMetadata.setMerchantItemForSales(items);
+        merchantMetadata.setRoomIds(Sets.newHashSet(98));
+        merchantMetadata.setValidTriggers(validTriggers);
+            String welcomeMessage = "  ____                                        \n" +
+                    " 6MMMMb\\                                      \n" +
+                    "6M'    `   /                                  \n" +
+                    "MM        /M       _____     _____   __ ____  \n" +
+                    "YM.      /MMMMM   6MMMMMb   6MMMMMb  `M6MMMMb \n" +
+                    " YMMMMb   MM     6M'   `Mb 6M'   `Mb  MM'  `Mb\n" +
+                    "     `Mb  MM     MM     MM MM     MM  MM    MM\n" +
+                    "      MM  MM     MM     MM MM     MM  MM    MM\n" +
+                    "      MM  MM     MM     MM MM     MM  MM    MM\n" +
+                    "L    ,M9  YM.  , YM.   ,M9 YM.   ,M9  MM.  ,M9\n" +
+                    "MYMMMM9    YMMM9  YMMMMM9   YMMMMM9   MMYMMM9 \n" +
+                    "                                      MM      \n" +
+                    "                                      MM      \n" +
+                    "                                     _MM_     \n" +
+                    "\n";
+        merchantMetadata.setWelcomeMessage(welcomeMessage);
+        FilebasedJsonStorage filebasedJsonStorage = new FilebasedJsonStorage(new GsonBuilder().setPrettyPrinting().create());
+        MerchantStorage merchantStorage = new MerchantStorage(null, filebasedJsonStorage);
+        merchantStorage.saveMerchantMetadata(merchantMetadata);
+
+        }
+
+
+
+        {
+            String welcomeMessage = "Welcome to the First National Bank of Creeper.";
+            final String name = "jim the banker";
+            final String colorName = BOLD_ON + Color.CYAN + name + Color.RESET;
+            Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"bank", "banker", "jim the banker", "jim", "j", name}));
+            MerchantMetadata merchantMetadata = new MerchantMetadata();
+            merchantMetadata.setWelcomeMessage(welcomeMessage);
+            merchantMetadata.setName(name);
+            merchantMetadata.setInternalName(name);
+            merchantMetadata.setColorName(colorName);
+            merchantMetadata.setValidTriggers(validTriggers);
+            merchantMetadata.setMerchantType(Merchant.MerchantType.BANK);
+            merchantMetadata.setRoomIds(Sets.newHashSet(65, 209));
+            FilebasedJsonStorage filebasedJsonStorage = new FilebasedJsonStorage(new GsonBuilder().setPrettyPrinting().create());
+            MerchantStorage merchantStorage = new MerchantStorage(null, filebasedJsonStorage);
+            merchantStorage.saveMerchantMetadata(merchantMetadata);
+        }
+
+        {
+            final String name = "old wise man";
+            final String colorName = BOLD_ON + Color.CYAN + name + Color.RESET;
+            String welcomeMessage = "The " + colorName + " can assist you in choosing a character class.\r\n";
+            Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"wise", "man", "old", "old wise man", "m", "w", name}));
+            MerchantMetadata merchantMetadata = new MerchantMetadata();
+            merchantMetadata.setWelcomeMessage(welcomeMessage);
+            merchantMetadata.setName(name);
+            merchantMetadata.setInternalName(name);
+            merchantMetadata.setColorName(colorName);
+            merchantMetadata.setValidTriggers(validTriggers);
+            merchantMetadata.setMerchantType(Merchant.MerchantType.PLAYERCLASS_SELECTOR);
+            merchantMetadata.setRoomIds(Sets.newHashSet(2));
+            FilebasedJsonStorage filebasedJsonStorage = new FilebasedJsonStorage(new GsonBuilder().setPrettyPrinting().create());
+            MerchantStorage merchantStorage = new MerchantStorage(null, filebasedJsonStorage);
+            merchantStorage.saveMerchantMetadata(merchantMetadata);
+        }
+
+        {
+            final String name = "a bank of lockers";
+            final String colorName = BOLD_ON + Color.CYAN + name + Color.RESET;
+            String welcomeMessage = "Locker opened.";
+            Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"lockers", "locker", "l", name}));
+            MerchantMetadata merchantMetadata = new MerchantMetadata();
+            merchantMetadata.setWelcomeMessage(welcomeMessage);
+            merchantMetadata.setName(name);
+            merchantMetadata.setInternalName(name);
+            merchantMetadata.setColorName(colorName);
+            merchantMetadata.setValidTriggers(validTriggers);
+            merchantMetadata.setMerchantType(Merchant.MerchantType.LOCKER);
+            merchantMetadata.setRoomIds(Sets.newHashSet(63));
+            FilebasedJsonStorage filebasedJsonStorage = new FilebasedJsonStorage(new GsonBuilder().setPrettyPrinting().create());
+            MerchantStorage merchantStorage = new MerchantStorage(null, filebasedJsonStorage);
+            merchantStorage.saveMerchantMetadata(merchantMetadata);
+
+        }
+
+    }
+
+}
+*/
diff --git a/src/test/com/comandante/creeper/player/combat_simuation/NpcTestHarness.java b/src/test/com/comandante/creeper/player/combat_simuation/NpcTestHarness.java
index 4dd6041b8106f7adad4cb552bc3d05249863a874..4d0df8fa76c2bdc8bef229e14e4a3d39fcb5007f 100644
--- a/src/test/com/comandante/creeper/player/combat_simuation/NpcTestHarness.java
+++ b/src/test/com/comandante/creeper/player/combat_simuation/NpcTestHarness.java
@@ -7,7 +7,6 @@ import com.comandante.creeper.core_game.GameManager;
 import com.comandante.creeper.core_game.SessionManager;
 import com.comandante.creeper.entity.EntityManager;
 import com.comandante.creeper.items.Item;
-import com.comandante.creeper.items.ItemType;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.npc.NpcBuilder;
 import com.comandante.creeper.player.*;
@@ -63,7 +62,7 @@ public class NpcTestHarness {
         Npc npcFromFile = npcsFromFile.stream().filter(npc -> npc.getName().equals("swamp berserker")).collect(Collectors.toList()).get(0);
         processRunAndVerify(npcFromFile, 1, Sets.newHashSet(), 15f, 0f, 10, 0, 10, 5);
         processRunAndVerify(npcFromFile, 2, Sets.newHashSet(), 25f, 0f, 10, 0, 10, 5);
-        processRunAndVerify(npcFromFile, 3, Sets.newHashSet(), 55f, 0f, 10, 0,10, 5);
+        processRunAndVerify(npcFromFile, 3, Sets.newHashSet(), 55f, 0f, 10, 0, 10, 5);
         processRunAndVerify(npcFromFile, 4, Sets.newHashSet(), 90f, 0f, 10, 0, 10, 5);
     }
 
@@ -74,7 +73,7 @@ public class NpcTestHarness {
         Npc npcFromFile = npcsFromFile.stream().filter(npc -> npc.getName().equals("blood wolf")).collect(Collectors.toList()).get(0);
         processRunAndVerify(npcFromFile, 1, Sets.newHashSet(), 15f, 0f, 10, 0, 14, 5);
         processRunAndVerify(npcFromFile, 2, Sets.newHashSet(), 25f, 0f, 10, 0, 14, 5);
-        processRunAndVerify(npcFromFile, 3, Sets.newHashSet(), 55f, 0f, 10, 0,14, 5);
+        processRunAndVerify(npcFromFile, 3, Sets.newHashSet(), 55f, 0f, 10, 0, 14, 5);
         processRunAndVerify(npcFromFile, 4, Sets.newHashSet(), 90f, 0f, 10, 0, 14, 5);
     }
 
@@ -86,7 +85,7 @@ public class NpcTestHarness {
         processRunAndVerify(npcFromFile, 3, Sets.newHashSet(), 20f, 12f, 10, 0, 14, 8);
         processRunAndVerify(npcFromFile, 4, Sets.newHashSet(), 40f, 33f, 10, 0, 14, 8);
         processRunAndVerify(npcFromFile, 5, Sets.newHashSet(), 80f, 70f, 10, 0, 14, 8);
-        processRunAndVerify(npcFromFile, 6, Sets.newHashSet(), 95f, 86f, 10, 0,14,8);
+        processRunAndVerify(npcFromFile, 6, Sets.newHashSet(), 95f, 86f, 10, 0, 14, 8);
     }
 
     // Levels 6-8
@@ -111,12 +110,13 @@ public class NpcTestHarness {
     }
 
     private Set<Item> getEarlyLevelArmorSet() {
-        return Sets.newHashSet(ItemType.BERSERKER_BATON.create(), ItemType.BERSEKER_BOOTS.create(), ItemType.BERSEKER_SHORTS.create());
+        //  return Sets.newHashSet(ItemType.BERSERKER_BATON.create(), ItemType.BERSEKER_BOOTS.create(), ItemType.BERSEKER_SHORTS.create());
+        return Sets.newConcurrentHashSet();
     }
 
     private Set<Item> getMidLevelArmorSet() {
         Set<Item> armorSet = getEarlyLevelArmorSet();
-        armorSet.addAll(Sets.newHashSet(ItemType.BERSERKER_BRACERS.create(), ItemType.BERSERKER_CHEST.create()));
+        //  armorSet.addAll(Sets.newHashSet(ItemType.BERSERKER_BRACERS.create(), ItemType.BERSERKER_CHEST.create()));
         return armorSet;
     }
 
@@ -129,7 +129,7 @@ public class NpcTestHarness {
         Assert.assertTrue("player at level: " + desiredLevel + " wins too quickly", combatSimulationResultLevel.getAverageRounds() >= minRounds);
         Assert.assertTrue("player at level: " + desiredLevel + " wins too slowly.", combatSimulationResultLevel.getAverageRounds() <= maxRounds);
         Assert.assertTrue("Not enough gold.", combatSimulationResultLevel.getAverageGoldPerWin() >= minAvgGold);
-        Assert.assertTrue("Too much gold.",combatSimulationResultLevel.getAverageGoldPerWin() <= maxAvgGold);
+        Assert.assertTrue("Too much gold.", combatSimulationResultLevel.getAverageGoldPerWin() <= maxAvgGold);
     }
 
     public CombatSimulationResult executeCombat(CombatSimulationDetails combatSimulationDetails) throws Exception {
@@ -292,12 +292,12 @@ public class NpcTestHarness {
         ChannelCommunicationUtils channelUtils = new ChannelCommunicationUtils() {
             @Override
             public void write(String playerId, String message) {
-               //System.out.println(message);
+                //System.out.println(message);
             }
 
             @Override
             public void write(String playerId, String message, boolean leadingBlankLine) {
-               //System.out.println(message);
+                //System.out.println(message);
             }
         };
         CreeperConfiguration creeperConfiguration = new CreeperConfiguration(new MapConfiguration(Maps.newHashMap()));
diff --git a/world/items/basic_key.json b/world/items/basic_key.json
new file mode 100644
index 0000000000000000000000000000000000000000..3f408daebf0c085807cd324ea2800efcbab75607
--- /dev/null
+++ b/world/items/basic_key.json
@@ -0,0 +1,28 @@
+{
+  "internalItemName": "basic key",
+  "itemName": "a shiny \u001b[33mgold key\u001b[m",
+  "itemDescription": "A basic key with nothing really remarkable other than its made of gold.",
+  "restingName": "a shiny \u001b[33mgold key\u001b[m catches your eye.",
+  "valueInGold": 10,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "itemTriggers": [
+    "key",
+    "gold key",
+    "shiny gold key"
+  ],
+  "validTimeOfDays": [
+    "NIGHT"
+  ],
+  "isDisposable": false,
+  "maxUses": 0,
+  "spawnRules": [
+    {
+      "area": "LOBBY",
+      "randomChance": 5,
+      "spawnIntervalTicks": 600,
+      "maxInstances": 1,
+      "maxPerRoom": 1
+    }
+  ]
+}
\ No newline at end of file
diff --git a/world/items/beserker_baton.json b/world/items/beserker_baton.json
new file mode 100644
index 0000000000000000000000000000000000000000..87fba918d030ceace1eedcda90abfb5635ffb35f
--- /dev/null
+++ b/world/items/beserker_baton.json
@@ -0,0 +1,40 @@
+{
+  "internalItemName": "beserker baton",
+  "itemName": "\u001b[36ma berserker baton\u001b[m",
+  "itemDescription": "a berserker baton",
+  "restingName": "a berserker baton rests upon the ground.",
+  "valueInGold": 100,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "equipment": {
+    "equipmentSlotType": "HAND",
+    "statsIncreaseWhileEquipped": {
+      "strength": 0,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 0,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 0,
+      "weaponRatingMax": 6,
+      "weaponRatingMin": 4,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 0,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "baton",
+    "a berserker baton",
+    "b"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/beserker_boots.json b/world/items/beserker_boots.json
new file mode 100644
index 0000000000000000000000000000000000000000..eb5f0bd7b0e421e7d3e815c591d66ff33a68184d
--- /dev/null
+++ b/world/items/beserker_boots.json
@@ -0,0 +1,41 @@
+{
+  "internalItemName": "beserker boots",
+  "itemName": "\u001b[36mberserker boots\u001b[m",
+  "itemDescription": "a pair of berserker boots",
+  "restingName": "a pair of berserker boots are here on the ground.",
+  "valueInGold": 50,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "equipment": {
+    "equipmentSlotType": "FEET",
+    "statsIncreaseWhileEquipped": {
+      "strength": 0,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 3,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 0,
+      "weaponRatingMax": 0,
+      "weaponRatingMin": 0,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 0,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "boots",
+    "boot",
+    "berserker boots",
+    "b"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/beserker_bracers.json b/world/items/beserker_bracers.json
new file mode 100644
index 0000000000000000000000000000000000000000..9cd91c21c3232fa7c328b9136487a2ea579f9d1b
--- /dev/null
+++ b/world/items/beserker_bracers.json
@@ -0,0 +1,40 @@
+{
+  "internalItemName": "beserker bracers",
+  "itemName": "\u001b[36mberserker bracers\u001b[m",
+  "itemDescription": "a pair of berserker bracers",
+  "restingName": "a pair of berserker bracers are here on the ground.",
+  "valueInGold": 40,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "equipment": {
+    "equipmentSlotType": "WRISTS",
+    "statsIncreaseWhileEquipped": {
+      "strength": 0,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 4,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 0,
+      "weaponRatingMax": 0,
+      "weaponRatingMin": 0,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 0,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "bracers",
+    "berserker bracers",
+    "b"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/beserker_chest.json b/world/items/beserker_chest.json
new file mode 100644
index 0000000000000000000000000000000000000000..813b8c501770ee7705851f744702c47e474f0f75
--- /dev/null
+++ b/world/items/beserker_chest.json
@@ -0,0 +1,40 @@
+{
+  "internalItemName": "beserker chest",
+  "itemName": "\u001b[36mberserker chest\u001b[m",
+  "itemDescription": "a berserker chest",
+  "restingName": "a berserker chest is on the ground.",
+  "valueInGold": 70,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "equipment": {
+    "equipmentSlotType": "CHEST",
+    "statsIncreaseWhileEquipped": {
+      "strength": 0,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 6,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 0,
+      "weaponRatingMax": 0,
+      "weaponRatingMin": 0,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 0,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "chest",
+    "berserker chest",
+    "c"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/beserker_helm.json b/world/items/beserker_helm.json
new file mode 100644
index 0000000000000000000000000000000000000000..41167b0885716e518e15a61e171a98ca9e32ad0c
--- /dev/null
+++ b/world/items/beserker_helm.json
@@ -0,0 +1,40 @@
+{
+  "internalItemName": "beserker helm",
+  "itemName": "\u001b[36mberserker helm\u001b[m",
+  "itemDescription": "a berserker helm",
+  "restingName": "a berserker helm is on the ground.",
+  "valueInGold": 40,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "equipment": {
+    "equipmentSlotType": "HEAD",
+    "statsIncreaseWhileEquipped": {
+      "strength": 0,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 3,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 0,
+      "weaponRatingMax": 0,
+      "weaponRatingMin": 0,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 0,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "helm",
+    "berserker helm",
+    "h"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/beserker_shorts.json b/world/items/beserker_shorts.json
new file mode 100644
index 0000000000000000000000000000000000000000..f223c806e5c27b83393b09b537559eba5323530e
--- /dev/null
+++ b/world/items/beserker_shorts.json
@@ -0,0 +1,40 @@
+{
+  "internalItemName": "beserker shorts",
+  "itemName": "\u001b[36mberserker shorts\u001b[m",
+  "itemDescription": "a pair of berserker shorts",
+  "restingName": "a pair of berserker shorts are here on the ground.",
+  "valueInGold": 80,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "equipment": {
+    "equipmentSlotType": "LEGS",
+    "statsIncreaseWhileEquipped": {
+      "strength": 0,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 4,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 0,
+      "weaponRatingMax": 0,
+      "weaponRatingMin": 0,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 0,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "shorts",
+    "berserker shorts",
+    "s"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/biggers_skin_satchel.json b/world/items/biggers_skin_satchel.json
new file mode 100644
index 0000000000000000000000000000000000000000..b458e7689e0a5e0bdf5950d4fcf400cf07587268
--- /dev/null
+++ b/world/items/biggers_skin_satchel.json
@@ -0,0 +1,39 @@
+{
+  "internalItemName": "biggers skin satchel",
+  "itemName": "a \u001b[32mbiggers skin satchel\u001b[m",
+  "itemDescription": "a \u001b[32mbiggers skin satchel\u001b[m with room to store 100 items.",
+  "restingName": "a \u001b[32mbiggers skin satchel\u001b[m",
+  "valueInGold": 3000,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "equipment": {
+    "equipmentSlotType": "BAG",
+    "statsIncreaseWhileEquipped": {
+      "strength": 0,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 0,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 0,
+      "weaponRatingMax": 0,
+      "weaponRatingMin": 0,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 100,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "biggers skin satchel",
+    "skin satchel"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/leather_satchel.json b/world/items/leather_satchel.json
new file mode 100644
index 0000000000000000000000000000000000000000..6cc70f06bad0cfcc954ce94d3099007677087486
--- /dev/null
+++ b/world/items/leather_satchel.json
@@ -0,0 +1,39 @@
+{
+  "internalItemName": "leather satchel",
+  "itemName": "a \u001b[32mleather satchel\u001b[m",
+  "itemDescription": "a \u001b[32mleather satchel\u001b[m (15 items)",
+  "restingName": "a \u001b[32mleather satchel\u001b[m",
+  "valueInGold": 800,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "equipment": {
+    "equipmentSlotType": "BAG",
+    "statsIncreaseWhileEquipped": {
+      "strength": 0,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 0,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 0,
+      "weaponRatingMax": 0,
+      "weaponRatingMin": 0,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 15,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "leather satchel",
+    "satchel"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/lightning_spellbook.json b/world/items/lightning_spellbook.json
new file mode 100644
index 0000000000000000000000000000000000000000..b0d55c1f3697c259514d62620fbb082fb65b6a38
--- /dev/null
+++ b/world/items/lightning_spellbook.json
@@ -0,0 +1,18 @@
+{
+  "internalItemName": "lightning spellbook",
+  "itemName": "a \u001b[33mlightning\u001b[m spell book.\u001b[m",
+  "itemDescription": "a \u001b[33mlightning\u001b[m spell book.\u001b[m",
+  "restingName": "a \u001b[33mlightning\u001b[m spell book.\u001b[m",
+  "valueInGold": 3000,
+  "itemHalfLifeTicks": 60,
+  "rarity": "RARE",
+  "itemTriggers": [
+    "lightning book",
+    "lightning spell book",
+    "book",
+    "spell book"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": true,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/marijuana.json b/world/items/marijuana.json
new file mode 100644
index 0000000000000000000000000000000000000000..12353731e870c541513d684f8e30e8e8520c675f
--- /dev/null
+++ b/world/items/marijuana.json
@@ -0,0 +1,57 @@
+{
+  "internalItemName": "marijuana",
+  "itemName": "\u001b[32mmarijuana\u001b[m flowers\u001b[m",
+  "itemDescription": "some \u001b[32mmarijuana\u001b[m flowers\u001b[m",
+  "restingName": "some \u001b[32mmarijuana\u001b[m flowers\u001b[m are here on the ground.",
+  "valueInGold": 10,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "itemTriggers": [
+    "marijuana",
+    "weed",
+    "m",
+    "w",
+    "f",
+    "flowers"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": true,
+  "maxUses": 0,
+  "forages": [
+    {
+      "minLevel": 0,
+      "pctOfSuccess": 40.0,
+      "minAmt": 1,
+      "maxAmt": 3,
+      "forageExperience": 4,
+      "coolDownTicks": 600,
+      "coolDownTicksLeft": 0,
+      "forageAreas": [
+        "BLOODRIDGE2_ZONE",
+        "BLOODRIDGE1_ZONE",
+        "WESTERN9_ZONE",
+        "NORTH3_ZONE"
+      ]
+    }
+  ],
+  "itemApplyStats": {
+    "strength": 0,
+    "intelligence": 0,
+    "willpower": 0,
+    "aim": 0,
+    "agile": 0,
+    "armorRating": 0,
+    "meleSkill": 0,
+    "currentHealth": 75,
+    "maxHealth": 0,
+    "weaponRatingMax": 0,
+    "weaponRatingMin": 0,
+    "numberOfWeaponRolls": 0,
+    "experience": 0,
+    "currentMana": 75,
+    "maxMana": 0,
+    "foraging": 0,
+    "inventorySize": 0,
+    "maxEffects": 0
+  }
+}
\ No newline at end of file
diff --git a/world/items/purple_drank.json b/world/items/purple_drank.json
new file mode 100644
index 0000000000000000000000000000000000000000..81e4f82ea65eb69cceec94baef692b48ff678041
--- /dev/null
+++ b/world/items/purple_drank.json
@@ -0,0 +1,40 @@
+{
+  "internalItemName": "purple drank",
+  "itemName": "a double cup of \u001b[35mpurple\u001b[m drank",
+  "itemDescription": "a tonic called \u001b[35mpurple\u001b[m drank that restores health\u001b[m",
+  "restingName": "a double cup of \u001b[35mpurple\u001b[m drank rests on the ground.",
+  "valueInGold": 30,
+  "itemHalfLifeTicks": 60,
+  "rarity": "BASIC",
+  "itemTriggers": [
+    "drank",
+    "purple drank",
+    "p",
+    "purple",
+    "lean",
+    "sizzurp"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": true,
+  "maxUses": 0,
+  "itemApplyStats": {
+    "strength": 0,
+    "intelligence": 0,
+    "willpower": 0,
+    "aim": 0,
+    "agile": 0,
+    "armorRating": 0,
+    "meleSkill": 0,
+    "currentHealth": 50,
+    "maxHealth": 0,
+    "weaponRatingMax": 0,
+    "weaponRatingMin": 0,
+    "numberOfWeaponRolls": 0,
+    "experience": 0,
+    "currentMana": 0,
+    "maxMana": 0,
+    "foraging": 0,
+    "inventorySize": 0,
+    "maxEffects": 0
+  }
+}
\ No newline at end of file
diff --git a/world/items/rad_claw_hoodie.json b/world/items/rad_claw_hoodie.json
new file mode 100644
index 0000000000000000000000000000000000000000..f2d64214ab8316c4096a1dc13f1dbcadeabf68e9
--- /dev/null
+++ b/world/items/rad_claw_hoodie.json
@@ -0,0 +1,40 @@
+{
+  "internalItemName": "rad claw hoodie",
+  "itemName": "\u001b[31mred-claw \u001b[mhoodie\u001b[m",
+  "itemDescription": "a red-claw hoodie",
+  "restingName": "a \u001b[31mred-claw \u001b[mhoodie is on the ground.",
+  "valueInGold": 3500,
+  "itemHalfLifeTicks": 60,
+  "rarity": "LEGENDARY",
+  "equipment": {
+    "equipmentSlotType": "CHEST",
+    "statsIncreaseWhileEquipped": {
+      "strength": 7,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 15,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 0,
+      "weaponRatingMax": 0,
+      "weaponRatingMin": 0,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 0,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "hoodie",
+    "red-claw hoodie",
+    "h"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/rad_claw_pants.json b/world/items/rad_claw_pants.json
new file mode 100644
index 0000000000000000000000000000000000000000..ee9f6b53de35ccbfbe80bee9470be4dc1eb7f6a6
--- /dev/null
+++ b/world/items/rad_claw_pants.json
@@ -0,0 +1,40 @@
+{
+  "internalItemName": "rad claw pants",
+  "itemName": "\u001b[31mred-claw \u001b[mpants\u001b[m",
+  "itemDescription": "a red-claw pants",
+  "restingName": "a \u001b[31mred-claw \u001b[mpants is on the ground.",
+  "valueInGold": 3500,
+  "itemHalfLifeTicks": 60,
+  "rarity": "LEGENDARY",
+  "equipment": {
+    "equipmentSlotType": "LEGS",
+    "statsIncreaseWhileEquipped": {
+      "strength": 7,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 15,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 0,
+      "weaponRatingMax": 0,
+      "weaponRatingMin": 0,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 0,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "pants",
+    "red-claw pants",
+    "p"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/red_claw_beanie.json b/world/items/red_claw_beanie.json
new file mode 100644
index 0000000000000000000000000000000000000000..6c8503bd31df632ddfd0203bc1bcefd2765eecc9
--- /dev/null
+++ b/world/items/red_claw_beanie.json
@@ -0,0 +1,40 @@
+{
+  "internalItemName": "red claw beanie",
+  "itemName": "\u001b[31mred-claw \u001b[mbeanie\u001b[m",
+  "itemDescription": "a red-claw beanie",
+  "restingName": "a \u001b[31mred-claw \u001b[mbeanie is on the ground.",
+  "valueInGold": 3500,
+  "itemHalfLifeTicks": 60,
+  "rarity": "LEGENDARY",
+  "equipment": {
+    "equipmentSlotType": "HEAD",
+    "statsIncreaseWhileEquipped": {
+      "strength": 4,
+      "intelligence": 0,
+      "willpower": 0,
+      "aim": 0,
+      "agile": 0,
+      "armorRating": 8,
+      "meleSkill": 0,
+      "currentHealth": 0,
+      "maxHealth": 50,
+      "weaponRatingMax": 0,
+      "weaponRatingMin": 0,
+      "numberOfWeaponRolls": 0,
+      "experience": 0,
+      "currentMana": 0,
+      "maxMana": 0,
+      "foraging": 0,
+      "inventorySize": 0,
+      "maxEffects": 0
+    }
+  },
+  "itemTriggers": [
+    "beanie",
+    "red-claw beanie",
+    "b"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": false,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/items/small_health_potion.json b/world/items/small_health_potion.json
new file mode 100644
index 0000000000000000000000000000000000000000..662f162b5dda9b8c888b27e25ff3f3e3804d49b4
--- /dev/null
+++ b/world/items/small_health_potion.json
@@ -0,0 +1,62 @@
+{
+  "internalItemName": "small health potion",
+  "itemName": "a small vial of \u001b[31mhealth potion\u001b[m",
+  "itemDescription": "a small vial of \u001b[31mhealth potion\u001b[m that restores 50 health\u001b[m",
+  "restingName": "a small vial of \u001b[31mhealth potion\u001b[m rests on the ground.",
+  "valueInGold": 1,
+  "itemHalfLifeTicks": 60,
+  "rarity": "OFTEN",
+  "itemTriggers": [
+    "potion",
+    "health potion",
+    "vial",
+    "small vial of health potion",
+    "p"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": true,
+  "maxUses": 0,
+  "spawnRules": [
+    {
+      "area": "NEWBIE_ZONE",
+      "randomChance": 40,
+      "spawnIntervalTicks": 600,
+      "maxInstances": 100,
+      "maxPerRoom": 5
+    },
+    {
+      "area": "FANCYHOUSE_ZONE",
+      "randomChance": 50,
+      "spawnIntervalTicks": 600,
+      "maxInstances": 12,
+      "maxPerRoom": 2
+    },
+    {
+      "area": "HOUSE_ZONE",
+      "randomChance": 50,
+      "spawnIntervalTicks": 600,
+      "maxInstances": 12,
+      "maxPerRoom": 2
+    }
+  ],
+  "itemApplyStats": {
+    "strength": 0,
+    "intelligence": 0,
+    "willpower": 0,
+    "aim": 0,
+    "agile": 0,
+    "armorRating": 0,
+    "meleSkill": 0,
+    "currentHealth": 20,
+    "maxHealth": 0,
+    "weaponRatingMax": 0,
+    "weaponRatingMin": 0,
+    "numberOfWeaponRolls": 0,
+    "experience": 0,
+    "currentMana": 0,
+    "maxMana": 0,
+    "foraging": 0,
+    "inventorySize": 0,
+    "maxEffects": 0
+  }
+}
\ No newline at end of file
diff --git a/world/items/stick_of_justice.json b/world/items/stick_of_justice.json
new file mode 100644
index 0000000000000000000000000000000000000000..4a2e3230c9b3480fbba5f7d51888dc4b652e2ff4
--- /dev/null
+++ b/world/items/stick_of_justice.json
@@ -0,0 +1,17 @@
+{
+  "internalItemName": "stick of justice",
+  "itemName": "a \u001b[1m\u001b[35mstick\u001b[22m\u001b[32m of \u001b[1m\u001b[34mjustice\u001b[m",
+  "itemDescription": "a \u001b[1m\u001b[35mstick\u001b[22m\u001b[32m of \u001b[1m\u001b[34mjustice\u001b[m",
+  "restingName": "a \u001b[1m\u001b[35mstick\u001b[22m\u001b[32m of \u001b[1m\u001b[34mjustice\u001b[m",
+  "valueInGold": 3000,
+  "itemHalfLifeTicks": 60,
+  "rarity": "RARE",
+  "itemTriggers": [
+    "stick of justice",
+    "justice",
+    "stick"
+  ],
+  "validTimeOfDays": [],
+  "isDisposable": true,
+  "maxUses": 0
+}
\ No newline at end of file
diff --git a/world/merchants/a_bank_of_lockers.json b/world/merchants/a_bank_of_lockers.json
new file mode 100644
index 0000000000000000000000000000000000000000..094a16ae97ed82df9d7d1fa40f52bc7b029bb9c4
--- /dev/null
+++ b/world/merchants/a_bank_of_lockers.json
@@ -0,0 +1,16 @@
+{
+  "internalName": "a bank of lockers",
+  "roomIds": [
+    63
+  ],
+  "name": "a bank of lockers",
+  "colorName": "\u001b[1m\u001b[36ma bank of lockers\u001b[m",
+  "validTriggers": [
+    "a bank of lockers",
+    "lockers",
+    "l",
+    "locker"
+  ],
+  "welcomeMessage": "Locker opened.",
+  "merchantType": "LOCKER"
+}
\ No newline at end of file
diff --git a/world/merchants/biggers_the_blacksmith.json b/world/merchants/biggers_the_blacksmith.json
new file mode 100644
index 0000000000000000000000000000000000000000..afa9c10b28a25c15a96aaa1628de360c8e444a4b
--- /dev/null
+++ b/world/merchants/biggers_the_blacksmith.json
@@ -0,0 +1,45 @@
+{
+  "internalName": "biggers the blacksmith",
+  "roomIds": [
+    253,
+    66
+  ],
+  "name": "biggers the blacksmith",
+  "colorName": "\u001b[1m\u001b[36mbiggers the blacksmith\u001b[m",
+  "validTriggers": [
+    "blacksmith",
+    "biggers",
+    "biggers the blacksmith"
+  ],
+  "merchantItemForSales": [
+    {
+      "internalItemName": "berserker baton",
+      "cost": 10000
+    },
+    {
+      "internalItemName": "berserker boots",
+      "cost": 3500
+    },
+    {
+      "internalItemName": "berserker bracers",
+      "cost": 3500
+    },
+    {
+      "internalItemName": "berserker helm",
+      "cost": 3500
+    },
+    {
+      "internalItemName": "berserker chest",
+      "cost": 7000
+    },
+    {
+      "internalItemName": "berserker shorts",
+      "cost": 8500
+    },
+    {
+      "internalItemName": "leather satchel",
+      "cost": 600
+    }
+  ],
+  "welcomeMessage": "  ____  _                                              \n\" +\n                    \" | __ )(_) __ _  __ _  ___ _ __ ___                    \\r\\n\" +\n                    \" |  _ \\\\| |/ _` |/ _` |/ _ \\\\ \u0027__/ __|                   \\r\\n\" +\n                    \" | |_) | | (_| | (_| |  __/ |  \\\\__ \\\\                   \\r\\n\" +\n                    \" |____/|_|\\\\__, |\\\\__, |\\\\___|_|  |___/                   \\r\\n\" +\n                    \"     ____ |___/ |___/   _                  _ _   _     \\r\\n\" +\n                    \"    | __ )| | __ _  ___| | _____ _ __ ___ (_) |_| |__  \\r\\n\" +\n                    \"    |  _ \\\\| |/ _` |/ __| |/ / __| \u0027_ ` _ \\\\| | __| \u0027_ \\\\ \\r\\n\" +\n                    \"    | |_) | | (_| | (__|   \u003c\\\\__ \\\\ | | | | | | |_| | | |\\r\\n\" +\n                    \"    |____/|_|\\__,_|\\___|_|\\_\\___/_| |_| |_|_|\\__|_| |_|\n"
+}
\ No newline at end of file
diff --git a/world/merchants/jim_the_banker.json b/world/merchants/jim_the_banker.json
new file mode 100644
index 0000000000000000000000000000000000000000..868c0a5586846c3b4164b06806f4da71728ede71
--- /dev/null
+++ b/world/merchants/jim_the_banker.json
@@ -0,0 +1,18 @@
+{
+  "internalName": "jim the banker",
+  "roomIds": [
+    65,
+    209
+  ],
+  "name": "jim the banker",
+  "colorName": "\u001b[1m\u001b[36mjim the banker\u001b[m",
+  "validTriggers": [
+    "bank",
+    "j",
+    "banker",
+    "jim the banker",
+    "jim"
+  ],
+  "welcomeMessage": "Welcome to the First National Bank of Creeper.",
+  "merchantType": "BANK"
+}
\ No newline at end of file
diff --git a/world/merchants/lloyd_the_bartender.json b/world/merchants/lloyd_the_bartender.json
new file mode 100644
index 0000000000000000000000000000000000000000..49660afd28dfae9c8340b486c131490a5fc88499
--- /dev/null
+++ b/world/merchants/lloyd_the_bartender.json
@@ -0,0 +1,31 @@
+{
+  "internalName": "lloyd the bartender",
+  "roomIds": [
+    64
+  ],
+  "name": "lloyd the bartender",
+  "colorName": "\u001b[1m\u001b[36mlloyd the bartender\u001b[m",
+  "validTriggers": [
+    "lloyd the bartender",
+    "bartender",
+    "LLOYD",
+    "barkeep",
+    "Lloyd",
+    "lloyd"
+  ],
+  "merchantItemForSales": [
+    {
+      "internalItemName": "small health potion",
+      "cost": 8
+    },
+    {
+      "internalItemName": "purple drank",
+      "cost": 80
+    },
+    {
+      "internalItemName": "biggers skin satchel",
+      "cost": 25000
+    }
+  ],
+  "welcomeMessage": " _        _        _______           ______   _  _______ \r\n( \\      ( \\      (  ___  )|\\     /|(  __  \\ ( )(  ____ \\\r\n| (      | (      | (   ) |( \\   / )| (  \\  )|/ | (    \\/\r\n| |      | |      | |   | | \\ (_) / | |   ) |   | (_____ \r\n| |      | |      | |   | |  \\   /  | |   | |   (_____  )\r\n| |      | |      | |   | |   ) (   | |   ) |         ) |\r\n| (____/\\| (____/\\| (___) |   | |   | (__/  )   /\\____) |\r\n(_______/(_______/(_______)   \\_/   (______/    \\_______)\r\n                                                         "
+}
\ No newline at end of file
diff --git a/world/merchants/nigel_the_bartender.json b/world/merchants/nigel_the_bartender.json
new file mode 100644
index 0000000000000000000000000000000000000000..be98637d92eb33d4f0f8fd34a73fc3120581d01f
--- /dev/null
+++ b/world/merchants/nigel_the_bartender.json
@@ -0,0 +1,23 @@
+{
+  "internalName": "nigel the bartender",
+  "roomIds": [
+    377
+  ],
+  "name": "nigel the bartender",
+  "colorName": "\u001b[1m\u001b[36mnigel the bartender\u001b[m",
+  "validTriggers": [
+    "nigel the bartender",
+    "bartender",
+    "barkeep",
+    "nigel",
+    "NIGEL",
+    "Nigel"
+  ],
+  "merchantItemForSales": [
+    {
+      "internalItemName": "small health potion",
+      "cost": 6
+    }
+  ],
+  "welcomeMessage": "\r\n N I G E L \u0027S   B A R \r\n"
+}
\ No newline at end of file
diff --git a/world/merchants/old_wise_man.json b/world/merchants/old_wise_man.json
new file mode 100644
index 0000000000000000000000000000000000000000..08bd894b1f5a1fa7f78f608ff08e04274f932275
--- /dev/null
+++ b/world/merchants/old_wise_man.json
@@ -0,0 +1,18 @@
+{
+  "internalName": "old wise man",
+  "roomIds": [
+    2
+  ],
+  "name": "old wise man",
+  "colorName": "\u001b[1m\u001b[36mold wise man\u001b[m",
+  "validTriggers": [
+    "old wise man",
+    "wise",
+    "old",
+    "w",
+    "man",
+    "m"
+  ],
+  "welcomeMessage": "The \u001b[1m\u001b[36mold wise man\u001b[m can assist you in choosing a character class.\r\n",
+  "merchantType": "PLAYERCLASS_SELECTOR"
+}
\ No newline at end of file
diff --git a/world/merchants/willy_the_wizard.json b/world/merchants/willy_the_wizard.json
new file mode 100644
index 0000000000000000000000000000000000000000..8da84c20f97e7137bdfd414ae06c4b145a8e7bcf
--- /dev/null
+++ b/world/merchants/willy_the_wizard.json
@@ -0,0 +1,20 @@
+{
+  "internalName": "willy the wizard",
+  "roomIds": [
+    98
+  ],
+  "name": "willy the wizard",
+  "colorName": "\u001b[1m\u001b[36mwilly the wizard\u001b[m",
+  "validTriggers": [
+    "willy the wizard",
+    "willy",
+    "wizard"
+  ],
+  "merchantItemForSales": [
+    {
+      "internalItemName": "lightning spellbook",
+      "cost": 50000
+    }
+  ],
+  "welcomeMessage": "  ____                                        \n 6MMMMb\\                                      \n6M\u0027    `   /                                  \nMM        /M       _____     _____   __ ____  \nYM.      /MMMMM   6MMMMMb   6MMMMMb  `M6MMMMb \n YMMMMb   MM     6M\u0027   `Mb 6M\u0027   `Mb  MM\u0027  `Mb\n     `Mb  MM     MM     MM MM     MM  MM    MM\n      MM  MM     MM     MM MM     MM  MM    MM\n      MM  MM     MM     MM MM     MM  MM    MM\nL    ,M9  YM.  , YM.   ,M9 YM.   ,M9  MM.  ,M9\nMYMMMM9    YMMM9  YMMMMM9   YMMMMM9   MMYMMM9 \n                                      MM      \n                                      MM      \n                                     _MM_     \n\n"
+}
\ No newline at end of file
diff --git a/world/npcs/demon_cat.json b/world/npcs/demon_cat.json
index 03eabb52da723880666daaddc0ee9237cfd8575c..5b5578f66f600069b72e2032f9f313bfbe78a151 100644
--- a/world/npcs/demon_cat.json
+++ b/world/npcs/demon_cat.json
@@ -43,7 +43,7 @@
   ],
   "loot": {
     "items": [
-      "SMALL_HEALTH_POTION"
+      "small health potion"
     ],
     "lootGoldMax": 3,
     "lootGoldMin": 1
diff --git a/world/npcs/red-eyed_bear.json b/world/npcs/red-eyed_bear.json
index 068528a7c16c998f2b085f27750b9ff1a415cf4a..cbf9498e9030a72883b319eedd0a5b5e1498ba00 100644
--- a/world/npcs/red-eyed_bear.json
+++ b/world/npcs/red-eyed_bear.json
@@ -53,10 +53,10 @@
   ],
   "loot": {
     "items": [
-      "BERSEKER_HELM",
-      "RED_CLAW_BEANIE",
-      "RED_CLAW_HOODIE",
-      "RED_CLAW_PANTS"
+      "berserker helm",
+      "red claw beanie",
+      "red claw pants",
+      "red claw hoodie"
     ],
     "lootGoldMax": 24,
     "lootGoldMin": 18
diff --git a/world/npcs/swamp_bear.json b/world/npcs/swamp_bear.json
index d67056971a157016f22ea9c1cae48a72f23a8141..bb064a67f5f38773ebaa3c533119d8ed5728c6e6 100644
--- a/world/npcs/swamp_bear.json
+++ b/world/npcs/swamp_bear.json
@@ -52,8 +52,8 @@
   ],
   "loot": {
     "items": [
-      "BERSERKER_BRACERS",
-      "BERSERKER_CHEST"
+      "berserker bracers",
+      "berserker chest"
     ],
     "lootGoldMax": 18,
     "lootGoldMin": 12
diff --git a/world/npcs/swamp_berserker.json b/world/npcs/swamp_berserker.json
index d8869852cb614df0027ac80bf0504df338e8c5b3..90ecbccda32a426ff98916cc276d42dd9bd10f3f 100644
--- a/world/npcs/swamp_berserker.json
+++ b/world/npcs/swamp_berserker.json
@@ -43,7 +43,7 @@
   ],
   "loot": {
     "items": [
-      "BERSERKER_BATON"
+      "berserker baton"
     ],
     "lootGoldMax": 10,
     "lootGoldMin": 5
diff --git a/world/npcs/tree_berserker.json b/world/npcs/tree_berserker.json
index ed5f53e532807f0a98d874ed028c1a0cb780a8e3..b0cbf18963680e83f97601c33097f3335b7d215a 100644
--- a/world/npcs/tree_berserker.json
+++ b/world/npcs/tree_berserker.json
@@ -44,9 +44,9 @@
   ],
   "loot": {
     "items": [
-      "BERSEKER_BOOTS",
-      "BERSEKER_SHORTS",
-      "SMALL_HEALTH_POTION"
+      "beserker boots",
+      "beserker shorts",
+      "small health potion"
     ],
     "lootGoldMax": 14,
     "lootGoldMin": 8