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