]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - hunt/huntd/driver.c
88b497fb1eb3bb3dc3fc3107c3fb7edf8efa2756
1 /* $NetBSD: driver.c,v 1.31 2014/03/29 22:11:19 dholland 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.31 2014/03/29 22:11:19 dholland Exp $");
38 #include <sys/ioctl.h>
48 #include "pathnames.h"
52 static uint16_t Test_port
= TEST_PORT
;
54 static const char Sock_name
[] = PATH_HUNTSOCKET
;
55 static const char Stat_name
[] = PATH_STATSOCKET
;
61 static int Test_socket
; /* test socket to answer datagrams */
62 static bool inetd_spawned
; /* invoked via inetd */
63 static bool standard_port
= true; /* true if listening on standard port */
64 static u_short sock_port
; /* port # of tcp listen socket */
65 static u_short stat_port
; /* port # of statistics tcp socket */
66 #define DAEMON_SIZE (sizeof Daemon)
68 #define DAEMON_SIZE (sizeof Daemon - 1)
72 static int volcano
= 0; /* Explosion size */
75 static int Status
; /* stat socket */
77 static void clear_scores(void);
78 static bool havechar(PLAYER
*, int);
79 static void init(void);
80 static void makeboots(void);
81 static void send_stats(void);
82 static void zap(PLAYER
*, bool, int);
90 main(int ac
, char **av
)
99 static bool first
= true;
100 static bool server
= false;
102 const int linger
= 90 * 1000;
104 while ((c
= getopt(ac
, av
, "sp:")) != -1) {
111 standard_port
= false;
112 Test_port
= atoi(optarg
);
117 fprintf(stderr
, "Usage: %s [-s] [-p port]\n", av
[0]);
130 while (poll(fdset
, 3+MAXPL
+MAXMON
, INFTIM
) < 0)
134 syslog(LOG_WARNING
, "poll: %m");
141 if (fdset
[2].revents
& POLLIN
) {
142 namelen
= DAEMON_SIZE
;
143 (void) recvfrom(Test_socket
, &msg
, sizeof msg
,
144 0, (struct sockaddr
*) &test
, &namelen
);
145 switch (ntohs(msg
)) {
149 reply
= htons((u_short
) Nplayer
);
150 (void) sendto(Test_socket
, &reply
,
152 (struct sockaddr
*) &test
, DAEMON_SIZE
);
155 reply
= htons(stat_port
);
156 (void) sendto(Test_socket
, &reply
,
158 (struct sockaddr
*) &test
, DAEMON_SIZE
);
162 if (msg
== C_MONITOR
&& Nplayer
<= 0)
164 reply
= htons(sock_port
);
165 (void) sendto(Test_socket
, &reply
,
167 (struct sockaddr
*) &test
, DAEMON_SIZE
);
173 for (pp
= Player
, i
= 0; pp
< End_player
; pp
++, i
++)
174 if (havechar(pp
, i
+ 3)) {
179 for (pp
= Monitor
, i
= 0; pp
< End_monitor
; pp
++, i
++)
180 if (havechar(pp
, i
+ MAXPL
+ 3)) {
186 for (pp
= Player
, i
= 0; pp
< End_player
; )
187 if (pp
->p_death
[0] != '\0')
188 zap(pp
, true, i
+ 3);
192 for (pp
= Monitor
, i
= 0; pp
< End_monitor
; )
193 if (pp
->p_death
[0] != '\0')
194 zap(pp
, false, i
+ MAXPL
+ 3);
199 if (fdset
[0].revents
& POLLIN
)
202 /* announce start of game? */
206 if (fdset
[1].revents
& POLLIN
)
208 for (pp
= Player
, i
= 0; pp
< End_player
; pp
++, i
++) {
209 if (fdset
[i
+ 3].revents
& POLLIN
)
210 sendcom(pp
, READY
, pp
->p_nexec
);
212 (void) fflush(pp
->p_output
);
215 for (pp
= Monitor
, i
= 0; pp
< End_monitor
; pp
++, i
++) {
216 if (fdset
[i
+ MAXPL
+ 3].revents
& POLLIN
)
217 sendcom(pp
, READY
, pp
->p_nexec
);
219 (void) fflush(pp
->p_output
);
222 } while (Nplayer
> 0);
224 if (poll(fdset
, 3+MAXPL
+MAXMON
, linger
) > 0) {
239 for (pp
= Monitor
, i
= 0; pp
< End_monitor
; i
++)
240 zap(pp
, false, i
+ MAXPL
+ 3);
249 * Initialize the global parameters.
263 (void) ioctl(fileno(stdout
), TIOCNOTTY
, NULL
);
265 (void) setpgrp(getpid(), getpid());
266 (void) signal(SIGHUP
, SIG_IGN
);
267 (void) signal(SIGINT
, SIG_IGN
);
268 (void) signal(SIGQUIT
, SIG_IGN
);
269 (void) signal(SIGTERM
, cleanup
);
272 (void) chdir("/var/tmp"); /* just in case it core dumps */
273 (void) umask(0); /* No privacy at all! */
274 (void) signal(SIGPIPE
, SIG_IGN
);
277 openlog("huntd", LOG_PID
, LOG_DAEMON
);
281 * Initialize statistics socket
284 Daemon
.sin_family
= SOCK_FAMILY
;
285 Daemon
.sin_addr
.s_addr
= INADDR_ANY
;
288 Daemon
.sun_family
= SOCK_FAMILY
;
289 (void) strcpy(Daemon
.sun_path
, Stat_name
);
292 Status
= socket(SOCK_FAMILY
, SOCK_STREAM
, 0);
293 if (bind(Status
, (struct sockaddr
*) &Daemon
, DAEMON_SIZE
) < 0) {
294 if (errno
== EADDRINUSE
)
298 syslog(LOG_ERR
, "bind: %m");
305 (void) listen(Status
, 5);
308 len
= sizeof (SOCKET
);
309 if (getsockname(Status
, (struct sockaddr
*) &Daemon
, &len
) < 0) {
311 syslog(LOG_ERR
, "getsockname: %m");
317 stat_port
= ntohs(Daemon
.sin_port
);
321 * Initialize main socket
324 Daemon
.sin_family
= SOCK_FAMILY
;
325 Daemon
.sin_addr
.s_addr
= INADDR_ANY
;
328 Daemon
.sun_family
= SOCK_FAMILY
;
329 (void) strcpy(Daemon
.sun_path
, Sock_name
);
332 Socket
= socket(SOCK_FAMILY
, SOCK_STREAM
, 0);
333 #if defined(INTERNET)
335 if (setsockopt(Socket
, SOL_SOCKET
, SO_USELOOPBACK
, &msg
, sizeof msg
)<0)
337 syslog(LOG_WARNING
, "setsockopt loopback %m");
339 warn("setsockopt loopback");
342 if (bind(Socket
, (struct sockaddr
*) &Daemon
, DAEMON_SIZE
) < 0) {
343 if (errno
== EADDRINUSE
)
347 syslog(LOG_ERR
, "bind: %m");
354 (void) listen(Socket
, 5);
357 len
= sizeof (SOCKET
);
358 if (getsockname(Socket
, (struct sockaddr
*) &Daemon
, &len
) < 0) {
360 syslog(LOG_ERR
, "getsockname: %m");
366 sock_port
= ntohs(Daemon
.sin_port
);
370 * Initialize minimal poll mask
372 fdset
[0].fd
= Socket
;
373 fdset
[0].events
= POLLIN
;
374 fdset
[1].fd
= Status
;
375 fdset
[1].events
= POLLIN
;
378 len
= sizeof (SOCKET
);
379 if (getsockname(0, (struct sockaddr
*) &test_port
, &len
) >= 0
380 && test_port
.sin_family
== AF_INET
) {
381 inetd_spawned
= true;
383 if (test_port
.sin_port
!= htons((u_short
) Test_port
)) {
384 standard_port
= false;
385 Test_port
= ntohs(test_port
.sin_port
);
389 test_port
.sin_port
= htons((u_short
) Test_port
);
391 Test_socket
= socket(SOCK_FAMILY
, SOCK_DGRAM
, 0);
392 if (bind(Test_socket
, (struct sockaddr
*) &test_port
,
395 syslog(LOG_ERR
, "bind: %m");
401 (void) listen(Test_socket
, 5);
404 fdset
[2].fd
= Test_socket
;
405 fdset
[2].events
= POLLIN
;
416 for (i
= 0; i
< NASCII
; i
++)
418 See_over
[DOOR
] = false;
419 See_over
[WALL1
] = false;
420 See_over
[WALL2
] = false;
421 See_over
[WALL3
] = false;
423 See_over
[WALL4
] = false;
424 See_over
[WALL5
] = false;
432 * Put the boots in the maze
441 x
= rand_num(WIDTH
- 1) + 1;
442 y
= rand_num(HEIGHT
- 1) + 1;
443 } while (Maze
[y
][x
] != SPACE
);
444 Maze
[y
][x
] = BOOT_PAIR
;
445 for (pp
= Boot
; pp
< &Boot
[NBOOTS
]; pp
++)
453 * Check the damage to the given player, and see if s/he is killed
456 checkdam(PLAYER
*ouch
, PLAYER
*gotcha
, IDENT
*credit
, int amt
,
461 if (ouch
->p_death
[0] != '\0')
464 if (this_shot_type
== SLIME
)
465 switch (ouch
->p_nboots
) {
473 message(gotcha
, "He has boots on!");
477 ouch
->p_damage
+= amt
;
478 if (ouch
->p_damage
<= ouch
->p_damcap
) {
479 (void) snprintf(Buf
, sizeof(Buf
), "%2d", ouch
->p_damage
);
480 cgoto(ouch
, STAT_DAM_ROW
, STAT_VALUE_COL
);
481 outstr(ouch
, Buf
, 2);
486 switch (this_shot_type
) {
492 cp
= "Killed on impact";
496 cp
= "Stabbed to death";
497 ouch
->p_ammo
= 0; /* No exploding */
500 cp
= "Shot to death";
529 if (credit
== NULL
) {
530 (void) snprintf(ouch
->p_death
, sizeof(ouch
->p_death
),
532 (this_shot_type
== MINE
|| this_shot_type
== GMINE
) ?
533 "a mine" : "act of God");
537 (void) snprintf(ouch
->p_death
, sizeof(ouch
->p_death
),
538 "| %s by %s |", cp
, credit
->i_name
);
540 if (ouch
== gotcha
) { /* No use killing yourself */
544 else if (ouch
->p_ident
->i_team
== ' '
545 || ouch
->p_ident
->i_team
!= credit
->i_team
) {
553 credit
->i_score
= credit
->i_kills
/ (double) credit
->i_entries
;
554 ouch
->p_ident
->i_deaths
++;
555 if (ouch
->p_nchar
== 0)
556 ouch
->p_ident
->i_stillb
++;
559 gotcha
->p_damcap
+= STABDAM
;
560 gotcha
->p_damage
-= STABDAM
;
561 if (gotcha
->p_damage
< 0)
562 gotcha
->p_damage
= 0;
563 (void) snprintf(Buf
, sizeof(Buf
), "%2d/%2d", gotcha
->p_damage
,
565 cgoto(gotcha
, STAT_DAM_ROW
, STAT_VALUE_COL
);
566 outstr(gotcha
, Buf
, 5);
567 (void) snprintf(Buf
, sizeof(Buf
), "%3d",
568 (gotcha
->p_damcap
- MAXDAM
) / 2);
569 cgoto(gotcha
, STAT_KILL_ROW
, STAT_VALUE_COL
);
570 outstr(gotcha
, Buf
, 3);
571 (void) snprintf(Buf
, sizeof(Buf
), "%5.2f", gotcha
->p_ident
->i_score
);
572 for (ouch
= Player
; ouch
< End_player
; ouch
++) {
573 cgoto(ouch
, STAT_PLAY_ROW
+ 1 + (gotcha
- Player
),
575 outstr(ouch
, Buf
, 5);
578 for (ouch
= Monitor
; ouch
< End_monitor
; ouch
++) {
579 cgoto(ouch
, STAT_PLAY_ROW
+ 1 + (gotcha
- Player
),
581 outstr(ouch
, Buf
, 5);
588 * Kill off a player and take him out of the game.
591 zap(PLAYER
*pp
, bool was_player
, int i
)
600 fixshots(pp
->p_y
, pp
->p_x
, pp
->p_over
);
601 drawplayer(pp
, false);
605 len
= strlen(pp
->p_death
); /* Display the cause of death */
606 x
= (WIDTH
- len
) / 2;
607 cgoto(pp
, HEIGHT
/ 2, x
);
608 outstr(pp
, pp
->p_death
, len
);
609 for (n
= 1; n
< len
; n
++)
610 pp
->p_death
[n
] = '-';
611 pp
->p_death
[0] = '+';
612 pp
->p_death
[len
- 1] = '+';
613 cgoto(pp
, HEIGHT
/ 2 - 1, x
);
614 outstr(pp
, pp
->p_death
, len
);
615 cgoto(pp
, HEIGHT
/ 2 + 1, x
);
616 outstr(pp
, pp
->p_death
, len
);
617 cgoto(pp
, HEIGHT
, 0);
622 for (bp
= Bullets
; bp
!= NULL
; bp
= bp
->b_next
) {
623 if (bp
->b_owner
== pp
)
625 if (bp
->b_x
== pp
->p_x
&& bp
->b_y
== pp
->p_y
)
629 n
= rand_num(pp
->p_ammo
);
630 x
= rand_num(pp
->p_ammo
);
635 else if (n
== pp
->p_ammo
- 1) {
640 for (x
= MAXBOMB
- 1; x
> 0; x
--)
641 if (n
>= shot_req
[x
])
643 for (y
= MAXSLIME
- 1; y
> 0; y
--)
644 if (n
>= slime_req
[y
])
646 if (y
>= 0 && slime_req
[y
] > shot_req
[x
]) {
656 (void) add_shot(len
, pp
->p_y
, pp
->p_x
, pp
->p_face
, x
,
658 (void) snprintf(Buf
, sizeof(Buf
), "%s detonated.",
659 pp
->p_ident
->i_name
);
660 for (np
= Player
; np
< End_player
; np
++)
663 for (np
= Monitor
; np
< End_monitor
; np
++)
667 while (pp
->p_nboots
-- > 0) {
668 for (np
= Boot
; np
< &Boot
[NBOOTS
]; np
++)
669 if (np
->p_flying
< 0)
671 if (np
>= &Boot
[NBOOTS
])
672 err(1, "Too many boots");
673 np
->p_undershot
= false;
676 np
->p_flying
= rand_num(20);
677 np
->p_flyx
= 2 * rand_num(6) - 5;
678 np
->p_flyy
= 2 * rand_num(6) - 5;
681 showexpl(np
->p_y
, np
->p_x
, BOOT
);
686 else if (pp
->p_nboots
> 0) {
687 if (pp
->p_nboots
== 2)
688 Maze
[pp
->p_y
][pp
->p_x
] = BOOT_PAIR
;
690 Maze
[pp
->p_y
][pp
->p_x
] = BOOT
;
692 fixshots(pp
->p_y
, pp
->p_x
,
693 Maze
[pp
->p_y
][pp
->p_x
]);
698 volcano
+= pp
->p_ammo
- x
;
699 if (rand_num(100) < volcano
/ 50) {
701 x
= rand_num(WIDTH
/ 2) + WIDTH
/ 4;
702 y
= rand_num(HEIGHT
/ 2) + HEIGHT
/ 4;
703 } while (Maze
[y
][x
] != SPACE
);
704 (void) add_shot(LAVA
, y
, x
, LEFTS
, volcano
,
706 for (np
= Player
; np
< End_player
; np
++)
707 message(np
, "Volcano eruption.");
713 if (rand_num(100) < 2) {
715 x
= rand_num(WIDTH
/ 2) + WIDTH
/ 4;
716 y
= rand_num(HEIGHT
/ 2) + HEIGHT
/ 4;
717 } while (Maze
[y
][x
] != SPACE
);
718 add_shot(DSHOT
, y
, x
, rand_dir(),
720 rand_num(MAXBOMB
- MINDSHOT
)],
726 (void) putc(' ', pp
->p_output
);
727 (void) fclose(pp
->p_output
);
730 if (pp
!= End_player
) {
731 memcpy(pp
, End_player
, sizeof (PLAYER
));
732 fdset
[i
] = fdset
[End_player
- Player
+ 3];
733 fdset
[End_player
- Player
+ 3].fd
= -1;
734 (void) snprintf(Buf
, sizeof(Buf
), "%5.2f%c%-10.10s %c",
735 pp
->p_ident
->i_score
, stat_char(pp
),
736 pp
->p_ident
->i_name
, pp
->p_ident
->i_team
);
737 n
= STAT_PLAY_ROW
+ 1 + (pp
- Player
);
738 for (np
= Player
; np
< End_player
; np
++) {
739 cgoto(np
, n
, STAT_NAME_COL
);
740 outstr(np
, Buf
, STAT_NAME_LEN
);
743 for (np
= Monitor
; np
< End_monitor
; np
++) {
744 cgoto(np
, n
, STAT_NAME_COL
);
745 outstr(np
, Buf
, STAT_NAME_LEN
);
751 /* Erase the last player */
752 n
= STAT_PLAY_ROW
+ 1 + Nplayer
;
753 for (np
= Player
; np
< End_player
; np
++) {
754 cgoto(np
, n
, STAT_NAME_COL
);
758 for (np
= Monitor
; np
< End_monitor
; np
++) {
759 cgoto(np
, n
, STAT_NAME_COL
);
765 (void) putc(LAST_PLAYER
, pp
->p_output
);
766 (void) fclose(pp
->p_output
);
769 if (pp
!= End_monitor
) {
770 memcpy(pp
, End_monitor
, sizeof (PLAYER
));
771 fdset
[i
] = fdset
[End_monitor
- Monitor
+ MAXPL
+ 3];
772 fdset
[End_monitor
- Monitor
+ MAXPL
+ 3].fd
= -1;
773 (void) snprintf(Buf
, sizeof(Buf
), "%5.5s %-10.10s %c",
775 pp
->p_ident
->i_name
, pp
->p_ident
->i_team
);
776 n
= STAT_MON_ROW
+ 1 + (pp
- Player
);
777 for (np
= Player
; np
< End_player
; np
++) {
778 cgoto(np
, n
, STAT_NAME_COL
);
779 outstr(np
, Buf
, STAT_NAME_LEN
);
781 for (np
= Monitor
; np
< End_monitor
; np
++) {
782 cgoto(np
, n
, STAT_NAME_COL
);
783 outstr(np
, Buf
, STAT_NAME_LEN
);
788 /* Erase the last monitor */
789 n
= STAT_MON_ROW
+ 1 + (End_monitor
- Monitor
);
790 for (np
= Player
; np
< End_player
; np
++) {
791 cgoto(np
, n
, STAT_NAME_COL
);
794 for (np
= Monitor
; np
< End_monitor
; np
++) {
795 cgoto(np
, n
, STAT_NAME_COL
);
804 * Return a random number in a given range.
809 return (range
== 0 ? 0 : random() % range
);
814 * Check to see if we have any characters in the input queue; if
815 * we do, read them, stash them away, and return true; else return
819 havechar(PLAYER
*pp
, int i
)
822 if (pp
->p_ncount
< pp
->p_nchar
)
824 if (!(fdset
[i
].revents
& POLLIN
))
827 pp
->p_nchar
= read(pp
->p_fd
, pp
->p_cbuf
, sizeof pp
->p_cbuf
);
828 if (pp
->p_nchar
< 0 && errno
== EINTR
) {
830 } else if (pp
->p_nchar
<= 0) {
840 * Exit with the given value, cleaning up any droppings lying around
847 for (pp
= Player
; pp
< End_player
; pp
++) {
848 cgoto(pp
, HEIGHT
, 0);
850 (void) putc(LAST_PLAYER
, pp
->p_output
);
851 (void) fclose(pp
->p_output
);
854 for (pp
= Monitor
; pp
< End_monitor
; pp
++) {
855 cgoto(pp
, HEIGHT
, 0);
857 (void) putc(LAST_PLAYER
, pp
->p_output
);
858 (void) fclose(pp
->p_output
);
861 (void) close(Socket
);
863 (void) unlink(Sock_name
);
871 * Print stats to requestor
883 * Get the output stream ready
886 socklen
= sizeof sockstruct
;
888 socklen
= sizeof sockstruct
- 1;
890 s
= accept(Status
, (struct sockaddr
*) &sockstruct
, &socklen
);
895 syslog(LOG_WARNING
, "accept: %m");
904 syslog(LOG_WARNING
, "fdopen: %m");
913 * Send output to requestor
915 fputs("Name\t\tScore\tDucked\tAbsorb\tFaced\tShot\tRobbed\tMissed\tSlimeK\n", fp
);
916 for (ip
= Scores
; ip
!= NULL
; ip
= ip
->i_next
) {
917 fprintf(fp
, "%s\t", ip
->i_name
);
918 if (strlen(ip
->i_name
) < 8)
920 fprintf(fp
, "%.2f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
921 ip
->i_score
, ip
->i_ducked
, ip
->i_absorbed
,
922 ip
->i_faced
, ip
->i_shot
, ip
->i_robbed
,
923 ip
->i_missed
, ip
->i_slime
);
925 fputs("\n\nName\t\tEnemy\tFriend\tDeaths\tStill\tSaved\n", fp
);
926 for (ip
= Scores
; ip
!= NULL
; ip
= ip
->i_next
) {
927 if (ip
->i_team
== ' ') {
928 fprintf(fp
, "%s\t", ip
->i_name
);
929 if (strlen(ip
->i_name
) < 8)
933 fprintf(fp
, "%s[%c]\t", ip
->i_name
, ip
->i_team
);
934 if (strlen(ip
->i_name
) + 3 < 8)
937 fprintf(fp
, "%d\t%d\t%d\t%d\t%d\n",
938 ip
->i_gkills
, ip
->i_bkills
, ip
->i_deaths
,
939 ip
->i_stillb
, ip
->i_saved
);
947 * Clear out the scores so the next session start clean
954 for (ip
= Scores
; ip
!= NULL
; ip
= nextip
) {