/* SCCS Id: @(#)vault.c 3.3 96/06/05 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "vault.h" STATIC_DCL struct monst *NDECL(findgd); #ifdef OVLB STATIC_DCL boolean FDECL(clear_fcorr, (struct monst *,BOOLEAN_P)); STATIC_DCL void FDECL(restfakecorr,(struct monst *)); STATIC_DCL boolean FDECL(in_fcorridor, (struct monst *,int,int)); STATIC_DCL void FDECL(move_gold,(struct obj *,int)); STATIC_DCL void FDECL(wallify_vault,(struct monst *)); STATIC_OVL boolean clear_fcorr(grd, forceshow) register struct monst *grd; register boolean forceshow; { register int fcx, fcy, fcbeg; register struct monst *mtmp; while((fcbeg = EGD(grd)->fcbeg) < EGD(grd)->fcend) { fcx = EGD(grd)->fakecorr[fcbeg].fx; fcy = EGD(grd)->fakecorr[fcbeg].fy; if((grd->mhp <= 0 || !in_fcorridor(grd, u.ux, u.uy)) && EGD(grd)->gddone) forceshow = TRUE; if((u.ux == fcx && u.uy == fcy && grd->mhp > 0) || (!forceshow && couldsee(fcx,fcy)) || (Punished && !carried(uball) && uball->ox == fcx && uball->oy == fcy)) return FALSE; if ((mtmp = m_at(fcx,fcy)) != 0) { if(mtmp->isgd) return(FALSE); else if(!in_fcorridor(grd, u.ux, u.uy)) { if(mtmp->mtame) yelp(mtmp); rloc(mtmp); } } levl[fcx][fcy].typ = EGD(grd)->fakecorr[fcbeg].ftyp; map_location(fcx, fcy, 1); /* bypass vision */ if(!ACCESSIBLE(levl[fcx][fcy].typ)) block_point(fcx,fcy); EGD(grd)->fcbeg++; } if(grd->mhp <= 0) { pline_The("corridor disappears."); if(IS_ROCK(levl[u.ux][u.uy].typ)) You("are encased in rock."); } return(TRUE); } STATIC_OVL void restfakecorr(grd) register struct monst *grd; { /* it seems you left the corridor - let the guard disappear */ if(clear_fcorr(grd, FALSE)) mongone(grd); } boolean grddead(grd) /* called in mon.c */ register struct monst *grd; { register boolean dispose = clear_fcorr(grd, TRUE); if(!dispose) { /* see comment by newpos in gd_move() */ remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, 0, 0); EGD(grd)->ogx = grd->mx; EGD(grd)->ogy = grd->my; dispose = clear_fcorr(grd, TRUE); } return(dispose); } STATIC_OVL boolean in_fcorridor(grd, x, y) register struct monst *grd; int x, y; { register int fci; for(fci = EGD(grd)->fcbeg; fci < EGD(grd)->fcend; fci++) if(x == EGD(grd)->fakecorr[fci].fx && y == EGD(grd)->fakecorr[fci].fy) return(TRUE); return(FALSE); } STATIC_OVL struct monst * findgd() { register struct monst *mtmp; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->isgd && !DEADMONSTER(mtmp) && on_level(&(EGD(mtmp)->gdlevel), &u.uz)) return(mtmp); return((struct monst *)0); } #endif /* OVLB */ #ifdef OVL0 char vault_occupied(array) char *array; { register char *ptr; for (ptr = array; *ptr; ptr++) if (rooms[*ptr - ROOMOFFSET].rtype == VAULT) return(*ptr); return('\0'); } void invault() { #ifdef BSD_43_BUG int dummy; /* hack to avoid schain botch */ #endif struct monst *guard; int vaultroom = (int)vault_occupied(u.urooms); if(!vaultroom) { u.uinvault = 0; return; } vaultroom -= ROOMOFFSET; guard = findgd(); if(++u.uinvault % 30 == 0 && !guard) { /* if time ok and no guard now. */ char buf[BUFSZ]; register int x, y, dd, gx, gy; int lx = 0, ly = 0; /* first find the goal for the guard */ for(dd = 2; (dd < ROWNO || dd < COLNO); dd++) { for(y = u.uy-dd; y <= u.uy+dd; ly = y, y++) { if(y < 0 || y > ROWNO-1) continue; for(x = u.ux-dd; x <= u.ux+dd; lx = x, x++) { if(y != u.uy-dd && y != u.uy+dd && x != u.ux-dd) x = u.ux+dd; if(x < 1 || x > COLNO-1) continue; if(levl[x][y].typ == CORR) { if(x < u.ux) lx = x + 1; else if(x > u.ux) lx = x - 1; else lx = x; if(y < u.uy) ly = y + 1; else if(y > u.uy) ly = y - 1; else ly = y; if(levl[lx][ly].typ != STONE && levl[lx][ly].typ != CORR) goto incr_radius; goto fnd; } } } incr_radius: ; } impossible("Not a single corridor on this level??"); tele(); return; fnd: gx = x; gy = y; /* next find a good place for a door in the wall */ x = u.ux; y = u.uy; if(levl[x][y].typ != ROOM) { /* player dug a door and is in it */ if(levl[x+1][y].typ == ROOM) x = x + 1; else if(levl[x][y+1].typ == ROOM) y = y + 1; else if(levl[x-1][y].typ == ROOM) x = x - 1; else if(levl[x][y-1].typ == ROOM) y = y - 1; else if(levl[x+1][y+1].typ == ROOM) { x = x + 1; y = y + 1; } else if (levl[x-1][y-1].typ == ROOM) { x = x - 1; y = y - 1; } else if (levl[x+1][y-1].typ == ROOM) { x = x + 1; y = y - 1; } else if (levl[x-1][y+1].typ == ROOM) { x = x - 1; y = y + 1; } } while(levl[x][y].typ == ROOM) { register int dx,dy; dx = (gx > x) ? 1 : (gx < x) ? -1 : 0; dy = (gy > y) ? 1 : (gy < y) ? -1 : 0; if(abs(gx-x) >= abs(gy-y)) x += dx; else y += dy; } if(x == u.ux && y == u.uy) { if(levl[x+1][y].typ == HWALL || levl[x+1][y].typ == DOOR) x = x + 1; else if(levl[x-1][y].typ == HWALL || levl[x-1][y].typ == DOOR) x = x - 1; else if(levl[x][y+1].typ == VWALL || levl[x][y+1].typ == DOOR) y = y + 1; else if(levl[x][y-1].typ == VWALL || levl[x][y-1].typ == DOOR) y = y - 1; else return; } /* make something interesting happen */ if(!(guard = makemon(&mons[PM_GUARD], x, y, NO_MM_FLAGS))) return; guard->isgd = 1; guard->mpeaceful = 1; set_malign(guard); EGD(guard)->gddone = 0; EGD(guard)->ogx = x; EGD(guard)->ogy = y; assign_level(&(EGD(guard)->gdlevel), &u.uz); EGD(guard)->vroom = vaultroom; EGD(guard)->warncnt = 0; if(!cansee(guard->mx, guard->my)) { mongone(guard); return; } reset_faint(); /* if fainted - wake up */ pline("Suddenly one of the Vault's guards enters!"); newsym(guard->mx,guard->my); if (Strangled || youmonst.data->msound == MS_SILENT) { verbalize("I'll be back when you're ready to speak to me!"); mongone(guard); return; } stop_occupation(); /* if occupied, stop it *now* */ do { getlin("\"Hello stranger, who are you?\" -",buf); } while (!letter(buf[0])); if (u.ualign.type == A_LAWFUL && /* ignore trailing text, in case player includes character's rank */ strncmpi(buf, plname, (int) strlen(plname)) != 0) { adjalign(-1); /* Liar! */ } if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos") #ifdef TOURIST || !strcmpi(buf, "Creosote") #endif ) { if (!mvitals[PM_CROESUS].died) { verbalize("Oh, yes, of course. Sorry to have disturbed you."); mongone(guard); } else { setmangry(guard); verbalize("Back from the dead, are you? I'll remedy that!"); /* don't want guard to waste next turn wielding a weapon */ if (!MON_WEP(guard)) { guard->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(guard); } } return; } verbalize("I don't know you."); if (!u.ugold && !hidden_gold()) verbalize("Please follow me."); else { if (!u.ugold) verbalize("You have hidden gold."); verbalize("Most likely all your gold was stolen from this vault."); verbalize("Please drop that gold and follow me."); } EGD(guard)->gdx = gx; EGD(guard)->gdy = gy; EGD(guard)->fcbeg = 0; EGD(guard)->fakecorr[0].fx = x; EGD(guard)->fakecorr[0].fy = y; if(IS_WALL(levl[x][y].typ)) EGD(guard)->fakecorr[0].ftyp = levl[x][y].typ; else { /* the initial guard location is a dug door */ int vlt = EGD(guard)->vroom; xchar lowx = rooms[vlt].lx, hix = rooms[vlt].hx; xchar lowy = rooms[vlt].ly, hiy = rooms[vlt].hy; if(x == lowx-1 && y == lowy-1) EGD(guard)->fakecorr[0].ftyp = TLCORNER; else if(x == hix+1 && y == lowy-1) EGD(guard)->fakecorr[0].ftyp = TRCORNER; else if(x == lowx-1 && y == hiy+1) EGD(guard)->fakecorr[0].ftyp = BLCORNER; else if(x == hix+1 && y == hiy+1) EGD(guard)->fakecorr[0].ftyp = BRCORNER; else if(y == lowy-1 || y == hiy+1) EGD(guard)->fakecorr[0].ftyp = HWALL; else if(x == lowx-1 || x == hix+1) EGD(guard)->fakecorr[0].ftyp = VWALL; } levl[x][y].typ = DOOR; levl[x][y].doormask = D_NODOOR; unblock_point(x, y); /* doesn't block light */ EGD(guard)->fcend = 1; EGD(guard)->warncnt = 1; } } #endif /* OVL0 */ #ifdef OVLB STATIC_OVL void move_gold(gold, vroom) struct obj *gold; int vroom; { xchar nx, ny; remove_object(gold); newsym(gold->ox, gold->oy); nx = rooms[vroom].lx + rn2(2); ny = rooms[vroom].ly + rn2(2); place_object(gold, nx, ny); stackobj(gold); newsym(nx,ny); } STATIC_OVL void wallify_vault(grd) struct monst *grd; { int x, y; int vlt = EGD(grd)->vroom; char tmp_viz; xchar lowx = rooms[vlt].lx, hix = rooms[vlt].hx; xchar lowy = rooms[vlt].ly, hiy = rooms[vlt].hy; register struct obj *gold; register boolean fixed = FALSE; register boolean movedgold = FALSE; for(x = lowx-1; x <= hix+1; x++) for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) { if(!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) { if(MON_AT(x, y) && grd->mx != x && grd->my != y) { struct monst *mon = m_at(x,y); if (mon->mtame) yelp(mon); rloc(mon); } if ((gold = g_at(x, y)) != 0) { move_gold(gold, EGD(grd)->vroom); movedgold = TRUE; } if(x == lowx-1 && y == lowy-1) levl[x][y].typ = TLCORNER; else if(x == hix+1 && y == lowy-1) levl[x][y].typ = TRCORNER; else if(x == lowx-1 && y == hiy+1) levl[x][y].typ = BLCORNER; else if(x == hix+1 && y == hiy+1) levl[x][y].typ = BRCORNER; else levl[x][y].typ = HWALL; levl[x][y].doormask = 0; /* * hack: player knows walls are restored because of the * message, below, so show this on the screen. */ tmp_viz = viz_array[y][x]; viz_array[y][x] = IN_SIGHT|COULD_SEE; newsym(x,y); viz_array[y][x] = tmp_viz; block_point(x,y); fixed = TRUE; } } for(x = lowx-1; x <= hix+1; x += (hix-lowx+2)) for(y = lowy; y <= hiy; y++) { if(!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) { if(MON_AT(x, y) && grd->mx != x && grd->my != y) { struct monst *mon = m_at(x,y); if (mon->mtame) yelp(mon); rloc(mon); } if ((gold = g_at(x, y)) != 0) { move_gold(gold, EGD(grd)->vroom); movedgold = TRUE; } levl[x][y].typ = VWALL; levl[x][y].doormask = 0; tmp_viz = viz_array[y][x]; viz_array[y][x] = IN_SIGHT|COULD_SEE; newsym(x,y); viz_array[y][x] = tmp_viz; block_point(x,y); fixed = TRUE; } } if(movedgold || fixed) { if(in_fcorridor(grd, grd->mx, grd->my) || cansee(grd->mx, grd->my)) pline_The("guard whispers an incantation."); else You_hear("a distant chant."); if(movedgold) pline("A mysterious force moves the gold into the vault."); if(fixed) pline_The("damaged vault's walls are magically restored!"); } } /* * return 1: guard moved, 0: guard didn't, -1: let m_move do it, -2: died */ int gd_move(grd) register struct monst *grd; { int x, y, nx, ny, m, n; int dx, dy, gx, gy, fci; uchar typ; struct fakecorridor *fcp; register struct egd *egrd = EGD(grd); register struct rm *crm; register boolean goldincorridor = FALSE, u_in_vault = vault_occupied(u.urooms)? TRUE : FALSE, grd_in_vault = *in_rooms(grd->mx, grd->my, VAULT)? TRUE : FALSE; boolean disappear_msg_seen = FALSE, semi_dead = (grd->mhp <= 0); register boolean u_carry_gold = ((u.ugold + hidden_gold()) > 0L); if(!on_level(&(egrd->gdlevel), &u.uz)) return(-1); nx = ny = m = n = 0; if(!u_in_vault && !grd_in_vault) wallify_vault(grd); if(!grd->mpeaceful) { if(semi_dead) { egrd->gddone =1; goto newpos; } if(!u_in_vault && (grd_in_vault || (in_fcorridor(grd, grd->mx, grd->my) && !in_fcorridor(grd, u.ux, u.uy)))) { rloc(grd); wallify_vault(grd); (void) clear_fcorr(grd, TRUE); goto letknow; } if(!in_fcorridor(grd, grd->mx, grd->my)) (void) clear_fcorr(grd, TRUE); return(-1); } if(abs(egrd->ogx - grd->mx) > 1 || abs(egrd->ogy - grd->my) > 1) return(-1); /* teleported guard - treat as monster */ if(egrd->fcend == 1) { if(u_in_vault && (u_carry_gold || um_dist(grd->mx, grd->my, 1))) { if(egrd->warncnt == 3) verbalize("I repeat, %sfollow me!", u_carry_gold ? (!u.ugold ? "drop that hidden gold and " : "drop that gold and ") : ""); if(egrd->warncnt == 7) { m = grd->mx; n = grd->my; verbalize("You've been warned, knave!"); mnexto(grd); levl[m][n].typ = egrd->fakecorr[0].ftyp; newsym(m,n); grd->mpeaceful = 0; return(-1); } /* not fair to get mad when (s)he's fainted or paralyzed */ if(!is_fainted() && multi >= 0) egrd->warncnt++; return(0); } if (!u_in_vault) { if (u_carry_gold) { /* player teleported */ m = grd->mx; n = grd->my; rloc(grd); levl[m][n].typ = egrd->fakecorr[0].ftyp; newsym(m,n); grd->mpeaceful = 0; letknow: if(!cansee(grd->mx, grd->my)) You_hear("the shrill sound of a guard's whistle."); else You(um_dist(grd->mx, grd->my, 2) ? "see an angry %s approaching." : "are confronted by an angry %s.", l_monnam(grd)); return(-1); } else { verbalize("Well, begone."); wallify_vault(grd); egrd->gddone = 1; goto cleanup; } } } if(egrd->fcend > 1) { if(egrd->fcend > 2 && in_fcorridor(grd, grd->mx, grd->my) && !egrd->gddone && !in_fcorridor(grd, u.ux, u.uy) && levl[egrd->fakecorr[0].fx][egrd->fakecorr[0].fy].typ == egrd->fakecorr[0].ftyp) { pline_The("guard, confused, disappears."); disappear_msg_seen = TRUE; goto cleanup; } if(u_carry_gold && (in_fcorridor(grd, u.ux, u.uy) || /* cover a 'blind' spot */ (egrd->fcend > 1 && u_in_vault))) { if(!grd->mx) { restfakecorr(grd); return(-2); } if(egrd->warncnt < 6) { egrd->warncnt = 6; verbalize("Drop all your gold, scoundrel!"); return(0); } else { verbalize("So be it, rogue!"); grd->mpeaceful = 0; return(-1); } } } for(fci = egrd->fcbeg; fci < egrd->fcend; fci++) if(g_at(egrd->fakecorr[fci].fx, egrd->fakecorr[fci].fy)){ m = egrd->fakecorr[fci].fx; n = egrd->fakecorr[fci].fy; goldincorridor = TRUE; } if(goldincorridor && !egrd->gddone) { x = grd->mx; y = grd->my; if (m == u.ux && n == u.uy) { struct obj *gold = g_at(m,n); /* Grab the gold from between the hero's feet. */ grd->mgold += gold->quan; delobj(gold); newsym(m,n); } else if (m == x && n == y) { mpickgold(grd); /* does a newsym */ } else { /* just for insurance... */ if (MON_AT(m, n) && m != grd->mx && n != grd->my) { verbalize("Out of my way, scum!"); rloc(m_at(m, n)); } remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, m, n); mpickgold(grd); /* does a newsym */ } if(cansee(m,n)) pline("%s%s picks up the gold.", Monnam(grd), grd->mpeaceful ? " calms down and" : ""); if(x != grd->mx || y != grd->my) { remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, x, y); newsym(x, y); } if(!grd->mpeaceful) return(-1); else { egrd->warncnt = 5; return(0); } } if(um_dist(grd->mx, grd->my, 1) || egrd->gddone) { if(!egrd->gddone && !rn2(10)) verbalize("Move along!"); restfakecorr(grd); return(0); /* didn't move */ } x = grd->mx; y = grd->my; if(u_in_vault) goto nextpos; /* 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) && (nx != x || ny != y) && isok(nx, ny)) { typ = (crm = &levl[nx][ny])->typ; if(!IS_STWALL(typ) && !IS_POOL(typ)) { if(in_fcorridor(grd, nx, ny)) goto nextnxy; if(*in_rooms(nx,ny,VAULT)) continue; /* seems we found a good place to leave him alone */ egrd->gddone = 1; if(ACCESSIBLE(typ)) goto newpos; #ifdef STUPID if (typ == SCORR) crm->typ = CORR; else crm->typ = DOOR; #else crm->typ = (typ == SCORR) ? CORR : DOOR; #endif if(crm->typ == DOOR) crm->doormask = D_NODOOR; goto proceed; } } nextnxy: ; } nextpos: nx = x; ny = y; gx = egrd->gdx; gy = egrd->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) && !IS_POOL(typ) && IS_ROOM(levl[nx+nx-x][ny+ny-y].typ)){ crm->typ = DOOR; crm->doormask = D_NODOOR; 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 ... */ if(IS_ROOM(typ)) { crm->typ = DOOR; crm->doormask = D_NODOOR; goto proceed; } break; } crm->typ = CORR; proceed: unblock_point(nx, ny); /* doesn't block light */ if (cansee(nx,ny)) newsym(nx,ny); fcp = &(egrd->fakecorr[egrd->fcend]); if(egrd->fcend++ == FCSIZ) panic("fakecorr overflow"); fcp->fx = nx; fcp->fy = ny; fcp->ftyp = typ; newpos: if(egrd->gddone) { /* The following is a kludge. We need to keep */ /* the guard around in order to be able to make */ /* the fake corridor disappear as the player */ /* moves out of it, but we also need the guard */ /* out of the way. We send the guard to never- */ /* never land. We set ogx ogy to mx my in order */ /* to avoid a check at the top of this function. */ /* At the end of the process, the guard is killed */ /* in restfakecorr(). */ cleanup: x = grd->mx; y = grd->my; wallify_vault(grd); remove_monster(grd->mx, grd->my); newsym(grd->mx,grd->my); place_monster(grd, 0, 0); egrd->ogx = grd->mx; egrd->ogy = grd->my; restfakecorr(grd); if(!semi_dead && (in_fcorridor(grd, u.ux, u.uy) || cansee(x, y))) { if (!disappear_msg_seen) pline("Suddenly, the guard disappears."); return(1); } return(-2); } egrd->ogx = grd->mx; /* update old positions */ egrd->ogy = grd->my; remove_monster(grd->mx, grd->my); place_monster(grd, nx, ny); newsym(grd->mx,grd->my); restfakecorr(grd); return(1); } /* Routine when dying or quitting with a vault guard around */ void paygd() { register struct monst *grd = findgd(); struct obj *gold; int gx,gy; char buf[BUFSZ]; if (!u.ugold || !grd) return; if (u.uinvault) { Your("%ld zorkmid%s goes into the Magic Memory Vault.", u.ugold, plur(u.ugold)); gx = u.ux; gy = u.uy; } else { if(grd->mpeaceful) { /* guard has no "right" to your gold */ mongone(grd); return; } mnexto(grd); pline("%s remits your gold to the vault.", Monnam(grd)); gx = rooms[EGD(grd)->vroom].lx + rn2(2); gy = rooms[EGD(grd)->vroom].ly + rn2(2); Sprintf(buf, "To Croesus: here's the gold recovered from %s the %s.", plname, mons[u.umonster].mname); make_grave(gx, gy, buf); } place_object(gold = mkgoldobj(u.ugold), gx, gy); stackobj(gold); mongone(grd); } long hidden_gold() { register long value = 0L; register struct obj *obj; for (obj = invent; obj; obj = obj->nobj) if (Has_contents(obj)) value += contained_gold(obj); /* unknown gold stuck inside statues may cause some consternation... */ return(value); } boolean gd_sound() /* prevent "You hear footsteps.." when inappropriate */ { register struct monst *grd = findgd(); if (vault_occupied(u.urooms)) return(FALSE); else return((boolean)(grd == (struct monst *)0)); } #endif /* OVLB */ /*vault.c*/