|
|
1.1 root 1: /*
2: * Hunt
3: * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
4: * San Francisco, California
5: *
6: * Copyright (c) 1985 Regents of the University of California.
7: * All rights reserved. The Berkeley software License Agreement
8: * specifies the terms and conditions for redistribution.
9: */
10:
11: # include "hunt.h"
12: # include <signal.h>
13:
14: # define PLUS_DELTA(x, max) if (x < max) x++; else x--
15: # define MINUS_DELTA(x, min) if (x > min) x--; else x++
16:
17: /*
18: * moveshots:
19: * Move the shots already in the air, taking explosions into account
20: */
21: moveshots()
22: {
23: register BULLET *bp, *next;
24: register PLAYER *pp;
25: register int x, y;
26: register BULLET *blist;
27: register int i;
28:
29: rollexpl();
30: if (Bullets == NULL)
31: goto ret;
32:
33: /*
34: * First we move through the bullet list BULSPD times, looking
35: * for things we may have run into. If we do run into
36: * something, we set up the explosion and disappear, checking
37: * for damage to any player who got in the way.
38: */
39:
40: blist = Bullets;
41: Bullets = NULL;
42: for (bp = blist; bp != NULL; bp = next) {
43: next = bp->b_next;
44: x = bp->b_x;
45: y = bp->b_y;
46: Maze[y][x] = bp->b_over;
47: for (pp = Player; pp < End_player; pp++)
48: check(pp, y, x);
49: # ifdef MONITOR
50: for (pp = Monitor; pp < End_monitor; pp++)
51: check(pp, y, x);
52: # endif MONITOR
53:
54: for (i = 0; i < BULSPD; i++) {
55: if (bp->b_expl)
56: break;
57:
58: x = bp->b_x;
59: y = bp->b_y;
60:
61: switch (bp->b_face) {
62: case LEFTS:
63: x--;
64: break;
65: case RIGHT:
66: x++;
67: break;
68: case ABOVE:
69: y--;
70: break;
71: case BELOW:
72: y++;
73: break;
74: }
75:
76: switch (Maze[y][x]) {
77: case SHOT:
78: if (rand_num(100) < 5) {
79: zapshot(Bullets, bp);
80: zapshot(next, bp);
81: }
82: break;
83: case GRENADE:
84: if (rand_num(100) < 10) {
85: zapshot(Bullets, bp);
86: zapshot(next, bp);
87: }
88: break;
89: # ifdef REFLECT
90: case WALL4: /* reflecting walls */
91: switch (bp->b_face) {
92: case LEFTS:
93: bp->b_face = BELOW;
94: break;
95: case RIGHT:
96: bp->b_face = ABOVE;
97: break;
98: case ABOVE:
99: bp->b_face = RIGHT;
100: break;
101: case BELOW:
102: bp->b_face = LEFTS;
103: break;
104: }
105: Maze[y][x] = WALL5;
106: # ifdef MONITOR
107: for (pp = Monitor; pp < End_monitor; pp++)
108: check(pp, y, x);
109: # endif MONITOR
110: break;
111: case WALL5:
112: switch (bp->b_face) {
113: case LEFTS:
114: bp->b_face = ABOVE;
115: break;
116: case RIGHT:
117: bp->b_face = BELOW;
118: break;
119: case ABOVE:
120: bp->b_face = LEFTS;
121: break;
122: case BELOW:
123: bp->b_face = RIGHT;
124: break;
125: }
126: Maze[y][x] = WALL4;
127: # ifdef MONITOR
128: for (pp = Monitor; pp < End_monitor; pp++)
129: check(pp, y, x);
130: # endif MONITOR
131: break;
132: # endif REFLECT
133: # ifdef RANDOM
134: case DOOR:
135: switch (rand_num(4)) {
136: case 0:
137: bp->b_face = ABOVE;
138: break;
139: case 1:
140: bp->b_face = BELOW;
141: break;
142: case 2:
143: bp->b_face = LEFTS;
144: break;
145: case 3:
146: bp->b_face = RIGHT;
147: break;
148: }
149: break;
150: # endif RANDOM
151: case LEFTS:
152: case RIGHT:
153: case BELOW:
154: case ABOVE:
155: # ifdef FLY
156: case FLYER:
157: # endif FLY
158: /*
159: * give the person a chance to catch a
160: * grenade if s/he is facing it
161: */
162: if (rand_num(100) < 10
163: && opposite(bp->b_face, Maze[y][x])) {
164: if (bp->b_owner != NULL)
165: message(bp->b_owner,
166: "Your charge was absorbed!");
167: pp = play_at(y, x);
168: pp->p_ammo += bp->b_charge;
169: (void) sprintf(Buf,
170: "Absorbed charge (good shield!)");
171: message(pp, Buf);
172: free((char *) bp);
173: (void) sprintf(Buf, "%3d", pp->p_ammo);
174: cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
175: outstr(pp, Buf, 3);
176: goto next_bullet;
177: }
178: /* FALLTHROUGH */
179: # ifndef RANDOM
180: case DOOR:
181: # endif RANDOM
182: case WALL1:
183: case WALL2:
184: case WALL3:
185: bp->b_expl = TRUE;
186: break;
187: }
188:
189: bp->b_x = x;
190: bp->b_y = y;
191: }
192:
193: bp->b_next = Bullets;
194: Bullets = bp;
195: next_bullet:
196: ;
197: }
198:
199: blist = Bullets;
200: Bullets = NULL;
201: for (bp = blist; bp != NULL; bp = next) {
202: next = bp->b_next;
203: if (!bp->b_expl) {
204: save_bullet(bp);
205: # ifdef MONITOR
206: for (pp = Monitor; pp < End_monitor; pp++)
207: check(pp, bp->b_y, bp->b_x);
208: # endif MONITOR
209: continue;
210: }
211:
212: chkshot(bp);
213: free((char *) bp);
214: }
215: for (pp = Player; pp < End_player; pp++)
216: Maze[pp->p_y][pp->p_x] = pp->p_face;
217: ret:
218: for (pp = Player; pp < End_player; pp++) {
219: # ifdef FLY
220: if (pp->p_flying >= 0) {
221: Maze[pp->p_y][pp->p_x] = pp->p_over;
222: x = pp->p_x + pp->p_flyx;
223: y = pp->p_y + pp->p_flyy;
224: if (x < 1) {
225: x = 1 - x;
226: pp->p_flyx = -pp->p_flyx;
227: }
228: else if (x > WIDTH - 2) {
229: x = (WIDTH - 2) - (x - (WIDTH - 2));
230: pp->p_flyx = -pp->p_flyx;
231: }
232: if (y < 1) {
233: y = 1 - y;
234: pp->p_flyy = -pp->p_flyy;
235: }
236: else if (y > HEIGHT - 2) {
237: y = (HEIGHT - 2) - (y - (HEIGHT - 2));
238: pp->p_flyy = -pp->p_flyy;
239: }
240: again: switch (Maze[y][x]) {
241: case LEFTS:
242: case RIGHT:
243: case ABOVE:
244: case BELOW:
245: case FLYER:
246: switch (rand_num(4)) {
247: case 0:
248: PLUS_DELTA(x, WIDTH - 2);
249: break;
250: case 1:
251: MINUS_DELTA(x, 1);
252: break;
253: case 2:
254: PLUS_DELTA(y, HEIGHT - 2);
255: break;
256: case 3:
257: MINUS_DELTA(y, 1);
258: break;
259: }
260: goto again;
261: case WALL1:
262: case WALL2:
263: case WALL3:
264: # ifdef REFLECT
265: case WALL4:
266: case WALL5:
267: # endif REFLECT
268: # ifdef RANDOM
269: case DOOR:
270: # endif RANDOM
271: if (pp->p_flying == 0)
272: pp->p_flying++;
273: break;
274: case MINE:
275: checkdam(pp, NULL, NULL, MINDAM, MINE);
276: Maze[y][x] = SPACE;
277: break;
278: case GMINE:
279: checkdam(pp, NULL, NULL, MINDAM, GMINE);
280: checkdam(pp, NULL, NULL, MINDAM, GMINE);
281: Maze[y][x] = SPACE;
282: break;
283: }
284: pp->p_y = y;
285: pp->p_x = x;
286: pp->p_over = Maze[y][x];
287: if (pp->p_flying-- == 0) {
288: checkdam(pp, NULL, NULL,
289: rand_num(pp->p_damage / 5), FALL);
290: rand_face(pp);
291: showstat(pp);
292: }
293: Maze[y][x] = pp->p_face;
294: showexpl(y, x, pp->p_face);
295: }
296: # endif FLY
297: sendcom(pp, REFRESH); /* Flush out the explosions */
298: look(pp);
299: sendcom(pp, REFRESH);
300: }
301: # ifdef MONITOR
302: for (pp = Monitor; pp < End_monitor; pp++)
303: sendcom(pp, REFRESH);
304: # endif MONITOR
305:
306: # ifdef CONSTANT_MOVE
307: if (Bullets != NULL) {
308: bul_alarm(1);
309: return;
310: }
311: for (i = 0; i < EXPLEN; i++)
312: if (Expl[i] != NULL) {
313: bul_alarm(1);
314: return;
315: }
316: bul_alarm(0);
317: # endif CONSTANT_MOVE
318:
319: return;
320: }
321:
322: save_bullet(bp)
323: register BULLET *bp;
324: {
325: bp->b_over = Maze[bp->b_y][bp->b_x];
326: switch (bp->b_over) {
327: case SHOT:
328: case GRENADE:
329: case SATCHEL:
330: case BOMB:
331: # ifdef OOZE
332: case SLIME:
333: # ifdef VOLCANO
334: case LAVA:
335: # endif VOLCANO
336: # endif OOZE
337: find_under(Bullets, bp);
338: break;
339: }
340:
341: switch (bp->b_over) {
342: case LEFTS:
343: case RIGHT:
344: case ABOVE:
345: case BELOW:
346: # ifdef FLY
347: case FLYER:
348: # endif FLY
349: mark_player(bp);
350: break;
351:
352: default:
353: Maze[bp->b_y][bp->b_x] = bp->b_type;
354: break;
355: }
356:
357: bp->b_next = Bullets;
358: Bullets = bp;
359: }
360:
361: /*
362: * chkshot
363: * Handle explosions
364: */
365: chkshot(bp)
366: register BULLET *bp;
367: {
368: register int y, x;
369: register int dy, dx, absdy;
370: register int delta, damage;
371: register char expl;
372: register PLAYER *pp;
373:
374: switch (bp->b_type) {
375: case SHOT:
376: case MINE:
377: delta = 0;
378: break;
379: case GRENADE:
380: case GMINE:
381: delta = 1;
382: break;
383: case SATCHEL:
384: delta = 2;
385: break;
386: case BOMB:
387: delta = 3;
388: break;
389: # ifdef OOZE
390: case SLIME:
391: # ifdef VOLCANO
392: case LAVA:
393: # endif VOLCANO
394: chkslime(bp);
395: return;
396: # endif OOZE
397: }
398: for (y = bp->b_y - delta; y <= bp->b_y + delta; y++) {
399: if (y < 0 || y >= HEIGHT)
400: continue;
401: dy = y - bp->b_y;
402: absdy = (dy < 0) ? -dy : dy;
403: for (x = bp->b_x - delta; x <= bp->b_x + delta; x++) {
404: if (x < 0 || x >= WIDTH)
405: continue;
406: dx = x - bp->b_x;
407: if (dx == 0)
408: expl = (dy == 0) ? '*' : '|';
409: else if (dy == 0)
410: expl = '-';
411: else if (dx == dy)
412: expl = '\\';
413: else if (dx == -dy)
414: expl = '/';
415: else
416: expl = '*';
417: showexpl(y, x, expl);
418: switch (Maze[y][x]) {
419: case LEFTS:
420: case RIGHT:
421: case ABOVE:
422: case BELOW:
423: # ifdef FLY
424: case FLYER:
425: # endif FLY
426: if (dx < 0)
427: dx = -dx;
428: if (absdy > dx)
429: damage = delta - absdy + 1;
430: else
431: damage = delta - dx + 1;
432: pp = play_at(y, x);
433: while (damage-- > 0)
434: checkdam(pp, bp->b_owner, bp->b_score,
435: MINDAM, bp->b_type);
436: break;
437: case GMINE:
438: case MINE:
439: add_shot((Maze[y][x] == GMINE) ?
440: GRENADE : SHOT,
441: y, x, LEFTS,
442: (Maze[y][x] == GMINE) ?
443: GRENREQ : BULREQ,
444: (PLAYER *) NULL, TRUE, SPACE);
445: Maze[y][x] = SPACE;
446: break;
447: }
448: }
449: }
450: }
451:
452: # ifdef OOZE
453: /*
454: * chkslime:
455: * handle slime shot exploding
456: */
457: chkslime(bp)
458: register BULLET *bp;
459: {
460: register BULLET *nbp;
461:
462: switch (Maze[bp->b_y][bp->b_x]) {
463: case WALL1:
464: case WALL2:
465: case WALL3:
466: # ifdef REFLECT
467: case WALL4:
468: case WALL5:
469: # endif REFLECT
470: # ifdef RANDOM
471: case DOOR:
472: # endif RANDOM
473: switch (bp->b_face) {
474: case LEFTS:
475: bp->b_x++;
476: break;
477: case RIGHT:
478: bp->b_x--;
479: break;
480: case ABOVE:
481: bp->b_y++;
482: break;
483: case BELOW:
484: bp->b_y--;
485: break;
486: }
487: break;
488: }
489: nbp = (BULLET *) malloc(sizeof (BULLET));
490: *nbp = *bp;
491: # ifdef VOLCANO
492: moveslime(nbp, nbp->b_type == SLIME ? SLIMESPEED : LAVASPEED);
493: # else VOLCANO
494: moveslime(nbp, SLIMESPEED);
495: # endif VOLCANO
496: }
497:
498: /*
499: * moveslime:
500: * move the given slime shot speed times and add it back if
501: * it hasn't fizzled yet
502: */
503: moveslime(bp, speed)
504: register BULLET *bp;
505: register int speed;
506: {
507: register int i, j, dirmask, count;
508: register PLAYER *pp;
509: register BULLET *nbp;
510:
511: if (speed == 0) {
512: if (bp->b_charge <= 0)
513: free((char *) bp);
514: else
515: save_bullet(bp);
516: return;
517: }
518:
519: # ifdef VOLCANO
520: showexpl(bp->b_y, bp->b_x, bp->b_type == LAVA ? LAVA : '*');
521: # else VOLCANO
522: showexpl(bp->b_y, bp->b_x, '*');
523: # endif VOLCANO
524: switch (Maze[bp->b_y][bp->b_x]) {
525: case LEFTS:
526: case RIGHT:
527: case ABOVE:
528: case BELOW:
529: # ifdef FLY
530: case FLYER:
531: # endif FLY
532: pp = play_at(bp->b_y, bp->b_x);
533: message(pp, "You've been slimed.");
534: checkdam(pp, bp->b_owner, bp->b_score, MINDAM, bp->b_type);
535: break;
536: }
537:
538: if (--bp->b_charge <= 0) {
539: free((char *) bp);
540: return;
541: }
542:
543: dirmask = 0;
544: count = 0;
545: switch (bp->b_face) {
546: case LEFTS:
547: if (!iswall(bp->b_y, bp->b_x - 1))
548: dirmask |= WEST, count++;
549: if (!iswall(bp->b_y - 1, bp->b_x))
550: dirmask |= NORTH, count++;
551: if (!iswall(bp->b_y + 1, bp->b_x))
552: dirmask |= SOUTH, count++;
553: if (dirmask == 0)
554: if (!iswall(bp->b_y, bp->b_x + 1))
555: dirmask |= EAST, count++;
556: break;
557: case RIGHT:
558: if (!iswall(bp->b_y, bp->b_x + 1))
559: dirmask |= EAST, count++;
560: if (!iswall(bp->b_y - 1, bp->b_x))
561: dirmask |= NORTH, count++;
562: if (!iswall(bp->b_y + 1, bp->b_x))
563: dirmask |= SOUTH, count++;
564: if (dirmask == 0)
565: if (!iswall(bp->b_y, bp->b_x - 1))
566: dirmask |= WEST, count++;
567: break;
568: case ABOVE:
569: if (!iswall(bp->b_y - 1, bp->b_x))
570: dirmask |= NORTH, count++;
571: if (!iswall(bp->b_y, bp->b_x - 1))
572: dirmask |= WEST, count++;
573: if (!iswall(bp->b_y, bp->b_x + 1))
574: dirmask |= EAST, count++;
575: if (dirmask == 0)
576: if (!iswall(bp->b_y + 1, bp->b_x))
577: dirmask |= SOUTH, count++;
578: break;
579: case BELOW:
580: if (!iswall(bp->b_y + 1, bp->b_x))
581: dirmask |= SOUTH, count++;
582: if (!iswall(bp->b_y, bp->b_x - 1))
583: dirmask |= WEST, count++;
584: if (!iswall(bp->b_y, bp->b_x + 1))
585: dirmask |= EAST, count++;
586: if (dirmask == 0)
587: if (!iswall(bp->b_y - 1, bp->b_x))
588: dirmask |= NORTH, count++;
589: break;
590: }
591: if (count == 0) {
592: /*
593: * No place to go. Just sit here for a while and wait
594: * for adjacent squares to clear out.
595: */
596: save_bullet(bp);
597: return;
598: }
599: if (bp->b_charge < count) {
600: /* Only bp->b_charge paths may be taken */
601: while (count > bp->b_charge) {
602: if (dirmask & WEST)
603: dirmask &= ~WEST;
604: else if (dirmask & EAST)
605: dirmask &= ~EAST;
606: else if (dirmask & NORTH)
607: dirmask &= ~NORTH;
608: else if (dirmask & SOUTH)
609: dirmask &= ~SOUTH;
610: count--;
611: }
612: }
613:
614: i = bp->b_charge / count;
615: j = bp->b_charge % count;
616: if (dirmask & WEST) {
617: count--;
618: nbp = create_shot(bp->b_type, bp->b_y, bp->b_x - 1, LEFTS,
619: i, bp->b_owner, bp->b_score, TRUE, SPACE);
620: moveslime(nbp, speed - 1);
621: }
622: if (dirmask & EAST) {
623: count--;
624: nbp = create_shot(bp->b_type, bp->b_y, bp->b_x + 1, RIGHT,
625: (count < j) ? i + 1 : i, bp->b_owner, bp->b_score,
626: TRUE, SPACE);
627: moveslime(nbp, speed - 1);
628: }
629: if (dirmask & NORTH) {
630: count--;
631: nbp = create_shot(bp->b_type, bp->b_y - 1, bp->b_x, ABOVE,
632: (count < j) ? i + 1 : i, bp->b_owner, bp->b_score,
633: TRUE, SPACE);
634: moveslime(nbp, speed - 1);
635: }
636: if (dirmask & SOUTH) {
637: count--;
638: nbp = create_shot(bp->b_type, bp->b_y + 1, bp->b_x, BELOW,
639: (count < j) ? i + 1 : i, bp->b_owner, bp->b_score,
640: TRUE, SPACE);
641: moveslime(nbp, speed - 1);
642: }
643:
644: free((char *) bp);
645: }
646:
647: /*
648: * iswall:
649: * returns whether the given location is a wall
650: */
651: iswall(y, x)
652: register int y, x;
653: {
654: if (y < 0 || x < 0 || y >= HEIGHT || x >= WIDTH)
655: return TRUE;
656: switch (Maze[y][x]) {
657: case WALL1:
658: case WALL2:
659: case WALL3:
660: # ifdef REFLECT
661: case WALL4:
662: case WALL5:
663: # endif REFLECT
664: # ifdef RANDOM
665: case DOOR:
666: # endif RANDOM
667: # ifdef VOLCANO
668: case LAVA:
669: # endif VOLCANO
670: return TRUE;
671: }
672: return FALSE;
673: }
674: # endif OOZE
675:
676: /*
677: * zapshot:
678: * Take a shot out of the air.
679: */
680: zapshot(blist, obp)
681: register BULLET *blist, *obp;
682: {
683: register BULLET *bp;
684: register FLAG explode;
685:
686: explode = FALSE;
687: for (bp = blist; bp != NULL; bp = bp->b_next) {
688: if (bp->b_x != obp->b_x || bp->b_y != obp->b_y)
689: continue;
690: if (bp->b_face == obp->b_face)
691: continue;
692: explode = TRUE;
693: break;
694: }
695: if (!explode)
696: return;
697: explshot(blist, obp->b_y, obp->b_x);
698: }
699:
700: /*
701: * explshot -
702: * Make all shots at this location blow up
703: */
704: explshot(blist, y, x)
705: register BULLET *blist;
706: register int y, x;
707: {
708: register BULLET *bp;
709:
710: for (bp = blist; bp != NULL; bp = bp->b_next)
711: if (bp->b_x == x && bp->b_y == y) {
712: bp->b_expl = TRUE;
713: if (bp->b_owner != NULL)
714: message(bp->b_owner, "Shot intercepted");
715: }
716: }
717:
718: /*
719: * play_at:
720: * Return a pointer to the player at the given location
721: */
722: PLAYER *
723: play_at(y, x)
724: register int y, x;
725: {
726: register PLAYER *pp;
727:
728: for (pp = Player; pp < End_player; pp++)
729: if (pp->p_x == x && pp->p_y == y)
730: return pp;
731: fprintf(stderr, "driver: couldn't find player at (%d,%d)\n", x, y);
732: abort();
733: /* NOTREACHED */
734: }
735:
736: /*
737: * opposite:
738: * Return TRUE if the bullet direction faces the opposite direction
739: * of the player in the maze
740: */
741: opposite(face, dir)
742: int face;
743: char dir;
744: {
745: switch (face) {
746: case LEFTS:
747: return (dir == RIGHT);
748: case RIGHT:
749: return (dir == LEFTS);
750: case ABOVE:
751: return (dir == BELOW);
752: case BELOW:
753: return (dir == ABOVE);
754: default:
755: return FALSE;
756: }
757: }
758:
759: /*
760: * is_bullet:
761: * Is there a bullet at the given coordinates? If so, return
762: * a pointer to the bullet, otherwise return NULL
763: */
764: BULLET *
765: is_bullet(y, x)
766: register int y, x;
767: {
768: register BULLET *bp;
769:
770: for (bp = Bullets; bp != NULL; bp = bp->b_next)
771: if (bp->b_y == y && bp->b_x == x)
772: return bp;
773: return NULL;
774: }
775:
776: /*
777: * fixshots:
778: * change the underlying character of the shots at a location
779: * to the given character.
780: */
781: fixshots(y, x, over)
782: register int y, x;
783: char over;
784: {
785: register BULLET *bp;
786:
787: for (bp = Bullets; bp != NULL; bp = bp->b_next)
788: if (bp->b_y == y && bp->b_x == x)
789: bp->b_over = over;
790: }
791:
792: /*
793: * find_under:
794: * find the underlying character for a bullet when it lands
795: * on another bullet.
796: */
797: find_under(blist, bp)
798: register BULLET *blist, *bp;
799: {
800: register BULLET *nbp;
801:
802: for (nbp = blist; nbp != NULL; nbp = nbp->b_next)
803: if (bp->b_y == nbp->b_y && bp->b_x == nbp->b_x) {
804: bp->b_over = nbp->b_over;
805: break;
806: }
807: }
808:
809: /*
810: * mark_player:
811: * mark a player as under a shot
812: */
813: mark_player(bp)
814: register BULLET *bp;
815: {
816: register PLAYER *pp;
817:
818: for (pp = Player; pp < End_player; pp++)
819: if (pp->p_y == bp->b_y && pp->p_x == bp->b_x) {
820: pp->p_undershot = TRUE;
821: break;
822: }
823: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.