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