Explorar o código

Space Ace, can now display the game card layout

We can now display the tri-peaks layout.
We can also select random deck back colors.
Which actually looks really nice I think.
Steve Thielemann %!s(int64=4) %!d(string=hai) anos
pai
achega
fc9aff7a47
Modificáronse 7 ficheiros con 656 adicións e 46 borrados
  1. 19 1
      CMakeLists.txt
  2. 17 0
      NOTES.md
  3. 10 0
      ansi/space.ans
  4. 24 0
      build_images.sh
  5. 262 0
      deck.cpp
  6. 32 0
      deck.h
  7. 292 45
      main.cpp

+ 19 - 1
CMakeLists.txt

@@ -28,6 +28,24 @@ set(CMAKE_CXX_EXTENSIONS ON)
 
 add_subdirectory(door++)
 
-add_executable(space-ace main.cpp)
+# hahaha.  Why am I not surprised to see glog not wanting to work AT ALL.
+#
+# add_subdirectory(glog)
+# find_package (glog 0.5.0 REQUIRED)
+
+file(GLOB IMAGES
+    ansi/*.ans
+)
+
+add_custom_command(
+    OUTPUT images.h
+    COMMAND ./build_images.sh
+    DEPENDS ${IMAGES}
+    COMMENT "Generating images.h"
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+)
+
+# add_executable(space-ace main.cpp deck.cpp images.h glog::glog)
+add_executable(space-ace main.cpp deck.cpp images.h)
 target_link_libraries(space-ace door++ pthread)
 

+ 17 - 0
NOTES.md

@@ -0,0 +1,17 @@
+
+BUG:
+
+FIXED.  We detect "hangup" SIGPIPE.
+
+Using rlinetd.conf, connect in and hangup on it (via syncterm).
+
+It goes 100% CPU utilization.
+
+DRAT.
+
+BUG:
+
+I see \x1b unicode symbol when using xfce4-terminal (not Konsole)!
+In scrollback buffer.
+
+

+ 10 - 0
ansi/space.ans

@@ -0,0 +1,10 @@
+[?7hワイイイイロワ アアイイロロアイイロアイイロロアイイロロアイイロアイイロロアイイロロ
+アアロアアロローアイローアロローアロローアイローアロローアロロ
+ーアワワワワ   ーアイロ ーイローーーーワワ ーイローーーーワワ
+ ゚゚゚゚イイーーアアイ  ーーアアイイ ー ー゚゚  ーーアアイイ ー ー゚゚
+ロ    アイ ー  アイ  アイ  アイ  アイ  アイ  アイ
+゚ ローーア゚     ーア  ーーア  ーーア  ーア  ーーア  ーーア
+
+
+Bugz in space, with a deck of cards
+

+ 24 - 0
build_images.sh

@@ -0,0 +1,24 @@
+#!/bin/bash
+
+BASE=.$$images.h
+FINAL=images.h
+
+ansi-to-src ansi/*.ans > $BASE
+
+# workaround
+if [ -f "$FINAL" ]; then
+  # file exists
+  diff -q $BASE $FINAL
+  status=$?
+  if [ $status -eq 0 ]; then
+    echo "no change..."
+    # Clean up temp file
+    rm -f $BASE    
+  else
+    mv -f $BASE $FINAL
+  fi	  
+else  
+  # file doesn't exist, so no choice by to copy it over.	
+  mv -f $BASE $FINAL
+fi	
+

+ 262 - 0
deck.cpp

@@ -0,0 +1,262 @@
+#include "deck.h"
+
+#include <sstream>
+
+Deck::Deck() {
+  cardback = door::ANSIColor(door::COLOR::RED);
+  init();
+}
+
+Deck::Deck(door::ANSIColor backcolor) : cardback{backcolor} { init(); }
+
+void Deck::init(void) {
+  for (int i = 0; i < 52; ++i) {
+    cards.push_back(card_of(i));
+  }
+  // 0 = BLANK, 1-4 levels
+  for (int i = 0; i < 5; ++i) {
+    backs.push_back(back_of(i));
+  }
+}
+
+Deck::~Deck() {
+  for (auto c : cards) {
+    delete c;
+  }
+  cards.clear();
+  for (auto b : backs) {
+    delete b;
+  }
+  backs.clear();
+}
+
+int Deck::is_suit(int c) { return c / 13; }
+int Deck::is_rank(int c) { return c % 13; }
+
+char Deck::rank_symbol(int c) {
+  switch (c) {
+  case 0:
+    return 'A';
+  case 1:
+  case 2:
+  case 3:
+  case 4:
+  case 5:
+  case 6:
+  case 7:
+  case 8:
+    return char(c + 0x30 + 1);
+  case 9:
+    return 'T';
+  case 10:
+    return 'J';
+  case 11:
+    return 'Q';
+  case 12:
+    return 'K';
+  }
+  return '?';
+}
+
+std::string Deck::suit_symbol(int c) {
+  // unicode
+  if (door::unicode) {
+    switch (c) {
+    case 0:
+      return std::string("\u2665");
+    case 1:
+      return std::string("\u2666");
+    case 2:
+      return std::string("\u2663");
+    case 3:
+      return std::string("\u2660");
+    }
+  } else {
+    switch (c) {
+    case 0:
+      return std::string(1, '\x03');
+    case 1:
+      return std::string(1, '\x04');
+    case 2:
+      return std::string(1, '\x05');
+    case 3:
+      return std::string(1, '\x06');
+    }
+  }
+  return std::string("!", 1);
+}
+
+door::Panel *Deck::card_of(int c) {
+  int suit = is_suit(c);
+  int rank = is_rank(c);
+  bool is_red = (suit < 2);
+  door::ANSIColor color;
+
+  if (is_red) {
+    color = door::ANSIColor(door::COLOR::RED, door::COLOR::WHITE);
+  } else {
+    color = door::ANSIColor(door::COLOR::BLACK, door::COLOR::WHITE);
+  }
+  door::Panel *p = new door::Panel(0, 0, 5);
+  // setColor sets border_color.  NOT WHAT I WANT.
+  // p->setColor(color);
+  char r = rank_symbol(rank);
+  std::string s = suit_symbol(suit);
+
+  // build lines
+  std::ostringstream oss;
+  oss << r << s << "   ";
+  std::string str = oss.str();
+  p->addLine(std::make_unique<door::Line>(str, 5, color));
+  oss.str(std::string());
+  oss.clear();
+  oss << "  " << s << "  ";
+  str = oss.str();
+  p->addLine(std::make_unique<door::Line>(str, 5, color));
+  oss.str(std::string());
+  oss.clear();
+  oss << "   " << s << r;
+  str = oss.str();
+  p->addLine(std::make_unique<door::Line>(str, 5, color));
+  oss.str(std::string());
+  oss.clear();
+
+  return p;
+}
+
+std::string Deck::back_char(int level) {
+  std::string c;
+  if (level == 0) {
+    c = ' ';
+    return c;
+  }
+  if (door::unicode) {
+    switch (level) {
+    case 1:
+      c = "\u2591";
+      break;
+    case 2:
+      c = "\u2592";
+      break;
+    case 3:
+      c = "\u2593";
+      break;
+    case 4:
+      c = "\u2588";
+      break;
+    }
+  } else {
+    switch (level) {
+    case 1:
+      c = "\xb0";
+      break;
+    case 2:
+      c = "\xb1";
+      break;
+    case 3:
+      c = "\xb2";
+      break;
+    case 4:
+      c = "\xdb";
+      break;
+    }
+  }
+  return c;
+}
+
+door::Panel *Deck::back_of(int level) {
+  // using: \xb0, 0xb1, 0xb2, 0xdb
+  // OR:    \u2591, \u2592, \u2593, \u2588
+
+  // door::ANSIColor color(door::COLOR::RED, door::COLOR::BLACK);
+  door::Panel *p = new door::Panel(0, 0, 5);
+  std::string c = back_char(level);
+  std::string l = c + c + c + c + c;
+  p->addLine(std::make_unique<door::Line>(l, 5, cardback));
+  p->addLine(std::make_unique<door::Line>(l, 5, cardback));
+  p->addLine(std::make_unique<door::Line>(l, 5, cardback));
+  return p;
+}
+
+void Deck::part(int x, int y, door::Door &d, int level, bool left) {
+  // Render part of the back of a card.
+  y += 2;
+  if (!left) {
+    x += 2;
+  }
+  std::string c = back_char(level);
+  std::string l = c + c + c;
+  door::Goto g(x, y);
+  d << g << cardback << l;
+}
+
+door::Panel *Deck::card(int c) { return cards[c]; }
+
+door::Panel *Deck::back(int level) { return backs[level]; }
+
+/*
+          1         2         3         4         5         6
+0123456789012345678901234567890123456789012345678901234567890
+         ░░░░░             ░░░░░             ░░░░░
+         ░░░░░             ░░░░░             ░░░░░
+      ▒▒▒▒▒░▒▒▒▒▒       #####░#####       #####░#####
+      ▒▒▒▒▒ ▒▒▒▒▒       ##### #####       ##### #####
+   ▓▓▓▓▓▒▓▓▓▓▓▒▓▓▓▓▓ #####=#####=##### #####=#####=#####
+   ▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓ ##### ##### ##### ##### ##### #####
+█████▓█████▓█████▓#####=#####=#####=#####=#####=#####=#####
+█████ █████ █████ ##### ##### ##### ##### ##### ##### #####
+█████ █████ █████ ##### ##### ##### ##### ##### ##### #####
+*/
+void cardgo(int pos, int &x, int &y, int &level) {
+  /*
+int levels[4] = {3, 6, 9, 10};
+
+  for (level = 0; level < 4; ++level) {
+      if (pos < levels[level]) {
+          level++;
+          // we're here
+          y = (level -1) * 2 + 1;
+      } else {
+          pos -= levels[level];
+      }
+  }
+*/
+
+  if (pos < 3) {
+    // top
+    level = 1;
+    y = (level - 1) * 2 + 1;
+    x = (pos)*18 + 10;
+    return;
+  } else {
+    pos -= 3;
+  }
+  if (pos < 6) {
+    level = 2;
+    y = (level - 1) * 2 + 1;
+    int group = (pos) / 2;
+    x = (pos)*6 + (group * 6) + 7;
+    return;
+  } else {
+    pos -= 6;
+  }
+  if (pos < 9) {
+    level = 3;
+    y = (level - 1) * 2 + 1;
+    x = (pos)*6 + 4;
+    return;
+  } else {
+    pos -= 9;
+  }
+  if (pos < 10) {
+    level = 4;
+    y = (level - 1) * 2 + 1;
+    x = (pos)*6 + 1;
+    return;
+  } else {
+    // something is wrong.
+    y = -1;
+    x = -1;
+    level = -1;
+  }
+}

+ 32 - 0
deck.h

@@ -0,0 +1,32 @@
+#include "door.h"
+
+#include <string>
+#include <vector>
+
+class Deck {
+private:
+  door::ANSIColor cardback;
+  vector<door::Panel *> cards;
+  vector<door::Panel *> backs;
+  door::Panel *card_of(int c);
+  std::string back_char(int level);
+  door::Panel *back_of(int level);
+  int is_rank(int c);
+  int is_suit(int c);
+  void init(void);
+  char rank_symbol(int c);
+  std::string suit_symbol(int c);
+
+public:
+  enum SUIT { HEART, DIAMOND, CLUBS, SPADE };
+
+  Deck();
+  Deck(door::ANSIColor backcolor);
+  ~Deck();
+
+  door::Panel *card(int c);
+  door::Panel *back(int level);
+  void part(int x, int y, door::Door &d, int level, bool left);
+};
+
+void cardgo(int pos, int &x, int &y, int &level);

+ 292 - 45
main.cpp

@@ -4,6 +4,72 @@
 #include <random>
 #include <string>
 
+#include "deck.h"
+/*
+
+Cards:
+
+4 layers deep.
+
+https://en.wikipedia.org/wiki/Code_page_437
+
+using: \xb0, 0xb1, 0xb2, 0xdb
+OR: \u2591, \u2592, \u2593, \u2588
+
+Like so:
+
+##### #####
+##### #####
+##### #####
+
+Cards:  (Black on White, or Red on White)
+8D### TH###
+##D## ##H##
+###D8 ###HT
+
+D, H = Red, Clubs, Spades = Black.
+
+^ Where D = Diamonds, H = Hearts
+
+♥, ♦, ♣, ♠
+\x03, \x04, \x05, \x06
+\u2665, \u2666, \u2663, \u2660
+
+Card layout.  Actual cards are 3 lines thick.
+
+         ░░░░░             ░░░░░             ░░░░░
+         ░░░░░             ░░░░░             ░░░░░
+      ▒▒▒▒▒░▒▒▒▒▒       #####░#####       #####░#####
+      ▒▒▒▒▒ ▒▒▒▒▒       ##### #####       ##### #####
+   ▓▓▓▓▓▒▓▓▓▓▓▒▓▓▓▓▓ #####=#####=##### #####=#####=#####
+   ▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓ ##### ##### ##### ##### ##### #####
+█████▓█████▓█████▓#####=#####=#####=#####=#####=#####=#####
+█████ █████ █████ ##### ##### ##### ##### ##### ##### #####
+█████ █████ █████ ##### ##### ##### ##### ##### ##### #####
+
+                           #####
+Player Information         #####        Time in: xx Time out: xx
+Name:                      #####    Playing Day: November 3rd
+Hand Score   :                            Current Streak: N
+Todays Score :      XX Cards Remaining    Longest Streak: NN
+Monthly Score:      Playing Hand X of X   Most Won: xxx Lost: xxx
+ [4] Lf [6] Rt  [Space] Play Card [Enter] Draw [D]one [H]elp [R]edraw
+
+►, ◄, ▲, ▼
+\x10, \x11, \x1e, \x1f
+\u25ba, \u25c4, \u25b2, \u25bc
+
+
+The Name is <- 6 to the left.
+
+# is back of card.  = is upper card showing between.
+
+There's no fancy anything here.  Cards overlap the last
+line of the previous line/card.
+
+
+ */
+
 // The idea is that this would be defined elsewhere (maybe)
 int user_score = 0;
 
@@ -44,6 +110,38 @@ door::Panel make_timeout(int mx, int my) {
   return timeout;
 }
 
+door::Panel make_notime(int mx, int my) {
+  door::ANSIColor yellowred =
+      door::ANSIColor(door::COLOR::YELLOW, door::COLOR::RED, door::ATTR::BOLD);
+
+  std::string line_text("Sorry, you've used up all your time for today.");
+  int msgWidth = line_text.length() + (2 * 3); // + padding * 2
+  door::Panel timeout((mx - (msgWidth)) / 2, my / 2 + 4, msgWidth);
+  // place.setTitle(std::make_unique<door::Line>(title), 1);
+  timeout.setStyle(door::BorderStyle::DOUBLE);
+  timeout.setColor(yellowred);
+
+  door::Line base(line_text);
+  base.setColor(yellowred);
+  std::string pad1(3, ' ');
+
+  /*
+      std::string pad1(3, '\xb0');
+      if (door::unicode) {
+        std::string unicode;
+        door::cp437toUnicode(pad1.c_str(), unicode);
+        pad1 = unicode;
+      }
+  */
+
+  base.setPadding(pad1, yellowred);
+  // base.setColor(door::ANSIColor(door::COLOR::GREEN, door::COLOR::BLACK));
+  std::unique_ptr<door::Line> stuff = std::make_unique<door::Line>(base);
+
+  timeout.addLine(std::make_unique<door::Line>(base));
+  return timeout;
+}
+
 door::Menu make_main_menu(void) {
   door::Menu m(5, 5, 25);
   door::Line mtitle("Space-Ace Main Menu");
@@ -84,13 +182,86 @@ door::Menu make_main_menu(void) {
   return m;
 }
 
+door::renderFunction statusValue(door::ANSIColor status,
+                                 door::ANSIColor value) {
+  door::renderFunction rf = [status,
+                             value](const std::string &txt) -> door::Render {
+    door::Render r(txt);
+    door::ColorOutput co;
+
+    co.pos = 0;
+    co.len = 0;
+    co.c = status;
+
+    size_t pos = txt.find(':');
+    if (pos == std::string::npos) {
+      // failed to find - use entire string as status color.
+      co.len = txt.length();
+      r.outputs.push_back(co);
+    } else {
+      pos++; // Have : in status color
+      co.len = pos;
+      r.outputs.push_back(co);
+      co.reset();
+      co.pos = pos;
+      co.c = value;
+      co.len = txt.length() - pos;
+      r.outputs.push_back(co);
+    }
+
+    return r;
+  };
+  return rf;
+}
+
+door::renderFunction rStatus = [](const std::string &txt) -> door::Render {
+  door::Render r(txt);
+  door::ColorOutput co;
+
+  // default colors STATUS: value
+  door::ANSIColor status(door::COLOR::BLUE, door::ATTR::BOLD);
+  door::ANSIColor value(door::COLOR::YELLOW, door::ATTR::BOLD);
+
+  co.pos = 0;
+  co.len = 0;
+  co.c = status;
+
+  size_t pos = txt.find(':');
+  if (pos == std::string::npos) {
+    // failed to find - use entire string as status color.
+    co.len = txt.length();
+    r.outputs.push_back(co);
+  } else {
+    pos++; // Have : in status color
+    co.len = pos;
+    r.outputs.push_back(co);
+    co.reset();
+    co.pos = pos;
+    co.c = value;
+    co.len = txt.length() - pos;
+    r.outputs.push_back(co);
+  }
+
+  return r;
+};
+
 door::Panel make_about(void) {
   door::Panel about(2, 2, 60);
   about.setStyle(door::BorderStyle::DOUBLE_SINGLE);
   about.setColor(door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLUE,
                                  door::ATTR::BOLD));
+
   about.addLine(std::make_unique<door::Line>("About This Door", 60));
   /*
+  door::Line magic("---------------------------------", 60);
+  magic.setColor(door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLACK,
+                                 door::ATTR::BOLD));
+*/
+  about.addLine(std::make_unique<door::Line>(
+      "---------------------------------", 60,
+      door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLACK,
+                      door::ATTR::BOLD)));
+  /*
   123456789012345678901234567890123456789012345678901234567890
   This door was written by Bugz.
 
@@ -107,6 +278,20 @@ door::Panel make_about(void) {
   about.addLine(std::make_unique<door::Line>(
       "It is written in c++, only support Linux, and replaces", 60));
   about.addLine(std::make_unique<door::Line>("opendoors.", 60));
+
+  about.addLine(std::make_unique<door::Line>(
+      "Status: blue", 60,
+      statusValue(door::ANSIColor(door::COLOR::GREEN, door::ATTR::BOLD),
+                  door::ANSIColor(door::COLOR::MAGENTA, door::ATTR::BLINK))));
+  about.addLine(std::make_unique<door::Line>("Name: BUGZ", 60, rStatus));
+  about.addLine(std::make_unique<door::Line>(
+      "Size: 10240", 60,
+      statusValue(door::ANSIColor(door::COLOR::GREEN, door::COLOR::BLUE,
+                                  door::ATTR::BOLD),
+                  door::ANSIColor(door::COLOR::YELLOW, door::COLOR::BLUE,
+                                  door::ATTR::BOLD, door::ATTR::BLINK))));
+  about.addLine(std::make_unique<door::Line>("Bugz is here.", 60, rStatus));
+
   return about;
 }
 
@@ -177,10 +362,19 @@ void display_starfield_space_ace(int mx, int my, door::Door &door,
 }
 
 int main(int argc, char *argv[]) {
+  /*
+  google::InitGoogleLogging(argv[0]);
+  LOG(INFO) << "Welcome!";
+  */
+
   door::Door door("space-ace", argc, argv);
   // door << door::reset << door::cls << door::nl;
   door::ANSIColor ac(door::COLOR::YELLOW, door::ATTR::BOLD);
 
+  door::ANSIColor mb(door::COLOR::MAGENTA, door::ATTR::BLINK);
+
+  door << mb << "Does this work?" << door::reset << door::nl;
+
   // https://stackoverflow.com/questions/5008804/generating-random-integer-from-a-range
 
   std::random_device rd; // only used once to initialise (seed) engine
@@ -202,62 +396,54 @@ int main(int argc, char *argv[]) {
   display_starfield_space_ace(mx, my, door, rng);
 
   // for testing inactivity timeout
-  door.inactivity = 10;
+  // door.inactivity = 10;
 
   door::Panel timeout = make_timeout(mx, my);
   door::Menu m = make_main_menu();
 
   int r = m.choose(door);
   // need to reset the colors.  (whoops!)
-  door << door::reset;
+  door << door::reset << door::nl;
 
-  if (r == -1) {
+  if (r < 0) {
   TIMEOUT:
-    door.log("TIMEOUT");
-    // mx, my
-    door::ANSIColor yellowred = door::ANSIColor(
-        door::COLOR::YELLOW, door::COLOR::RED, door::ATTR::BOLD);
-
-    std::string line_text("Sorry, you've been inactive for too long.");
-    int msgWidth = line_text.length() + (2 * 3); // + padding * 2
-    door::Panel timeout((mx - (msgWidth)) / 2, my / 2 + 4, msgWidth);
-    // place.setTitle(std::make_unique<door::Line>(title), 1);
-    timeout.setStyle(door::BorderStyle::DOUBLE);
-    timeout.setColor(yellowred);
-
-    door::Line base(line_text);
-    base.setColor(yellowred);
-    std::string pad1(3, ' ');
-
-    /*
-        std::string pad1(3, '\xb0');
-        if (door::unicode) {
-          std::string unicode;
-          door::cp437toUnicode(pad1.c_str(), unicode);
-          pad1 = unicode;
-        }
-    */
-
-    base.setPadding(pad1, yellowred);
-    // base.setColor(door::ANSIColor(door::COLOR::GREEN, door::COLOR::BLACK));
-    std::unique_ptr<door::Line> stuff = std::make_unique<door::Line>(base);
-
-    timeout.addLine(std::make_unique<door::Line>(base));
-    door << timeout << door::reset << door::nl << door::nl;
+    if (r == -1) {
+      door.log("TIMEOUT");
+
+      door << timeout << door::reset << door::nl << door::nl;
+    } else {
+      if (r == -3) {
+        door.log("OUTTA TIME");
+        door::Panel notime = make_notime(mx, my);
+        door << notime << door::reset << door::nl;
+      }
+    }
     return 0;
   }
 
-  display_starfield(mx, my, door, rng);
-  // WARNING: After starfield, cursor position is random!
+  /*
+    display_starfield(mx, my, door, rng);
+    // WARNING: After starfield, cursor position is random!
 
-  door << door::Goto(1, 9); // door::nl << door::nl; // door::cls;
-  door << "Hello, " << door.username << ", you chose option " << r << "!"
-       << door::nl;
+    door << door::Goto(1, 9); // door::nl << door::nl; // door::cls;
 
-  door << "Press a key...";
-  r = door.sleep_key(door.inactivity);
-  if (r == -1)
-    goto TIMEOUT;
+    door << "Your name: "
+         << door::ANSIColor(door::COLOR::WHITE, door::COLOR::GREEN,
+                            door::ATTR::BOLD);
+    std::string istring;
+    istring = door.input_string(25);
+    door << door::reset << door::nl << "You typed in [" << istring << "]"
+         << door::nl;
+
+    door << "Hello, " << door.username << ", you chose option " << r << "!"
+         << door::nl;
+
+    door << "Press a key...";
+    r = door.sleep_key(door.inactivity);
+    if (r < 0)
+      goto TIMEOUT;
+
+  */
 
   door << door::nl;
 
@@ -268,11 +454,73 @@ int main(int argc, char *argv[]) {
 
   door << door::reset << door::nl << "Press another key...";
   r = door.sleep_key(door.inactivity);
-  if (r == -1)
+  if (r < 0)
     goto TIMEOUT;
 
   door << door::nl;
 
+  door::ANSIColor deck_color;
+  // RED, BLUE, GREEN, MAGENTA, CYAN
+  std::uniform_int_distribution<int> rand_color(0, 4);
+
+  switch (rand_color(rng)) {
+  case 0:
+    deck_color = door::ANSIColor(door::COLOR::RED);
+    break;
+  case 1:
+    deck_color = door::ANSIColor(door::COLOR::BLUE);
+    break;
+  case 2:
+    deck_color = door::ANSIColor(door::COLOR::GREEN);
+    break;
+  case 3:
+    deck_color = door::ANSIColor(door::COLOR::MAGENTA);
+    break;
+  case 4:
+    deck_color = door::ANSIColor(door::COLOR::CYAN);
+    break;
+  default:
+    deck_color = door::ANSIColor(door::COLOR::BLUE, door::ATTR::BLINK);
+    break;
+  }
+
+  Deck d(deck_color);
+  door::Panel *c;
+  door << door::reset << door::cls;
+
+  // This displays the cards in the upper left corner.
+  // We want them center, and down some.
+
+  // int cards_delt_width = 59; int cards_delt_height = 9;
+  int off_x = (mx - 59) / 2;
+  int off_y = (my - 9) / 2;
+
+  for (int x = 0; x < 28; x++) {
+    int cx, cy, level;
+    cardgo(x, cx, cy, level);
+    c = d.back(level);
+    c->set(cx + off_x, cy + off_y);
+    door << *c;
+  }
+  door << door::nl << door::nl;
+
+  r = door.sleep_key(door.inactivity);
+  if (r < 0)
+    goto TIMEOUT;
+
+  /*
+    door::Panel *p = d.back(2);
+    p->set(10, 10);
+    door << *p;
+    door::Panel *d8 = d.card(8);
+    d8->set(20, 8);
+    door << *d8;
+
+    r = door.sleep_key(door.inactivity);
+    if (r < 0)
+      goto TIMEOUT;
+  */
+
   // door << door::reset << door::cls;
   display_starfield(mx, my, door, rng);
   door << m << door::reset << door::nl << "This is what the menu looked liked!"
@@ -280,7 +528,6 @@ int main(int argc, char *argv[]) {
 
   // Normal DOOR exit goes here...
   door << door::nl << "Returning you to the BBS, please wait..." << door::nl;
-  sleep(2);
 
   return 0;
 }