diff --git a/Gemfile.lock b/Gemfile.lock
index 267bd723462d258f015e5be041b0b15637b5ef49..eb65157c8cf59d13b93e5ad75a84c6b46cc95e0d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -19,6 +19,7 @@ GEM
       ffi (~> 1.9)
       rspec-expectations (>= 2.99)
       thor (>= 0.19, < 2.0)
+    ast (2.4.0)
     backports (3.17.1)
     builder (3.2.4)
     childprocess (3.0.0)
@@ -44,20 +45,36 @@ GEM
     eventmachine (1.2.7)
     ffi (1.12.2)
     gherkin (5.1.0)
+    jaro_winkler (1.5.4)
     json (1.8.6)
     methadone (1.9.5)
       bundler
     multi_json (1.14.1)
     multi_test (0.1.2)
     ncursesw (1.4.10)
+    parallel (1.19.1)
+    parser (2.7.1.1)
+      ast (~> 2.4.0)
+    rainbow (3.0.0)
     rake (11.3.0)
     rdoc (4.3.0)
     require_all (2.0.0)
+    rexml (3.2.4)
     rspec-expectations (3.9.1)
       diff-lcs (>= 1.2.0, < 2.0)
       rspec-support (~> 3.9.0)
     rspec-support (3.9.2)
+    rubocop (0.82.0)
+      jaro_winkler (~> 1.5.1)
+      parallel (~> 1.10)
+      parser (>= 2.7.0.1)
+      rainbow (>= 2.2.2, < 4.0)
+      rexml
+      ruby-progressbar (~> 1.7)
+      unicode-display_width (>= 1.4.0, < 2.0)
+    ruby-progressbar (1.10.1)
     thor (1.0.1)
+    unicode-display_width (1.7.0)
     wisper (2.0.1)
 
 PLATFORMS
@@ -70,6 +87,7 @@ DEPENDENCIES
   json (~> 1.8)
   rake (~> 11.3)
   rdoc (~> 4.2)
+  rubocop (~> 0.82)
 
 BUNDLED WITH
    2.1.4
diff --git a/aethyr.gemspec b/aethyr.gemspec
index 2deda025e326729156d3284e99e02960a641f60e..7dcbf938e94edb111acc90199bfe47a21aa509b6 100644
--- a/aethyr.gemspec
+++ b/aethyr.gemspec
@@ -40,4 +40,5 @@ Gem::Specification.new do |spec|
   spec.add_development_dependency 'rake', '~> 11.3'
   spec.add_development_dependency 'rdoc', '~> 4.2'
   spec.add_development_dependency 'aruba', '~> 0.14'
+  spec.add_development_dependency 'rubocop', '~> 0.82'
 end
diff --git a/lib/aethyr/core/connection/telnet.rb b/lib/aethyr/core/connection/telnet.rb
index 3000919204a2191abc06ca39b8760b5c2c665eaa..71a8af2ae800f08da943787a234a0d126abeffe6 100644
--- a/lib/aethyr/core/connection/telnet.rb
+++ b/lib/aethyr/core/connection/telnet.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'socket'
 require 'aethyr/core/connection/telnet_codes'
 
@@ -7,7 +9,7 @@ class TelnetScanner
               IAC + WILL + OPT_ECHO,
               IAC + WILL + OPT_MSSP,
               IAC + WONT + OPT_COMPRESS2,
-              IAC + DO + OPT_NAWS]
+              IAC + DO + OPT_NAWS].freeze
 
   def initialize(socket, display)
     @socket = socket
@@ -26,196 +28,223 @@ class TelnetScanner
   def supports_naws(does_it)
     if does_it
       @supports_naws = true
-      log "Client supports NAWS"
+      log 'Client supports NAWS'
     else
       @supports_naws = false
-      log "Client does NOT support NAWS"
+      log 'Client does NOT support NAWS'
     end
   end
 
   def send_mssp
-    log "sending mssp"
+    log 'sending mssp'
     mssp_options = nil
     options = IAC + SB + OPT_MSSP
 
-    if File.exist? "conf/mssp.yaml"
-      File.open "conf/mssp.yaml" do |f|
-        mssp_options = YAML.load(f)
+    if File.exist? 'conf/mssp.yaml'
+      File.open 'conf/mssp.yaml' do |f|
+        mssp_options = YAML.safe_load(f)
       end
 
-      mssp_options.each do |k,v|
+      mssp_options.each do |k, v|
         options << (MSSP_VAR + k + MSSP_VAL + v.to_s)
       end
     end
 
