2 * Netris -- A free networked version of T*tris
3 * Copyright (C) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * $Id: curses.c,v 1.33 1999/05/16 06:56:25 mhw Exp $
23 #include <sys/types.h>
29 #ifdef NCURSES_VERSION
40 { BT_white, COLOR_WHITE },
41 { BT_blue, COLOR_BLUE },
42 { BT_magenta, COLOR_MAGENTA },
43 { BT_cyan, COLOR_CYAN },
44 { BT_yellow, COLOR_YELLOW },
45 { BT_green, COLOR_GREEN },
46 { BT_red, COLOR_RED },
51 ExtFunc void PlotBlock1(int scr, int y, int x, BlockType type);
52 static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event);
54 static EventGenRec keyGen =
55 { NULL, 0, FT_read, STDIN_FILENO, KeyGenFunc, EM_key };
57 static int boardYPos[MAX_SCREENS], boardXPos[MAX_SCREENS];
58 static int statusYPos, statusXPos;
61 static char *term_vi; /* String to make cursor invisible */
62 static char *term_ve; /* String to make cursor visible */
64 ExtFunc void InitScreens(void)
71 * Block signals while initializing curses. Otherwise a badly timed
72 * Ctrl-C during initialization might leave the terminal in a bad state.
74 BlockSignals(&oldMask, SIGINT, 0);
86 haveColor = colorEnable && has_colors();
92 for (i = 0; myColorTable[i].type != BT_none; ++i)
93 init_pair(myColorTable[i].type, COLOR_BLACK,
94 myColorTable[i].color);
100 AtExit(CleanupScreens);
101 RestoreSignals(NULL, &oldMask);
105 OutputTermStr(term_vi, 0);
106 AddEventGen(&keyGen);
110 addstr(version_string);
111 addstr(" (C) 1994-1996,1999 Mark H. Weaver "
112 "\"netris -h\" for more info");
117 ExtFunc void CleanupScreens(void)
119 RemoveEventGen(&keyGen);
121 OutputTermStr(term_ve, 1);
124 ExtFunc void GetTermcapInfo(void)
126 char *term, *buf, *data;
129 if (!(term = getenv("TERM")))
131 if (tgetent(scratch, term) == 1) {
133 * Make the buffer HUGE, since tgetstr is unsafe.
134 * Allocate it on the heap too.
136 data = buf = malloc(bufSize);
139 * There is no standard include file for tgetstr, no prototype
140 * definitions. I like casting better than using my own prototypes
141 * because if I guess the prototype, I might be wrong, especially
142 * with regards to "const".
144 term_vi = (char *)tgetstr("vi", &data);
145 term_ve = (char *)tgetstr("ve", &data);
147 /* Okay, so I'm paranoid; I just don't like unsafe routines */
148 if (data > buf + bufSize)
149 fatal("tgetstr overflow, you must have a very sick termcap");
151 /* Trim off the unused portion of buffer */
152 buf = realloc(buf, data - buf);
156 * If that fails, use hardcoded vt220 codes.
157 * They don't seem to do anything bad on vt100's, so
158 * we'll try them just in case they work.
160 if (!term_vi || !term_ve) {
161 static char *vts[] = {
162 "vt100", "vt101", "vt102",
163 "vt200", "vt220", "vt300",
164 "vt320", "vt400", "vt420",
165 "screen", "xterm", NULL };
168 for (i = 0; vts[i]; i++)
169 if (!strcmp(term, vts[i]))
171 term_vi = "\033[?25l";
172 term_ve = "\033[?25h";
176 if (!term_vi || !term_ve)
177 term_vi = term_ve = NULL;
180 ExtFunc void OutputTermStr(char *str, int flush)
189 ExtFunc void InitScreen(int scr)
196 boardXPos[scr] = boardXPos[scr - 1] +
197 2 * boardWidth[scr - 1] + 3;
199 boardXPos[scr] += 24;
201 statusXPos = 2 * boardWidth[0] + 3;
202 // if (statusXPos < boardXPos[scr] + 2 * boardWidth[scr] + 3)
203 // statusXPos = boardXPos[scr] + 2 * boardWidth[scr] + 3;
204 for (y = boardVisible[scr] - 1; y >= 0; --y) {
205 move(boardYPos[scr] - y, boardXPos[scr] - 1);
207 move(boardYPos[scr] - y, boardXPos[scr] + 2 * boardWidth[scr]);
210 for (y = boardVisible[scr]; y >= -1; y -= boardVisible[scr] + 1) {
211 move(boardYPos[scr] - y, boardXPos[scr] - 1);
213 for (x = boardWidth[scr] - 1; x >= 0; --x)
219 ExtFunc void CleanupScreen(int scr)
223 ExtFunc void PlotBlock1(int scr, int y, int x, BlockType type)
225 int colorIndex = abs(type);
227 move(boardYPos[scr] - y, boardXPos[scr] + 2 * x);
237 attrset(COLOR_PAIR(colorIndex));
243 addstr(type ? "[]" : "$$");
248 ExtFunc void PlotBlock(int scr, int y, int x, BlockType type)
250 if (y >= 0 && y < boardVisible[scr] && x >= 0 && x < boardWidth[scr])
251 PlotBlock1(scr, y, x, type);
254 ExtFunc void PlotUnderline(int scr, int x, int flag)
256 move(boardYPos[scr] + 1, boardXPos[scr] + 2 * x);
257 addstr(flag ? "==" : "--");
260 ExtFunc void ShowDisplayInfo(void)
262 move(statusYPos - 9, statusXPos);
263 printw("Seed: %010d", initSeed);
264 move(statusYPos - 8, statusXPos);
265 printw("Speed: %dms ", speed / 1000);
267 move(statusYPos - 6, statusXPos);
269 addstr("Controlled by a fair robot");
271 addstr("Controlled by a robot");
274 if (opponentFlags & SCF_usingRobot) {
275 move(statusYPos - 5, statusXPos);
276 if (opponentFlags & SCF_fairRobot)
277 addstr("The opponent is a fair robot");
279 addstr("The opponent is a robot");
284 ExtFunc void ShowScore(int scr, int totalDrops, int totalLines, int totalAdds)
287 move(6, statusXPos); addstr("Next: ");
288 move(7, statusXPos + 6); addstr(" ");
289 ShapeIterate(nextShape[scr], scr,
290 ShapeToNetNum(nextShape[scr]) == 15 ? 15 : 16, statusXPos/2 + 4,
291 1, GlanceFunc, NULL);
292 move(statusYPos - 20 + 1, statusXPos);
293 timer = CurTimeval() / 1e6;
294 printw("Lines: %05d", totalLines);
296 printw(" (%.1f ppm)", totalDrops * 60 / timer);
297 move(statusYPos - 18, statusXPos);
298 printw("apm: %.1f", totalAdds * 60 / timer);
300 printw(" (%d%% yield) ", 100 * totalAdds / totalLines);
303 ExtFunc void UpdateOpponentDisplay(void)
306 printw("Playing %s@%s", opponentName, opponentHost);
310 ExtFunc void ShowPause(int pausedByMe, int pausedByThem)
312 move(statusYPos - 3, statusXPos);
314 addstr("Game paused by opponent");
317 move(statusYPos - 2, statusXPos);
319 addstr("Game paused by you");
324 ExtFunc void Message(char *s)
328 // move(statusYPos - 20 + line, statusXPos);
329 move(statusYPos + 2 + line, 1);
330 addstr(s); /* XXX Should truncate long lines */
332 line = (line + 1) % 10;
333 // move(statusYPos - 20 + line, statusXPos);
334 move(statusYPos + 2 + line, 1);
338 ExtFunc void RefreshScreen(void)
341 static char timeStr[2][32];
345 strftime(timeStr[0], 30, "%I:%M %p", localtime(&theTime));
346 // Just in case the local curses library sucks
347 if (strcmp(timeStr[0], timeStr[1]))
349 move(statusYPos, statusXPos);
351 strcpy(timeStr[1], timeStr[0]);
353 move(boardYPos[0] + 1, boardXPos[0] + 2 * boardWidth[0] + 1);
356 move(statusYPos, statusXPos);
357 printw("Timer: %.0f ", CurTimeval() / 1e6);
358 move(boardYPos[0] + 1, boardXPos[0] + 2 * boardWidth[0] + 1);
362 ExtFunc void ScheduleFullRedraw(void)
367 static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event)
369 if (MyRead(gen->fd, &event->u.key, 1))