initial interface requests
[netris.git] / curses.c
index 2d9390064446c9b8244e2627cc7e4a2d413d7a11..9649d853a9b9062dc7863328f20f336478c5d2c5 100644 (file)
--- a/curses.c
+++ b/curses.c
@@ -1,6 +1,6 @@
 /*
- * Netris -- A free networked version of Tetris
- * Copyright (C) 1994,1995  Mark Weaver <Mark_Weaver@brown.edu>
+ * Netris -- A free networked version of T*tris
+ * Copyright (C) 1994-1996,1999  Mark H. Weaver <mhw@netris.org>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: curses.c,v 1.29 1995/07/11 08:53:21 mhw Exp $
+ * $Id: curses.c,v 1.33 1999/05/16 06:56:25 mhw Exp $
  */
 
 #include "netris.h"
 #include <string.h>
 #include <stdlib.h>
 
-static void PlotBlock1(int scr, int y, int x, BlockType type);
+#ifdef NCURSES_VERSION
+# define HAVE_NCURSES
+#endif
+
+#ifdef HAVE_NCURSES
+static struct
+{
+       BlockType type;
+       short color;
+} myColorTable[] =
+{
+       { BT_white,             COLOR_WHITE },
+       { BT_blue,              COLOR_BLUE },
+       { BT_magenta,   COLOR_MAGENTA },
+       { BT_cyan,              COLOR_CYAN },
+       { BT_yellow,    COLOR_YELLOW },
+       { BT_green,             COLOR_GREEN },
+       { BT_red,               COLOR_RED },
+       { BT_none, 0 }
+};
+#endif
+
+ExtFunc void PlotBlock1(int scr, int y, int x, BlockType type);
 static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event);
 
 static EventGenRec keyGen =
@@ -34,23 +56,60 @@ static EventGenRec keyGen =
 
 static int boardYPos[MAX_SCREENS], boardXPos[MAX_SCREENS];
 static int statusYPos, statusXPos;
+static int haveColor;
+
+static char *term_vi;  /* String to make cursor invisible */
+static char *term_ve;  /* String to make cursor visible */
 
 ExtFunc void InitScreens(void)
 {
        MySigSet oldMask;
 
+       GetTermcapInfo();
+
+       /*
+        * Block signals while initializing curses.  Otherwise a badly timed
+        * Ctrl-C during initialization might leave the terminal in a bad state.
+        */
        BlockSignals(&oldMask, SIGINT, 0);
        initscr();
+
+#ifdef CURSES_HACK
+       {
+               extern char *CS;
+
+               CS = 0;
+       }
+#endif
+
+#ifdef HAVE_NCURSES
+       haveColor = colorEnable && has_colors();
+       if (haveColor)
+       {
+               int i = 0;
+
+               start_color();
+               for (i = 0; myColorTable[i].type != BT_none; ++i)
+                       init_pair(myColorTable[i].type, COLOR_BLACK,
+                                       myColorTable[i].color);
+       }
+#else
+       haveColor = 0;
+#endif
+
        AtExit(CleanupScreens);
        RestoreSignals(NULL, &oldMask);
+
        cbreak();
        noecho();
+       OutputTermStr(term_vi, 0);
        AddEventGen(&keyGen);
+
        move(0, 0);
        addstr("Netris ");
        addstr(version_string);
-       addstr(" (C) 1994,1995  Mark Weaver         "
-               "\"netris -h\" for more info");
+       addstr(" (C) 1994-1996,1999  Mark H. Weaver     "
+                       "\"netris -h\" for more info");
        statusYPos = 22;
        statusXPos = 0;
 }