-    options << (MSSP_VAR + "PLAYERS" + MSSP_VAL + $manager.find_all("class", Player).length.to_s)
-    options << (MSSP_VAR + "UPTIME" + MSSP_VAL + $manager.uptime.to_s)
-    options << (MSSP_VAR + "ROOMS" + MSSP_VAL + $manager.find_all("class", Room).length.to_s)
-    options << (MSSP_VAR + "AREAS" + MSSP_VAL + $manager.find_all("class", Area).length.to_s)
-    options << (MSSP_VAR + "ANSI" + MSSP_VAL + "1")
-    options << (MSSP_VAR + "FAMILY" + MSSP_VAL + "CUSTOM")
-    options << (MSSP_VAR + "CODEBASE" + MSSP_VAL + "Aethyr " + $AETHYR_VERSION)
-    options << (MSSP_VAR + "PORT" + MSSP_VAL + ServerConfig.port.to_s)
-    options << (MSSP_VAR + "MCCP" + MSSP_VAL + (ServerConfig[:mccp] ? "1" : "0"))
+    options << (MSSP_VAR + 'PLAYERS' + MSSP_VAL + $manager.find_all('class', Player).length.to_s)
+    options << (MSSP_VAR + 'UPTIME' + MSSP_VAL + $manager.uptime.to_s)
+    options << (MSSP_VAR + 'ROOMS' + MSSP_VAL + $manager.find_all('class', Room).length.to_s)
+    options << (MSSP_VAR + 'AREAS' + MSSP_VAL + $manager.find_all('class', Area).length.to_s)
+    options << (MSSP_VAR + 'ANSI' + MSSP_VAL + '1')
+    options << (MSSP_VAR + 'FAMILY' + MSSP_VAL + 'CUSTOM')
+    options << (MSSP_VAR + 'CODEBASE' + MSSP_VAL + 'Aethyr ' + $AETHYR_VERSION)
+    options << (MSSP_VAR + 'PORT' + MSSP_VAL + ServerConfig.port.to_s)
+    options << (MSSP_VAR + 'MCCP' + MSSP_VAL + (ServerConfig[:mccp] ? '1' : '0'))
     options << (IAC + SE)
     @display.send_raw options
   end
 
   def process_iac
-    log "doing process_iac"
-
-    iac_state = :none if iac_state.nil?
-    while ch = @socket.recv(1, Socket::MSG_PEEK) do
-      ch = ch.chr
-      log "processing #{ch.ord}"
-      if iac_state == :none && ch == IAC
-        @socket.recv(1)
-        iac_state = :IAC
-        next
-      elsif iac_state == :none
+    log 'doing process_iac'
+
+    @iac_state = :none if @iac_state.nil?
+    puts 'start'
+    ch = nil?
+    begin
+      ch = @socket.recv_nonblock(1, Socket::MSG_PEEK)
+    rescue Errno::EWOULDBLOCK
+      return false
+    end
+    return false if ch.nil?
+
+    puts 'stop'
+    ch = ch.chr
+    log "processing #{ch.ord}"
+    if @iac_state == :none && ch == IAC
+      @socket.recv(1)
+      @iac_state = :IAC
+      return false
+    elsif @iac_state == :none
+      return true
+    else
+      @socket.recv(1) if @iac_state != IAC || ch != IAC
+
+      case @iac_state
+      when :IAC
+        if ch == WILL
+          @iac_state = :IAC_WILL
+        elsif ch == SB
+          @iac_state = :IAC_SB
+        elsif ch == WONT
+          @iac_state = :IAC_WONT
+        elsif ch == DONT
+          @iac_state = :IAC_DONT
+        elsif ch == DO
+          @iac_state = :IAC_DO
+        elsif ch == IAC
+          @iac_state = :none
           return true
