1 /* SCCS Id: @(#)vault.c 3.4 2003/01/15 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
8 STATIC_DCL struct monst *NDECL(findgd);
10 #define g_monnam(mtmp) \
11 x_monnam(mtmp, ARTICLE_NONE, (char *)0, SUPPRESS_IT, FALSE)
15 STATIC_DCL boolean FDECL(clear_fcorr, (struct monst *,BOOLEAN_P));
16 STATIC_DCL void FDECL(restfakecorr,(struct monst *));
17 STATIC_DCL boolean FDECL(in_fcorridor, (struct monst *,int,int));
18 STATIC_DCL void FDECL(move_gold,(struct obj *,int));
19 STATIC_DCL void FDECL(wallify_vault,(struct monst *));
22 clear_fcorr(grd, forceshow)
23 register struct monst *grd;
24 register boolean forceshow;
26 register int fcx, fcy, fcbeg;
27 register struct monst *mtmp;
29 if (!on_level(&(EGD(grd)->gdlevel), &u.uz)) return TRUE;
31 while((fcbeg = EGD(grd)->fcbeg) < EGD(grd)->fcend) {
32 fcx = EGD(grd)->fakecorr[fcbeg].fx;
33 fcy = EGD(grd)->fakecorr[fcbeg].fy;
34 if((grd->mhp <= 0 || !in_fcorridor(grd, u.ux, u.uy)) &&
37 if((u.ux == fcx && u.uy == fcy && grd->mhp > 0)
38 || (!forceshow && couldsee(fcx,fcy))
39 || (Punished && !carried(uball)
40 && uball->ox == fcx && uball->oy == fcy))
43 if ((mtmp = m_at(fcx,fcy)) != 0) {
44 if(mtmp->isgd) return(FALSE);
45 else if(!in_fcorridor(grd, u.ux, u.uy)) {
46 if(mtmp->mtame) yelp(mtmp);
47 (void) rloc(mtmp, FALSE);
50 levl[fcx][fcy].typ = EGD(grd)->fakecorr[fcbeg].ftyp;
51 map_location(fcx, fcy, 1); /* bypass vision */
52 if(!ACCESSIBLE(levl[fcx][fcy].typ)) block_point(fcx,fcy);
56 pline_The("corridor disappears.");
57 if(IS_ROCK(levl[u.ux][u.uy].typ)) You("are encased in rock.");
64 register struct monst *grd;
66 /* it seems you left the corridor - let the guard disappear */
67 if(clear_fcorr(grd, FALSE)) mongone(grd);
71 grddead(grd) /* called in mon.c */
72 register struct monst *grd;
74 register boolean dispose = clear_fcorr(grd, TRUE);
77 /* see comment by newpos in gd_move() */
78 remove_monster(grd->mx, grd->my);
79 newsym(grd->mx, grd->my);
80 place_monster(grd, 0, 0);
81 EGD(grd)->ogx = grd->mx;
82 EGD(grd)->ogy = grd->my;
83 dispose = clear_fcorr(grd, TRUE);
89 in_fcorridor(grd, x, y)
90 register struct monst *grd;
95 for(fci = EGD(grd)->fcbeg; fci < EGD(grd)->fcend; fci++)
96 if(x == EGD(grd)->fakecorr[fci].fx &&
97 y == EGD(grd)->fakecorr[fci].fy)
106 register struct monst *mtmp;
108 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
109 if(mtmp->isgd && !DEADMONSTER(mtmp) && on_level(&(EGD(mtmp)->gdlevel), &u.uz))
111 return((struct monst *)0);
118 vault_occupied(array)
123 for (ptr = array; *ptr; ptr++)
124 if (rooms[*ptr - ROOMOFFSET].rtype == VAULT)
133 int dummy; /* hack to avoid schain botch */
136 int trycount, vaultroom = (int)vault_occupied(u.urooms);
143 vaultroom -= ROOMOFFSET;
146 if(++u.uinvault % 30 == 0 && !guard) { /* if time ok and no guard now. */
148 register int x, y, dd, gx, gy;
153 /* first find the goal for the guard */
154 for(dd = 2; (dd < ROWNO || dd < COLNO); dd++) {
155 for(y = u.uy-dd; y <= u.uy+dd; ly = y, y++) {
156 if(y < 0 || y > ROWNO-1) continue;
157 for(x = u.ux-dd; x <= u.ux+dd; lx = x, x++) {
158 if(y != u.uy-dd && y != u.uy+dd && x != u.ux-dd)
160 if(x < 1 || x > COLNO-1) continue;
161 if(levl[x][y].typ == CORR) {
162 if(x < u.ux) lx = x + 1;
163 else if(x > u.ux) lx = x - 1;
165 if(y < u.uy) ly = y + 1;
166 else if(y > u.uy) ly = y - 1;
168 if(levl[lx][ly].typ != STONE && levl[lx][ly].typ != CORR)
176 impossible("Not a single corridor on this level??");
182 /* next find a good place for a door in the wall */
184 if(levl[x][y].typ != ROOM) { /* player dug a door and is in it */
185 if(levl[x+1][y].typ == ROOM) x = x + 1;
186 else if(levl[x][y+1].typ == ROOM) y = y + 1;
187 else if(levl[x-1][y].typ == ROOM) x = x - 1;
188 else if(levl[x][y-1].typ == ROOM) y = y - 1;
189 else if(levl[x+1][y+1].typ == ROOM) {
192 } else if (levl[x-1][y-1].typ == ROOM) {
195 } else if (levl[x+1][y-1].typ == ROOM) {
198 } else if (levl[x-1][y+1].typ == ROOM) {
203 while(levl[x][y].typ == ROOM) {
206 dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
207 dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
208 if(abs(gx-x) >= abs(gy-y))
213 if(x == u.ux && y == u.uy) {
214 if(levl[x+1][y].typ == HWALL || levl[x+1][y].typ == DOOR)
216 else if(levl[x-1][y].typ == HWALL || levl[x-1][y].typ == DOOR)
218 else if(levl[x][y+1].typ == VWALL || levl[x][y+1].typ == DOOR)
220 else if(levl[x][y-1].typ == VWALL || levl[x][y-1].typ == DOOR)
225 /* make something interesting happen */
226 if(!(guard = makemon(&mons[PM_GUARD], x, y, NO_MM_FLAGS))) return;
228 guard->mpeaceful = 1;
230 EGD(guard)->gddone = 0;
233 assign_level(&(EGD(guard)->gdlevel), &u.uz);
234 EGD(guard)->vroom = vaultroom;
235 EGD(guard)->warncnt = 0;
237 reset_faint(); /* if fainted - wake up */
238 if (canspotmon(guard))
239 pline("Suddenly one of the Vault's %s enters!",
240 makeplural(g_monnam(guard)));
242 pline("Someone else has entered the Vault.");
243 newsym(guard->mx,guard->my);
244 if (youmonst.m_ap_type == M_AP_OBJECT || u.uundetected) {
245 if (youmonst.m_ap_type == M_AP_OBJECT &&
246 youmonst.mappearance != GOLD_PIECE)
247 verbalize("Hey! Who left that %s in here?", mimic_obj_name(&youmonst));
248 /* You're mimicking some object or you're hidden. */
249 pline("Puzzled, %s turns around and leaves.", mhe(guard));
253 if (Strangled || is_silent(youmonst.data) || multi < 0) {
254 /* [we ought to record whether this this message has already
255 been given in order to vary it upon repeat visits, but
256 discarding the monster and its egd data renders that hard] */
257 verbalize("I'll be back when you're ready to speak to me!");
262 stop_occupation(); /* if occupied, stop it *now* */
263 if (multi > 0) { nomul(0); unmul((char *)0); }
266 getlin("\"Hello stranger, who are you?\" -", buf);
267 (void) mungspaces(buf);
268 } while (!letter(buf[0]) && --trycount > 0);
270 if (u.ualign.type == A_LAWFUL &&
271 /* ignore trailing text, in case player includes character's rank */
272 strncmpi(buf, plname, (int) strlen(plname)) != 0) {
273 adjalign(-1); /* Liar! */
276 if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos")
278 || !strcmpi(buf, "Creosote")
281 if (!mvitals[PM_CROESUS].died) {
282 verbalize("Oh, yes, of course. Sorry to have disturbed you.");
286 verbalize("Back from the dead, are you? I'll remedy that!");
287 /* don't want guard to waste next turn wielding a weapon */
288 if (!MON_WEP(guard)) {
289 guard->weapon_check = NEED_HTH_WEAPON;
290 (void) mon_wield_item(guard);
295 verbalize("I don't know you.");
297 if (!u.ugold && !hidden_gold())
298 verbalize("Please follow me.");
301 verbalize("You have hidden gold.");
302 verbalize("Most likely all your gold was stolen from this vault.");
303 verbalize("Please drop that gold and follow me.");
306 umoney = money_cnt(invent);
307 if (!umoney && !hidden_gold())
308 verbalize("Please follow me.");
311 verbalize("You have hidden money.");
312 verbalize("Most likely all your money was stolen from this vault.");
313 verbalize("Please drop that money and follow me.");
316 EGD(guard)->gdx = gx;
317 EGD(guard)->gdy = gy;
318 EGD(guard)->fcbeg = 0;
319 EGD(guard)->fakecorr[0].fx = x;
320 EGD(guard)->fakecorr[0].fy = y;
321 if(IS_WALL(levl[x][y].typ))
322 EGD(guard)->fakecorr[0].ftyp = levl[x][y].typ;
323 else { /* the initial guard location is a dug door */
324 int vlt = EGD(guard)->vroom;
325 xchar lowx = rooms[vlt].lx, hix = rooms[vlt].hx;
326 xchar lowy = rooms[vlt].ly, hiy = rooms[vlt].hy;
328 if(x == lowx-1 && y == lowy-1)
329 EGD(guard)->fakecorr[0].ftyp = TLCORNER;
330 else if(x == hix+1 && y == lowy-1)
331 EGD(guard)->fakecorr[0].ftyp = TRCORNER;
332 else if(x == lowx-1 && y == hiy+1)
333 EGD(guard)->fakecorr[0].ftyp = BLCORNER;
334 else if(x == hix+1 && y == hiy+1)
335 EGD(guard)->fakecorr[0].ftyp = BRCORNER;
336 else if(y == lowy-1 || y == hiy+1)
337 EGD(guard)->fakecorr[0].ftyp = HWALL;
338 else if(x == lowx-1 || x == hix+1)
339 EGD(guard)->fakecorr[0].ftyp = VWALL;
341 levl[x][y].typ = DOOR;
342 levl[x][y].doormask = D_NODOOR;
343 unblock_point(x, y); /* doesn't block light */
344 EGD(guard)->fcend = 1;
345 EGD(guard)->warncnt = 1;
353 move_gold(gold, vroom)
360 newsym(gold->ox, gold->oy);
361 nx = rooms[vroom].lx + rn2(2);
362 ny = rooms[vroom].ly + rn2(2);
363 place_object(gold, nx, ny);
373 int vlt = EGD(grd)->vroom;
375 xchar lox = rooms[vlt].lx - 1, hix = rooms[vlt].hx + 1,
376 loy = rooms[vlt].ly - 1, hiy = rooms[vlt].hy + 1;
380 boolean fixed = FALSE;
381 boolean movedgold = FALSE;
383 for (x = lox; x <= hix; x++)
384 for (y = loy; y <= hiy; y++) {
385 /* if not on the room boundary, skip ahead */
386 if (x != lox && x != hix && y != loy && y != hiy) continue;
388 if (!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) {
389 if ((mon = m_at(x, y)) != 0 && mon != grd) {
390 if (mon->mtame) yelp(mon);
391 (void) rloc(mon, FALSE);
393 if ((gold = g_at(x, y)) != 0) {
394 move_gold(gold, EGD(grd)->vroom);
397 if ((trap = t_at(x, y)) != 0)
400 typ = (y == loy) ? TLCORNER :
401 (y == hiy) ? BLCORNER : VWALL;
403 typ = (y == loy) ? TRCORNER :
404 (y == hiy) ? BRCORNER : VWALL;
405 else /* not left or right side, must be top or bottom */
407 levl[x][y].typ = typ;
408 levl[x][y].doormask = 0;
410 * hack: player knows walls are restored because of the
411 * message, below, so show this on the screen.
413 tmp_viz = viz_array[y][x];
414 viz_array[y][x] = IN_SIGHT|COULD_SEE;
416 viz_array[y][x] = tmp_viz;
422 if(movedgold || fixed) {
423 if(in_fcorridor(grd, grd->mx, grd->my) || cansee(grd->mx, grd->my))
424 pline_The("%s whispers an incantation.", g_monnam(grd));
425 else You_hear("a distant chant.");
427 pline("A mysterious force moves the gold into the vault.");
429 pline_The("damaged vault's walls are magically restored!");
434 * return 1: guard moved, 0: guard didn't, -1: let m_move do it, -2: died
438 register struct monst *grd;
440 int x, y, nx, ny, m, n;
441 int dx, dy, gx, gy, fci;
443 struct fakecorridor *fcp;
444 register struct egd *egrd = EGD(grd);
445 register struct rm *crm;
446 register boolean goldincorridor = FALSE,
447 u_in_vault = vault_occupied(u.urooms)? TRUE : FALSE,
448 grd_in_vault = *in_rooms(grd->mx, grd->my, VAULT)?
450 boolean disappear_msg_seen = FALSE, semi_dead = (grd->mhp <= 0);
452 register boolean u_carry_gold = ((u.ugold + hidden_gold()) > 0L);
454 long umoney = money_cnt(invent);
455 register boolean u_carry_gold = ((umoney + hidden_gold()) > 0L);
459 if(!on_level(&(egrd->gdlevel), &u.uz)) return(-1);
461 if(!u_in_vault && !grd_in_vault)
463 if(!grd->mpeaceful) {
470 (in_fcorridor(grd, grd->mx, grd->my) &&
471 !in_fcorridor(grd, u.ux, u.uy)))) {
472 (void) rloc(grd, FALSE);
474 (void) clear_fcorr(grd, TRUE);
477 if(!in_fcorridor(grd, grd->mx, grd->my))
478 (void) clear_fcorr(grd, TRUE);
481 if(abs(egrd->ogx - grd->mx) > 1 ||
482 abs(egrd->ogy - grd->my) > 1)
483 return(-1); /* teleported guard - treat as monster */
484 if(egrd->fcend == 1) {
486 (u_carry_gold || um_dist(grd->mx, grd->my, 1))) {
487 if(egrd->warncnt == 3)
488 verbalize("I repeat, %sfollow me!",
492 "drop that hidden gold and " :
493 "drop that gold and ") : "");
496 "drop that hidden money and " :
497 "drop that money and ") : "");
499 if(egrd->warncnt == 7) {
502 verbalize("You've been warned, knave!");
504 levl[m][n].typ = egrd->fakecorr[0].ftyp;
509 /* not fair to get mad when (s)he's fainted or paralyzed */
510 if(!is_fainted() && multi >= 0) egrd->warncnt++;
515 if (u_carry_gold) { /* player teleported */
518 (void) rloc(grd, FALSE);
519 levl[m][n].typ = egrd->fakecorr[0].ftyp;
523 if (!cansee(grd->mx, grd->my) || !mon_visible(grd))
524 You_hear("the shrill sound of a guard's whistle.");
526 You(um_dist(grd->mx, grd->my, 2) ?
527 "see an angry %s approaching." :
528 "are confronted by an angry %s.",
532 verbalize("Well, begone.");
540 if(egrd->fcend > 1) {
541 if(egrd->fcend > 2 && in_fcorridor(grd, grd->mx, grd->my) &&
542 !egrd->gddone && !in_fcorridor(grd, u.ux, u.uy) &&
543 levl[egrd->fakecorr[0].fx][egrd->fakecorr[0].fy].typ
544 == egrd->fakecorr[0].ftyp) {
545 pline_The("%s, confused, disappears.", g_monnam(grd));
546 disappear_msg_seen = TRUE;
550 (in_fcorridor(grd, u.ux, u.uy) ||
551 /* cover a 'blind' spot */
552 (egrd->fcend > 1 && u_in_vault))) {
557 if(egrd->warncnt < 6) {
559 verbalize("Drop all your gold, scoundrel!");
562 verbalize("So be it, rogue!");
568 for(fci = egrd->fcbeg; fci < egrd->fcend; fci++)
569 if(g_at(egrd->fakecorr[fci].fx, egrd->fakecorr[fci].fy)){
570 m = egrd->fakecorr[fci].fx;
571 n = egrd->fakecorr[fci].fy;
572 goldincorridor = TRUE;
574 if(goldincorridor && !egrd->gddone) {
577 if (m == u.ux && n == u.uy) {
578 struct obj *gold = g_at(m,n);
579 /* Grab the gold from between the hero's feet. */
581 grd->mgold += gold->quan;
584 obj_extract_self(gold);
585 add_to_minv(grd, gold);
588 } else if (m == x && n == y) {
589 mpickgold(grd); /* does a newsym */
591 /* just for insurance... */
592 if (MON_AT(m, n) && m != grd->mx && n != grd->my) {
593 verbalize("Out of my way, scum!");
594 (void) rloc(m_at(m, n), FALSE);
596 remove_monster(grd->mx, grd->my);
597 newsym(grd->mx, grd->my);
598 place_monster(grd, m, n);
599 mpickgold(grd); /* does a newsym */
602 pline("%s%s picks up the gold.", Monnam(grd),
603 grd->mpeaceful ? " calms down and" : "");
604 if(x != grd->mx || y != grd->my) {
605 remove_monster(grd->mx, grd->my);
606 newsym(grd->mx, grd->my);
607 place_monster(grd, x, y);
610 if(!grd->mpeaceful) return(-1);
616 if(um_dist(grd->mx, grd->my, 1) || egrd->gddone) {
617 if(!egrd->gddone && !rn2(10)) verbalize("Move along!");
619 return(0); /* didn't move */
624 if(u_in_vault) goto nextpos;
626 /* look around (hor & vert only) for accessible places */
627 for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++) {
628 if((nx == x || ny == y) && (nx != x || ny != y) && isok(nx, ny)) {
630 typ = (crm = &levl[nx][ny])->typ;
631 if(!IS_STWALL(typ) && !IS_POOL(typ)) {
633 if(in_fcorridor(grd, nx, ny))
636 if(*in_rooms(nx,ny,VAULT))
639 /* seems we found a good place to leave him alone */
641 if(ACCESSIBLE(typ)) goto newpos;
648 crm->typ = (typ == SCORR) ? CORR : DOOR;
650 if(crm->typ == DOOR) crm->doormask = D_NODOOR;
661 dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
662 dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
663 if(abs(gx-x) >= abs(gy-y)) nx += dx; else ny += dy;
665 while((typ = (crm = &levl[nx][ny])->typ) != 0) {
666 /* in view of the above we must have IS_WALL(typ) or typ == POOL */
667 /* must be a wall here */
668 if(isok(nx+nx-x,ny+ny-y) && !IS_POOL(typ) &&
669 IS_ROOM(levl[nx+nx-x][ny+ny-y].typ)){
671 crm->doormask = D_NODOOR;
679 ny = y; nx = x+dx; dy = 0;
682 /* I don't like this, but ... */
685 crm->doormask = D_NODOOR;
692 unblock_point(nx, ny); /* doesn't block light */
696 fcp = &(egrd->fakecorr[egrd->fcend]);
697 if(egrd->fcend++ == FCSIZ) panic("fakecorr overflow");
703 /* The following is a kludge. We need to keep */
704 /* the guard around in order to be able to make */
705 /* the fake corridor disappear as the player */
706 /* moves out of it, but we also need the guard */
707 /* out of the way. We send the guard to never- */
708 /* never land. We set ogx ogy to mx my in order */
709 /* to avoid a check at the top of this function. */
710 /* At the end of the process, the guard is killed */
711 /* in restfakecorr(). */
713 x = grd->mx; y = grd->my;
715 see_guard = canspotmon(grd);
717 remove_monster(grd->mx, grd->my);
718 newsym(grd->mx,grd->my);
719 place_monster(grd, 0, 0);
723 if(!semi_dead && (in_fcorridor(grd, u.ux, u.uy) ||
725 if (!disappear_msg_seen && see_guard)
726 pline("Suddenly, the %s disappears.", g_monnam(grd));
731 egrd->ogx = grd->mx; /* update old positions */
733 remove_monster(grd->mx, grd->my);
734 place_monster(grd, nx, ny);
735 newsym(grd->mx,grd->my);
740 /* Routine when dying or quitting with a vault guard around */
744 register struct monst *grd = findgd();
748 long umoney = money_cnt(invent);
749 struct obj *coins, *nextcoins;
755 if (!u.ugold || !grd) return;
757 if (!umoney || !grd) return;
761 Your("%ld %s goes into the Magic Memory Vault.",
772 if(grd->mpeaceful) { /* guard has no "right" to your gold */
777 pline("%s remits your gold to the vault.", Monnam(grd));
778 gx = rooms[EGD(grd)->vroom].lx + rn2(2);
779 gy = rooms[EGD(grd)->vroom].ly + rn2(2);
781 "To Croesus: here's the gold recovered from %s the %s.",
782 plname, mons[u.umonster].mname);
783 make_grave(gx, gy, buf);
786 place_object(gold = mkgoldobj(u.ugold), gx, gy);
789 for (coins = invent; coins; coins = nextcoins) {
790 nextcoins = coins->nobj;
791 if (objects[coins->otyp].oc_class == COIN_CLASS) {
793 place_object(coins, gx, gy);
804 register long value = 0L;
805 register struct obj *obj;
807 for (obj = invent; obj; obj = obj->nobj)
808 if (Has_contents(obj))
809 value += contained_gold(obj);
810 /* unknown gold stuck inside statues may cause some consternation... */
816 gd_sound() /* prevent "You hear footsteps.." when inappropriate */
818 register struct monst *grd = findgd();
820 if (vault_occupied(u.urooms)) return(FALSE);
821 else return((boolean)(grd == (struct monst *)0));