static struct monst * bchit(int ddx, int ddy, int range, char sym) { struct monst *mtmp = (struct monst *) 0; int bchx = u.ux, bchy = u.uy; if(sym) Tmp_at(-1, sym); /* open call */ while(range--) { bchx += ddx; bchy += ddy; if ((mtmp = m_at(bchx,bchy))) break; if(!ZAP_POS(levl[bchx][bchy].typ)) { bchx -= ddx; bchy -= ddy; break; } if(sym) Tmp_at(bchx, bchy); } if(sym) Tmp_at(-1, -1); return(mtmp); }
struct monst * boomhit(int dx, int dy) { int i, ct; struct monst *mtmp; char sym = ')'; bhitpos.x = u.ux; bhitpos.y = u.uy; for (i = 0; i < 8; i++) if (xdir[i] == dx && ydir[i] == dy) break; tmp_at(-1, sym); /* open call */ for (ct = 0; ct < 10; ct++) { if (i == 8) i = 0; sym = ')' + '(' - sym; tmp_at(-2, sym); /* change let call */ dx = xdir[i]; dy = ydir[i]; bhitpos.x += dx; bhitpos.y += dy; if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != NULL) { tmp_at(-1, -1); return (mtmp); } if (!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ)) { bhitpos.x -= dx; bhitpos.y -= dy; break; } if (bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */ if (rn2(20) >= 10 + u.ulevel) { /* we hit ourselves */ thitu(10, rnd(10), "boomerang"); break; } else { /* we catch it */ tmp_at(-1, -1); pline("Skillfully, you catch the boomerang."); return (&youmonst); } } tmp_at(bhitpos.x, bhitpos.y); if (ct % 5 != 0) i++; } tmp_at(-1, -1); /* do not leave last symbol */ return (0); }
/* ddx, ddy, range: direction and range * sym: symbol displayed on path * fhitm, fhito: fns called when mon/obj hit * obj: 2nd arg to fhitm/fhito */ struct monst * bhit(int ddx, int ddy, int range, char sym, void (*fhitm)(struct monst *, struct obj *), bool (*fhito)(struct obj *, struct obj *), struct obj *obj) { struct monst *mtmp; struct obj *otmp; int typ; bhitpos.x = u.ux; bhitpos.y = u.uy; if (sym) /* open call */ tmp_at(-1, sym); while (range-- > 0) { bhitpos.x += ddx; bhitpos.y += ddy; typ = levl[bhitpos.x][bhitpos.y].typ; if ((mtmp = m_at(bhitpos.x, bhitpos.y))) { if (sym) { tmp_at(-1, -1); /* close call */ return (mtmp); } (*fhitm)(mtmp, obj); range -= 3; } if (fhito && (otmp = o_at(bhitpos.x, bhitpos.y))) { if ((*fhito)(otmp, obj)) range--; } if (!ZAP_POS(typ)) { bhitpos.x -= ddx; bhitpos.y -= ddy; break; } if (sym) tmp_at(bhitpos.x, bhitpos.y); } /* leave last symbol unless in a pool */ if (sym) tmp_at(-1, (levl[bhitpos.x][bhitpos.y].typ == POOL) ? -1 : 0); return (0); }
int gd_move() { int x,y,dx,dy,gx,gy,nx,ny,typ; struct fakecorridor *fcp; struct rm *crm; if(!guard || gdlevel != dlevel){ impossible("Where is the guard?"); return(2); /* died */ } if(u.ugold || goldincorridor()) return(0); /* didnt move */ if(dist(guard->mx,guard->my) > 1 || EGD->gddone) { restfakecorr(); return(0); /* didnt move */ } x = guard->mx; y = guard->my; /* look around (hor & vert only) for accessible places */ for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++) { if(nx == x || ny == y) if(nx != x || ny != y) if(isok(nx,ny)) if(!IS_WALL(typ = (crm = &levl[nx][ny])->typ) && typ != POOL) { int i; for(i = EGD->fcbeg; i < EGD->fcend; i++) if(EGD->fakecorr[i].fx == nx && EGD->fakecorr[i].fy == ny) goto nextnxy; if((i = inroom(nx,ny)) >= 0 && rooms[i].rtype == VAULT) goto nextnxy; /* seems we found a good place to leave him alone */ EGD->gddone = 1; if(ACCESSIBLE(typ)) goto newpos; crm->typ = (typ == SCORR) ? CORR : DOOR; goto proceed; } nextnxy: ; } nx = x; ny = y; gx = EGD->gdx; gy = EGD->gdy; dx = (gx > x) ? 1 : (gx < x) ? -1 : 0; dy = (gy > y) ? 1 : (gy < y) ? -1 : 0; if(abs(gx-x) >= abs(gy-y)) nx += dx; else ny += dy; while((typ = (crm = &levl[nx][ny])->typ) != 0) { /* in view of the above we must have IS_WALL(typ) or typ == POOL */ /* must be a wall here */ if(isok(nx+nx-x,ny+ny-y) && typ != POOL && ZAP_POS(levl[nx+nx-x][ny+ny-y].typ)){ crm->typ = DOOR; goto proceed; } if(dy && nx != x) { nx = x; ny = y+dy; continue; } if(dx && ny != y) { ny = y; nx = x+dx; dy = 0; continue; } /* I don't like this, but ... */ crm->typ = DOOR; goto proceed; } crm->typ = CORR; proceed: if(cansee(nx,ny)) { mnewsym(nx,ny); prl(nx,ny); } fcp = &(EGD->fakecorr[EGD->fcend]); if(EGD->fcend++ == FCSIZ) panic("fakecorr overflow"); fcp->fx = nx; fcp->fy = ny; fcp->ftyp = typ; newpos: if(EGD->gddone) nx = ny = 0; guard->mx = nx; guard->my = ny; pmon(guard); restfakecorr(); return(1); }
/* called with dx = dy = 0 with vertical bolts */ void buzz(int type, xchar sx, xchar sy, int dx, int dy) { int abstype = abs(type); const char *fltxt = (type == -1) ? "blaze of fire" : fl[abstype]; struct rm *lev; xchar range; struct monst *mon; if(u.uswallow) { int tmp; if(type < 0) return; tmp = zhit(u.ustuck, type); pline("The %s rips into %s%s", fltxt, monnam(u.ustuck), exclam(tmp)); return; } if(type < 0) pru(); range = rn1(7,7); Tmp_at(-1, dirlet(dx,dy)); /* open call */ while(range-- > 0) { sx += dx; sy += dy; if((lev = &levl[sx][sy])->typ) Tmp_at(sx,sy); else { int bounce = 0; if(cansee(sx-dx,sy-dy)) pline("The %s bounces!", fltxt); if(ZAP_POS(levl[sx][sy-dy].typ)) bounce = 1; if(ZAP_POS(levl[sx-dx][sy].typ)) { if(!bounce || rn2(2)) bounce = 2; } switch(bounce){ case 0: dx = -dx; dy = -dy; continue; case 1: dy = -dy; sx -= dx; break; case 2: dx = -dx; sy -= dy; break; } Tmp_at(-2,dirlet(dx,dy)); continue; } if(lev->typ == POOL && abstype == 1 /* fire */) { range -= 3; lev->typ = ROOM; if(cansee(sx,sy)) { mnewsym(sx,sy); pline("The water evaporates."); } else pline("You hear a hissing sound."); } if((mon = m_at(sx,sy)) && (type != -1 || mon->data->mlet != 'D')) { wakeup(mon); if(rnd(20) < 18 + mon->data->ac) { int tmp = zhit(mon,abstype); if(mon->mhp < 1) { if(type < 0) { if(cansee(mon->mx,mon->my)) pline("%s is killed by the %s!", Monnam(mon), fltxt); mondied(mon); } else killed(mon); } else hit(fltxt, mon, exclam(tmp)); range -= 2; } else miss(fltxt,mon); } else if(sx == u.ux && sy == u.uy) { nomul(0); if(rnd(20) < 18+u.uac) { int dam = 0; range -= 2; pline("The %s hits you!",fltxt); switch(abstype) { case 0: dam = d(2,6); break; case 1: if(Fire_resistance) pline("You don't feel hot!"); else dam = d(6,6); if(!rn2(3)) burn_scrolls(); break; case 2: nomul(-rnd(25)); /* sleep ray */ break; case 3: if(Cold_resistance) pline("You don't feel cold!"); else dam = d(6,6); break; case 4: u.uhp = -1; } losehp(dam,fltxt); } else pline("The %s whizzes by you!",fltxt); stop_occupation(); } if(!ZAP_POS(lev->typ)) { int bounce = 0, rmn; if(cansee(sx,sy)) pline("The %s bounces!",fltxt); range--; if(!dx || !dy || !rn2(20)){ dx = -dx; dy = -dy; } else { if(ZAP_POS(rmn = levl[sx][sy-dy].typ) && (IS_ROOM(rmn) || ZAP_POS(levl[sx+dx][sy-dy].typ))) bounce = 1; if(ZAP_POS(rmn = levl[sx-dx][sy].typ) && (IS_ROOM(rmn) || ZAP_POS(levl[sx-dx][sy+dy].typ))) if(!bounce || rn2(2)) bounce = 2; switch(bounce){ case 0: dy = -dy; dx = -dx; break; case 1: dy = -dy; break; case 2: dx = -dx; break; } Tmp_at(-2, dirlet(dx,dy)); } } } Tmp_at(-1,-1); }
/* Is a monster willing to fire with a compass beam in a given direction? Returns TRUE and sets *mdef to a monster if there's a monster it wants to target (and no monster it doesn't want to attack). *mdef can be &youmonst. If mdef is non-NULL, also set the tbx/tby globals for backwards compatibility (clobbered on a *mdef == NULL return, appropriately otherwise). TODO: get rid of these, they're really spaghetti. Returns TRUE and sets *mdef to NULL if there's no reason it wants to fire in that direction, but no reason it dislikes firing in that direction either. Returns FALSE if the monster refuses to fire in that direction. In this case, *mdef will be a monster that we don't want to target (possibly &youmonst). helpful determines whether or not a beam gives a positive effect */ boolean m_beam_ok(struct monst *magr, int dx, int dy, struct monst **mdef, boolean helpful) { int x = magr->mx; int y = magr->my; int i; struct monst *mat; if (mdef) *mdef = NULL; for (i = 0; i < BOLT_LIM; i++) { x += dx; y += dy; /* Will the beam stop at this point? As usual, assume that monsters have perfect knowledge of the level layout. */ if (!isok(x, y) || !ZAP_POS(level->locations[x][y].typ) || closed_door(level, x, y)) break; /* Will the monster think that the beam will hit the player? Does it care? Hostiles like to attack the player; peacefuls don't want to. Pets have perfect knowledge of their master's location even if they can't sense their master. Confused monsters can't aim a beam at the player (or to avoid the player); no monster can hit an engulfed player with a beam. */ if ((x == magr->mux && y == magr->muy && msensem(magr, &youmonst)) || (magr->mtame && x == u.ux && y == u.uy)) { if (!Engulfed && !magr->mconf) { if (mdef) { *mdef = &youmonst; tbx = x - magr->mx; tby = y - magr->my; } if (!Conflict) { if ((!helpful && magr->mpeaceful) || (helpful && !magr->mpeaceful)) return FALSE; } } } mat = m_at(level, x, y); /* special case: make sure we don't hit the quest leader with stray beams, as it can make the game unwinnable; do this regardless of LOS or hostility or Conflict or confusion or anything like that */ if (mat && mat->data->msound == MS_LEADER && !helpful) { if (mdef) *mdef = mat; return FALSE; } /* Confused monsters aren't trying to target anything in particular, because they don't have full control of their actions. Monsters won't intentionally aim at or to avoid a monster they can't see (apart from the above MS_LEADER case). */ if (mat && (msensem(magr, mat) & ~MSENSE_ITEMMIMIC) && !magr->mconf) { /* Note: the couldsee() here is an LOE check and has nothing to do with vision; it determines conflict radius */ if (Conflict && !resist(magr, RING_CLASS, 0, 0) && couldsee(magr->mx, magr->my) && distu(magr->mx, magr->my) <= BOLT_LIM * BOLT_LIM) { /* we're conflicted, anything is a valid target */ if (mdef) { *mdef = mat; tbx = x - magr->mx; tby = y - magr->my; } } else if (mm_aggression(magr, mat) & ALLOW_M && !helpful) { /* we want to target this monster */ if (mdef) { *mdef = mat; tbx = x - magr->mx; tby = y - magr->my; } } else if (!helpful && (magr->mpeaceful || mat->mpeaceful)) { /* we don't want to attack this monster; peacefuls (including pets) should avoid collateral damage; also handles the pet_attacks_up_to_difficulty checks; symmetrised so that hostiles won't attack pets who won't attack them */ if (mdef) *mdef = mat; return FALSE; } else if (helpful && ((magr->mpeaceful && mat->mpeaceful) || (!magr->mpeaceful && !mat->mpeaceful))) { /* helpful beam, hostile-hostile or peaceful/tame-peaceful/tame is OK; the peaceful checks aren't redundant with above since pet_attacks_up_to_difficulty is a thing */ if (mdef) { *mdef = mat; tbx = x - magr->mx; tby = y - magr->my; } } } } return TRUE; }
/* returns number of scattered objects */ long scatter(int sx, int sy, /* location of objects to scatter */ int blastforce, /* force behind the scattering */ unsigned int scflags, struct obj *obj) { /* only scatter this obj */ struct obj *otmp; struct level *lev = obj ? obj->olev : level; int tmp; int farthest = 0; uchar typ; long qtmp; boolean used_up; boolean individual_object = obj ? TRUE : FALSE; struct monst *mtmp; struct scatter_chain *stmp, *stmp2 = 0; struct scatter_chain *schain = NULL; long total = 0L; boolean visible = (lev == level && cansee(sx, sy)); while ((otmp = individual_object ? obj : lev->objects[sx][sy]) != 0) { if (otmp->quan > 1L) { qtmp = otmp->quan - 1; if (qtmp > LARGEST_INT) qtmp = LARGEST_INT; qtmp = (long)rnd((int)qtmp); otmp = splitobj(otmp, qtmp); } else { obj = NULL; /* all used */ } obj_extract_self(otmp); used_up = FALSE; /* 9 in 10 chance of fracturing boulders or statues */ if ((scflags & MAY_FRACTURE) && ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE)) && rn2(10)) { if (otmp->otyp == BOULDER) { if (visible) pline("%s apart.", Tobjnam(otmp, "break")); fracture_rock(otmp); place_object(otmp, lev, sx, sy); if ((otmp = sobj_at(BOULDER, lev, sx, sy)) != 0) { /* another boulder here, restack it to the top */ obj_extract_self(otmp); place_object(otmp, lev, sx, sy); } } else { struct trap *trap; if ((trap = t_at(lev, sx, sy)) && trap->ttyp == STATUE_TRAP) deltrap(lev, trap); if (visible) pline("%s.", Tobjnam(otmp, "crumble")); break_statue(otmp); place_object(otmp, lev, sx, sy); /* put fragments on floor */ } used_up = TRUE; /* 1 in 10 chance of destruction of obj; glass, egg destruction */ } else if ((scflags & MAY_DESTROY) && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS || otmp->otyp == EGG))) { if (breaks(otmp, (xchar) sx, (xchar) sy)) used_up = TRUE; } if (!used_up) { stmp = malloc(sizeof (struct scatter_chain)); stmp->next = NULL; stmp->obj = otmp; stmp->ox = sx; stmp->oy = sy; tmp = rn2(8); /* get the direction */ stmp->dx = xdir[tmp]; stmp->dy = ydir[tmp]; tmp = blastforce - (otmp->owt / 40); if (tmp < 1) tmp = 1; stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */ if (farthest < stmp->range) farthest = stmp->range; stmp->stopped = FALSE; if (!schain) schain = stmp; else stmp2->next = stmp; stmp2 = stmp; } } while (farthest-- > 0) { for (stmp = schain; stmp; stmp = stmp->next) { if ((stmp->range-- > 0) && (!stmp->stopped)) { bhitpos.x = stmp->ox + stmp->dx; bhitpos.y = stmp->oy + stmp->dy; typ = lev->locations[bhitpos.x][bhitpos.y].typ; if (!isok(bhitpos.x, bhitpos.y)) { bhitpos.x -= stmp->dx; bhitpos.y -= stmp->dy; stmp->stopped = TRUE; } else if (!ZAP_POS(typ) || closed_door(lev, bhitpos.x, bhitpos.y)) { bhitpos.x -= stmp->dx; bhitpos.y -= stmp->dy; stmp->stopped = TRUE; } else if ((mtmp = m_at(lev, bhitpos.x, bhitpos.y)) != 0) { if (scflags & MAY_HITMON) { stmp->range--; if (ohitmon(mtmp, stmp->obj, 1, FALSE)) { stmp->obj = NULL; stmp->stopped = TRUE; } } } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) { if (scflags & MAY_HITYOU) { int hitvalu, hitu; action_interrupted(); hitvalu = 8 + stmp->obj->spe; if (bigmonst(youmonst.data)) hitvalu++; hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst), stmp->obj, NULL); if (hitu) stmp->range -= 3; } } else { if (scflags & VIS_EFFECTS) { /* tmpsym_at(bhitpos.x, bhitpos.y); */ /* delay_output(); */ } } stmp->ox = bhitpos.x; stmp->oy = bhitpos.y; } } } for (stmp = schain; stmp; stmp = stmp2) { int x, y; stmp2 = stmp->next; x = stmp->ox; y = stmp->oy; if (stmp->obj) { if (x != sx || y != sy) total += stmp->obj->quan; place_object(stmp->obj, lev, x, y); stackobj(stmp->obj); } free(stmp); if (lev == level) newsym(x, y); } return total; }