@@ -59,6 +118,72 @@ ExtFunc void CleanupScreens(void)
 {
        RemoveEventGen(&keyGen);
        endwin();
+       OutputTermStr(term_ve, 1);
+}
+
+ExtFunc void GetTermcapInfo(void)
+{
+       char *term, *buf, *data;
+       int bufSize = 10240;
+
+       if (!(term = getenv("TERM")))
+               return;
+       if (tgetent(scratch, term) == 1) {
+               /*
+                * Make the buffer HUGE, since tgetstr is unsafe.
+                * Allocate it on the heap too.
+                */
+               data = buf = malloc(bufSize);
+
+               /*
+                * There is no standard include file for tgetstr, no prototype
+                * definitions.  I like casting better than using my own prototypes
+                * because if I guess the prototype, I might be wrong, especially
+                * with regards to "const".
+                */
+               term_vi = (char *)tgetstr("vi", &data);
+               term_ve = (char *)tgetstr("ve", &data);
+
+               /* Okay, so I'm paranoid; I just don't like unsafe routines */
+               if (data > buf + bufSize)
+                       fatal("tgetstr overflow, you must have a very sick termcap");
+
+               /* Trim off the unused portion of buffer */
+               buf = realloc(buf, data - buf);
+       }
+
+       /*
+        * If that fails, use hardcoded vt220 codes.
+        * They don't seem to do anything bad on vt100's, so
+        * we'll try them just in case they work.
+        */
+       if (!term_vi || !term_ve) {
+               static char *vts[] = {
+                               "vt100", "vt101", "vt102",
+                               "vt200", "vt220", "vt300",
+                               "vt320", "vt400", "vt420",
+                               "screen", "xterm", NULL };
+               int i;
+
+               for (i = 0; vts[i]; i++)
+                       if (!strcmp(term, vts[i]))
+                       {
+                               term_vi = "\033[?25l";
+                               term_ve = "\033[?25h";
+                               break;
+                       }
+       }
+       if (!term_vi || !term_ve)
+               term_vi = term_ve = NULL;
+}
+
+ExtFunc void OutputTermStr(char *str, int flush)
+{
+       if (str) {
+               fputs(str, stdout);
+               if (flush)
+                       fflush(stdout);
+       }
 }
 
 ExtFunc void InitScreen(int scr)
@@ -70,9 +195,12 @@ ExtFunc void InitScreen(int scr)
        else
                boardXPos[scr] = boardXPos[scr - 1] +
                                        2 * boardWidth[scr - 1] + 3;
+       if (scr == 1)
+               boardXPos[scr] += 24;
        boardYPos[scr] = 22;