-      elsif iac_state != :none
-        @socket.recv(1) if iac_state != IAC || ch != IAC
-        case iac_state
-
-        when :IAC
-          if ch == WILL
-            iac_state = :IAC_WILL
-          elsif ch == SB
-            iac_state = :IAC_SB
-          elsif ch == WONT
-            iac_state = :IAC_WONT
-          elsif ch == DONT
-            iac_state = :IAC_DONT
-          elsif ch == DO
-            iac_state = :IAC_DO
-          elsif ch == IAC
-            iac_state = :none
-            return true
-          else
-            iac_state = :none
-          end
-
-        when :IAC_WILL
-          if OPT_BINARY == ch
-            @socket.puts(IAC + DO + OPT_BINARY)
-          elsif ch == OPT_NAWS
-            supports_naws(true)
-          elsif ch == OPT_LINEMODE
-            @linemode_supported = true
-          elsif OPT_ECHO == ch
-            @socket.puts(IAC + DONT + OPT_ECHO)
-          elsif OPT_SGA  == ch
-            @socket.puts(IAC + DO + OPT_SGA)
-          else
-            @socket.puts(IAC + DONT + ch)
-          end
-          iac_state = :none
-
-        when :IAC_WONT
-          if ch == OPT_LINEMODE
-            @linemode_supported = false
-          elsif ch == OPT_NAWS
-            supports_naws(false)
-          else
-            @socket.puts(IAC + DONT + ch)
-          end
-          iac_state = :none
-
-        when :IAC_DO
-          if ch == OPT_BINARY
-            @socket.puts(IAC + WILL + OPT_BINARY)
-          elsif ch == OPT_ECHO
-            @echo_supported = true
-          elsif ch == OPT_MSSP
-            send_mssp
-            @mssp_supported = true
-          else
-            @socket.puts(IAC + WONT + ch)
-          end
-          iac_state = :none
-
-        when :IAC_DONT
-          if ch == OPT_ECHO
-            @echo_supported = false
-          elsif ch == OPT_COMPRESS2
-            #do nothing
-          elsif ch == OPT_MSSP
-            @mssp_supported = false
-          else
-            @socket.puts(IAC + WONT + ch)
-          end
-          iac_state = :none
-
-        when :IAC_SB
-          if ch == OPT_NAWS
-            iac_state = :IAC_SB_NAWS
-          else
-            iac_state = :IAC_SB_SOMETHING
-          end
-
-        when :IAC_SB_NAWS
-          lwidth = ch.ord
-          iac_state = :IAC_SB_NAWS_LWIDTH
-          if ch == IAC && @socket.getch != IAC
-            log "escaped IAC expected but not found"
-            break
-          end
-
-        when :IAC_SB_NAWS_LWIDTH
-          hwidth = ch.ord
-          iac_state = :IAC_SB_NAWS_LWIDTH_HWIDTH
-          if ch == IAC && @socket.getch != IAC
-            log "escaped IAC expected but not found"
-            break
-          end
-
-        when :IAC_SB_NAWS_LWIDTH_HWIDTH
-          lheight = ch.ord
-          iac_state = :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT
-          if ch == IAC && @socket.getch != IAC
-            log "escaped IAC expected but not found"
-            break
-          end
-
-        when :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT
-          hheight = ch.ord
-          iac_state = :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_HHEIGHT
-          if ch == IAC && @socket.getch != IAC
-            log "escaped IAC expected but not found"
-            break
-          end
-
-        when :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_HHEIGHT
-          if ch == IAC
-            iac_state = :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_HHEIGHT_IAC
-          else
-            log "invalid IAC"
-            iac_state = :none
-          end
-
-        when :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_HHEIGHT_IAC
-          if ch == SE
-            new_width = lwidth*256 + hwidth
-            new_height = lheight*256 + hheight
-            log "setting resolution #{new_width} #{new_height}"
-            @display.resolution = [new_width, new_height]
-          else
-            log "invalid IAC"
-          end
-          iac_state = :none
-        when :IAC_SB_SOMETHING
-          iac_state = :IAC_SB_SOMETHING_IAC if ch == IAC
-
-        when :IAC_SB_SOMETHING_IAC
-          iac_state = :IAC_SB_SOMETHING if ch == IAC
-          iac_state = :none if ch == SE
         else
