]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - hunt/huntd/driver.c
1 /* $NetBSD: driver.c,v 1.10 2004/01/27 20:30:29 jsm Exp $ */
3 * Copyright (c) 1983-2003, Regents of the University of California.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
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
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>
35 __RCSID("$NetBSD: driver.c,v 1.10 2004/01/27 20:30:29 jsm Exp $");
38 # include <sys/ioctl.h>
39 # include <sys/stat.h>
40 # include <sys/time.h>
49 # define RN (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff)
51 # define RN ((Seed = Seed * 11109 + 13849) & 0x7fff)
58 char *First_arg
; /* pointer to argv[0] */
59 char *Last_arg
; /* pointer to end of argv/environ */
61 int Test_socket
; /* test socket to answer datagrams */
62 FLAG inetd_spawned
; /* invoked via inetd */
63 FLAG standard_port
= TRUE
; /* true if listening on standard port */
64 u_short sock_port
; /* port # of tcp listen socket */
65 u_short stat_port
; /* port # of statistics tcp socket */
66 # define DAEMON_SIZE (sizeof Daemon)
68 # define DAEMON_SIZE (sizeof Daemon - 1)
71 static void clear_scores(void);
72 static int havechar(PLAYER
*, int);
73 static void init(void);
74 int main(int, char *[], char *[]);
75 static void makeboots(void);
76 static void send_stats(void);
77 static void zap(PLAYER
*, FLAG
, int);
92 short port_num
, reply
;
96 static FLAG first
= TRUE
;
97 static FLAG server
= FALSE
;
99 const int linger
= 90 * 1000;
102 if (ep
== NULL
|| *ep
== NULL
)
106 Last_arg
= ep
[-1] + strlen(ep
[-1]);
108 while ((c
= getopt(ac
, av
, "sp:")) != -1) {
115 standard_port
= FALSE
;
116 Test_port
= atoi(optarg
);
121 fprintf(stderr
, "Usage: %s [-s] [-p port]\n", av
[0]);
134 while (poll(fdset
, 3+MAXPL
+MAXMON
, INFTIM
) < 0)
138 syslog(LOG_WARNING
, "select: %m");
145 if (fdset
[2].revents
& POLLIN
) {
146 namelen
= DAEMON_SIZE
;
147 port_num
= htons(sock_port
);
148 (void) recvfrom(Test_socket
, (char *) &msg
, sizeof msg
,
149 0, (struct sockaddr
*) &test
, &namelen
);
150 switch (ntohs(msg
)) {
154 reply
= htons((u_short
) Nplayer
);
155 (void) sendto(Test_socket
, (char *) &reply
,
157 (struct sockaddr
*) &test
, DAEMON_SIZE
);
160 reply
= htons(stat_port
);
161 (void) sendto(Test_socket
, (char *) &reply
,
163 (struct sockaddr
*) &test
, DAEMON_SIZE
);
167 if (msg
== C_MONITOR
&& Nplayer
<= 0)
169 reply
= htons(sock_port
);
170 (void) sendto(Test_socket
, (char *) &reply
,
172 (struct sockaddr
*) &test
, DAEMON_SIZE
);
178 for (pp
= Player
, i
= 0; pp
< End_player
; pp
++, i
++)
179 if (havechar(pp
, i
+ 3)) {
184 for (pp
= Monitor
, i
= 0; pp
< End_monitor
; pp
++, i
++)
185 if (havechar(pp
, i
+ MAXPL
+ 3)) {
191 for (pp
= Player
, i
= 0; pp
< End_player
; )
192 if (pp
->p_death
[0] != '\0')
193 zap(pp
, TRUE
, i
+ 3);
197 for (pp
= Monitor
, i
= 0; pp
< End_monitor
; )
198 if (pp
->p_death
[0] != '\0')
199 zap(pp
, FALSE
, i
+ MAXPL
+ 3);
204 if (fdset
[0].revents
& POLLIN
)
207 if (first
&& standard_port
)
212 if (fdset
[1].revents
& POLLIN
)
214 for (pp
= Player
, i
= 0; pp
< End_player
; pp
++, i
++) {
215 if (fdset
[i
+ 3].revents
& POLLIN
)
216 sendcom(pp
, READY
, pp
->p_nexec
);
218 (void) fflush(pp
->p_output
);
221 for (pp
= Monitor
, i
= 0; pp
< End_monitor
; pp
++, i
++) {
222 if (fdset
[i
+ MAXPL
+ 3].revents
& POLLIN
)
223 sendcom(pp
, READY
, pp
->p_nexec
);
225 (void) fflush(pp
->p_output
);
228 } while (Nplayer
> 0);
230 if (poll(fdset
, 3+MAXPL
+MAXMON
, linger
) > 0) {
245 for (pp
= Monitor
, i
= 0; pp
< End_monitor
; i
++)
246 zap(pp
, FALSE
, i
+ MAXPL
+ 3);
255 * Initialize the global parameters.
269 (void) ioctl(fileno(stdout
), TIOCNOTTY
, NULL
);
271 (void) setpgrp(getpid(), getpid());
272 (void) signal(SIGHUP
, SIG_IGN
);
273 (void) signal(SIGINT
, SIG_IGN
);
274 (void) signal(SIGQUIT
, SIG_IGN
);
275 (void) signal(SIGTERM
, cleanup
);
278 (void) chdir("/var/tmp"); /* just in case it core dumps */
279 (void) umask(0); /* No privacy at all! */
280 (void) signal(SIGPIPE
, SIG_IGN
);
284 openlog("huntd", LOG_PID
, LOG_DAEMON
);
287 openlog("huntd", LOG_PID
);
292 * Initialize statistics socket
295 Daemon
.sin_family
= SOCK_FAMILY
;
296 Daemon
.sin_addr
.s_addr
= INADDR_ANY
;
299 Daemon
.sun_family
= SOCK_FAMILY
;
300 (void) strcpy(Daemon
.sun_path
, Stat_name
);
303 Status
= socket(SOCK_FAMILY
, SOCK_STREAM
, 0);
304 if (bind(Status
, (struct sockaddr
*) &Daemon
, DAEMON_SIZE
) < 0) {
305 if (errno
== EADDRINUSE
)
309 syslog(LOG_ERR
, "bind: %m");
316 (void) listen(Status
, 5);
319 len
= sizeof (SOCKET
);
320 if (getsockname(Status
, (struct sockaddr
*) &Daemon
, &len
) < 0) {
322 syslog(LOG_ERR
, "getsockname: %m");
328 stat_port
= ntohs(Daemon
.sin_port
);
332 * Initialize main socket
335 Daemon
.sin_family
= SOCK_FAMILY
;
336 Daemon
.sin_addr
.s_addr
= INADDR_ANY
;
339 Daemon
.sun_family
= SOCK_FAMILY
;
340 (void) strcpy(Daemon
.sun_path
, Sock_name
);
343 Socket
= socket(SOCK_FAMILY
, SOCK_STREAM
, 0);
344 # if defined(INTERNET)
346 if (setsockopt(Socket
, SOL_SOCKET
, SO_USELOOPBACK
, &msg
, sizeof msg
)<0)
348 syslog(LOG_WARNING
, "setsockopt loopback %m");
350 warn("setsockopt loopback");
353 if (bind(Socket
, (struct sockaddr
*) &Daemon
, DAEMON_SIZE
) < 0) {
354 if (errno
== EADDRINUSE
)
358 syslog(LOG_ERR
, "bind: %m");
365 (void) listen(Socket
, 5);
368 len
= sizeof (SOCKET
);
369 if (getsockname(Socket
, (struct sockaddr
*) &Daemon
, &len
) < 0) {
371 syslog(LOG_ERR
, "getsockname: %m");
377 sock_port
= ntohs(Daemon
.sin_port
);
381 * Initialize minimal select mask
383 fdset
[0].fd
= Socket
;
384 fdset
[0].events
= POLLIN
;
385 fdset
[1].fd
= Status
;
386 fdset
[1].events
= POLLIN
;
389 len
= sizeof (SOCKET
);
390 if (getsockname(0, (struct sockaddr
*) &test_port
, &len
) >= 0
391 && test_port
.sin_family
== AF_INET
) {
392 inetd_spawned
= TRUE
;
394 if (test_port
.sin_port
!= htons((u_short
) Test_port
)) {
395 standard_port
= FALSE
;
396 Test_port
= ntohs(test_port
.sin_port
);
400 test_port
.sin_port
= htons((u_short
) Test_port
);
402 Test_socket
= socket(SOCK_FAMILY
, SOCK_DGRAM
, 0);
403 if (bind(Test_socket
, (struct sockaddr
*) &test_port
,
406 syslog(LOG_ERR
, "bind: %m");
412 (void) listen(Test_socket
, 5);
415 fdset
[2].fd
= Test_socket
;
416 fdset
[2].events
= POLLIN
;
421 Seed
= getpid() + time((time_t *) NULL
);
427 for (i
= 0; i
< NASCII
; i
++)
429 See_over
[DOOR
] = FALSE
;
430 See_over
[WALL1
] = FALSE
;
431 See_over
[WALL2
] = FALSE
;
432 See_over
[WALL3
] = FALSE
;
434 See_over
[WALL4
] = FALSE
;
435 See_over
[WALL5
] = FALSE
;
443 * Put the boots in the maze
452 x
= rand_num(WIDTH
- 1) + 1;
453 y
= rand_num(HEIGHT
- 1) + 1;
454 } while (Maze
[y
][x
] != SPACE
);
455 Maze
[y
][x
] = BOOT_PAIR
;
456 for (pp
= Boot
; pp
< &Boot
[NBOOTS
]; pp
++)
464 * Check the damage to the given player, and see if s/he is killed
467 checkdam(ouch
, gotcha
, credit
, amt
, shot_type
)
468 PLAYER
*ouch
, *gotcha
;
475 if (ouch
->p_death
[0] != '\0')
478 if (shot_type
== SLIME
)
479 switch (ouch
->p_nboots
) {
487 message(gotcha
, "He has boots on!");
491 ouch
->p_damage
+= amt
;
492 if (ouch
->p_damage
<= ouch
->p_damcap
) {
493 (void) sprintf(Buf
, "%2d", ouch
->p_damage
);
494 cgoto(ouch
, STAT_DAM_ROW
, STAT_VALUE_COL
);
495 outstr(ouch
, Buf
, 2);
506 cp
= "Killed on impact";
510 cp
= "Stabbed to death";
511 ouch
->p_ammo
= 0; /* No exploding */
514 cp
= "Shot to death";
543 if (credit
== NULL
) {
544 (void) sprintf(ouch
->p_death
, "| %s by %s |", cp
,
545 (shot_type
== MINE
|| shot_type
== GMINE
) ?
546 "a mine" : "act of God");
550 (void) sprintf(ouch
->p_death
, "| %s by %s |", cp
, credit
->i_name
);
552 if (ouch
== gotcha
) { /* No use killing yourself */
556 else if (ouch
->p_ident
->i_team
== ' '
557 || ouch
->p_ident
->i_team
!= credit
->i_team
) {
565 credit
->i_score
= credit
->i_kills
/ (double) credit
->i_entries
;
566 ouch
->p_ident
->i_deaths
++;
567 if (ouch
->p_nchar
== 0)
568 ouch
->p_ident
->i_stillb
++;
571 gotcha
->p_damcap
+= STABDAM
;
572 gotcha
->p_damage
-= STABDAM
;
573 if (gotcha
->p_damage
< 0)
574 gotcha
->p_damage
= 0;
575 (void) sprintf(Buf
, "%2d/%2d", gotcha
->p_damage
, gotcha
->p_damcap
);
576 cgoto(gotcha
, STAT_DAM_ROW
, STAT_VALUE_COL
);
577 outstr(gotcha
, Buf
, 5);
578 (void) sprintf(Buf
, "%3d", (gotcha
->p_damcap
- MAXDAM
) / 2);
579 cgoto(gotcha
, STAT_KILL_ROW
, STAT_VALUE_COL
);
580 outstr(gotcha
, Buf
, 3);
581 (void) sprintf(Buf
, "%5.2f", gotcha
->p_ident
->i_score
);
582 for (ouch
= Player
; ouch
< End_player
; ouch
++) {
583 cgoto(ouch
, STAT_PLAY_ROW
+ 1 + (gotcha
- Player
),
585 outstr(ouch
, Buf
, 5);
588 for (ouch
= Monitor
; ouch
< End_monitor
; ouch
++) {
589 cgoto(ouch
, STAT_PLAY_ROW
+ 1 + (gotcha
- Player
),
591 outstr(ouch
, Buf
, 5);
598 * Kill off a player and take him out of the game.
601 zap(pp
, was_player
, i
)
614 fixshots(pp
->p_y
, pp
->p_x
, pp
->p_over
);
615 drawplayer(pp
, FALSE
);
619 len
= strlen(pp
->p_death
); /* Display the cause of death */
620 x
= (WIDTH
- len
) / 2;
621 cgoto(pp
, HEIGHT
/ 2, x
);
622 outstr(pp
, pp
->p_death
, len
);
623 for (n
= 1; n
< len
; n
++)
624 pp
->p_death
[n
] = '-';
625 pp
->p_death
[0] = '+';
626 pp
->p_death
[len
- 1] = '+';
627 cgoto(pp
, HEIGHT
/ 2 - 1, x
);
628 outstr(pp
, pp
->p_death
, len
);
629 cgoto(pp
, HEIGHT
/ 2 + 1, x
);
630 outstr(pp
, pp
->p_death
, len
);
631 cgoto(pp
, HEIGHT
, 0);
638 for (bp
= Bullets
; bp
!= NULL
; bp
= bp
->b_next
) {
639 if (bp
->b_owner
== pp
)
641 if (bp
->b_x
== pp
->p_x
&& bp
->b_y
== pp
->p_y
)
645 n
= rand_num(pp
->p_ammo
);
646 x
= rand_num(pp
->p_ammo
);
651 else if (n
== pp
->p_ammo
- 1) {
656 for (x
= MAXBOMB
- 1; x
> 0; x
--)
657 if (n
>= shot_req
[x
])
659 for (y
= MAXSLIME
- 1; y
> 0; y
--)
660 if (n
>= slime_req
[y
])
662 if (y
>= 0 && slime_req
[y
] > shot_req
[x
]) {
672 (void) add_shot(len
, pp
->p_y
, pp
->p_x
, pp
->p_face
, x
,
673 (PLAYER
*) NULL
, TRUE
, SPACE
);
674 (void) sprintf(Buf
, "%s detonated.",
675 pp
->p_ident
->i_name
);
676 for (np
= Player
; np
< End_player
; np
++)
679 for (np
= Monitor
; np
< End_monitor
; np
++)
683 while (pp
->p_nboots
-- > 0) {
684 for (np
= Boot
; np
< &Boot
[NBOOTS
]; np
++)
685 if (np
->p_flying
< 0)
687 if (np
>= &Boot
[NBOOTS
])
688 err(1, "Too many boots");
689 np
->p_undershot
= FALSE
;
692 np
->p_flying
= rand_num(20);
693 np
->p_flyx
= 2 * rand_num(6) - 5;
694 np
->p_flyy
= 2 * rand_num(6) - 5;
697 showexpl(np
->p_y
, np
->p_x
, BOOT
);
702 else if (pp
->p_nboots
> 0) {
703 if (pp
->p_nboots
== 2)
704 Maze
[pp
->p_y
][pp
->p_x
] = BOOT_PAIR
;
706 Maze
[pp
->p_y
][pp
->p_x
] = BOOT
;
708 fixshots(pp
->p_y
, pp
->p_x
,
709 Maze
[pp
->p_y
][pp
->p_x
]);
714 volcano
+= pp
->p_ammo
- x
;
715 if (rand_num(100) < volcano
/ 50) {
717 x
= rand_num(WIDTH
/ 2) + WIDTH
/ 4;
718 y
= rand_num(HEIGHT
/ 2) + HEIGHT
/ 4;
719 } while (Maze
[y
][x
] != SPACE
);
720 (void) add_shot(LAVA
, y
, x
, LEFTS
, volcano
,
721 (PLAYER
*) NULL
, TRUE
, SPACE
);
722 for (np
= Player
; np
< End_player
; np
++)
723 message(np
, "Volcano eruption.");
729 if (rand_num(100) < 2) {
731 x
= rand_num(WIDTH
/ 2) + WIDTH
/ 4;
732 y
= rand_num(HEIGHT
/ 2) + HEIGHT
/ 4;
733 } while (Maze
[y
][x
] != SPACE
);
734 add_shot(DSHOT
, y
, x
, rand_dir(),
736 rand_num(MAXBOMB
- MINDSHOT
)],
737 (PLAYER
*) NULL
, FALSE
, SPACE
);
742 (void) putc(' ', pp
->p_output
);
743 (void) fclose(pp
->p_output
);
746 if (pp
!= End_player
) {
747 memcpy(pp
, End_player
, sizeof (PLAYER
));
748 fdset
[i
] = fdset
[End_player
- Player
+ 3];
749 fdset
[End_player
- Player
+ 3].fd
= -1;
750 (void) sprintf(Buf
, "%5.2f%c%-10.10s %c",
751 pp
->p_ident
->i_score
, stat_char(pp
),
752 pp
->p_ident
->i_name
, pp
->p_ident
->i_team
);
753 n
= STAT_PLAY_ROW
+ 1 + (pp
- Player
);
754 for (np
= Player
; np
< End_player
; np
++) {
755 cgoto(np
, n
, STAT_NAME_COL
);
756 outstr(np
, Buf
, STAT_NAME_LEN
);
759 for (np
= Monitor
; np
< End_monitor
; np
++) {
760 cgoto(np
, n
, STAT_NAME_COL
);
761 outstr(np
, Buf
, STAT_NAME_LEN
);
767 /* Erase the last player */
768 n
= STAT_PLAY_ROW
+ 1 + Nplayer
;
769 for (np
= Player
; np
< End_player
; np
++) {
770 cgoto(np
, n
, STAT_NAME_COL
);
774 for (np
= Monitor
; np
< End_monitor
; np
++) {
775 cgoto(np
, n
, STAT_NAME_COL
);
781 (void) putc(LAST_PLAYER
, pp
->p_output
);
782 (void) fclose(pp
->p_output
);
785 if (pp
!= End_monitor
) {
786 memcpy(pp
, End_monitor
, sizeof (PLAYER
));
787 fdset
[i
] = fdset
[End_monitor
- Monitor
+ MAXPL
+ 3];
788 fdset
[End_monitor
- Monitor
+ MAXPL
+ 3].fd
= -1;
789 (void) sprintf(Buf
, "%5.5s %-10.10s %c", " ",
790 pp
->p_ident
->i_name
, pp
->p_ident
->i_team
);
791 n
= STAT_MON_ROW
+ 1 + (pp
- Player
);
792 for (np
= Player
; np
< End_player
; np
++) {
793 cgoto(np
, n
, STAT_NAME_COL
);
794 outstr(np
, Buf
, STAT_NAME_LEN
);
796 for (np
= Monitor
; np
< End_monitor
; np
++) {
797 cgoto(np
, n
, STAT_NAME_COL
);
798 outstr(np
, Buf
, STAT_NAME_LEN
);
803 /* Erase the last monitor */
804 n
= STAT_MON_ROW
+ 1 + (End_monitor
- Monitor
);
805 for (np
= Player
; np
< End_player
; np
++) {
806 cgoto(np
, n
, STAT_NAME_COL
);
809 for (np
= Monitor
; np
< End_monitor
; np
++) {
810 cgoto(np
, n
, STAT_NAME_COL
);
819 * Return a random number in a given range.
825 return (range
== 0 ? 0 : RN
% range
);
830 * Check to see if we have any characters in the input queue; if
831 * we do, read them, stash them away, and return TRUE; else return
840 if (pp
->p_ncount
< pp
->p_nchar
)
842 if (!(fdset
[i
].revents
& POLLIN
))
846 if ((pp
->p_nchar
= read(pp
->p_fd
, pp
->p_cbuf
, sizeof pp
->p_cbuf
)) <= 0)
858 * Exit with the given value, cleaning up any droppings lying around
866 for (pp
= Player
; pp
< End_player
; pp
++) {
867 cgoto(pp
, HEIGHT
, 0);
869 (void) putc(LAST_PLAYER
, pp
->p_output
);
870 (void) fclose(pp
->p_output
);
873 for (pp
= Monitor
; pp
< End_monitor
; pp
++) {
874 cgoto(pp
, HEIGHT
, 0);
876 (void) putc(LAST_PLAYER
, pp
->p_output
);
877 (void) fclose(pp
->p_output
);
880 (void) close(Socket
);
882 (void) unlink(Sock_name
);
890 * Print stats to requestor
902 * Get the output stream ready
905 socklen
= sizeof sockstruct
;
907 socklen
= sizeof sockstruct
- 1;
909 s
= accept(Status
, (struct sockaddr
*) &sockstruct
, &socklen
);
914 syslog(LOG_WARNING
, "accept: %m");
923 syslog(LOG_WARNING
, "fdopen: %m");
932 * Send output to requestor
934 fputs("Name\t\tScore\tDucked\tAbsorb\tFaced\tShot\tRobbed\tMissed\tSlimeK\n", fp
);
935 for (ip
= Scores
; ip
!= NULL
; ip
= ip
->i_next
) {
936 fprintf(fp
, "%s\t", ip
->i_name
);
937 if (strlen(ip
->i_name
) < 8)
939 fprintf(fp
, "%.2f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
940 ip
->i_score
, ip
->i_ducked
, ip
->i_absorbed
,
941 ip
->i_faced
, ip
->i_shot
, ip
->i_robbed
,
942 ip
->i_missed
, ip
->i_slime
);
944 fputs("\n\nName\t\tEnemy\tFriend\tDeaths\tStill\tSaved\n", fp
);
945 for (ip
= Scores
; ip
!= NULL
; ip
= ip
->i_next
) {
946 if (ip
->i_team
== ' ') {
947 fprintf(fp
, "%s\t", ip
->i_name
);
948 if (strlen(ip
->i_name
) < 8)
952 fprintf(fp
, "%s[%c]\t", ip
->i_name
, ip
->i_team
);
953 if (strlen(ip
->i_name
) + 3 < 8)
956 fprintf(fp
, "%d\t%d\t%d\t%d\t%d\n",
957 ip
->i_gkills
, ip
->i_bkills
, ip
->i_deaths
,
958 ip
->i_stillb
, ip
->i_saved
);
966 * Clear out the scores so the next session start clean
973 for (ip
= Scores
; ip
!= NULL
; ip
= nextip
) {
975 (void) free((char *) ip
);