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