-          iac_state = :none
+          @iac_state = :none
+        end
+
+      when :IAC_WILL
+        if OPT_BINARY == ch
+          @socket.puts(IAC + DO + OPT_BINARY)
+        elsif ch == OPT_NAWS
+          supports_naws(true)
+        elsif ch == OPT_LINEMODE
+          @linemode_supported = true
+        elsif OPT_ECHO == ch
+          @socket.puts(IAC + DONT + OPT_ECHO)
+        elsif OPT_SGA  == ch
+          @socket.puts(IAC + DO + OPT_SGA)
+        else
+          @socket.puts(IAC + DONT + ch)
+        end
+        @iac_state = :none
+
+      when :IAC_WONT
+        if ch == OPT_LINEMODE
+          @linemode_supported = false
+        elsif ch == OPT_NAWS
+          supports_naws(false)
+        else
+          @socket.puts(IAC + DONT + ch)
+        end
+        @iac_state = :none
+
+      when :IAC_DO
+        if ch == OPT_BINARY
+          @socket.puts(IAC + WILL + OPT_BINARY)
+        elsif ch == OPT_ECHO
+          @echo_supported = true
+        elsif ch == OPT_MSSP
+          send_mssp
+          @mssp_supported = true
+        else
+          @socket.puts(IAC + WONT + ch)
+        end
+        @iac_state = :none
+
+      when :IAC_DONT
+        if ch == OPT_ECHO
+          @echo_supported = false
+        elsif ch == OPT_COMPRESS2
+          # do nothing
+        elsif ch == OPT_MSSP
+          @mssp_supported = false
+        else
+          @socket.puts(IAC + WONT + ch)
+        end
+        @iac_state = :none
+
+      when :IAC_SB
+        @iac_state = if ch == OPT_NAWS
+                      :IAC_SB_NAWS
+                    else
+                      :IAC_SB_SOMETHING
+                    end
+
+      when :IAC_SB_NAWS
+        if ch != IAC
+          @lwidth = ch.ord
+          @iac_state = :IAC_SB_NAWS_LWIDTH
+        else
+          @iac_state = :IAC_SB_NAWS_IAC
         end
+
+      when :IAC_SB_NAWS_IAC
+        if ch == IAC
+          @lwidth = IAC
+          @iac_state = :IAC_SB_NAWS_LWIDTH
+        else
+          raise "IAC escape expected"
+        end
+
+      when :IAC_SB_NAWS_LWIDTH
+        if ch != IAC
+          @hwidth = ch.ord
+          @iac_state = :IAC_SB_NAWS_LWIDTH_HWIDTH
+        else
+          @iac_state = :IAC_SB_NAWS_LWIDTH_IAC
+        end
+
+      when :IAC_SB_NAWS_LWIDTH_IAC
+        if ch == IAC
+          @hwidth = IAC
+          @iac_state = IAC_SB_NAWS_LWIDTH_HWIDTH
+        else
+          raise "IAC escape expected"
+        end
+
+      when :IAC_SB_NAWS_LWIDTH_HWIDTH
+        @lheight = ch.ord
+        @iac_state = :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT
+        if ch == IAC #&& @socket.getch != IAC
+          raise 'escaped IAC expected but not found'
+        end
+
+      when :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT
+        if ch != IAC
+          @hheight = ch.ord
+          @iac_state = :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_HHEIGHT
+        else
+          @iac_state = :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_IAC
+        end
+
+      when :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_IAC
+        if ch == IAC
+          @hheight = IAC
+          @iac_state = :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_HHEIGHT
+        else
+          raise "IAC escape expected"
+        end
+
+      when :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_HHEIGHT
+        if ch == IAC
+          @iac_state = :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_HHEIGHT_IAC
+        else
+          raise "invalid IAC"
+        end
+
+      when :IAC_SB_NAWS_LWIDTH_HWIDTH_LHEIGHT_HHEIGHT_IAC
+        if ch == SE
+          new_width = @lwidth * 256 + @hwidth
+          new_height = @lheight * 256 + @hheight
+          log "setting resolution #{new_width} #{new_height}"
+          @display.resolution = [new_width, new_height]
+        else
+          raise 'invalid IAC'
+        end
+        @iac_state = :none
+      when :IAC_SB_SOMETHING
+        @iac_state = :IAC_SB_SOMETHING_IAC if ch == IAC
+
+      when :IAC_SB_SOMETHING_IAC
+        @iac_state = :IAC_SB_SOMETHING if ch == IAC
+        @iac_state = :none if ch == SE
       else
-        log "Invalid IAC logic #{iac_state} #{ch}"
-        return false
+        @iac_state = :none
       end
     end
 
diff --git a/lib/aethyr/core/render/display.rb b/lib/aethyr/core/render/display.rb
index f5bf9882bcbed0ed5a66ae77093b2b537236d386..080102ce04b9aad50e84a7e05eec12d6bd45628c 100644
--- a/lib/aethyr/core/render/display.rb
+++ b/lib/aethyr/core/render/display.rb
@@ -329,6 +329,7 @@ CONF
       Ncurses.doupdate();
 
       next if not @scanner.process_iac
+
       ch = @windows[:input].window_text.getch
       puts ch