From 58d9e185caef8c120b771b22dcb42766cfde0f7e Mon Sep 17 00:00:00 2001
From: Chris Kearney <chris@kearneymail.com>
Date: Mon, 27 Apr 2015 23:21:05 -0700
Subject: [PATCH] merchants and lots of new npc

---
 pom.xml                                       | 209 +++++++++---------
 .../comandante/creeper/Items/ItemType.java    |   2 +-
 .../creeper/Items/ItemUseHandler.java         |   6 +-
 .../java/com/comandante/creeper/Main.java     |  88 +++++++-
 .../creeper/managers/GameManager.java         |  28 ++-
 .../creeper/merchant/LloydBartender.java      |  40 ++++
 .../comandante/creeper/merchant/Merchant.java |  92 ++++++++
 .../merchant/MerchantCommandHandler.java      |  50 +++++
 .../creeper/merchant/MerchantItemForSale.java |  27 +++
 .../creeper/merchant/MerchantManager.java     |  39 ++++
 .../comandante/creeper/npc/DeathGriffin.java  |  35 +++
 .../comandante/creeper/npc/DemonSuccubus.java |  35 +++
 .../creeper/npc/NightmareTroll.java           |  35 +++
 .../com/comandante/creeper/npc/NpcStats.java  | 111 ++++++++++
 .../comandante/creeper/npc/PhantomKnight.java |  35 +++
 .../comandante/creeper/npc/PhantomOrc.java    |  35 +++
 .../comandante/creeper/npc/PhantomWizard.java |  35 +++
 .../comandante/creeper/npc/RazorClawWolf.java |  35 +++
 .../creeper/npc/TigerMonocerus.java           |  35 +++
 .../creeper/server/CreeperCommandHandler.java |  14 ++
 .../creeper/server/CreeperSession.java        |  18 ++
 .../creeper/server/command/Command.java       |  27 ++-
 .../creeper/server/command/TalkCommand.java   |  54 +++++
 .../creeper/server/command/WhoCommand.java    |   1 -
 .../creeper/spawner/ItemSpawner.java          |   3 +
 .../creeper/spawner/NpcSpawner.java           |   3 +
 .../com/comandante/creeper/world/Room.java    |  18 ++
 .../comandante/creeper/world/RoomManager.java |   5 +
 .../creeper/world/WorldExporter.java          |   1 +
 src/main/resources/log4j.properties           |  22 ++
 30 files changed, 1009 insertions(+), 129 deletions(-)
 create mode 100644 src/main/java/com/comandante/creeper/merchant/LloydBartender.java
 create mode 100644 src/main/java/com/comandante/creeper/merchant/Merchant.java
 create mode 100644 src/main/java/com/comandante/creeper/merchant/MerchantCommandHandler.java
 create mode 100644 src/main/java/com/comandante/creeper/merchant/MerchantItemForSale.java
 create mode 100644 src/main/java/com/comandante/creeper/merchant/MerchantManager.java
 create mode 100644 src/main/java/com/comandante/creeper/npc/DeathGriffin.java
 create mode 100644 src/main/java/com/comandante/creeper/npc/DemonSuccubus.java
 create mode 100644 src/main/java/com/comandante/creeper/npc/NightmareTroll.java
 create mode 100644 src/main/java/com/comandante/creeper/npc/PhantomKnight.java
 create mode 100644 src/main/java/com/comandante/creeper/npc/PhantomOrc.java
 create mode 100644 src/main/java/com/comandante/creeper/npc/PhantomWizard.java
 create mode 100644 src/main/java/com/comandante/creeper/npc/RazorClawWolf.java
 create mode 100644 src/main/java/com/comandante/creeper/npc/TigerMonocerus.java
 create mode 100644 src/main/java/com/comandante/creeper/server/command/TalkCommand.java
 create mode 100644 src/main/resources/log4j.properties

diff --git a/pom.xml b/pom.xml
index dd19dc4c..8d8e31b4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,106 +2,117 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>com.comandante</groupId>
-  <artifactId>creeper</artifactId>
-  <version>0.1.0-SNAPSHOT</version>
-  <dependencies>
-    <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava</artifactId>
-      <version>17.0</version>
-    </dependency>
-    <dependency>
-      <groupId>io.netty</groupId>
-      <artifactId>netty</artifactId>
-      <version>3.6.9.Final</version>
-    </dependency>
-    <dependency>
-      <groupId>commons-codec</groupId>
-      <artifactId>commons-codec</artifactId>
-      <version>1.9</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-lang3</artifactId>
-      <version>3.3.2</version>
-    </dependency>
-    <dependency>
-      <groupId>org.fusesource.jansi</groupId>
-      <artifactId>jansi</artifactId>
-      <version>1.11</version>
-    </dependency>
-    <dependency>
-      <groupId>org.mapdb</groupId>
-      <artifactId>mapdb</artifactId>
-      <version>1.0.6</version>
-    </dependency>
-    <dependency>
-      <groupId>com.google.code.gson</groupId>
-      <artifactId>gson</artifactId>
-      <version>2.2.4</version>
-    </dependency>
-    <dependency>
-      <groupId>org.ow2.sirocco</groupId>
-      <artifactId>sirocco-text-table-formatter</artifactId>
-      <version>1.0</version>
-    </dependency>
-    <dependency>
-      <groupId>com.codahale.metrics</groupId>
-      <artifactId>metrics-core</artifactId>
-      <version>3.0.2</version>
-    </dependency>
-    <dependency>
-      <groupId>com.googlecode.concurrentlinkedhashmap</groupId>
-      <artifactId>concurrentlinkedhashmap-lru</artifactId>
-      <version>1.4</version>
-    </dependency>
-    <dependency>
-      <groupId>log4j</groupId>
-      <artifactId>log4j</artifactId>
-      <version>1.2.17</version>
-    </dependency>
-  </dependencies>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.comandante</groupId>
+    <artifactId>creeper</artifactId>
+    <version>0.1.0-SNAPSHOT</version>
+    <dependencies>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>17.0</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty</artifactId>
+            <version>3.6.9.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.9</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.3.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.fusesource.jansi</groupId>
+            <artifactId>jansi</artifactId>
+            <version>1.11</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mapdb</groupId>
+            <artifactId>mapdb</artifactId>
+            <version>1.0.6</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.2.4</version>
+        </dependency>
+        <dependency>
+            <groupId>org.ow2.sirocco</groupId>
+            <artifactId>sirocco-text-table-formatter</artifactId>
+            <version>1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>io.dropwizard.metrics</groupId>
+            <artifactId>metrics-core</artifactId>
+            <version>3.1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>io.dropwizard.metrics</groupId>
+            <artifactId>metrics-graphite</artifactId>
+            <version>3.1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.googlecode.concurrentlinkedhashmap</groupId>
+            <artifactId>concurrentlinkedhashmap-lru</artifactId>
+            <version>1.4</version>
+        </dependency>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.17</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <version>1.7.12</version>
+        </dependency>
 
+    </dependencies>
 
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.1</version>
-        <configuration>
-          <source>1.7</source>
-          <target>1.7</target>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-        <version>2.3</version>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>shade</goal>
-            </goals>
-            <configuration>
-              <createDependencyReducedPom>false</createDependencyReducedPom>
-              <transformers>
-                <transformer
-                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
-                  <manifestEntries>
-                    <Main-Class>com.comandante.creeper.Main</Main-Class>
-                    <Build-Number>0.1.0-SNAPSHOT</Build-Number>
-                  </manifestEntries>
-                </transformer>
-              </transformers>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.3</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <createDependencyReducedPom>false</createDependencyReducedPom>
+                            <transformers>
+                                <transformer
+                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <manifestEntries>
+                                        <Main-Class>com.comandante.creeper.Main</Main-Class>
+                                        <Build-Number>0.1.0-SNAPSHOT</Build-Number>
+                                    </manifestEntries>
+                                </transformer>
+                            </transformers>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
 
 </project>
