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