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