Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / games / hunt / huntd / driver.c
blob1cb3e49f4839ab237611589e594dd65966a5d5ea
1 /* $NetBSD: driver.c,v 1.19 2009/07/04 06:38:35 dholland Exp $ */
2 /*
3 * Copyright (c) 1983-2003, Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * + Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * + Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * + Neither the name of the University of California, San Francisco nor
16 * the names of its contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __RCSID("$NetBSD: driver.c,v 1.19 2009/07/04 06:38:35 dholland Exp $");
36 #endif /* not lint */
38 #include <sys/ioctl.h>
39 #include <sys/stat.h>
40 #include <sys/time.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <signal.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include"hunt.h"
48 #ifndef pdp11
49 #define RN (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff)
50 #else
51 #define RN ((Seed = Seed * 11109 + 13849) & 0x7fff)
52 #endif
54 static int Seed = 0;
57 static SOCKET Daemon;
58 static char *First_arg; /* pointer to argv[0] */
59 static char *Last_arg; /* pointer to end of argv/environ */
61 #ifdef INTERNET
62 static int Test_socket; /* test socket to answer datagrams */
63 static FLAG inetd_spawned; /* invoked via inetd */
64 static FLAG standard_port = TRUE; /* true if listening on standard port */
65 static u_short sock_port; /* port # of tcp listen socket */
66 static u_short stat_port; /* port # of statistics tcp socket */
67 #define DAEMON_SIZE (sizeof Daemon)
68 #else
69 #define DAEMON_SIZE (sizeof Daemon - 1)
70 #endif
72 static void clear_scores(void);
73 static int havechar(PLAYER *, int);
74 static void init(void);
75 int main(int, char *[], char *[]);
76 static void makeboots(void);
77 static void send_stats(void);
78 static void zap(PLAYER *, FLAG, int);
82 * main:
83 * The main program.
85 int
86 main(int ac, char **av, char **ep)
88 PLAYER *pp;
89 #ifdef INTERNET
90 u_short msg;
91 short port_num, reply;
92 socklen_t namelen;
93 SOCKET test;
94 #endif
95 static FLAG first = TRUE;
96 static FLAG server = FALSE;
97 int c, i;
98 const int linger = 90 * 1000;
100 First_arg = av[0];
101 if (ep == NULL || *ep == NULL)
102 ep = av + ac;
103 while (*ep)
104 ep++;
105 Last_arg = ep[-1] + strlen(ep[-1]);
107 while ((c = getopt(ac, av, "sp:")) != -1) {
108 switch (c) {
109 case 's':
110 server = TRUE;
111 break;
112 #ifdef INTERNET
113 case 'p':
114 standard_port = FALSE;
115 Test_port = atoi(optarg);
116 break;
117 #endif
118 default:
119 erred:
120 fprintf(stderr, "Usage: %s [-s] [-p port]\n", av[0]);
121 exit(1);
124 if (optind < ac)
125 goto erred;
127 init();
130 again:
131 do {
132 errno = 0;
133 while (poll(fdset, 3+MAXPL+MAXMON, INFTIM) < 0)
135 if (errno != EINTR)
136 #ifdef LOG
137 syslog(LOG_WARNING, "poll: %m");
138 #else
139 warn("poll");
140 #endif
141 errno = 0;
143 #ifdef INTERNET
144 if (fdset[2].revents & POLLIN) {
145 namelen = DAEMON_SIZE;
146 port_num = htons(sock_port);
147 (void) recvfrom(Test_socket, &msg, sizeof msg,
148 0, (struct sockaddr *) &test, &namelen);
149 switch (ntohs(msg)) {
150 case C_MESSAGE:
151 if (Nplayer <= 0)
152 break;
153 reply = htons((u_short) Nplayer);
154 (void) sendto(Test_socket, &reply,
155 sizeof reply, 0,
156 (struct sockaddr *) &test, DAEMON_SIZE);
157 break;
158 case C_SCORES:
159 reply = htons(stat_port);
160 (void) sendto(Test_socket, &reply,
161 sizeof reply, 0,
162 (struct sockaddr *) &test, DAEMON_SIZE);
163 break;
164 case C_PLAYER:
165 case C_MONITOR:
166 if (msg == C_MONITOR && Nplayer <= 0)
167 break;
168 reply = htons(sock_port);
169 (void) sendto(Test_socket, &reply,
170 sizeof reply, 0,
171 (struct sockaddr *) &test, DAEMON_SIZE);
172 break;
175 #endif
177 for (pp = Player, i = 0; pp < End_player; pp++, i++)
178 if (havechar(pp, i + 3)) {
179 execute(pp);
180 pp->p_nexec++;
182 #ifdef MONITOR
183 for (pp = Monitor, i = 0; pp < End_monitor; pp++, i++)
184 if (havechar(pp, i + MAXPL + 3)) {
185 mon_execute(pp);
186 pp->p_nexec++;
188 #endif
189 moveshots();
190 for (pp = Player, i = 0; pp < End_player; )
191 if (pp->p_death[0] != '\0')
192 zap(pp, TRUE, i + 3);
193 else
194 pp++, i++;
195 #ifdef MONITOR
196 for (pp = Monitor, i = 0; pp < End_monitor; )
197 if (pp->p_death[0] != '\0')
198 zap(pp, FALSE, i + MAXPL + 3);
199 else
200 pp++, i++;
201 #endif
203 if (fdset[0].revents & POLLIN)
204 if (answer()) {
205 #ifdef INTERNET
206 if (first && standard_port)
207 faketalk();
208 #endif
209 first = FALSE;
211 if (fdset[1].revents & POLLIN)
212 send_stats();
213 for (pp = Player, i = 0; pp < End_player; pp++, i++) {
214 if (fdset[i + 3].revents & POLLIN)
215 sendcom(pp, READY, pp->p_nexec);
216 pp->p_nexec = 0;
217 (void) fflush(pp->p_output);
219 #ifdef MONITOR
220 for (pp = Monitor, i = 0; pp < End_monitor; pp++, i++) {
221 if (fdset[i + MAXPL + 3].revents & POLLIN)
222 sendcom(pp, READY, pp->p_nexec);
223 pp->p_nexec = 0;
224 (void) fflush(pp->p_output);
226 #endif
227 } while (Nplayer > 0);
229 if (poll(fdset, 3+MAXPL+MAXMON, linger) > 0) {
230 goto again;
232 if (server) {
233 clear_scores();
234 makemaze();
235 clearwalls();
236 #ifdef BOOTS
237 makeboots();
238 #endif
239 first = TRUE;
240 goto again;
243 #ifdef MONITOR
244 for (pp = Monitor, i = 0; pp < End_monitor; i++)
245 zap(pp, FALSE, i + MAXPL + 3);
246 #endif
247 cleanup(0);
248 /* NOTREACHED */
249 return(0);
253 * init:
254 * Initialize the global parameters.
256 static void
257 init(void)
259 int i;
260 #ifdef INTERNET
261 SOCKET test_port;
262 int msg;
263 socklen_t len;
264 #endif
266 #ifndef DEBUG
267 #ifdef TIOCNOTTY
268 (void) ioctl(fileno(stdout), TIOCNOTTY, NULL);
269 #endif
270 (void) setpgrp(getpid(), getpid());
271 (void) signal(SIGHUP, SIG_IGN);
272 (void) signal(SIGINT, SIG_IGN);
273 (void) signal(SIGQUIT, SIG_IGN);
274 (void) signal(SIGTERM, cleanup);
275 #endif
277 (void) chdir("/var/tmp"); /* just in case it core dumps */
278 (void) umask(0); /* No privacy at all! */
279 (void) signal(SIGPIPE, SIG_IGN);
281 #ifdef LOG
282 openlog("huntd", LOG_PID, LOG_DAEMON);
283 #endif
286 * Initialize statistics socket
288 #ifdef INTERNET
289 Daemon.sin_family = SOCK_FAMILY;
290 Daemon.sin_addr.s_addr = INADDR_ANY;
291 Daemon.sin_port = 0;
292 #else
293 Daemon.sun_family = SOCK_FAMILY;
294 (void) strcpy(Daemon.sun_path, Stat_name);
295 #endif
297 Status = socket(SOCK_FAMILY, SOCK_STREAM, 0);
298 if (bind(Status, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
299 if (errno == EADDRINUSE)
300 exit(0);
301 else {
302 #ifdef LOG
303 syslog(LOG_ERR, "bind: %m");
304 #else
305 warn("bind");
306 #endif
307 cleanup(1);
310 (void) listen(Status, 5);
312 #ifdef INTERNET
313 len = sizeof (SOCKET);
314 if (getsockname(Status, (struct sockaddr *) &Daemon, &len) < 0) {
315 #ifdef LOG
316 syslog(LOG_ERR, "getsockname: %m");
317 #else
318 warn("getsockname");
319 #endif
320 exit(1);
322 stat_port = ntohs(Daemon.sin_port);
323 #endif
326 * Initialize main socket
328 #ifdef INTERNET
329 Daemon.sin_family = SOCK_FAMILY;
330 Daemon.sin_addr.s_addr = INADDR_ANY;
331 Daemon.sin_port = 0;
332 #else
333 Daemon.sun_family = SOCK_FAMILY;
334 (void) strcpy(Daemon.sun_path, Sock_name);
335 #endif
337 Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
338 #if defined(INTERNET)
339 msg = 1;
340 if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, &msg, sizeof msg)<0)
341 #ifdef LOG
342 syslog(LOG_WARNING, "setsockopt loopback %m");
343 #else
344 warn("setsockopt loopback");
345 #endif
346 #endif
347 if (bind(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
348 if (errno == EADDRINUSE)
349 exit(0);
350 else {
351 #ifdef LOG
352 syslog(LOG_ERR, "bind: %m");
353 #else
354 warn("bind");
355 #endif
356 cleanup(1);
359 (void) listen(Socket, 5);
361 #ifdef INTERNET
362 len = sizeof (SOCKET);
363 if (getsockname(Socket, (struct sockaddr *) &Daemon, &len) < 0) {
364 #ifdef LOG
365 syslog(LOG_ERR, "getsockname: %m");
366 #else
367 warn("getsockname");
368 #endif
369 exit(1);
371 sock_port = ntohs(Daemon.sin_port);
372 #endif
375 * Initialize minimal poll mask
377 fdset[0].fd = Socket;
378 fdset[0].events = POLLIN;
379 fdset[1].fd = Status;
380 fdset[1].events = POLLIN;
382 #ifdef INTERNET
383 len = sizeof (SOCKET);
384 if (getsockname(0, (struct sockaddr *) &test_port, &len) >= 0
385 && test_port.sin_family == AF_INET) {
386 inetd_spawned = TRUE;
387 Test_socket = 0;
388 if (test_port.sin_port != htons((u_short) Test_port)) {
389 standard_port = FALSE;
390 Test_port = ntohs(test_port.sin_port);
392 } else {
393 test_port = Daemon;
394 test_port.sin_port = htons((u_short) Test_port);
396 Test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
397 if (bind(Test_socket, (struct sockaddr *) &test_port,
398 DAEMON_SIZE) < 0) {
399 #ifdef LOG
400 syslog(LOG_ERR, "bind: %m");
401 #else
402 warn("bind");
403 #endif
404 exit(1);
406 (void) listen(Test_socket, 5);
409 fdset[2].fd = Test_socket;
410 fdset[2].events = POLLIN;
411 #else
412 fdset[2].fd = -1;
413 #endif
415 Seed = getpid() + time((time_t *) NULL);
416 makemaze();
417 #ifdef BOOTS
418 makeboots();
419 #endif
421 for (i = 0; i < NASCII; i++)
422 See_over[i] = TRUE;
423 See_over[DOOR] = FALSE;
424 See_over[WALL1] = FALSE;
425 See_over[WALL2] = FALSE;
426 See_over[WALL3] = FALSE;
427 #ifdef REFLECT
428 See_over[WALL4] = FALSE;
429 See_over[WALL5] = FALSE;
430 #endif
434 #ifdef BOOTS
436 * makeboots:
437 * Put the boots in the maze
439 static void
440 makeboots(void)
442 int x, y;
443 PLAYER *pp;
445 do {
446 x = rand_num(WIDTH - 1) + 1;
447 y = rand_num(HEIGHT - 1) + 1;
448 } while (Maze[y][x] != SPACE);
449 Maze[y][x] = BOOT_PAIR;
450 for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
451 pp->p_flying = -1;
453 #endif
457 * checkdam:
458 * Check the damage to the given player, and see if s/he is killed
460 void
461 checkdam(PLAYER *ouch, PLAYER *gotcha, IDENT *credit, int amt,
462 char this_shot_type)
464 const char *cp;
466 if (ouch->p_death[0] != '\0')
467 return;
468 #ifdef BOOTS
469 if (this_shot_type == SLIME)
470 switch (ouch->p_nboots) {
471 default:
472 break;
473 case 1:
474 amt = (amt + 1) / 2;
475 break;
476 case 2:
477 if (gotcha != NULL)
478 message(gotcha, "He has boots on!");
479 return;
481 #endif
482 ouch->p_damage += amt;
483 if (ouch->p_damage <= ouch->p_damcap) {
484 (void) snprintf(Buf, sizeof(Buf), "%2d", ouch->p_damage);
485 cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL);
486 outstr(ouch, Buf, 2);
487 return;
490 /* Someone DIED */
491 switch (this_shot_type) {
492 default:
493 cp = "Killed";
494 break;
495 #ifdef FLY
496 case FALL:
497 cp = "Killed on impact";
498 break;
499 #endif
500 case KNIFE:
501 cp = "Stabbed to death";
502 ouch->p_ammo = 0; /* No exploding */
503 break;
504 case SHOT:
505 cp = "Shot to death";
506 break;
507 case GRENADE:
508 case SATCHEL:
509 case BOMB:
510 cp = "Bombed";
511 break;
512 case MINE:
513 case GMINE:
514 cp = "Blown apart";
515 break;
516 #ifdef OOZE
517 case SLIME:
518 cp = "Slimed";
519 if (credit != NULL)
520 credit->i_slime++;
521 break;
522 #endif
523 #ifdef VOLCANO
524 case LAVA:
525 cp = "Baked";
526 break;
527 #endif
528 #ifdef DRONE
529 case DSHOT:
530 cp = "Eliminated";
531 break;
532 #endif
534 if (credit == NULL) {
535 (void) snprintf(ouch->p_death, sizeof(ouch->p_death),
536 "| %s by %s |", cp,
537 (this_shot_type == MINE || this_shot_type == GMINE) ?
538 "a mine" : "act of God");
539 return;
542 (void) snprintf(ouch->p_death, sizeof(ouch->p_death),
543 "| %s by %s |", cp, credit->i_name);
545 if (ouch == gotcha) { /* No use killing yourself */
546 credit->i_kills--;
547 credit->i_bkills++;
549 else if (ouch->p_ident->i_team == ' '
550 || ouch->p_ident->i_team != credit->i_team) {
551 credit->i_kills++;
552 credit->i_gkills++;
554 else {
555 credit->i_kills--;
556 credit->i_bkills++;
558 credit->i_score = credit->i_kills / (double) credit->i_entries;
559 ouch->p_ident->i_deaths++;
560 if (ouch->p_nchar == 0)
561 ouch->p_ident->i_stillb++;
562 if (gotcha == NULL)
563 return;
564 gotcha->p_damcap += STABDAM;
565 gotcha->p_damage -= STABDAM;
566 if (gotcha->p_damage < 0)
567 gotcha->p_damage = 0;
568 (void) snprintf(Buf, sizeof(Buf), "%2d/%2d", gotcha->p_damage,
569 gotcha->p_damcap);
570 cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL);
571 outstr(gotcha, Buf, 5);
572 (void) snprintf(Buf, sizeof(Buf), "%3d",
573 (gotcha->p_damcap - MAXDAM) / 2);
574 cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL);
575 outstr(gotcha, Buf, 3);
576 (void) snprintf(Buf, sizeof(Buf), "%5.2f", gotcha->p_ident->i_score);
577 for (ouch = Player; ouch < End_player; ouch++) {
578 cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
579 STAT_NAME_COL);
580 outstr(ouch, Buf, 5);
582 #ifdef MONITOR
583 for (ouch = Monitor; ouch < End_monitor; ouch++) {
584 cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
585 STAT_NAME_COL);
586 outstr(ouch, Buf, 5);
588 #endif
592 * zap:
593 * Kill off a player and take him out of the game.
595 static void
596 zap(PLAYER *pp, FLAG was_player, int i)
598 int n, len;
599 BULLET *bp;
600 PLAYER *np;
601 int x, y;
602 int savefd;
604 if (was_player) {
605 if (pp->p_undershot)
606 fixshots(pp->p_y, pp->p_x, pp->p_over);
607 drawplayer(pp, FALSE);
608 Nplayer--;
611 len = strlen(pp->p_death); /* Display the cause of death */
612 x = (WIDTH - len) / 2;
613 cgoto(pp, HEIGHT / 2, x);
614 outstr(pp, pp->p_death, len);
615 for (n = 1; n < len; n++)
616 pp->p_death[n] = '-';
617 pp->p_death[0] = '+';
618 pp->p_death[len - 1] = '+';
619 cgoto(pp, HEIGHT / 2 - 1, x);
620 outstr(pp, pp->p_death, len);
621 cgoto(pp, HEIGHT / 2 + 1, x);
622 outstr(pp, pp->p_death, len);
623 cgoto(pp, HEIGHT, 0);
625 savefd = pp->p_fd;
627 #ifdef MONITOR
628 if (was_player) {
629 #endif
630 for (bp = Bullets; bp != NULL; bp = bp->b_next) {
631 if (bp->b_owner == pp)
632 bp->b_owner = NULL;
633 if (bp->b_x == pp->p_x && bp->b_y == pp->p_y)
634 bp->b_over = SPACE;
637 n = rand_num(pp->p_ammo);
638 x = rand_num(pp->p_ammo);
639 if (x > n)
640 n = x;
641 if (pp->p_ammo == 0)
642 x = 0;
643 else if (n == pp->p_ammo - 1) {
644 x = pp->p_ammo;
645 len = SLIME;
647 else {
648 for (x = MAXBOMB - 1; x > 0; x--)
649 if (n >= shot_req[x])
650 break;
651 for (y = MAXSLIME - 1; y > 0; y--)
652 if (n >= slime_req[y])
653 break;
654 if (y >= 0 && slime_req[y] > shot_req[x]) {
655 x = slime_req[y];
656 len = SLIME;
658 else if (x != 0) {
659 len = shot_type[x];
660 x = shot_req[x];
663 if (x > 0) {
664 (void) add_shot(len, pp->p_y, pp->p_x, pp->p_face, x,
665 (PLAYER *) NULL, TRUE, SPACE);
666 (void) snprintf(Buf, sizeof(Buf), "%s detonated.",
667 pp->p_ident->i_name);
668 for (np = Player; np < End_player; np++)
669 message(np, Buf);
670 #ifdef MONITOR
671 for (np = Monitor; np < End_monitor; np++)
672 message(np, Buf);
673 #endif
674 #ifdef BOOTS
675 while (pp->p_nboots-- > 0) {
676 for (np = Boot; np < &Boot[NBOOTS]; np++)
677 if (np->p_flying < 0)
678 break;
679 if (np >= &Boot[NBOOTS])
680 err(1, "Too many boots");
681 np->p_undershot = FALSE;
682 np->p_x = pp->p_x;
683 np->p_y = pp->p_y;
684 np->p_flying = rand_num(20);
685 np->p_flyx = 2 * rand_num(6) - 5;
686 np->p_flyy = 2 * rand_num(6) - 5;
687 np->p_over = SPACE;
688 np->p_face = BOOT;
689 showexpl(np->p_y, np->p_x, BOOT);
691 #endif
693 #ifdef BOOTS
694 else if (pp->p_nboots > 0) {
695 if (pp->p_nboots == 2)
696 Maze[pp->p_y][pp->p_x] = BOOT_PAIR;
697 else
698 Maze[pp->p_y][pp->p_x] = BOOT;
699 if (pp->p_undershot)
700 fixshots(pp->p_y, pp->p_x,
701 Maze[pp->p_y][pp->p_x]);
703 #endif
705 #ifdef VOLCANO
706 volcano += pp->p_ammo - x;
707 if (rand_num(100) < volcano / 50) {
708 do {
709 x = rand_num(WIDTH / 2) + WIDTH / 4;
710 y = rand_num(HEIGHT / 2) + HEIGHT / 4;
711 } while (Maze[y][x] != SPACE);
712 (void) add_shot(LAVA, y, x, LEFTS, volcano,
713 (PLAYER *) NULL, TRUE, SPACE);
714 for (np = Player; np < End_player; np++)
715 message(np, "Volcano eruption.");
716 volcano = 0;
718 #endif
720 #ifdef DRONE
721 if (rand_num(100) < 2) {
722 do {
723 x = rand_num(WIDTH / 2) + WIDTH / 4;
724 y = rand_num(HEIGHT / 2) + HEIGHT / 4;
725 } while (Maze[y][x] != SPACE);
726 add_shot(DSHOT, y, x, rand_dir(),
727 shot_req[MINDSHOT +
728 rand_num(MAXBOMB - MINDSHOT)],
729 (PLAYER *) NULL, FALSE, SPACE);
731 #endif
733 sendcom(pp, ENDWIN);
734 (void) putc(' ', pp->p_output);
735 (void) fclose(pp->p_output);
737 End_player--;
738 if (pp != End_player) {
739 memcpy(pp, End_player, sizeof (PLAYER));
740 fdset[i] = fdset[End_player - Player + 3];
741 fdset[End_player - Player + 3].fd = -1;
742 (void) snprintf(Buf, sizeof(Buf), "%5.2f%c%-10.10s %c",
743 pp->p_ident->i_score, stat_char(pp),
744 pp->p_ident->i_name, pp->p_ident->i_team);
745 n = STAT_PLAY_ROW + 1 + (pp - Player);
746 for (np = Player; np < End_player; np++) {
747 cgoto(np, n, STAT_NAME_COL);
748 outstr(np, Buf, STAT_NAME_LEN);
750 #ifdef MONITOR
751 for (np = Monitor; np < End_monitor; np++) {
752 cgoto(np, n, STAT_NAME_COL);
753 outstr(np, Buf, STAT_NAME_LEN);
755 #endif
756 } else
757 fdset[i].fd = -1;
759 /* Erase the last player */
760 n = STAT_PLAY_ROW + 1 + Nplayer;
761 for (np = Player; np < End_player; np++) {
762 cgoto(np, n, STAT_NAME_COL);
763 ce(np);
765 #ifdef MONITOR
766 for (np = Monitor; np < End_monitor; np++) {
767 cgoto(np, n, STAT_NAME_COL);
768 ce(np);
771 else {
772 sendcom(pp, ENDWIN);
773 (void) putc(LAST_PLAYER, pp->p_output);
774 (void) fclose(pp->p_output);
776 End_monitor--;
777 if (pp != End_monitor) {
778 memcpy(pp, End_monitor, sizeof (PLAYER));
779 fdset[i] = fdset[End_monitor - Monitor + MAXPL + 3];
780 fdset[End_monitor - Monitor + MAXPL + 3].fd = -1;
781 (void) snprintf(Buf, sizeof(Buf), "%5.5s %-10.10s %c",
782 " ",
783 pp->p_ident->i_name, pp->p_ident->i_team);
784 n = STAT_MON_ROW + 1 + (pp - Player);
785 for (np = Player; np < End_player; np++) {
786 cgoto(np, n, STAT_NAME_COL);
787 outstr(np, Buf, STAT_NAME_LEN);
789 for (np = Monitor; np < End_monitor; np++) {
790 cgoto(np, n, STAT_NAME_COL);
791 outstr(np, Buf, STAT_NAME_LEN);
793 } else
794 fdset[i].fd = -1;
796 /* Erase the last monitor */
797 n = STAT_MON_ROW + 1 + (End_monitor - Monitor);
798 for (np = Player; np < End_player; np++) {
799 cgoto(np, n, STAT_NAME_COL);
800 ce(np);
802 for (np = Monitor; np < End_monitor; np++) {
803 cgoto(np, n, STAT_NAME_COL);
804 ce(np);
807 #endif
811 * rand_num:
812 * Return a random number in a given range.
815 rand_num(int range)
817 return (range == 0 ? 0 : RN % range);
821 * havechar:
822 * Check to see if we have any characters in the input queue; if
823 * we do, read them, stash them away, and return TRUE; else return
824 * FALSE.
826 static int
827 havechar(PLAYER *pp, int i)
830 if (pp->p_ncount < pp->p_nchar)
831 return TRUE;
832 if (!(fdset[i].revents & POLLIN))
833 return FALSE;
834 check_again:
835 errno = 0;
836 if ((pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf)) <= 0)
838 if (errno == EINTR)
839 goto check_again;
840 pp->p_cbuf[0] = 'q';
842 pp->p_ncount = 0;
843 return TRUE;
847 * cleanup:
848 * Exit with the given value, cleaning up any droppings lying around
850 void
851 cleanup(int eval)
853 PLAYER *pp;
855 for (pp = Player; pp < End_player; pp++) {
856 cgoto(pp, HEIGHT, 0);
857 sendcom(pp, ENDWIN);
858 (void) putc(LAST_PLAYER, pp->p_output);
859 (void) fclose(pp->p_output);
861 #ifdef MONITOR
862 for (pp = Monitor; pp < End_monitor; pp++) {
863 cgoto(pp, HEIGHT, 0);
864 sendcom(pp, ENDWIN);
865 (void) putc(LAST_PLAYER, pp->p_output);
866 (void) fclose(pp->p_output);
868 #endif
869 (void) close(Socket);
870 #ifdef AF_UNIX_HACK
871 (void) unlink(Sock_name);
872 #endif
874 exit(eval);
878 * send_stats:
879 * Print stats to requestor
881 static void
882 send_stats(void)
884 IDENT *ip;
885 FILE *fp;
886 int s;
887 SOCKET sockstruct;
888 socklen_t socklen;
891 * Get the output stream ready
893 #ifdef INTERNET
894 socklen = sizeof sockstruct;
895 #else
896 socklen = sizeof sockstruct - 1;
897 #endif
898 s = accept(Status, (struct sockaddr *) &sockstruct, &socklen);
899 if (s < 0) {
900 if (errno == EINTR)
901 return;
902 #ifdef LOG
903 syslog(LOG_WARNING, "accept: %m");
904 #else
905 warn("accept");
906 #endif
907 return;
909 fp = fdopen(s, "w");
910 if (fp == NULL) {
911 #ifdef LOG
912 syslog(LOG_WARNING, "fdopen: %m");
913 #else
914 warn("fdopen");
915 #endif
916 (void) close(s);
917 return;
921 * Send output to requestor
923 fputs("Name\t\tScore\tDucked\tAbsorb\tFaced\tShot\tRobbed\tMissed\tSlimeK\n", fp);
924 for (ip = Scores; ip != NULL; ip = ip->i_next) {
925 fprintf(fp, "%s\t", ip->i_name);
926 if (strlen(ip->i_name) < 8)
927 putc('\t', fp);
928 fprintf(fp, "%.2f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
929 ip->i_score, ip->i_ducked, ip->i_absorbed,
930 ip->i_faced, ip->i_shot, ip->i_robbed,
931 ip->i_missed, ip->i_slime);
933 fputs("\n\nName\t\tEnemy\tFriend\tDeaths\tStill\tSaved\n", fp);
934 for (ip = Scores; ip != NULL; ip = ip->i_next) {
935 if (ip->i_team == ' ') {
936 fprintf(fp, "%s\t", ip->i_name);
937 if (strlen(ip->i_name) < 8)
938 putc('\t', fp);
940 else {
941 fprintf(fp, "%s[%c]\t", ip->i_name, ip->i_team);
942 if (strlen(ip->i_name) + 3 < 8)
943 putc('\t', fp);
945 fprintf(fp, "%d\t%d\t%d\t%d\t%d\n",
946 ip->i_gkills, ip->i_bkills, ip->i_deaths,
947 ip->i_stillb, ip->i_saved);
950 (void) fclose(fp);
954 * clear_scores:
955 * Clear out the scores so the next session start clean
957 static void
958 clear_scores(void)
960 IDENT *ip, *nextip;
962 for (ip = Scores; ip != NULL; ip = nextip) {
963 nextip = ip->i_next;
964 (void) free(ip);
966 Scores = NULL;