]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - warp/weapon.c
cgram: use ASCII-only implementation of <ctype.h> functions
[bsdgames-darwin.git] / warp / weapon.c
1 /* Header: weapon.c,v 7.0.1.2 86/10/20 14:36:33 lwall Exp */
2
3 /* Log: weapon.c,v
4 * Revision 7.0.1.2 86/10/20 14:36:33 lwall
5 * Picked some lint.
6 *
7 * Revision 7.0.1.1 86/10/16 10:54:42 lwall
8 * Added Damage. Fixed random bugs.
9 *
10 * Revision 7.0 86/10/08 15:18:08 lwall
11 * Split into separate files. Added amoebas and pirates.
12 *
13 */
14
15 #include "EXTERN.h"
16 #include "warp.h"
17 #include "bang.h"
18 #include "object.h"
19 #include "move.h"
20 #include "score.h"
21 #include "sig.h"
22 #include "term.h"
23 #include "them.h"
24 #include "us.h"
25 #include "util.h"
26 #include "INTERN.h"
27 #include "weapon.h"
28
29 void
30 weapon_init(void)
31 {
32 ;
33 }
34
35 void
36 fire_torp(OBJECT *from, int ydir, int xdir)
37 {
38 OBJECT *to;
39
40 if (from->type == Enemy ||
41 (from == ent && etorp > 0) ||
42 (from == base && btorp > 0)) {
43 to = occupant[(from->posy+from->vely+ydir+YSIZE00)%YSIZE]
44 [(from->posx+from->velx+xdir+XSIZE00)%XSIZE];
45 if (from->type != Enemy || !to || to->vely || to->velx) {
46 if (from->type != Enemy &&
47 (to = isatorp[from==base][ydir+1][xdir+1])) {
48 to->vely += ydir;
49 to->velx += xdir;
50 }
51 else {
52 if (from == ent) {
53 to = make_object(Torp, '+', from->posy,from->posx,
54 from->vely+ydir,from->velx+xdir, 0L, 1L,&root);
55 aretorps++;
56 isatorp[0][ydir+1][xdir+1] = to;
57 etorp--;
58 }
59 else if (from == base) {
60 to = make_object(Torp, '+', from->posy,from->posx,
61 from->vely+ydir,from->velx+xdir, 0L, 1L,&root);
62 aretorps++;
63 isatorp[1][ydir+1][xdir+1] = to;
64 btorp--;
65 }
66 else if (from->image == 'G') {
67 numos++;
68 to = make_object(Torp, 'o', from->posy,from->posx,
69 from->vely+ydir,from->velx+xdir, 100L, 1L,&root);
70 if (madgorns) {
71 possiblescore += 35;
72 to->image = '0';
73 to->mass = 2000;
74 to->energy = 2000;
75 }
76 else if (rand_mod(120)+10 > smarts)
77 possiblescore += 100;
78 else {
79 possiblescore += 200;
80 to->image = 'O';
81 }
82 }
83 else {
84 to = make_object(Torp, 'x', from->posy,from->posx,
85 from->vely+ydir,from->velx+xdir, 0L, 1L,&root);
86 if (rand_mod(160)+10 > smarts)
87 possiblescore += 10;
88 else {
89 possiblescore += 100;
90 to->image = 'X';
91 to->mass = 1000+super*20;
92 numxes++;
93 }
94 }
95 }
96 }
97 }
98 }
99
100 void
101 attack(OBJECT *attackee)
102 {
103 int dx;
104 int dy;
105 int curx;
106 int cury;
107 int prob;
108 OBJECT *obj;
109 bool torps;
110 bool webnear = false;
111 bool thru_stars;
112 int nukey;
113 int nukex;
114 int nukedist;
115
116 if (attackee) {
117 if (attackee == nuke) {
118 if (amb[attackee->posy][attackee->posx] != '~')
119 return;
120 nukey = nukex = 0;
121 nukedist = 100;
122 }
123 for (dx= -1; dx<=1 ; dx++) {
124 for (dy= -1; dy<=1; dy++) {
125 if (dx||dy) {
126 cury = attackee->posy;
127 curx = attackee->posx;
128 torps = thru_stars = false;
129 if (massacre || madgorns || !rand_mod(53-super) )
130 webnear += rand_mod(2);
131 else
132 webnear = false;
133 for (prob = scandist;prob;prob--) {
134 cury = (cury + dy + YSIZE00) % YSIZE;
135 curx = (curx + dx + XSIZE00) % XSIZE;
136 if ((obj = occupant[cury][curx]) != NULL) {
137 switch (obj->image) {
138 case 'P': case 'K': case 'R': case ' ':
139 pot_shot:
140 if (attackee == nuke) {
141 if (rand_mod(2+scandist-prob) <
142 rand_mod(smarts/40+1))
143 tract(nuke,dy,dx,rand_mod(3)?1:-1);
144 }
145 if (rand_mod(51 - sm50) <= prob) {
146 switch (obj->strategy||thru_stars?0:
147 rand_mod(ent?4:2)) {
148 case 1: case 2:
149 if (-dy + attackee->vely == obj->vely
150 && -dx + attackee->velx == obj->velx)
151 fire_torp(obj,
152 -dy + attackee->vely,
153 -dx + attackee->velx);
154 else
155 fire_torp(obj,
156 -dy + attackee->vely - obj->vely,
157 -dx + attackee->velx - obj->velx);
158 if (obj->image == ' ')
159 setimage(obj,
160 obj->flags & PIRATE ? 'P' : 'R');
161 break;
162 case 3: {
163 int newspeed =
164 rand_mod(prob<5&&smarts>70?4:3)-1;
165
166 obj->vely = -dy * newspeed;
167 obj->velx = -dx * newspeed;
168 if (newspeed >= 0 &&
169 !rand_mod(82-sm80)) {
170 obj->vely += attackee->vely;
171 obj->velx += attackee->velx;
172 }
173 break;
174 }
175 case 0:
176 if (!torps && obj->energy > 1000) {
177 fire_phaser(obj, -dy, -dx);
178 if (smarts > 40 &&
179 (scandist-prob > 5
180 || attackee==base) &&
181 (massacre || obj->strategy ||
182 rand_mod(2)))
183 while (rand_mod(2))
184 fire_phaser(obj, -dy, -dx);
185 if (obj->image == ' ')
186 setimage(obj,
187 obj->flags&PIRATE ? 'P':'R');
188 }
189 if (obj->strategy) {
190 obj->velx = obj->vely = 0;
191 if (obj->energy < 1000 ||
192 bvely || bvelx)
193 obj->strategy = 0;
194 }
195 else if ((attackee==base ||
196 (cloaking && attackee==ent)
197 ) &&
198 scandist-prob > 5 &&
199 !(rand_mod(
200 ent?antibase*2:antibase)) )
201 obj->strategy = 1;
202 break;
203 }
204 }
205 goto bombout;
206 case 'G':
207 if (thru_stars && obj->strategy < 7)
208 goto bombout;
209 if (attackee == nuke) {
210 if (rand_mod(2+scandist-prob) <
211 rand_mod(smarts/40+1))
212 tract(nuke,dy,dx,rand_mod(3)?1:-1);
213 goto bombout;
214 }
215 if (obj->strategy) {
216 if (madgorns || !rand_mod(4)) {
217 obj->vely = attackee->vely;
218 obj->velx = attackee->velx;
219 }
220 obj->strategy += (!torps && deados > 10);
221 if (obj->strategy > 4)
222 madgorns = true;
223 if (!torps && obj->strategy > 5) {
224 do {
225 fire_phaser(obj, -dy, -dx);
226 } while (rand_mod(2));
227 }
228 }
229 else if (numgorns >= numenemies-1 &&
230 deados > 15+numgorns*5)
231 obj->strategy = 1;
232 if (madgorns || rand_mod(51 - sm50) <= prob) {
233 if (-dy + attackee->vely == obj->vely
234 && -dx + attackee->velx == obj->velx)
235 fire_torp(obj,
236 -dy + attackee->vely,
237 -dx + attackee->velx);
238 else
239 fire_torp(obj,
240 -dy + attackee->vely - obj->vely,
241 -dx + attackee->velx - obj->velx);
242 }
243 goto bombout;
244 case 'T':
245 if (attackee == nuke) {
246 if (rand_mod(2+scandist-prob) <
247 rand_mod(smarts/40+1))
248 tract(nuke,dy,dx,rand_mod(3)?1:-1);
249 }
250 if (thru_stars)
251 goto bombout;
252 if (webnear && scandist-prob > 5) {
253 if (massacre || rand_mod(50) < super) {
254 if (!torps && obj->energy > 1000) {
255 fire_phaser(obj, -dy, -dx);
256 while (!rand_mod(57-sm55))
257 fire_phaser(obj, -dy, -dx);
258 }
259 }
260 }
261 goto bombout;
262 case 'C': case 'c':
263 if (thru_stars)
264 goto bombout;
265 break;
266 case 'Q': case 'W': case 'Y': case 'U':
267 case 'I': case 'S': case 'D': case 'H': case 'J':
268 case 'L': case 'Z': case 'V': case 'M': case 'F':
269 if (attackee == nuke) {
270 if (rand_mod(2+scandist-prob) <
271 rand_mod(smarts/40+1))
272 tract(nuke,dy,dx,rand_mod(3)?1:-1);
273 if (rand_mod(2))
274 goto pot_shot;
275 }
276 if (madfriends > 1000) {
277 madfriends -= 200;
278 goto pot_shot;
279 }
280 /* FALL THROUGH */
281 case '+':
282 if (attackee == nuke) {
283 if (smarts > 70) {
284 if (
285 (obj->posx + obj->velx + XSIZE00)%XSIZE
286 == attackee->posx &&
287 (obj->posy + obj->vely + YSIZE00)%YSIZE
288 == attackee->posy ) {
289 tract(nuke,dy,dx,-1);
290 }
291 else
292 while (!rand_mod(82-sm80))
293 tract(nuke,dy,dx,-1);
294 }
295 else if (smarts > 60 ||
296 rand_mod(2+scandist-prob) <
297 rand_mod(smarts/20+1))
298 tract(nuke,dy,dx,rand_mod(3)?1:-1);
299 }
300 torps = false;
301 thru_stars = false;
302 break;
303 case '|': case '-': case '/': case '\\':
304 if (thru_stars)
305 goto bombout;
306 webnear = (scandist-prob < 3);
307 torps = false;
308 break;
309 case 'x':
310 if (attackee == nuke) {
311 if (rand_mod(2+scandist-prob) <
312 rand_mod(smarts/20+1))
313 tract(nuke,dy,dx,rand_mod(3)?1:-1);
314 }
315 if (thru_stars)
316 goto bombout;
317 torps = true;
318 break;
319 case 'o': case 'O': case '0':
320 if (attackee == nuke) {
321 if (rand_mod(2+scandist-prob) <
322 rand_mod(smarts/20+1))
323 tract(nuke,dy,dx,rand_mod(3)?1:-1);
324 }
325 if (thru_stars)
326 goto bombout;
327 torps = true;
328 if (rand_mod(99+3*scandist) < smarts+3*prob) {
329 obj->vely = -dy + attackee->vely;
330 obj->velx = -dx + attackee->velx;
331 if (obj->flags & STATIC) {/* not a mover? */
332 obj->flags &= ~STATIC;
333 obj->prev->next = obj->next;
334 obj->next->prev = obj->prev;
335 root.prev->next = obj;
336 obj->prev = root.prev;
337 root.prev = obj;
338 obj->next = &root;
339 }
340 }
341 if (obj->image != '0')
342 break;
343 /*FALLTHROUGH*/
344 case 'X':
345 if (attackee == nuke) {
346 if (rand_mod(2+scandist-prob) <
347 rand_mod(smarts/20+1))
348 tract(nuke,dy,dx,rand_mod(3)?1:-1);
349 }
350 torps = true;
351 if (thru_stars)
352 goto bombout;
353 if (prob == scandist) {
354 int y, x;
355
356 blast[y=(obj->posy+obj->vely+YSIZE00)%YSIZE]
357 [x=(obj->posx+obj->velx+XSIZE00)%XSIZE]
358 += (obj->image == '0' ? 2000 : 200);
359 yblasted[y] |= 1;
360 xblasted[x] |= 1;
361 blasted = true;
362 }
363 break;
364 case 'A':
365 if (attackee != nuke) {
366 if (scandist-prob>1 && !rand_mod(51-super))
367 tract(obj,-dy,-dx,1);
368 }
369 /* FALL THROUGH */
370 case '*': case '@':
371 if (attackee == nuke) {
372 if (amb[cury][curx] != '~') {
373 if (scandist-prob < nukedist) {
374 nukedist = scandist-prob;
375 nukey = dy; /* nearest food in */
376 nukex = dx; /* this direction */
377 }
378 if (smarts > 55 && scandist-prob > 8) {
379 if (rand_mod(30+scandist-prob) <
380 rand_mod(smarts/20+1))
381 tract(nuke,dy,dx,1);
382 }
383 }
384 else if (obj->vely || obj->velx) {
385 tract(nuke,dy,dx,1); /* for looks */
386 obj->vely = obj->velx = 0;
387 }
388 }
389 if (!thru_stars) {
390 if (rand_mod(97-sm95))
391 goto bombout;
392 else
393 thru_stars = true;
394 }
395 break;
396 case '<': case '>':
397 if (attackee == nuke) {
398 if ((!dy && scandist-prob < 8) ||
399 rand_mod(2+scandist-prob) <
400 rand_mod(smarts/20+1) ) {
401 nuke->mass += 10000;
402 tract(nuke,dy,dx,-1);
403 nuke->mass -= 10000;
404 }
405 }
406 goto bombout;
407 case 'E': case 'B':
408 if (attackee == nuke) {
409 if (rand_mod(2+scandist-prob) <
410 rand_mod(smarts/40+1))
411 tract(nuke,dy,dx,rand_mod(3)?1:-1);
412 }
413 goto bombout;
414 default:
415 goto bombout;
416 }
417 }
418 else {
419 if (thru_stars)
420 goto bombout;
421 }
422 }
423 bombout: ; /* end of loop */
424 }
425 }
426 }
427 if (attackee == nuke && nukedist < 100) {/* aim amoeba at nearest */
428 if (nukey < 0) /* free star */
429 nukey = 2;
430 if (nukex < 0)
431 nukex = 2;
432 nuke->strategy = nukey + (nukex << 2);
433 }
434 }
435 }
436
437 void
438 fire_phaser(OBJECT *obj, int dy, int dx)
439 {
440 int y;
441 int x;
442 int skipping;
443 int size=5000;
444 int decr = 50, oldy, oldx;
445 static char curchar[] = "@* ";
446
447 if (obj == ent)
448 decr = 100;
449 else if (obj == base) {
450 decr = 1000;
451 size = 200;
452 }
453 if (!dy)
454 curchar[2] = '-';
455 else if (!dx)
456 curchar[2] = '!';
457 else if (dy == dx)
458 curchar[2] = '\\';
459 else
460 curchar[2] = '/';
461 if (obj->energy >= decr) {
462 obj->energy -= decr;
463 for (
464 /* initialize */
465 skipping = (obj != base),
466 y = (obj->posy+(obj==base?dy*2:dy)+YSIZE00)%YSIZE,
467 x = (obj->posx+(obj==base?dx*2:dx)+XSIZE00)%XSIZE;
468 /* while */
469 size && (!occupant[y][x]||(skipping && occupant[y][x]->type==Star));
470 /* at end of loop */
471 y = (y+dy+YSIZE00) % YSIZE,
472 x = (x+dx+XSIZE00) % XSIZE,
473 size = size * 3 / 4 ) {
474 move(y+1,x*2,0);
475 beg_qwrite();
476 if (obj == base || obj->image == 'T') {
477 *filler = '@';
478 qwrite();
479 *filler = '#';
480 qwrite();
481 *filler = '~';
482 qwrite();
483 *filler = '%';
484 qwrite();
485 *filler = ':';
486 qwrite();
487 *filler = '@';
488 }
489 else {
490 *filler = size >= 500 ?
491 *curchar : (size >= 50 ?
492 curchar[1] :
493 curchar[2]);
494 }
495 qwrite();
496 if (occupant[y][x])
497 qaddc(occupant[y][x]->image);
498 else {
499 if (numamoebas)
500 qaddc(amb[y][x]);
501 else
502 qaddspace();
503 if (skipping)
504 skipping = 0;
505 }
506 end_qwrite();
507 }
508 if (size) {
509 char img;
510
511 assert(occupant[y][x]);
512 img = occupant[y][x]->image;
513 if (occupant[y][x]->type == Crusher) {
514 if (dy)
515 return;
516 if (dx==(img == '<' ? 1 : -1) ) {
517 occupant[y][x]->image =
518 (occupant[y][x]->velx *= -1) < 0 ? '>' : '<';
519 return;
520 }
521 }
522 else if (occupant[y][x]->flags & FRIENDLY)
523 madfriends += 200;
524 if (numamoebas && amb[y][x] == '~' && smarts % 3 &&
525 (smarts > 70 || rand_mod(smarts) > rand_mod(20)) ) {
526 if (size > 10000)
527 modify_amoeba(y,x,1,'~',10);
528 else if (size > 1000)
529 modify_amoeba(y,x,1,'~',7);
530 else if (size > 50)
531 modify_amoeba(y,x,1,'~',5);
532 else
533 modify_amoeba(y,x,1,'~',2);
534 if (occupant[y][x] == nuke) {
535 nuke->strategy = rand_mod(30);
536 nuke->flags |= COUNTDOWN;
537 }
538 return;
539 }
540 else {
541 move(y+1,x*2,0);
542 beg_qwrite();
543 if (img == ' ') {
544 *filler = occupant[y][x]->flags & PIRATE ? 'P' : 'R';
545 occupant[y][x]->image = *filler;
546 occupant[y][x]->strategy = 0;
547 qwrite();
548 qwrite();
549 }
550 else if (img == 'C' || img == 'c') {
551 cloaked = 0;
552 img += 2;
553 occupant[y][x]->image = img;
554 *filler = img;
555 qwrite();
556 qwrite();
557 }
558 else if (img == 'K' && size > 50)
559 occupant[y][x]->strategy = 0;
560 *filler = '@';
561 qwrite();
562 *filler = '#';
563 qwrite();
564 *filler = '@';
565 qwrite();
566 *filler = '#';
567 qwrite();
568 *filler = '@';
569 qwrite();
570 qaddc(img);
571 end_qwrite();
572 oldy = y;
573 oldx = x;
574 y = (occupant[oldy][oldx]->posy + occupant[oldy][oldx]->vely +
575 YSIZE00) % YSIZE;
576 x = (occupant[oldy][oldx]->posx + occupant[oldy][oldx]->velx +
577 XSIZE00) % XSIZE;
578 if (occupant[y][x] && occupant[y][x]->type == Star) {
579 y = occupant[oldy][oldx]->posy;
580 x = occupant[oldy][oldx]->posx;
581 }
582 if (obj==base)
583 blast[y][x] += size>50 ? 15000 : (size>15 ? 1500 : 150);
584 else if (obj==ent)
585 blast[y][x] += size*4;
586 else if (obj->image=='T')
587 blast[y][x] += 15000;
588 else
589 blast[y][x] += size*smarts/25;
590 yblasted[y] |= 1;
591 xblasted[x] |= 1;
592 blasted = true;
593 }
594 }
595 }
596 }
597
598 int
599 tract(OBJECT *obj, int dy, int dx, int to_or_fro)
600 {
601 int y;
602 int x;
603 int size=10;
604 static char ch;
605 OBJECT *tractee;
606
607 if (!dy)
608 ch = '|';
609 else if (!dx)
610 ch = '-';
611 else if (dy == dx)
612 ch = '/';
613 else
614 ch = '\\';
615 {
616 for (
617 y = (obj->posy+dy+YSIZE00)%YSIZE,
618 x = (obj->posx+dx+XSIZE00)%XSIZE;
619 size && (!occupant[y][x]);
620 y = (y+dy+YSIZE00) % YSIZE, x = (x+dx+XSIZE00) % XSIZE, size--) {
621 move(y+1,x*2,0);
622 beg_qwrite();
623 *filler = ch;
624 qwrite();
625 qwrite();
626 if (numamoebas)
627 qaddch(amb[y][x]);
628 else
629 qaddspace();
630 end_qwrite();
631 }
632 tractee = occupant[y][x];
633 if (size) {
634 assert(tractee);
635 if (numamoebas && obj != nuke && amb[y][x] == '~') {
636 if (to_or_fro > 0)
637 modify_amoeba(y,x,2,'~',size);
638 else
639 modify_amoeba(y,x,1,' ',size);
640 }
641 if (tractee->type != Web &&
642 (tractee->mass < obj->mass * 5 ||
643 (tractee->type == Crusher && !dx) ) ) {
644 if (tractee == ent) {
645 evely -= dy * to_or_fro;
646 evelx -= dx * to_or_fro;
647 }
648 else if (tractee == base) {
649 bvely -= dy * to_or_fro;
650 bvelx -= dx * to_or_fro;
651 }
652 else {
653 tractee->vely -= dy * to_or_fro;
654 tractee->velx -= dx * to_or_fro;
655 }
656 if (tractee->type == Torp ||
657 tractee->type == Star) {
658 if (tractee->flags & STATIC) { /* not a mover? */
659 tractee->flags &= ~STATIC;
660 tractee->prev->next = tractee->next;
661 tractee->next->prev = tractee->prev;
662 root.prev->next = tractee;
663 tractee->prev = root.prev;
664 root.prev = tractee;
665 tractee->next = &root;
666 }
667 }
668 }
669 else if (tractee->type == Crusher && !dy &&
670 dx==(tractee->image == '<' ? 1 : -1) ) {
671 setimage(tractee, (tractee->velx *= -1) < 0 ? '>' : '<');
672 }
673 if (tractee->mass * 5 > obj->mass)
674 return(1);
675 }
676 }
677 return(0);
678 }