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