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