diff --git a/src/main/java/com/comandante/creeper/Items/ItemType.java b/src/main/java/com/comandante/creeper/Items/ItemType.java
index 566915ff..0756c1c8 100644
--- a/src/main/java/com/comandante/creeper/Items/ItemType.java
+++ b/src/main/java/com/comandante/creeper/Items/ItemType.java
@@ -21,7 +21,7 @@ public enum ItemType {
     BEER(2, Arrays.asList("beer", "can of beer", "b"),
             "a dented can of " + CYAN + "beer" + RESET,
             "a " + CYAN + "beer" + RESET + " lies on the ground, unopened",
-            "This beer looks sketch but you'll probably drink it anyways.",
+            "an ice cold " + CYAN + "beer" + RESET + " that restores 20 health" + RESET,
             true,
             2,
             60),
diff --git a/src/main/java/com/comandante/creeper/Items/ItemUseHandler.java b/src/main/java/com/comandante/creeper/Items/ItemUseHandler.java
index 3aa63c8a..871db8bf 100644
--- a/src/main/java/com/comandante/creeper/Items/ItemUseHandler.java
+++ b/src/main/java/com/comandante/creeper/Items/ItemUseHandler.java
@@ -1,6 +1,8 @@
 package com.comandante.creeper.Items;
 
 
+import com.codahale.metrics.MetricRegistry;
+import com.comandante.creeper.Main;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.server.CreeperSession;
 
@@ -26,9 +28,11 @@ public class ItemUseHandler {
     }
 
     private void processBeer() {
-        writeToRoom(gameManager.getPlayerManager().getPlayer(playerId).getPlayerName() + " drinks an ice cold cruiser." + "\r\n");
+        String playerName = gameManager.getPlayerManager().getPlayer(playerId).getPlayerName();
+        writeToRoom(playerName + " drinks an ice cold cruiser." + "\r\n");
         writeToPlayer("20 health is restored.");
         gameManager.getPlayerManager().getPlayerMetadata(playerId).getStats().incrementHealth(20);
+        Main.metrics.counter(MetricRegistry.name(ItemUseHandler.class, playerName + "-beer-drank")).inc();
     }
 
     private void processBook() {
diff --git a/src/main/java/com/comandante/creeper/Main.java b/src/main/java/com/comandante/creeper/Main.java
index 661bb877..c3fe8980 100644
--- a/src/main/java/com/comandante/creeper/Main.java
+++ b/src/main/java/com/comandante/creeper/Main.java
@@ -1,14 +1,22 @@
 package com.comandante.creeper;
 
+import com.codahale.metrics.JmxReporter;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.graphite.Graphite;
+import com.codahale.metrics.graphite.GraphiteReporter;
+import com.codahale.metrics.graphite.PickledGraphite;
 import com.comandante.creeper.Items.Item;
 import com.comandante.creeper.Items.ItemType;
 import com.comandante.creeper.Items.Loot;
 import com.comandante.creeper.entity.EntityManager;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.managers.SessionManager;
+import com.comandante.creeper.merchant.LloydBartender;
+import com.comandante.creeper.merchant.Merchant;
+import com.comandante.creeper.merchant.MerchantItemForSale;
 import com.comandante.creeper.npc.*;
 import com.comandante.creeper.player.PlayerManager;
-import com.comandante.creeper.player.PlayerMetadata;
 import com.comandante.creeper.server.ChannelUtils;
 import com.comandante.creeper.server.CreeperCommandRegistry;
 import com.comandante.creeper.server.CreeperServer;
@@ -17,14 +25,11 @@ import com.comandante.creeper.server.command.admin.*;
 import com.comandante.creeper.spawner.ItemSpawner;
 import com.comandante.creeper.spawner.NpcSpawner;
 import com.comandante.creeper.spawner.SpawnRule;
-import com.comandante.creeper.stat.Stats;
-import com.comandante.creeper.stat.StatsBuilder;
 import com.comandante.creeper.world.Area;
 import com.comandante.creeper.world.MapsManager;
-import com.comandante.creeper.world.Room;
 import com.comandante.creeper.world.RoomManager;
 import com.comandante.creeper.world.WorldExporter;
-import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.io.Files;
 import org.apache.commons.codec.binary.Base64;
@@ -34,9 +39,9 @@ import org.mapdb.DBMaker;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.Iterator;
+import java.net.InetSocketAddress;
 import java.util.Map;
-import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 public class Main {
 
@@ -46,8 +51,22 @@ public class Main {
     private static final int PORT = 8080;
     public static final String MUD_NAME = "creeper";
 
+    final public static MetricRegistry metrics = new MetricRegistry();
+
     public static void main(String[] args) throws Exception {
 
+        final JmxReporter jmxReporter = JmxReporter.forRegistry(metrics).build();
+        jmxReporter.start();
+
+        final PickledGraphite pickledGraphite = new PickledGraphite(new InetSocketAddress("192.168.1.11", 2004));
+        final GraphiteReporter reporter = GraphiteReporter.forRegistry(metrics)
+                .prefixedWith(MUD_NAME)
+                .convertRatesTo(TimeUnit.SECONDS)
+                .convertDurationsTo(TimeUnit.MILLISECONDS)
+                .filter(MetricFilter.ALL)
+                .build(pickledGraphite);
+        reporter.start(1, TimeUnit.MINUTES);
+
         checkAndCreateWorld();
 
         DB db = DBMaker.newFileDB(new File("world/creeper.mapdb")).closeOnJvmShutdown().encryptionEnable("creepandicrawl").make();
@@ -91,6 +110,8 @@ public class Main {
         creeperCommandRegistry.addCommand(new GoldCommand(gameManager));
         creeperCommandRegistry.addCommand(new InfoCommand(gameManager));
         creeperCommandRegistry.addCommand(new TeleportCommand(gameManager));
+        creeperCommandRegistry.addCommand(new TalkCommand(gameManager));
+
 
         createNpcs(entityManager, gameManager);
 
@@ -101,7 +122,7 @@ public class Main {
     }
 
     private static void startUpMessage(String message) {
-        System.out.println("[STARTUP] " + message);
+        //System.out.println("[STARTUP] " + message);
         log.info(message);
     }
 
@@ -151,5 +172,54 @@ public class Main {
         entityManager.addEntity(new NpcSpawner(new StealthPanther(gameManager, new Loot(14, 22, Sets.<Item>newHashSet())), Sets.newHashSet(Area.NORTH5_ZONE), gameManager, new SpawnRule(10, 12, 3, 100)));
         entityManager.addEntity(new NpcSpawner(new StealthPanther(gameManager, new Loot(14, 22, Sets.<Item>newHashSet())), Sets.newHashSet(Area.NORTH6_ZONE), gameManager, new SpawnRule(10, 12, 3, 100)));
 
-  }
+        startUpMessage("Adding Phantom Knights");
+
+        PhantomKnight phantomKnight = new PhantomKnight(gameManager, new Loot(18, 26, Sets.<Item>newHashSet()));
+        entityManager.addEntity(new NpcSpawner(phantomKnight, Sets.newHashSet(Area.BLOODRIDGE5_ZONE), gameManager, new SpawnRule(10, 6, 2, 100)));
+        entityManager.addEntity(new NpcSpawner(phantomKnight, Sets.newHashSet(Area.BLOODRIDGE6_ZONE), gameManager, new SpawnRule(10, 14, 2, 100)));
+        entityManager.addEntity(new NpcSpawner(phantomKnight, Sets.newHashSet(Area.BLOODRIDGE7_ZONE), gameManager, new SpawnRule(10, 14, 2, 100)));
+
+
+        PhantomOrc phantomOrc = new PhantomOrc(gameManager, new Loot(16, 24, Sets.<Item>newHashSet()));
+        startUpMessage("Adding Phantom Orcs");
+        entityManager.addEntity(new NpcSpawner(phantomOrc, Sets.newHashSet(Area.BLOODRIDGE4_ZONE), gameManager, new SpawnRule(10, 6, 2, 100)));
+        entityManager.addEntity(new NpcSpawner(phantomOrc, Sets.newHashSet(Area.BLOODRIDGE4_ZONE), gameManager, new SpawnRule(10, 14, 2, 100)));
+
+        PhantomWizard phantomWizard = new PhantomWizard(gameManager, new Loot(16, 24, Sets.<Item>newHashSet()));
+        startUpMessage("Adding Phantom Wizards");
+        entityManager.addEntity(new NpcSpawner(phantomWizard, Sets.newHashSet(Area.BLOODRIDGE4_ZONE), gameManager, new SpawnRule(10, 6, 2, 100)));
+        entityManager.addEntity(new NpcSpawner(phantomWizard, Sets.newHashSet(Area.BLOODRIDGE5_ZONE), gameManager, new SpawnRule(10, 14, 2, 100)));
+
+        startUpMessage("Adding Demon Succubi");
+        DemonSuccubus demonSuccubus = new DemonSuccubus(gameManager, new Loot(80, 100, Sets.<Item>newHashSet()));
+        entityManager.addEntity(new NpcSpawner(demonSuccubus, Sets.newHashSet(Area.WESTERN9_ZONE), gameManager, new SpawnRule(10, 6, 2, 100)));
+        entityManager.addEntity(new NpcSpawner(demonSuccubus, Sets.newHashSet(Area.WESTERN10_ZONE), gameManager, new SpawnRule(10, 14, 2, 100)));
+
+        startUpMessage("Adding Death Griffins");
+        DeathGriffin deathGriffin = new DeathGriffin(gameManager, new Loot(60, 80, Sets.<Item>newHashSet()));
+        entityManager.addEntity(new NpcSpawner(deathGriffin, Sets.newHashSet(Area.WESTERN8_ZONE), gameManager, new SpawnRule(10, 6, 2, 100)));
+        entityManager.addEntity(new NpcSpawner(deathGriffin, Sets.newHashSet(Area.WESTERN9_ZONE), gameManager, new SpawnRule(10, 14, 2, 100)));
+
+        startUpMessage("Adding Nightmare Trolls");
+        NightmareTroll nightmareTroll = new NightmareTroll(gameManager, new Loot(18, 26, Sets.<Item>newHashSet()));
+        entityManager.addEntity(new NpcSpawner(nightmareTroll, Sets.newHashSet(Area.NORTH7_ZONE), gameManager, new SpawnRule(10, 6, 2, 100)));
+        entityManager.addEntity(new NpcSpawner(nightmareTroll, Sets.newHashSet(Area.NORTH8_ZONE), gameManager, new SpawnRule(10, 14, 2, 100)));
+
+        startUpMessage("Adding Tiger Monoceruses");
+        TigerMonocerus tigerMonocerus = new TigerMonocerus(gameManager, new Loot(20, 29, Sets.<Item>newHashSet()));
+        entityManager.addEntity(new NpcSpawner(tigerMonocerus, Sets.newHashSet(Area.NORTH8_ZONE), gameManager, new SpawnRule(10, 6, 2, 100)));
+        entityManager.addEntity(new NpcSpawner(tigerMonocerus, Sets.newHashSet(Area.NORTH9_ZONE), gameManager, new SpawnRule(10, 14, 2, 100)));
+
+        startUpMessage("Adding Razor-claw Wolves");
+        RazorClawWolf razorClawWolf = new RazorClawWolf(gameManager, new Loot(18, 26, Sets.<Item>newHashSet()));
+        entityManager.addEntity(new NpcSpawner(razorClawWolf, Sets.newHashSet(Area.TOFT2_ZONE), gameManager, new SpawnRule(10, 6, 2, 100)));
+        entityManager.addEntity(new NpcSpawner(razorClawWolf, Sets.newHashSet(Area.TOFT3_ZONE), gameManager, new SpawnRule(10, 14, 2, 100)));
+
+        Map<Integer, MerchantItemForSale> itemsForSale = Maps.newHashMap();
+        MerchantItemForSale merchantItemForSale = new MerchantItemForSale(ItemType.BEER, 2);
+        itemsForSale.put(1, merchantItemForSale);
+        LloydBartender lloydBartender = new LloydBartender(gameManager, new Loot(18, 26, Sets.<Item>newHashSet()), itemsForSale);
+        gameManager.getRoomManager().addMerchant(64, lloydBartender);
+
+    }
 }
diff --git a/src/main/java/com/comandante/creeper/managers/GameManager.java b/src/main/java/com/comandante/creeper/managers/GameManager.java
index 3f4c0a46..3be257f3 100644
--- a/src/main/java/com/comandante/creeper/managers/GameManager.java
+++ b/src/main/java/com/comandante/creeper/managers/GameManager.java
@@ -6,6 +6,7 @@ import com.comandante.creeper.Items.ItemDecayManager;
 import com.comandante.creeper.Items.LootManager;
 import com.comandante.creeper.entity.EntityManager;
 import com.comandante.creeper.fight.FightManager;
+import com.comandante.creeper.merchant.Merchant;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.player.PlayerManager;
@@ -30,15 +31,15 @@ import static com.comandante.creeper.server.Color.*;
 
 public class GameManager {
 
-    public static String LOGO = " ▄████▄   ██▀███  ▓█████ ▓█████  ██▓███  ▓█████  ██▀███  \n" +
-            "▒██▀ ▀█  ▓██ ▒ ██▒▓█   ▀ ▓█   ▀ ▓██░  ██▒▓█   ▀ ▓██ ▒ ██▒\n" +
-            "▒▓█    ▄ ▓██ ░▄█ ▒▒███   ▒███   ▓██░ ██▓▒▒███   ▓██ ░▄█ ▒\n" +
-            "▒▓▓▄ ▄██▒▒██▀▀█▄  ▒▓█  ▄ ▒▓█  ▄ ▒██▄█▓▒ ▒▒▓█  ▄ ▒██▀▀█▄  \n" +
-            "▒ ▓███▀ ░░██▓ ▒██▒░▒████▒░▒████▒▒██▒ ░  ░░▒████▒░██▓ ▒██▒\n" +
-            "â–‘ â–‘â–’ â–’  â–‘â–‘ â–’â–“ â–‘â–’â–“â–‘â–‘â–‘ â–’â–‘ â–‘â–‘â–‘ â–’â–‘ â–‘â–’â–“â–’â–‘ â–‘  â–‘â–‘â–‘ â–’â–‘ â–‘â–‘ â–’â–“ â–‘â–’â–“â–‘\n" +
-            "  â–‘  â–’     â–‘â–’ â–‘ â–’â–‘ â–‘ â–‘  â–‘ â–‘ â–‘  â–‘â–‘â–’ â–‘      â–‘ â–‘  â–‘  â–‘â–’ â–‘ â–’â–‘\n" +
-            "â–‘          â–‘â–‘   â–‘    â–‘      â–‘   â–‘â–‘          â–‘     â–‘â–‘   â–‘ \n" +
-            "â–‘ â–‘         â–‘        â–‘  â–‘   â–‘  â–‘            â–‘  â–‘   â–‘     \n" +
+    public static String LOGO = " ▄████▄   ██▀███  ▓█████ ▓█████  ██▓███  ▓█████  ██▀███  \r\n" +
+            "▒██▀ ▀█  ▓██ ▒ ██▒▓█   ▀ ▓█   ▀ ▓██░  ██▒▓█   ▀ ▓██ ▒ ██▒\r\n" +
+            "▒▓█    ▄ ▓██ ░▄█ ▒▒███   ▒███   ▓██░ ██▓▒▒███   ▓██ ░▄█ ▒\r\n" +
+            "▒▓▓▄ ▄██▒▒██▀▀█▄  ▒▓█  ▄ ▒▓█  ▄ ▒██▄█▓▒ ▒▒▓█  ▄ ▒██▀▀█▄  \r\n" +
+            "▒ ▓███▀ ░░██▓ ▒██▒░▒████▒░▒████▒▒██▒ ░  ░░▒████▒░██▓ ▒██▒\r\n" +
+            "â–‘ â–‘â–’ â–’  â–‘â–‘ â–’â–“ â–‘â–’â–“â–‘â–‘â–‘ â–’â–‘ â–‘â–‘â–‘ â–’â–‘ â–‘â–’â–“â–’â–‘ â–‘  â–‘â–‘â–‘ â–’â–‘ â–‘â–‘ â–’â–“ â–‘â–’â–“â–‘\r\n" +
+            "  â–‘  â–’     â–‘â–’ â–‘ â–’â–‘ â–‘ â–‘  â–‘ â–‘ â–‘  â–‘â–‘â–’ â–‘      â–‘ â–‘  â–‘  â–‘â–’ â–‘ â–’â–‘\r\n" +
+            "â–‘          â–‘â–‘   â–‘    â–‘      â–‘   â–‘â–‘          â–‘     â–‘â–‘   â–‘ \r\n" +
+            "â–‘ â–‘         â–‘        â–‘  â–‘   â–‘  â–‘            â–‘  â–‘   â–‘     \r\n" +
             "â–‘                                                        ";
 
     public static String VERSION = "0.1-SNAPSHOT";
@@ -267,6 +268,11 @@ public class GameManager {
         //      sb.append(playerCurrentRoom.getMapData().get()).append("\r\n");
         //  }
         sb.append(getExits(playerCurrentRoom, player)).append("\r\n");
+
+        Set<Merchant> merchants = playerCurrentRoom.getMerchants();
+        for (Merchant merchant: merchants) {
+            sb.append(merchant.getColorName()).append(" is here.").append(RESET).append("\r\n");
+        }
         for (String searchPlayerId : playerCurrentRoom.getPresentPlayerIds()) {
             if (searchPlayerId.equals(player.getPlayerId())) {
                 continue;
@@ -309,7 +315,9 @@ public class GameManager {
 
     public void acquireItem(Player player, String itemId) {
         Room playerCurrentRoom = roomManager.getPlayerCurrentRoom(player).get();
-        playerCurrentRoom.getItemIds().remove(itemId);
+        if (playerCurrentRoom.getItemIds().contains(itemId)) {
+            playerCurrentRoom.getItemIds().remove(itemId);
+        }
         playerManager.addInventoryId(player.getPlayerId(), itemId);
         Item itemEntity = entityManager.getItemEntity(itemId);
         itemEntity.setWithPlayer(true);
diff --git a/src/main/java/com/comandante/creeper/merchant/LloydBartender.java b/src/main/java/com/comandante/creeper/merchant/LloydBartender.java
new file mode 100644
index 00000000..67b49e35
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/merchant/LloydBartender.java
@@ -0,0 +1,40 @@
+package com.comandante.creeper.merchant;
+
+import com.comandante.creeper.Items.Loot;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.npc.Npc;
+import com.comandante.creeper.npc.NpcStats;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.world.Area;
+import com.google.common.base.Optional;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static com.comandante.creeper.server.Color.BOLD_ON;
+import static com.comandante.creeper.server.Color.RESET;
+
+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/Merchant.java b/src/main/java/com/comandante/creeper/merchant/Merchant.java
new file mode 100644
index 00000000..fb6f3d67
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/merchant/Merchant.java
@@ -0,0 +1,92 @@
+package com.comandante.creeper.merchant;
+
+import com.comandante.creeper.Items.Item;
+import com.comandante.creeper.Items.Loot;
+import com.comandante.creeper.entity.CreeperEntity;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.player.Player;
+import com.comandante.creeper.stat.Stats;
+import com.comandante.creeper.world.Area;
+import com.google.common.base.Optional;
+import org.nocrala.tools.texttablefmt.BorderStyle;
+import org.nocrala.tools.texttablefmt.ShownBorders;
+import org.nocrala.tools.texttablefmt.Table;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public abstract class Merchant extends CreeperEntity {
+
+    private long lastPhraseTimestamp;
+    private final GameManager gameManager;
+    private final String name;
+    private final String colorName;
+    private final Set<String> validTriggers;
+    private final Map<Integer, MerchantItemForSale> merchantItemForSales;
+    private final String welcomeMessage;
+
+    public Merchant(GameManager gameManager, String name, String colorName, Set<String> validTriggers, Map<Integer, MerchantItemForSale> merchantItemForSales, String welcomeMessage) {
+        this.gameManager = gameManager;
+        this.name = name;
+        this.colorName = colorName;
+        this.validTriggers = validTriggers;
+        this.merchantItemForSales = merchantItemForSales;
+        this.welcomeMessage = welcomeMessage;
+    }
+
+    public String getMenu() {
+        Table t = new Table(3, BorderStyle.CLASSIC_COMPATIBLE,
+                ShownBorders.HEADER_FOOTER_FIRST_AND_LAST_COLLUMN);
+        t.setColumnWidth(0, 2, 5);
+        t.setColumnWidth(1, 5, 5);
+        t.setColumnWidth(2, 50, 69);
+        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(String.valueOf(next.getValue().getCost()));
+            t.addCell(next.getValue().getItem().getItemDescription());
+            i++;
+        }
+        return t.render();
+    }
+
+    @Override
+    public void run() {
+
+    }
+
+    public long getLastPhraseTimestamp() {
+        return lastPhraseTimestamp;
+    }
+
+    public GameManager getGameManager() {
+        return gameManager;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getColorName() {
+        return colorName;
+    }
+
+    public Set<String> getValidTriggers() {
+        return validTriggers;
+    }
+
+    public Map<Integer, MerchantItemForSale> getMerchantItemForSales() {
+        return merchantItemForSales;
+    }
+
+    public String getWelcomeMessage() {
+        return welcomeMessage;
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/merchant/MerchantCommandHandler.java b/src/main/java/com/comandante/creeper/merchant/MerchantCommandHandler.java
new file mode 100644
index 00000000..0a9ef254
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/merchant/MerchantCommandHandler.java
@@ -0,0 +1,50 @@
+package com.comandante.creeper.merchant;
+
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.player.Player;
+import com.comandante.creeper.server.CreeperSession;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
+
+import java.util.UUID;
+
+public class MerchantCommandHandler extends SimpleChannelUpstreamHandler {
+
+    private final GameManager gameManager;
+    private final Merchant merchant;
+    private final MerchantManager merchantManager;
+
+    public MerchantCommandHandler(GameManager gameManager, Merchant merchant) {
+        this.gameManager = gameManager;
+        this.merchant = merchant;
+        this.merchantManager = new MerchantManager(gameManager);
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        CreeperSession creeperSession = (CreeperSession) e.getChannel().getAttachment();
+        Player playerByUsername = gameManager.getPlayerManager().getPlayerByUsername(creeperSession.getUsername().get());
+        try {
+            String message = (String) e.getMessage();
+            String cmd = message;
+            if (message.contains(" ")) {
+                String[] split = message.split(" ");
+                cmd = split[0];
+                Integer desiredItem = Integer.parseInt(split[1]);
+                if (cmd.equalsIgnoreCase("buy")) {
+                    merchantManager.purchaseItem(merchant, desiredItem, playerByUsername);
+                }
+            } else if (cmd.equalsIgnoreCase("done")) {
+                gameManager.getChannelUtils().write(playerByUsername.getPlayerId(), "Thanks, COME AGAIN." + "\r\n"+ "\r\n"+ "\r\n", true);
+                e.getChannel().getPipeline().addLast(UUID.randomUUID().toString(), creeperSession.getGrabMerchant().get().getValue());
+                return;
+            }
+            gameManager.getChannelUtils().write(playerByUsername.getPlayerId(), merchant.getMenu() + "\r\n");
+            gameManager.getChannelUtils().write(playerByUsername.getPlayerId(), "\r\n[" + merchant.getName() + " (done to exit, buy <itemNo>)] ");
+        } finally {
+            e.getChannel().getPipeline().remove(ctx.getHandler());
+            super.messageReceived(ctx, e);
+        }
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/merchant/MerchantItemForSale.java b/src/main/java/com/comandante/creeper/merchant/MerchantItemForSale.java
new file mode 100644
index 00000000..73880ba7
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/merchant/MerchantItemForSale.java
@@ -0,0 +1,27 @@
+package com.comandante.creeper.merchant;
+
+import com.comandante.creeper.Items.Item;
+import com.comandante.creeper.Items.ItemType;
+import com.comandante.creeper.managers.GameManager;
+
+import java.util.Map;
+import java.util.Set;
+
+
+public class MerchantItemForSale {
+    private final ItemType itemType;
+    private final int cost;
+
+    public MerchantItemForSale(ItemType itemType, int cost) {
+        this.itemType = itemType;
+        this.cost = cost;
+    }
+
+    public ItemType getItem() {
+        return itemType;
+    }
+
+    public int getCost() {
+        return cost;
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/merchant/MerchantManager.java b/src/main/java/com/comandante/creeper/merchant/MerchantManager.java
new file mode 100644
index 00000000..47e54e1f
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/merchant/MerchantManager.java
@@ -0,0 +1,39 @@
+package com.comandante.creeper.merchant;
+
+
+import com.comandante.creeper.Items.Item;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.player.Player;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.UUID;
+
+public class MerchantManager {
+
+    private final GameManager gameManager;
+
+    public MerchantManager(GameManager gameManager) {
+        this.gameManager = gameManager;
+    }
+
+    public void purchaseItem(Merchant merchant, int itemNo, Player player) {
+        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 price = next.getValue().getCost();
+                int availableGold = gameManager.getPlayerManager().getPlayerMetadata(player.getPlayerId()).getGold();
+                if (availableGold >= price) {
+                    Item item = next.getValue().getItem().create();
+                    gameManager.getEntityManager().addItem(item);
+                    gameManager.acquireItem(player, item.getItemId());
+                    gameManager.getPlayerManager().incrementGold(player.getPlayerId(), -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");
+                }
+            }
+        }
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/npc/DeathGriffin.java b/src/main/java/com/comandante/creeper/npc/DeathGriffin.java
new file mode 100644
index 00000000..c01b96df
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/npc/DeathGriffin.java
@@ -0,0 +1,35 @@
+package com.comandante.creeper.npc;
+
+
+import com.comandante.creeper.Items.Loot;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.world.Area;
+import com.google.common.base.Optional;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.comandante.creeper.server.Color.BOLD_ON;
+import static com.comandante.creeper.server.Color.RESET;
+
+public class DeathGriffin extends Npc {
+    private final static long phraseIntervalMs = 300000;
+    private final static String NAME = "death griffin";
+    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"d", "death", "griffin","g", NAME}
+    ));
+
+    private final static String colorName = "death" + BOLD_ON + Color.MAGENTA + " griffin"  + Color.RESET ;
+    private final static String dieMessage = "a " + colorName + " breathes his last breath in a pool of " + BOLD_ON + Color.RED + "blood" + RESET + ".";
+
+    public DeathGriffin(GameManager gameManager, Loot loot) {
+        super(gameManager, NAME, colorName, 0, NpcStats.DEATH_GRIFFIN.createStats(), dieMessage, Optional.<HashSet<Area>>absent(), validTriggers, loot);
+    }
+
+    @Override
+    public DeathGriffin create(GameManager gameManager, Loot loot) {
+        return new DeathGriffin(gameManager, loot);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/npc/DemonSuccubus.java b/src/main/java/com/comandante/creeper/npc/DemonSuccubus.java
new file mode 100644
index 00000000..f968040d
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/npc/DemonSuccubus.java
@@ -0,0 +1,35 @@
+package com.comandante.creeper.npc;
+
+
+import com.comandante.creeper.Items.Loot;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.world.Area;
+import com.google.common.base.Optional;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.comandante.creeper.server.Color.BOLD_ON;
+import static com.comandante.creeper.server.Color.RESET;
+
+public class DemonSuccubus extends Npc {
+    private final static long phraseIntervalMs = 300000;
+    private final static String NAME = "demon succubus";
+    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"d", "demon", "succubus","s", NAME}
+    ));
+
+    private final static String colorName = "demon" + BOLD_ON + Color.MAGENTA + " succubus"  + Color.RESET ;
+    private final static String dieMessage = "a " + colorName + " breathes his last breath in a pool of " + BOLD_ON + Color.RED + "blood" + RESET + ".";
+
+    public DemonSuccubus(GameManager gameManager, Loot loot) {
+        super(gameManager, NAME, colorName, 0, NpcStats.DEMON_SUCCUBUS.createStats(), dieMessage, Optional.<HashSet<Area>>absent(), validTriggers, loot);
+    }
+
+    @Override
+    public DemonSuccubus create(GameManager gameManager, Loot loot) {
+        return new DemonSuccubus(gameManager, loot);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/npc/NightmareTroll.java b/src/main/java/com/comandante/creeper/npc/NightmareTroll.java
new file mode 100644
index 00000000..89bde58d
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/npc/NightmareTroll.java
@@ -0,0 +1,35 @@
+package com.comandante.creeper.npc;
+
+
+import com.comandante.creeper.Items.Loot;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.world.Area;
+import com.google.common.base.Optional;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.comandante.creeper.server.Color.BOLD_ON;
+import static com.comandante.creeper.server.Color.RESET;
+
+public class NightmareTroll extends Npc {
+    private final static long phraseIntervalMs = 300000;
+    private final static String NAME = "nightmare troll";
+    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"n", "nightmare", "troll","t", NAME}
+    ));
+
+    private final static String colorName = "nightmare" + BOLD_ON + Color.MAGENTA + " troll"  + Color.RESET ;
+    private final static String dieMessage = "a " + colorName + " breathes his last breath in a pool of " + BOLD_ON + Color.RED + "blood" + RESET + ".";
+
+    public NightmareTroll(GameManager gameManager, Loot loot) {
+        super(gameManager, NAME, colorName, 0, NpcStats.NIGHTMARE_TROLL.createStats(), dieMessage, Optional.<HashSet<Area>>absent(), validTriggers, loot);
+    }
+
+    @Override
+    public NightmareTroll create(GameManager gameManager, Loot loot) {
+        return new NightmareTroll(gameManager, loot);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/npc/NpcStats.java b/src/main/java/com/comandante/creeper/npc/NpcStats.java
index 2ad1673a..f92aeca4 100644
--- a/src/main/java/com/comandante/creeper/npc/NpcStats.java
+++ b/src/main/java/com/comandante/creeper/npc/NpcStats.java
@@ -136,5 +136,116 @@ public class NpcStats {
             .setNumberweaponOfRolls(1)
             .setExperience(510);
 
+    public final static StatsBuilder DEATH_GRIFFIN = new StatsBuilder()
+            .setStrength(55)
+            .setWillpower(30)
+            .setAim(24)
+            .setAgile(24)
+            .setArmorRating(20)
+            .setMeleSkill(19)
+            .setCurrentHealth(1000)
+            .setMaxHealth(1000)
+            .setWeaponRatingMin(20)
+            .setWeaponRatingMax(65)
+            .setNumberweaponOfRolls(1)
+            .setExperience(2100);
+
+    public final static StatsBuilder DEMON_SUCCUBUS = new StatsBuilder()
+            .setStrength(70)
+            .setWillpower(35)
+            .setAim(14)
+            .setAgile(14)
+            .setArmorRating(25)
+            .setMeleSkill(19)
+            .setCurrentHealth(1200)
+            .setMaxHealth(1200)
+            .setWeaponRatingMin(35)
+            .setWeaponRatingMax(60)
+            .setNumberweaponOfRolls(1)
+            .setExperience(2600);
+
+    public final static StatsBuilder TIGER_MONOCERUS = new StatsBuilder()
+            .setStrength(28)
+            .setWillpower(10)
+            .setAim(5)
+            .setAgile(9)
+            .setArmorRating(12)
+            .setMeleSkill(19)
+            .setCurrentHealth(600)
+            .setMaxHealth(600)
+            .setWeaponRatingMin(20)
+            .setWeaponRatingMax(36)
+            .setNumberweaponOfRolls(1)
+            .setExperience(800);
+
+    public final static StatsBuilder NIGHTMARE_TROLL = new StatsBuilder()
+            .setStrength(34)
+            .setWillpower(7)
+            .setAim(6)
+            .setAgile(6)
+            .setArmorRating(18)
+            .setMeleSkill(8)
+            .setCurrentHealth(550)
+            .setMaxHealth(550)
+            .setWeaponRatingMin(5)
+            .setWeaponRatingMax(32)
+            .setNumberweaponOfRolls(1)
+            .setExperience(720);
+
+    public final static StatsBuilder RAZORCLAW_WOLF = new StatsBuilder()
+            .setStrength(25)
+            .setWillpower(10)
+            .setAim(5)
+            .setAgile(9)
+            .setArmorRating(8)
+            .setMeleSkill(12)
+            .setCurrentHealth(500)
+            .setMaxHealth(500)
+            .setWeaponRatingMin(10)
+            .setWeaponRatingMax(27)
+            .setNumberweaponOfRolls(1)
+            .setExperience(600);
+
+    public final static StatsBuilder PHANTOM_WIZARD = new StatsBuilder()
+            .setStrength(16)
+            .setWillpower(9)
+            .setAim(4)
+            .setAgile(5)
+            .setArmorRating(9)
+            .setMeleSkill(8)
+            .setCurrentHealth(400)
+            .setMaxHealth(400)
+            .setWeaponRatingMin(12)
+            .setWeaponRatingMax(25)
+            .setNumberweaponOfRolls(1)
+            .setExperience(510);
+
+    public final static StatsBuilder PHANTOM_KNIGHT = new StatsBuilder()
+            .setStrength(28)
+            .setWillpower(5)
+            .setAim(5)
+            .setAgile(6)
+            .setArmorRating(14)
+            .setMeleSkill(8)
+            .setCurrentHealth(500)
+            .setMaxHealth(500)
+            .setWeaponRatingMin(10)
+            .setWeaponRatingMax(20)
+            .setNumberweaponOfRolls(1)
+            .setExperience(600);
+
+    public final static StatsBuilder PHANTOM_ORC = new StatsBuilder()
+            .setStrength(23)
+            .setWillpower(4)
+            .setAim(5)
+            .setAgile(6)
+            .setArmorRating(11)
+            .setMeleSkill(8)
+            .setCurrentHealth(500)
+            .setMaxHealth(500)
+            .setWeaponRatingMin(10)
+            .setWeaponRatingMax(20)
+            .setNumberweaponOfRolls(1)
+            .setExperience(510);
 
 }
diff --git a/src/main/java/com/comandante/creeper/npc/PhantomKnight.java b/src/main/java/com/comandante/creeper/npc/PhantomKnight.java
new file mode 100644
index 00000000..e5746138
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/npc/PhantomKnight.java
@@ -0,0 +1,35 @@
+package com.comandante.creeper.npc;
+
+
+import com.comandante.creeper.Items.Loot;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.world.Area;
+import com.google.common.base.Optional;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.comandante.creeper.server.Color.BOLD_ON;
+import static com.comandante.creeper.server.Color.RESET;
+
+public class PhantomKnight extends Npc {
+    private final static long phraseIntervalMs = 300000;
+    private final static String NAME = "phantom knight";
+    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"p", "phantom", "knight","k", NAME}
+    ));
+
+    private final static String colorName = "phantom" + BOLD_ON + Color.MAGENTA + " knight"  + Color.RESET ;
+    private final static String dieMessage = "a " + colorName + " breathes his last breath in a pool of " + BOLD_ON + Color.RED + "blood" + RESET + ".";
+
+    public PhantomKnight(GameManager gameManager, Loot loot) {
+        super(gameManager, NAME, colorName, 0, NpcStats.PHANTOM_KNIGHT.createStats(), dieMessage, Optional.<HashSet<Area>>absent(), validTriggers, loot);
+    }
+
+    @Override
+    public PhantomKnight create(GameManager gameManager, Loot loot) {
+        return new PhantomKnight(gameManager, loot);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/npc/PhantomOrc.java b/src/main/java/com/comandante/creeper/npc/PhantomOrc.java
new file mode 100644
index 00000000..73b0c6fc
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/npc/PhantomOrc.java
@@ -0,0 +1,35 @@
+package com.comandante.creeper.npc;
+
+
+import com.comandante.creeper.Items.Loot;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.world.Area;
+import com.google.common.base.Optional;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.comandante.creeper.server.Color.BOLD_ON;
+import static com.comandante.creeper.server.Color.RESET;
+
+public class PhantomOrc extends Npc {
+    private final static long phraseIntervalMs = 300000;
+    private final static String NAME = "phantom orc";
+    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"p", "phantom", "orc","o", NAME}
+    ));
+
+    private final static String colorName = "phantom" + BOLD_ON + Color.MAGENTA + " orc"  + Color.RESET ;
+    private final static String dieMessage = "a " + colorName + " breathes his last breath in a pool of " + BOLD_ON + Color.RED + "blood" + RESET + ".";
+
+    public PhantomOrc(GameManager gameManager, Loot loot) {
+        super(gameManager, NAME, colorName, 0, NpcStats.PHANTOM_ORC.createStats(), dieMessage, Optional.<HashSet<Area>>absent(), validTriggers, loot);
+    }
+
+    @Override
+    public PhantomOrc create(GameManager gameManager, Loot loot) {
+        return new PhantomOrc(gameManager, loot);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/npc/PhantomWizard.java b/src/main/java/com/comandante/creeper/npc/PhantomWizard.java
new file mode 100644
index 00000000..a733f635
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/npc/PhantomWizard.java
@@ -0,0 +1,35 @@
+package com.comandante.creeper.npc;
+
+
+import com.comandante.creeper.Items.Loot;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.world.Area;
+import com.google.common.base.Optional;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.comandante.creeper.server.Color.BOLD_ON;
+import static com.comandante.creeper.server.Color.RESET;
+
+public class PhantomWizard extends Npc {
+    private final static long phraseIntervalMs = 300000;
+    private final static String NAME = "phantom wizard";
+    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"p", "phantom", "wizard","w", NAME}
+    ));
+
+    private final static String colorName = "phantom" + BOLD_ON + Color.MAGENTA + " wizard"  + Color.RESET ;
+    private final static String dieMessage = "a " + colorName + " breathes his last breath in a pool of " + BOLD_ON + Color.RED + "blood" + RESET + ".";
+
+    public PhantomWizard(GameManager gameManager, Loot loot) {
+        super(gameManager, NAME, colorName, 0, NpcStats.PHANTOM_WIZARD.createStats(), dieMessage, Optional.<HashSet<Area>>absent(), validTriggers, loot);
+    }
+
+    @Override
+    public PhantomWizard create(GameManager gameManager, Loot loot) {
+        return new PhantomWizard(gameManager, loot);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/npc/RazorClawWolf.java b/src/main/java/com/comandante/creeper/npc/RazorClawWolf.java
new file mode 100644
index 00000000..5ccd3ce3
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/npc/RazorClawWolf.java
@@ -0,0 +1,35 @@
+package com.comandante.creeper.npc;
+
+
+import com.comandante.creeper.Items.Loot;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.world.Area;
+import com.google.common.base.Optional;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.comandante.creeper.server.Color.BOLD_ON;
+import static com.comandante.creeper.server.Color.RESET;
+
+public class RazorClawWolf extends Npc {
+    private final static long phraseIntervalMs = 300000;
+    private final static String NAME = "razor-claw wolf";
+    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"r", "razor-claw", "wolf","w", NAME}
+    ));
+
+    private final static String colorName = "razor-claw" + BOLD_ON + Color.MAGENTA + " wolf"  + Color.RESET ;
+    private final static String dieMessage = "a " + colorName + " breathes his last breath in a pool of " + BOLD_ON + Color.RED + "blood" + RESET + ".";
+
+    public RazorClawWolf(GameManager gameManager, Loot loot) {
+        super(gameManager, NAME, colorName, 0, NpcStats.RAZORCLAW_WOLF.createStats(), dieMessage, Optional.<HashSet<Area>>absent(), validTriggers, loot);
+    }
+
+    @Override
+    public RazorClawWolf create(GameManager gameManager, Loot loot) {
+        return new RazorClawWolf(gameManager, loot);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/npc/TigerMonocerus.java b/src/main/java/com/comandante/creeper/npc/TigerMonocerus.java
new file mode 100644
index 00000000..e866f6a3
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/npc/TigerMonocerus.java
@@ -0,0 +1,35 @@
+package com.comandante.creeper.npc;
+
+
+import com.comandante.creeper.Items.Loot;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.world.Area;
+import com.google.common.base.Optional;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.comandante.creeper.server.Color.BOLD_ON;
+import static com.comandante.creeper.server.Color.RESET;
+
+public class TigerMonocerus extends Npc {
+    private final static long phraseIntervalMs = 300000;
+    private final static String NAME = "tiger monocerus";
+    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
+                    {"t", "tiger", "monocerus","m", NAME}
+    ));
+
+    private final static String colorName = "tiger" + BOLD_ON + Color.MAGENTA + " monocerus"  + Color.RESET ;
+    private final static String dieMessage = "a " + colorName + " breathes his last breath in a pool of " + BOLD_ON + Color.RED + "blood" + RESET + ".";
+
+    public TigerMonocerus(GameManager gameManager, Loot loot) {
+        super(gameManager, NAME, colorName, 0, NpcStats.TIGER_MONOCERUS.createStats(), dieMessage, Optional.<HashSet<Area>>absent(), validTriggers, loot);
+    }
+
+    @Override
+    public TigerMonocerus create(GameManager gameManager, Loot loot) {
+        return new TigerMonocerus(gameManager, loot);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/server/CreeperCommandHandler.java b/src/main/java/com/comandante/creeper/server/CreeperCommandHandler.java
index 8a2a7351..e62c071c 100644
--- a/src/main/java/com/comandante/creeper/server/CreeperCommandHandler.java
+++ b/src/main/java/com/comandante/creeper/server/CreeperCommandHandler.java
@@ -1,7 +1,12 @@
 package com.comandante.creeper.server;
 
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
 import com.comandante.creeper.Main;
 import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.merchant.Merchant;
+import com.comandante.creeper.merchant.MerchantCommandHandler;
 import com.comandante.creeper.server.command.Command;
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.channel.ExceptionEvent;
@@ -11,6 +16,7 @@ import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
 public class CreeperCommandHandler extends SimpleChannelUpstreamHandler {
 
     private final GameManager gameManager;
+    private final Meter commandMeter =  Main.metrics.meter(MetricRegistry.name(CreeperCommandHandler.class, "commands"));
 
     public CreeperCommandHandler(GameManager gameManager) {
         this.gameManager = gameManager;
@@ -25,7 +31,15 @@ public class CreeperCommandHandler extends SimpleChannelUpstreamHandler {
             super.messageReceived(ctx, e);
             return;
         }
+        if (session.getGrabMerchant().isPresent()) {
+            Merchant merchant = session.getGrabMerchant().get().getKey();
+            e.getChannel().getPipeline().addLast("executed_command", new MerchantCommandHandler(gameManager, merchant));
+            super.messageReceived(ctx, e);
+            return;
+        }
         Command commandByTrigger = Main.creeperCommandRegistry.getCommandByTrigger(rootCommand);
+        Main.metrics.counter(MetricRegistry.name(CreeperCommandHandler.class, rootCommand + "-cmd")).inc();
+        commandMeter.mark();
         e.getChannel().getPipeline().addLast("executed_command", commandByTrigger);
         super.messageReceived(ctx, e);
     }
diff --git a/src/main/java/com/comandante/creeper/server/CreeperSession.java b/src/main/java/com/comandante/creeper/server/CreeperSession.java
index cfeba11e..9d026c7e 100644
--- a/src/main/java/com/comandante/creeper/server/CreeperSession.java
+++ b/src/main/java/com/comandante/creeper/server/CreeperSession.java
@@ -2,6 +2,7 @@ package com.comandante.creeper.server;
 
 import com.comandante.creeper.CreeperEntry;
 import com.comandante.creeper.fight.FightResults;
+import com.comandante.creeper.merchant.Merchant;
 import com.comandante.creeper.server.command.Command;
 import com.google.common.base.Optional;
 
@@ -19,6 +20,7 @@ public class CreeperSession {
     private Optional<Future<FightResults>> activeFight = Optional.absent();
     private AtomicBoolean isAbleToDoAbility = new AtomicBoolean(false);
     private Optional<CreeperEntry<UUID, Command>> grabMultiLineInput = Optional.absent();
+    private Optional<CreeperEntry<Merchant, Command>> grabMerchant = Optional.absent();
     private final long sessionCreationTimestamp = System.currentTimeMillis();
     private String lastMessage;
 
@@ -104,4 +106,20 @@ public class CreeperSession {
     public void setGrabMultiLineInput(Optional<CreeperEntry<UUID, Command>> grabMultiLineInput) {
         this.grabMultiLineInput = grabMultiLineInput;
     }
+
+    public AtomicBoolean getIsAbleToDoAbility() {
+        return isAbleToDoAbility;
+    }
+
+    public void setIsAbleToDoAbility(AtomicBoolean isAbleToDoAbility) {
+        this.isAbleToDoAbility = isAbleToDoAbility;
+    }
+
+    public Optional<CreeperEntry<Merchant, Command>> getGrabMerchant() {
+        return grabMerchant;
+    }
+
+    public void setGrabMerchant(Optional<CreeperEntry<Merchant, Command>> grabMerchant) {
+        this.grabMerchant = grabMerchant;
+    }
 }
diff --git a/src/main/java/com/comandante/creeper/server/command/Command.java b/src/main/java/com/comandante/creeper/server/command/Command.java
index 9d1d23e1..09d7f5ab 100644
--- a/src/main/java/com/comandante/creeper/server/command/Command.java
+++ b/src/main/java/com/comandante/creeper/server/command/Command.java
@@ -77,7 +77,7 @@ public abstract class Command extends SimpleChannelUpstreamHandler {
         this.player = playerManager.getPlayer(extractPlayerId(creeperSession));
         this.playerId = player.getPlayerId();
         this.currentRoom = gameManager.getRoomManager().getPlayerCurrentRoom(player).get();
-        this.mapMatrix  = mapsManager.getFloorMatrixMaps().get(currentRoom.getFloorId());
+        this.mapMatrix = mapsManager.getFloorMatrixMaps().get(currentRoom.getFloorId());
         this.currentRoomCoords = mapMatrix.getCoords(currentRoom.getRoomId());
         this.originalMessageParts = getOriginalMessageParts(e);
         this.playerMetadata = gameManager.getPlayerManager().getPlayerMetadata(playerId);
@@ -85,11 +85,18 @@ public abstract class Command extends SimpleChannelUpstreamHandler {
 
     @Override
     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
-        e.getChannel().getPipeline().remove(ctx.getHandler());
-        String playerId = extractPlayerId(extractCreeperSession(e.getChannel()));
-        String prompt = gameManager.getPlayerManager().buildPrompt(playerId);
-        gameManager.getChannelUtils().write(playerId, prompt, true);
-        super.messageReceived(ctx, e);
+        try {
+            CreeperSession creeperSession = extractCreeperSession(e.getChannel());
+            e.getChannel().getPipeline().remove(ctx.getHandler());
+            if (creeperSession.getGrabMerchant().isPresent()) {
+                return;
+            }
+            String playerId = extractPlayerId(creeperSession);
+            String prompt = gameManager.getPlayerManager().buildPrompt(playerId);
+            gameManager.getChannelUtils().write(playerId, prompt, true);
+        } finally {
+            super.messageReceived(ctx, e);
+        }
     }
 
     public CreeperSession extractCreeperSession(Channel channel) {
@@ -101,7 +108,7 @@ public abstract class Command extends SimpleChannelUpstreamHandler {
         return Main.createPlayerId(creeperSession.getUsername().get());
     }
 
-    public String getRootCommand(MessageEvent e){
+    public String getRootCommand(MessageEvent e) {
         String origMessage = (String) e.getMessage();
         return origMessage.split(" ")[0].toLowerCase();
     }
@@ -123,7 +130,7 @@ public abstract class Command extends SimpleChannelUpstreamHandler {
         channelUtils.writeToRoom(playerId, msg);
     }
 
-    public void currentRoomLogic(){
+    public void currentRoomLogic() {
         gameManager.currentRoomLogic(playerId);
     }
 
@@ -134,4 +141,8 @@ public abstract class Command extends SimpleChannelUpstreamHandler {
     public String getPrompt() {
         return playerManager.buildPrompt(playerId);
     }
+
+    public String getDescription() {
+        return description;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/server/command/TalkCommand.java b/src/main/java/com/comandante/creeper/server/command/TalkCommand.java
new file mode 100644
index 00000000..f698e8c1
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/server/command/TalkCommand.java
@@ -0,0 +1,54 @@
+package com.comandante.creeper.server.command;
+
+
+import com.comandante.creeper.CreeperEntry;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.merchant.Merchant;
+import com.comandante.creeper.player.Player;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.MessageEvent;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import static com.comandante.creeper.server.Color.RESET;
+import static com.comandante.creeper.server.Color.YELLOW;
+
+public class TalkCommand extends Command {
+
+    final static List<String> validTriggers = Arrays.asList("talk");
+    final static String description = "Talk to a merchant.";
+
+    public TalkCommand(GameManager gameManager) {
+        super(gameManager, validTriggers, description);
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        configure(e);
+        try {
+            if (creeperSession.getGrabMerchant().isPresent()) {
+                creeperSession.setGrabMerchant(Optional.<CreeperEntry<Merchant, Command>>absent());
+                return;
+            }
+            originalMessageParts.remove(0);
+            String desiredMerchantTalk = Joiner.on(" ").join(originalMessageParts);
+            Set<Merchant> merchants = currentRoom.getMerchants();
+            for (Merchant merchant: merchants) {
+                if (merchant.getValidTriggers().contains(desiredMerchantTalk)) {
+                    write(merchant.getWelcomeMessage() + "\r\n");
+                    write(merchant.getMenu() + "\r\n");
+                    gameManager.getChannelUtils().write(playerId, "\r\n[" + merchant.getName() + " (done to exit, buy <itemNo>)] ");
+                    creeperSession.setGrabMerchant(Optional.of(
+                            new CreeperEntry<Merchant, Command>(merchant, this)));
+                }
+            }
+        } finally {
+            super.messageReceived(ctx, e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/server/command/WhoCommand.java b/src/main/java/com/comandante/creeper/server/command/WhoCommand.java
index 490f728d..a3c5f32c 100644
--- a/src/main/java/com/comandante/creeper/server/command/WhoCommand.java
+++ b/src/main/java/com/comandante/creeper/server/command/WhoCommand.java
@@ -28,7 +28,6 @@ public class WhoCommand extends Command {
         try {
             Table t = new Table(3, BorderStyle.CLASSIC_COMPATIBLE,
                     ShownBorders.HEADER_AND_FIRST_COLLUMN);
-
             t.setColumnWidth(0, 8, 14);
             t.setColumnWidth(1, 14, 16);
             t.setColumnWidth(2, 26, 26);
diff --git a/src/main/java/com/comandante/creeper/spawner/ItemSpawner.java b/src/main/java/com/comandante/creeper/spawner/ItemSpawner.java
index 78150bf5..0d7a9c2e 100644
--- a/src/main/java/com/comandante/creeper/spawner/ItemSpawner.java
+++ b/src/main/java/com/comandante/creeper/spawner/ItemSpawner.java
@@ -1,7 +1,9 @@
 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.entity.CreeperEntity;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.world.Area;
@@ -58,6 +60,7 @@ public class ItemSpawner extends CreeperEntity {
         Item item = spawnItemType.create();
         gameManager.getEntityManager().addItem(item);
         gameManager.placeItemInRoom(room.getRoomId(), item.getItemId());
+        Main.metrics.counter(MetricRegistry.name(ItemSpawner.class, item.getItemName()  + "-spawn")).inc();
     }
 
     private int counterNumberInArea() {
diff --git a/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java b/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java
index cf9b4d20..eb555787 100644
--- a/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java
+++ b/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java
@@ -1,6 +1,8 @@
 package com.comandante.creeper.spawner;
 
 
+import com.codahale.metrics.MetricRegistry;
+import com.comandante.creeper.Main;
 import com.comandante.creeper.entity.CreeperEntity;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.npc.Npc;
@@ -75,6 +77,7 @@ public class NpcSpawner extends CreeperEntity {
         Npc newNpc = npc.create(gameManager, npc.getLoot());
         gameManager.getEntityManager().addEntity(newNpc);
         room.addPresentNpc(newNpc.getEntityId());
+        Main.metrics.counter(MetricRegistry.name(NpcSpawner.class, npc.getName() + "-spawn")).inc();
     }
 
     private Predicate<Room> getRoomsWithRoom() {
diff --git a/src/main/java/com/comandante/creeper/world/Room.java b/src/main/java/com/comandante/creeper/world/Room.java
index 87ce45cb..816f678c 100644
--- a/src/main/java/com/comandante/creeper/world/Room.java
+++ b/src/main/java/com/comandante/creeper/world/Room.java
@@ -1,6 +1,7 @@
 package com.comandante.creeper.world;
 
 import com.comandante.creeper.entity.CreeperEntity;
+import com.comandante.creeper.merchant.Merchant;
 import com.comandante.creeper.spawner.ItemSpawner;
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
@@ -40,6 +41,7 @@ public abstract class Room extends CreeperEntity {
     private Set<Area> areas = Sets.newConcurrentHashSet();
     private Optional<String> mapData = Optional.absent();
     private final Set<String> roomTags;
+    private final Set<Merchant> merchants = Sets.newConcurrentHashSet();
 
     public Room(Integer roomId,
                 String roomTitle,
@@ -68,6 +70,22 @@ public abstract class Room extends CreeperEntity {
         this.enterExits = enterExits;
     }
 
+    public List<ItemSpawner> getItemSpawners() {
+        return itemSpawners;
+    }
+
+    public void setItemSpawners(List<ItemSpawner> itemSpawners) {
+        this.itemSpawners = itemSpawners;
+    }
+
+    public Set<Merchant> getMerchants() {
+        return merchants;
+    }
+
+    public void addMerchant(Merchant merchant) {
+        merchants.add(merchant);
+    }
+
     public Set<String> getRoomTags() {
         return roomTags;
     }
diff --git a/src/main/java/com/comandante/creeper/world/RoomManager.java b/src/main/java/com/comandante/creeper/world/RoomManager.java
index 4acdc970..fa7f3f1e 100644
--- a/src/main/java/com/comandante/creeper/world/RoomManager.java
+++ b/src/main/java/com/comandante/creeper/world/RoomManager.java
@@ -1,5 +1,6 @@
 package com.comandante.creeper.world;
 
+import com.comandante.creeper.merchant.Merchant;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.player.Player;
 import com.google.common.base.Optional;
@@ -41,6 +42,10 @@ public class RoomManager {
         }
     }
 
+    public void addMerchant(Integer roomId, Merchant merchant) {
+        getRoom(roomId).addMerchant(merchant);
+    }
+
     public void tagRoom(Integer roomId, String tag) {
         getRoom(roomId).addTag(tag);
     }
diff --git a/src/main/java/com/comandante/creeper/world/WorldExporter.java b/src/main/java/com/comandante/creeper/world/WorldExporter.java
index e8be11cb..dd5ed253 100644
--- a/src/main/java/com/comandante/creeper/world/WorldExporter.java
+++ b/src/main/java/com/comandante/creeper/world/WorldExporter.java
@@ -110,6 +110,7 @@ public class WorldExporter {
                         Map.Entry<String, String> next = iterator.next();
                         RemoteExit remoteExit = new RemoteExit(RemoteExit.Direction.ENTER, Integer.parseInt(next.getKey()), next.getValue());
                         basicRoomBuilder.addEnterExit(remoteExit);
+                        mapMatrix.addRemote(roomModel.getRoomId(), remoteExit);
                     }
                 }
                 configureExits(basicRoomBuilder, mapMatrix, roomModel.getRoomId());
diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties
new file mode 100644
index 00000000..40b54e0b
--- /dev/null
+++ b/src/main/resources/log4j.properties
@@ -0,0 +1,22 @@
+log4j.rootLogger=DEBUG, stdout, stderr
+
+# configure stdout
+# set the conversion pattern of stdout
+# Print the date in ISO 8601 format
+log4j.appender.stdout = org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Threshold = INFO
+log4j.appender.stdout.Target   = System.out
+log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern = %-5p %d [%t][%F:%L] : %m%n
+log4j.appender.stdout.filter.filter1=org.apache.log4j.varia.LevelRangeFilter
+log4j.appender.stdout.filter.filter1.levelMin=TRACE
+log4j.appender.stdout.filter.filter1.levelMax=INFO
+
+# configure stderr
+# set the conversion pattern of stdout
+# Print the date in ISO 8601 format
+log4j.appender.stderr = org.apache.log4j.ConsoleAppender
+log4j.appender.stderr.Threshold = WARN
+log4j.appender.stderr.Target   = System.err
+log4j.appender.stderr.layout = org.apache.log4j.PatternLayout
+log4j.appender.stderr.layout.ConversionPattern = %-5p %d [%t][%F:%L] : %m%n
\ No newline at end of file
-- 
GitLab