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