]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - hunt/huntd/driver.c
1f3b47a376ad86351d20b8162fb067e5a3b935a1
1 /* $NetBSD: driver.c,v 1.2 1997/10/10 16:33:08 lukem Exp $ */
4 * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
5 * San Francisco, California
10 __RCSID("$NetBSD: driver.c,v 1.2 1997/10/10 16:33:08 lukem Exp $");
13 # include <sys/ioctl.h>
14 # include <sys/stat.h>
15 # include <sys/time.h>
24 # define RN (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff)
26 # define RN ((Seed = Seed * 11109 + 13849) & 0x7fff)
33 char *First_arg
; /* pointer to argv[0] */
34 char *Last_arg
; /* pointer to end of argv/environ */
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)
43 # define DAEMON_SIZE (sizeof Daemon - 1)
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
));
68 short port_num
, reply
;
72 static fd_set read_fds
;
73 static FLAG first
= TRUE
;
74 static FLAG server
= FALSE
;
78 static struct timeval linger
= { 90, 0 };
81 if (ep
== NULL
|| *ep
== NULL
)
85 Last_arg
= ep
[-1] + strlen(ep
[-1]);
87 while ((c
= getopt(ac
, av
, "sp:")) != -1) {
94 standard_port
= FALSE
;
95 Test_port
= atoi(optarg
);
100 fprintf(stderr
, "Usage: %s [-s] [-p port]\n", av
[0]);
114 while (select(Num_fds
, &read_fds
, NULL
, NULL
, NULL
) < 0)
118 syslog(LOG_WARNING
, "select: %m");
126 if (FD_ISSET(Test_socket
, &read_fds
)) {
127 namelen
= DAEMON_SIZE
;
128 port_num
= htons(sock_port
);
129 (void) recvfrom(Test_socket
, (char *) &msg
, sizeof msg
,
130 0, (struct sockaddr
*) &test
, &namelen
);
131 switch (ntohs(msg
)) {
135 reply
= htons((u_short
) Nplayer
);
136 (void) sendto(Test_socket
, (char *) &reply
,
138 (struct sockaddr
*) &test
, DAEMON_SIZE
);
141 reply
= htons(stat_port
);
142 (void) sendto(Test_socket
, (char *) &reply
,
144 (struct sockaddr
*) &test
, DAEMON_SIZE
);
148 if (msg
== C_MONITOR
&& Nplayer
<= 0)
150 reply
= htons(sock_port
);
151 (void) sendto(Test_socket
, (char *) &reply
,
153 (struct sockaddr
*) &test
, DAEMON_SIZE
);
160 for (pp
= Player
; pp
< End_player
; pp
++)
167 for (pp
= Monitor
; pp
< End_monitor
; pp
++)
177 for (pp
= Player
; pp
< End_player
; )
178 if (pp
->p_death
[0] != '\0')
183 for (pp
= Monitor
; pp
< End_monitor
; )
184 if (pp
->p_death
[0] != '\0')
190 if (FD_ISSET(Socket
, &read_fds
))
193 if (first
&& standard_port
)
198 if (FD_ISSET(Status
, &read_fds
))
200 for (pp
= Player
; pp
< End_player
; pp
++) {
201 if (FD_ISSET(pp
->p_fd
, &read_fds
))
202 sendcom(pp
, READY
, pp
->p_nexec
);
204 (void) fflush(pp
->p_output
);
207 for (pp
= Monitor
; pp
< End_monitor
; pp
++) {
208 if (FD_ISSET(pp
->p_fd
, &read_fds
))
209 sendcom(pp
, READY
, pp
->p_nexec
);
211 (void) fflush(pp
->p_output
);
214 } while (Nplayer
> 0);
217 if (select(Num_fds
, &read_fds
, NULL
, NULL
, &linger
) > 0) {
232 for (pp
= Monitor
; pp
< End_monitor
; )
242 * Initialize the global parameters.
256 (void) ioctl(fileno(stdout
), TIOCNOTTY
, NULL
);
258 (void) setpgrp(getpid(), getpid());
259 (void) signal(SIGHUP
, SIG_IGN
);
260 (void) signal(SIGINT
, SIG_IGN
);
261 (void) signal(SIGQUIT
, SIG_IGN
);
262 (void) signal(SIGTERM
, cleanup
);
265 (void) chdir("/usr/tmp"); /* just in case it core dumps */
266 (void) umask(0); /* No privacy at all! */
267 (void) signal(SIGPIPE
, SIG_IGN
);
271 openlog("HUNT", LOG_PID
, LOG_DAEMON
);
274 openlog("HUNT", LOG_PID
);
279 * Initialize statistics socket
282 Daemon
.sin_family
= SOCK_FAMILY
;
283 Daemon
.sin_addr
.s_addr
= INADDR_ANY
;
286 Daemon
.sun_family
= SOCK_FAMILY
;
287 (void) strcpy(Daemon
.sun_path
, Stat_name
);
290 Status
= socket(SOCK_FAMILY
, SOCK_STREAM
, 0);
291 if (bind(Status
, (struct sockaddr
*) &Daemon
, DAEMON_SIZE
) < 0) {
292 if (errno
== EADDRINUSE
)
296 syslog(LOG_ERR
, "bind: %m");
303 (void) listen(Status
, 5);
306 len
= sizeof (SOCKET
);
307 if (getsockname(Status
, (struct sockaddr
*) &Daemon
, &len
) < 0) {
309 syslog(LOG_ERR
, "getsockname: %m");
311 perror("getsockname");
315 stat_port
= ntohs(Daemon
.sin_port
);
319 * Initialize main socket
322 Daemon
.sin_family
= SOCK_FAMILY
;
323 Daemon
.sin_addr
.s_addr
= INADDR_ANY
;
326 Daemon
.sun_family
= SOCK_FAMILY
;
327 (void) strcpy(Daemon
.sun_path
, Sock_name
);
330 Socket
= socket(SOCK_FAMILY
, SOCK_STREAM
, 0);
331 # if defined(INTERNET)
333 if (setsockopt(Socket
, SOL_SOCKET
, SO_USELOOPBACK
, &msg
, sizeof msg
)<0)
335 syslog(LOG_WARNING
, "setsockopt loopback %m");
337 perror("setsockopt loopback");
340 if (bind(Socket
, (struct sockaddr
*) &Daemon
, DAEMON_SIZE
) < 0) {
341 if (errno
== EADDRINUSE
)
345 syslog(LOG_ERR
, "bind: %m");
352 (void) listen(Socket
, 5);
355 len
= sizeof (SOCKET
);
356 if (getsockname(Socket
, (struct sockaddr
*) &Daemon
, &len
) < 0) {
358 syslog(LOG_ERR
, "getsockname: %m");
360 perror("getsockname");
364 sock_port
= ntohs(Daemon
.sin_port
);
368 * Initialize minimal select mask
370 FD_SET(Socket
, &Fds_mask
);
371 FD_SET(Status
, &Fds_mask
);
372 Num_fds
= ((Socket
> Status
) ? Socket
: Status
) + 1;
375 len
= sizeof (SOCKET
);
376 if (getsockname(0, (struct sockaddr
*) &test_port
, &len
) >= 0
377 && test_port
.sin_family
== AF_INET
) {
378 inetd_spawned
= TRUE
;
380 if (test_port
.sin_port
!= htons((u_short
) Test_port
)) {
381 standard_port
= FALSE
;
382 Test_port
= ntohs(test_port
.sin_port
);
386 test_port
.sin_port
= htons((u_short
) Test_port
);
388 Test_socket
= socket(SOCK_FAMILY
, SOCK_DGRAM
, 0);
389 if (bind(Test_socket
, (struct sockaddr
*) &test_port
,
392 syslog(LOG_ERR
, "bind: %m");
398 (void) listen(Test_socket
, 5);
401 FD_SET(Test_socket
, &Fds_mask
);
402 if (Test_socket
+ 1 > Num_fds
)
403 Num_fds
= Test_socket
+ 1;
406 Seed
= getpid() + time((time_t *) NULL
);
412 for (i
= 0; i
< NASCII
; i
++)
414 See_over
[DOOR
] = FALSE
;
415 See_over
[WALL1
] = FALSE
;
416 See_over
[WALL2
] = FALSE
;
417 See_over
[WALL3
] = FALSE
;
419 See_over
[WALL4
] = FALSE
;
420 See_over
[WALL5
] = FALSE
;
428 * Put the boots in the maze
437 x
= rand_num(WIDTH
- 1) + 1;
438 y
= rand_num(HEIGHT
- 1) + 1;
439 } while (Maze
[y
][x
] != SPACE
);
440 Maze
[y
][x
] = BOOT_PAIR
;
441 for (pp
= Boot
; pp
< &Boot
[NBOOTS
]; pp
++)
449 * Check the damage to the given player, and see if s/he is killed
452 checkdam(ouch
, gotcha
, credit
, amt
, shot_type
)
453 PLAYER
*ouch
, *gotcha
;
460 if (ouch
->p_death
[0] != '\0')
463 if (shot_type
== SLIME
)
464 switch (ouch
->p_nboots
) {
472 message(gotcha
, "He has boots on!");
476 ouch
->p_damage
+= amt
;
477 if (ouch
->p_damage
<= ouch
->p_damcap
) {
478 (void) sprintf(Buf
, "%2d", ouch
->p_damage
);
479 cgoto(ouch
, STAT_DAM_ROW
, STAT_VALUE_COL
);
480 outstr(ouch
, Buf
, 2);
491 cp
= "Killed on impact";
495 cp
= "Stabbed to death";
496 ouch
->p_ammo
= 0; /* No exploding */
499 cp
= "Shot to death";
528 if (credit
== NULL
) {
529 (void) sprintf(ouch
->p_death
, "| %s by %s |", cp
,
530 (shot_type
== MINE
|| shot_type
== GMINE
) ?
531 "a mine" : "act of God");
535 (void) sprintf(ouch
->p_death
, "| %s by %s |", cp
, credit
->i_name
);
537 if (ouch
== gotcha
) { /* No use killing yourself */
541 else if (ouch
->p_ident
->i_team
== ' '
542 || ouch
->p_ident
->i_team
!= credit
->i_team
) {
550 credit
->i_score
= credit
->i_kills
/ (double) credit
->i_entries
;
551 ouch
->p_ident
->i_deaths
++;
552 if (ouch
->p_nchar
== 0)
553 ouch
->p_ident
->i_stillb
++;
556 gotcha
->p_damcap
+= STABDAM
;
557 gotcha
->p_damage
-= STABDAM
;
558 if (gotcha
->p_damage
< 0)
559 gotcha
->p_damage
= 0;
560 (void) sprintf(Buf
, "%2d/%2d", gotcha
->p_damage
, gotcha
->p_damcap
);
561 cgoto(gotcha
, STAT_DAM_ROW
, STAT_VALUE_COL
);
562 outstr(gotcha
, Buf
, 5);
563 (void) sprintf(Buf
, "%3d", (gotcha
->p_damcap
- MAXDAM
) / 2);
564 cgoto(gotcha
, STAT_KILL_ROW
, STAT_VALUE_COL
);
565 outstr(gotcha
, Buf
, 3);
566 (void) sprintf(Buf
, "%5.2f", gotcha
->p_ident
->i_score
);
567 for (ouch
= Player
; ouch
< End_player
; ouch
++) {
568 cgoto(ouch
, STAT_PLAY_ROW
+ 1 + (gotcha
- Player
),
570 outstr(ouch
, Buf
, 5);
573 for (ouch
= Monitor
; ouch
< End_monitor
; ouch
++) {
574 cgoto(ouch
, STAT_PLAY_ROW
+ 1 + (gotcha
- Player
),
576 outstr(ouch
, Buf
, 5);
583 * Kill off a player and take him out of the game.
598 fixshots(pp
->p_y
, pp
->p_x
, pp
->p_over
);
599 drawplayer(pp
, FALSE
);
603 len
= strlen(pp
->p_death
); /* Display the cause of death */
604 x
= (WIDTH
- len
) / 2;
605 cgoto(pp
, HEIGHT
/ 2, x
);
606 outstr(pp
, pp
->p_death
, len
);
607 for (i
= 1; i
< len
; i
++)
608 pp
->p_death
[i
] = '-';
609 pp
->p_death
[0] = '+';
610 pp
->p_death
[len
- 1] = '+';
611 cgoto(pp
, HEIGHT
/ 2 - 1, x
);
612 outstr(pp
, pp
->p_death
, len
);
613 cgoto(pp
, HEIGHT
/ 2 + 1, x
);
614 outstr(pp
, pp
->p_death
, len
);
615 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 i
= rand_num(pp
->p_ammo
);
630 x
= rand_num(pp
->p_ammo
);
635 else if (i
== pp
->p_ammo
- 1) {
640 for (x
= MAXBOMB
- 1; x
> 0; x
--)
641 if (i
>= shot_req
[x
])
643 for (y
= MAXSLIME
- 1; y
> 0; y
--)
644 if (i
>= 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
,
657 (PLAYER
*) NULL
, TRUE
, SPACE
);
658 (void) sprintf(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
,
705 (PLAYER
*) NULL
, TRUE
, SPACE
);
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
)],
721 (PLAYER
*) NULL
, FALSE
, SPACE
);
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 (void) sprintf(Buf
, "%5.2f%c%-10.10s %c",
733 pp
->p_ident
->i_score
, stat_char(pp
),
734 pp
->p_ident
->i_name
, pp
->p_ident
->i_team
);
735 i
= STAT_PLAY_ROW
+ 1 + (pp
- Player
);
736 for (np
= Player
; np
< End_player
; np
++) {
737 cgoto(np
, i
, STAT_NAME_COL
);
738 outstr(np
, Buf
, STAT_NAME_LEN
);
741 for (np
= Monitor
; np
< End_monitor
; np
++) {
742 cgoto(np
, i
, STAT_NAME_COL
);
743 outstr(np
, Buf
, STAT_NAME_LEN
);
748 /* Erase the last player */
749 i
= STAT_PLAY_ROW
+ 1 + Nplayer
;
750 for (np
= Player
; np
< End_player
; np
++) {
751 cgoto(np
, i
, STAT_NAME_COL
);
755 for (np
= Monitor
; np
< End_monitor
; np
++) {
756 cgoto(np
, i
, STAT_NAME_COL
);
762 (void) putc(LAST_PLAYER
, pp
->p_output
);
763 (void) fclose(pp
->p_output
);
766 if (pp
!= End_monitor
) {
767 memcpy(pp
, End_monitor
, sizeof (PLAYER
));
768 (void) sprintf(Buf
, "%5.5s %-10.10s %c", " ",
769 pp
->p_ident
->i_name
, pp
->p_ident
->i_team
);
770 i
= STAT_MON_ROW
+ 1 + (pp
- Player
);
771 for (np
= Player
; np
< End_player
; np
++) {
772 cgoto(np
, i
, STAT_NAME_COL
);
773 outstr(np
, Buf
, STAT_NAME_LEN
);
775 for (np
= Monitor
; np
< End_monitor
; np
++) {
776 cgoto(np
, i
, STAT_NAME_COL
);
777 outstr(np
, Buf
, STAT_NAME_LEN
);
781 /* Erase the last monitor */
782 i
= STAT_MON_ROW
+ 1 + (End_monitor
- Monitor
);
783 for (np
= Player
; np
< End_player
; np
++) {
784 cgoto(np
, i
, STAT_NAME_COL
);
787 for (np
= Monitor
; np
< End_monitor
; np
++) {
788 cgoto(np
, i
, STAT_NAME_COL
);
795 FD_CLR(savefd
, &Fds_mask
);
796 if (Num_fds
== savefd
+ 1) {
799 if (Test_socket
> Socket
)
800 Num_fds
= Test_socket
;
802 for (np
= Player
; np
< End_player
; np
++)
803 if (np
->p_fd
> Num_fds
)
806 for (np
= Monitor
; np
< End_monitor
; np
++)
807 if (np
->p_fd
> Num_fds
)
816 * Return a random number in a given range.
822 return (range
== 0 ? 0 : RN
% range
);
827 * Check to see if we have any characters in the input queue; if
828 * we do, read them, stash them away, and return TRUE; else return
836 if (pp
->p_ncount
< pp
->p_nchar
)
838 if (!FD_ISSET(pp
->p_fd
, &Have_inp
))
840 FD_CLR(pp
->p_fd
, &Have_inp
);
843 if ((pp
->p_nchar
= read(pp
->p_fd
, pp
->p_cbuf
, sizeof pp
->p_cbuf
)) <= 0)
855 * Exit with the given value, cleaning up any droppings lying around
863 for (pp
= Player
; pp
< End_player
; pp
++) {
864 cgoto(pp
, HEIGHT
, 0);
866 (void) putc(LAST_PLAYER
, pp
->p_output
);
867 (void) fclose(pp
->p_output
);
870 for (pp
= Monitor
; pp
< End_monitor
; pp
++) {
871 cgoto(pp
, HEIGHT
, 0);
873 (void) putc(LAST_PLAYER
, pp
->p_output
);
874 (void) fclose(pp
->p_output
);
877 (void) close(Socket
);
879 (void) unlink(Sock_name
);
887 * Print stats to requestor
899 * Get the output stream ready
902 socklen
= sizeof sockstruct
;
904 socklen
= sizeof sockstruct
- 1;
906 s
= accept(Status
, (struct sockaddr
*) &sockstruct
, &socklen
);
911 syslog(LOG_ERR
, "accept: %m");
920 syslog(LOG_ERR
, "fdopen: %m");
929 * Send output to requestor
931 fputs("Name\t\tScore\tDucked\tAbsorb\tFaced\tShot\tRobbed\tMissed\tSlimeK\n", fp
);
932 for (ip
= Scores
; ip
!= NULL
; ip
= ip
->i_next
) {
933 fprintf(fp
, "%s\t", ip
->i_name
);
934 if (strlen(ip
->i_name
) < 8)
936 fprintf(fp
, "%.2f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
937 ip
->i_score
, ip
->i_ducked
, ip
->i_absorbed
,
938 ip
->i_faced
, ip
->i_shot
, ip
->i_robbed
,
939 ip
->i_missed
, ip
->i_slime
);
941 fputs("\n\nName\t\tEnemy\tFriend\tDeaths\tStill\tSaved\n", fp
);
942 for (ip
= Scores
; ip
!= NULL
; ip
= ip
->i_next
) {
943 if (ip
->i_team
== ' ') {
944 fprintf(fp
, "%s\t", ip
->i_name
);
945 if (strlen(ip
->i_name
) < 8)
949 fprintf(fp
, "%s[%c]\t", ip
->i_name
, ip
->i_team
);
950 if (strlen(ip
->i_name
) + 3 < 8)
953 fprintf(fp
, "%d\t%d\t%d\t%d\t%d\n",
954 ip
->i_gkills
, ip
->i_bkills
, ip
->i_deaths
,
955 ip
->i_stillb
, ip
->i_saved
);
963 * Clear out the scores so the next session start clean
970 for (ip
= Scores
; ip
!= NULL
; ip
= nextip
) {
972 (void) free((char *) ip
);