1 /* $NetBSD: driver.c,v 1.5 1997/10/20 00:37:16 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: driver.c,v 1.5 1997/10/20 00:37:16 lukem Exp $"); 11 #endif /* not lint */ 12 13 # include <sys/ioctl.h> 14 # include <sys/stat.h> 15 # include <sys/time.h> 16 # include <err.h> 17 # include <errno.h> 18 # include <signal.h> 19 # include <stdlib.h> 20 # include <unistd.h> 21 # include "hunt.h" 22 23 # ifndef pdp11 24 # define RN (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff) 25 # else 26 # define RN ((Seed = Seed * 11109 + 13849) & 0x7fff) 27 # endif 28 29 int Seed = 0; 30 31 32 SOCKET Daemon; 33 char *First_arg; /* pointer to argv[0] */ 34 char *Last_arg; /* pointer to end of argv/environ */ 35 # ifdef INTERNET 36 int Test_socket; /* test socket to answer datagrams */ 37 FLAG inetd_spawned; /* invoked via inetd */ 38 FLAG standard_port = TRUE; /* true if listening on standard port */ 39 u_short sock_port; /* port # of tcp listen socket */ 40 u_short stat_port; /* port # of statistics tcp socket */ 41 # define DAEMON_SIZE (sizeof Daemon) 42 # else 43 # define DAEMON_SIZE (sizeof Daemon - 1) 44 # endif 45 46 static void clear_scores __P((void)); 47 static int havechar __P((PLAYER *)); 48 static void init __P((void)); 49 int main __P((int, char *[], char *[])); 50 static void makeboots __P((void)); 51 static void send_stats __P((void)); 52 static void zap __P((PLAYER *, FLAG)); 53 54 55 /* 56 * main: 57 * The main program. 58 */ 59 int 60 main(ac, av, ep) 61 int ac; 62 char **av, **ep; 63 { 64 PLAYER *pp; 65 int had_char; 66 # ifdef INTERNET 67 u_short msg; 68 short port_num, reply; 69 int namelen; 70 SOCKET test; 71 # endif 72 static fd_set read_fds; 73 static FLAG first = TRUE; 74 static FLAG server = FALSE; 75 extern int optind; 76 extern char *optarg; 77 int c; 78 static struct timeval linger = { 90, 0 }; 79 80 First_arg = av[0]; 81 if (ep == NULL || *ep == NULL) 82 ep = av + ac; 83 while (*ep) 84 ep++; 85 Last_arg = ep[-1] + strlen(ep[-1]); 86 87 while ((c = getopt(ac, av, "sp:")) != -1) { 88 switch (c) { 89 case 's': 90 server = TRUE; 91 break; 92 # ifdef INTERNET 93 case 'p': 94 standard_port = FALSE; 95 Test_port = atoi(optarg); 96 break; 97 # endif 98 default: 99 erred: 100 fprintf(stderr, "Usage: %s [-s] [-p port]\n", av[0]); 101 exit(1); 102 } 103 } 104 if (optind < ac) 105 goto erred; 106 107 init(); 108 109 110 again: 111 do { 112 read_fds = Fds_mask; 113 errno = 0; 114 while (select(Num_fds, &read_fds, NULL, NULL, NULL) < 0) 115 { 116 if (errno != EINTR) 117 # ifdef LOG 118 syslog(LOG_WARNING, "select: %m"); 119 # else 120 warn("select"); 121 # endif 122 errno = 0; 123 } 124 Have_inp = read_fds; 125 # ifdef INTERNET 126 if (FD_ISSET(Test_socket, &read_fds)) { 127 namelen = DAEMON_SIZE; 128 port_num = htons(sock_port); 129 (void) recvfrom(Test_socket, (char *) &msg, sizeof msg, 130 0, (struct sockaddr *) &test, &namelen); 131 switch (ntohs(msg)) { 132 case C_MESSAGE: 133 if (Nplayer <= 0) 134 break; 135 reply = htons((u_short) Nplayer); 136 (void) sendto(Test_socket, (char *) &reply, 137 sizeof reply, 0, 138 (struct sockaddr *) &test, DAEMON_SIZE); 139 break; 140 case C_SCORES: 141 reply = htons(stat_port); 142 (void) sendto(Test_socket, (char *) &reply, 143 sizeof reply, 0, 144 (struct sockaddr *) &test, DAEMON_SIZE); 145 break; 146 case C_PLAYER: 147 case C_MONITOR: 148 if (msg == C_MONITOR && Nplayer <= 0) 149 break; 150 reply = htons(sock_port); 151 (void) sendto(Test_socket, (char *) &reply, 152 sizeof reply, 0, 153 (struct sockaddr *) &test, DAEMON_SIZE); 154 break; 155 } 156 } 157 # endif 158 for (;;) { 159 had_char = FALSE; 160 for (pp = Player; pp < End_player; pp++) 161 if (havechar(pp)) { 162 execute(pp); 163 pp->p_nexec++; 164 had_char++; 165 } 166 # ifdef MONITOR 167 for (pp = Monitor; pp < End_monitor; pp++) 168 if (havechar(pp)) { 169 mon_execute(pp); 170 pp->p_nexec++; 171 had_char++; 172 } 173 # endif 174 if (!had_char) 175 break; 176 moveshots(); 177 for (pp = Player; pp < End_player; ) 178 if (pp->p_death[0] != '\0') 179 zap(pp, TRUE); 180 else 181 pp++; 182 # ifdef MONITOR 183 for (pp = Monitor; pp < End_monitor; ) 184 if (pp->p_death[0] != '\0') 185 zap(pp, FALSE); 186 else 187 pp++; 188 # endif 189 } 190 if (FD_ISSET(Socket, &read_fds)) 191 if (answer()) { 192 # ifdef INTERNET 193 if (first && standard_port) 194 faketalk(); 195 # endif 196 first = FALSE; 197 } 198 if (FD_ISSET(Status, &read_fds)) 199 send_stats(); 200 for (pp = Player; pp < End_player; pp++) { 201 if (FD_ISSET(pp->p_fd, &read_fds)) 202 sendcom(pp, READY, pp->p_nexec); 203 pp->p_nexec = 0; 204 (void) fflush(pp->p_output); 205 } 206 # ifdef MONITOR 207 for (pp = Monitor; pp < End_monitor; pp++) { 208 if (FD_ISSET(pp->p_fd, &read_fds)) 209 sendcom(pp, READY, pp->p_nexec); 210 pp->p_nexec = 0; 211 (void) fflush(pp->p_output); 212 } 213 # endif 214 } while (Nplayer > 0); 215 216 read_fds = Fds_mask; 217 if (select(Num_fds, &read_fds, NULL, NULL, &linger) > 0) { 218 goto again; 219 } 220 if (server) { 221 clear_scores(); 222 makemaze(); 223 clearwalls(); 224 # ifdef BOOTS 225 makeboots(); 226 # endif 227 first = TRUE; 228 goto again; 229 } 230 231 # ifdef MONITOR 232 for (pp = Monitor; pp < End_monitor; ) 233 zap(pp, FALSE); 234 # endif 235 cleanup(0); 236 /* NOTREACHED */ 237 return(0); 238 } 239 240 /* 241 * init: 242 * Initialize the global parameters. 243 */ 244 static void 245 init() 246 { 247 int i; 248 # ifdef INTERNET 249 SOCKET test_port; 250 int msg; 251 int len; 252 # endif 253 254 # ifndef DEBUG 255 # ifdef TIOCNOTTY 256 (void) ioctl(fileno(stdout), TIOCNOTTY, NULL); 257 # endif 258 (void) setpgrp(getpid(), getpid()); 259 (void) signal(SIGHUP, SIG_IGN); 260 (void) signal(SIGINT, SIG_IGN); 261 (void) signal(SIGQUIT, SIG_IGN); 262 (void) signal(SIGTERM, cleanup); 263 # endif 264 265 (void) chdir("/var/tmp"); /* just in case it core dumps */ 266 (void) umask(0); /* No privacy at all! */ 267 (void) signal(SIGPIPE, SIG_IGN); 268 269 # ifdef LOG 270 # ifdef SYSLOG_43 271 openlog("HUNT", LOG_PID, LOG_DAEMON); 272 # endif 273 # ifdef SYSLOG_42 274 openlog("HUNT", LOG_PID); 275 # endif 276 # endif 277 278 /* 279 * Initialize statistics socket 280 */ 281 # ifdef INTERNET 282 Daemon.sin_family = SOCK_FAMILY; 283 Daemon.sin_addr.s_addr = INADDR_ANY; 284 Daemon.sin_port = 0; 285 # else 286 Daemon.sun_family = SOCK_FAMILY; 287 (void) strcpy(Daemon.sun_path, Stat_name); 288 # endif 289 290 Status = socket(SOCK_FAMILY, SOCK_STREAM, 0); 291 if (bind(Status, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) { 292 if (errno == EADDRINUSE) 293 exit(0); 294 else { 295 # ifdef LOG 296 syslog(LOG_ERR, "bind: %m"); 297 # else 298 warn("bind"); 299 # endif 300 cleanup(1); 301 } 302 } 303 (void) listen(Status, 5); 304 305 # ifdef INTERNET 306 len = sizeof (SOCKET); 307 if (getsockname(Status, (struct sockaddr *) &Daemon, &len) < 0) { 308 # ifdef LOG 309 syslog(LOG_ERR, "getsockname: %m"); 310 # else 311 warn("getsockname"); 312 # endif 313 exit(1); 314 } 315 stat_port = ntohs(Daemon.sin_port); 316 # endif 317 318 /* 319 * Initialize main socket 320 */ 321 # ifdef INTERNET 322 Daemon.sin_family = SOCK_FAMILY; 323 Daemon.sin_addr.s_addr = INADDR_ANY; 324 Daemon.sin_port = 0; 325 # else 326 Daemon.sun_family = SOCK_FAMILY; 327 (void) strcpy(Daemon.sun_path, Sock_name); 328 # endif 329 330 Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0); 331 # if defined(INTERNET) 332 msg = 1; 333 if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, &msg, sizeof msg)<0) 334 # ifdef LOG 335 syslog(LOG_WARNING, "setsockopt loopback %m"); 336 # else 337 warn("setsockopt loopback"); 338 # endif 339 # endif 340 if (bind(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) { 341 if (errno == EADDRINUSE) 342 exit(0); 343 else { 344 # ifdef LOG 345 syslog(LOG_ERR, "bind: %m"); 346 # else 347 warn("bind"); 348 # endif 349 cleanup(1); 350 } 351 } 352 (void) listen(Socket, 5); 353 354 # ifdef INTERNET 355 len = sizeof (SOCKET); 356 if (getsockname(Socket, (struct sockaddr *) &Daemon, &len) < 0) { 357 # ifdef LOG 358 syslog(LOG_ERR, "getsockname: %m"); 359 # else 360 warn("getsockname"); 361 # endif 362 exit(1); 363 } 364 sock_port = ntohs(Daemon.sin_port); 365 # endif 366 367 /* 368 * Initialize minimal select mask 369 */ 370 FD_ZERO(&Fds_mask); 371 FD_SET(Socket, &Fds_mask); 372 FD_SET(Status, &Fds_mask); 373 Num_fds = ((Socket > Status) ? Socket : Status) + 1; 374 375 # ifdef INTERNET 376 len = sizeof (SOCKET); 377 if (getsockname(0, (struct sockaddr *) &test_port, &len) >= 0 378 && test_port.sin_family == AF_INET) { 379 inetd_spawned = TRUE; 380 Test_socket = 0; 381 if (test_port.sin_port != htons((u_short) Test_port)) { 382 standard_port = FALSE; 383 Test_port = ntohs(test_port.sin_port); 384 } 385 } else { 386 test_port = Daemon; 387 test_port.sin_port = htons((u_short) Test_port); 388 389 Test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0); 390 if (bind(Test_socket, (struct sockaddr *) &test_port, 391 DAEMON_SIZE) < 0) { 392 # ifdef LOG 393 syslog(LOG_ERR, "bind: %m"); 394 # else 395 warn("bind"); 396 # endif 397 exit(1); 398 } 399 (void) listen(Test_socket, 5); 400 } 401 402 FD_SET(Test_socket, &Fds_mask); 403 if (Test_socket + 1 > Num_fds) 404 Num_fds = Test_socket + 1; 405 # endif 406 407 Seed = getpid() + time((time_t *) NULL); 408 makemaze(); 409 # ifdef BOOTS 410 makeboots(); 411 # endif 412 413 for (i = 0; i < NASCII; i++) 414 See_over[i] = TRUE; 415 See_over[DOOR] = FALSE; 416 See_over[WALL1] = FALSE; 417 See_over[WALL2] = FALSE; 418 See_over[WALL3] = FALSE; 419 # ifdef REFLECT 420 See_over[WALL4] = FALSE; 421 See_over[WALL5] = FALSE; 422 # endif 423 424 } 425 426 # ifdef BOOTS 427 /* 428 * makeboots: 429 * Put the boots in the maze 430 */ 431 static void 432 makeboots() 433 { 434 int x, y; 435 PLAYER *pp; 436 437 do { 438 x = rand_num(WIDTH - 1) + 1; 439 y = rand_num(HEIGHT - 1) + 1; 440 } while (Maze[y][x] != SPACE); 441 Maze[y][x] = BOOT_PAIR; 442 for (pp = Boot; pp < &Boot[NBOOTS]; pp++) 443 pp->p_flying = -1; 444 } 445 # endif 446 447 448 /* 449 * checkdam: 450 * Check the damage to the given player, and see if s/he is killed 451 */ 452 void 453 checkdam(ouch, gotcha, credit, amt, shot_type) 454 PLAYER *ouch, *gotcha; 455 IDENT *credit; 456 int amt; 457 char shot_type; 458 { 459 char *cp; 460 461 if (ouch->p_death[0] != '\0') 462 return; 463 # ifdef BOOTS 464 if (shot_type == SLIME) 465 switch (ouch->p_nboots) { 466 default: 467 break; 468 case 1: 469 amt = (amt + 1) / 2; 470 break; 471 case 2: 472 if (gotcha != NULL) 473 message(gotcha, "He has boots on!"); 474 return; 475 } 476 # endif 477 ouch->p_damage += amt; 478 if (ouch->p_damage <= ouch->p_damcap) { 479 (void) sprintf(Buf, "%2d", ouch->p_damage); 480 cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL); 481 outstr(ouch, Buf, 2); 482 return; 483 } 484 485 /* Someone DIED */ 486 switch (shot_type) { 487 default: 488 cp = "Killed"; 489 break; 490 # ifdef FLY 491 case FALL: 492 cp = "Killed on impact"; 493 break; 494 # endif 495 case KNIFE: 496 cp = "Stabbed to death"; 497 ouch->p_ammo = 0; /* No exploding */ 498 break; 499 case SHOT: 500 cp = "Shot to death"; 501 break; 502 case GRENADE: 503 case SATCHEL: 504 case BOMB: 505 cp = "Bombed"; 506 break; 507 case MINE: 508 case GMINE: 509 cp = "Blown apart"; 510 break; 511 # ifdef OOZE 512 case SLIME: 513 cp = "Slimed"; 514 if (credit != NULL) 515 credit->i_slime++; 516 break; 517 # endif 518 # ifdef VOLCANO 519 case LAVA: 520 cp = "Baked"; 521 break; 522 # endif 523 # ifdef DRONE 524 case DSHOT: 525 cp = "Eliminated"; 526 break; 527 # endif 528 } 529 if (credit == NULL) { 530 (void) sprintf(ouch->p_death, "| %s by %s |", cp, 531 (shot_type == MINE || shot_type == GMINE) ? 532 "a mine" : "act of God"); 533 return; 534 } 535 536 (void) sprintf(ouch->p_death, "| %s by %s |", cp, credit->i_name); 537 538 if (ouch == gotcha) { /* No use killing yourself */ 539 credit->i_kills--; 540 credit->i_bkills++; 541 } 542 else if (ouch->p_ident->i_team == ' ' 543 || ouch->p_ident->i_team != credit->i_team) { 544 credit->i_kills++; 545 credit->i_gkills++; 546 } 547 else { 548 credit->i_kills--; 549 credit->i_bkills++; 550 } 551 credit->i_score = credit->i_kills / (double) credit->i_entries; 552 ouch->p_ident->i_deaths++; 553 if (ouch->p_nchar == 0) 554 ouch->p_ident->i_stillb++; 555 if (gotcha == NULL) 556 return; 557 gotcha->p_damcap += STABDAM; 558 gotcha->p_damage -= STABDAM; 559 if (gotcha->p_damage < 0) 560 gotcha->p_damage = 0; 561 (void) sprintf(Buf, "%2d/%2d", gotcha->p_damage, gotcha->p_damcap); 562 cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL); 563 outstr(gotcha, Buf, 5); 564 (void) sprintf(Buf, "%3d", (gotcha->p_damcap - MAXDAM) / 2); 565 cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL); 566 outstr(gotcha, Buf, 3); 567 (void) sprintf(Buf, "%5.2f", gotcha->p_ident->i_score); 568 for (ouch = Player; ouch < End_player; ouch++) { 569 cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player), 570 STAT_NAME_COL); 571 outstr(ouch, Buf, 5); 572 } 573 # ifdef MONITOR 574 for (ouch = Monitor; ouch < End_monitor; ouch++) { 575 cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player), 576 STAT_NAME_COL); 577 outstr(ouch, Buf, 5); 578 } 579 # endif 580 } 581 582 /* 583 * zap: 584 * Kill off a player and take him out of the game. 585 */ 586 static void 587 zap(pp, was_player) 588 PLAYER *pp; 589 FLAG was_player; 590 { 591 int i, len; 592 BULLET *bp; 593 PLAYER *np; 594 int x, y; 595 int savefd; 596 597 if (was_player) { 598 if (pp->p_undershot) 599 fixshots(pp->p_y, pp->p_x, pp->p_over); 600 drawplayer(pp, FALSE); 601 Nplayer--; 602 } 603 604 len = strlen(pp->p_death); /* Display the cause of death */ 605 x = (WIDTH - len) / 2; 606 cgoto(pp, HEIGHT / 2, x); 607 outstr(pp, pp->p_death, len); 608 for (i = 1; i < len; i++) 609 pp->p_death[i] = '-'; 610 pp->p_death[0] = '+'; 611 pp->p_death[len - 1] = '+'; 612 cgoto(pp, HEIGHT / 2 - 1, x); 613 outstr(pp, pp->p_death, len); 614 cgoto(pp, HEIGHT / 2 + 1, x); 615 outstr(pp, pp->p_death, len); 616 cgoto(pp, HEIGHT, 0); 617 618 savefd = pp->p_fd; 619 620 # ifdef MONITOR 621 if (was_player) { 622 # endif 623 for (bp = Bullets; bp != NULL; bp = bp->b_next) { 624 if (bp->b_owner == pp) 625 bp->b_owner = NULL; 626 if (bp->b_x == pp->p_x && bp->b_y == pp->p_y) 627 bp->b_over = SPACE; 628 } 629 630 i = rand_num(pp->p_ammo); 631 x = rand_num(pp->p_ammo); 632 if (x > i) 633 i = x; 634 if (pp->p_ammo == 0) 635 x = 0; 636 else if (i == pp->p_ammo - 1) { 637 x = pp->p_ammo; 638 len = SLIME; 639 } 640 else { 641 for (x = MAXBOMB - 1; x > 0; x--) 642 if (i >= shot_req[x]) 643 break; 644 for (y = MAXSLIME - 1; y > 0; y--) 645 if (i >= slime_req[y]) 646 break; 647 if (y >= 0 && slime_req[y] > shot_req[x]) { 648 x = slime_req[y]; 649 len = SLIME; 650 } 651 else if (x != 0) { 652 len = shot_type[x]; 653 x = shot_req[x]; 654 } 655 } 656 if (x > 0) { 657 (void) add_shot(len, pp->p_y, pp->p_x, pp->p_face, x, 658 (PLAYER *) NULL, TRUE, SPACE); 659 (void) sprintf(Buf, "%s detonated.", 660 pp->p_ident->i_name); 661 for (np = Player; np < End_player; np++) 662 message(np, Buf); 663 # ifdef MONITOR 664 for (np = Monitor; np < End_monitor; np++) 665 message(np, Buf); 666 # endif 667 # ifdef BOOTS 668 while (pp->p_nboots-- > 0) { 669 for (np = Boot; np < &Boot[NBOOTS]; np++) 670 if (np->p_flying < 0) 671 break; 672 if (np >= &Boot[NBOOTS]) 673 err(1, "Too many boots"); 674 np->p_undershot = FALSE; 675 np->p_x = pp->p_x; 676 np->p_y = pp->p_y; 677 np->p_flying = rand_num(20); 678 np->p_flyx = 2 * rand_num(6) - 5; 679 np->p_flyy = 2 * rand_num(6) - 5; 680 np->p_over = SPACE; 681 np->p_face = BOOT; 682 showexpl(np->p_y, np->p_x, BOOT); 683 } 684 # endif 685 } 686 # ifdef BOOTS 687 else if (pp->p_nboots > 0) { 688 if (pp->p_nboots == 2) 689 Maze[pp->p_y][pp->p_x] = BOOT_PAIR; 690 else 691 Maze[pp->p_y][pp->p_x] = BOOT; 692 if (pp->p_undershot) 693 fixshots(pp->p_y, pp->p_x, 694 Maze[pp->p_y][pp->p_x]); 695 } 696 # endif 697 698 # ifdef VOLCANO 699 volcano += pp->p_ammo - x; 700 if (rand_num(100) < volcano / 50) { 701 do { 702 x = rand_num(WIDTH / 2) + WIDTH / 4; 703 y = rand_num(HEIGHT / 2) + HEIGHT / 4; 704 } while (Maze[y][x] != SPACE); 705 (void) add_shot(LAVA, y, x, LEFTS, volcano, 706 (PLAYER *) NULL, TRUE, SPACE); 707 for (np = Player; np < End_player; np++) 708 message(np, "Volcano eruption."); 709 volcano = 0; 710 } 711 # endif 712 713 # ifdef DRONE 714 if (rand_num(100) < 2) { 715 do { 716 x = rand_num(WIDTH / 2) + WIDTH / 4; 717 y = rand_num(HEIGHT / 2) + HEIGHT / 4; 718 } while (Maze[y][x] != SPACE); 719 add_shot(DSHOT, y, x, rand_dir(), 720 shot_req[MINDSHOT + 721 rand_num(MAXBOMB - MINDSHOT)], 722 (PLAYER *) NULL, FALSE, SPACE); 723 } 724 # endif 725 726 sendcom(pp, ENDWIN); 727 (void) putc(' ', pp->p_output); 728 (void) fclose(pp->p_output); 729 730 End_player--; 731 if (pp != End_player) { 732 memcpy(pp, End_player, sizeof (PLAYER)); 733 (void) sprintf(Buf, "%5.2f%c%-10.10s %c", 734 pp->p_ident->i_score, stat_char(pp), 735 pp->p_ident->i_name, pp->p_ident->i_team); 736 i = STAT_PLAY_ROW + 1 + (pp - Player); 737 for (np = Player; np < End_player; np++) { 738 cgoto(np, i, STAT_NAME_COL); 739 outstr(np, Buf, STAT_NAME_LEN); 740 } 741 # ifdef MONITOR 742 for (np = Monitor; np < End_monitor; np++) { 743 cgoto(np, i, STAT_NAME_COL); 744 outstr(np, Buf, STAT_NAME_LEN); 745 } 746 # endif 747 } 748 749 /* Erase the last player */ 750 i = STAT_PLAY_ROW + 1 + Nplayer; 751 for (np = Player; np < End_player; np++) { 752 cgoto(np, i, STAT_NAME_COL); 753 ce(np); 754 } 755 # ifdef MONITOR 756 for (np = Monitor; np < End_monitor; np++) { 757 cgoto(np, i, STAT_NAME_COL); 758 ce(np); 759 } 760 } 761 else { 762 sendcom(pp, ENDWIN); 763 (void) putc(LAST_PLAYER, pp->p_output); 764 (void) fclose(pp->p_output); 765 766 End_monitor--; 767 if (pp != End_monitor) { 768 memcpy(pp, End_monitor, sizeof (PLAYER)); 769 (void) sprintf(Buf, "%5.5s %-10.10s %c", " ", 770 pp->p_ident->i_name, pp->p_ident->i_team); 771 i = STAT_MON_ROW + 1 + (pp - Player); 772 for (np = Player; np < End_player; np++) { 773 cgoto(np, i, STAT_NAME_COL); 774 outstr(np, Buf, STAT_NAME_LEN); 775 } 776 for (np = Monitor; np < End_monitor; np++) { 777 cgoto(np, i, STAT_NAME_COL); 778 outstr(np, Buf, STAT_NAME_LEN); 779 } 780 } 781 782 /* Erase the last monitor */ 783 i = STAT_MON_ROW + 1 + (End_monitor - Monitor); 784 for (np = Player; np < End_player; np++) { 785 cgoto(np, i, STAT_NAME_COL); 786 ce(np); 787 } 788 for (np = Monitor; np < End_monitor; np++) { 789 cgoto(np, i, STAT_NAME_COL); 790 ce(np); 791 } 792 793 } 794 # endif 795 796 FD_CLR(savefd, &Fds_mask); 797 if (Num_fds == savefd + 1) { 798 Num_fds = Socket; 799 # ifdef INTERNET 800 if (Test_socket > Socket) 801 Num_fds = Test_socket; 802 # endif 803 for (np = Player; np < End_player; np++) 804 if (np->p_fd > Num_fds) 805 Num_fds = np->p_fd; 806 # ifdef MONITOR 807 for (np = Monitor; np < End_monitor; np++) 808 if (np->p_fd > Num_fds) 809 Num_fds = np->p_fd; 810 # endif 811 Num_fds++; 812 } 813 } 814 815 /* 816 * rand_num: 817 * Return a random number in a given range. 818 */ 819 int 820 rand_num(range) 821 int range; 822 { 823 return (range == 0 ? 0 : RN % range); 824 } 825 826 /* 827 * havechar: 828 * Check to see if we have any characters in the input queue; if 829 * we do, read them, stash them away, and return TRUE; else return 830 * FALSE. 831 */ 832 static int 833 havechar(pp) 834 PLAYER *pp; 835 { 836 837 if (pp->p_ncount < pp->p_nchar) 838 return TRUE; 839 if (!FD_ISSET(pp->p_fd, &Have_inp)) 840 return FALSE; 841 FD_CLR(pp->p_fd, &Have_inp); 842 check_again: 843 errno = 0; 844 if ((pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf)) <= 0) 845 { 846 if (errno == EINTR) 847 goto check_again; 848 pp->p_cbuf[0] = 'q'; 849 } 850 pp->p_ncount = 0; 851 return TRUE; 852 } 853 854 /* 855 * cleanup: 856 * Exit with the given value, cleaning up any droppings lying around 857 */ 858 SIGNAL_TYPE 859 cleanup(eval) 860 int eval; 861 { 862 PLAYER *pp; 863 864 for (pp = Player; pp < End_player; pp++) { 865 cgoto(pp, HEIGHT, 0); 866 sendcom(pp, ENDWIN); 867 (void) putc(LAST_PLAYER, pp->p_output); 868 (void) fclose(pp->p_output); 869 } 870 # ifdef MONITOR 871 for (pp = Monitor; pp < End_monitor; pp++) { 872 cgoto(pp, HEIGHT, 0); 873 sendcom(pp, ENDWIN); 874 (void) putc(LAST_PLAYER, pp->p_output); 875 (void) fclose(pp->p_output); 876 } 877 # endif 878 (void) close(Socket); 879 # ifdef AF_UNIX_HACK 880 (void) unlink(Sock_name); 881 # endif 882 883 exit(eval); 884 } 885 886 /* 887 * send_stats: 888 * Print stats to requestor 889 */ 890 static void 891 send_stats() 892 { 893 IDENT *ip; 894 FILE *fp; 895 int s; 896 SOCKET sockstruct; 897 int socklen; 898 899 /* 900 * Get the output stream ready 901 */ 902 # ifdef INTERNET 903 socklen = sizeof sockstruct; 904 # else 905 socklen = sizeof sockstruct - 1; 906 # endif 907 s = accept(Status, (struct sockaddr *) &sockstruct, &socklen); 908 if (s < 0) { 909 if (errno == EINTR) 910 return; 911 # ifdef LOG 912 syslog(LOG_ERR, "accept: %m"); 913 # else 914 warn("accept"); 915 # endif 916 return; 917 } 918 fp = fdopen(s, "w"); 919 if (fp == NULL) { 920 # ifdef LOG 921 syslog(LOG_ERR, "fdopen: %m"); 922 # else 923 warn("fdopen"); 924 # endif 925 (void) close(s); 926 return; 927 } 928 929 /* 930 * Send output to requestor 931 */ 932 fputs("Name\t\tScore\tDucked\tAbsorb\tFaced\tShot\tRobbed\tMissed\tSlimeK\n", fp); 933 for (ip = Scores; ip != NULL; ip = ip->i_next) { 934 fprintf(fp, "%s\t", ip->i_name); 935 if (strlen(ip->i_name) < 8) 936 putc('\t', fp); 937 fprintf(fp, "%.2f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", 938 ip->i_score, ip->i_ducked, ip->i_absorbed, 939 ip->i_faced, ip->i_shot, ip->i_robbed, 940 ip->i_missed, ip->i_slime); 941 } 942 fputs("\n\nName\t\tEnemy\tFriend\tDeaths\tStill\tSaved\n", fp); 943 for (ip = Scores; ip != NULL; ip = ip->i_next) { 944 if (ip->i_team == ' ') { 945 fprintf(fp, "%s\t", ip->i_name); 946 if (strlen(ip->i_name) < 8) 947 putc('\t', fp); 948 } 949 else { 950 fprintf(fp, "%s[%c]\t", ip->i_name, ip->i_team); 951 if (strlen(ip->i_name) + 3 < 8) 952 putc('\t', fp); 953 } 954 fprintf(fp, "%d\t%d\t%d\t%d\t%d\n", 955 ip->i_gkills, ip->i_bkills, ip->i_deaths, 956 ip->i_stillb, ip->i_saved); 957 } 958 959 (void) fclose(fp); 960 } 961 962 /* 963 * clear_scores: 964 * Clear out the scores so the next session start clean 965 */ 966 static void 967 clear_scores() 968 { 969 IDENT *ip, *nextip; 970 971 for (ip = Scores; ip != NULL; ip = nextip) { 972 nextip = ip->i_next; 973 (void) free((char *) ip); 974 } 975 Scores = NULL; 976 } 977