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