Home | History | Annotate | Line # | Download | only in hunt
      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
     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
    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
    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
    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
    414 clear_the_screen(void)
    415 {
    416 	clear();
    417 	move(0, 0);
    418 	refresh();
    419 }
    420 
    421 static 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
    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