(linenum→info "unix/slp.c:2238")

bsd-games/2.17/hunt/hunt/playit.c

    1: /*      $NetBSD: playit.c,v 1.8 2004/01/27 20:30:29 jsm 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.8 2004/01/27 20:30:29 jsm 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       <sys/time.h>
   46: # if defined(HPUX) || (defined(BSD_RELEASE) && BSD_RELEASE >= 44)
   47: # include       <termios.h>
   48: # include       <unistd.h>
   49: # endif
   50: # include       "hunt.h"
   51: 
   52: # ifndef FREAD
   53: # define        FREAD  1
   54: # endif
   55: 
   56: # if !defined(USE_CURSES) || !defined(TERMINFO)
   57: # define        beep()         (void) putchar(CTRL('G'))
   58: # endif
   59: # if !defined(USE_CURSES)
   60: # undef         refresh
   61: # define        refresh()      (void) fflush(stdout);
   62: # endif
   63: # ifdef USE_CURSES
   64: # define        clear_eol()    clrtoeol()
   65: # define        put_ch         addch
   66: # define        put_str                addstr
   67: # endif
   68: 
   69: static int      nchar_send;
   70: # ifndef USE_CURSES
   71: char            screen[SCREEN_HEIGHT][SCREEN_WIDTH2], blanks[SCREEN_WIDTH];
   72: int             cur_row, cur_col;
   73: # endif
   74: # ifdef OTTO
   75: int             Otto_count;
   76: int             Otto_mode;
   77: static int      otto_y, otto_x;
   78: static char     otto_face;
   79: # endif
   80: 
   81: # define        MAX_SEND       5
   82: # define        STDIN          0
   83: 
   84: /*
   85:  * ibuf is the input buffer used for the stream from the driver.
   86:  * It is small because we do not check for user input when there
   87:  * are characters in the input buffer.
   88:  */
   89: static int              icnt = 0;
   90: static unsigned char    ibuf[256], *iptr = ibuf;
   91: 
   92: #define GETCHR()        (--icnt < 0 ? getchr() : *iptr++)
   93: 
   94: #if !defined(BSD_RELEASE) || BSD_RELEASE < 44
   95: extern int      _putchar();
   96: #endif
   97: 
   98: static  unsigned char    getchr(void);
   99: static  void             send_stuff(void);
  100: 
  101: /*
  102:  * playit:
  103:  *      Play a given game, handling all the curses commands from
  104:  *      the driver.
  105:  */
  106: void
  107: playit()
  108: {
  109:         int            ch;
  110:         int            y, x;
  111:         u_int32_t      version;
  112: 
  113:         if (read(Socket, (char *) &version, LONGLEN) != LONGLEN) {
  114:                 bad_con();
  115:                 /* NOTREACHED */
  116:         }
  117:         if (ntohl(version) != (unsigned long)HUNT_VERSION) {
  118:                 bad_ver();
  119:                 /* NOTREACHED */
  120:         }
  121:         errno = 0;
  122: # ifdef OTTO
  123:         Otto_count = 0;
  124: # endif
  125:         nchar_send = MAX_SEND;
  126:         while ((ch = GETCHR()) != EOF) {
  127: # ifdef DEBUG
  128:                 fputc(ch, stderr);
  129: # endif
  130:                 switch (ch & 0377) {
  131:                   case MOVE:
  132:                         y = GETCHR();
  133:                         x = GETCHR();
  134: # ifdef USE_CURSES
  135:                         move(y, x);
  136: # else
  137:                         mvcur(cur_row, cur_col, y, x);
  138:                         cur_row = y;
  139:                         cur_col = x;
  140: # endif
  141:                         break;
  142:                   case ADDCH:
  143:                         ch = GETCHR();
  144: # ifdef OTTO
  145:                         switch (ch) {
  146: 
  147:                         case '<':
  148:                         case '>':
  149:                         case '^':
  150:                         case 'v':
  151:                                 otto_face = ch;
  152: # ifdef USE_CURSES
  153:                                 getyx(stdscr, otto_y, otto_x);
  154: # else
  155:                                 otto_y = cur_row;
  156:                                 otto_x = cur_col;
  157: # endif
  158:                                 break;
  159:                         }
  160: # endif
  161:                         put_ch(ch);
  162:                         break;
  163:                   case CLRTOEOL:
  164:                         clear_eol();
  165:                         break;
  166:                   case CLEAR:
  167:                         clear_the_screen();
  168:                         break;
  169:                   case REFRESH:
  170:                         refresh();
  171:                         break;
  172:                   case REDRAW:
  173:                         redraw_screen();
  174:                         refresh();
  175:                         break;
  176:                   case ENDWIN:
  177:                         refresh();
  178:                         if ((ch = GETCHR()) == LAST_PLAYER)
  179:                                 Last_player = TRUE;
  180:                         ch = EOF;
  181:                         goto out;
  182:                   case BELL:
  183:                         beep();
  184:                         break;
  185:                   case READY:
  186:                         refresh();
  187:                         if (nchar_send < 0)
  188: # if defined(HPUX) || (defined(BSD_RELEASE) && BSD_RELEASE >= 44)
  189:                                 tcflush(STDIN, TCIFLUSH);
  190: # else
  191: # ifndef TCFLSH
  192:                                 (void) ioctl(STDIN, TIOCFLUSH, &in);
  193: # else
  194:                                 (void) ioctl(STDIN, TCFLSH, 0);
  195: # endif
  196: # endif
  197:                         nchar_send = MAX_SEND;
  198: # ifndef OTTO
  199:                         (void) GETCHR();
  200: # else
  201:                         Otto_count -= (GETCHR() & 0xff);
  202:                         if (!Am_monitor) {
  203: # ifdef DEBUG
  204:                                 fputc('0' + Otto_count, stderr);
  205: # endif
  206:                                 if (Otto_count == 0 && Otto_mode)
  207:                                         otto(otto_y, otto_x, otto_face);
  208:                         }
  209: # endif
  210:                         break;
  211:                   default:
  212: # ifdef OTTO
  213:                         switch (ch) {
  214: 
  215:                         case '<':
  216:                         case '>':
  217:                         case '^':
  218:                         case 'v':
  219:                                 otto_face = ch;
  220: # ifdef USE_CURSES
  221:                                 getyx(stdscr, otto_y, otto_x);
  222: # else
  223:                                 otto_y = cur_row;
  224:                                 otto_x = cur_col;
  225: # endif
  226:                                 break;
  227:                         }
  228: # endif
  229:                         put_ch(ch);
  230:                         break;
  231:                 }
  232:         }
  233: out:
  234:         (void) close(Socket);
  235: }
  236: 
  237: /*
  238:  * getchr:
  239:  *      Grab input and pass it along to the driver
  240:  *      Return any characters from the driver
  241:  *      When this routine is called by GETCHR, we already know there are
  242:  *      no characters in the input buffer.
  243:  */
  244: static unsigned char
  245: getchr()
  246: {
  247:         struct pollfd set[2];
  248:         int    nfds;
  249: 
  250:         set[0].fd = Socket;
  251:         set[0].events = POLLIN;
  252:         set[1].fd = STDIN;
  253:         set[1].events = POLLIN;
  254: 
  255: one_more_time:
  256:         do {
  257:                 errno = 0;
  258:                 nfds = poll(set, 2, INFTIM);
  259:         } while (nfds <= 0 && errno == EINTR);
  260: 
  261:         if (set[1].revents && POLLIN)
  262:                 send_stuff();
  263:         if (! (set[0].revents & POLLIN))
  264:                 goto one_more_time;
  265:         icnt = read(Socket, ibuf, sizeof ibuf);
  266:         if (icnt < 0) {
  267:                 bad_con();
  268:                 /* NOTREACHED */
  269:         }
  270:         if (icnt == 0)
  271:                 goto one_more_time;
  272:         iptr = ibuf;
  273:         icnt--;
  274:         return *iptr++;
  275: }
  276: 
  277: /*
  278:  * send_stuff:
  279:  *      Send standard input characters to the driver
  280:  */
  281: static void
  282: send_stuff()
  283: {
  284:         int            count;
  285:         char           *sp, *nsp;
  286:         static char    inp[sizeof Buf];
  287: 
  288:         count = read(STDIN, Buf, sizeof Buf);
  289:         if (count <= 0)
  290:                 return;
  291:         if (nchar_send <= 0 && !no_beep) {
  292:                 (void) write(1, "\7", 1);     /* CTRL('G') */
  293:                 return;
  294:         }
  295: 
  296:         /*
  297:          * look for 'q'uit commands; if we find one,
  298:          * confirm it.  If it is not confirmed, strip
  299:          * it out of the input
  300:          */
  301:         Buf[count] = '\0';
  302:         nsp = inp;
  303:         for (sp = Buf; *sp != '\0'; sp++)
  304:                 if ((*nsp = map_key[(int)*sp]) == 'q')
  305:                         intr(0);
  306:                 else
  307:                         nsp++;
  308:         count = nsp - inp;
  309:         if (count) {
  310: # ifdef OTTO
  311:                 Otto_count += count;
  312: # endif
  313:                 nchar_send -= count;
  314:                 if (nchar_send < 0)
  315:                         count += nchar_send;
  316:                 (void) write(Socket, inp, count);
  317:         }
  318: }
  319: 
  320: /*
  321:  * quit:
  322:  *      Handle the end of the game when the player dies
  323:  */
  324: int
  325: quit(old_status)
  326:         int    old_status;
  327: {
  328:         int    explain, ch;
  329: 
  330:         if (Last_player)
  331:                 return Q_QUIT;
  332: # ifdef OTTO
  333:         if (Otto_mode)
  334:                 return Q_CLOAK;
  335: # endif
  336: # ifdef USE_CURSES
  337:         move(HEIGHT, 0);
  338: # else
  339:         mvcur(cur_row, cur_col, HEIGHT, 0);
  340:         cur_row = HEIGHT;
  341:         cur_col = 0;
  342: # endif
  343:         put_str("Re-enter game [ynwo]? ");
  344:         clear_eol();
  345:         explain = FALSE;
  346:         for (;;) {
  347:                 refresh();
  348:                 if (isupper(ch = getchar()))
  349:                         ch = tolower(ch);
  350:                 if (ch == 'y')
  351:                         return old_status;
  352:                 else if (ch == 'o')
  353:                         break;
  354:                 else if (ch == 'n') {
  355: # ifndef INTERNET
  356:                         return Q_QUIT;
  357: # else
  358: # ifdef USE_CURSES
  359:                         move(HEIGHT, 0);
  360: # else
  361:                         mvcur(cur_row, cur_col, HEIGHT, 0);
  362:                         cur_row = HEIGHT;
  363:                         cur_col = 0;
  364: # endif
  365:                         put_str("Write a parting message [yn]? ");
  366:                         clear_eol();
  367:                         refresh();
  368:                         for (;;) {
  369:                                 if (isupper(ch = getchar()))
  370:                                         ch = tolower(ch);
  371:                                 if (ch == 'y')
  372:                                         goto get_message;
  373:                                 if (ch == 'n')
  374:                                         return Q_QUIT;
  375:                         }
  376: # endif
  377:                 }
  378: # ifdef INTERNET
  379:                 else if (ch == 'w') {
  380:                         static       char  buf[WIDTH + WIDTH % 2];
  381:                         char         *cp, c;
  382: 
  383: get_message:
  384:                         c = ch;              /* save how we got here */
  385: # ifdef USE_CURSES
  386:                         move(HEIGHT, 0);
  387: # else
  388:                         mvcur(cur_row, cur_col, HEIGHT, 0);
  389:                         cur_row = HEIGHT;
  390:                         cur_col = 0;
  391: # endif
  392:                         put_str("Message: ");
  393:                         clear_eol();
  394:                         refresh();
  395:                         cp = buf;
  396:                         for (;;) {
  397:                                 refresh();
  398:                                 if ((ch = getchar()) == '\n' || ch == '\r')
  399:                                         break;
  400: # if defined(TERMINFO) || BSD_RELEASE >= 44
  401:                                 if (ch == erasechar())
  402: # else
  403:                                 if (ch == _tty.sg_erase)
  404: # endif
  405:                                 {
  406:                                         if (cp > buf) {
  407: # ifdef USE_CURSES
  408:                                                 int y, x;
  409:                                                 getyx(stdscr, y, x);
  410:                                                 move(y, x - 1);
  411: # else
  412:                                                 mvcur(cur_row, cur_col, cur_row,
  413:                                                                 cur_col - 1);
  414:                                                 cur_col -= 1;
  415: # endif
  416:                                                 cp -= 1;
  417:                                                 clear_eol();
  418:                                         }
  419:                                         continue;
  420:                                 }
  421: # if defined(TERMINFO) || BSD_RELEASE >= 44
  422:                                 else if (ch == killchar())
  423: # else
  424:                                 else if (ch == _tty.sg_kill)
  425: # endif
  426:                                 {
  427: # ifdef USE_CURSES
  428:                                         int y, x;
  429:                                         getyx(stdscr, y, x);
  430:                                         move(y, x - (cp - buf));
  431: # else
  432:                                         mvcur(cur_row, cur_col, cur_row,
  433:                                                         cur_col - (cp - buf));
  434:                                         cur_col -= cp - buf;
  435: # endif
  436:                                         cp = buf;
  437:                                         clear_eol();
  438:                                         continue;
  439:                                 } else if (!isprint(ch)) {
  440:                                         beep();
  441:                                         continue;
  442:                                 }
  443:                                 put_ch(ch);
  444:                                 *cp++ = ch;
  445:                                 if (cp + 1 >= buf + sizeof buf)
  446:                                         break;
  447:                         }
  448:                         *cp = '\0';
  449:                         Send_message = buf;
  450:                         return (c == 'w') ? old_status : Q_MESSAGE;
  451:                 }
  452: # endif
  453:                 beep();
  454:                 if (!explain) {
  455:                         put_str("(Yes, No, Write message, or Options) ");
  456:                         explain = TRUE;
  457:                 }
  458:         }
  459: 
  460: # ifdef USE_CURSES
  461:         move(HEIGHT, 0);
  462: # else
  463:         mvcur(cur_row, cur_col, HEIGHT, 0);
  464:         cur_row = HEIGHT;
  465:         cur_col = 0;
  466: # endif
  467: # ifdef FLY
  468:         put_str("Scan, Cloak, Flying, or Quit? ");
  469: # else
  470:         put_str("Scan, Cloak, or Quit? ");
  471: # endif
  472:         clear_eol();
  473:         refresh();
  474:         explain = FALSE;
  475:         for (;;) {
  476:                 if (isupper(ch = getchar()))
  477:                         ch = tolower(ch);
  478:                 if (ch == 's')
  479:                         return Q_SCAN;
  480:                 else if (ch == 'c')
  481:                         return Q_CLOAK;
  482: # ifdef FLY
  483:                 else if (ch == 'f')
  484:                         return Q_FLY;
  485: # endif
  486:                 else if (ch == 'q')
  487:                         return Q_QUIT;
  488:                 beep();
  489:                 if (!explain) {
  490: # ifdef FLY
  491:                         put_str("[SCFQ] ");
  492: # else
  493:                         put_str("[SCQ] ");
  494: # endif
  495:                         explain = TRUE;
  496:                 }
  497:                 refresh();
  498:         }
  499: }
  500: 
  501: # ifndef USE_CURSES
  502: void
  503: put_ch(ch)
  504:         char   ch;
  505: {
  506:         if (!isprint(ch)) {
  507:                 fprintf(stderr, "r,c,ch: %d,%d,%d", cur_row, cur_col, ch);
  508:                 return;
  509:         }
  510:         screen[cur_row][cur_col] = ch;
  511:         putchar(ch);
  512:         if (++cur_col >= COLS) {
  513:                 if (!AM || XN)
  514:                         putchar('\n');
  515:                 cur_col = 0;
  516:                 if (++cur_row >= LINES)
  517:                         cur_row = LINES;
  518:         }
  519: }
  520: 
  521: void
  522: put_str(s)
  523:         const char     *s;
  524: {
  525:         while (*s)
  526:                 put_ch(*s++);
  527: }
  528: # endif
  529: 
  530: void
  531: clear_the_screen()
  532: {
  533: # ifdef USE_CURSES
  534:         clear();
  535:         move(0, 0);
  536:         refresh();
  537: # else
  538:         int    i;
  539: 
  540:         if (blanks[0] == '\0')
  541:                 for (i = 0; i < SCREEN_WIDTH; i++)
  542:                         blanks[i] = ' ';
  543: 
  544:         if (CL != NULL) {
  545: #if !defined(BSD_RELEASE) || BSD_RELEASE < 44
  546:                 tputs(CL, LINES, _putchar);