BSD 4_3_Reno release
[unix-history] / usr / src / games / hunt / driver / driver.c
CommitLineData
ca67e7b4
C
1/*
2 * Copyright (c) 1985 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18#ifndef lint
19char copyright[] =
20"@(#) Copyright (c) 1985 Regents of the University of California.\n\
21 All rights reserved.\n";
22#endif /* not lint */
23
24#ifndef lint
25static char sccsid[] = "@(#)driver.c 5.3 (Berkeley) 6/27/88";
26#endif /* not lint */
27
db16ccc5
C
28/*
29 * Hunt
30 * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
31 * San Francisco, California
db16ccc5
C
32 */
33
34# include "hunt.h"
35# include <signal.h>
36# include <errno.h>
37# include <sys/ioctl.h>
38# include <sys/time.h>
39
40# ifndef pdp11
41# define RN (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff)
42# else pdp11
43# define RN ((Seed = Seed * 11109 + 13849) & 0x7fff)
44# endif pdp11
45
46int Seed = 0;
47
48# ifdef CONSTANT_MOVE
49static struct itimerval Timing;
50# endif CONSTANT_MOVE
51
52SOCKET Daemon;
53# ifdef INTERNET
54int Test_socket; /* test socket to answer datagrams */
55# define DAEMON_SIZE (sizeof Daemon)
56# else INTERNET
57# define DAEMON_SIZE (sizeof Daemon - 1)
58# endif INTERNET
59
60/*
61 * main:
62 * The main program.
63 */
64main()
65{
66 register PLAYER *pp;
67 register int had_char;
68# ifdef INTERNET
69 register long test_mask;
70 int msg;
71 int namelen;
72 SOCKET test;
73# endif INTERNET
74# ifdef CONSTANT_MOVE
75 register int enable_alarm, disable_alarm;
76# endif CONSTANT_MOVE
77 static long read_fds;
78
79 init();
80 Sock_mask = (1 << Socket);
81# ifdef INTERNET
82 test_mask = (1 << Test_socket);
83# endif INTERNET
84
85# ifdef CONSTANT_MOVE
86 enable_alarm = sigblock(0);
87 disable_alarm = enable_alarm | (1 << (SIGALRM - 1));
88 (void) sigsetmask(disable_alarm);
89 (void) signal(SIGALRM, moveshots);
90# endif CONSTANT_MOVE
91
92 while (Nplayer > 0) {
93# ifdef CONSTANT_MOVE
94 (void) sigsetmask(enable_alarm);
95# endif CONSTANT_MOVE
96 read_fds = Fds_mask;
97 errno = 0;
98# ifndef OLDIPC
99 while (select(Num_fds, &read_fds, (int *) NULL,
100 (int *) NULL, (struct timeval *) NULL) < 0)
101# else OLDIPC
102 while (select(20, &read_fds, NULL, 32767) < 0)
103# endif OLDIPC
104 {
105 if (errno != EINTR)
106 perror("select");
107 if (Nplayer == 0)
108 goto out;
109 errno = 0;
110 }
111 Have_inp = read_fds;
112# ifdef CONSTANT_MOVE
113 (void) sigsetmask(disable_alarm);
114# endif CONSTANT_MOVE
115# ifdef INTERNET
116 if (read_fds & test_mask) {
117 namelen = DAEMON_SIZE;
118# ifndef OLDIPC
119 (void) recvfrom(Test_socket, (char *) &msg, sizeof msg,
120 0, (struct sockaddr *) &test, &namelen);
121 (void) sendto(Test_socket, (char *) &msg, sizeof msg,
122 0, (struct sockaddr *) &test, DAEMON_SIZE);
123# else OLDIPC
124 (void) receive(Test_socket, (struct sockaddr *) &test,
125 (char *) &msg, sizeof msg);
126 (void) send(Test_socket, (struct sockaddr *) &test,
127 (char *) &msg, sizeof msg);
128# endif OLDIPC
129 }
130# endif INTERNET
131 for (;;) {
132 had_char = FALSE;
133 for (pp = Player; pp < End_player; pp++)
134 if (havechar(pp)) {
135 execute(pp);
136 pp->p_nexec++;
137 had_char++;
138 }
139# ifdef MONITOR
140 for (pp = Monitor; pp < End_monitor; pp++)
141 if (havechar(pp)) {
142 mon_execute(pp);
143 pp->p_nexec++;
144 had_char++;
145 }
146# endif MONITOR
147 if (!had_char)
148 break;
149# ifdef CONSTANT_MOVE
150 for (pp = Player; pp < End_player; pp++) {
151 look(pp);
152 sendcom(pp, REFRESH);
153 }
154# ifdef MONITOR
155 for (pp = Monitor; pp < End_monitor; pp++)
156 sendcom(pp, REFRESH);
157# endif MONITOR
158# else CONSTANT_MOVE
159 moveshots();
160# endif CONSTANT_MOVE
161 for (pp = Player; pp < End_player; )
162 if (pp->p_death[0] != '\0')
163 zap(pp, TRUE);
164 else
165 pp++;
166# ifdef MONITOR
167 for (pp = Monitor; pp < End_monitor; )
168 if (pp->p_death[0] != '\0')
169 zap(pp, FALSE);
170 else
171 pp++;
172# endif MONITOR
173 }
174 if (read_fds & Sock_mask)
175 answer();
176 for (pp = Player; pp < End_player; pp++) {
177 if (read_fds & pp->p_mask)
178 sendcom(pp, READY, pp->p_nexec);
179 pp->p_nexec = 0;
180 (void) fflush(pp->p_output);
181 }
182# ifdef MONITOR
183 for (pp = Monitor; pp < End_monitor; pp++) {
184 if (read_fds & pp->p_mask)
185 sendcom(pp, READY, pp->p_nexec);
186 pp->p_nexec = 0;
187 (void) fflush(pp->p_output);
188 }
189# endif MONITOR
190 }
191out:
192# ifdef CONSTANT_MOVE
193 bul_alarm(0);
194# endif CONSTANT_MOVE
195
196# ifdef MONITOR
197 for (pp = Monitor; pp < End_monitor; )
198 zap(pp, FALSE);
199# endif MONITOR
200 cleanup(0);
201}
202
203/*
204 * init:
205 * Initialize the global parameters.
206 */
207init()
208{
209 register int i;
210# ifdef INTERNET
211 SOCKET test_port;
212 auto int msg;
213# endif INTERNET
ca67e7b4 214 int cleanup();
db16ccc5
C
215
216# ifndef DEBUG
217 (void) ioctl(fileno(stdout), TIOCNOTTY, NULL);
218 (void) setpgrp(getpid(), getpid());
219 (void) signal(SIGHUP, SIG_IGN);
220 (void) signal(SIGINT, SIG_IGN);
221 (void) signal(SIGQUIT, SIG_IGN);
222 (void) signal(SIGTERM, cleanup);
223# endif DEBUG
224
225 (void) chdir("/usr/tmp"); /* just in case it core dumps */
226 (void) signal(SIGPIPE, SIG_IGN);
227
228# ifdef INTERNET
229 Daemon.sin_family = SOCK_FAMILY;
230# ifdef OLD
231 if (gethostname(local_name, sizeof local_name) < 0) {
232 perror("gethostname");
233 exit(1);
234 }
235 if ((hp = gethostbyname(local_name)) == NULL) {
236 fprintf(stderr, "Unknown host %s\n", local_name);
237 exit(1);
238 }
239 bcopy(hp->h_addr, &(Daemon.sin_addr.s_addr), hp->h_length);
240# else
241 Daemon.sin_addr.s_addr = INADDR_ANY;
242# endif OLD
243 Daemon.sin_port = htons(Sock_port);
244# else INTERNET
245 Daemon.sun_family = SOCK_FAMILY;
246 (void) strcpy(Daemon.sun_path, Sock_name);
247# endif INTERNET
248
249# ifndef OLDIPC
250 Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
251# else OLDIPC
252 Socket = socket(SOCK_STREAM, 0, (struct sockaddr *) &Daemon,
253 SO_ACCEPTCONN);
254# endif OLDIPC
255# if defined(INTERNET) && !defined(OLDIPC)
256 if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, &msg, sizeof msg)<0)
257 perror("setsockopt loopback");
258# endif INTERNET
259# ifndef OLDIPC
260 if (bind(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
261 if (errno == EADDRINUSE)
262 exit(0);
263 else {
264 perror("bind");
265 cleanup(1);
266 }
267 }
268 (void) listen(Socket, 5);
269# endif OLDIPC
270 Fds_mask = (1 << Socket);
271 Num_fds = Socket + 1;
272
273# ifdef INTERNET
274 test_port = Daemon;
275 test_port.sin_port = htons(Test_port);
276
277# ifndef OLDIPC
278 Test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
279 if (bind(Test_socket, (struct sockaddr *) &test_port,
280 DAEMON_SIZE) < 0) {
281 perror("bind");
282 exit(1);
283 }
284 (void) listen(Test_socket, 5);
285# else OLDIPC
286 Test_socket = socket(SOCK_DGRAM, 0, (struct sockaddr *) &test_port, 0);
287# endif OLDIPC
288 Fds_mask |= (1 << Test_socket);
289 if (Test_socket > Socket)
290 Num_fds = Test_socket + 1;
291# endif INTERNET
292
293 Seed = getpid() + time((time_t *) NULL);
294 makemaze();
295
296 for (i = 0; i < NASCII; i++)
297 See_over[i] = TRUE;
298 See_over[DOOR] = FALSE;
299 See_over[WALL1] = FALSE;
300 See_over[WALL2] = FALSE;
301 See_over[WALL3] = FALSE;
302# ifdef REFLECT
303 See_over[WALL4] = FALSE;
304 See_over[WALL5] = FALSE;
305# endif REFLECT
306
307# ifdef CONSTANT_MOVE
308 getitimer(ITIMER_REAL, &Timing);
309 Timing.it_interval.tv_sec = 0;
310 Timing.it_interval.tv_usec = 500;
311 Timing.it_value.tv_sec = 0;
312 Timing.it_value.tv_usec = 0;
313 setitimer(ITIMER_REAL, &Timing, NULL);
314# endif CONSTANT_MOVE
315
316 answer();
317}
318
319# ifdef CONSTANT_MOVE
320/*
321 * bul_alarm:
322 * Set up the alarm for the bullets
323 */
324bul_alarm(val)
325int val;
326{
327 Timing.it_value.tv_usec = val * Timing.it_interval.tv_usec;
328 setitimer(ITIMER_REAL, &Timing, NULL);
329}
330# endif CONSTANT_MOVE
331
332/*
333 * checkdam:
334 * Check the damage to the given player, and see if s/he is killed
335 */
336checkdam(ouch, gotcha, credit, amt, shot_type)
337register PLAYER *ouch, *gotcha;
338register IDENT *credit;
339int amt;
340char shot_type;
341{
342 register char *cp;
343
344 if (ouch->p_death[0] != '\0')
345 return;
346 if (rand_num(100) < 5) {
347 message(ouch, "Missed you by a hair");
348 if (gotcha != NULL)
349 message(gotcha, "Missed him");
350 return;
351 }
352 ouch->p_damage += amt;
353 if (ouch->p_damage <= ouch->p_damcap) {
354 (void) sprintf(Buf, "%2d", ouch->p_damage);
355 cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL);
356 outstr(ouch, Buf, 2);
357 return;
358 }
359
360 /* Someone DIED */
361 switch (shot_type) {
362 default:
363 cp = "Killed";
364 break;
365# ifdef FLY
366 case FALL:
367 cp = "Killed on impact";
368 break;
369# endif FLY
370 case KNIFE:
371 cp = "Stabbed to death";
372 break;
373 case SHOT:
374 cp = "Shot to death";
375 break;
376 case GRENADE:
377 case SATCHEL:
378 case BOMB:
379 cp = "Bombed";
380 break;
381 case MINE:
382 case GMINE:
383 cp = "Blown apart";
384 break;
385# ifdef OOZE
386 case SLIME:
387 cp = "Slimed";
388 break;
389# endif OOZE
390# ifdef VOLCANO
391 case LAVA:
392 cp = "Baked";
393 break;
394# endif VOLCANO
395 }
396 if (credit == NULL) {
397 (void) sprintf(ouch->p_death, "| %s by %s |", cp,
398 (shot_type == MINE || shot_type == GMINE) ?
399 "a mine" : "act of God");
400 return;
401 }
402
403 (void) sprintf(ouch->p_death, "| %s by %s |", cp, credit->i_name);
404
405 credit->i_kills++;
406 credit->i_score = credit->i_kills / (double) credit->i_entries;
407 if (gotcha == NULL)
408 return;
409 gotcha->p_damcap += STABDAM;
410 gotcha->p_damage -= STABDAM;
411 if (gotcha->p_damage < 0)
412 gotcha->p_damage = 0;
413 (void) sprintf(Buf, "%2d/%2d", gotcha->p_damage, gotcha->p_damcap);
414 cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL);
415 outstr(gotcha, Buf, 5);
416 (void) sprintf(Buf, "%3d", (gotcha->p_damcap - MAXDAM) / 2);
417 cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL);
418 outstr(gotcha, Buf, 3);
419 (void) sprintf(Buf, "%5.2f", gotcha->p_ident->i_score);
420 for (ouch = Player; ouch < End_player; ouch++) {
421 cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
422 STAT_NAME_COL);
423 outstr(ouch, Buf, 5);
424 }
425}
426
427/*
428 * zap:
429 * Kill off a player and take him out of the game.
430 */
431zap(pp, was_player)
432register PLAYER *pp;
433FLAG was_player;
434{
435 register int i, len;
436 register BULLET *bp;
437 register PLAYER *np;
438 register int x, y;
439 int savefd, savemask;
440
441 if (was_player) {
442 drawplayer(pp, FALSE);
443 Nplayer--;
444 }
445
446 len = strlen(pp->p_death); /* Display the cause of death */
447 x = (WIDTH - len) / 2;
448 cgoto(pp, HEIGHT / 2, x);
449 outstr(pp, pp->p_death, len);
450 for (i = 1; i < len; i++)
451 pp->p_death[i] = '-';
452 pp->p_death[0] = '+';
453 pp->p_death[len - 1] = '+';
454 cgoto(pp, HEIGHT / 2 - 1, x);
455 outstr(pp, pp->p_death, len);
456 cgoto(pp, HEIGHT / 2 + 1, x);
457 outstr(pp, pp->p_death, len);
458 cgoto(pp, HEIGHT, 0);
459
460 if (Nplayer == 0) {
461# ifdef CONSTANT_MOVE
462 bul_alarm(0);
463# endif CONSTANT_MOVE
464 cleanup(0);
465 /* NOTREACHED */
466 }
467
468 savefd = pp->p_fd;
469 savemask = pp->p_mask;
470
471# ifdef MONITOR
472 if (was_player) {
473# endif MONITOR
474 for (bp = Bullets; bp != NULL; bp = bp->b_next) {
475 if (bp->b_owner == pp)
476 bp->b_owner = NULL;
477 if (bp->b_x == pp->p_x && bp->b_y == pp->p_y)
478 bp->b_over = SPACE;
479 }
480
481 i = rand_num(pp->p_ammo);
482 if (i == pp->p_ammo - 1) {
483 x = pp->p_ammo;
484 len = SLIME;
485 }
486 else if (i >= BOMBREQ) {
487 x = BOMBREQ;
488 len = BOMB;
489 }
490 else if (i >= SSLIMEREQ) {
491 x = SSLIMEREQ;
492 len = SLIME;
493 }
494 else if (i >= SATREQ) {
495 x = SATREQ;
496 len = SATCHEL;
497 }
498 else if (i >= SLIMEREQ) {
499 x = SLIMEREQ;
500 len = SLIME;
501 }
502 else if (i >= GRENREQ) {
503 x = GRENREQ;
504 len = GRENADE;
505 }
506 else
507 x = 0;
508 if (x > 0) {
509 add_shot(len, pp->p_y, pp->p_x, pp->p_face, x,
510 (PLAYER *) NULL, TRUE, SPACE);
511 (void) sprintf(Buf, "%s detonated.",
512 pp->p_ident->i_name);
513 for (np = Player; np < End_player; np++)
514 message(np, Buf);
515# ifdef MONITOR
516 for (np = Monitor; np < End_monitor; np++)
517 message(np, Buf);
518# endif MONITOR
519 }
520
521# ifdef VOLCANO
522 volcano += pp->p_ammo - x;
523 if (rand_num(100) < volcano / 50) {
524 do {
525 x = rand_num(WIDTH / 2) + WIDTH / 4;
526 y = rand_num(HEIGHT / 2) + HEIGHT / 4;
527 } while (Maze[y][x] != SPACE);
528 add_shot(LAVA, y, x, LEFTS, volcano,
529 (PLAYER *) NULL, TRUE, SPACE);
530 for (np = Player; np < End_player; np++)
531 message(np, "Volcano eruption.");
532 volcano = 0;
533 }
534# endif VOLCANO
535
536 sendcom(pp, ENDWIN);
537 (void) fclose(pp->p_output);
538
539 End_player--;
540 if (pp != End_player) {
541 bcopy((char *) End_player, (char *) pp,
542 sizeof (PLAYER));
543 (void) sprintf(Buf, "%5.2f%c%-10.10s",
544 pp->p_ident->i_score, stat_char(pp),
545 pp->p_ident->i_name);
546 i = STAT_PLAY_ROW + 1 + (pp - Player);
547 for (np = Player; np < End_player; np++) {
548 cgoto(np, i, STAT_NAME_COL);
549 outstr(np, Buf, STAT_NAME_LEN);
550 }
551# ifdef MONITOR
552 for (np = Monitor; np < End_monitor; np++) {
553 cgoto(np, i, STAT_NAME_COL);
554 outstr(np, Buf, STAT_NAME_LEN);
555 }
556# endif MONITOR
557 }
558
559 /* Erase the last player */
560 i = STAT_PLAY_ROW + 1 + Nplayer;
561 for (np = Player; np < End_player; np++) {
562 cgoto(np, i, STAT_NAME_COL);
563 ce(np);
564 }
565# ifdef MONITOR
566 for (np = Monitor; np < End_monitor; np++) {
567 cgoto(np, i, STAT_NAME_COL);
568 ce(np);
569 }
570 }
571 else {
572 sendcom(pp, ENDWIN);
573 (void) putc(LAST_PLAYER, pp->p_output);
574 (void) fclose(pp->p_output);
575
576 End_monitor--;
577 if (pp != End_monitor) {
578 bcopy((char *) End_monitor, (char *) pp,
579 sizeof (PLAYER));
580 (void) sprintf(Buf, "%5.5s %-10.10s", " ",
581 pp->p_ident->i_name);
582 i = STAT_MON_ROW + 1 + (pp - Player);
583 for (np = Player; np < End_player; np++) {
584 cgoto(np, i, STAT_NAME_COL);
585 outstr(np, Buf, STAT_NAME_LEN);
586 }
587 for (np = Monitor; np < End_monitor; np++) {
588 cgoto(np, i, STAT_NAME_COL);
589 outstr(np, Buf, STAT_NAME_LEN);
590 }
591 }
592
593 /* Erase the last monitor */
594 i = STAT_MON_ROW + 1 + (End_monitor - Monitor);
595 for (np = Player; np < End_player; np++) {
596 cgoto(np, i, STAT_NAME_COL);
597 ce(np);
598 }
599 for (np = Monitor; np < End_monitor; np++) {
600 cgoto(np, i, STAT_NAME_COL);
601 ce(np);
602 }
603
604 }
605# endif MONITOR
606
607 Fds_mask &= ~savemask;
608 if (Num_fds == savefd + 1) {
609 Num_fds = Socket;
610# ifdef INTERNET
611 if (Test_socket > Socket)
612 Num_fds = Test_socket;
613# endif INTERNET
614 for (np = Player; np < End_player; np++)
615 if (np->p_fd > Num_fds)
616 Num_fds = np->p_fd;
617# ifdef MONITOR
618 for (np = Monitor; np < End_monitor; np++)
619 if (np->p_fd > Num_fds)
620 Num_fds = np->p_fd;
621# endif MONITOR
622 Num_fds++;
623 }
624}
625
626/*
627 * rand_num:
628 * Return a random number in a given range.
629 */
630rand_num(range)
631int range;
632{
633 return (range == 0 ? 0 : RN % range);
634}
635
636/*
637 * havechar:
638 * Check to see if we have any characters in the input queue; if
639 * we do, read them, stash them away, and return TRUE; else return
640 * FALSE.
641 */
642havechar(pp)
643register PLAYER *pp;
644{
645 extern int errno;
646
647 if (pp->p_ncount < pp->p_nchar)
648 return TRUE;
649 if (!(Have_inp & pp->p_mask))
650 return FALSE;
651 Have_inp &= ~pp->p_mask;
652check_again:
653 errno = 0;
654 if ((pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf)) <= 0)
655 {
656 if (errno == EINTR)
657 goto check_again;
658 pp->p_cbuf[0] = 'q';
659 }
660 pp->p_ncount = 0;
661 return TRUE;
662}
663
664/*
665 * cleanup:
666 * Exit with the given value, cleaning up any droppings lying around
667 */
668cleanup(eval)
669int eval;
670{
671 register PLAYER *pp;
672
673 for (pp = Player; pp < End_player; pp++) {
674 cgoto(pp, HEIGHT, 0);
675 sendcom(pp, ENDWIN);
676 (void) putc(LAST_PLAYER, pp->p_output);
677 (void) fclose(pp->p_output);
678 }
679# ifdef MONITOR
680 for (pp = Monitor; pp < End_monitor; pp++) {
681 cgoto(pp, HEIGHT, 0);
682 sendcom(pp, ENDWIN);
683 (void) putc(LAST_PLAYER, pp->p_output);
684 (void) fclose(pp->p_output);
685 }
686# endif MONITOR
687 (void) close(Socket);
688# ifdef AF_UNIX_HACK
689 (void) unlink(Sock_name);
690# endif AF_UNIX_HACK
691 exit(eval);
692}