1: /* 2: * Hunt 3: * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold 4: * San Francisco, California 5: * 6: * Copyright (c) 1985 Regents of the University of California. 7: * All rights reserved. The Berkeley software License Agreement 8: * specifies the terms and conditions for redistribution. 9: * 10: * 1997/9/9 - updated to use sigprocmask (and compute the alarm mask correctly) 11: */ 12: 13: # include "hunt.h" 14: # include <signal.h> 15: # include <errno.h> 16: # include <sys/ioctl.h> 17: # include <sys/time.h> 18: 19: # ifndef pdp11 20: # define RN (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff) 21: # else pdp11 22: # define RN ((Seed = Seed * 11109 + 13849) & 0x7fff) 23: # endif pdp11 24: 25: int Seed = 0; 26: 27: # ifdef CONSTANT_MOVE 28: static struct itimerval Timing; 29: # endif CONSTANT_MOVE 30: 31: SOCKET Daemon; 32: # ifdef INTERNET 33: int Test_socket; /* test socket to answer datagrams */ 34: # define DAEMON_SIZE (sizeof Daemon) 35: # else INTERNET 36: # define DAEMON_SIZE (sizeof Daemon - 1) 37: # endif INTERNET 38: 39: /* 40: * main: 41: * The main program. 42: */ 43: main() 44: { 45: register PLAYER *pp; 46: register int had_char; 47: # ifdef INTERNET 48: register long test_mask; 49: int msg; 50: int namelen; 51: SOCKET test; 52: # endif INTERNET 53: # ifdef CONSTANT_MOVE 54: sigset_t alarm_sigset; 55: # endif CONSTANT_MOVE 56: static long read_fds; 57: 58: init(); 59: Sock_mask = (1 << Socket); 60: # ifdef INTERNET 61: test_mask = (1 << Test_socket); 62: # endif INTERNET 63: 64: # ifdef CONSTANT_MOVE 65: sigemptyset(&alarm_sigset); 66: sigaddset(&alarm_sigset, SIGALRM); 67: (void) sigprocmask(SIG_BLOCK, &alarm_sigset, NULL); 68: (void) signal(SIGALRM, moveshots); 69: # endif CONSTANT_MOVE 70: 71: while (Nplayer > 0) { 72: # ifdef CONSTANT_MOVE 73: (void) sigprocmask(SIG_UNBLOCK, &alarm_sigset, NULL); 74: # endif CONSTANT_MOVE 75: read_fds = Fds_mask; 76: errno = 0; 77: # ifndef OLDIPC 78: while (select(Num_fds, &read_fds, (int *) NULL, 79: (int *) NULL, (struct timeval *) NULL) < 0) 80: # else OLDIPC 81: while (select(20, &read_fds, NULL, 32767) < 0) 82: # endif OLDIPC 83: { 84: if (errno != EINTR) 85: perror("select"); 86: if (Nplayer == 0) 87: goto out; 88: errno = 0; 89: } 90: Have_inp = read_fds; 91: # ifdef CONSTANT_MOVE 92: (void) sigprocmask(SIG_BLOCK, &alarm_sigset, NULL); 93: # endif CONSTANT_MOVE 94: # ifdef INTERNET 95: if (read_fds & test_mask) { 96: namelen = DAEMON_SIZE; 97: # ifndef OLDIPC 98: (void) recvfrom(Test_socket, (char *) &msg, sizeof msg, 99: 0, (struct sockaddr *) &test, &namelen); 100: (void) sendto(Test_socket, (char *) &msg, sizeof msg, 101: 0, (struct sockaddr *) &test, DAEMON_SIZE); 102: # else OLDIPC 103: (void) receive(Test_socket, (struct sockaddr *) &test, 104: (char *) &msg, sizeof msg); 105: (void) send(Test_socket, (struct sockaddr *) &test, 106: (char *) &msg, sizeof msg); 107: # endif OLDIPC 108: } 109: # endif INTERNET 110: for (;;) { 111: had_char = FALSE; 112: for (pp = Player; pp < End_player; pp++) 113: if (havechar(pp)) { 114: execute(pp); 115: pp->p_nexec++; 116: had_char++; 117: } 118: # ifdef MONITOR 119: for (pp = Monitor; pp < End_monitor; pp++) 120: if (havechar(pp)) { 121: mon_execute(pp); 122: pp->p_nexec++; 123: had_char++; 124: } 125: # endif MONITOR 126: if (!had_char) 127: break; 128: # ifdef CONSTANT_MOVE 129: for (pp = Player; pp < End_player; pp++) { 130: look(pp); 131: sendcom(pp, REFRESH); 132: } 133: # ifdef MONITOR 134: for (pp = Monitor; pp < End_monitor; pp++) 135: sendcom(pp, REFRESH); 136: # endif MONITOR 137: # else CONSTANT_MOVE 138: moveshots(); 139: # endif CONSTANT_MOVE 140: for (pp = Player; pp < End_player; ) 141: if (pp->p_death[0] != '\0') 142: zap(pp, TRUE); 143: else 144: pp++; 145: # ifdef MONITOR 146: for (pp = Monitor; pp < End_monitor; ) 147: if (pp->p_death[0] != '\0') 148: zap(pp, FALSE); 149: else 150: pp++; 151: # endif MONITOR 152: } 153: if (read_fds & Sock_mask) 154: answer(); 155: for (pp = Player; pp < End_player; pp++) { 156: if (read_fds & pp->p_mask) 157: sendcom(pp, READY, pp->p_nexec); 158: pp->p_nexec = 0; 159: (void) fflush(pp->p_output); 160: } 161: # ifdef MONITOR 162: for (pp = Monitor; pp < End_monitor; pp++) { 163: if (read_fds & pp->p_mask) 164: sendcom(pp, READY, pp->p_nexec); 165: pp->p_nexec = 0; 166: (void) fflush(pp->p_output); 167: } 168: # endif MONITOR 169: } 170: out: 171: # ifdef CONSTANT_MOVE 172: bul_alarm(0); 173: # endif CONSTANT_MOVE 174: 175: # ifdef MONITOR 176: for (pp = Monitor; pp < End_monitor; ) 177: zap(pp, FALSE); 178: # endif MONITOR 179: cleanup(0); 180: } 181: 182: /* 183: * init: 184: * Initialize the global parameters. 185: */ 186: init() 187: { 188: register int i; 189: # ifdef INTERNET 190: SOCKET test_port; 191: auto int msg; 192: # endif INTERNET 193: int cleanup(); 194: 195: # ifndef DEBUG 196: (void) ioctl(fileno(stdout), TIOCNOTTY, NULL); 197: (void) setpgrp(getpid(), getpid()); 198: (void) signal(SIGHUP, SIG_IGN); 199: (void) signal(SIGINT, SIG_IGN); 200: (void) signal(SIGQUIT, SIG_IGN); 201: (void) signal(SIGTERM, cleanup); 202: # endif DEBUG 203: 204: (void) chdir("/usr/tmp"); /* just in case it core dumps */ 205: (void) signal(SIGPIPE, SIG_IGN); 206: 207: # ifdef INTERNET 208: Daemon.sin_family = SOCK_FAMILY; 209: # ifdef OLD 210: if (gethostname(local_name, sizeof local_name) < 0) { 211: perror("gethostname"); 212: exit(1); 213: } 214: if ((hp = gethostbyname(local_name)) == NULL) { 215: fprintf(stderr, "Unknown host %s\n", local_name); 216: exit(1); 217: } 218: bcopy(hp->h_addr, &(Daemon.sin_addr.s_addr), hp->h_length); 219: # else 220: Daemon.sin_addr.s_addr = INADDR_ANY; 221: # endif OLD 222: Daemon.sin_port = htons(Sock_port); 223: # else INTERNET 224: Daemon.sun_family = SOCK_FAMILY; 225: (void) strcpy(Daemon.sun_path, Sock_name); 226: # endif INTERNET 227: 228: # ifndef OLDIPC 229: Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0); 230: # else OLDIPC 231: Socket = socket(SOCK_STREAM, 0, (struct sockaddr *) &Daemon, 232: SO_ACCEPTCONN); 233: # endif OLDIPC 234: # if defined(INTERNET) && !defined(OLDIPC) 235: if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, &msg, sizeof msg)<0) 236: perror("setsockopt loopback"); 237: # endif INTERNET 238: # ifndef OLDIPC 239: if (bind(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) { 240: if (errno == EADDRINUSE) 241: exit(0); 242: else { 243: perror("bind"); 244: cleanup(1); 245: } 246: } 247: (void) listen(Socket, 5); 248: # endif OLDIPC 249: Fds_mask = (1 << Socket); 250: Num_fds = Socket + 1; 251: 252: # ifdef INTERNET 253: test_port = Daemon; 254: test_port.sin_port = htons(Test_port); 255: 256: # ifndef OLDIPC 257: Test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0); 258: if (bind(Test_socket, (struct sockaddr *) &test_port, 259: DAEMON_SIZE) < 0) { 260: perror("bind"); 261: exit(1); 262: } 263: (void) listen(Test_socket, 5); 264: # else OLDIPC 265: Test_socket = socket(SOCK_DGRAM, 0, (struct sockaddr *) &test_port, 0); 266: # endif OLDIPC 267: Fds_mask |= (1 << Test_socket); 268: if (Test_socket > Socket) 269: Num_fds = Test_socket + 1; 270: # endif INTERNET 271: 272: Seed = getpid() + time((time_t *) NULL); 273: makemaze(); 274: 275: for (i = 0; i < NASCII; i++) 276: See_over[i] = TRUE; 277: See_over[DOOR] = FALSE; 278: See_over[WALL1] = FALSE; 279: See_over[WALL2] = FALSE; 280: See_over[WALL3] = FALSE; 281: # ifdef REFLECT 282: See_over[WALL4] = FALSE; 283: See_over[WALL5] = FALSE; 284: # endif REFLECT 285: 286: # ifdef CONSTANT_MOVE 287: getitimer(ITIMER_REAL, &Timing); 288: Timing.it_interval.tv_sec = 0; 289: Timing.it_interval.tv_usec = 500; 290: Timing.it_value.tv_sec = 0; 291: Timing.it_value.tv_usec = 0; 292: setitimer(ITIMER_REAL, &Timing, NULL); 293: # endif CONSTANT_MOVE 294: 295: answer(); 296: } 297: 298: # ifdef CONSTANT_MOVE 299: /* 300: * bul_alarm: 301: * Set up the alarm for the bullets 302: */ 303: bul_alarm(val) 304: int val; 305: { 306: Timing.it_value.tv_usec = val * Timing.it_interval.tv_usec; 307: setitimer(ITIMER_REAL, &Timing, NULL); 308: } 309: # endif CONSTANT_MOVE 310: 311: /* 312: * checkdam: 313: * Check the damage to the given player, and see if s/he is killed 314: */ 315: checkdam(ouch, gotcha, credit, amt, shot_type) 316: register PLAYER *ouch, *gotcha; 317: register IDENT *credit; 318: int amt; 319: char shot_type; 320: { 321: register char *cp; 322: 323: if (ouch->p_death[0] != '\0') 324: return; 325: if (rand_num(100) < 5) { 326: message(ouch, "Missed you by a hair"); 327: if (gotcha != NULL) 328: message(gotcha, "Missed him"); 329: return; 330: } 331: ouch->p_damage += amt; 332: if (ouch->p_damage <= ouch->p_damcap) { 333: (void) sprintf(Buf, "%2d", ouch->p_damage); 334: cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL); 335: outstr(ouch, Buf, 2); 336: return; 337: } 338: 339: /* Someone DIED */ 340: switch (shot_type) { 341: default: 342: cp = "Killed"; 343: break; 344: # ifdef FLY 345: case FALL: 346: cp = "Killed on impact"; 347: break; 348: # endif FLY 349: case KNIFE: 350: cp = "Stabbed to death"; 351: break; 352: case SHOT: 353: cp = "Shot to death"; 354: break; 355: case GRENADE: 356: case SATCHEL: 357: case BOMB: 358: cp = "Bombed"; 359: break; 360: case MINE: 361: case GMINE: 362: cp = "Blown apart"; 363: break; 364: # ifdef OOZE 365: case SLIME: 366: cp = "Slimed"; 367: break; 368: # endif OOZE 369: # ifdef VOLCANO 370: case LAVA: 371: cp = "Baked"; 372: break; 373: # endif VOLCANO 374: } 375: if (credit == NULL) { 376: (void) sprintf(ouch->p_death, "| %s by %s |", cp, 377: (shot_type == MINE || shot_type == GMINE) ? 378: "a mine" : "act of God"); 379: return; 380: } 381: 382: (void) sprintf(ouch->p_death, "| %s by %s |", cp, credit->i_name); 383: 384: credit->i_kills++; 385: credit->i_score = credit->i_kills / (double) credit->i_entries; 386: if (gotcha == NULL) 387: return; 388: gotcha->p_damcap += STABDAM; 389: gotcha->p_damage -= STABDAM; 390: if (gotcha->p_damage < 0) 391: gotcha->p_damage = 0; 392: (void) sprintf(Buf, "%2d/%2d", gotcha->p_damage, gotcha->p_damcap); 393: cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL); 394: outstr(gotcha, Buf, 5); 395: (void) sprintf(Buf, "%3d", (gotcha->p_damcap - MAXDAM) / 2); 396: cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL); 397: outstr(gotcha, Buf, 3); 398: (void) sprintf(Buf, "%5.2f", gotcha->p_ident->i_score); 399: for (ouch = Player; ouch < End_player; ouch++) { 400: cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player), 401: STAT_NAME_COL); 402: outstr(ouch, Buf, 5); 403: } 404: } 405: 406: /* 407: * zap: 408: * Kill off a player and take him out of the game. 409: */ 410: zap(pp, was_player) 411: register PLAYER *pp; 412: FLAG was_player; 413: { 414: register int i, len; 415: register BULLET *bp; 416: register PLAYER *np; 417: register int x, y; 418: int savefd, savemask; 419: 420: if (was_player) { 421: drawplayer(pp, FALSE); 422: Nplayer--; 423: } 424: 425: len = strlen(pp->p_death); /* Display the cause of death */ 426: x = (WIDTH - len) / 2; 427: cgoto(pp, HEIGHT / 2, x); 428: outstr(pp, pp->p_death, len); 429: for (i = 1; i < len; i++) 430: pp->p_death[i] = '-'; 431: pp->p_death[0] = '+'; 432: pp->p_death[len - 1] = '+'; 433: cgoto(pp, HEIGHT / 2 - 1, x); 434: outstr(pp, pp->p_death, len); 435: cgoto(pp, HEIGHT / 2 + 1, x); 436: outstr(pp, pp->p_death, len); 437: cgoto(pp, HEIGHT, 0); 438: 439: if (Nplayer == 0) { 440: # ifdef CONSTANT_MOVE 441: bul_alarm(0); 442: # endif CONSTANT_MOVE 443: cleanup(0); 444: /* NOTREACHED */ 445: } 446: 447: savefd = pp->p_fd; 448: savemask = pp->p_mask; 449: 450: # ifdef MONITOR 451: if (was_player) { 452: # endif MONITOR 453: for (bp = Bullets; bp != NULL; bp = bp->b_next) { 454: if (bp->b_owner == pp) 455: bp->b_owner = NULL; 456: if (bp->b_x == pp->p_x && bp->b_y == pp->p_y) 457: bp->b_over = SPACE; 458: } 459: 460: i = rand_num(pp->p_ammo); 461: if (i == pp->p_ammo - 1) { 462: x = pp->p_ammo; 463: len = SLIME; 464: } 465: else if (i >= BOMBREQ) { 466: x = BOMBREQ; 467: len = BOMB; 468: } 469: else if (i >= SSLIMEREQ) { 470: x = SSLIMEREQ; 471: len = SLIME; 472: } 473: else if (i >= SATREQ) { 474: x = SATREQ; 475: len = SATCHEL; 476: } 477: else if (i >= SLIMEREQ) { 478: x = SLIMEREQ; 479: len = SLIME; 480: } 481: else if (i >= GRENREQ) { 482: x = GRENREQ; 483: len = GRENADE; 484: } 485: else 486: x = 0; 487: if (x > 0) { 488: add_shot(len, pp->p_y, pp->p_x, pp->p_face, x, 489: (PLAYER *) NULL, TRUE, SPACE); 490: (void) sprintf(Buf, "%s detonated.", 491: pp->p_ident->i_name); 492: for (np = Player; np < End_player; np++) 493: message(np, Buf); 494: # ifdef MONITOR 495: for (np = Monitor; np < End_monitor; np++) 496: message(np, Buf); 497: # endif MONITOR 498: } 499: 500: # ifdef VOLCANO 501: volcano += pp->p_ammo - x; 502: if (rand_num(100) < volcano / 50) { 503: do { 504: x = rand_num(WIDTH / 2) + WIDTH / 4; 505: y = rand_num(HEIGHT / 2) + HEIGHT / 4; 506: } while (Maze[y][x] != SPACE); 507: add_shot(LAVA, y, x, LEFTS, volcano, 508: (PLAYER *) NULL, TRUE, SPACE); 509: for (np = Player; np < End_player; np++) 510: message(np, "Volcano eruption."); 511: volcano = 0; 512: } 513: # endif VOLCANO 514: 515: sendcom(pp, ENDWIN); 516: (void) fclose(pp->p_output); 517: 518: End_player--; 519: if (pp != End_player) { 520: bcopy((char *) End_player, (char *) pp, 521: sizeof (PLAYER)); 522: (void) sprintf(Buf, "%5.2f%c%-10.10s", 523: pp->p_ident->i_score, stat_char(pp), 524: pp->p_ident->i_name); 525: i = STAT_PLAY_ROW + 1 + (pp - Player); 526: for (np = Player; np < End_player; np++) { 527: cgoto(np, i, STAT_NAME_COL); 528: outstr(np, Buf, STAT_NAME_LEN); 529: } 530: # ifdef MONITOR 531: for (np = Monitor; np < End_monitor; np++) { 532: cgoto(np, i, STAT_NAME_COL); 533: outstr(np, Buf, STAT_NAME_LEN); 534: } 535: # endif MONITOR 536: } 537: 538: /* Erase the last player */ 539: i = STAT_PLAY_ROW + 1 + Nplayer; 540: for (np = Player; np < End_player; np++) { 541: cgoto(np, i, STAT_NAME_COL); 542: ce(np); 543: } 544: # ifdef MONITOR 545: for (np = Monitor; np < End_monitor; np++) { 546: cgoto(np, i, STAT_NAME_COL); 547: ce(np); 548: } 549: } 550: else { 551: sendcom(pp, ENDWIN); 552: (void) putc(LAST_PLAYER, pp->p_output); 553: (void) fclose(pp->p_output); 554: 555: End_monitor--; 556: if (pp != End_monitor) { 557: bcopy((char *) End_monitor, (char *) pp, 558: sizeof (PLAYER)); 559: (void) sprintf(Buf, "%5.5s %-10.10s", " ", 560: pp->p_ident->i_name); 561: i = STAT_MON_ROW + 1 + (pp - Player); 562: for (np = Player; np < End_player; np++) { 563: cgoto(np, i, STAT_NAME_COL); 564: outstr(np, Buf, STAT_NAME_LEN); 565: } 566: for (np = Monitor; np < End_monitor; np++) { 567: cgoto(np, i, STAT_NAME_COL); 568: outstr(np, Buf, STAT_NAME_LEN); 569: } 570: } 571: 572: /* Erase the last monitor */ 573: i = STAT_MON_ROW + 1 + (End_monitor - Monitor); 574: for (np = Player; np < End_player; np++) { 575: cgoto(np, i, STAT_NAME_COL); 576: ce(np); 577: } 578: for (np = Monitor; np < End_monitor; np++) { 579: cgoto(np, i, STAT_NAME_COL); 580: ce(np); 581: } 582: 583: } 584: # endif MONITOR 585: 586: Fds_mask &= ~savemask; 587: if (Num_fds == savefd + 1) { 588: Num_fds = Socket; 589: # ifdef INTERNET 590: if (Test_socket > Socket) 591: Num_fds = Test_socket; 592: # endif INTERNET 593: for (np = Player; np < End_player; np++) 594: if (np->p_fd > Num_fds) 595: Num_fds = np->p_fd; 596: # ifdef MONITOR 597: for (np = Monitor; np < End_monitor; np++) 598: if (np->p_fd > Num_fds) 599: Num_fds = np->p_fd; 600: # endif MONITOR 601: Num_fds++; 602: } 603: } 604: 605: /* 606: * rand_num: 607: * Return a random number in a given range. 608: */ 609: rand_num(range) 610: int range; 611: { 612: return (range == 0 ? 0 : RN % range); 613: } 614: 615: /* 616: * havechar: 617: * Check to see if we have any characters in the input queue; if 618: * we do, read them, stash them away, and return TRUE; else return 619: * FALSE. 620: */ 621: havechar(pp) 622: register PLAYER *pp; 623: { 624: extern int errno; 625: 626: if (pp->p_ncount < pp->p_nchar) 627: return TRUE; 628: if (!(Have_inp & pp->p_mask)) 629: return FALSE; 630: Have_inp &= ~pp->p_mask; 631: check_again: 632: errno = 0; 633: if ((pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf)) <= 0) 634: { 635: if (errno == EINTR) 636: goto check_again; 637: pp->p_cbuf[0] = 'q'; 638: } 639: pp->p_ncount = 0; 640: return TRUE; 641: } 642: 643: /* 644: * cleanup: 645: * Exit with the given value, cleaning up any droppings lying around 646: */ 647: cleanup(eval) 648: int eval; 649: { 650: register PLAYER *pp; 651: 652: for (pp = Player; pp < End_player; pp++) { 653: cgoto(pp, HEIGHT, 0); 654: sendcom(pp, ENDWIN); 655: (void) putc(LAST_PLAYER, pp->p_output); 656: (void) fclose(pp->p_output); 657: } 658: # ifdef MONITOR 659: for (pp = Monitor; pp < End_monitor; pp++) { 660: cgoto(pp, HEIGHT, 0); 661: sendcom(pp, ENDWIN); 662: (void) putc(LAST_PLAYER, pp->p_output); 663: (void) fclose(pp->p_output); 664: } 665: # endif MONITOR 666: (void) close(Socket); 667: # ifdef AF_UNIX_HACK 668: (void) unlink(Sock_name); 669: # endif AF_UNIX_HACK 670: exit(eval); 671: }