/*- * Copyright (c) 1983-2003, Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University of California, San Francisco nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $OpenBSD: playit.c,v 1.8 2003/06/11 08:45:25 pjanzen Exp $ * $NetBSD: playit.c,v 1.4 1997/10/20 00:37:15 lukem Exp $ * $DragonFly: src/games/hunt/hunt/playit.c,v 1.2 2008/09/04 16:12:51 swildner Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include "hunt.h" #include "display.h" #include "client.h" static int nchar_send; static FLAG Last_player; static int Otto_expect; # define MAX_SEND 5 /* * ibuf is the input buffer used for the stream from the driver. * It is small because we do not check for user input when there * are characters in the input buffer. */ static int icnt = 0; static unsigned char ibuf[256], *iptr = ibuf; #define GETCHR() (--icnt < 0 ? getchr() : *iptr++) static unsigned char getchr(void); static void send_stuff(void); /* * playit: * Play a given game, handling all the curses commands from * the driver. */ void playit(void) { int ch; int y, x; u_int32_t version; int otto_y, otto_x; char otto_face = ' '; int chars_processed; if (read(Socket, &version, sizeof version) != sizeof version) { bad_con(); /* NOTREACHED */ } if (ntohl(version) != (unsigned int)HUNT_VERSION) { bad_ver(); /* NOTREACHED */ } errno = 0; nchar_send = MAX_SEND; Otto_expect = 0; while ((ch = GETCHR()) != EOF) { switch (ch & 0377) { case MOVE: y = GETCHR(); x = GETCHR(); display_move(y, x); break; case CLRTOEOL: display_clear_eol(); break; case CLEAR: display_clear_the_screen(); break; case REFRESH: display_refresh(); break; case REDRAW: display_redraw_screen(); display_refresh(); break; case ENDWIN: display_refresh(); if ((ch = GETCHR()) == LAST_PLAYER) Last_player = TRUE; ch = EOF; goto out; case BELL: display_beep(); break; case READY: chars_processed = GETCHR(); display_refresh(); if (nchar_send < 0) tcflush(STDIN_FILENO, TCIFLUSH); nchar_send = MAX_SEND; if (Otto_mode) { /* * The driver returns the number of keypresses * that it has processed. Use this to figure * out if otto's commands have completed. */ Otto_expect -= chars_processed; if (Otto_expect == 0) { /* not very fair! */ static char buf[MAX_SEND * 2]; int len; /* Ask otto what it wants to do: */ len = otto(otto_y, otto_x, otto_face, buf, sizeof buf); if (len) { /* Pass it on to the driver: */ write(Socket, buf, len); /* Update expectations: */ Otto_expect += len; } } } break; case ADDCH: ch = GETCHR(); /* FALLTHROUGH */ default: if (!isprint(ch)) ch = ' '; display_put_ch(ch); if (Otto_mode) switch (ch) { case '<': case '>': case '^': case 'v': otto_face = ch; display_getyx(&otto_y, &otto_x); otto_x--; break; } break; } } out: (void) close(Socket); } /* * getchr: * Grab input and pass it along to the driver * Return any characters from the driver * When this routine is called by GETCHR, we already know there are * no characters in the input buffer. */ static unsigned char getchr(void) { fd_set readfds, s_readfds; int nfds, s_nfds; FD_ZERO(&s_readfds); FD_SET(Socket, &s_readfds); FD_SET(STDIN_FILENO, &s_readfds); s_nfds = (Socket > STDIN_FILENO) ? Socket : STDIN_FILENO; s_nfds++; one_more_time: do { errno = 0; readfds = s_readfds; nfds = s_nfds; nfds = select(nfds, &readfds, NULL, NULL, NULL); } while (nfds <= 0 && errno == EINTR); if (FD_ISSET(STDIN_FILENO, &readfds)) send_stuff(); if (!FD_ISSET(Socket, &readfds)) goto one_more_time; icnt = read(Socket, ibuf, sizeof ibuf); if (icnt <= 0) { bad_con(); /* NOTREACHED */ } iptr = ibuf; icnt--; return *iptr++; } /* * send_stuff: * Send standard input characters to the driver */ static void send_stuff(void) { int count; char *sp, *nsp; static char inp[BUFSIZ]; static char Buf[BUFSIZ]; /* Drain the user's keystrokes: */ count = read(STDIN_FILENO, Buf, sizeof Buf); if (count < 0) err(1, "read"); if (count == 0) return; if (nchar_send <= 0 && !no_beep) { display_beep(); return; } /* * look for 'q'uit commands; if we find one, * confirm it. If it is not confirmed, strip * it out of the input */ Buf[count] = '\0'; for (sp = Buf, nsp = inp; *sp != '\0'; sp++, nsp++) { *nsp = map_key[(int)*sp]; if (*nsp == 'q') intr(0); } count = nsp - inp; if (count) { nchar_send -= count; if (nchar_send < 0) count += nchar_send; (void) write(Socket, inp, count); if (Otto_mode) { /* * The user can insert commands over otto. * So, otto shouldn't be alarmed when the * server processes more than otto asks for. */ Otto_expect += count; } } } /* * quit: * Handle the end of the game when the player dies */ int quit(int old_status) { int explain, ch; if (Last_player) return Q_QUIT; if (Otto_mode) return otto_quit(old_status); display_move(HEIGHT, 0); display_put_str("Re-enter game [ynwo]? "); display_clear_eol(); explain = FALSE; for (;;) { display_refresh(); if (isupper(ch = getchar())) ch = tolower(ch); if (ch == 'y') return old_status; else if (ch == 'o') break; else if (ch == 'n') { display_move(HEIGHT, 0); display_put_str("Write a parting message [yn]? "); display_clear_eol(); display_refresh(); for (;;) { if (isupper(ch = getchar())) ch = tolower(ch); if (ch == 'y') goto get_message; if (ch == 'n') return Q_QUIT; } } else if (ch == 'w') { static char buf[WIDTH + WIDTH % 2]; char *cp, c; get_message: c = ch; /* save how we got here */ display_move(HEIGHT, 0); display_put_str("Message: "); display_clear_eol(); display_refresh(); cp = buf; for (;;) { display_refresh(); if ((ch = getchar()) == '\n' || ch == '\r') break; if (display_iserasechar(ch)) { if (cp > buf) { int y, x; display_getyx(&y, &x); display_move(y, x - 1); cp -= 1; display_clear_eol(); } continue; } else if (display_iskillchar(ch)) { int y, x; display_getyx(&y, &x); display_move(y, x - (cp - buf)); cp = buf; display_clear_eol(); continue; } else if (!isprint(ch)) { display_beep(); continue; } display_put_ch(ch); *cp++ = ch; if (cp + 1 >= buf + sizeof buf) break; } *cp = '\0'; Send_message = buf; return (c == 'w') ? old_status : Q_MESSAGE; } display_beep(); if (!explain) { display_put_str("(Yes, No, Write message, or Options) "); explain = TRUE; } } display_move(HEIGHT, 0); display_put_str("Scan, Cloak, Flying, or Quit? "); display_clear_eol(); display_refresh(); explain = FALSE; for (;;) { if (isupper(ch = getchar())) ch = tolower(ch); if (ch == 's') return Q_SCAN; else if (ch == 'c') return Q_CLOAK; else if (ch == 'f') return Q_FLY; else if (ch == 'q') return Q_QUIT; display_beep(); if (!explain) { display_put_str("[SCFQ] "); explain = TRUE; } display_refresh(); } } /* * do_message: * Send a message to the driver and return */ void do_message(void) { u_int32_t version; if (read(Socket, &version, sizeof version) != sizeof version) { bad_con(); /* NOTREACHED */ } if (ntohl(version) != (unsigned int)HUNT_VERSION) { bad_ver(); /* NOTREACHED */ } if (write(Socket, Send_message, strlen(Send_message)) < 0) { bad_con(); /* NOTREACHED */ } (void) close(Socket); }