Imported Upstream version 0.4
[pkg/netris.git] / curses.c
1 /*
2  * Netris -- A free networked version of T*tris
3  * Copyright (C) 1994,1995,1996  Mark H. Weaver <mhw@netris.org>
4  * 
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.
9  * 
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.
14  * 
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.
18  *
19  * $Id: curses.c,v 1.32 1996/02/09 08:47:25 mhw Exp $
20  */
21
22 #include "netris.h"
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <curses.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 static void PlotBlock1(int scr, int y, int x, BlockType type);
30 static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event);
31
32 static EventGenRec keyGen =
33                 { NULL, 0, FT_read, STDIN_FILENO, KeyGenFunc, EM_key };
34
35 static int boardYPos[MAX_SCREENS], boardXPos[MAX_SCREENS];
36 static int statusYPos, statusXPos;
37
38 static char *term_vi;   /* String to make cursor invisible */
39 static char *term_ve;   /* String to make cursor visible */
40
41 ExtFunc void InitScreens(void)
42 {
43         MySigSet oldMask;
44
45         GetTermcapInfo();
46
47         /*
48          * Do this atomically.  Otherwise a badly timed Ctrl-C during
49          * initialization will leave your terminal in a bad state.
50          */
51         BlockSignals(&oldMask, SIGINT, 0);
52         initscr();
53         AtExit(CleanupScreens);
54         RestoreSignals(NULL, &oldMask);
55
56         cbreak();
57         noecho();
58         OutputTermStr(term_vi, 0);
59         AddEventGen(&keyGen);
60
61         move(0, 0);
62         addstr("Netris ");
63         addstr(version_string);
64         addstr(" (C) 1994,1995,1996  Mark H. Weaver     "
65                         "\"netris -h\" for more info");
66         statusYPos = 22;
67         statusXPos = 0;
68 }
69
70 ExtFunc void CleanupScreens(void)
71 {
72         RemoveEventGen(&keyGen);
73         endwin();
74         OutputTermStr(term_ve, 1);
75 }
76
77 ExtFunc void GetTermcapInfo(void)
78 {
79         char *term, *buf, *data;
80         int bufSize = 10240;
81
82         if (!(term = getenv("TERM")))
83                 return;
84         if (tgetent(scratch, term) == 1) {
85                 /*
86                  * Make the buffer HUGE, since tgetstr is unsafe.
87                  * Allocate it on the heap too.
88                  */
89                 data = buf = malloc(bufSize);
90
91                 /*
92                  * There is no standard include file for tgetstr, no prototype
93                  * definitions.  I like casting better than using my own prototypes
94                  * because if I guess the prototype, I might be wrong, especially
95                  * with regards to "const".
96                  */
97                 term_vi = (char *)tgetstr("vi", &data);
98                 term_ve = (char *)tgetstr("ve", &data);
99
100                 /* Okay, so I'm paranoid; I just don't like unsafe routines */
101                 if (data > buf + bufSize)
102                         fatal("tgetstr overflow, you must have a very sick termcap");
103
104                 /* Trim off the unused portion of buffer */
105                 buf = realloc(buf, data - buf);
106         }
107
108         /*
109          * If that fails, use hardcoded vt220 codes.
110          * They don't seem to do anything bad on vt100's, so
111          * we'll try them just in case they work.
112          */
113         if (!term_vi || !term_ve) {
114                 static char *vts[] = {
115                                 "vt100", "vt101", "vt102",
116                                 "vt200", "vt220", "vt300",
117                                 "vt320", "vt400", "vt420",
118                                 "screen", "xterm", NULL };
119                 int i;
120
121                 for (i = 0; vts[i]; i++)
122                         if (!strcmp(term, vts[i]))
123                         {
124                                 term_vi = "\033[?25l";
125                                 term_ve = "\033[?25h";
126                                 break;
127                         }
128         }
129         if (!term_vi || !term_ve)
130                 term_vi = term_ve = NULL;
131 }
132
133 ExtFunc void OutputTermStr(char *str, int flush)
134 {
135         if (str) {
136                 fputs(str, stdout);
137                 if (flush)
138                         fflush(stdout);
139         }
140 }
141
142 ExtFunc void InitScreen(int scr)
143 {
144         int y, x;
145
146         if (scr == 0)
147                 boardXPos[scr] = 1;
148         else
149                 boardXPos[scr] = boardXPos[scr - 1] +
150                                         2 * boardWidth[scr - 1] + 3;
151         boardYPos[scr] = 22;
152         if (statusXPos < boardXPos[scr] + 2 * boardWidth[scr] + 3)
153                 statusXPos = boardXPos[scr] + 2 * boardWidth[scr] + 3;
154         for (y = boardVisible[scr] - 1; y >= 0; --y) {
155                 move(boardYPos[scr] - y, boardXPos[scr] - 1);
156                 addch('|');
157                 move(boardYPos[scr] - y, boardXPos[scr] + 2 * boardWidth[scr]);
158                 addch('|');
159         }
160         for (y = boardVisible[scr]; y >= -1; y -= boardVisible[scr] + 1) {
161                 move(boardYPos[scr] - y, boardXPos[scr] - 1);
162                 addch('+');
163                 for (x = boardWidth[scr] - 1; x >= 0; --x)
164                         addstr("--");
165                 addch('+');
166         }
167 }
168
169 ExtFunc void CleanupScreen(int scr)
170 {
171 }
172
173 static void PlotBlock1(int scr, int y, int x, BlockType type)
174 {
175         move(boardYPos[scr] - y, boardXPos[scr] + 2 * x);
176         switch (type) {
177                 case BT_none:
178                         addstr("  ");
179                         break;
180                 case -BT_piece1:
181                         if (standoutEnable)
182                                 standout();
183                         addstr("$$");
184                         if (standoutEnable)
185                                 standend();
186                         break;
187                 case BT_piece1:
188                         if (standoutEnable)
189                                 standout();
190                         addstr("[]");
191                         if (standoutEnable)
192                                 standend();
193                         break;
194                 default:
195                         assert(0);
196         }
197 }
198
199 ExtFunc void PlotBlock(int scr, int y, int x, BlockType type)
200 {
201         if (y >= 0 && y < boardVisible[scr] && x >= 0 && x < boardWidth[scr])
202                 PlotBlock1(scr, y, x, type);
203 }
204
205 ExtFunc void PlotUnderline(int scr, int x, int flag)
206 {
207         move(boardYPos[scr] + 1, boardXPos[scr] + 2 * x);
208         addstr(flag ? "==" : "--");
209 }
210
211 ExtFunc void ShowDisplayInfo(void)
212 {
213         move(statusYPos - 9, statusXPos);
214         printw("Seed: %d", initSeed);
215         clrtoeol();
216         move(statusYPos - 8, statusXPos);
217         printw("Speed: %dms", speed / 1000);
218         clrtoeol();
219         if (robotEnable) {
220                 move(statusYPos - 6, statusXPos);
221                 if (fairRobot)
222                         addstr("Controlled by a fair robot");
223                 else
224                         addstr("Controlled by a robot");
225                 clrtoeol();
226         }
227         if (opponentFlags & SCF_usingRobot) {
228                 move(statusYPos - 5, statusXPos);
229                 if (opponentFlags & SCF_fairRobot)
230                         addstr("The opponent is a fair robot");
231                 else
232                         addstr("The opponent is a robot");
233                 clrtoeol();
234         }
235 }
236
237 ExtFunc void UpdateOpponentDisplay(void)
238 {
239         move(1, 0);
240         printw("Playing %s@%s", opponentName, opponentHost);
241         clrtoeol();
242 }
243
244 ExtFunc void ShowPause(int pausedByMe, int pausedByThem)
245 {
246         move(statusYPos - 3, statusXPos);
247         if (pausedByThem)
248                 addstr("Game paused by opponent");
249         else
250                 clrtoeol();
251         move(statusYPos - 2, statusXPos);
252         if (pausedByMe)
253                 addstr("Game paused by you");
254         else
255                 clrtoeol();
256 }
257
258 ExtFunc void Message(char *s)
259 {
260         static int line = 0;
261
262         move(statusYPos - 20 + line, statusXPos);
263         addstr(s);      /* XXX Should truncate long lines */
264         clrtoeol();
265         line = (line + 1) % 10;
266         move(statusYPos - 20 + line, statusXPos);
267         clrtoeol();
268 }
269
270 ExtFunc void RefreshScreen(void)
271 {
272         static char timeStr[2][32];
273         time_t theTime;
274
275         time(&theTime);
276         strftime(timeStr[0], 30, "%I:%M %p", localtime(&theTime));
277         /* Just in case the local curses library sucks */
278         if (strcmp(timeStr[0], timeStr[1]))
279         {
280                 move(statusYPos, statusXPos);
281                 addstr(timeStr[0]);
282                 strcpy(timeStr[1], timeStr[0]);
283         }
284         move(boardYPos[0] + 1, boardXPos[0] + 2 * boardWidth[0] + 1);
285         refresh();
286 }
287
288 ExtFunc void ScheduleFullRedraw(void)
289 {
290         touchwin(stdscr);
291 }
292
293 static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event)
294 {
295         if (MyRead(gen->fd, &event->u.key, 1))
296                 return E_key;
297         else
298                 return E_none;
299 }
300
301 /*
302  * vi: ts=4 ai
303  * vim: noai si
304  */