/* Header: weapon.c,v 7.0.1.2 86/10/20 14:36:33 lwall Exp */ /* Log: weapon.c,v * Revision 7.0.1.2 86/10/20 14:36:33 lwall * Picked some lint. * * Revision 7.0.1.1 86/10/16 10:54:42 lwall * Added Damage. Fixed random bugs. * * Revision 7.0 86/10/08 15:18:08 lwall * Split into separate files. Added amoebas and pirates. * */ #include "EXTERN.h" #include "warp.h" #include "bang.h" #include "object.h" #include "move.h" #include "score.h" #include "sig.h" #include "term.h" #include "them.h" #include "us.h" #include "util.h" #include "INTERN.h" #include "weapon.h" void weapon_init(void) { ; } void fire_torp(OBJECT *from, int ydir, int xdir) { OBJECT *to; if (from->type == Enemy || (from == ent && etorp > 0) || (from == base && btorp > 0)) { to = occupant[(from->posy+from->vely+ydir+YSIZE00)%YSIZE] [(from->posx+from->velx+xdir+XSIZE00)%XSIZE]; if (from->type != Enemy || !to || to->vely || to->velx) { if (from->type != Enemy && (to = isatorp[from==base][ydir+1][xdir+1])) { to->vely += ydir; to->velx += xdir; } else { if (from == ent) { to = make_object(Torp, '+', from->posy,from->posx, from->vely+ydir,from->velx+xdir, 0L, 1L,&root); aretorps++; isatorp[0][ydir+1][xdir+1] = to; etorp--; } else if (from == base) { to = make_object(Torp, '+', from->posy,from->posx, from->vely+ydir,from->velx+xdir, 0L, 1L,&root); aretorps++; isatorp[1][ydir+1][xdir+1] = to; btorp--; } else if (from->image == 'G') { numos++; to = make_object(Torp, 'o', from->posy,from->posx, from->vely+ydir,from->velx+xdir, 100L, 1L,&root); if (madgorns) { possiblescore += 35; to->image = '0'; to->mass = 2000; to->energy = 2000; } else if (rand_mod(120)+10 > smarts) possiblescore += 100; else { possiblescore += 200; to->image = 'O'; } } else { to = make_object(Torp, 'x', from->posy,from->posx, from->vely+ydir,from->velx+xdir, 0L, 1L,&root); if (rand_mod(160)+10 > smarts) possiblescore += 10; else { possiblescore += 100; to->image = 'X'; to->mass = 1000+super*20; numxes++; } } } } } } void attack(OBJECT *attackee) { int dx; int dy; int curx; int cury; int prob; OBJECT *obj; bool torps; bool webnear = false; bool thru_stars; int nukey; int nukex; int nukedist; if (attackee) { if (attackee == nuke) { if (amb[attackee->posy][attackee->posx] != '~') return; nukey = nukex = 0; nukedist = 100; } for (dx= -1; dx<=1 ; dx++) { for (dy= -1; dy<=1; dy++) { if (dx||dy) { cury = attackee->posy; curx = attackee->posx; torps = thru_stars = false; if (massacre || madgorns || !rand_mod(53-super) ) webnear += rand_mod(2); else webnear = false; for (prob = scandist;prob;prob--) { cury = (cury + dy + YSIZE00) % YSIZE; curx = (curx + dx + XSIZE00) % XSIZE; if ((obj = occupant[cury][curx]) != NULL) { switch (obj->image) { case 'P': case 'K': case 'R': case ' ': pot_shot: if (attackee == nuke) { if (rand_mod(2+scandist-prob) < rand_mod(smarts/40+1)) tract(nuke,dy,dx,rand_mod(3)?1:-1); } if (rand_mod(51 - sm50) <= prob) { switch (obj->strategy||thru_stars?0: rand_mod(ent?4:2)) { case 1: case 2: if (-dy + attackee->vely == obj->vely && -dx + attackee->velx == obj->velx) fire_torp(obj, -dy + attackee->vely, -dx + attackee->velx); else fire_torp(obj, -dy + attackee->vely - obj->vely, -dx + attackee->velx - obj->velx); if (obj->image == ' ') setimage(obj, obj->flags & PIRATE ? 'P' : 'R'); break; case 3: { int newspeed = rand_mod(prob<5&&smarts>70?4:3)-1; obj->vely = -dy * newspeed; obj->velx = -dx * newspeed; if (newspeed >= 0 && !rand_mod(82-sm80)) { obj->vely += attackee->vely; obj->velx += attackee->velx; } break; } case 0: if (!torps && obj->energy > 1000) { fire_phaser(obj, -dy, -dx); if (smarts > 40 && (scandist-prob > 5 || attackee==base) && (massacre || obj->strategy || rand_mod(2))) while (rand_mod(2)) fire_phaser(obj, -dy, -dx); if (obj->image == ' ') setimage(obj, obj->flags&PIRATE ? 'P':'R'); } if (obj->strategy) { obj->velx = obj->vely = 0; if (obj->energy < 1000 || bvely || bvelx) obj->strategy = 0; } else if ((attackee==base || (cloaking && attackee==ent) ) && scandist-prob > 5 && !(rand_mod( ent?antibase*2:antibase)) ) obj->strategy = 1; break; } } goto bombout; case 'G': if (thru_stars && obj->strategy < 7) goto bombout; if (attackee == nuke) { if (rand_mod(2+scandist-prob) < rand_mod(smarts/40+1)) tract(nuke,dy,dx,rand_mod(3)?1:-1); goto bombout; } if (obj->strategy) { if (madgorns || !rand_mod(4)) { obj->vely = attackee->vely; obj->velx = attackee->velx; } obj->strategy += (!torps && deados > 10); if (obj->strategy > 4) madgorns = true; if (!torps && obj->strategy > 5) { do { fire_phaser(obj, -dy, -dx); } while (rand_mod(2)); } } else if (numgorns >= numenemies-1 && deados > 15+numgorns*5) obj->strategy = 1; if (madgorns || rand_mod(51 - sm50) <= prob) { if (-dy + attackee->vely == obj->vely && -dx + attackee->velx == obj->velx) fire_torp(obj, -dy + attackee->vely, -dx + attackee->velx); else fire_torp(obj, -dy + attackee->vely - obj->vely, -dx + attackee->velx - obj->velx); } goto bombout; case 'T': if (attackee == nuke) { if (rand_mod(2+scandist-prob) < rand_mod(smarts/40+1)) tract(nuke,dy,dx,rand_mod(3)?1:-1); } if (thru_stars) goto bombout; if (webnear && scandist-prob > 5) { if (massacre || rand_mod(50) < super) { if (!torps && obj->energy > 1000) { fire_phaser(obj, -dy, -dx); while (!rand_mod(57-sm55)) fire_phaser(obj, -dy, -dx); } } } goto bombout; case 'C': case 'c': if (thru_stars) goto bombout; break; case 'Q': case 'W': case 'Y': case 'U': case 'I': case 'S': case 'D': case 'H': case 'J': case 'L': case 'Z': case 'V': case 'M': case 'F': if (attackee == nuke) { if (rand_mod(2+scandist-prob) < rand_mod(smarts/40+1)) tract(nuke,dy,dx,rand_mod(3)?1:-1); if (rand_mod(2)) goto pot_shot; } if (madfriends > 1000) { madfriends -= 200; goto pot_shot; } /* FALL THROUGH */ case '+': if (attackee == nuke) { if (smarts > 70) { if ( (obj->posx + obj->velx + XSIZE00)%XSIZE == attackee->posx && (obj->posy + obj->vely + YSIZE00)%YSIZE == attackee->posy ) { tract(nuke,dy,dx,-1); } else while (!rand_mod(82-sm80)) tract(nuke,dy,dx,-1); } else if (smarts > 60 || rand_mod(2+scandist-prob) < rand_mod(smarts/20+1)) tract(nuke,dy,dx,rand_mod(3)?1:-1); } torps = false; thru_stars = false; break; case '|': case '-': case '/': case '\\': if (thru_stars) goto bombout; webnear = (scandist-prob < 3); torps = false; break; case 'x': if (attackee == nuke) { if (rand_mod(2+scandist-prob) < rand_mod(smarts/20+1)) tract(nuke,dy,dx,rand_mod(3)?1:-1); } if (thru_stars) goto bombout; torps = true; break; case 'o': case 'O': case '0': if (attackee == nuke) { if (rand_mod(2+scandist-prob) < rand_mod(smarts/20+1)) tract(nuke,dy,dx,rand_mod(3)?1:-1); } if (thru_stars) goto bombout; torps = true; if (rand_mod(99+3*scandist) < smarts+3*prob) { obj->vely = -dy + attackee->vely; obj->velx = -dx + attackee->velx; if (obj->flags & STATIC) {/* not a mover? */ obj->flags &= ~STATIC; obj->prev->next = obj->next; obj->next->prev = obj->prev; root.prev->next = obj; obj->prev = root.prev; root.prev = obj; obj->next = &root; } } if (obj->image != '0') break; /*FALLTHROUGH*/ case 'X': if (attackee == nuke) { if (rand_mod(2+scandist-prob) < rand_mod(smarts/20+1)) tract(nuke,dy,dx,rand_mod(3)?1:-1); } torps = true; if (thru_stars) goto bombout; if (prob == scandist) { int y, x; blast[y=(obj->posy+obj->vely+YSIZE00)%YSIZE] [x=(obj->posx+obj->velx+XSIZE00)%XSIZE] += (obj->image == '0' ? 2000 : 200); yblasted[y] |= 1; xblasted[x] |= 1; blasted = true; } break; case 'A': if (attackee != nuke) { if (scandist-prob>1 && !rand_mod(51-super)) tract(obj,-dy,-dx,1); } /* FALL THROUGH */ case '*': case '@': if (attackee == nuke) { if (amb[cury][curx] != '~') { if (scandist-prob < nukedist) { nukedist = scandist-prob; nukey = dy; /* nearest food in */ nukex = dx; /* this direction */ } if (smarts > 55 && scandist-prob > 8) { if (rand_mod(30+scandist-prob) < rand_mod(smarts/20+1)) tract(nuke,dy,dx,1); } } else if (obj->vely || obj->velx) { tract(nuke,dy,dx,1); /* for looks */ obj->vely = obj->velx = 0; } } if (!thru_stars) { if (rand_mod(97-sm95)) goto bombout; else thru_stars = true; } break; case '<': case '>': if (attackee == nuke) { if ((!dy && scandist-prob < 8) || rand_mod(2+scandist-prob) < rand_mod(smarts/20+1) ) { nuke->mass += 10000; tract(nuke,dy,dx,-1); nuke->mass -= 10000; } } goto bombout; case 'E': case 'B': if (attackee == nuke) { if (rand_mod(2+scandist-prob) < rand_mod(smarts/40+1)) tract(nuke,dy,dx,rand_mod(3)?1:-1); } goto bombout; default: goto bombout; } } else { if (thru_stars) goto bombout; } } bombout: ; /* end of loop */ } } } if (attackee == nuke && nukedist < 100) {/* aim amoeba at nearest */ if (nukey < 0) /* free star */ nukey = 2; if (nukex < 0) nukex = 2; nuke->strategy = nukey + (nukex << 2); } } } void fire_phaser(OBJECT *obj, int dy, int dx) { int y; int x; int skipping; int size=5000; int decr = 50, oldy, oldx; static char curchar[] = "@* "; if (obj == ent) decr = 100; else if (obj == base) { decr = 1000; size = 200; } if (!dy) curchar[2] = '-'; else if (!dx) curchar[2] = '!'; else if (dy == dx) curchar[2] = '\\'; else curchar[2] = '/'; if (obj->energy >= decr) { obj->energy -= decr; for ( /* initialize */ skipping = (obj != base), y = (obj->posy+(obj==base?dy*2:dy)+YSIZE00)%YSIZE, x = (obj->posx+(obj==base?dx*2:dx)+XSIZE00)%XSIZE; /* while */ size && (!occupant[y][x]||(skipping && occupant[y][x]->type==Star)); /* at end of loop */ y = (y+dy+YSIZE00) % YSIZE, x = (x+dx+XSIZE00) % XSIZE, size = size * 3 / 4 ) { move(y+1,x*2,0); beg_qwrite(); if (obj == base || obj->image == 'T') { *filler = '@'; qwrite(); *filler = '#'; qwrite(); *filler = '~'; qwrite(); *filler = '%'; qwrite(); *filler = ':'; qwrite(); *filler = '@'; } else { *filler = size >= 500 ? *curchar : (size >= 50 ? curchar[1] : curchar[2]); } qwrite(); if (occupant[y][x]) qaddc(occupant[y][x]->image); else { if (numamoebas) qaddc(amb[y][x]); else qaddspace(); if (skipping) skipping = 0; } end_qwrite(); } if (size) { char img; assert(occupant[y][x]); img = occupant[y][x]->image; if (occupant[y][x]->type == Crusher) { if (dy) return; if (dx==(img == '<' ? 1 : -1) ) { occupant[y][x]->image = (occupant[y][x]->velx *= -1) < 0 ? '>' : '<'; return; } } else if (occupant[y][x]->flags & FRIENDLY) madfriends += 200; if (numamoebas && amb[y][x] == '~' && smarts % 3 && (smarts > 70 || rand_mod(smarts) > rand_mod(20)) ) { if (size > 10000) modify_amoeba(y,x,1,'~',10); else if (size > 1000) modify_amoeba(y,x,1,'~',7); else if (size > 50) modify_amoeba(y,x,1,'~',5); else modify_amoeba(y,x,1,'~',2); if (occupant[y][x] == nuke) { nuke->strategy = rand_mod(30); nuke->flags |= COUNTDOWN; } return; } else { move(y+1,x*2,0); beg_qwrite(); if (img == ' ') { *filler = occupant[y][x]->flags & PIRATE ? 'P' : 'R'; occupant[y][x]->image = *filler; occupant[y][x]->strategy = 0; qwrite(); qwrite(); } else if (img == 'C' || img == 'c') { cloaked = 0; img += 2; occupant[y][x]->image = img; *filler = img; qwrite(); qwrite(); } else if (img == 'K' && size > 50) occupant[y][x]->strategy = 0; *filler = '@'; qwrite(); *filler = '#'; qwrite(); *filler = '@'; qwrite(); *filler = '#'; qwrite(); *filler = '@'; qwrite(); qaddc(img); end_qwrite(); oldy = y; oldx = x; y = (occupant[oldy][oldx]->posy + occupant[oldy][oldx]->vely + YSIZE00) % YSIZE; x = (occupant[oldy][oldx]->posx + occupant[oldy][oldx]->velx + XSIZE00) % XSIZE; if (occupant[y][x] && occupant[y][x]->type == Star) { y = occupant[oldy][oldx]->posy; x = occupant[oldy][oldx]->posx; } if (obj==base) blast[y][x] += size>50 ? 15000 : (size>15 ? 1500 : 150); else if (obj==ent) blast[y][x] += size*4; else if (obj->image=='T') blast[y][x] += 15000; else blast[y][x] += size*smarts/25; yblasted[y] |= 1; xblasted[x] |= 1; blasted = true; } } } } int tract(OBJECT *obj, int dy, int dx, int to_or_fro) { int y; int x; int size=10; static char ch; OBJECT *tractee; if (!dy) ch = '|'; else if (!dx) ch = '-'; else if (dy == dx) ch = '/'; else ch = '\\'; { for ( y = (obj->posy+dy+YSIZE00)%YSIZE, x = (obj->posx+dx+XSIZE00)%XSIZE; size && (!occupant[y][x]); y = (y+dy+YSIZE00) % YSIZE, x = (x+dx+XSIZE00) % XSIZE, size--) { move(y+1,x*2,0); beg_qwrite(); *filler = ch; qwrite(); qwrite(); if (numamoebas) qaddch(amb[y][x]); else qaddspace(); end_qwrite(); } tractee = occupant[y][x]; if (size) { assert(tractee); if (numamoebas && obj != nuke && amb[y][x] == '~') { if (to_or_fro > 0) modify_amoeba(y,x,2,'~',size); else modify_amoeba(y,x,1,' ',size); } if (tractee->type != Web && (tractee->mass < obj->mass * 5 || (tractee->type == Crusher && !dx) ) ) { if (tractee == ent) { evely -= dy * to_or_fro; evelx -= dx * to_or_fro; } else if (tractee == base) { bvely -= dy * to_or_fro; bvelx -= dx * to_or_fro; } else { tractee->vely -= dy * to_or_fro; tractee->velx -= dx * to_or_fro; } if (tractee->type == Torp || tractee->type == Star) { if (tractee->flags & STATIC) { /* not a mover? */ tractee->flags &= ~STATIC; tractee->prev->next = tractee->next; tractee->next->prev = tractee->prev; root.prev->next = tractee; tractee->prev = root.prev; root.prev = tractee; tractee->next = &root; } } } else if (tractee->type == Crusher && !dy && dx==(tractee->image == '<' ? 1 : -1) ) { setimage(tractee, (tractee->velx *= -1) < 0 ? '>' : '<'); } if (tractee->mass * 5 > obj->mass) return(1); } } return(0); }