1 1.36 rillig /* $NetBSD: driver.c,v 1.36 2021/05/02 12:50:45 rillig Exp $ */ 2 1.1 mrg /* 3 1.9 wiz * Copyright (c) 1983-2003, Regents of the University of California. 4 1.9 wiz * All rights reserved. 5 1.36 rillig * 6 1.36 rillig * Redistribution and use in source and binary forms, with or without 7 1.36 rillig * modification, are permitted provided that the following conditions are 8 1.9 wiz * met: 9 1.36 rillig * 10 1.36 rillig * + Redistributions of source code must retain the above copyright 11 1.9 wiz * notice, this list of conditions and the following disclaimer. 12 1.36 rillig * + Redistributions in binary form must reproduce the above copyright 13 1.36 rillig * notice, this list of conditions and the following disclaimer in the 14 1.9 wiz * documentation and/or other materials provided with the distribution. 15 1.36 rillig * + Neither the name of the University of California, San Francisco nor 16 1.36 rillig * the names of its contributors may be used to endorse or promote 17 1.36 rillig * products derived from this software without specific prior written 18 1.9 wiz * permission. 19 1.36 rillig * 20 1.36 rillig * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 1.36 rillig * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.36 rillig * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 1.36 rillig * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 1.36 rillig * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 1.36 rillig * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 1.36 rillig * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 1.36 rillig * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 1.36 rillig * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 1.36 rillig * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 1.9 wiz * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 1.1 mrg */ 32 1.1 mrg 33 1.2 lukem #include <sys/cdefs.h> 34 1.2 lukem #ifndef lint 35 1.36 rillig __RCSID("$NetBSD: driver.c,v 1.36 2021/05/02 12:50:45 rillig Exp $"); 36 1.2 lukem #endif /* not lint */ 37 1.2 lukem 38 1.33 dholland #include <sys/types.h> 39 1.33 dholland #include <sys/socket.h> 40 1.17 dholland #include <sys/stat.h> 41 1.17 dholland #include <sys/time.h> 42 1.35 dholland #include <sys/un.h> 43 1.35 dholland 44 1.35 dholland #include <netinet/in.h> 45 1.35 dholland #include <netdb.h> 46 1.35 dholland #include <arpa/inet.h> 47 1.35 dholland #include <net/if.h> 48 1.35 dholland 49 1.17 dholland #include <stdlib.h> 50 1.17 dholland #include <unistd.h> 51 1.35 dholland #include <signal.h> 52 1.35 dholland #include <errno.h> 53 1.35 dholland #include <err.h> 54 1.31 dholland 55 1.31 dholland #include "hunt.h" 56 1.31 dholland #include "pathnames.h" 57 1.17 dholland 58 1.34 dholland /* 59 1.34 dholland * There are three listening sockets in this daemon: 60 1.34 dholland * - a datagram socket that listens on a well known port 61 1.34 dholland * - a stream socket for general player connections 62 1.34 dholland * - a second stream socket that prints the stats/scores 63 1.34 dholland * 64 1.34 dholland * These are (now) named as follows: 65 1.34 dholland * - contact (contactsock, contactaddr, etc.) 66 1.34 dholland * - hunt (huntsock, huntaddr, etc.) 67 1.34 dholland * - stat (statsock, stataddr, etc.) 68 1.34 dholland * 69 1.34 dholland * Until being cleaned up in 2014 the code used an assortment of 70 1.34 dholland * inconsistent and confusing names to refer to the pieces of these: 71 1.34 dholland * 72 1.34 dholland * test_port -> contactaddr 73 1.34 dholland * Test_port -> contactport 74 1.34 dholland * Test_socket -> contactsock 75 1.34 dholland * 76 1.34 dholland * sock_port -> huntport 77 1.34 dholland * Socket -> huntsock 78 1.34 dholland * 79 1.34 dholland * Daemon -> both stataddr and huntaddr 80 1.34 dholland * stat_port -> statport 81 1.34 dholland * status -> statsock 82 1.34 dholland * 83 1.34 dholland * It isn't clear to me what purpose contactsocket is supposed to 84 1.34 dholland * serve; maybe it was supposed to avoid asking inetd to support 85 1.34 dholland * tcp/wait sockets? Anyway, we can't really change the protocol at 86 1.34 dholland * this point. (To complicate matters, contactsocket doesn't exist if 87 1.34 dholland * using AF_UNIX sockets; you just connect to the game socket.) 88 1.34 dholland * 89 1.34 dholland * When using internet sockets: 90 1.34 dholland * - the contact socket listens on INADDR_ANY using the game port 91 1.34 dholland * (either specified or the default: CONTACT_PORT, currently 92 1.34 dholland * spelled TEST_PORT) 93 1.34 dholland * - the hunt socket listens on INADDR_ANY using whatever port 94 1.34 dholland * - the stat socket listens on INADDR_ANY using whatever port 95 1.34 dholland * 96 1.34 dholland * When using AF_UNIX sockets: 97 1.34 dholland * - the contact socket isn't used 98 1.34 dholland * - the hunt socket listens on the game socket (either a specified path 99 1.34 dholland * or /tmp/hunt) 100 1.34 dholland * - the stat socket listens on its own socket (huntsocket's path + 101 1.34 dholland * ".stats") 102 1.34 dholland */ 103 1.34 dholland 104 1.35 dholland static bool localmode; /* true -> AF_UNIX; false -> AF_INET */ 105 1.35 dholland static bool inetd_spawned; /* invoked via inetd? */ 106 1.35 dholland static bool standard_port = true; /* listening on standard port? */ 107 1.35 dholland 108 1.35 dholland static struct sockaddr_storage huntaddr; 109 1.35 dholland static struct sockaddr_storage stataddr; 110 1.35 dholland static socklen_t huntaddrlen; 111 1.35 dholland static socklen_t stataddrlen; 112 1.35 dholland 113 1.34 dholland static uint16_t contactport = TEST_PORT; 114 1.34 dholland static uint16_t huntport; /* port # of tcp listen socket */ 115 1.34 dholland static uint16_t statport; /* port # of statistics tcp socket */ 116 1.35 dholland 117 1.35 dholland static const char *huntsockpath = PATH_HUNTSOCKET; 118 1.35 dholland static char *statsockpath; 119 1.35 dholland 120 1.34 dholland static int contactsock; /* socket to answer datagrams */ 121 1.34 dholland int huntsock; /* main socket */ 122 1.34 dholland static int statsock; /* stat socket */ 123 1.17 dholland 124 1.29 dholland #ifdef VOLCANO 125 1.29 dholland static int volcano = 0; /* Explosion size */ 126 1.29 dholland #endif 127 1.29 dholland 128 1.17 dholland static void clear_scores(void); 129 1.24 dholland static bool havechar(PLAYER *, int); 130 1.17 dholland static void init(void); 131 1.17 dholland static void makeboots(void); 132 1.17 dholland static void send_stats(void); 133 1.24 dholland static void zap(PLAYER *, bool, int); 134 1.2 lukem 135 1.35 dholland static int 136 1.35 dholland getnum(const char *s, unsigned long *ret) 137 1.35 dholland { 138 1.35 dholland char *t; 139 1.35 dholland 140 1.35 dholland errno = 0; 141 1.35 dholland *ret = strtoul(s, &t, 0); 142 1.35 dholland if (errno || *t != '\0') { 143 1.35 dholland return -1; 144 1.35 dholland } 145 1.35 dholland return 0; 146 1.35 dholland } 147 1.35 dholland 148 1.35 dholland static __dead void 149 1.35 dholland usage(const char *av0) 150 1.35 dholland { 151 1.35 dholland fprintf(stderr, "Usage: %s [-s] [-p portnumber|socketpath]\n", av0); 152 1.35 dholland exit(1); 153 1.35 dholland } 154 1.35 dholland 155 1.35 dholland static void 156 1.35 dholland makeaddr(const char *path, uint16_t port, 157 1.35 dholland struct sockaddr_storage *ss, socklen_t *len) 158 1.35 dholland { 159 1.35 dholland struct sockaddr_in *sin; 160 1.35 dholland struct sockaddr_un *sun; 161 1.35 dholland 162 1.35 dholland if (path == NULL) { 163 1.35 dholland sin = (struct sockaddr_in *)ss; 164 1.35 dholland sin->sin_family = AF_INET; 165 1.35 dholland sin->sin_addr.s_addr = INADDR_ANY; 166 1.35 dholland sin->sin_port = htons(port); 167 1.35 dholland *len = sizeof(*sin); 168 1.35 dholland } else { 169 1.35 dholland sun = (struct sockaddr_un *)ss; 170 1.35 dholland sun->sun_family = AF_UNIX; 171 1.35 dholland strlcpy(sun->sun_path, path, sizeof(sun->sun_path)); 172 1.35 dholland *len = SUN_LEN(sun); 173 1.35 dholland } 174 1.35 dholland } 175 1.35 dholland 176 1.35 dholland static uint16_t 177 1.35 dholland getsockport(int sock) 178 1.35 dholland { 179 1.35 dholland struct sockaddr_storage addr; 180 1.35 dholland socklen_t len; 181 1.35 dholland 182 1.35 dholland len = sizeof(addr); 183 1.35 dholland if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) { 184 1.35 dholland complain(LOG_ERR, "getsockname"); 185 1.35 dholland exit(1); 186 1.35 dholland } 187 1.35 dholland switch (addr.ss_family) { 188 1.35 dholland case AF_INET: 189 1.35 dholland return ntohs(((struct sockaddr_in *)&addr)->sin_port); 190 1.35 dholland case AF_INET6: 191 1.35 dholland return ntohs(((struct sockaddr_in6 *)&addr)->sin6_port); 192 1.35 dholland default: 193 1.35 dholland break; 194 1.35 dholland } 195 1.35 dholland return 0; 196 1.35 dholland } 197 1.1 mrg 198 1.1 mrg /* 199 1.1 mrg * main: 200 1.1 mrg * The main program. 201 1.1 mrg */ 202 1.2 lukem int 203 1.26 dholland main(int ac, char **av) 204 1.1 mrg { 205 1.17 dholland PLAYER *pp; 206 1.35 dholland unsigned long optargnum; 207 1.35 dholland uint16_t msg, reply; 208 1.35 dholland struct sockaddr_storage msgaddr; 209 1.35 dholland socklen_t msgaddrlen; 210 1.24 dholland static bool first = true; 211 1.24 dholland static bool server = false; 212 1.17 dholland int c, i; 213 1.17 dholland const int linger = 90 * 1000; 214 1.1 mrg 215 1.2 lukem while ((c = getopt(ac, av, "sp:")) != -1) { 216 1.1 mrg switch (c) { 217 1.1 mrg case 's': 218 1.24 dholland server = true; 219 1.1 mrg break; 220 1.1 mrg case 'p': 221 1.24 dholland standard_port = false; 222 1.35 dholland if (getnum(optarg, &optargnum) < 0) { 223 1.35 dholland localmode = true; 224 1.35 dholland huntsockpath = optarg; 225 1.35 dholland } else if (optargnum < 0xffff) { 226 1.35 dholland localmode = false; 227 1.35 dholland contactport = optargnum; 228 1.35 dholland } else { 229 1.35 dholland usage(av[0]); 230 1.35 dholland } 231 1.1 mrg break; 232 1.1 mrg default: 233 1.35 dholland usage(av[0]); 234 1.1 mrg } 235 1.1 mrg } 236 1.1 mrg if (optind < ac) 237 1.35 dholland usage(av[0]); 238 1.1 mrg 239 1.35 dholland asprintf(&statsockpath, "%s.stats", huntsockpath); 240 1.1 mrg init(); 241 1.1 mrg 242 1.1 mrg 243 1.1 mrg again: 244 1.1 mrg do { 245 1.1 mrg errno = 0; 246 1.8 mycroft while (poll(fdset, 3+MAXPL+MAXMON, INFTIM) < 0) 247 1.1 mrg { 248 1.1 mrg if (errno != EINTR) 249 1.32 dholland complain(LOG_WARNING, "poll"); 250 1.1 mrg errno = 0; 251 1.1 mrg } 252 1.35 dholland if (!localmode && fdset[2].revents & POLLIN) { 253 1.35 dholland msgaddrlen = sizeof(msgaddr); 254 1.34 dholland (void) recvfrom(contactsock, &msg, sizeof msg, 255 1.35 dholland 0, (struct sockaddr *)&msgaddr, &msgaddrlen); 256 1.1 mrg switch (ntohs(msg)) { 257 1.1 mrg case C_MESSAGE: 258 1.1 mrg if (Nplayer <= 0) 259 1.1 mrg break; 260 1.1 mrg reply = htons((u_short) Nplayer); 261 1.34 dholland (void) sendto(contactsock, &reply, 262 1.1 mrg sizeof reply, 0, 263 1.35 dholland (struct sockaddr *)&msgaddr, 264 1.35 dholland msgaddrlen); 265 1.1 mrg break; 266 1.1 mrg case C_SCORES: 267 1.34 dholland reply = htons(statport); 268 1.34 dholland (void) sendto(contactsock, &reply, 269 1.1 mrg sizeof reply, 0, 270 1.35 dholland (struct sockaddr *)&msgaddr, 271 1.35 dholland msgaddrlen); 272 1.1 mrg break; 273 1.1 mrg case C_PLAYER: 274 1.1 mrg case C_MONITOR: 275 1.1 mrg if (msg == C_MONITOR && Nplayer <= 0) 276 1.1 mrg break; 277 1.34 dholland reply = htons(huntport); 278 1.34 dholland (void) sendto(contactsock, &reply, 279 1.1 mrg sizeof reply, 0, 280 1.35 dholland (struct sockaddr *)&msgaddr, 281 1.35 dholland msgaddrlen); 282 1.1 mrg break; 283 1.1 mrg } 284 1.1 mrg } 285 1.35 dholland 286 1.8 mycroft { 287 1.8 mycroft for (pp = Player, i = 0; pp < End_player; pp++, i++) 288 1.8 mycroft if (havechar(pp, i + 3)) { 289 1.1 mrg execute(pp); 290 1.1 mrg pp->p_nexec++; 291 1.1 mrg } 292 1.17 dholland #ifdef MONITOR 293 1.8 mycroft for (pp = Monitor, i = 0; pp < End_monitor; pp++, i++) 294 1.8 mycroft if (havechar(pp, i + MAXPL + 3)) { 295 1.1 mrg mon_execute(pp); 296 1.1 mrg pp->p_nexec++; 297 1.1 mrg } 298 1.17 dholland #endif 299 1.1 mrg moveshots(); 300 1.8 mycroft for (pp = Player, i = 0; pp < End_player; ) 301 1.1 mrg if (pp->p_death[0] != '\0') 302 1.24 dholland zap(pp, true, i + 3); 303 1.1 mrg else 304 1.8 mycroft pp++, i++; 305 1.17 dholland #ifdef MONITOR 306 1.8 mycroft for (pp = Monitor, i = 0; pp < End_monitor; ) 307 1.1 mrg if (pp->p_death[0] != '\0') 308 1.24 dholland zap(pp, false, i + MAXPL + 3); 309 1.1 mrg else 310 1.8 mycroft pp++, i++; 311 1.17 dholland #endif 312 1.1 mrg } 313 1.8 mycroft if (fdset[0].revents & POLLIN) 314 1.1 mrg if (answer()) { 315 1.27 dholland if (first) { 316 1.27 dholland /* announce start of game? */ 317 1.27 dholland } 318 1.24 dholland first = false; 319 1.1 mrg } 320 1.8 mycroft if (fdset[1].revents & POLLIN) 321 1.1 mrg send_stats(); 322 1.8 mycroft for (pp = Player, i = 0; pp < End_player; pp++, i++) { 323 1.8 mycroft if (fdset[i + 3].revents & POLLIN) 324 1.1 mrg sendcom(pp, READY, pp->p_nexec); 325 1.1 mrg pp->p_nexec = 0; 326 1.1 mrg (void) fflush(pp->p_output); 327 1.1 mrg } 328 1.17 dholland #ifdef MONITOR 329 1.8 mycroft for (pp = Monitor, i = 0; pp < End_monitor; pp++, i++) { 330 1.8 mycroft if (fdset[i + MAXPL + 3].revents & POLLIN) 331 1.1 mrg sendcom(pp, READY, pp->p_nexec); 332 1.1 mrg pp->p_nexec = 0; 333 1.1 mrg (void) fflush(pp->p_output); 334 1.1 mrg } 335 1.17 dholland #endif 336 1.1 mrg } while (Nplayer > 0); 337 1.1 mrg 338 1.8 mycroft if (poll(fdset, 3+MAXPL+MAXMON, linger) > 0) { 339 1.1 mrg goto again; 340 1.1 mrg } 341 1.1 mrg if (server) { 342 1.1 mrg clear_scores(); 343 1.1 mrg makemaze(); 344 1.1 mrg clearwalls(); 345 1.17 dholland #ifdef BOOTS 346 1.1 mrg makeboots(); 347 1.17 dholland #endif 348 1.24 dholland first = true; 349 1.1 mrg goto again; 350 1.1 mrg } 351 1.1 mrg 352 1.17 dholland #ifdef MONITOR 353 1.8 mycroft for (pp = Monitor, i = 0; pp < End_monitor; i++) 354 1.24 dholland zap(pp, false, i + MAXPL + 3); 355 1.17 dholland #endif 356 1.1 mrg cleanup(0); 357 1.2 lukem /* NOTREACHED */ 358 1.2 lukem return(0); 359 1.1 mrg } 360 1.1 mrg 361 1.1 mrg /* 362 1.1 mrg * init: 363 1.1 mrg * Initialize the global parameters. 364 1.1 mrg */ 365 1.2 lukem static void 366 1.16 dholland init(void) 367 1.1 mrg { 368 1.17 dholland int i; 369 1.35 dholland struct sockaddr_storage stdinaddr; 370 1.35 dholland struct sockaddr_storage contactaddr; 371 1.35 dholland socklen_t contactaddrlen; 372 1.17 dholland socklen_t len; 373 1.1 mrg 374 1.17 dholland #ifndef DEBUG 375 1.17 dholland #ifdef TIOCNOTTY 376 1.1 mrg (void) ioctl(fileno(stdout), TIOCNOTTY, NULL); 377 1.17 dholland #endif 378 1.1 mrg (void) setpgrp(getpid(), getpid()); 379 1.1 mrg (void) signal(SIGHUP, SIG_IGN); 380 1.1 mrg (void) signal(SIGINT, SIG_IGN); 381 1.1 mrg (void) signal(SIGQUIT, SIG_IGN); 382 1.1 mrg (void) signal(SIGTERM, cleanup); 383 1.17 dholland #endif 384 1.1 mrg 385 1.4 mrg (void) chdir("/var/tmp"); /* just in case it core dumps */ 386 1.1 mrg (void) umask(0); /* No privacy at all! */ 387 1.1 mrg (void) signal(SIGPIPE, SIG_IGN); 388 1.1 mrg 389 1.17 dholland #ifdef LOG 390 1.7 lukem openlog("huntd", LOG_PID, LOG_DAEMON); 391 1.17 dholland #endif 392 1.1 mrg 393 1.1 mrg /* 394 1.35 dholland * check for inetd 395 1.1 mrg */ 396 1.35 dholland len = sizeof(stdinaddr); 397 1.35 dholland if (getsockname(STDIN_FILENO, (struct sockaddr *)&stdinaddr, 398 1.35 dholland &len) >= 0) { 399 1.35 dholland inetd_spawned = true; 400 1.35 dholland /* force localmode, assimilate stdin as appropriate */ 401 1.35 dholland if (stdinaddr.ss_family == AF_UNIX) { 402 1.35 dholland localmode = true; 403 1.35 dholland contactsock = -1; 404 1.35 dholland huntsock = STDIN_FILENO; 405 1.35 dholland } 406 1.35 dholland else { 407 1.35 dholland localmode = false; 408 1.35 dholland contactsock = STDIN_FILENO; 409 1.35 dholland huntsock = -1; 410 1.35 dholland } 411 1.35 dholland } else { 412 1.35 dholland /* keep value of localmode; no sockets yet */ 413 1.35 dholland contactsock = -1; 414 1.35 dholland huntsock = -1; 415 1.35 dholland } 416 1.1 mrg 417 1.35 dholland /* 418 1.35 dholland * initialize contact socket 419 1.35 dholland */ 420 1.35 dholland if (!localmode && contactsock < 0) { 421 1.35 dholland makeaddr(NULL, contactport, &contactaddr, &contactaddrlen); 422 1.35 dholland contactsock = socket(AF_INET, SOCK_DGRAM, 0); 423 1.35 dholland if (bind(contactsock, (struct sockaddr *) &contactaddr, 424 1.35 dholland contactaddrlen) < 0) { 425 1.32 dholland complain(LOG_ERR, "bind"); 426 1.35 dholland exit(1); 427 1.1 mrg } 428 1.35 dholland (void) listen(contactsock, 5); 429 1.1 mrg } 430 1.1 mrg 431 1.35 dholland /* 432 1.35 dholland * Initialize main socket 433 1.35 dholland */ 434 1.35 dholland if (huntsock < 0) { 435 1.35 dholland makeaddr(localmode ? huntsockpath : NULL, 0, &huntaddr, 436 1.35 dholland &huntaddrlen); 437 1.35 dholland huntsock = socket(huntaddr.ss_family, SOCK_STREAM, 0); 438 1.35 dholland if (bind(huntsock, (struct sockaddr *)&huntaddr, 439 1.35 dholland huntaddrlen) < 0) { 440 1.35 dholland if (errno == EADDRINUSE) 441 1.35 dholland exit(0); 442 1.35 dholland else { 443 1.35 dholland complain(LOG_ERR, "bind"); 444 1.35 dholland cleanup(1); 445 1.35 dholland } 446 1.35 dholland } 447 1.35 dholland (void) listen(huntsock, 5); 448 1.1 mrg } 449 1.1 mrg 450 1.1 mrg /* 451 1.35 dholland * Initialize statistics socket 452 1.1 mrg */ 453 1.35 dholland makeaddr(localmode ? statsockpath : NULL, 0, &stataddr, &stataddrlen); 454 1.35 dholland statsock = socket(stataddr.ss_family, SOCK_STREAM, 0); 455 1.35 dholland if (bind(statsock, (struct sockaddr *)&stataddr, stataddrlen) < 0) { 456 1.1 mrg if (errno == EADDRINUSE) 457 1.1 mrg exit(0); 458 1.1 mrg else { 459 1.32 dholland complain(LOG_ERR, "bind"); 460 1.1 mrg cleanup(1); 461 1.1 mrg } 462 1.1 mrg } 463 1.35 dholland (void) listen(statsock, 5); 464 1.1 mrg 465 1.35 dholland if (!localmode) { 466 1.35 dholland contactport = getsockport(contactsock); 467 1.35 dholland statport = getsockport(statsock); 468 1.35 dholland huntport = getsockport(huntsock); 469 1.35 dholland if (contactport != TEST_PORT) { 470 1.35 dholland standard_port = false; 471 1.35 dholland } 472 1.1 mrg } 473 1.1 mrg 474 1.1 mrg /* 475 1.12 elad * Initialize minimal poll mask 476 1.1 mrg */ 477 1.34 dholland fdset[0].fd = huntsock; 478 1.8 mycroft fdset[0].events = POLLIN; 479 1.34 dholland fdset[1].fd = statsock; 480 1.8 mycroft fdset[1].events = POLLIN; 481 1.35 dholland if (localmode) { 482 1.35 dholland fdset[2].fd = -1; 483 1.35 dholland fdset[2].events = 0; 484 1.1 mrg } else { 485 1.35 dholland fdset[2].fd = contactsock; 486 1.35 dholland fdset[2].events = POLLIN; 487 1.1 mrg } 488 1.1 mrg 489 1.23 dholland srandom(time(NULL)); 490 1.1 mrg makemaze(); 491 1.17 dholland #ifdef BOOTS 492 1.1 mrg makeboots(); 493 1.17 dholland #endif 494 1.1 mrg 495 1.1 mrg for (i = 0; i < NASCII; i++) 496 1.24 dholland See_over[i] = true; 497 1.24 dholland See_over[DOOR] = false; 498 1.24 dholland See_over[WALL1] = false; 499 1.24 dholland See_over[WALL2] = false; 500 1.24 dholland See_over[WALL3] = false; 501 1.17 dholland #ifdef REFLECT 502 1.24 dholland See_over[WALL4] = false; 503 1.24 dholland See_over[WALL5] = false; 504 1.17 dholland #endif 505 1.1 mrg 506 1.1 mrg } 507 1.1 mrg 508 1.17 dholland #ifdef BOOTS 509 1.1 mrg /* 510 1.1 mrg * makeboots: 511 1.1 mrg * Put the boots in the maze 512 1.1 mrg */ 513 1.2 lukem static void 514 1.16 dholland makeboots(void) 515 1.1 mrg { 516 1.17 dholland int x, y; 517 1.17 dholland PLAYER *pp; 518 1.1 mrg 519 1.1 mrg do { 520 1.1 mrg x = rand_num(WIDTH - 1) + 1; 521 1.1 mrg y = rand_num(HEIGHT - 1) + 1; 522 1.1 mrg } while (Maze[y][x] != SPACE); 523 1.1 mrg Maze[y][x] = BOOT_PAIR; 524 1.1 mrg for (pp = Boot; pp < &Boot[NBOOTS]; pp++) 525 1.1 mrg pp->p_flying = -1; 526 1.1 mrg } 527 1.17 dholland #endif 528 1.1 mrg 529 1.1 mrg 530 1.1 mrg /* 531 1.1 mrg * checkdam: 532 1.1 mrg * Check the damage to the given player, and see if s/he is killed 533 1.1 mrg */ 534 1.2 lukem void 535 1.16 dholland checkdam(PLAYER *ouch, PLAYER *gotcha, IDENT *credit, int amt, 536 1.16 dholland char this_shot_type) 537 1.1 mrg { 538 1.17 dholland const char *cp; 539 1.1 mrg 540 1.1 mrg if (ouch->p_death[0] != '\0') 541 1.1 mrg return; 542 1.17 dholland #ifdef BOOTS 543 1.13 dholland if (this_shot_type == SLIME) 544 1.1 mrg switch (ouch->p_nboots) { 545 1.1 mrg default: 546 1.1 mrg break; 547 1.1 mrg case 1: 548 1.1 mrg amt = (amt + 1) / 2; 549 1.1 mrg break; 550 1.1 mrg case 2: 551 1.1 mrg if (gotcha != NULL) 552 1.1 mrg message(gotcha, "He has boots on!"); 553 1.1 mrg return; 554 1.1 mrg } 555 1.17 dholland #endif 556 1.1 mrg ouch->p_damage += amt; 557 1.1 mrg if (ouch->p_damage <= ouch->p_damcap) { 558 1.14 dholland (void) snprintf(Buf, sizeof(Buf), "%2d", ouch->p_damage); 559 1.1 mrg cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL); 560 1.1 mrg outstr(ouch, Buf, 2); 561 1.1 mrg return; 562 1.1 mrg } 563 1.1 mrg 564 1.1 mrg /* Someone DIED */ 565 1.13 dholland switch (this_shot_type) { 566 1.1 mrg default: 567 1.1 mrg cp = "Killed"; 568 1.1 mrg break; 569 1.17 dholland #ifdef FLY 570 1.1 mrg case FALL: 571 1.1 mrg cp = "Killed on impact"; 572 1.1 mrg break; 573 1.17 dholland #endif 574 1.1 mrg case KNIFE: 575 1.1 mrg cp = "Stabbed to death"; 576 1.1 mrg ouch->p_ammo = 0; /* No exploding */ 577 1.1 mrg break; 578 1.1 mrg case SHOT: 579 1.1 mrg cp = "Shot to death"; 580 1.1 mrg break; 581 1.1 mrg case GRENADE: 582 1.1 mrg case SATCHEL: 583 1.1 mrg case BOMB: 584 1.1 mrg cp = "Bombed"; 585 1.1 mrg break; 586 1.1 mrg case MINE: 587 1.1 mrg case GMINE: 588 1.1 mrg cp = "Blown apart"; 589 1.1 mrg break; 590 1.17 dholland #ifdef OOZE 591 1.1 mrg case SLIME: 592 1.1 mrg cp = "Slimed"; 593 1.1 mrg if (credit != NULL) 594 1.1 mrg credit->i_slime++; 595 1.1 mrg break; 596 1.17 dholland #endif 597 1.17 dholland #ifdef VOLCANO 598 1.1 mrg case LAVA: 599 1.1 mrg cp = "Baked"; 600 1.1 mrg break; 601 1.17 dholland #endif 602 1.17 dholland #ifdef DRONE 603 1.1 mrg case DSHOT: 604 1.1 mrg cp = "Eliminated"; 605 1.1 mrg break; 606 1.17 dholland #endif 607 1.1 mrg } 608 1.1 mrg if (credit == NULL) { 609 1.14 dholland (void) snprintf(ouch->p_death, sizeof(ouch->p_death), 610 1.14 dholland "| %s by %s |", cp, 611 1.13 dholland (this_shot_type == MINE || this_shot_type == GMINE) ? 612 1.1 mrg "a mine" : "act of God"); 613 1.1 mrg return; 614 1.1 mrg } 615 1.1 mrg 616 1.14 dholland (void) snprintf(ouch->p_death, sizeof(ouch->p_death), 617 1.14 dholland "| %s by %s |", cp, credit->i_name); 618 1.1 mrg 619 1.1 mrg if (ouch == gotcha) { /* No use killing yourself */ 620 1.1 mrg credit->i_kills--; 621 1.1 mrg credit->i_bkills++; 622 1.1 mrg } 623 1.1 mrg else if (ouch->p_ident->i_team == ' ' 624 1.1 mrg || ouch->p_ident->i_team != credit->i_team) { 625 1.1 mrg credit->i_kills++; 626 1.1 mrg credit->i_gkills++; 627 1.1 mrg } 628 1.1 mrg else { 629 1.1 mrg credit->i_kills--; 630 1.1 mrg credit->i_bkills++; 631 1.1 mrg } 632 1.1 mrg credit->i_score = credit->i_kills / (double) credit->i_entries; 633 1.1 mrg ouch->p_ident->i_deaths++; 634 1.1 mrg if (ouch->p_nchar == 0) 635 1.1 mrg ouch->p_ident->i_stillb++; 636 1.1 mrg if (gotcha == NULL) 637 1.1 mrg return; 638 1.1 mrg gotcha->p_damcap += STABDAM; 639 1.1 mrg gotcha->p_damage -= STABDAM; 640 1.1 mrg if (gotcha->p_damage < 0) 641 1.1 mrg gotcha->p_damage = 0; 642 1.14 dholland (void) snprintf(Buf, sizeof(Buf), "%2d/%2d", gotcha->p_damage, 643 1.14 dholland gotcha->p_damcap); 644 1.1 mrg cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL); 645 1.1 mrg outstr(gotcha, Buf, 5); 646 1.14 dholland (void) snprintf(Buf, sizeof(Buf), "%3d", 647 1.14 dholland (gotcha->p_damcap - MAXDAM) / 2); 648 1.1 mrg cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL); 649 1.1 mrg outstr(gotcha, Buf, 3); 650 1.14 dholland (void) snprintf(Buf, sizeof(Buf), "%5.2f", gotcha->p_ident->i_score); 651 1.1 mrg for (ouch = Player; ouch < End_player; ouch++) { 652 1.1 mrg cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player), 653 1.1 mrg STAT_NAME_COL); 654 1.1 mrg outstr(ouch, Buf, 5); 655 1.1 mrg } 656 1.17 dholland #ifdef MONITOR 657 1.1 mrg for (ouch = Monitor; ouch < End_monitor; ouch++) { 658 1.1 mrg cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player), 659 1.1 mrg STAT_NAME_COL); 660 1.1 mrg outstr(ouch, Buf, 5); 661 1.1 mrg } 662 1.17 dholland #endif 663 1.1 mrg } 664 1.1 mrg 665 1.1 mrg /* 666 1.1 mrg * zap: 667 1.1 mrg * Kill off a player and take him out of the game. 668 1.1 mrg */ 669 1.2 lukem static void 670 1.24 dholland zap(PLAYER *pp, bool was_player, int i) 671 1.1 mrg { 672 1.17 dholland int n, len; 673 1.17 dholland BULLET *bp; 674 1.17 dholland PLAYER *np; 675 1.17 dholland int x, y; 676 1.1 mrg 677 1.1 mrg if (was_player) { 678 1.1 mrg if (pp->p_undershot) 679 1.1 mrg fixshots(pp->p_y, pp->p_x, pp->p_over); 680 1.24 dholland drawplayer(pp, false); 681 1.1 mrg Nplayer--; 682 1.1 mrg } 683 1.1 mrg 684 1.1 mrg len = strlen(pp->p_death); /* Display the cause of death */ 685 1.1 mrg x = (WIDTH - len) / 2; 686 1.1 mrg cgoto(pp, HEIGHT / 2, x); 687 1.1 mrg outstr(pp, pp->p_death, len); 688 1.8 mycroft for (n = 1; n < len; n++) 689 1.8 mycroft pp->p_death[n] = '-'; 690 1.1 mrg pp->p_death[0] = '+'; 691 1.1 mrg pp->p_death[len - 1] = '+'; 692 1.1 mrg cgoto(pp, HEIGHT / 2 - 1, x); 693 1.1 mrg outstr(pp, pp->p_death, len); 694 1.1 mrg cgoto(pp, HEIGHT / 2 + 1, x); 695 1.1 mrg outstr(pp, pp->p_death, len); 696 1.1 mrg cgoto(pp, HEIGHT, 0); 697 1.1 mrg 698 1.17 dholland #ifdef MONITOR 699 1.1 mrg if (was_player) { 700 1.17 dholland #endif 701 1.1 mrg for (bp = Bullets; bp != NULL; bp = bp->b_next) { 702 1.1 mrg if (bp->b_owner == pp) 703 1.1 mrg bp->b_owner = NULL; 704 1.1 mrg if (bp->b_x == pp->p_x && bp->b_y == pp->p_y) 705 1.1 mrg bp->b_over = SPACE; 706 1.1 mrg } 707 1.1 mrg 708 1.8 mycroft n = rand_num(pp->p_ammo); 709 1.1 mrg x = rand_num(pp->p_ammo); 710 1.8 mycroft if (x > n) 711 1.8 mycroft n = x; 712 1.1 mrg if (pp->p_ammo == 0) 713 1.1 mrg x = 0; 714 1.8 mycroft else if (n == pp->p_ammo - 1) { 715 1.1 mrg x = pp->p_ammo; 716 1.1 mrg len = SLIME; 717 1.1 mrg } 718 1.1 mrg else { 719 1.1 mrg for (x = MAXBOMB - 1; x > 0; x--) 720 1.8 mycroft if (n >= shot_req[x]) 721 1.1 mrg break; 722 1.1 mrg for (y = MAXSLIME - 1; y > 0; y--) 723 1.8 mycroft if (n >= slime_req[y]) 724 1.1 mrg break; 725 1.1 mrg if (y >= 0 && slime_req[y] > shot_req[x]) { 726 1.1 mrg x = slime_req[y]; 727 1.1 mrg len = SLIME; 728 1.1 mrg } 729 1.1 mrg else if (x != 0) { 730 1.1 mrg len = shot_type[x]; 731 1.1 mrg x = shot_req[x]; 732 1.1 mrg } 733 1.1 mrg } 734 1.1 mrg if (x > 0) { 735 1.1 mrg (void) add_shot(len, pp->p_y, pp->p_x, pp->p_face, x, 736 1.24 dholland NULL, true, SPACE); 737 1.14 dholland (void) snprintf(Buf, sizeof(Buf), "%s detonated.", 738 1.1 mrg pp->p_ident->i_name); 739 1.1 mrg for (np = Player; np < End_player; np++) 740 1.1 mrg message(np, Buf); 741 1.17 dholland #ifdef MONITOR 742 1.1 mrg for (np = Monitor; np < End_monitor; np++) 743 1.1 mrg message(np, Buf); 744 1.17 dholland #endif 745 1.17 dholland #ifdef BOOTS 746 1.1 mrg while (pp->p_nboots-- > 0) { 747 1.1 mrg for (np = Boot; np < &Boot[NBOOTS]; np++) 748 1.1 mrg if (np->p_flying < 0) 749 1.1 mrg break; 750 1.1 mrg if (np >= &Boot[NBOOTS]) 751 1.2 lukem err(1, "Too many boots"); 752 1.24 dholland np->p_undershot = false; 753 1.1 mrg np->p_x = pp->p_x; 754 1.1 mrg np->p_y = pp->p_y; 755 1.1 mrg np->p_flying = rand_num(20); 756 1.1 mrg np->p_flyx = 2 * rand_num(6) - 5; 757 1.1 mrg np->p_flyy = 2 * rand_num(6) - 5; 758 1.1 mrg np->p_over = SPACE; 759 1.1 mrg np->p_face = BOOT; 760 1.1 mrg showexpl(np->p_y, np->p_x, BOOT); 761 1.1 mrg } 762 1.17 dholland #endif 763 1.1 mrg } 764 1.17 dholland #ifdef BOOTS 765 1.1 mrg else if (pp->p_nboots > 0) { 766 1.1 mrg if (pp->p_nboots == 2) 767 1.1 mrg Maze[pp->p_y][pp->p_x] = BOOT_PAIR; 768 1.1 mrg else 769 1.1 mrg Maze[pp->p_y][pp->p_x] = BOOT; 770 1.1 mrg if (pp->p_undershot) 771 1.1 mrg fixshots(pp->p_y, pp->p_x, 772 1.1 mrg Maze[pp->p_y][pp->p_x]); 773 1.1 mrg } 774 1.17 dholland #endif 775 1.1 mrg 776 1.17 dholland #ifdef VOLCANO 777 1.1 mrg volcano += pp->p_ammo - x; 778 1.1 mrg if (rand_num(100) < volcano / 50) { 779 1.1 mrg do { 780 1.1 mrg x = rand_num(WIDTH / 2) + WIDTH / 4; 781 1.1 mrg y = rand_num(HEIGHT / 2) + HEIGHT / 4; 782 1.1 mrg } while (Maze[y][x] != SPACE); 783 1.1 mrg (void) add_shot(LAVA, y, x, LEFTS, volcano, 784 1.24 dholland NULL, true, SPACE); 785 1.1 mrg for (np = Player; np < End_player; np++) 786 1.1 mrg message(np, "Volcano eruption."); 787 1.1 mrg volcano = 0; 788 1.1 mrg } 789 1.17 dholland #endif 790 1.1 mrg 791 1.17 dholland #ifdef DRONE 792 1.1 mrg if (rand_num(100) < 2) { 793 1.1 mrg do { 794 1.1 mrg x = rand_num(WIDTH / 2) + WIDTH / 4; 795 1.1 mrg y = rand_num(HEIGHT / 2) + HEIGHT / 4; 796 1.1 mrg } while (Maze[y][x] != SPACE); 797 1.1 mrg add_shot(DSHOT, y, x, rand_dir(), 798 1.1 mrg shot_req[MINDSHOT + 799 1.1 mrg rand_num(MAXBOMB - MINDSHOT)], 800 1.24 dholland NULL, false, SPACE); 801 1.1 mrg } 802 1.17 dholland #endif 803 1.1 mrg 804 1.1 mrg sendcom(pp, ENDWIN); 805 1.1 mrg (void) putc(' ', pp->p_output); 806 1.1 mrg (void) fclose(pp->p_output); 807 1.1 mrg 808 1.1 mrg End_player--; 809 1.1 mrg if (pp != End_player) { 810 1.1 mrg memcpy(pp, End_player, sizeof (PLAYER)); 811 1.8 mycroft fdset[i] = fdset[End_player - Player + 3]; 812 1.8 mycroft fdset[End_player - Player + 3].fd = -1; 813 1.14 dholland (void) snprintf(Buf, sizeof(Buf), "%5.2f%c%-10.10s %c", 814 1.1 mrg pp->p_ident->i_score, stat_char(pp), 815 1.1 mrg pp->p_ident->i_name, pp->p_ident->i_team); 816 1.8 mycroft n = STAT_PLAY_ROW + 1 + (pp - Player); 817 1.1 mrg for (np = Player; np < End_player; np++) { 818 1.8 mycroft cgoto(np, n, STAT_NAME_COL); 819 1.1 mrg outstr(np, Buf, STAT_NAME_LEN); 820 1.1 mrg } 821 1.17 dholland #ifdef MONITOR 822 1.1 mrg for (np = Monitor; np < End_monitor; np++) { 823 1.8 mycroft cgoto(np, n, STAT_NAME_COL); 824 1.1 mrg outstr(np, Buf, STAT_NAME_LEN); 825 1.1 mrg } 826 1.17 dholland #endif 827 1.8 mycroft } else 828 1.8 mycroft fdset[i].fd = -1; 829 1.1 mrg 830 1.1 mrg /* Erase the last player */ 831 1.8 mycroft n = STAT_PLAY_ROW + 1 + Nplayer; 832 1.1 mrg for (np = Player; np < End_player; np++) { 833 1.8 mycroft cgoto(np, n, STAT_NAME_COL); 834 1.1 mrg ce(np); 835 1.1 mrg } 836 1.17 dholland #ifdef MONITOR 837 1.1 mrg for (np = Monitor; np < End_monitor; np++) { 838 1.8 mycroft cgoto(np, n, STAT_NAME_COL); 839 1.1 mrg ce(np); 840 1.1 mrg } 841 1.1 mrg } 842 1.1 mrg else { 843 1.1 mrg sendcom(pp, ENDWIN); 844 1.1 mrg (void) putc(LAST_PLAYER, pp->p_output); 845 1.1 mrg (void) fclose(pp->p_output); 846 1.1 mrg 847 1.1 mrg End_monitor--; 848 1.1 mrg if (pp != End_monitor) { 849 1.1 mrg memcpy(pp, End_monitor, sizeof (PLAYER)); 850 1.8 mycroft fdset[i] = fdset[End_monitor - Monitor + MAXPL + 3]; 851 1.8 mycroft fdset[End_monitor - Monitor + MAXPL + 3].fd = -1; 852 1.14 dholland (void) snprintf(Buf, sizeof(Buf), "%5.5s %-10.10s %c", 853 1.14 dholland " ", 854 1.1 mrg pp->p_ident->i_name, pp->p_ident->i_team); 855 1.8 mycroft n = STAT_MON_ROW + 1 + (pp - Player); 856 1.1 mrg for (np = Player; np < End_player; np++) { 857 1.8 mycroft cgoto(np, n, STAT_NAME_COL); 858 1.1 mrg outstr(np, Buf, STAT_NAME_LEN); 859 1.1 mrg } 860 1.1 mrg for (np = Monitor; np < End_monitor; np++) { 861 1.8 mycroft cgoto(np, n, STAT_NAME_COL); 862 1.1 mrg outstr(np, Buf, STAT_NAME_LEN); 863 1.1 mrg } 864 1.8 mycroft } else 865 1.8 mycroft fdset[i].fd = -1; 866 1.1 mrg 867 1.1 mrg /* Erase the last monitor */ 868 1.8 mycroft n = STAT_MON_ROW + 1 + (End_monitor - Monitor); 869 1.1 mrg for (np = Player; np < End_player; np++) { 870 1.8 mycroft cgoto(np, n, STAT_NAME_COL); 871 1.1 mrg ce(np); 872 1.1 mrg } 873 1.1 mrg for (np = Monitor; np < End_monitor; np++) { 874 1.8 mycroft cgoto(np, n, STAT_NAME_COL); 875 1.1 mrg ce(np); 876 1.1 mrg } 877 1.1 mrg } 878 1.17 dholland #endif 879 1.1 mrg } 880 1.1 mrg 881 1.1 mrg /* 882 1.1 mrg * rand_num: 883 1.1 mrg * Return a random number in a given range. 884 1.1 mrg */ 885 1.2 lukem int 886 1.16 dholland rand_num(int range) 887 1.1 mrg { 888 1.23 dholland return (range == 0 ? 0 : random() % range); 889 1.1 mrg } 890 1.1 mrg 891 1.1 mrg /* 892 1.1 mrg * havechar: 893 1.1 mrg * Check to see if we have any characters in the input queue; if 894 1.24 dholland * we do, read them, stash them away, and return true; else return 895 1.24 dholland * false. 896 1.1 mrg */ 897 1.24 dholland static bool 898 1.16 dholland havechar(PLAYER *pp, int i) 899 1.1 mrg { 900 1.1 mrg 901 1.1 mrg if (pp->p_ncount < pp->p_nchar) 902 1.24 dholland return true; 903 1.8 mycroft if (!(fdset[i].revents & POLLIN)) 904 1.24 dholland return false; 905 1.1 mrg check_again: 906 1.30 dholland pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf); 907 1.30 dholland if (pp->p_nchar < 0 && errno == EINTR) { 908 1.30 dholland goto check_again; 909 1.30 dholland } else if (pp->p_nchar <= 0) { 910 1.1 mrg if (errno == EINTR) 911 1.1 mrg pp->p_cbuf[0] = 'q'; 912 1.1 mrg } 913 1.1 mrg pp->p_ncount = 0; 914 1.24 dholland return true; 915 1.1 mrg } 916 1.1 mrg 917 1.1 mrg /* 918 1.1 mrg * cleanup: 919 1.1 mrg * Exit with the given value, cleaning up any droppings lying around 920 1.1 mrg */ 921 1.19 dholland void 922 1.30 dholland cleanup(int exitval) 923 1.1 mrg { 924 1.17 dholland PLAYER *pp; 925 1.1 mrg 926 1.1 mrg for (pp = Player; pp < End_player; pp++) { 927 1.1 mrg cgoto(pp, HEIGHT, 0); 928 1.1 mrg sendcom(pp, ENDWIN); 929 1.1 mrg (void) putc(LAST_PLAYER, pp->p_output); 930 1.1 mrg (void) fclose(pp->p_output); 931 1.1 mrg } 932 1.17 dholland #ifdef MONITOR 933 1.1 mrg for (pp = Monitor; pp < End_monitor; pp++) { 934 1.1 mrg cgoto(pp, HEIGHT, 0); 935 1.1 mrg sendcom(pp, ENDWIN); 936 1.1 mrg (void) putc(LAST_PLAYER, pp->p_output); 937 1.1 mrg (void) fclose(pp->p_output); 938 1.1 mrg } 939 1.17 dholland #endif 940 1.34 dholland (void) close(huntsock); 941 1.17 dholland #ifdef AF_UNIX_HACK 942 1.34 dholland (void) unlink(huntsockpath); 943 1.17 dholland #endif 944 1.1 mrg 945 1.30 dholland exit(exitval); 946 1.1 mrg } 947 1.1 mrg 948 1.1 mrg /* 949 1.1 mrg * send_stats: 950 1.1 mrg * Print stats to requestor 951 1.1 mrg */ 952 1.2 lukem static void 953 1.16 dholland send_stats(void) 954 1.1 mrg { 955 1.17 dholland IDENT *ip; 956 1.17 dholland FILE *fp; 957 1.17 dholland int s; 958 1.35 dholland struct sockaddr_storage newaddr; 959 1.17 dholland socklen_t socklen; 960 1.1 mrg 961 1.1 mrg /* 962 1.1 mrg * Get the output stream ready 963 1.1 mrg */ 964 1.35 dholland socklen = sizeof(newaddr); 965 1.35 dholland s = accept(statsock, (struct sockaddr *)&newaddr, &socklen); 966 1.1 mrg if (s < 0) { 967 1.1 mrg if (errno == EINTR) 968 1.1 mrg return; 969 1.32 dholland complain(LOG_WARNING, "accept"); 970 1.1 mrg return; 971 1.1 mrg } 972 1.1 mrg fp = fdopen(s, "w"); 973 1.1 mrg if (fp == NULL) { 974 1.32 dholland complain(LOG_WARNING, "fdopen"); 975 1.1 mrg (void) close(s); 976 1.1 mrg return; 977 1.1 mrg } 978 1.1 mrg 979 1.1 mrg /* 980 1.1 mrg * Send output to requestor 981 1.1 mrg */ 982 1.1 mrg fputs("Name\t\tScore\tDucked\tAbsorb\tFaced\tShot\tRobbed\tMissed\tSlimeK\n", fp); 983 1.1 mrg for (ip = Scores; ip != NULL; ip = ip->i_next) { 984 1.1 mrg fprintf(fp, "%s\t", ip->i_name); 985 1.1 mrg if (strlen(ip->i_name) < 8) 986 1.1 mrg putc('\t', fp); 987 1.1 mrg fprintf(fp, "%.2f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", 988 1.1 mrg ip->i_score, ip->i_ducked, ip->i_absorbed, 989 1.1 mrg ip->i_faced, ip->i_shot, ip->i_robbed, 990 1.1 mrg ip->i_missed, ip->i_slime); 991 1.1 mrg } 992 1.1 mrg fputs("\n\nName\t\tEnemy\tFriend\tDeaths\tStill\tSaved\n", fp); 993 1.1 mrg for (ip = Scores; ip != NULL; ip = ip->i_next) { 994 1.1 mrg if (ip->i_team == ' ') { 995 1.1 mrg fprintf(fp, "%s\t", ip->i_name); 996 1.1 mrg if (strlen(ip->i_name) < 8) 997 1.1 mrg putc('\t', fp); 998 1.1 mrg } 999 1.1 mrg else { 1000 1.1 mrg fprintf(fp, "%s[%c]\t", ip->i_name, ip->i_team); 1001 1.1 mrg if (strlen(ip->i_name) + 3 < 8) 1002 1.1 mrg putc('\t', fp); 1003 1.1 mrg } 1004 1.1 mrg fprintf(fp, "%d\t%d\t%d\t%d\t%d\n", 1005 1.1 mrg ip->i_gkills, ip->i_bkills, ip->i_deaths, 1006 1.1 mrg ip->i_stillb, ip->i_saved); 1007 1.1 mrg } 1008 1.1 mrg 1009 1.1 mrg (void) fclose(fp); 1010 1.1 mrg } 1011 1.1 mrg 1012 1.1 mrg /* 1013 1.1 mrg * clear_scores: 1014 1.1 mrg * Clear out the scores so the next session start clean 1015 1.1 mrg */ 1016 1.2 lukem static void 1017 1.16 dholland clear_scores(void) 1018 1.1 mrg { 1019 1.17 dholland IDENT *ip, *nextip; 1020 1.1 mrg 1021 1.1 mrg for (ip = Scores; ip != NULL; ip = nextip) { 1022 1.1 mrg nextip = ip->i_next; 1023 1.15 dholland (void) free(ip); 1024 1.1 mrg } 1025 1.1 mrg Scores = NULL; 1026 1.1 mrg } 1027