/* * Is (x,y) a good position of mtmp? If mtmp is NULL, then is (x,y) good * for an object? * * This function will only look at mtmp->mdat, so makemon, mplayer, etc can * call it to generate new monster positions with fake monster structures. */ boolean goodpos(struct level *lev, int x, int y, struct monst *mtmp, unsigned gpflags) { const struct permonst *mdat = NULL; boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0); if (!isok(x, y)) return FALSE; /* in many cases, we're trying to create a new monster, which * can't go on top of the player or any existing monster. * however, occasionally we are relocating engravings or objects, * which could be co-located and thus get restricted a bit too much. * oh well. */ if (mtmp != &youmonst && x == u.ux && y == u.uy && (!u.usteed || mtmp != u.usteed)) return FALSE; if (mtmp) { struct monst *mtmp2 = m_at(lev, x,y); /* Be careful with long worms. A monster may be placed back in * its own location. Normally, if m_at() returns the same monster * that we're trying to place, the monster is being placed in its * own location. However, that is not correct for worm segments, * because all the segments of the worm return the same m_at(). * Actually we overdo the check a little bit--a worm can't be placed * in its own location, period. If we just checked for mtmp->mx * != x || mtmp->my != y, we'd miss the case where we're called * to place the worm segment and the worm's head is at x,y. */ if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno)) return FALSE; mdat = mtmp->data; if (is_pool(lev, x,y) && !ignorewater) { if (mtmp == &youmonst) return !!(HLevitation || Flying || Wwalking || Swimming || Amphibious); else return (is_flyer(mdat) || is_swimmer(mdat) || is_clinger(mdat)); } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) { return FALSE; } else if (is_lava(lev, x,y)) { if (mtmp == &youmonst) return !!HLevitation; else return is_flyer(mdat) || likes_lava(mdat); } if (passes_walls(mdat) && may_passwall(lev, x,y)) return TRUE; } if (!ACCESSIBLE(lev->locations[x][y].typ)) { if (!(is_pool(lev, x,y) && ignorewater)) return FALSE; } if (closed_door(lev, x, y) && (!mdat || !amorphous(mdat))) return FALSE; if (sobj_at(BOULDER, lev, x, y) && (!mdat || !throws_rocks(mdat))) return FALSE; return TRUE; }
int goodpos(int x, int y) { // used only in mnexto and rloc return !(x < 1 || x > COLNO - 2 || y < 1 || y > ROWNO - 2 || m_at(x, y) || !ACCESSIBLE(_level->l[x][y].typ) || (x == _u.ux && y == _u.uy) || sobj_at(ENORMOUS_ROCK, x, y) ); }
static Boolean teleok(Short x, Short y) { /* might throw him into a POOL */ return( !OUT_OF_BOUNDS(x,y) && !IS_ROCK(get_cell_type(floor_info[x][y])) && !mon_at(x,y) && !sobj_at(ENORMOUS_ROCK,x,y) && !trap_at(x,y) ); /* Note: gold is permitted (because of vaults) */ }
bool goodpos(int x, int y) /* used only in mnexto and rloc */ { return ( !(x < 1 || x > COLNO - 2 || y < 1 || y > ROWNO - 2 || m_at(x, y) || !ACCESSIBLE(levl[x][y].typ) || (x == u.ux && y == u.uy) || sobj_at(ENORMOUS_ROCK, x, y) )); }
/* used only in mnexto and rloc */ int goodpos(int x, int y) { return( ! (x < 1 || x > COLNO-2 || y < 1 || y > ROWNO-2 || m_at(x,y) || !ACCESSIBLE(levl[x][y].typ) || (x == u.ux && y == u.uy) || sobj_at(ENORMOUS_ROCK, x, y) )); }
/* make a swarm of undead around mm; uses the main RNG */ void mkundead(struct level *lev, coord *mm, boolean revive_corpses, int mm_flags) { int cnt = (level_difficulty(&lev->z) + 1) / 10 + rnd(5); const struct permonst *mdat; struct obj *otmp; coord cc; while (cnt--) { mdat = morguemon(&lev->z, rng_main); if (enexto(&cc, lev, mm->x, mm->y, mdat) && (!revive_corpses || !(otmp = sobj_at(CORPSE, lev, cc.x, cc.y)) || !revive(otmp))) makemon(mdat, lev, cc.x, cc.y, mm_flags); } lev->flags.graveyard = TRUE; /* reduced chance for undead corpse */ }
/* make a swarm of undead around mm */ void mkundead (coord *mm, bool revive_corpses, int mm_flags) { int cnt = (level_difficulty() + 1)/10 + rnd(5); struct permonst *mdat; struct obj *otmp; coord cc; while (cnt--) { mdat = morguemon(); if (enexto(&cc, mm->x, mm->y, mdat) && (!revive_corpses || !(otmp = sobj_at(CORPSE, cc.x, cc.y)) || !revive(otmp))) (void) makemon(mdat, cc.x, cc.y, mm_flags); } level.flags.graveyard = true; /* reduced chance for undead corpse */ }
/* * Try to find a dismount point adjacent to the steed's location. * If all else fails, try enexto(). Use enexto() as a last resort because * enexto() chooses its point randomly, possibly even outside the * room's walls, which is not what we want. * Adapted from mail daemon code. */ static boolean landing_spot(coord * spot, /* landing position (we fill it in) */ int reason, int forceit) { int i = 0, x, y, distance, min_distance = -1; boolean found = FALSE; struct trap *t; /* avoid known traps (i == 0) and boulders, but allow them as a backup */ if (reason != DISMOUNT_BYCHOICE || Stunned || Confusion || Fumbling) i = 1; for (; !found && i < 2; ++i) { for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) { if (!isok(x, y) || (x == u.ux && y == u.uy)) continue; if (ACCESSIBLE(level->locations[x][y].typ) && !MON_AT(level, x, y) && !closed_door(level, x, y)) { distance = distu(x, y); if (min_distance < 0 || distance < min_distance || (distance == min_distance && rn2(2))) { if (i > 0 || (((t = t_at(level, x, y)) == 0 || !t->tseen) && (!sobj_at(BOULDER, level, x, y) || throws_rocks(youmonst.data)))) { spot->x = x; spot->y = y; min_distance = distance; found = TRUE; } } } } } /* If we didn't find a good spot and forceit is on, try enexto(). */ if (forceit && min_distance < 0 && !enexto(spot, level, u.ux, u.uy, youmonst.data)) return FALSE; return found; }
/* * shk_move: return 1: he moved 0: he didnt -1: let m_move do it * (what about "return 2" ??? */ Short shk_move(monst_t *shkp) { monst_t *mtmp; permonst_t *mdat = shkp->data; UChar gx,gy,omx,omy,nx,ny,nix,niy; Int8 appr,i; Short udist; Short z; Int8 shkroom,chi,chcnt,cnt; Boolean uondoor=false, satdoor, avoid=false, badinv; coord poss[9]; Short info[9]; obj_t *ib = NULL; omx = shkp->mx; omy = shkp->my; if ((udist = dist(omx,omy)) < 3) { if (ANGRY(shkp)) { hit_you(shkp, dice(mdat->damn, mdat->damd)+1); return 0; } if (ESHK(shkp)->following) { if (StrNCompare(ESHK(shkp)->customer, plname, PL_NSIZ)) { StrPrintF(ScratchBuffer, "Hello %s! I was looking for %s.", plname, ESHK(shkp)->customer); message(ScratchBuffer); ESHK(shkp)->following = false; return 0; } if (!ESHK(shkp)->robbed) { /* impossible? */ ESHK(shkp)->following = false; return 0; } if (moves > followmsg+4) { StrPrintF(ScratchBuffer, "Hello %s! Didn't you forget to pay?", plname); message(ScratchBuffer); followmsg = moves; } if (udist < 2) return 0; } } shkroom = inroom(omx,omy); appr = 1; gx = ESHK(shkp)->shk.x; gy = ESHK(shkp)->shk.y; satdoor = (gx == omx && gy == omy); if (ESHK(shkp)->following || ((z = holetime()) >= 0 && z*z <= udist)){ gx = you.ux; gy = you.uy; if (shkroom < 0 || shkroom != inroom(you.ux,you.uy)) if (udist > 4) return -1; /* leave it to m_move */ } else if (ANGRY(shkp)) { Long saveBlind = Blind; Blind = 0; if ((shkp->mcansee_and_blinded & M_CAN_SEE) && !Invis && cansee(omx,omy)) { gx = you.ux; gy = you.uy; } Blind = saveBlind; avoid = false; } else { #define GDIST(x,y) ((x-gx)*(x-gx)+(y-gy)*(y-gy)) if (Invis) avoid = false; else { uondoor = (you.ux == ESHK(shkp)->shd.x && you.uy == ESHK(shkp)->shd.y); if (uondoor) { if (ESHK(shkp)->billct) { StrPrintF(ScratchBuffer, "Hello %s! Will you please pay before leaving?", plname); message(ScratchBuffer); } badinv = (carrying(PICK_AXE) || carrying(ICE_BOX)); if (satdoor && badinv) return 0; avoid = !badinv; } else { avoid = (you.uinshop && dist(gx,gy) > 8); badinv = false; } if (((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid) && GDIST(omx,omy) < 3) { if (!badinv && !online(omx,omy)) return 0; if (satdoor) appr = gx = gy = 0; } } } if (omx == gx && omy == gy) return 0; if (shkp->bitflags & M_IS_CONFUSED) { avoid = false; appr = 0; } nix = omx; niy = omy; cnt = mfindpos(shkp,poss,info,ALLOW_SSM); if (avoid && uondoor) { /* perhaps we cannot avoid him */ for (i=0; i<cnt; i++) if (!(info[i] & NOTONL)) goto notonl_ok; avoid = false; notonl_ok: ; } chi = -1; chcnt = 0; for (i = 0 ; i < cnt ; i++) { nx = poss[i].x; ny = poss[i].y; if (get_cell_type(floor_info[nx][ny]) == ROOM || shkroom != ESHK(shkp)->shoproom || ESHK(shkp)->following) { #ifdef STUPID /* cater for stupid compilers */ Short zz; #endif STUPID if (uondoor && (ib = sobj_at(ICE_BOX, nx, ny))) { nix = nx; niy = ny; chi = i; break; } if (avoid && (info[i] & NOTONL)) continue; if ((!appr && !rund(++chcnt)) || #ifdef STUPID (appr && (zz = GDIST(nix,niy)) && zz > GDIST(nx,ny)) #else (appr && GDIST(nx,ny) < GDIST(nix,niy)) #endif STUPID ) { nix = nx; niy = ny; chi = i; } } } if (nix != omx || niy != omy) { if (info[chi] & ALLOW_M){ mtmp = mon_at(nix,niy); if (hitmm(shkp,mtmp) == 1 && rund(3) && hitmm(mtmp,shkp) == 2) return 2; return 0; } else if (info[chi] & ALLOW_U){ hit_you(shkp, dice(mdat->damn, mdat->damd)+1); return 0; } shkp->mx = nix; shkp->my = niy; pmon(shkp); if (ib) { unlink_obj(ib);//freeobj mpickobj(shkp, ib); } return 1; } return 0; }
/* * Let's destroy the drawbridge located at x,y */ void destroy_drawbridge(int x, int y) { struct rm *loc1, *loc2; struct trap *t; int x2, y2; int db_u; boolean e_inview; struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]); loc1 = &level->locations[x][y]; if (!IS_DRAWBRIDGE(loc1->typ)) return; x2 = x; y2 = y; get_wall_for_db(&x2,&y2); loc2 = &level->locations[x2][y2]; db_u = (loc1->drawbridgemask & DB_UNDER); if (db_u == DB_MOAT || db_u == DB_LAVA || db_u == DB_BOG) { struct obj *otmp; int where = (db_u == DB_LAVA) ? 0 : (db_u == DB_MOAT) ? 1 : 2; static char *wstr[3] = { "lava", "moat", "swamp" }; if (loc1->typ == DRAWBRIDGE_UP) { if (cansee(x2,y2)) pline("The portcullis of the drawbridge falls into the %s!", wstr[where]); else if (flags.soundok) You_hear("a loud *SPLASH*!"); } else { if (cansee(x,y)) pline("The drawbridge collapses into the %s!", wstr[where]); else if (flags.soundok) You_hear("a loud *SPLASH*!"); } loc1->typ = (where == 0) ? LAVAPOOL : (where == 1) ? MOAT : BOG; loc1->drawbridgemask = 0; if ((otmp = sobj_at(BOULDER, level, x,y)) != 0) { obj_extract_self(otmp); flooreffects(otmp,x,y,"fall"); } } else { if (cansee(x,y)) pline("The drawbridge disintegrates!"); else You_hear("a loud *CRASH*!"); loc1->typ = ((loc1->drawbridgemask & DB_ICE) ? ICE : ROOM); loc1->icedpool = ((loc1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0); } wake_nearto(x, y, 500); loc2->typ = DOOR; loc2->doormask = D_NODOOR; if ((t = t_at(level, x, y)) != 0) deltrap(level, t); if ((t = t_at(level, x2, y2)) != 0) deltrap(level, t); newsym(x,y); newsym(x2,y2); if (!does_block(level, x2, y2, NULL)) unblock_point(x2,y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; set_entity(x2, y2, etmp2); /* currently only automissers can be here */ if (etmp2->edata) { e_inview = e_canseemon(level, etmp2); if (!automiss(etmp2)) { if (e_inview) pline("%s blown apart by flying debris.", E_phrase(etmp2, "are")); killer_format = KILLED_BY_AN; killer = "exploding drawbridge"; e_died(etmp2, e_inview? 3 : 2, CRUSHING); /*no corpse*/ } /* nothing which is vulnerable can survive this */ } set_entity(x, y, etmp1); if (etmp1->edata) { e_inview = e_canseemon(level, etmp1); if (!e_missed(etmp1, TRUE)) { if (e_inview) { if (!is_u(etmp1) && Hallucination) pline("%s into some heavy metal!", E_phrase(etmp1, "get")); else pline("%s hit by a huge chunk of metal!", E_phrase(etmp1, "are")); } else { if (flags.soundok && !is_u(etmp1) && !is_pool(level, x,y)) You_hear("a crushing sound."); } killer_format = KILLED_BY_AN; killer = "collapsing drawbridge"; e_died(etmp1, e_inview? 3 : 2, CRUSHING); /*no corpse*/ if (loc1->typ == MOAT) do_entity(etmp1); } } }
static int dig() { struct rm *lev; int dpx = dig_pos.x, dpy = dig_pos.y; /* perhaps a nymph stole his pick-axe while he was busy digging */ /* or perhaps he teleported away */ if(u.uswallow || !uwep || uwep->otyp != PICK_AXE || dig_level != dlevel || ((dig_down && (dpx != u.ux || dpy != u.uy)) || (!dig_down && dist(dpx,dpy) > 2))) return(0); dig_effort += 10 + abon() + uwep->spe + rn2(5); if(dig_down) { if(!xdnstair) { pline("The floor here seems too hard to dig in."); return(0); } if(dig_effort > 250) { dighole(); return(0); /* done with digging */ } if(dig_effort > 50) { struct trap *ttmp = t_at(dpx,dpy); if(!ttmp) { ttmp = maketrap(dpx,dpy,PIT); ttmp->tseen = 1; pline("You have dug a pit."); u.utrap = rn1(4,2); u.utraptype = TT_PIT; return(0); } } } else if (dig_effort > 100) { char *digtxt; struct obj *obj; lev = &levl[dpx][dpy]; if ((obj = sobj_at(ENORMOUS_ROCK, dpx, dpy))) { fracture_rock(obj); digtxt = "The rock falls apart."; } else if(!lev->typ || lev->typ == SCORR) { lev->typ = CORR; digtxt = "You succeeded in cutting away some rock."; } else if(lev->typ == HWALL || lev->typ == VWALL || lev->typ == SDOOR) { lev->typ = xdnstair ? DOOR : ROOM; digtxt = "You just made an opening in the wall."; } else digtxt = "Now what exactly was it that you were digging in?"; mnewsym(dpx, dpy); prl(dpx, dpy); pline(digtxt); /* after mnewsym & prl */ return(0); } else { if(IS_WALL(levl[dpx][dpy].typ)) { int rno = inroom(dpx,dpy); if(rno >= 0 && rooms[rno].rtype >= 8) { pline("This wall seems too hard to dig into."); return(0); } } pline("You hit the rock with all your might."); } return(1); }
static int use_pick_axe(struct obj *obj) { char dirsyms[12]; extern char sdir[]; char *dsp = dirsyms, *sdp = sdir; struct monst *mtmp; struct rm *lev; int rx, ry, res = 0; if(obj != uwep) { if(uwep && uwep->cursed) { /* Andreas Bormann - ihnp4!decvax!mcvax!unido!ab */ pline("Since your weapon is welded to your hand,"); pline("you cannot use that pick-axe."); return(0); } pline("You now wield %s.", doname(obj)); setuwep(obj); res = 1; } while(*sdp) { (void) movecmd(*sdp); /* sets u.dx and u.dy and u.dz */ rx = u.ux + u.dx; ry = u.uy + u.dy; if(u.dz > 0 || (u.dz == 0 && isok(rx, ry) && (IS_ROCK(levl[rx][ry].typ) || sobj_at(ENORMOUS_ROCK, rx, ry)))) *dsp++ = *sdp; sdp++; } *dsp = 0; pline("In what direction do you want to dig? [%s] ", dirsyms); if(!getdir(0)) /* no txt */ return(res); if(u.uswallow && attack(u.ustuck)) /* return(1) */; else if(u.dz < 0) pline("You cannot reach the ceiling."); else if(u.dz == 0) { if(Confusion) confdir(); rx = u.ux + u.dx; ry = u.uy + u.dy; if((mtmp = m_at(rx, ry)) && attack(mtmp)) return(1); if(!isok(rx, ry)) { pline("Clash!"); return(1); } lev = &levl[rx][ry]; if(lev->typ == DOOR) pline("Your %s against the door.", aobjnam(obj, "clang")); else if(!IS_ROCK(lev->typ) && !sobj_at(ENORMOUS_ROCK, rx, ry)) { /* ACCESSIBLE or POOL */ pline("You swing your %s through thin air.", aobjnam(obj, (char *) 0)); } else { if(dig_pos.x != rx || dig_pos.y != ry || dig_level != dlevel || dig_down) { dig_down = FALSE; dig_pos.x = rx; dig_pos.y = ry; dig_level = dlevel; dig_effort = 0; pline("You start digging."); } else pline("You continue digging."); occupation = dig; occtxt = "digging"; } } else if(Levitation) { pline("You cannot reach the floor."); } else { if(dig_pos.x != u.ux || dig_pos.y != u.uy || dig_level != dlevel || !dig_down) { dig_down = TRUE; dig_pos.x = u.ux; dig_pos.y = u.uy; dig_level = dlevel; dig_effort = 0; pline("You start digging in the floor."); if(inshop()) shopdig(0); } else pline("You continue digging in the floor."); occupation = dig; occtxt = "digging"; } return(1); }
/* * shk_move: return 1: he moved 0: he didnt -1: let m_move do it */ int shk_move(struct monst *shkp) { struct monst *mtmp; struct permonst *mdat = shkp->data; xchar gx, gy, omx, omy, nx, ny, nix, niy; schar appr, i; int udist; int z; schar shkroom, chi, chcnt, cnt; boolean uondoor = 0, satdoor, avoid = 0, badinv; coord poss[9]; int info[9]; struct obj *ib = NULL; omx = shkp->mx; omy = shkp->my; if ((udist = dist(omx, omy)) < 3) { if (ANGRY(shkp)) { hitu(shkp, d(mdat->damn, mdat->damd) + 1); return (0); } if (ESHK(shkp)->following) { if (strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)) { pline("Hello %s! I was looking for %s.", plname, ESHK(shkp)->customer); ESHK(shkp)->following = 0; return (0); } if (!ESHK(shkp)->robbed) { /* impossible? */ ESHK(shkp)->following = 0; return (0); } if (moves > followmsg + 4) { pline("Hello %s! Didn't you forget to pay?", plname); followmsg = moves; } if (udist < 2) return (0); } } shkroom = inroom(omx, omy); appr = 1; gx = ESHK(shkp)->shk.x; gy = ESHK(shkp)->shk.y; satdoor = (gx == omx && gy == omy); if (ESHK(shkp)->following || ((z = holetime()) >= 0 && z * z <= udist)) { gx = u.ux; gy = u.uy; if (shkroom < 0 || shkroom != inroom(u.ux, u.uy)) if (udist > 4) return (-1); /* leave it to m_move */ } else if (ANGRY(shkp)) { long saveBlind = Blind; Blind = 0; if (shkp->mcansee && !Invis && cansee(omx, omy)) { gx = u.ux; gy = u.uy; } Blind = saveBlind; avoid = FALSE; } else { #define GDIST(x, y) ((x - gx) * (x - gx) + (y - gy) * (y - gy)) if (Invis) avoid = FALSE; else { uondoor = (u.ux == ESHK(shkp)->shd.x && u.uy == ESHK(shkp)->shd.y); if (uondoor) { if (ESHK(shkp)->billct) pline("Hello %s! Will you please pay before leaving?", plname); badinv = (carrying(PICK_AXE) || carrying(ICE_BOX)); if (satdoor && badinv) return (0); avoid = !badinv; } else { avoid = (u.uinshop && dist(gx, gy) > 8); badinv = FALSE; } if (((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid) && GDIST(omx, omy) < 3) { if (!badinv && !online(omx, omy)) return (0); if (satdoor) appr = gx = gy = 0; } } } if (omx == gx && omy == gy) return (0); if (shkp->mconf) { avoid = FALSE; appr = 0; } nix = omx; niy = omy; cnt = mfndpos(shkp, poss, info, ALLOW_SSM); if (avoid && uondoor) { /* perhaps we cannot avoid him */ for (i = 0; i < cnt; i++) if (!(info[i] & NOTONL)) goto notonl_ok; avoid = FALSE; notonl_ok: ; } chi = -1; chcnt = 0; for (i = 0; i < cnt; i++) { nx = poss[i].x; ny = poss[i].y; if (levl[nx][ny].typ == ROOM || shkroom != ESHK(shkp)->shoproom || ESHK(shkp)->following) { #ifdef STUPID /* cater for stupid compilers */ int zz; #endif /* STUPID */ if (uondoor && (ib = sobj_at(ICE_BOX, nx, ny))) { nix = nx; niy = ny; chi = i; break; } if (avoid && (info[i] & NOTONL)) continue; if ((!appr && !rn2(++chcnt)) || #ifdef STUPID (appr && (zz = GDIST(nix, niy)) && zz > GDIST(nx, ny)) #else (appr && GDIST(nx, ny) < GDIST(nix, niy)) #endif /* STUPID */ ) { nix = nx; niy = ny; chi = i; } } } if (nix != omx || niy != omy) { if (info[chi] & ALLOW_M) { mtmp = m_at(nix, niy); if (hitmm(shkp, mtmp) == 1 && rn2(3) && hitmm(mtmp, shkp) == 2) return (2); return (0); } else if (info[chi] & ALLOW_U) { hitu(shkp, d(mdat->damn, mdat->damd) + 1); return (0); } shkp->mx = nix; shkp->my = niy; pmon(shkp); if (ib) { freeobj(ib); mpickobj(shkp, ib); } return (1); } return (0); }
/* Returns 1 if monster died moving, 0 otherwise */ int dochug(struct monst *mtmp) { struct permonst *mdat; int tmp = 0; if((mtmp->cham != 0) && (rn2(6) == 0)) { newcham(mtmp, &mons[(dlevel + 14) + rn2((CMNUM - 14) - dlevel)]); } mdat = mtmp->data; if(mdat->mlevel < 0) { panic("bad monster %c (%d)", mdat->mlet, mdat->mlevel); } if((((moves % 20) == 0) || (index("ViT", mdat->mlet) != 0)) && (mtmp->mhp < mtmp->orig_hp)) { /* Regenerate monsters. */ ++mtmp->mhp; } if(mtmp->mfroz != 0) { /* Frozen monsters don't do anything. */ return 0; } if(mtmp->msleep != 0) { /* Wake up a monster, or get out of here. */ if((cansee(mtmp->mx, mtmp->my) != 0) && (Stealth == 0) && ((index("NL", mdat->mlet) == 0) || (rn2(50) == 0)) && ((Aggravate_monster != 0) || ((rn2(7) == 0) && (mtmp->mimic == 0)))) { mtmp->msleep = 0; } else { return 0; } } /* Not frozen or sleeping: wipe out texts written in the dust */ wipe_engr_at(mtmp->mx, mtmp->my, 1); /* Confused monsters get unconfused with small probability */ if((mtmp->mconf != 0) && (rn2(50) == 0)) { mtmp->mconf = 0; } /* Some monsters teleport */ if((mtmp->mflee != 0) && (index("tNL", mdat->mlet) != 0) && (rn2(40) == 0)) { rloc(mtmp); return 0; } if(mdat->mmove < rnd(6)) { return 0; } if((mtmp->mflee != 0) || (mtmp->mconf != 0) || ((index("BIuy", mdat->mlet) != 0) && (rn2(4) == 0)) || ((mdat->mlet == 'L') && (u.ugold == 0) && ((mtmp->mgold != 0) || (rn2(2) != 0))) || (dist(mtmp->mx, mtmp->my) > 2) || ((mtmp->mcansee == 0) && (rn2(4) == 0)) || (mtmp->mpeaceful != 0)) { tmp = m_move(mtmp, 0); if((tmp != 0) && (mdat->mmove < 12)) { if(tmp == 2) { return 1; } else { return 0; } } } if(tmp == 2) { /* Monster died moving */ return 1; } if((index("Ea", mdat->mlet) == 0) && (dist(mtmp->mx, mtmp->my) < 3) && (mtmp->mpeaceful == 0) && (u.uhp > 0) && (sengr_at("Elbereth", u.ux, u.uy) == 0) && (sobj_at(SCR_SCARE_MONSTER, u.ux, u.uy) == 0)) { if(mhitu(mtmp) != 0) { /* Monster died (e.g. 'y' or 'F') */ return 1; } } /* Extra movement for fast monsters */ if((mdat->mmove - 12) > rnd(12)) { tmp = m_move(mtmp, 1); } if(tmp == 2) { return 1; } else { return 0; } }
/* Return number of acceptable neighbour positions */ int mfndpos(struct monst *mon, coord poss[9], int info[9], int flag) { int x; int y; int nx; int ny; int cnt = 0; int tmp; struct monst *mtmp; x = mon->mx; y = mon->my; if(mon->mconf != 0) { flag |= ALLOW_ALL; flag &= ~NOTONL; } for(nx = x - 1; nx <= x + 1; ++nx) { for(ny = y - 1; ny <= y + 1; ++ny) { if((nx != x) || (ny != y)) { if(isok(nx, ny) != 0) { tmp = levl[nx][ny].typ; if(tmp >= DOOR) { if((nx == x) || (ny == y) || ((levl[x][y].typ != DOOR) && (tmp != DOOR))) { info[cnt] = 0; if((nx == u.ux) && (ny == u.uy)) { if((flag & ALLOW_U) == 0) { continue; } info[cnt] = ALLOW_U; } else { mtmp = m_at(nx, ny); if(mtmp != 0) { if((flag & ALLOW_M) == 0) { continue; } info[cnt] = ALLOW_M; } if(mtmp->mtame != 0) { if((flag & ALLOW_TM) == 0) { continue; } info[cnt] |= ALLOW_TM; } } if(sobj_at(CLOVE_OF_GARLIC, nx, ny) != 0) { if((flag & NOGARLIC) != 0) { continue; } info[cnt] |= NOGARLIC; } if((sobj_at(SCR_SCARE_MONSTER, nx, ny) != 0) || ((mon->mpeaceful == 0) && (sengr_at("Elbereth", nx, ny) != 0))) { if((flag & ALLOW_SSM) == 0) { continue; } info[cnt] |= ALLOW_SSM; } if(sobj_at(ENORMOUS_ROCK, nx, ny) != 0) { if((flag & ALLOW_ROCK) == 0) { continue; } info[cnt] |= ALLOW_ROCK; } if((Invis == 0) && (online(nx, ny) != 0)) { if((flag & NOTONL) != 0) { continue; } info[cnt] |= NOTONL; } /* We cannot avoid traps of an unknown kind */ struct gen *gtmp = g_at(nx, ny, ftrap); int tt; if(gtmp != NULL) { tt = 1 << (gtmp->gflag & ~SEEN); if((mon->mtrapseen & tt) != 0) { if((flag & tt) == 0) { continue; } info[cnt] |= tt; } } poss[cnt].x = nx; poss[cnt].y = ny; ++cnt; } } } } } } return cnt; }
/* * Let's destroy the drawbridge located at x,y */ void destroy_drawbridge(int x, int y) { struct rm *loc1, *loc2; struct trap *t; int x2, y2; boolean e_inview; struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]); loc1 = &level->locations[x][y]; if (!IS_DRAWBRIDGE(loc1->typ)) return; x2 = x; y2 = y; get_wall_for_db(&x2, &y2); loc2 = &level->locations[x2][y2]; if ((loc1->drawbridgemask & DB_UNDER) == DB_MOAT || (loc1->drawbridgemask & DB_UNDER) == DB_LAVA) { struct obj *otmp; boolean lava = (loc1->drawbridgemask & DB_UNDER) == DB_LAVA; if (loc1->typ == DRAWBRIDGE_UP) { if (cansee(x2, y2)) pline(msgc_consequence, "The portcullis of the drawbridge falls into the %s!", lava ? "lava" : waterbody_name(x2, y2)); else You_hear(msgc_levelsound, "a loud *SPLASH*!"); } else { if (cansee(x, y)) pline(msgc_consequence, "The drawbridge collapses into the %s!", lava ? "lava" : waterbody_name(x, y)); else You_hear(msgc_levelsound, "a loud *SPLASH*!"); } loc1->typ = lava ? LAVAPOOL : MOAT; loc1->drawbridgemask = 0; if ((otmp = sobj_at(BOULDER, level, x, y)) != 0) { obj_extract_self(otmp); flooreffects(otmp, x, y, "fall"); } } else { if (cansee(x, y)) pline(msgc_consequence, "The drawbridge disintegrates!"); else You_hear(msgc_levelsound, "a loud *CRASH*!"); loc1->typ = ((loc1->drawbridgemask & DB_ICE) ? ICE : ROOM); loc1->icedpool = ((loc1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0); } wake_nearto(x, y, 500); loc2->typ = DOOR; loc2->doormask = D_NODOOR; if ((t = t_at(level, x, y)) != 0) deltrap(level, t); if ((t = t_at(level, x2, y2)) != 0) deltrap(level, t); newsym(x, y); newsym(x2, y2); if (!does_block(level, x2, y2)) unblock_point(x2, y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; set_entity(x2, y2, etmp2); /* currently only automissers can be here */ if (etmp2->edata) { enum msg_channel hit_msgc; if (is_u(etmp2)) hit_msgc = msgc_fatal_predone; else if (etmp2->emon->mtame && canspotmon(etmp2->emon)) hit_msgc = msgc_petfatal; else hit_msgc = msgc_monneutral; e_inview = e_canseemon(etmp2); if (!automiss(etmp2)) { if (e_inview) pline(hit_msgc, "%s blown apart by flying debris.", E_phrase(etmp2, "are")); e_died(etmp2, e_inview ? 3 : 2, CRUSHING, killer_msg(CRUSHING, "an exploding drawbridge")); } /* nothing which is vulnerable can survive this */ } set_entity(x, y, etmp1); if (etmp1->edata) { enum msg_channel hit_msgc; if (is_u(etmp1)) hit_msgc = msgc_fatal_predone; else if (etmp1->emon->mtame && canspotmon(etmp1->emon)) hit_msgc = msgc_petfatal; else hit_msgc = msgc_monneutral; e_inview = e_canseemon(etmp1); if (!e_missed(etmp1, TRUE)) { if (e_inview) { if (!is_u(etmp1) && Hallucination) pline(hit_msgc, "%s into some heavy metal!", E_phrase(etmp1, "get")); else pline(hit_msgc, "%s hit by a huge chunk of metal!", E_phrase(etmp1, "are")); } else { if (!is_u(etmp1) && !is_pool(level, x, y)) You_hear(msgc_levelsound, "a crushing sound."); } e_died(etmp1, e_inview ? 3 : 2, CRUSHING, killer_msg(CRUSHING, "a collapsing drawbridge")); /* if (loc1->typ == MOAT) do_entity(etmp1); */ } if (is_u(etmp1)) spoteffects(FALSE); else if (!DEADMONSTER(etmp1->emon)) minliquid(etmp1->emon); } }
/* * Let's destroy the drawbridge located at x,y */ void destroy_drawbridge(int x, int y) { struct rm *loc1, *loc2; struct trap *t; struct obj *chain; int x2, y2, i; boolean e_inview; struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]); loc1 = &level->locations[x][y]; if (!IS_DRAWBRIDGE(loc1->typ)) return; x2 = x; y2 = y; get_wall_for_db(&x2, &y2); loc2 = &level->locations[x2][y2]; if ((loc1->drawbridgemask & DB_UNDER) == DB_MOAT || (loc1->drawbridgemask & DB_UNDER) == DB_LAVA) { struct obj *otmp; boolean lava = (loc1->drawbridgemask & DB_UNDER) == DB_LAVA; if (loc1->typ == DRAWBRIDGE_UP) { if (cansee(x2, y2)) pline("The portcullis of the drawbridge falls into the %s!", lava ? "lava" : waterbody_name(x2, y2)); else You_hear("a loud *SPLASH*!"); } else { if (cansee(x, y)) pline("The drawbridge collapses into the %s!", lava ? "lava" : waterbody_name(x, y)); else You_hear("a loud *SPLASH*!"); } loc1->typ = lava ? LAVAPOOL : MOAT; loc1->drawbridgemask = 0; if ((otmp = sobj_at(BOULDER, level, x, y)) != 0) { obj_extract_self(otmp); flooreffects(otmp, x, y, "fall"); } } else { if (cansee(x, y)) pline("The drawbridge disintegrates!"); else You_hear("a loud *CRASH*!"); loc1->typ = ((loc1->drawbridgemask & DB_ICE) ? ICE : ROOM); loc1->icedpool = ((loc1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0); } wake_nearto(x, y, 500); loc2->typ = DOOR; loc2->doormask = D_NODOOR; if ((t = t_at(level, x, y)) != 0) deltrap(level, t); if ((t = t_at(level, x2, y2)) != 0) deltrap(level, t); del_engr_at(level, x, y); del_engr_at(level, x2, y2); for (i = rn2(6); i > 0; --i) { /* scatter some debris */ /* doesn't matter if we happen to pick <x,y2> or <x2,y>; since drawbridges are never placed diagonally, those pairings will always match one of <x,y> or <x2,y2> */ chain = mksobj_at(IRON_CHAIN, level, rn2(2) ? x : x2, rn2(2) ? y : y2, TRUE, FALSE, rng_main); /* a force of 5 here would yield a radius of 2 for iron chain; anything less produces a radius of 1 */ (void) scatter(chain->ox, chain->oy, 1, MAY_HIT, chain); } newsym(x, y); newsym(x2, y2); if (!does_block(level, x2, y2)) unblock_point(x2, y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; set_entity(x2, y2, etmp2); /* currently only automissers can be here */ if (etmp2->edata) { e_inview = e_canseemon(etmp2); if (!automiss(etmp2)) { if (e_inview) pline("%s blown apart by flying debris.", E_phrase(etmp2, "are")); e_died(etmp2, e_inview ? 3 : 2, CRUSHING, killer_msg(CRUSHING, "an exploding drawbridge")); } /* nothing which is vulnerable can survive this */ } set_entity(x, y, etmp1); if (etmp1->edata) { e_inview = e_canseemon(etmp1); if (!e_missed(etmp1, TRUE)) { if (e_inview) { if (!is_u(etmp1) && Hallucination) pline("%s into some heavy metal!", E_phrase(etmp1, "get")); else pline("%s hit by a huge chunk of metal!", E_phrase(etmp1, "are")); } else { if (!is_u(etmp1) && !is_pool(level, x, y)) You_hear("a crushing sound."); } e_died(etmp1, e_inview ? 3 : 2, CRUSHING, killer_msg(CRUSHING, "a collapsing drawbridge")); /* if (loc1->typ == MOAT) do_entity(etmp1); */ } if (is_u(etmp1)) spoteffects(FALSE); else if (!DEADMONSTER(etmp1->emon)) minliquid(etmp1->emon); } }
/* quick: use cursor && don't search for "more info" */ static int do_look (bool quick) { char out_str[BUFSZ], look_buf[BUFSZ]; const char *x_str, *firstmatch = 0; struct permonst *pm = 0; int i, ans = 0; int sym; /* typed symbol or converted glyph */ int found; /* count of matching syms found */ coord cc; /* screen pos of unknown glyph */ bool save_verbose; /* saved value of flags.verbose */ bool from_screen; /* question from the screen */ bool need_to_look; /* need to get explan. from glyph */ bool hit_trap; /* true if found trap explanation */ int skipped_venom; /* non-zero if we ignored "splash of venom" */ static const char *mon_interior = "the interior of a monster"; if (quick) { from_screen = true; /* yes, we want to use the cursor */ } else { i = ynq("Specify unknown object by cursor?"); if (i == 'q') return 0; from_screen = (i == 'y'); } if (from_screen) { cc.x = u.ux; cc.y = u.uy; sym = 0; /* gcc -Wall lint */ } else { getlin("Specify what? (type the word)", out_str); if (out_str[0] == '\0' || out_str[0] == '\033') return 0; if (out_str[1]) { /* user typed in a complete string */ checkfile(out_str, pm, true, true); return 0; } sym = out_str[0]; } /* Save the verbose flag, we change it later. */ save_verbose = flags.verbose; flags.verbose = flags.verbose && !quick; /* * The user typed one letter, or we're identifying from the screen. */ do { /* Reset some variables. */ need_to_look = false; pm = (struct permonst *)0; skipped_venom = 0; found = 0; out_str[0] = '\0'; if (from_screen) { int glyph; /* glyph at selected position */ if (flags.verbose) pline("Please move the cursor to %s.", what_is_an_unknown_object); else pline("Pick an object."); ans = getpos(&cc, quick, what_is_an_unknown_object); if (ans < 0 || cc.x < 0) { flags.verbose = save_verbose; return 0; /* done */ } flags.verbose = false; /* only print long question once */ /* Convert the glyph at the selected position to a symbol. */ glyph = glyph_at(cc.x,cc.y); if (glyph_is_cmap(glyph)) { sym = showsyms[glyph_to_cmap(glyph)]; } else if (glyph_is_trap(glyph)) { sym = showsyms[trap_to_defsym(glyph_to_trap(glyph))]; } else if (glyph_is_object(glyph)) { sym = oc_syms[(int)objects[glyph_to_obj(glyph)].oc_class]; if (sym == '`' && iflags.bouldersym && (int)glyph_to_obj(glyph) == BOULDER) sym = iflags.bouldersym; } else if (glyph_is_monster(glyph)) { /* takes care of pets, detected, ridden, and regular mons */ sym = monsyms[(int)mons[glyph_to_mon(glyph)].mlet]; } else if (glyph_is_swallow(glyph)) { sym = showsyms[glyph_to_swallow(glyph)+S_sw_tl]; } else if (glyph_is_invisible(glyph)) { sym = DEF_INVISIBLE; } else if (glyph_is_warning(glyph)) { sym = glyph_to_warning(glyph); sym = warnsyms[sym]; } else { impossible("do_look: bad glyph %d at (%d,%d)", glyph, (int)cc.x, (int)cc.y); sym = ' '; } } /* * Check all the possibilities, saving all explanations in a buffer. * When all have been checked then the string is printed. */ /* Check for monsters */ for (i = 0; i < MAXMCLASSES; i++) { if (sym == (from_screen ? monsyms[i] : def_monsyms[i]) && monexplain[i]) { need_to_look = true; if (!found) { sprintf(out_str, "%c %s", sym, an(monexplain[i])); firstmatch = monexplain[i]; found++; } else { found += append_str(out_str, an(monexplain[i])); } } } /* handle '@' as a special case if it refers to you and you're playing a character which isn't normally displayed by that symbol; firstmatch is assumed to already be set for '@' */ if ((from_screen ? (sym == monsyms[S_HUMAN] && cc.x == u.ux && cc.y == u.uy) : (sym == def_monsyms[S_HUMAN] && !iflags.showrace)) && !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd) found += append_str(out_str, "you"); /* tack on "or you" */ /* * Special case: if identifying from the screen, and we're swallowed, * and looking at something other than our own symbol, then just say * "the interior of a monster". */ if (u.uswallow && from_screen && is_swallow_sym(sym)) { if (!found) { sprintf(out_str, "%c %s", sym, mon_interior); firstmatch = mon_interior; } else { found += append_str(out_str, mon_interior); } need_to_look = true; } /* Now check for objects */ for (i = 1; i < MAXOCLASSES; i++) { if (sym == (from_screen ? oc_syms[i] : def_oc_syms[i])) { need_to_look = true; if (from_screen && i == VENOM_CLASS) { skipped_venom++; continue; } if (!found) { sprintf(out_str, "%c %s", sym, an(objexplain[i])); firstmatch = objexplain[i]; found++; } else { found += append_str(out_str, an(objexplain[i])); } } } if (sym == DEF_INVISIBLE) { if (!found) { sprintf(out_str, "%c %s", sym, an(invisexplain)); firstmatch = invisexplain; found++; } else { found += append_str(out_str, an(invisexplain)); } } #define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap) #define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge) /* Now check for graphics symbols */ for (hit_trap = false, i = 0; i < MAXPCHARS; i++) { x_str = defsyms[i].explanation; if (sym == (from_screen ? showsyms[i] : defsyms[i].sym) && *x_str) { /* avoid "an air", "a water", or "a floor of a room" */ int article = (i == S_room) ? 2 : /* 2=>"the" */ !(strcmp(x_str, "air") == 0 || /* 1=>"an" */ strcmp(x_str, "water") == 0); /* 0=>(none)*/ if (!found) { if (is_cmap_trap(i)) { sprintf(out_str, "%c a trap", sym); hit_trap = true; } else { sprintf(out_str, "%c %s", sym, article == 2 ? the(x_str) : article == 1 ? an(x_str) : x_str); } firstmatch = x_str; found++; } else if (!u.uswallow && !(hit_trap && is_cmap_trap(i)) && !(found >= 3 && is_cmap_drawbridge(i))) { found += append_str(out_str, article == 2 ? the(x_str) : article == 1 ? an(x_str) : x_str); if (is_cmap_trap(i)) hit_trap = true; } if (i == S_altar || is_cmap_trap(i)) need_to_look = true; } } /* Now check for warning symbols */ for (i = 1; i < WARNCOUNT; i++) { x_str = def_warnsyms[i].explanation; if (sym == (from_screen ? warnsyms[i] : def_warnsyms[i].sym)) { if (!found) { sprintf(out_str, "%c %s", sym, def_warnsyms[i].explanation); firstmatch = def_warnsyms[i].explanation; found++; } else { found += append_str(out_str, def_warnsyms[i].explanation); } /* Kludge: warning trumps boulders on the display. Reveal the boulder too or player can get confused */ if (from_screen && sobj_at(BOULDER, cc.x, cc.y)) strcat(out_str, " co-located with a boulder"); break; /* out of for loop*/ } } /* if we ignored venom and list turned out to be short, put it back */ if (skipped_venom && found < 2) { x_str = objexplain[VENOM_CLASS]; if (!found) { sprintf(out_str, "%c %s", sym, an(x_str)); firstmatch = x_str; found++; } else { found += append_str(out_str, an(x_str)); } } /* handle optional boulder symbol as a special case */ if (iflags.bouldersym && sym == iflags.bouldersym) { if (!found) { firstmatch = "boulder"; sprintf(out_str, "%c %s", sym, an(firstmatch)); found++; } else { found += append_str(out_str, "boulder"); } } /* * If we are looking at the screen, follow multiple possibilities or * an ambiguous explanation by something more detailed. */ if (from_screen) { if (found > 1 || need_to_look) { char monbuf[BUFSZ]; char temp_buf[BUFSZ]; pm = lookat(cc.x, cc.y, look_buf, monbuf); firstmatch = look_buf; if (*firstmatch) { sprintf(temp_buf, " (%s)", firstmatch); (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1); found = 1; /* we have something to look up */ } if (monbuf[0]) { sprintf(temp_buf, " [seen: %s]", monbuf); (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1); } } } /* Finally, print out our explanation. */ if (found) { pline("%s", out_str); /* check the data file for information about this thing */ if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE && (ans == LOOK_VERBOSE || (flags.help && !quick))) { char temp_buf[BUFSZ]; strcpy(temp_buf, firstmatch); checkfile(temp_buf, pm, false, (bool)(ans == LOOK_VERBOSE)); } } else { pline("I've never heard of such things."); } } while (from_screen && !quick && ans != LOOK_ONCE); flags.verbose = save_verbose; return 0; }
/* 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; }
/* Generate earthquake :-) of desired force. That is: create random chasms (pits). Currently assumes that the player created it (you'll need to change at least messages, angering, and kill credit if you generalize it). */ static void do_earthquake(int force) { int x, y; struct monst *mtmp; struct obj *otmp; struct trap *chasm, *oldtrap; int start_x, start_y, end_x, end_y; start_x = youmonst.mx - (force * 2); start_y = youmonst.my - (force * 2); end_x = youmonst.mx + (force * 2); end_y = youmonst.my + (force * 2); if (start_x < 0) start_x = 0; if (start_y < 0) start_y = 0; if (end_x >= COLNO) end_x = COLNO - 1; if (end_y >= ROWNO) end_y = ROWNO - 1; for (x = start_x; x <= end_x; x++) for (y = start_y; y <= end_y; y++) { if ((mtmp = m_at(level, x, y)) != 0) { wakeup(mtmp, FALSE); /* peaceful monster will become hostile */ if (mtmp->mundetected && is_hider(mtmp->data)) { mtmp->mundetected = 0; if (cansee(x, y)) pline(msgc_youdiscover, "%s is shaken loose from %s!", Amonnam(mtmp), mtmp->data == &mons[PM_TRAPPER] ? "its hiding place" : the(ceiling(youmonst.mx, youmonst.my))); else You_hear(msgc_levelsound, "a thumping sound."); if (x == youmonst.mx && y == youmonst.my && mtmp->data != &mons[PM_TRAPPER]) pline(msgc_moncombatgood, "You easily dodge the falling %s.", mon_nam(mtmp)); newsym(x, y); } } if (!rn2(14 - force)) switch (level->locations[x][y].typ) { case FOUNTAIN: /* Make the fountain disappear */ if (cansee(x, y)) pline(msgc_consequence, "The fountain falls into a chasm."); goto do_pit; case SINK: if (cansee(x, y)) pline(msgc_consequence, "The kitchen sink falls into a chasm."); goto do_pit; case ALTAR: if (level->locations[x][y].altarmask & AM_SANCTUM) break; if (cansee(x, y)) pline(msgc_consequence, "The altar falls into a chasm."); goto do_pit; case GRAVE: if (cansee(x, y)) pline(msgc_consequence, "The headstone topples into a chasm."); goto do_pit; case THRONE: if (cansee(x, y)) pline(msgc_consequence, "The throne falls into a chasm."); /* Falls into next case */ case ROOM: case CORR: /* Try to make a pit */ /* Pits, spiked pits, holes, trapdoors, vibrating squares, magic portals are immune. A bear trap will leave the trap in the pit. It would be kind of cool to make landmines detonate, but that's more trouble than it's worth. */ if ((oldtrap = t_at(level, x, y))) { if (oldtrap->ttyp == PIT || oldtrap->ttyp == SPIKED_PIT || oldtrap->ttyp == HOLE || oldtrap->ttyp == TRAPDOOR || oldtrap->ttyp == VIBRATING_SQUARE || oldtrap->ttyp == MAGIC_PORTAL) break; if (oldtrap->ttyp == BEAR_TRAP) { if (mtmp) mtmp->mtrapped = 0; cnv_trap_obj(level, BEARTRAP, 1, oldtrap); } } do_pit: chasm = maketrap(level, x, y, PIT, rng_main); if (!chasm) break; /* no pit if portal at that location */ chasm->tseen = 1; level->locations[x][y].doormask = 0; mtmp = m_at(level, x, y); if ((otmp = sobj_at(BOULDER, level, x, y)) != 0) { if (cansee(x, y)) pline(msgc_consequence, "KADOOM! The boulder falls into a chasm%s!", ((x == youmonst.mx) && (y == youmonst.my)) ? " below you" : ""); if (mtmp) mtmp->mtrapped = 0; obj_extract_self(otmp); flooreffects(otmp, x, y, ""); break; } /* We have to check whether monsters or player falls in a chasm... */ if (mtmp) { if (!flying(mtmp) && !levitates(mtmp) && !is_clinger(mtmp->data)) { mtmp->mtrapped = 1; if (cansee(x, y)) pline(combat_msgc(&youmonst, mtmp, cr_hit), "%s falls into a chasm!", Monnam(mtmp)); else if (humanoid(mtmp->data)) You_hear(msgc_levelsound, "a scream!"); mselftouch(mtmp, "Falling, ", &youmonst); if (!DEADMONSTER(mtmp)) if ((mtmp->mhp -= rnd(6)) <= 0) { if (!cansee(x, y)) pline(msgc_kill, "It is destroyed!"); else { pline(msgc_petfatal, "You destroy %s!", mtmp->mtame ? x_monnam(mtmp, ARTICLE_THE, "poor", mx_name(mtmp) ? SUPPRESS_SADDLE : 0, FALSE) : mon_nam(mtmp)); } xkilled(mtmp, 0); } } } else if (!u.utrap && x == youmonst.mx && y == youmonst.my) { if (Levitation || Flying || is_clinger(youmonst.data)) { pline(msgc_noconsequence, "A chasm opens up under you!"); pline(msgc_noconsequence, "You don't fall in!"); } else { pline(msgc_badidea, "You fall into a chasm!"); u.utrap = rn1(6, 2); u.utraptype = TT_PIT; turnstate.vision_full_recalc = TRUE; losehp(rnd(6), "fell into a chasm"); selftouch("Falling, you", "falling into a chasm while wielding"); } } else newsym(x, y); break; case DOOR: /* Make the door collapse */ if (level->locations[x][y].doormask == D_NODOOR) goto do_pit; if (cansee(x, y)) pline(msgc_consequence, "The door collapses."); if (*in_rooms(level, x, y, SHOPBASE)) add_damage(x, y, 0L); level->locations[x][y].doormask = D_NODOOR; unblock_point(x, y); newsym(x, y); break; } } }