-       if (statusXPos < boardXPos[scr] + 2 * boardWidth[scr] + 3)
-               statusXPos = boardXPos[scr] + 2 * boardWidth[scr] + 3;
+       statusXPos = 2 * boardWidth[0] + 3;
+//     if (statusXPos < boardXPos[scr] + 2 * boardWidth[scr] + 3)
+//             statusXPos = boardXPos[scr] + 2 * boardWidth[scr] + 3;
        for (y = boardVisible[scr] - 1; y >= 0; --y) {
                move(boardYPos[scr] - y, boardXPos[scr] - 1);
                addch('|');
@@ -92,29 +220,28 @@ ExtFunc void CleanupScreen(int scr)
 {
 }
 
-static void PlotBlock1(int scr, int y, int x, BlockType type)
+ExtFunc void PlotBlock1(int scr, int y, int x, BlockType type)
 {
+       int colorIndex = abs(type);
+
        move(boardYPos[scr] - y, boardXPos[scr] + 2 * x);
-       switch (type) {
-               case BT_none:
-                       addstr("  ");
-                       break;
-               case -BT_piece1:
-                       if (standoutEnable)
-                               standout();
-                       addstr("$$");
-                       if (standoutEnable)
-                               standend();
-                       break;
-               case BT_piece1:
-                       if (standoutEnable)
+
+       if (type == BT_none)
+               addstr("  ");
+       else
+       {
+               if (standoutEnable)
+               {
+#ifdef HAVE_NCURSES
+                       if (haveColor)
+                               attrset(COLOR_PAIR(colorIndex));
+                       else
+#endif
                                standout();
-                       addstr("[]");
-                       if (standoutEnable)
-                               standend();
-                       break;
-               default:
-                       assert(0);
+               }
+
+               addstr(type ? "[]" : "$$");
+               standend();
        }
 }
 
@@ -133,18 +260,16 @@ ExtFunc void PlotUnderline(int scr, int x, int flag)
 ExtFunc void ShowDisplayInfo(void)
 {
        move(statusYPos - 9, statusXPos);
-       printw("Seed = %d", initSeed);
-       clrtoeol();
+       printw("Seed: %010d", initSeed);
        move(statusYPos - 8, statusXPos);
-       printw("Speed = %dms", speed / 1000);
-       clrtoeol();
+       printw("Speed: %dms ", speed / 1000);
        if (robotEnable) {
                move(statusYPos - 6, statusXPos);
                if (fairRobot)
                        addstr("Controlled by a fair robot");
                else
                        addstr("Controlled by a robot");
-               clrtoeol();
+//             clrtoeol();
        }
        if (opponentFlags & SCF_usingRobot) {
                move(statusYPos - 5, statusXPos);
@@ -152,10 +277,29 @@ ExtFunc void ShowDisplayInfo(void)
                        addstr("The opponent is a fair robot");
                else
                        addstr("The opponent is a robot");
-               clrtoeol();
+//             clrtoeol();
        }
 }
 
+ExtFunc void ShowScore(int scr, int totalDrops, int totalLines, int totalAdds)
+{
+       float timer;
+       move(6, statusXPos); addstr("Next:         ");
+       move(7, statusXPos + 6);    addstr("        ");
+       ShapeIterate(nextShape[scr], scr,
+               ShapeToNetNum(nextShape[scr]) == 15 ? 15 : 16, statusXPos/2 + 4,
+               1, GlanceFunc, NULL);
+       move(statusYPos - 20 + 1, statusXPos);
+       timer = CurTimeval() / 1e6;
+       printw("Lines: %05d", totalLines);
+       if (timer > 4)
+               printw(" (%.1f ppm)", totalDrops * 60 / timer);
+       move(statusYPos - 18, statusXPos);
+       printw("apm: %.1f", totalAdds * 60 / timer);
+       if (totalLines > 0)
+               printw(" (%d%% yield)  ", 100 * totalAdds / totalLines);
+}
+
 ExtFunc void UpdateOpponentDisplay(void)
 {
        move(1, 0);
@@ -169,34 +313,37 @@ ExtFunc void ShowPause(int pausedByMe, int pausedByThem)
        if (pausedByThem)
                addstr("Game paused by opponent");
        else
-               clrtoeol();
+               addstr("                       ");
        move(statusYPos - 2, statusXPos);
        if (pausedByMe)
                addstr("Game paused by you");
        else
-               clrtoeol();
+               addstr("                  ");
 }
 
 ExtFunc void Message(char *s)
 {
        static int line = 0;
 
-       move(statusYPos - 20 + line, statusXPos);
+//     move(statusYPos - 20 + line, statusXPos);
+       move(statusYPos + 2 + line, 1);
        addstr(s);      /* XXX Should truncate long lines */
        clrtoeol();
        line = (line + 1) % 10;
-       move(statusYPos - 20 + line, statusXPos);
+//     move(statusYPos - 20 + line, statusXPos);
+       move(statusYPos + 2 + line, 1);
        clrtoeol();
 }
 
 ExtFunc void RefreshScreen(void)
 {
+/*
        static char timeStr[2][32];
        time_t theTime;
 
        time(&theTime);
        strftime(timeStr[0], 30, "%I:%M %p", localtime(&theTime));
-       /* Just in case the local curses library sucks */
+       // Just in case the local curses library sucks
        if (strcmp(timeStr[0], timeStr[1]))
        {
                move(statusYPos, statusXPos);
@@ -205,6 +352,16 @@ ExtFunc void RefreshScreen(void)
        }
        move(boardYPos[0] + 1, boardXPos[0] + 2 * boardWidth[0] + 1);
        refresh();
+*/
+       move(statusYPos, statusXPos);
+       printw("Timer: %.0f ", CurTimeval() / 1e6);
+       move(boardYPos[0] + 1, boardXPos[0] + 2 * boardWidth[0] + 1);
+       refresh();
+}
+
+ExtFunc void ScheduleFullRedraw(void)
+{
+       touchwin(stdscr);
 }
 
 static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event)
@@ -215,3 +372,7 @@ static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event)
                return E_none;
 }
 
+/*
+ * vi: ts=4 ai
+ * vim: noai si
+ */