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