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