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 } 679