xref: /netbsd/games/hunt/hunt/playit.c (revision 6db346a2)
1*6db346a2Sdholland /*	$NetBSD: playit.c,v 1.25 2014/03/30 05:48:35 dholland Exp $	*/
24052d13dSmrg /*
311967175Swiz  * Copyright (c) 1983-2003, Regents of the University of California.
411967175Swiz  * All rights reserved.
511967175Swiz  *
611967175Swiz  * Redistribution and use in source and binary forms, with or without
711967175Swiz  * modification, are permitted provided that the following conditions are
811967175Swiz  * met:
911967175Swiz  *
1011967175Swiz  * + Redistributions of source code must retain the above copyright
1111967175Swiz  *   notice, this list of conditions and the following disclaimer.
1211967175Swiz  * + Redistributions in binary form must reproduce the above copyright
1311967175Swiz  *   notice, this list of conditions and the following disclaimer in the
1411967175Swiz  *   documentation and/or other materials provided with the distribution.
1511967175Swiz  * + Neither the name of the University of California, San Francisco nor
1611967175Swiz  *   the names of its contributors may be used to endorse or promote
1711967175Swiz  *   products derived from this software without specific prior written
1811967175Swiz  *   permission.
1911967175Swiz  *
2011967175Swiz  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
2111967175Swiz  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2211967175Swiz  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2311967175Swiz  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2411967175Swiz  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2511967175Swiz  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2611967175Swiz  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2711967175Swiz  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2811967175Swiz  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2911967175Swiz  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3011967175Swiz  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
314052d13dSmrg  */
324052d13dSmrg 
33544a5e33Slukem #include <sys/cdefs.h>
34544a5e33Slukem #ifndef lint
35*6db346a2Sdholland __RCSID("$NetBSD: playit.c,v 1.25 2014/03/30 05:48:35 dholland Exp $");
36544a5e33Slukem #endif /* not lint */
37544a5e33Slukem 
38544a5e33Slukem #include <sys/file.h>
39e92308f2Smycroft #include <sys/poll.h>
40ff943cc8Slukem #include <err.h>
41544a5e33Slukem #include <errno.h>
424052d13dSmrg #include <curses.h>
434052d13dSmrg #include <ctype.h>
444052d13dSmrg #include <signal.h>
4509d8e77cSdholland #include <string.h>
46544a5e33Slukem #include <termios.h>
47544a5e33Slukem #include <unistd.h>
4809d8e77cSdholland 
4909d8e77cSdholland #include "hunt_common.h"
5009d8e77cSdholland #include "hunt_private.h"
514052d13dSmrg 
524052d13dSmrg #ifndef FREAD
534052d13dSmrg #define FREAD	1
544052d13dSmrg #endif
554052d13dSmrg 
564052d13dSmrg 
574052d13dSmrg static int nchar_send;
584052d13dSmrg #ifdef OTTO
594052d13dSmrg int Otto_count;
604052d13dSmrg int Otto_mode;
614052d13dSmrg static int otto_y, otto_x;
624052d13dSmrg static char otto_face;
634052d13dSmrg #endif
644052d13dSmrg 
654052d13dSmrg #define MAX_SEND	5
664052d13dSmrg 
674052d13dSmrg /*
684052d13dSmrg  * ibuf is the input buffer used for the stream from the driver.
694052d13dSmrg  * It is small because we do not check for user input when there
704052d13dSmrg  * are characters in the input buffer.
714052d13dSmrg  */
724052d13dSmrg static int icnt = 0;
734052d13dSmrg static unsigned char ibuf[256], *iptr = ibuf;
744052d13dSmrg 
754052d13dSmrg #define GETCHR()	(--icnt < 0 ? getchr() : *iptr++)
764052d13dSmrg 
77cb5fd834Sjsm static unsigned char getchr(void);
78cb5fd834Sjsm static void send_stuff(void);
7975b3905dSdholland static void redraw_screen(void);
80544a5e33Slukem 
814052d13dSmrg /*
824052d13dSmrg  * playit:
834052d13dSmrg  *	Play a given game, handling all the curses commands from
844052d13dSmrg  *	the driver.
854052d13dSmrg  */
86544a5e33Slukem void
playit(void)87fbca3d8cSdholland playit(void)
884052d13dSmrg {
89544a5e33Slukem 	int ch;
90544a5e33Slukem 	int y, x;
919ac5061bSdholland 	uint32_t version;
92a4a1b9dcSdholland 	ssize_t result;
934052d13dSmrg 
94a4a1b9dcSdholland 	result = read(huntsocket, &version, sizeof(version));
95a4a1b9dcSdholland 	if (result != (ssize_t)sizeof(version)) {
964052d13dSmrg 		bad_con();
974052d13dSmrg 		/* NOTREACHED */
984052d13dSmrg 	}
999ac5061bSdholland 	if (ntohl(version) != (uint32_t)HUNT_VERSION) {
1004052d13dSmrg 		bad_ver();
1014052d13dSmrg 		/* NOTREACHED */
1024052d13dSmrg 	}
1034052d13dSmrg 	errno = 0;
1044052d13dSmrg #ifdef OTTO
1054052d13dSmrg 	Otto_count = 0;
1064052d13dSmrg #endif
1074052d13dSmrg 	nchar_send = MAX_SEND;
1084052d13dSmrg 	while ((ch = GETCHR()) != EOF) {
1094052d13dSmrg #ifdef DEBUG
1104052d13dSmrg 		fputc(ch, stderr);
1114052d13dSmrg #endif
1124052d13dSmrg 		switch (ch & 0377) {
1134052d13dSmrg 		  case MOVE:
1144052d13dSmrg 			y = GETCHR();
1154052d13dSmrg 			x = GETCHR();
1164052d13dSmrg 			move(y, x);
1174052d13dSmrg 			break;
1184052d13dSmrg 		  case ADDCH:
1194052d13dSmrg 			ch = GETCHR();
1204052d13dSmrg #ifdef OTTO
1214052d13dSmrg 			switch (ch) {
1224052d13dSmrg 
1234052d13dSmrg 			case '<':
1244052d13dSmrg 			case '>':
1254052d13dSmrg 			case '^':
1264052d13dSmrg 			case 'v':
1274052d13dSmrg 				otto_face = ch;
1284052d13dSmrg 				getyx(stdscr, otto_y, otto_x);
1294052d13dSmrg 				break;
1304052d13dSmrg 			}
1314052d13dSmrg #endif
1328a10ca78Sdholland 			addch(ch);
1334052d13dSmrg 			break;
1344052d13dSmrg 		  case CLRTOEOL:
1358a10ca78Sdholland 			clrtoeol();
1364052d13dSmrg 			break;
1374052d13dSmrg 		  case CLEAR:
1384052d13dSmrg 			clear_the_screen();
1394052d13dSmrg 			break;
1404052d13dSmrg 		  case REFRESH:
1414052d13dSmrg 			refresh();
1424052d13dSmrg 			break;
1434052d13dSmrg 		  case REDRAW:
1444052d13dSmrg 			redraw_screen();
1454052d13dSmrg 			refresh();
1464052d13dSmrg 			break;
1474052d13dSmrg 		  case ENDWIN:
1484052d13dSmrg 			refresh();
1494052d13dSmrg 			if ((ch = GETCHR()) == LAST_PLAYER)
150276cb4ddSdholland 				Last_player = true;
1514052d13dSmrg 			ch = EOF;
1524052d13dSmrg 			goto out;
1534052d13dSmrg 		  case BELL:
1544052d13dSmrg 			beep();
1554052d13dSmrg 			break;
1564052d13dSmrg 		  case READY:
1574052d13dSmrg 			refresh();
1584052d13dSmrg 			if (nchar_send < 0)
159978477fcSdholland 				tcflush(STDIN_FILENO, TCIFLUSH);
1604052d13dSmrg 			nchar_send = MAX_SEND;
1614052d13dSmrg #ifndef OTTO
1624052d13dSmrg 			(void) GETCHR();
1634052d13dSmrg #else
1644052d13dSmrg 			Otto_count -= (GETCHR() & 0xff);
1654052d13dSmrg 			if (!Am_monitor) {
1664052d13dSmrg #ifdef DEBUG
1674052d13dSmrg 				fputc('0' + Otto_count, stderr);
1684052d13dSmrg #endif
1694052d13dSmrg 				if (Otto_count == 0 && Otto_mode)
1704052d13dSmrg 					otto(otto_y, otto_x, otto_face);
1714052d13dSmrg 			}
1724052d13dSmrg #endif
1734052d13dSmrg 			break;
1744052d13dSmrg 		  default:
1754052d13dSmrg #ifdef OTTO
1764052d13dSmrg 			switch (ch) {
1774052d13dSmrg 
1784052d13dSmrg 			case '<':
1794052d13dSmrg 			case '>':
1804052d13dSmrg 			case '^':
1814052d13dSmrg 			case 'v':
1824052d13dSmrg 				otto_face = ch;
1834052d13dSmrg 				getyx(stdscr, otto_y, otto_x);
1844052d13dSmrg 				break;
1854052d13dSmrg 			}
1864052d13dSmrg #endif
1878a10ca78Sdholland 			addch(ch);
1884052d13dSmrg 			break;
1894052d13dSmrg 		}
1904052d13dSmrg 	}
1914052d13dSmrg out:
192ca5d861dSdholland 	(void) close(huntsocket);
1934052d13dSmrg }
1944052d13dSmrg 
1954052d13dSmrg /*
1964052d13dSmrg  * getchr:
1974052d13dSmrg  *	Grab input and pass it along to the driver
1984052d13dSmrg  *	Return any characters from the driver
1994052d13dSmrg  *	When this routine is called by GETCHR, we already know there are
2004052d13dSmrg  *	no characters in the input buffer.
2014052d13dSmrg  */
202544a5e33Slukem static unsigned char
getchr(void)203fbca3d8cSdholland getchr(void)
2044052d13dSmrg {
205e92308f2Smycroft 	struct pollfd set[2];
206e92308f2Smycroft 	int nfds;
2074052d13dSmrg 
208ca5d861dSdholland 	set[0].fd = huntsocket;
209e92308f2Smycroft 	set[0].events = POLLIN;
210978477fcSdholland 	set[1].fd = STDIN_FILENO;
211e92308f2Smycroft 	set[1].events = POLLIN;
2124052d13dSmrg 
2134052d13dSmrg one_more_time:
2144052d13dSmrg 	do {
2154052d13dSmrg 		errno = 0;
216e92308f2Smycroft 		nfds = poll(set, 2, INFTIM);
2174052d13dSmrg 	} while (nfds <= 0 && errno == EINTR);
2184052d13dSmrg 
219e92308f2Smycroft 	if (set[1].revents && POLLIN)
2204052d13dSmrg 		send_stuff();
221e92308f2Smycroft 	if (! (set[0].revents & POLLIN))
2224052d13dSmrg 		goto one_more_time;
223ca5d861dSdholland 	icnt = read(huntsocket, ibuf, sizeof ibuf);
2244052d13dSmrg 	if (icnt < 0) {
2254052d13dSmrg 		bad_con();
2264052d13dSmrg 		/* NOTREACHED */
2274052d13dSmrg 	}
2284052d13dSmrg 	if (icnt == 0)
2294052d13dSmrg 		goto one_more_time;
2304052d13dSmrg 	iptr = ibuf;
2314052d13dSmrg 	icnt--;
2324052d13dSmrg 	return *iptr++;
2334052d13dSmrg }
2344052d13dSmrg 
2354052d13dSmrg /*
2364052d13dSmrg  * send_stuff:
2374052d13dSmrg  *	Send standard input characters to the driver
2384052d13dSmrg  */
239544a5e33Slukem static void
send_stuff(void)240fbca3d8cSdholland send_stuff(void)
2414052d13dSmrg {
242544a5e33Slukem 	int count;
243544a5e33Slukem 	char *sp, *nsp;
2444052d13dSmrg 	static char inp[sizeof Buf];
2454052d13dSmrg 
2463316770aSdholland 	count = read(STDIN_FILENO, Buf, sizeof(Buf) - 1);
2474052d13dSmrg 	if (count <= 0)
2484052d13dSmrg 		return;
2494052d13dSmrg 	if (nchar_send <= 0 && !no_beep) {
250*6db346a2Sdholland 		(void) beep();
2514052d13dSmrg 		return;
2524052d13dSmrg 	}
2534052d13dSmrg 
2544052d13dSmrg 	/*
2554052d13dSmrg 	 * look for 'q'uit commands; if we find one,
2564052d13dSmrg 	 * confirm it.  If it is not confirmed, strip
2574052d13dSmrg 	 * it out of the input
2584052d13dSmrg 	 */
2594052d13dSmrg 	Buf[count] = '\0';
2604052d13dSmrg 	nsp = inp;
2614052d13dSmrg 	for (sp = Buf; *sp != '\0'; sp++)
26250b357ccSdholland 		if ((*nsp = map_key[(unsigned char)*sp]) == 'q')
263544a5e33Slukem 			intr(0);
2644052d13dSmrg 		else
2654052d13dSmrg 			nsp++;
2664052d13dSmrg 	count = nsp - inp;
2674052d13dSmrg 	if (count) {
2684052d13dSmrg #ifdef OTTO
2694052d13dSmrg 		Otto_count += count;
2704052d13dSmrg #endif
2714052d13dSmrg 		nchar_send -= count;
2724052d13dSmrg 		if (nchar_send < 0)
2734052d13dSmrg 			count += nchar_send;
274ca5d861dSdholland 		(void) write(huntsocket, inp, count);
2754052d13dSmrg 	}
2764052d13dSmrg }
2774052d13dSmrg 
2784052d13dSmrg /*
2794052d13dSmrg  * quit:
2804052d13dSmrg  *	Handle the end of the game when the player dies
2814052d13dSmrg  */
282544a5e33Slukem int
quit(int old_status)283fbca3d8cSdholland quit(int old_status)
2844052d13dSmrg {
285276cb4ddSdholland 	bool explain;
286276cb4ddSdholland 	int ch;
2874052d13dSmrg 
2884052d13dSmrg 	if (Last_player)
2894052d13dSmrg 		return Q_QUIT;
2904052d13dSmrg #ifdef OTTO
2914052d13dSmrg 	if (Otto_mode)
2924052d13dSmrg 		return Q_CLOAK;
2934052d13dSmrg #endif
2944052d13dSmrg 	move(HEIGHT, 0);
2958a10ca78Sdholland 	addstr("Re-enter game [ynwo]? ");
2968a10ca78Sdholland 	clrtoeol();
297276cb4ddSdholland 	explain = false;
2984052d13dSmrg 	for (;;) {
2994052d13dSmrg 		refresh();
3004052d13dSmrg 		if (isupper(ch = getchar()))
3014052d13dSmrg 			ch = tolower(ch);
3024052d13dSmrg 		if (ch == 'y')
3034052d13dSmrg 			return old_status;
3044052d13dSmrg 		else if (ch == 'o')
3054052d13dSmrg 			break;
3064052d13dSmrg 		else if (ch == 'n') {
3074052d13dSmrg #ifndef INTERNET
3084052d13dSmrg 			return Q_QUIT;
3094052d13dSmrg #else
3104052d13dSmrg 			move(HEIGHT, 0);
3118a10ca78Sdholland 			addstr("Write a parting message [yn]? ");
3128a10ca78Sdholland 			clrtoeol();
3134052d13dSmrg 			refresh();
3144052d13dSmrg 			for (;;) {
3154052d13dSmrg 				if (isupper(ch = getchar()))
3164052d13dSmrg 					ch = tolower(ch);
3174052d13dSmrg 				if (ch == 'y')
3184052d13dSmrg 					goto get_message;
3194052d13dSmrg 				if (ch == 'n')
3204052d13dSmrg 					return Q_QUIT;
3214052d13dSmrg 			}
3224052d13dSmrg #endif
3234052d13dSmrg 		}
3244052d13dSmrg #ifdef INTERNET
3254052d13dSmrg 		else if (ch == 'w') {
3264052d13dSmrg 			static char buf[WIDTH + WIDTH % 2];
3274052d13dSmrg 			char *cp, c;
3284052d13dSmrg 
3294052d13dSmrg get_message:
3304052d13dSmrg 			c = ch;		/* save how we got here */
3314052d13dSmrg 			move(HEIGHT, 0);
3328a10ca78Sdholland 			addstr("Message: ");
3338a10ca78Sdholland 			clrtoeol();
3344052d13dSmrg 			refresh();
3354052d13dSmrg 			cp = buf;
3364052d13dSmrg 			for (;;) {
3374052d13dSmrg 				refresh();
3384052d13dSmrg 				if ((ch = getchar()) == '\n' || ch == '\r')
3394052d13dSmrg 					break;
34081eafd78Sdholland 				if (ch == erasechar()) {
3414052d13dSmrg 					if (cp > buf) {
3424052d13dSmrg 						int y, x;
3434052d13dSmrg 						getyx(stdscr, y, x);
3444052d13dSmrg 						move(y, x - 1);
3454052d13dSmrg 						cp -= 1;
3468a10ca78Sdholland 						clrtoeol();
3474052d13dSmrg 					}
3484052d13dSmrg 					continue;
3494052d13dSmrg 				}
35081eafd78Sdholland 				else if (ch == killchar()) {
3514052d13dSmrg 					int y, x;
3524052d13dSmrg 					getyx(stdscr, y, x);
3534052d13dSmrg 					move(y, x - (cp - buf));
3544052d13dSmrg 					cp = buf;
3558a10ca78Sdholland 					clrtoeol();
3564052d13dSmrg 					continue;
3574052d13dSmrg 				} else if (!isprint(ch)) {
3584052d13dSmrg 					beep();
3594052d13dSmrg 					continue;
3604052d13dSmrg 				}
3618a10ca78Sdholland 				addch(ch);
3624052d13dSmrg 				*cp++ = ch;
3634052d13dSmrg 				if (cp + 1 >= buf + sizeof buf)
3644052d13dSmrg 					break;
3654052d13dSmrg 			}
3664052d13dSmrg 			*cp = '\0';
3674052d13dSmrg 			Send_message = buf;
3684052d13dSmrg 			return (c == 'w') ? old_status : Q_MESSAGE;
3694052d13dSmrg 		}
3704052d13dSmrg #endif
3714052d13dSmrg 		beep();
3724052d13dSmrg 		if (!explain) {
3738a10ca78Sdholland 			addstr("(Yes, No, Write message, or Options) ");
374276cb4ddSdholland 			explain = true;
3754052d13dSmrg 		}
3764052d13dSmrg 	}
3774052d13dSmrg 
3784052d13dSmrg 	move(HEIGHT, 0);
3794052d13dSmrg #ifdef FLY
3808a10ca78Sdholland 	addstr("Scan, Cloak, Flying, or Quit? ");
3814052d13dSmrg #else
3828a10ca78Sdholland 	addstr("Scan, Cloak, or Quit? ");
3834052d13dSmrg #endif
3848a10ca78Sdholland 	clrtoeol();
3854052d13dSmrg 	refresh();
386276cb4ddSdholland 	explain = false;
3874052d13dSmrg 	for (;;) {
3884052d13dSmrg 		if (isupper(ch = getchar()))
3894052d13dSmrg 			ch = tolower(ch);
3904052d13dSmrg 		if (ch == 's')
3914052d13dSmrg 			return Q_SCAN;
3924052d13dSmrg 		else if (ch == 'c')
3934052d13dSmrg 			return Q_CLOAK;
3944052d13dSmrg #ifdef FLY
3954052d13dSmrg 		else if (ch == 'f')
3964052d13dSmrg 			return Q_FLY;
3974052d13dSmrg #endif
3984052d13dSmrg 		else if (ch == 'q')
3994052d13dSmrg 			return Q_QUIT;
4004052d13dSmrg 		beep();
4014052d13dSmrg 		if (!explain) {
4024052d13dSmrg #ifdef FLY
4038a10ca78Sdholland 			addstr("[SCFQ] ");
4044052d13dSmrg #else
4058a10ca78Sdholland 			addstr("[SCQ] ");
4064052d13dSmrg #endif
407276cb4ddSdholland 			explain = true;
4084052d13dSmrg 		}
4094052d13dSmrg 		refresh();
4104052d13dSmrg 	}
4114052d13dSmrg }
4124052d13dSmrg 
413544a5e33Slukem void
clear_the_screen(void)414fbca3d8cSdholland clear_the_screen(void)
4154052d13dSmrg {
4164052d13dSmrg 	clear();
4174052d13dSmrg 	move(0, 0);
4184052d13dSmrg 	refresh();
4194052d13dSmrg }
4204052d13dSmrg 
42175b3905dSdholland static void
redraw_screen(void)422fbca3d8cSdholland redraw_screen(void)
4234052d13dSmrg {
4244052d13dSmrg 	clearok(stdscr, TRUE);
4254052d13dSmrg 	touchwin(stdscr);
4264052d13dSmrg }
4274052d13dSmrg 
4284052d13dSmrg /*
4294052d13dSmrg  * do_message:
4304052d13dSmrg  *	Send a message to the driver and return
4314052d13dSmrg  */
432544a5e33Slukem void
do_message(void)433fbca3d8cSdholland do_message(void)
4344052d13dSmrg {
4359ac5061bSdholland 	uint32_t version;
436a4a1b9dcSdholland 	ssize_t result;
4374052d13dSmrg 
438a4a1b9dcSdholland 	result = read(huntsocket, &version, sizeof(version));
439a4a1b9dcSdholland 	if (result != (ssize_t)sizeof(version)) {
4404052d13dSmrg 		bad_con();
4414052d13dSmrg 		/* NOTREACHED */
4424052d13dSmrg 	}
4439ac5061bSdholland 	if (ntohl(version) != (uint32_t)HUNT_VERSION) {
4444052d13dSmrg 		bad_ver();
4454052d13dSmrg 		/* NOTREACHED */
4464052d13dSmrg 	}
4474052d13dSmrg #ifdef INTERNET
448ca5d861dSdholland 	if (write(huntsocket, Send_message, strlen(Send_message)) < 0) {
4494052d13dSmrg 		bad_con();
4504052d13dSmrg 		/* NOTREACHED */
4514052d13dSmrg 	}
4524052d13dSmrg #endif
453ca5d861dSdholland 	(void) close(huntsocket);
4544052d13dSmrg }
455