driver.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988
  1. /* $NetBSD: driver.c,v 1.10 2004/01/27 20:30:29 jsm 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.
  19. *
  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.
  31. */
  32. #include <sys/cdefs.h>
  33. #ifndef lint
  34. __RCSID("$NetBSD: driver.c,v 1.10 2004/01/27 20:30:29 jsm Exp $");
  35. #endif /* not lint */
  36. # include <sys/ioctl.h>
  37. # include <sys/stat.h>
  38. # include <sys/time.h>
  39. # include <err.h>
  40. # include <errno.h>
  41. # include <signal.h>
  42. # include <stdlib.h>
  43. # include <time.h>
  44. # include <unistd.h>
  45. # include "hunt.h"
  46. # ifndef pdp11
  47. # define RN (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff)
  48. # else
  49. # define RN ((Seed = Seed * 11109 + 13849) & 0x7fff)
  50. # endif
  51. int Seed = 0;
  52. SOCKET Daemon;
  53. char *First_arg; /* pointer to argv[0] */
  54. char *Last_arg; /* pointer to end of argv/environ */
  55. # ifdef INTERNET
  56. int Test_socket; /* test socket to answer datagrams */
  57. FLAG inetd_spawned; /* invoked via inetd */
  58. FLAG standard_port = TRUE; /* true if listening on standard port */
  59. u_short sock_port; /* port # of tcp listen socket */
  60. u_short stat_port; /* port # of statistics tcp socket */
  61. # define DAEMON_SIZE (sizeof Daemon)
  62. # else
  63. # define DAEMON_SIZE (sizeof Daemon - 1)
  64. # endif
  65. static void clear_scores(void);
  66. static int havechar(PLAYER *, int);
  67. static void init(void);
  68. int main(int, char *[], char *[]);
  69. static void makeboots(void);
  70. static void send_stats(void);
  71. static void zap(PLAYER *, FLAG, int);
  72. /*
  73. * main:
  74. * The main program.
  75. */
  76. int
  77. main(ac, av, ep)
  78. int ac;
  79. char **av, **ep;
  80. {
  81. PLAYER *pp;
  82. # ifdef INTERNET
  83. u_short msg;
  84. short port_num, reply;
  85. int namelen;
  86. SOCKET test;
  87. # endif
  88. static FLAG first = TRUE;
  89. static FLAG server = FALSE;
  90. int c, i;
  91. const int linger = 90 * 1000;
  92. First_arg = av[0];
  93. if (ep == NULL || *ep == NULL)
  94. ep = av + ac;
  95. while (*ep)
  96. ep++;
  97. Last_arg = ep[-1] + strlen(ep[-1]);
  98. while ((c = getopt(ac, av, "sp:")) != -1) {
  99. switch (c) {
  100. case 's':
  101. server = TRUE;
  102. break;
  103. # ifdef INTERNET
  104. case 'p':
  105. standard_port = FALSE;
  106. Test_port = atoi(optarg);
  107. break;
  108. # endif
  109. default:
  110. erred:
  111. fprintf(stderr, "Usage: %s [-s] [-p port]\n", av[0]);
  112. exit(1);
  113. }
  114. }
  115. if (optind < ac)
  116. goto erred;
  117. init();
  118. again:
  119. do {
  120. errno = 0;
  121. while (poll(fdset, 3+MAXPL+MAXMON, INFTIM) < 0)
  122. {
  123. if (errno != EINTR)
  124. # ifdef LOG
  125. syslog(LOG_WARNING, "select: %m");
  126. # else
  127. warn("select");
  128. # endif
  129. errno = 0;
  130. }
  131. # ifdef INTERNET
  132. if (fdset[2].revents & POLLIN) {
  133. namelen = DAEMON_SIZE;
  134. port_num = htons(sock_port);
  135. (void) recvfrom(Test_socket, (char *) &msg, sizeof msg,
  136. 0, (struct sockaddr *) &test, &namelen);
  137. switch (ntohs(msg)) {
  138. case C_MESSAGE:
  139. if (Nplayer <= 0)
  140. break;
  141. reply = htons((u_short) Nplayer);
  142. (void) sendto(Test_socket, (char *) &reply,
  143. sizeof reply, 0,
  144. (struct sockaddr *) &test, DAEMON_SIZE);
  145. break;
  146. case C_SCORES:
  147. reply = htons(stat_port);
  148. (void) sendto(Test_socket, (char *) &reply,
  149. sizeof reply, 0,
  150. (struct sockaddr *) &test, DAEMON_SIZE);
  151. break;
  152. case C_PLAYER:
  153. case C_MONITOR:
  154. if (msg == C_MONITOR && Nplayer <= 0)
  155. break;
  156. reply = htons(sock_port);
  157. (void) sendto(Test_socket, (char *) &reply,
  158. sizeof reply, 0,
  159. (struct sockaddr *) &test, DAEMON_SIZE);
  160. break;
  161. }
  162. }
  163. # endif
  164. {
  165. for (pp = Player, i = 0; pp < End_player; pp++, i++)
  166. if (havechar(pp, i + 3)) {
  167. execute(pp);
  168. pp->p_nexec++;
  169. }
  170. # ifdef MONITOR
  171. for (pp = Monitor, i = 0; pp < End_monitor; pp++, i++)
  172. if (havechar(pp, i + MAXPL + 3)) {
  173. mon_execute(pp);
  174. pp->p_nexec++;
  175. }
  176. # endif
  177. moveshots();
  178. for (pp = Player, i = 0; pp < End_player; )
  179. if (pp->p_death[0] != '\0')
  180. zap(pp, TRUE, i + 3);
  181. else
  182. pp++, i++;
  183. # ifdef MONITOR
  184. for (pp = Monitor, i = 0; pp < End_monitor; )
  185. if (pp->p_death[0] != '\0')
  186. zap(pp, FALSE, i + MAXPL + 3);
  187. else
  188. pp++, i++;
  189. # endif
  190. }
  191. if (fdset[0].revents & POLLIN)
  192. if (answer()) {
  193. # ifdef INTERNET
  194. if (first && standard_port)
  195. faketalk();
  196. # endif
  197. first = FALSE;
  198. }
  199. if (fdset[1].revents & POLLIN)
  200. send_stats();
  201. for (pp = Player, i = 0; pp < End_player; pp++, i++) {
  202. if (fdset[i + 3].revents & POLLIN)
  203. sendcom(pp, READY, pp->p_nexec);
  204. pp->p_nexec = 0;
  205. (void) fflush(pp->p_output);
  206. }
  207. # ifdef MONITOR
  208. for (pp = Monitor, i = 0; pp < End_monitor; pp++, i++) {
  209. if (fdset[i + MAXPL + 3].revents & POLLIN)
  210. sendcom(pp, READY, pp->p_nexec);
  211. pp->p_nexec = 0;
  212. (void) fflush(pp->p_output);
  213. }
  214. # endif
  215. } while (Nplayer > 0);
  216. if (poll(fdset, 3+MAXPL+MAXMON, linger) > 0) {
  217. goto again;
  218. }
  219. if (server) {
  220. clear_scores();
  221. makemaze();
  222. clearwalls();
  223. # ifdef BOOTS
  224. makeboots();
  225. # endif
  226. first = TRUE;
  227. goto again;
  228. }
  229. # ifdef MONITOR
  230. for (pp = Monitor, i = 0; pp < End_monitor; i++)
  231. zap(pp, FALSE, i + MAXPL + 3);
  232. # endif
  233. cleanup(0);
  234. /* NOTREACHED */
  235. return(0);
  236. }
  237. /*
  238. * init:
  239. * Initialize the global parameters.
  240. */
  241. static void
  242. init()
  243. {
  244. int i;
  245. # ifdef INTERNET
  246. SOCKET test_port;
  247. int msg;
  248. int len;
  249. # endif
  250. # ifndef DEBUG
  251. switch (fork()) {
  252. case -1:
  253. err(1, "fork");
  254. case 0:
  255. break; /* child */
  256. default:
  257. exit(0); /* parent */
  258. }
  259. if (setsid() == -1)
  260. err(1, "setsid");
  261. (void) signal(SIGHUP, SIG_IGN);
  262. (void) signal(SIGINT, SIG_IGN);
  263. (void) signal(SIGQUIT, SIG_IGN);
  264. (void) signal(SIGTERM, cleanup);
  265. # endif
  266. (void) chdir("/var/tmp"); /* just in case it core dumps */
  267. (void) umask(0); /* No privacy at all! */
  268. (void) signal(SIGPIPE, SIG_IGN);
  269. # ifdef LOG
  270. # ifdef SYSLOG_43
  271. openlog("huntd", LOG_PID, LOG_DAEMON);
  272. # endif
  273. # ifdef SYSLOG_42
  274. openlog("huntd", LOG_PID);
  275. # endif
  276. # endif
  277. /*
  278. * Initialize statistics socket
  279. */
  280. # ifdef INTERNET
  281. Daemon.sin_family = SOCK_FAMILY;
  282. Daemon.sin_addr.s_addr = INADDR_ANY;
  283. Daemon.sin_port = 0;
  284. # else
  285. Daemon.sun_family = SOCK_FAMILY;
  286. (void) strcpy(Daemon.sun_path, Stat_name);
  287. # endif
  288. Status = socket(SOCK_FAMILY, SOCK_STREAM, 0);
  289. if (bind(Status, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
  290. if (errno == EADDRINUSE)
  291. exit(0);
  292. else {
  293. # ifdef LOG
  294. syslog(LOG_ERR, "bind: %m");
  295. # else
  296. warn("bind");
  297. # endif
  298. cleanup(1);
  299. }
  300. }
  301. (void) listen(Status, 5);
  302. # ifdef INTERNET
  303. len = sizeof (SOCKET);
  304. if (getsockname(Status, (struct sockaddr *) &Daemon, &len) < 0) {
  305. # ifdef LOG
  306. syslog(LOG_ERR, "getsockname: %m");
  307. # else
  308. warn("getsockname");
  309. # endif
  310. exit(1);
  311. }
  312. stat_port = ntohs(Daemon.sin_port);
  313. # endif
  314. /*
  315. * Initialize main socket
  316. */
  317. # ifdef INTERNET
  318. Daemon.sin_family = SOCK_FAMILY;
  319. Daemon.sin_addr.s_addr = INADDR_ANY;
  320. Daemon.sin_port = 0;
  321. # else
  322. Daemon.sun_family = SOCK_FAMILY;
  323. (void) strcpy(Daemon.sun_path, Sock_name);
  324. # endif
  325. Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
  326. # if defined(INTERNET)
  327. msg = 1;
  328. #ifdef SO_USELOOPBACK
  329. if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, &msg, sizeof msg)<0)
  330. # ifdef LOG
  331. syslog(LOG_WARNING, "setsockopt loopback %m");
  332. # else
  333. warn("setsockopt loopback");
  334. # endif
  335. #endif
  336. # endif
  337. if (bind(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
  338. if (errno == EADDRINUSE)
  339. exit(0);
  340. else {
  341. # ifdef LOG
  342. syslog(LOG_ERR, "bind: %m");
  343. # else
  344. warn("bind");
  345. # endif
  346. cleanup(1);
  347. }
  348. }
  349. (void) listen(Socket, 5);
  350. # ifdef INTERNET
  351. len = sizeof (SOCKET);
  352. if (getsockname(Socket, (struct sockaddr *) &Daemon, &len) < 0) {
  353. # ifdef LOG
  354. syslog(LOG_ERR, "getsockname: %m");
  355. # else
  356. warn("getsockname");
  357. # endif
  358. exit(1);
  359. }
  360. sock_port = ntohs(Daemon.sin_port);
  361. # endif
  362. /*
  363. * Initialize minimal select mask
  364. */
  365. fdset[0].fd = Socket;
  366. fdset[0].events = POLLIN;
  367. fdset[1].fd = Status;
  368. fdset[1].events = POLLIN;
  369. # ifdef INTERNET
  370. len = sizeof (SOCKET);
  371. if (getsockname(0, (struct sockaddr *) &test_port, &len) >= 0
  372. && test_port.sin_family == AF_INET) {
  373. inetd_spawned = TRUE;
  374. Test_socket = 0;
  375. if (test_port.sin_port != htons((u_short) Test_port)) {
  376. standard_port = FALSE;
  377. Test_port = ntohs(test_port.sin_port);
  378. }
  379. } else {
  380. test_port = Daemon;
  381. test_port.sin_port = htons((u_short) Test_port);
  382. Test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
  383. if (bind(Test_socket, (struct sockaddr *) &test_port,
  384. DAEMON_SIZE) < 0) {
  385. # ifdef LOG
  386. syslog(LOG_ERR, "bind: %m");
  387. # else
  388. warn("bind");
  389. # endif
  390. exit(1);
  391. }
  392. (void) listen(Test_socket, 5);
  393. }
  394. fdset[2].fd = Test_socket;
  395. fdset[2].events = POLLIN;
  396. # else
  397. fdset[2].fd = -1;
  398. # endif
  399. Seed = getpid() + time((time_t *) NULL);
  400. makemaze();
  401. # ifdef BOOTS
  402. makeboots();
  403. # endif
  404. for (i = 0; i < NASCII; i++)
  405. See_over[i] = TRUE;
  406. See_over[DOOR] = FALSE;
  407. See_over[WALL1] = FALSE;
  408. See_over[WALL2] = FALSE;
  409. See_over[WALL3] = FALSE;
  410. # ifdef REFLECT
  411. See_over[WALL4] = FALSE;
  412. See_over[WALL5] = FALSE;
  413. # endif
  414. }
  415. # ifdef BOOTS
  416. /*
  417. * makeboots:
  418. * Put the boots in the maze
  419. */
  420. static void
  421. makeboots()
  422. {
  423. int x, y;
  424. PLAYER *pp;
  425. do {
  426. x = rand_num(WIDTH - 1) + 1;
  427. y = rand_num(HEIGHT - 1) + 1;
  428. } while (Maze[y][x] != SPACE);
  429. Maze[y][x] = BOOT_PAIR;
  430. for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
  431. pp->p_flying = -1;
  432. }
  433. # endif
  434. /*
  435. * checkdam:
  436. * Check the damage to the given player, and see if s/he is killed
  437. */
  438. void
  439. checkdam(ouch, gotcha, credit, amt, shot_type)
  440. PLAYER *ouch, *gotcha;
  441. IDENT *credit;
  442. int amt;
  443. char shot_type;
  444. {
  445. const char *cp;
  446. if (ouch->p_death[0] != '\0')
  447. return;
  448. # ifdef BOOTS
  449. if (shot_type == SLIME)
  450. switch (ouch->p_nboots) {
  451. default:
  452. break;
  453. case 1:
  454. amt = (amt + 1) / 2;
  455. break;
  456. case 2:
  457. if (gotcha != NULL)
  458. message(gotcha, "He has boots on!");
  459. return;
  460. }
  461. # endif
  462. ouch->p_damage += amt;
  463. if (ouch->p_damage <= ouch->p_damcap) {
  464. (void) sprintf(Buf, "%2d", ouch->p_damage);
  465. cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL);
  466. outstr(ouch, Buf, 2);
  467. return;
  468. }
  469. /* Someone DIED */
  470. switch (shot_type) {
  471. default:
  472. cp = "Killed";
  473. break;
  474. # ifdef FLY
  475. case FALL:
  476. cp = "Killed on impact";
  477. break;
  478. # endif
  479. case KNIFE:
  480. cp = "Stabbed to death";
  481. ouch->p_ammo = 0; /* No exploding */
  482. break;
  483. case SHOT:
  484. cp = "Shot to death";
  485. break;
  486. case GRENADE:
  487. case SATCHEL:
  488. case BOMB:
  489. cp = "Bombed";
  490. break;
  491. case MINE:
  492. case GMINE:
  493. cp = "Blown apart";
  494. break;
  495. # ifdef OOZE
  496. case SLIME:
  497. cp = "Slimed";
  498. if (credit != NULL)
  499. credit->i_slime++;
  500. break;
  501. # endif
  502. # ifdef VOLCANO
  503. case LAVA:
  504. cp = "Baked";
  505. break;
  506. # endif
  507. # ifdef DRONE
  508. case DSHOT:
  509. cp = "Eliminated";
  510. break;
  511. # endif
  512. }
  513. if (credit == NULL) {
  514. (void) sprintf(ouch->p_death, "| %s by %s |", cp,
  515. (shot_type == MINE || shot_type == GMINE) ?
  516. "a mine" : "act of God");
  517. return;
  518. }
  519. (void) sprintf(ouch->p_death, "| %s by %s |", cp, credit->i_name);
  520. if (ouch == gotcha) { /* No use killing yourself */
  521. credit->i_kills--;
  522. credit->i_bkills++;
  523. }
  524. else if (ouch->p_ident->i_team == ' '
  525. || ouch->p_ident->i_team != credit->i_team) {
  526. credit->i_kills++;
  527. credit->i_gkills++;
  528. }
  529. else {
  530. credit->i_kills--;
  531. credit->i_bkills++;
  532. }
  533. credit->i_score = credit->i_kills / (double) credit->i_entries;
  534. ouch->p_ident->i_deaths++;
  535. if (ouch->p_nchar == 0)
  536. ouch->p_ident->i_stillb++;
  537. if (gotcha == NULL)
  538. return;
  539. gotcha->p_damcap += STABDAM;
  540. gotcha->p_damage -= STABDAM;
  541. if (gotcha->p_damage < 0)
  542. gotcha->p_damage = 0;
  543. (void) sprintf(Buf, "%2d/%2d", gotcha->p_damage, gotcha->p_damcap);
  544. cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL);
  545. outstr(gotcha, Buf, 5);
  546. (void) sprintf(Buf, "%3d", (gotcha->p_damcap - MAXDAM) / 2);
  547. cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL);
  548. outstr(gotcha, Buf, 3);
  549. (void) sprintf(Buf, "%5.2f", gotcha->p_ident->i_score);
  550. for (ouch = Player; ouch < End_player; ouch++) {
  551. cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
  552. STAT_NAME_COL);
  553. outstr(ouch, Buf, 5);
  554. }
  555. # ifdef MONITOR
  556. for (ouch = Monitor; ouch < End_monitor; ouch++) {
  557. cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
  558. STAT_NAME_COL);
  559. outstr(ouch, Buf, 5);
  560. }
  561. # endif
  562. }
  563. /*
  564. * zap:
  565. * Kill off a player and take him out of the game.
  566. */
  567. static void
  568. zap(pp, was_player, i)
  569. PLAYER *pp;
  570. FLAG was_player;
  571. int i;
  572. {
  573. int n, len;
  574. BULLET *bp;
  575. PLAYER *np;
  576. int x, y;
  577. int savefd;
  578. if (was_player) {
  579. if (pp->p_undershot)
  580. fixshots(pp->p_y, pp->p_x, pp->p_over);
  581. drawplayer(pp, FALSE);
  582. Nplayer--;
  583. }
  584. len = strlen(pp->p_death); /* Display the cause of death */
  585. x = (WIDTH - len) / 2;
  586. cgoto(pp, HEIGHT / 2, x);
  587. outstr(pp, pp->p_death, len);
  588. for (n = 1; n < len; n++)
  589. pp->p_death[n] = '-';
  590. pp->p_death[0] = '+';
  591. pp->p_death[len - 1] = '+';
  592. cgoto(pp, HEIGHT / 2 - 1, x);
  593. outstr(pp, pp->p_death, len);
  594. cgoto(pp, HEIGHT / 2 + 1, x);
  595. outstr(pp, pp->p_death, len);
  596. cgoto(pp, HEIGHT, 0);
  597. savefd = pp->p_fd;
  598. # ifdef MONITOR
  599. if (was_player) {
  600. # endif
  601. for (bp = Bullets; bp != NULL; bp = bp->b_next) {
  602. if (bp->b_owner == pp)
  603. bp->b_owner = NULL;
  604. if (bp->b_x == pp->p_x && bp->b_y == pp->p_y)
  605. bp->b_over = SPACE;
  606. }
  607. n = rand_num(pp->p_ammo);
  608. x = rand_num(pp->p_ammo);
  609. if (x > n)
  610. n = x;
  611. if (pp->p_ammo == 0)
  612. x = 0;
  613. else if (n == pp->p_ammo - 1) {
  614. x = pp->p_ammo;
  615. len = SLIME;
  616. }
  617. else {
  618. for (x = MAXBOMB - 1; x > 0; x--)
  619. if (n >= shot_req[x])
  620. break;
  621. for (y = MAXSLIME - 1; y > 0; y--)
  622. if (n >= slime_req[y])
  623. break;
  624. if (y >= 0 && slime_req[y] > shot_req[x]) {
  625. x = slime_req[y];
  626. len = SLIME;
  627. }
  628. else if (x != 0) {
  629. len = shot_type[x];
  630. x = shot_req[x];
  631. }
  632. }
  633. if (x > 0) {
  634. (void) add_shot(len, pp->p_y, pp->p_x, pp->p_face, x,
  635. (PLAYER *) NULL, TRUE, SPACE);
  636. (void) sprintf(Buf, "%s detonated.",
  637. pp->p_ident->i_name);
  638. for (np = Player; np < End_player; np++)
  639. message(np, Buf);
  640. # ifdef MONITOR
  641. for (np = Monitor; np < End_monitor; np++)
  642. message(np, Buf);
  643. # endif
  644. # ifdef BOOTS
  645. while (pp->p_nboots-- > 0) {
  646. for (np = Boot; np < &Boot[NBOOTS]; np++)
  647. if (np->p_flying < 0)
  648. break;
  649. if (np >= &Boot[NBOOTS])
  650. err(1, "Too many boots");
  651. np->p_undershot = FALSE;
  652. np->p_x = pp->p_x;
  653. np->p_y = pp->p_y;
  654. np->p_flying = rand_num(20);
  655. np->p_flyx = 2 * rand_num(6) - 5;
  656. np->p_flyy = 2 * rand_num(6) - 5;
  657. np->p_over = SPACE;
  658. np->p_face = BOOT;
  659. showexpl(np->p_y, np->p_x, BOOT);
  660. }
  661. # endif
  662. }
  663. # ifdef BOOTS
  664. else if (pp->p_nboots > 0) {
  665. if (pp->p_nboots == 2)
  666. Maze[pp->p_y][pp->p_x] = BOOT_PAIR;
  667. else
  668. Maze[pp->p_y][pp->p_x] = BOOT;
  669. if (pp->p_undershot)
  670. fixshots(pp->p_y, pp->p_x,
  671. Maze[pp->p_y][pp->p_x]);
  672. }
  673. # endif
  674. # ifdef VOLCANO
  675. volcano += pp->p_ammo - x;
  676. if (rand_num(100) < volcano / 50) {
  677. do {
  678. x = rand_num(WIDTH / 2) + WIDTH / 4;
  679. y = rand_num(HEIGHT / 2) + HEIGHT / 4;
  680. } while (Maze[y][x] != SPACE);
  681. (void) add_shot(LAVA, y, x, LEFTS, volcano,
  682. (PLAYER *) NULL, TRUE, SPACE);
  683. for (np = Player; np < End_player; np++)
  684. message(np, "Volcano eruption.");
  685. volcano = 0;
  686. }
  687. # endif
  688. # ifdef DRONE
  689. if (rand_num(100) < 2) {
  690. do {
  691. x = rand_num(WIDTH / 2) + WIDTH / 4;
  692. y = rand_num(HEIGHT / 2) + HEIGHT / 4;
  693. } while (Maze[y][x] != SPACE);
  694. add_shot(DSHOT, y, x, rand_dir(),
  695. shot_req[MINDSHOT +
  696. rand_num(MAXBOMB - MINDSHOT)],
  697. (PLAYER *) NULL, FALSE, SPACE);
  698. }
  699. # endif
  700. sendcom(pp, ENDWIN);
  701. (void) putc(' ', pp->p_output);
  702. (void) fclose(pp->p_output);
  703. End_player--;
  704. if (pp != End_player) {
  705. memcpy(pp, End_player, sizeof (PLAYER));
  706. fdset[i] = fdset[End_player - Player + 3];
  707. fdset[End_player - Player + 3].fd = -1;
  708. (void) sprintf(Buf, "%5.2f%c%-10.10s %c",
  709. pp->p_ident->i_score, stat_char(pp),
  710. pp->p_ident->i_name, pp->p_ident->i_team);
  711. n = STAT_PLAY_ROW + 1 + (pp - Player);
  712. for (np = Player; np < End_player; np++) {
  713. cgoto(np, n, STAT_NAME_COL);
  714. outstr(np, Buf, STAT_NAME_LEN);
  715. }
  716. # ifdef MONITOR
  717. for (np = Monitor; np < End_monitor; np++) {
  718. cgoto(np, n, STAT_NAME_COL);
  719. outstr(np, Buf, STAT_NAME_LEN);
  720. }
  721. # endif
  722. } else
  723. fdset[i].fd = -1;
  724. /* Erase the last player */
  725. n = STAT_PLAY_ROW + 1 + Nplayer;
  726. for (np = Player; np < End_player; np++) {
  727. cgoto(np, n, STAT_NAME_COL);
  728. ce(np);
  729. }
  730. # ifdef MONITOR
  731. for (np = Monitor; np < End_monitor; np++) {
  732. cgoto(np, n, STAT_NAME_COL);
  733. ce(np);
  734. }
  735. }
  736. else {
  737. sendcom(pp, ENDWIN);
  738. (void) putc(LAST_PLAYER, pp->p_output);
  739. (void) fclose(pp->p_output);
  740. End_monitor--;
  741. if (pp != End_monitor) {
  742. memcpy(pp, End_monitor, sizeof (PLAYER));
  743. fdset[i] = fdset[End_monitor - Monitor + MAXPL + 3];
  744. fdset[End_monitor - Monitor + MAXPL + 3].fd = -1;
  745. (void) sprintf(Buf, "%5.5s %-10.10s %c", " ",
  746. pp->p_ident->i_name, pp->p_ident->i_team);
  747. n = STAT_MON_ROW + 1 + (pp - Player);
  748. for (np = Player; np < End_player; np++) {
  749. cgoto(np, n, STAT_NAME_COL);
  750. outstr(np, Buf, STAT_NAME_LEN);
  751. }
  752. for (np = Monitor; np < End_monitor; np++) {
  753. cgoto(np, n, STAT_NAME_COL);
  754. outstr(np, Buf, STAT_NAME_LEN);
  755. }
  756. } else
  757. fdset[i].fd = -1;
  758. /* Erase the last monitor */
  759. n = STAT_MON_ROW + 1 + (End_monitor - Monitor);
  760. for (np = Player; np < End_player; np++) {
  761. cgoto(np, n, STAT_NAME_COL);
  762. ce(np);
  763. }
  764. for (np = Monitor; np < End_monitor; np++) {
  765. cgoto(np, n, STAT_NAME_COL);
  766. ce(np);
  767. }
  768. }
  769. # endif
  770. }
  771. /*
  772. * rand_num:
  773. * Return a random number in a given range.
  774. */
  775. int
  776. rand_num(range)
  777. int range;
  778. {
  779. return (range == 0 ? 0 : RN % range);
  780. }
  781. /*
  782. * havechar:
  783. * Check to see if we have any characters in the input queue; if
  784. * we do, read them, stash them away, and return TRUE; else return
  785. * FALSE.
  786. */
  787. static int
  788. havechar(pp, i)
  789. PLAYER *pp;
  790. int i;
  791. {
  792. if (pp->p_ncount < pp->p_nchar)
  793. return TRUE;
  794. if (!(fdset[i].revents & POLLIN))
  795. return FALSE;
  796. check_again:
  797. errno = 0;
  798. if ((pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf)) <= 0)
  799. {
  800. if (errno == EINTR)
  801. goto check_again;
  802. pp->p_cbuf[0] = 'q';
  803. }
  804. pp->p_ncount = 0;
  805. return TRUE;
  806. }
  807. /*
  808. * cleanup:
  809. * Exit with the given value, cleaning up any droppings lying around
  810. */
  811. SIGNAL_TYPE
  812. cleanup(eval)
  813. int eval;
  814. {
  815. PLAYER *pp;
  816. for (pp = Player; pp < End_player; pp++) {
  817. cgoto(pp, HEIGHT, 0);
  818. sendcom(pp, ENDWIN);
  819. (void) putc(LAST_PLAYER, pp->p_output);
  820. (void) fclose(pp->p_output);
  821. }
  822. # ifdef MONITOR
  823. for (pp = Monitor; pp < End_monitor; pp++) {
  824. cgoto(pp, HEIGHT, 0);
  825. sendcom(pp, ENDWIN);
  826. (void) putc(LAST_PLAYER, pp->p_output);
  827. (void) fclose(pp->p_output);
  828. }
  829. # endif
  830. (void) close(Socket);
  831. # ifdef AF_UNIX_HACK
  832. (void) unlink(Sock_name);
  833. # endif
  834. exit(eval);
  835. }
  836. /*
  837. * send_stats:
  838. * Print stats to requestor
  839. */
  840. static void
  841. send_stats()
  842. {
  843. IDENT *ip;
  844. FILE *fp;
  845. int s;
  846. SOCKET sockstruct;
  847. int socklen;
  848. /*
  849. * Get the output stream ready
  850. */
  851. # ifdef INTERNET
  852. socklen = sizeof sockstruct;
  853. # else
  854. socklen = sizeof sockstruct - 1;
  855. # endif
  856. s = accept(Status, (struct sockaddr *) &sockstruct, &socklen);
  857. if (s < 0) {
  858. if (errno == EINTR)
  859. return;
  860. # ifdef LOG
  861. syslog(LOG_WARNING, "accept: %m");
  862. # else
  863. warn("accept");
  864. # endif
  865. return;
  866. }
  867. fp = fdopen(s, "w");
  868. if (fp == NULL) {
  869. # ifdef LOG
  870. syslog(LOG_WARNING, "fdopen: %m");
  871. # else
  872. warn("fdopen");
  873. # endif
  874. (void) close(s);
  875. return;
  876. }
  877. /*
  878. * Send output to requestor
  879. */
  880. fputs("Name\t\tScore\tDucked\tAbsorb\tFaced\tShot\tRobbed\tMissed\tSlimeK\n", fp);
  881. for (ip = Scores; ip != NULL; ip = ip->i_next) {
  882. fprintf(fp, "%s\t", ip->i_name);
  883. if (strlen(ip->i_name) < 8)
  884. putc('\t', fp);
  885. fprintf(fp, "%.2f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
  886. ip->i_score, ip->i_ducked, ip->i_absorbed,
  887. ip->i_faced, ip->i_shot, ip->i_robbed,
  888. ip->i_missed, ip->i_slime);
  889. }
  890. fputs("\n\nName\t\tEnemy\tFriend\tDeaths\tStill\tSaved\n", fp);
  891. for (ip = Scores; ip != NULL; ip = ip->i_next) {
  892. if (ip->i_team == ' ') {
  893. fprintf(fp, "%s\t", ip->i_name);
  894. if (strlen(ip->i_name) < 8)
  895. putc('\t', fp);
  896. }
  897. else {
  898. fprintf(fp, "%s[%c]\t", ip->i_name, ip->i_team);
  899. if (strlen(ip->i_name) + 3 < 8)
  900. putc('\t', fp);
  901. }
  902. fprintf(fp, "%d\t%d\t%d\t%d\t%d\n",
  903. ip->i_gkills, ip->i_bkills, ip->i_deaths,
  904. ip->i_stillb, ip->i_saved);
  905. }
  906. (void) fclose(fp);
  907. }
  908. /*
  909. * clear_scores:
  910. * Clear out the scores so the next session start clean
  911. */
  912. static void
  913. clear_scores()
  914. {
  915. IDENT *ip, *nextip;
  916. for (ip = Scores; ip != NULL; ip = nextip) {
  917. nextip = ip->i_next;
  918. (void) free((char *) ip);
  919. }
  920. Scores = NULL;
  921. }