1 /* $NetBSD: playit.c,v 1.25 2014/03/30 05:48:35 dholland Exp $ */
2 /*
3 * Copyright (c) 1983-2003, Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * + Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * + Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * + Neither the name of the University of California, San Francisco nor
16 * the names of its contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __RCSID("$NetBSD: playit.c,v 1.25 2014/03/30 05:48:35 dholland Exp $");
36 #endif /* not lint */
37
38 #include <sys/file.h>
39 #include <sys/poll.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <curses.h>
43 #include <ctype.h>
44 #include <signal.h>
45 #include <string.h>
46 #include <termios.h>
47 #include <unistd.h>
48
49 #include "hunt_common.h"
50 #include "hunt_private.h"
51
52 #ifndef FREAD
53 #define FREAD 1
54 #endif
55
56
57 static int nchar_send;
58 #ifdef OTTO
59 int Otto_count;
60 int Otto_mode;
61 static int otto_y, otto_x;
62 static char otto_face;
63 #endif
64
65 #define MAX_SEND 5
66
67 /*
68 * ibuf is the input buffer used for the stream from the driver.
69 * It is small because we do not check for user input when there
70 * are characters in the input buffer.
71 */
72 static int icnt = 0;
73 static unsigned char ibuf[256], *iptr = ibuf;
74
75 #define GETCHR() (--icnt < 0 ? getchr() : *iptr++)
76
77 static unsigned char getchr(void);
78 static void send_stuff(void);
79 static void redraw_screen(void);
80
81 /*
82 * playit:
83 * Play a given game, handling all the curses commands from
84 * the driver.
85 */
86 void
playit(void)87 playit(void)
88 {
89 int ch;
90 int y, x;
91 uint32_t version;
92 ssize_t result;
93
94 result = read(huntsocket, &version, sizeof(version));
95 if (result != (ssize_t)sizeof(version)) {
96 bad_con();
97 /* NOTREACHED */
98 }
99 if (ntohl(version) != (uint32_t)HUNT_VERSION) {
100 bad_ver();
101 /* NOTREACHED */
102 }
103 errno = 0;
104 #ifdef OTTO
105 Otto_count = 0;
106 #endif
107 nchar_send = MAX_SEND;
108 while ((ch = GETCHR()) != EOF) {
109 #ifdef DEBUG
110 fputc(ch, stderr);
111 #endif
112 switch (ch & 0377) {
113 case MOVE:
114 y = GETCHR();
115 x = GETCHR();
116 move(y, x);
117 break;
118 case ADDCH:
119 ch = GETCHR();
120 #ifdef OTTO
121 switch (ch) {
122
123 case '<':
124 case '>':
125 case '^':
126 case 'v':
127 otto_face = ch;
128 getyx(stdscr, otto_y, otto_x);
129 break;
130 }
131 #endif
132 addch(ch);
133 break;
134 case CLRTOEOL:
135 clrtoeol();
136 break;
137 case CLEAR:
138 clear_the_screen();
139 break;
140 case REFRESH:
141 refresh();
142 break;
143 case REDRAW:
144 redraw_screen();
145 refresh();
146 break;
147 case ENDWIN:
148 refresh();
149 if ((ch = GETCHR()) == LAST_PLAYER)
150 Last_player = true;
151 ch = EOF;
152 goto out;
153 case BELL:
154 beep();
155 break;
156 case READY:
157 refresh();
158 if (nchar_send < 0)
159 tcflush(STDIN_FILENO, TCIFLUSH);
160 nchar_send = MAX_SEND;
161 #ifndef OTTO
162 (void) GETCHR();
163 #else
164 Otto_count -= (GETCHR() & 0xff);
165 if (!Am_monitor) {
166 #ifdef DEBUG
167 fputc('0' + Otto_count, stderr);
168 #endif
169 if (Otto_count == 0 && Otto_mode)
170 otto(otto_y, otto_x, otto_face);
171 }
172 #endif
173 break;
174 default:
175 #ifdef OTTO
176 switch (ch) {
177
178 case '<':
179 case '>':
180 case '^':
181 case 'v':
182 otto_face = ch;
183 getyx(stdscr, otto_y, otto_x);
184 break;
185 }
186 #endif
187 addch(ch);
188 break;
189 }
190 }
191 out:
192 (void) close(huntsocket);
193 }
194
195 /*
196 * getchr:
197 * Grab input and pass it along to the driver
198 * Return any characters from the driver
199 * When this routine is called by GETCHR, we already know there are
200 * no characters in the input buffer.
201 */
202 static unsigned char
getchr(void)203 getchr(void)
204 {
205 struct pollfd set[2];
206 int nfds;
207
208 set[0].fd = huntsocket;
209 set[0].events = POLLIN;
210 set[1].fd = STDIN_FILENO;
211 set[1].events = POLLIN;
212
213 one_more_time:
214 do {
215 errno = 0;
216 nfds = poll(set, 2, INFTIM);
217 } while (nfds <= 0 && errno == EINTR);
218
219 if (set[1].revents && POLLIN)
220 send_stuff();
221 if (! (set[0].revents & POLLIN))
222 goto one_more_time;
223 icnt = read(huntsocket, ibuf, sizeof ibuf);
224 if (icnt < 0) {
225 bad_con();
226 /* NOTREACHED */
227 }
228 if (icnt == 0)
229 goto one_more_time;
230 iptr = ibuf;
231 icnt--;
232 return *iptr++;
233 }
234
235 /*
236 * send_stuff:
237 * Send standard input characters to the driver
238 */
239 static void
send_stuff(void)240 send_stuff(void)
241 {
242 int count;
243 char *sp, *nsp;
244 static char inp[sizeof Buf];
245
246 count = read(STDIN_FILENO, Buf, sizeof(Buf) - 1);
247 if (count <= 0)
248 return;
249 if (nchar_send <= 0 && !no_beep) {
250 (void) beep();
251 return;
252 }
253
254 /*
255 * look for 'q'uit commands; if we find one,
256 * confirm it. If it is not confirmed, strip
257 * it out of the input
258 */
259 Buf[count] = '\0';
260 nsp = inp;
261 for (sp = Buf; *sp != '\0'; sp++)
262 if ((*nsp = map_key[(unsigned char)*sp]) == 'q')
263 intr(0);
264 else
265 nsp++;
266 count = nsp - inp;
267 if (count) {
268 #ifdef OTTO
269 Otto_count += count;
270 #endif
271 nchar_send -= count;
272 if (nchar_send < 0)
273 count += nchar_send;
274 (void) write(huntsocket, inp, count);
275 }
276 }
277
278 /*
279 * quit:
280 * Handle the end of the game when the player dies
281 */
282 int
quit(int old_status)283 quit(int old_status)
284 {
285 bool explain;
286 int ch;
287
288 if (Last_player)
289 return Q_QUIT;
290 #ifdef OTTO
291 if (Otto_mode)
292 return Q_CLOAK;
293 #endif
294 move(HEIGHT, 0);
295 addstr("Re-enter game [ynwo]? ");
296 clrtoeol();
297 explain = false;
298 for (;;) {
299 refresh();
300 if (isupper(ch = getchar()))
301 ch = tolower(ch);
302 if (ch == 'y')
303 return old_status;
304 else if (ch == 'o')
305 break;
306 else if (ch == 'n') {
307 #ifndef INTERNET
308 return Q_QUIT;
309 #else
310 move(HEIGHT, 0);
311 addstr("Write a parting message [yn]? ");
312 clrtoeol();
313 refresh();
314 for (;;) {
315 if (isupper(ch = getchar()))
316 ch = tolower(ch);
317 if (ch == 'y')
318 goto get_message;
319 if (ch == 'n')
320 return Q_QUIT;
321 }
322 #endif
323 }
324 #ifdef INTERNET
325 else if (ch == 'w') {
326 static char buf[WIDTH + WIDTH % 2];
327 char *cp, c;
328
329 get_message:
330 c = ch; /* save how we got here */
331 move(HEIGHT, 0);
332 addstr("Message: ");
333 clrtoeol();
334 refresh();
335 cp = buf;
336 for (;;) {
337 refresh();
338 if ((ch = getchar()) == '\n' || ch == '\r')
339 break;
340 if (ch == erasechar()) {
341 if (cp > buf) {
342 int y, x;
343 getyx(stdscr, y, x);
344 move(y, x - 1);
345 cp -= 1;
346 clrtoeol();
347 }
348 continue;
349 }
350 else if (ch == killchar()) {
351 int y, x;
352 getyx(stdscr, y, x);
353 move(y, x - (cp - buf));
354 cp = buf;
355 clrtoeol();
356 continue;
357 } else if (!isprint(ch)) {
358 beep();
359 continue;
360 }
361 addch(ch);
362 *cp++ = ch;
363 if (cp + 1 >= buf + sizeof buf)
364 break;
365 }
366 *cp = '\0';
367 Send_message = buf;
368 return (c == 'w') ? old_status : Q_MESSAGE;
369 }
370 #endif
371 beep();
372 if (!explain) {
373 addstr("(Yes, No, Write message, or Options) ");
374 explain = true;
375 }
376 }
377
378 move(HEIGHT, 0);
379 #ifdef FLY
380 addstr("Scan, Cloak, Flying, or Quit? ");
381 #else
382 addstr("Scan, Cloak, or Quit? ");
383 #endif
384 clrtoeol();
385 refresh();
386 explain = false;
387 for (;;) {
388 if (isupper(ch = getchar()))
389 ch = tolower(ch);
390 if (ch == 's')
391 return Q_SCAN;
392 else if (ch == 'c')
393 return Q_CLOAK;
394 #ifdef FLY
395 else if (ch == 'f')
396 return Q_FLY;
397 #endif
398 else if (ch == 'q')
399 return Q_QUIT;
400 beep();
401 if (!explain) {
402 #ifdef FLY
403 addstr("[SCFQ] ");
404 #else
405 addstr("[SCQ] ");
406 #endif
407 explain = true;
408 }
409 refresh();
410 }
411 }
412
413 void
clear_the_screen(void)414 clear_the_screen(void)
415 {
416 clear();
417 move(0, 0);
418 refresh();
419 }
420
421 static void
redraw_screen(void)422 redraw_screen(void)
423 {
424 clearok(stdscr, TRUE);
425 touchwin(stdscr);
426 }
427
428 /*
429 * do_message:
430 * Send a message to the driver and return
431 */
432 void
do_message(void)433 do_message(void)
434 {
435 uint32_t version;
436 ssize_t result;
437
438 result = read(huntsocket, &version, sizeof(version));
439 if (result != (ssize_t)sizeof(version)) {
440 bad_con();
441 /* NOTREACHED */
442 }
443 if (ntohl(version) != (uint32_t)HUNT_VERSION) {
444 bad_ver();
445 /* NOTREACHED */
446 }
447 #ifdef INTERNET
448 if (write(huntsocket, Send_message, strlen(Send_message)) < 0) {
449 bad_con();
450 /* NOTREACHED */
451 }
452 #endif
453 (void) close(huntsocket);
454 }
455