static void makeniche(bool with_trap) { struct mkroom *aroom; struct rm *rm; int vct = 8; coord dd; int dy,xx,yy; struct trap *ttmp; if(doorindex < DOORMAX) while(vct--) { aroom = &rooms[rn2(nroom-1)]; if(aroom->rtype != 0) continue; /* not an ordinary room */ if(aroom->doorct == 1 && rn2(5)) continue; if(rn2(2)) { dy = 1; dd = finddpos(aroom->lx,aroom->hy+1,aroom->hx,aroom->hy+1); } else { dy = -1; dd = finddpos(aroom->lx,aroom->ly-1,aroom->hx,aroom->ly-1); } xx = dd.x; yy = dd.y; if((rm = &levl[xx][yy+dy])->typ) continue; if(with_trap || !rn2(4)) { rm->typ = SCORR; rm->scrsym = ' '; if(with_trap) { ttmp = maketrap(xx, yy+dy, TELEP_TRAP); ttmp->once = 1; make_engr_at(xx, yy-dy, "ad ae?ar um"); } dosdoor(xx, yy, aroom, SDOOR); } else { rm->typ = CORR; rm->scrsym = CORR_SYM; if(rn2(7)) dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR); else { mksobj_at(SCR_TELEPORTATION, xx, yy+dy); if(!rn2(3)) mkobj_at(0, xx, yy+dy); } } return; } }
/* stock a newly-created room with objects */ void stock_room(int shp_indx, struct level *lev, struct mkroom *sroom) { /* * Someday soon we'll dispatch on the shdist field of shclass to do * different placements in this routine. Currently it only supports * shop-style placement (all squares except a row nearest the first * door get objects). */ int sx, sy, sh; int rmno = (sroom - lev->rooms) + ROOMOFFSET; const struct shclass *shp = &shtypes[shp_indx]; /* first, try to place a shopkeeper in the room */ if ((sh = shkinit(shp, lev, sroom)) < 0) return; /* make sure no doorways without doors, and no */ /* trapped doors, in shops. */ sx = lev->doors[sroom->fdoor].x; sy = lev->doors[sroom->fdoor].y; if (lev->locations[sx][sy].doormask == D_NODOOR) { lev->locations[sx][sy].doormask = D_ISOPEN; if (lev == level) newsym(sx, sy); } if (lev->locations[sx][sy].typ == SDOOR) { cvt_sdoor_to_door(&lev->locations[sx][sy], &lev->z); /* .typ = DOOR */ if (lev == level) newsym(sx, sy); } if (lev->locations[sx][sy].doormask & D_TRAPPED) lev->locations[sx][sy].doormask = D_LOCKED; if (lev->locations[sx][sy].doormask == D_LOCKED) { int m = sx, n = sy; if (inside_shop(lev, sx + 1, sy)) m--; else if (inside_shop(lev, sx - 1, sy)) m++; if (inside_shop(lev, sx, sy + 1)) n--; else if (inside_shop(lev, sx, sy - 1)) n++; make_engr_at(lev, m, n, "Closed for inventory", 0L, DUST); } for (sx = sroom->lx; sx <= sroom->hx; sx++) for (sy = sroom->ly; sy <= sroom->hy; sy++) { if (sroom->irregular) { if (lev->locations[sx][sy].edge || (int)lev->locations[sx][sy].roomno != rmno || distmin(sx, sy, lev->doors[sh].x, lev->doors[sh].y) <= 1) continue; } else if ((sx == sroom->lx && lev->doors[sh].x == sx - 1) || (sx == sroom->hx && lev->doors[sh].x == sx + 1) || (sy == sroom->ly && lev->doors[sh].y == sy - 1) || (sy == sroom->hy && lev->doors[sh].y == sy + 1)) continue; mkshobj_at(shp, lev, sx, sy); } /* * Special monster placements (if any) should go here: that way, * monsters will sit on top of objects and not the other way around. */ }
/* return 1 if action took 1 (or more) moves, 0 if error or aborted */ int doengrave(struct obj *otmp) { boolean dengr = FALSE; /* TRUE if we wipe out the current engraving */ boolean doblind = FALSE;/* TRUE if engraving blinds the player */ boolean doknown = FALSE;/* TRUE if we identify the stylus */ boolean eow = FALSE; /* TRUE if we are overwriting oep */ boolean jello = FALSE; /* TRUE if we are engraving in slime */ boolean ptext = TRUE; /* TRUE if we must prompt for engrave text */ boolean teleengr =FALSE;/* TRUE if we move the old engraving */ boolean zapwand = FALSE;/* TRUE if we remove a wand charge */ xchar type = DUST; /* Type of engraving made */ char buf[BUFSZ]; /* Buffer for final/poly engraving text */ char ebuf[BUFSZ]; /* Buffer for initial engraving text */ char qbuf[QBUFSZ]; /* Buffer for query text */ char post_engr_text[BUFSZ]; /* Text displayed after engraving prompt */ const char *everb; /* Present tense of engraving type */ const char *eloc; /* Where the engraving is (ie dust/floor/...) */ char *sp; /* Place holder for space count of engr text */ int len; /* # of nonspace chars of new engraving text */ int maxelen; /* Max allowable length of engraving text */ struct engr *oep = engr_at(level, u.ux,u.uy); /* The current engraving */ char *writer; multi = 0; /* moves consumed */ nomovemsg = NULL; /* occupation end message */ buf[0] = (char)0; ebuf[0] = (char)0; post_engr_text[0] = (char)0; maxelen = BUFSZ - 1; if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE) type = ENGR_BLOOD; /* Can the adventurer engrave at all? */ if (u.uswallow) { if (is_animal(u.ustuck->data)) { pline("What would you write? \"Jonah was here\"?"); return 0; } else if (is_whirly(u.ustuck->data)) { pline("You can't reach the %s.", surface(u.ux,u.uy)); return 0; } else jello = TRUE; } else if (is_lava(level, u.ux, u.uy)) { pline("You can't write on the lava!"); return 0; } else if (Underwater) { pline("You can't write underwater!"); return 0; } else if (is_pool(level, u.ux,u.uy) || IS_FOUNTAIN(level->locations[u.ux][u.uy].typ)) { pline("You can't write on the water!"); return 0; } if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)/* in bubble */) { pline("You can't write in thin air!"); return 0; } if (cantwield(youmonst.data)) { pline("You can't even hold anything!"); return 0; } if (check_capacity(NULL)) return 0; /* One may write with finger, or weapon, or wand, or..., or... * Edited by GAN 10/20/86 so as not to change weapon wielded. */ if (otmp && !validate_object(otmp, styluses, "write with")) return 0; else if (!otmp) otmp = getobj(styluses, "write with"); if (!otmp) return 0; /* otmp == zeroobj if fingers */ if (otmp == &zeroobj) writer = makeplural(body_part(FINGER)); else writer = xname(otmp); /* There's no reason you should be able to write with a wand * while both your hands are tied up. */ if (!freehand() && otmp != uwep && !otmp->owornmask) { pline("You have no free %s to write with!", body_part(HAND)); return 0; } if (jello) { pline("You tickle %s with your %s.", mon_nam(u.ustuck), writer); pline("Your message dissolves..."); return 0; } if (otmp->oclass != WAND_CLASS && !can_reach_floor()) { pline("You can't reach the %s!", surface(u.ux,u.uy)); return 0; } if (IS_ALTAR(level->locations[u.ux][u.uy].typ)) { pline("You make a motion towards the altar with your %s.", writer); altar_wrath(u.ux, u.uy); return 0; } if (IS_GRAVE(level->locations[u.ux][u.uy].typ)) { if (otmp == &zeroobj) { /* using only finger */ pline("You would only make a small smudge on the %s.", surface(u.ux, u.uy)); return 0; } else if (!level->locations[u.ux][u.uy].disturbed) { pline("You disturb the undead!"); level->locations[u.ux][u.uy].disturbed = 1; makemon(&mons[PM_GHOUL], level, u.ux, u.uy, NO_MM_FLAGS); exercise(A_WIS, FALSE); return 1; } } /* SPFX for items */ switch (otmp->oclass) { default: case AMULET_CLASS: case CHAIN_CLASS: case POTION_CLASS: case COIN_CLASS: break; case RING_CLASS: /* "diamond" rings and others should work */ case GEM_CLASS: /* diamonds & other hard gems should work */ if (objects[otmp->otyp].oc_tough) { type = ENGRAVE; break; } break; case ARMOR_CLASS: if (is_boots(otmp)) { type = DUST; break; } /* fall through */ /* Objects too large to engrave with */ case BALL_CLASS: case ROCK_CLASS: pline("You can't engrave with such a large object!"); ptext = FALSE; break; /* Objects too silly to engrave with */ case FOOD_CLASS: case SCROLL_CLASS: case SPBOOK_CLASS: pline("Your %s would get %s.", xname(otmp), is_ice(level, u.ux, u.uy) ? "all frosty" : "too dirty"); ptext = FALSE; break; case RANDOM_CLASS: /* This should mean fingers */ break; /* The charge is removed from the wand before prompting for * the engraving text, because all kinds of setup decisions * and pre-engraving messages are based upon knowing what type * of engraving the wand is going to do. Also, the player * will have potentially seen "You wrest .." message, and * therefore will know they are using a charge. */ case WAND_CLASS: if (zappable(otmp)) { check_unpaid(otmp); zapwand = TRUE; if (Levitation) ptext = FALSE; switch (otmp->otyp) { /* DUST wands */ default: break; /* NODIR wands */ case WAN_LIGHT: case WAN_SECRET_DOOR_DETECTION: case WAN_CREATE_MONSTER: case WAN_WISHING: case WAN_ENLIGHTENMENT: zapnodir(otmp); break; /* IMMEDIATE wands */ /* If wand is "IMMEDIATE", remember to affect the * previous engraving even if turning to dust. */ case WAN_STRIKING: strcpy(post_engr_text, "The wand unsuccessfully fights your attempt to write!" ); break; case WAN_SLOW_MONSTER: if (!Blind) { sprintf(post_engr_text, "The bugs on the %s slow down!", surface(u.ux, u.uy)); } break; case WAN_SPEED_MONSTER: if (!Blind) { sprintf(post_engr_text, "The bugs on the %s speed up!", surface(u.ux, u.uy)); } break; case WAN_POLYMORPH: if (oep) { if (!Blind) { type = (xchar)0; /* random */ random_engraving(buf); } dengr = TRUE; } break; case WAN_NOTHING: case WAN_UNDEAD_TURNING: case WAN_OPENING: case WAN_LOCKING: case WAN_PROBING: break; /* RAY wands */ case WAN_MAGIC_MISSILE: ptext = TRUE; if (!Blind) { sprintf(post_engr_text, "The %s is riddled by bullet holes!", surface(u.ux, u.uy)); } break; /* can't tell sleep from death - Eric Backus */ case WAN_SLEEP: case WAN_DEATH: if (!Blind) { sprintf(post_engr_text, "The bugs on the %s stop moving!", surface(u.ux, u.uy)); } break; case WAN_COLD: if (!Blind) strcpy(post_engr_text, "A few ice cubes drop from the wand."); if (!oep || (oep->engr_type != BURN)) break; case WAN_CANCELLATION: case WAN_MAKE_INVISIBLE: if (oep && oep->engr_type != HEADSTONE) { if (!Blind) pline("The engraving on the %s vanishes!", surface(u.ux,u.uy)); dengr = TRUE; } break; case WAN_TELEPORTATION: if (oep && oep->engr_type != HEADSTONE) { if (!Blind) pline("The engraving on the %s vanishes!", surface(u.ux,u.uy)); teleengr = TRUE; } break; /* type = ENGRAVE wands */ case WAN_DIGGING: ptext = TRUE; type = ENGRAVE; if (!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of digging!", xname(otmp)); doknown = TRUE; } if (!Blind) strcpy(post_engr_text, IS_GRAVE(level->locations[u.ux][u.uy].typ) ? "Chips fly out from the headstone." : is_ice(level, u.ux, u.uy) ? "Ice chips fly up from the ice surface!" : "Gravel flies up from the floor."); else strcpy(post_engr_text, "You hear drilling!"); break; /* type = BURN wands */ case WAN_FIRE: ptext = TRUE; type = BURN; if (!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of fire!", xname(otmp)); doknown = TRUE; } strcpy(post_engr_text, Blind ? "You feel the wand heat up." : "Flames fly from the wand."); break; case WAN_LIGHTNING: ptext = TRUE; type = BURN; if (!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of lightning!", xname(otmp)); doknown = TRUE; } if (!Blind) { strcpy(post_engr_text, "Lightning arcs from the wand."); doblind = TRUE; } else strcpy(post_engr_text, "You hear crackling!"); break; /* type = MARK wands */ /* type = ENGR_BLOOD wands */ } } else /* end if zappable */ if (!can_reach_floor()) { pline("You can't reach the %s!", surface(u.ux,u.uy)); /* If it's a wrestable wand, the player wasted a turn trying. */ if (wrestable(otmp)) return 1; else return 0; } break; case WEAPON_CLASS: if (is_blade(otmp)) { if ((int)otmp->spe > -3) type = ENGRAVE; else pline("Your %s too dull for engraving.", aobjnam(otmp,"are")); } break; case TOOL_CLASS: if (otmp == ublindf) { pline( "That is a bit difficult to engrave with, don't you think?"); return 0; } switch (otmp->otyp) { case MAGIC_MARKER: if (otmp->spe <= 0) pline("Your marker has dried out."); else type = MARK; break; case TOWEL: /* Can't really engrave with a towel */ ptext = FALSE; if (oep) if ((oep->engr_type == DUST ) || (oep->engr_type == ENGR_BLOOD) || (oep->engr_type == MARK )) { if (!Blind) pline("You wipe out the message here."); else pline("Your %s %s %s.", xname(otmp), otense(otmp, "get"), is_ice(level, u.ux, u.uy) ? "frosty" : "dusty"); dengr = TRUE; } else pline("Your %s can't wipe out this engraving.", xname(otmp)); else pline("Your %s %s %s.", xname(otmp), otense(otmp, "get"), is_ice(level, u.ux, u.uy) ? "frosty" : "dusty"); break; default: break; } break; case VENOM_CLASS: if (wizard) { pline("Writing a poison pen letter??"); break; } case ILLOBJ_CLASS: impossible("You're engraving with an illegal object!"); break; } if (IS_GRAVE(level->locations[u.ux][u.uy].typ)) { if (type == ENGRAVE || type == 0) type = HEADSTONE; else { /* ensures the "cannot wipe out" case */ type = DUST; dengr = FALSE; teleengr = FALSE; buf[0] = (char)0; } } /* End of implement setup */ /* Identify stylus */ if (doknown) { makeknown(otmp->otyp); more_experienced(0,10); } if (teleengr) { rloc_engr(oep); oep = NULL; } if (dengr) { del_engr(oep, level); oep = NULL; } /* Something has changed the engraving here */ if (*buf) { make_engr_at(level, u.ux, u.uy, buf, moves, type); pline("The engraving now reads: \"%s\".", buf); ptext = FALSE; } if (zapwand && (otmp->spe < 0)) { pline("%s %sturns to dust.", The(xname(otmp)), Blind ? "" : "glows violently, then "); if (!IS_GRAVE(level->locations[u.ux][u.uy].typ)) pline("You are not going to get anywhere trying to write in the %s with your dust.", is_ice(level, u.ux, u.uy) ? "frost" : "dust"); useup(otmp); ptext = FALSE; } if (!ptext) { /* Early exit for some implements. */ if (otmp->oclass == WAND_CLASS && !can_reach_floor()) pline("You can't reach the %s!", surface(u.ux,u.uy)); return 1; } /* Special effects should have deleted the current engraving (if * possible) by now. */ if (oep) { char c = 'n'; /* Give player the choice to add to engraving. */ if (type == HEADSTONE) { /* no choice, only append */ c = 'y'; } else if ( (type == oep->engr_type) && (!Blind || (oep->engr_type == BURN) || (oep->engr_type == ENGRAVE)) ) { c = yn_function("Do you want to add to the current engraving?", ynqchars, 'y'); if (c == 'q') { pline("Never mind."); return 0; } } if (c == 'n' || Blind) { if ( (oep->engr_type == DUST) || (oep->engr_type == ENGR_BLOOD) || (oep->engr_type == MARK) ) { if (!Blind) { pline("You wipe out the message that was %s here.", ((oep->engr_type == DUST) ? "written in the dust" : ((oep->engr_type == ENGR_BLOOD) ? "scrawled in blood" : "written"))); del_engr(oep, level); oep = NULL; } else /* Don't delete engr until after we *know* we're engraving */ eow = TRUE; } else if ( (type == DUST) || (type == MARK) || (type == ENGR_BLOOD) ) { pline( "You cannot wipe out the message that is %s the %s here.", oep->engr_type == BURN ? (is_ice(level, u.ux, u.uy) ? "melted into" : "burned into") : "engraved in", surface(u.ux,u.uy)); return 1; } else if ( (type != oep->engr_type) || (c == 'n') ) { if (!Blind || can_reach_floor()) pline("You will overwrite the current message."); eow = TRUE; } } } eloc = surface(u.ux,u.uy); switch(type){ default: everb = (oep && !eow ? "add to the weird writing on" : "write strangely on"); break; case DUST: everb = (oep && !eow ? "add to the writing in" : "write in"); eloc = is_ice(level, u.ux, u.uy) ? "frost" : "dust"; break; case HEADSTONE: everb = (oep && !eow ? "add to the epitaph on" : "engrave on"); break; case ENGRAVE: everb = (oep && !eow ? "add to the engraving in" : "engrave in"); break; case BURN: everb = (oep && !eow ? ( is_ice(level, u.ux,u.uy) ? "add to the text melted into" : "add to the text burned into") : ( is_ice(level, u.ux,u.uy) ? "melt into" : "burn into")); break; case MARK: everb = (oep && !eow ? "add to the graffiti on" : "scribble on"); break; case ENGR_BLOOD: everb = (oep && !eow ? "add to the scrawl on" : "scrawl on"); break; } /* Tell adventurer what is going on */ if (otmp != &zeroobj) pline("You %s the %s with %s.", everb, eloc, doname(otmp)); else pline("You %s the %s with your %s.", everb, eloc, makeplural(body_part(FINGER))); /* Prompt for engraving! */ sprintf(qbuf,"What do you want to %s the %s here?", everb, eloc); getlin(qbuf, ebuf); /* Count the actual # of chars engraved not including spaces */ len = strlen(ebuf); for (sp = ebuf; *sp; sp++) if (isspace(*sp)) len -= 1; if (len == 0 || strchr(ebuf, '\033')) { if (zapwand) { if (!Blind) pline("%s, then %s.", Tobjnam(otmp, "glow"), otense(otmp, "fade")); return 1; } else { pline("Never mind."); if (otmp && otmp->oclass == WAND_CLASS && wrestable(otmp)) return 1; /* disallow zero turn wrest */ else return 0; } } /* A single `x' is the traditional signature of an illiterate person */ if (len != 1 || (!strchr(ebuf, 'x') && !strchr(ebuf, 'X'))) u.uconduct.literate++; /* Mix up engraving if surface or state of mind is unsound. Note: this won't add or remove any spaces. */ for (sp = ebuf; *sp; sp++) { if (isspace(*sp)) continue; if (((type == DUST || type == ENGR_BLOOD) && !rn2(25)) || (Blind && !rn2(11)) || (Confusion && !rn2(7)) || (Stunned && !rn2(4)) || (Hallucination && !rn2(2))) *sp = ' ' + rnd(96 - 2); /* ASCII '!' thru '~' (excludes ' ' and DEL) */ } /* Previous engraving is overwritten */ if (eow) { del_engr(oep, level); oep = NULL; } /* Figure out how long it took to engrave, and if player has * engraved too much. */ switch(type){ default: multi = -(len/10); if (multi) nomovemsg = "You finish your weird engraving."; break; case DUST: multi = -(len/10); if (multi) nomovemsg = "You finish writing in the dust."; break; case HEADSTONE: case ENGRAVE: multi = -(len/10); if ((otmp->oclass == WEAPON_CLASS) && ((otmp->otyp != ATHAME) || otmp->cursed)) { multi = -len; maxelen = ((otmp->spe + 3) * 2) + 1; /* -2 = 3, -1 = 5, 0 = 7, +1 = 9, +2 = 11 * Note: this does not allow a +0 anything (except * an athame) to engrave "Elbereth" all at once. * However, you could now engrave "Elb", then * "ere", then "th". */ pline("Your %s dull.", aobjnam(otmp, "get")); if (otmp->unpaid) { struct monst *shkp = shop_keeper(level, *u.ushops); if (shkp) { pline("You damage it, you pay for it!"); bill_dummy_object(otmp); } } if (len > maxelen) { multi = -maxelen; otmp->spe = -3; } else if (len > 1) otmp->spe -= len >> 1; else otmp->spe -= 1; /* Prevent infinite engraving */ } else