unofficial version 0.7: multiplayer improvements
[netris.git] / curses.c
index 047efa4bc496de98ca707516db7cc60d53fb8c07..f28a6a36a2ec81cf6c846f87599e187a31713c05 100644 (file)
--- a/curses.c
+++ b/curses.c
@@ -1,6 +1,6 @@
 /*
  * Netris -- A free networked version of T*tris
- * Copyright (C) 1994,1995,1996  Mark H. Weaver <mhw@netris.org>
+ * 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.32 1996/02/09 08:47:25 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,6 +54,7 @@ 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 */
@@ -45,11 +66,34 @@ ExtFunc void InitScreens(void)
        GetTermcapInfo();
 
        /*
-        * Do this atomically.  Otherwise a badly timed Ctrl-C during
-        * initialization will leave your terminal in a bad state.
+        * 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 = Game.color && 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);
 
@@ -58,21 +102,27 @@ ExtFunc void InitScreens(void)
        OutputTermStr(term_vi, 0);
        AddEventGen(&keyGen);
 
-       move(0, 0);
-       addstr("Netris ");
+       move(0, 1);
+       addstr("NETRIS ");
        addstr(version_string);
-       addstr(" (C) 1994,1995,1996  Mark H. Weaver     "
-                       "\"netris -h\" for more info");
+       {
+               int rows, cols;
+
+               getmaxyx(stdscr, rows, cols);
+               move(0, cols - 48);
+               addstr("(C)1994-1996,1999 Mark H. Weaver, (C)2002 Shiar");
+//             addstr("    \"netris -h\" for more info");
+       }
        statusYPos = 22;
        statusXPos = 0;
-}
+} //InitScreens
 
 ExtFunc void CleanupScreens(void)
 {
        RemoveEventGen(&keyGen);
        endwin();
        OutputTermStr(term_ve, 1);
-}
+} //CleanupScreens
 
 ExtFunc void GetTermcapInfo(void)
 {
@@ -128,175 +178,218 @@ ExtFunc void GetTermcapInfo(void)
        }
        if (!term_vi || !term_ve)
                term_vi = term_ve = NULL;
-}
+} //GetTermcapInfo
 
 ExtFunc void OutputTermStr(char *str, int flush)
 {
        if (str) {
                fputs(str, stdout);
-               if (flush)
-                       fflush(stdout);
+               if (flush) fflush(stdout);
        }
-}
+} //OutputTermStr
 
-ExtFunc void InitScreen(int scr)
-{
-       int y, x;
+ExtFunc void DrawField(int scr)
+{ //drow field for player scr
+       {
+               int y, x;
+
+               getmaxyx(stdscr, y, x);
+               if (x < boardXPos[scr] + 2 * Players[scr].boardWidth + 1) {
+                       Players[scr].spy = 0;
+                       return;
+               }
+
+               for (y = Players[scr].boardVisible - 1; y >= 0; --y) {
+                       mvaddch(boardYPos[scr] - y, boardXPos[scr] - 1,
+                               Game.ascii ? '|' : ACS_VLINE); //left
+                       mvaddch(boardYPos[scr] - y,
+                               boardXPos[scr] + 2 * Players[scr].boardWidth,
+                               Game.ascii ? '|' : ACS_VLINE); //right
+               }
+               move(2, boardXPos[scr] - 1); //top
+               addch(Game.ascii ? '+' : ACS_ULCORNER);
+               for (x = Players[scr].boardWidth * 2 - 1; x >= 0; --x)
+                       addch(Game.ascii ? '-' : ACS_HLINE);
+               addch(Game.ascii ? '+' : ACS_URCORNER);
+               move(boardYPos[scr] + 1, boardXPos[scr] - 1); //bottom
+               addch(Game.ascii ? '+' : ACS_LLCORNER);
+               for (x = Players[scr].boardWidth * 2 - 1; x >= 0; --x)
+                       addch(Game.ascii ? '-' : ACS_HLINE);
+               addch(Game.ascii ? '+' : ACS_LRCORNER);
+       } //draw field grid
 
-       if (scr == 0)
-               boardXPos[scr] = 1;
-       else
-               boardXPos[scr] = boardXPos[scr - 1] +
-                                       2 * boardWidth[scr - 1] + 3;
-       boardYPos[scr] = 22;
-       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('|');
-               move(boardYPos[scr] - y, boardXPos[scr] + 2 * boardWidth[scr]);
-               addch('|');
-       }
-       for (y = boardVisible[scr]; y >= -1; y -= boardVisible[scr] + 1) {
-               move(boardYPos[scr] - y, boardXPos[scr] - 1);
-               addch('+');
-               for (x = boardWidth[scr] - 1; x >= 0; --x)
-                       addstr("--");
-               addch('+');
+       {
+               char userstr[300];
+
+               if (Players[scr].host && Players[scr].host[0])
+                        sprintf(userstr, "%s <%s>", Players[scr].name, Players[scr].host);
+               else sprintf(userstr, "%s", Players[scr].name);
+               userstr[20 - 7*((Players[scr].flags & SCF_usingRobot) != 0)
+                       - 5*((Players[scr].flags & SCF_fairRobot) != 0)] = 0;
+               mvaddstr(1, boardXPos[scr], userstr);
+
+               if (Players[scr].flags & SCF_usingRobot) {
+                       addstr((Players[scr].flags & SCF_fairRobot)
+                               ? "(fair robot)" : "(robot)");
+               }
+       } //display playername/host
+
+       ShowPause(scr);
+} //DrawScreen
+
+ExtFunc void InitFields()
+{ //place fields for all players
+       int scr, prevscr;
+
+       statusXPos = 2 * Players[me].boardWidth + 3;
+       boardXPos[me] = 1;
+       boardYPos[me] = 22;
+       prevscr = me;
+       for (scr = 1; scr <= totalPlayers + 1; scr++) if (scr != me) {
+               boardXPos[scr] =
+                       boardXPos[prevscr] + 2 * Players[prevscr].boardWidth + 3;
+               if (prevscr == me)
+                       boardXPos[scr] += 24; //scorebar
+               boardYPos[scr] = 22;
+               prevscr = scr;
        }
-}
+} //InitScreen
 
 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)
 {
-       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)
+       int colorIndex = abs(type);
+
+       move(y, x);
+
+       if (type == BT_none)
+               addstr("  ");
+       else
+       {
+               if (Game.standout)
+               {
+#ifdef HAVE_NCURSES
+                       if (haveColor)
+                               attrset(COLOR_PAIR(colorIndex));
+                       else
+#endif
                                standout();
-                       addstr("[]");
-                       if (standoutEnable)
-                               standend();
-                       break;
-               default:
-                       assert(0);
+               }
+
+               addstr(type ? "[]" : "$$");
+               standend();
        }
-}
+} //PlotBlock1
 
 ExtFunc void PlotBlock(int scr, int y, int x, BlockType type)
 {
-       if (y >= 0 && y < boardVisible[scr] && x >= 0 && x < boardWidth[scr])
-               PlotBlock1(scr, y, x, type);
-}
+       if (y >= 0 && y < Players[scr].boardVisible &&
+               x >= 0 && x < Players[scr].boardWidth)
+         PlotBlock1(scr, boardYPos[scr] - y, boardXPos[scr] + 2 * x, type);
+} //PlotBlock
 
 ExtFunc void PlotUnderline(int scr, int x, int flag)
 {
-       move(boardYPos[scr] + 1, boardXPos[scr] + 2 * x);
+  move(boardYPos[scr] + 1, boardXPos[scr] + 2 * x);
+  if (Game.ascii)
        addstr(flag ? "==" : "--");
-}
-
-ExtFunc void ShowDisplayInfo(void)
-{
-       move(statusYPos - 9, statusXPos);
-       printw("Seed: %d", initSeed);
-       clrtoeol();
-       move(statusYPos - 8, statusXPos);
-       printw("Speed: %dms", speed / 1000);
-       clrtoeol();
-       if (robotEnable) {
-               move(statusYPos - 6, statusXPos);
-               if (fairRobot)
-                       addstr("Controlled by a fair robot");
-               else
-                       addstr("Controlled by a robot");
-               clrtoeol();
+  else {
+       addch(flag ? ACS_BTEE : ACS_HLINE);
+       addch(flag ? ACS_BTEE : ACS_HLINE);
+  }
+} //PlotUnderline
+
+ExtFunc void ShowScore(int scr, struct _Score score)
+{ //show score stuff
+       float timer;
+
+       move(6, statusXPos); addstr("Next:          ");
+       move(7, statusXPos + 7);    addstr("        ");
+       ShapeIterate(Players[scr].nextShape, scr,
+         ShapeToNetNum(Players[scr].nextShape) == 15 ? 13 : 14,
+         statusXPos / 2 + 5, 1, GlanceFunc, NULL);
+       move(statusYPos - 21 + 1, statusXPos);
+       printw("Score:%6d  level: %2d", score.score, score.level);
+       move(statusYPos - 20 + 1, statusXPos);
+       timer = CurTimeval() / 1e6;
+       printw("Lines:%6d", score.lines);
+       if (timer > 4) {
+               printw("  ppm:%5.1f", score.drops * 60 / timer);
+               move(statusYPos - 18, statusXPos);
+               if (score.lines > 0)
+                       printw("yield:  %3d%%", 100 * score.adds / score.lines);
+               else addstr("            ");
+               printw("  apm:%5.1f", score.adds * 60 / timer);
        }
-       if (opponentFlags & SCF_usingRobot) {
-               move(statusYPos - 5, statusXPos);
-               if (opponentFlags & SCF_fairRobot)
-                       addstr("The opponent is a fair robot");
-               else
-                       addstr("The opponent is a robot");
-               clrtoeol();
-       }
-}
-
-ExtFunc void UpdateOpponentDisplay(void)
-{
-       move(1, 0);
-       printw("Playing %s@%s", opponentName, opponentHost);
-       clrtoeol();
-}
+} //ShowScore
+
+ExtFunc void FieldMessage(int playa, char *message)
+{ //put a message over playa's field
+       if (!Players[playa].spy) return;
+       if (message) {
+               char s[MAX_BOARD_WIDTH+1];
+               memset(s, ' ', MAX_BOARD_WIDTH);
+               memcpy(&s[Players[playa].boardWidth - strlen(message) / 2],
+                       message, strlen(message));
+               s[Players[playa].boardWidth * 2] = 0;
+               if (Game.standout) standout();
+               mvprintw(boardYPos[playa] - Players[playa].boardVisible / 2,
+                       boardXPos[playa], "%s", s);
+               standend();
+       } //display
+       else {
+               int x, y;
+               y = Players[playa].boardVisible / 2;
+               for (x = 0; x <= Players[playa].boardWidth; x++)
+                       PlotBlock(playa, y, x, GetBlock(playa, y, x));
+       } //restore field
+} //FieldMessage
+
+ExtFunc void ShowPause(int playa)
+{ //put paused over player's field
+       if (Players[playa].flags & SCF_paused)
+               FieldMessage(playa, "P A U S E D");
+       else FieldMessage(playa, NULL);
+} //ShowPause
 
-ExtFunc void ShowPause(int pausedByMe, int pausedByThem)
-{
-       move(statusYPos - 3, statusXPos);
-       if (pausedByThem)
-               addstr("Game paused by opponent");
-       else
-               clrtoeol();
-       move(statusYPos - 2, statusXPos);
-       if (pausedByMe)
-               addstr("Game paused by you");
-       else
-               clrtoeol();
-}
 
 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();
-}
+} //Message
 
-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 */
-       if (strcmp(timeStr[0], timeStr[1]))
-       {
-               move(statusYPos, statusXPos);
-               addstr(timeStr[0]);
-               strcpy(timeStr[1], timeStr[0]);
-       }
-       move(boardYPos[0] + 1, boardXPos[0] + 2 * boardWidth[0] + 1);
-       refresh();
-}
+ExtFunc void ShowTime(void)
+{ //display timer
+       move(statusYPos, statusXPos);
+       printw("Timer: %.0f ", CurTimeval() / 1e6);
+       move(boardYPos[0] + 1, boardXPos[0] + 2 * Players[0].boardWidth + 1);
+//     refresh();
+} //ShowTime
 
 ExtFunc void ScheduleFullRedraw(void)
 {
        touchwin(stdscr);
-}
+} //ScheduleFullRedraw
 
 static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event)
-{
+{ //read keypresses
        if (MyRead(gen->fd, &event->u.key, 1))
                return E_key;
        else
                return E_none;
-}
+} //KeyGenFunc
 
 /*
  * vi: ts=4 ai