int do_mname(const struct nh_cmd_arg *arg) { coord cc; int cx, cy; struct monst *mtmp; const char *qbuf, *buf; if (Hallucination) { pline(msgc_cancelled, "You would never recognize it anyway."); return 0; } cc.x = youmonst.mx; cc.y = youmonst.my; if (getargpos(arg, &cc, FALSE, "the monster you want to name") == NHCR_CLIENT_CANCEL || (cx = cc.x) < 0) return 0; cy = cc.y; if (cx == youmonst.mx && cy == youmonst.my) { if (u.usteed && canspotmon(u.usteed)) mtmp = u.usteed; else { pline(msgc_cancelled, "This %s creature is called %s and cannot be renamed.", beautiful(), u.uplname); return 0; } } else mtmp = vismon_at(level, cx, cy); unsigned msense_status = mtmp ? msensem(&youmonst, mtmp) : 0; if (!(msense_status & ~MSENSE_ITEMMIMIC)) { pline(msgc_mispaste, "I see no monster there."); return 0; } else if (!(msense_status & (MSENSE_ANYDETECT | MSENSE_ANYVISION))) { pline(msgc_cancelled, "You can't see it well enough to recognise it in the future."); return 0; } /* special case similar to the one in lookat() */ qbuf = distant_monnam(mtmp, NULL, ARTICLE_THE); qbuf = msgprintf("What do you want to call %s?", qbuf); buf = getarglin(arg, qbuf); if (!*buf || *buf == '\033') return 0; /* strip leading and trailing spaces; unnames monster if all spaces */ buf = msgmungspaces(buf); if (mtmp->data->geno & G_UNIQ) { qbuf = msgupcasefirst(distant_monnam(mtmp, NULL, ARTICLE_THE)); pline(msgc_cancelled, "%s doesn't like being called names!", qbuf); } else christen_monst(mtmp, buf); return 0; }
/* * This routine changes the address of obj. Be careful not to call it * when there might be pointers around in unknown places. For now: only * when obj is in the inventory. */ int do_oname(const struct nh_cmd_arg *arg) { const char *qbuf, *buf; const char *aname; short objtyp; struct obj *obj; obj = getargobj(arg, nameable, "name"); if (!obj) return 0; qbuf = msgprintf("What do you want to name %s %s?", is_plural(obj) ? "these" : "this", safe_qbuf("", sizeof("What do you want to name these ?"), xname(obj), simple_typename(obj->otyp), is_plural(obj) ? "things" : "thing")); buf = getarglin(arg, qbuf); if (!*buf || *buf == '\033') return 0; /* strip leading and trailing spaces; unnames item if all spaces */ buf = msgmungspaces(buf); /* relax restrictions over proper capitalization for artifacts */ if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp) buf = aname; char slipbuf[strlen(buf) + 1]; if (obj->oartifact) { pline("The artifact seems to resist the attempt."); return 0; } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) { int n = rn2((int)strlen(buf)); char c1, c2; strcpy(slipbuf, buf); c1 = lowc(buf[n]); do c2 = 'a' + rn2('z' - 'a' + 1); while (c1 == c2); slipbuf[n] = (slipbuf[n] == c1) ? c2 : highc(c2); /* keep same case */ pline("While engraving your %s slips.", body_part(HAND)); win_pause_output(P_MESSAGE); pline("You engrave: \"%s\".", slipbuf); buf = slipbuf; } oname(obj, buf); return 0; }
static void docall_inner(const struct nh_cmd_arg *arg, int otyp) { const char *qbuf, *buf; char **str1; const char *ot = obj_typename(otyp); qbuf = "Call "; if (strstr(ot, " boots") || strstr(ot, " gloves")) qbuf = msgcat(qbuf, ot); else qbuf = msgcat(qbuf, an(ot)); qbuf = msgcat(qbuf, ":"); buf = getarglin(arg, qbuf); if (!*buf || *buf == '\033') return; /* clear old name */ str1 = &(objects[otyp].oc_uname); if (*str1) free(*str1); /* strip leading and trailing spaces; uncalls item if all spaces */ buf = msgmungspaces(buf); if (!*buf) { if (*str1) { /* had name, so possibly remove from disco[] */ /* strip name first, for the update_inventory() call from undiscover_object() */ *str1 = (char *)0; undiscover_object(otyp); } } else { *str1 = strcpy((char *)malloc((unsigned)strlen(buf) + 1), buf); discover_object(otyp, FALSE, TRUE, TRUE); /* possibly add to disco[] */ } }
int dowrite(struct obj *pen, const struct nh_cmd_arg *arg) { struct obj *paper; const char *namebuf, *nm, *bp; struct obj *new_obj; int basecost, actualcost; int curseval; const char *qbuf; int first, last, i; boolean by_descr = FALSE, by_name = FALSE; const char *typeword; if (nohands(youmonst.data)) { pline(msgc_cancelled, "You need hands to be able to write!"); return 0; } else if (slippery_fingers(&youmonst)) { pline(msgc_cancelled1, "%s from your %s.", Tobjnam(pen, "slip"), makeplural(body_part(FINGER))); unwield_silently(pen); dropx(pen); return 1; } /* get paper to write on */ paper = getargobj(arg, write_on, "write on"); if (!paper) return 0; typeword = (paper->oclass == SPBOOK_CLASS) ? "spellbook" : "scroll"; if (Blind && !paper->dknown) { pline(msgc_cancelled1, "You don't know if that %s is blank or not!", typeword); return 1; } paper->dknown = 1; if (paper->otyp != SCR_BLANK_PAPER && paper->otyp != SPE_BLANK_PAPER) { pline(msgc_cancelled1, "That %s is not blank!", typeword); exercise(A_WIS, FALSE); return 1; } /* what to write */ qbuf = msgprintf("What type of %s do you want to write?", typeword); namebuf = getarglin(arg, qbuf); namebuf = msgmungspaces(namebuf); /* remove any excess whitespace */ if (namebuf[0] == '\033' || !namebuf[0]) return 1; nm = namebuf; if (!strncmpi(nm, "scroll ", 7)) nm += 7; else if (!strncmpi(nm, "spellbook ", 10)) nm += 10; if (!strncmpi(nm, "of ", 3)) nm += 3; if ((bp = strstri(nm, " armour")) != 0) nm = msgcat_many(msgchop(nm, bp-nm), " armor", bp+7, NULL); first = bases[(int)paper->oclass]; last = bases[(int)paper->oclass + 1] - 1; for (i = first; i <= last; i++) { /* extra shufflable descr not representing a real object */ if (!OBJ_NAME(objects[i])) continue; if (!strcmpi(OBJ_NAME(objects[i]), nm)) goto found; if (!strcmpi(OBJ_DESCR(objects[i]), nm)) { by_descr = TRUE; goto found; } if (objects[i].oc_uname && !strcmpi(objects[i].oc_uname, nm)) { by_name = TRUE; goto found; } } pline(msgc_cancelled1, "There is no such %s!", typeword); return 1; found: if (i == SCR_BLANK_PAPER || i == SPE_BLANK_PAPER) { pline(msgc_cancelled1, "You can't write that!"); pline(msgc_cancelled1, "It's obscene!"); return 1; } else if (i == SPE_BOOK_OF_THE_DEAD) { pline(msgc_cancelled1, "No mere dungeon adventurer could write that."); return 1; } else if ((by_descr || by_name) && paper->oclass == SPBOOK_CLASS && !objects[i].oc_name_known) { /* can't write unknown spellbooks by description */ pline(msgc_cancelled1, "Unfortunately you don't have enough information to go on."); return 1; } /* KMH, conduct */ break_conduct(conduct_illiterate); new_obj = mksobj(level, i, FALSE, FALSE, rng_main); new_obj->bknown = (paper->bknown && pen->bknown); /* shk imposes a flat rate per use, not based on actual charges used */ check_unpaid(pen); /* see if there's enough ink */ basecost = cost(new_obj); if (pen->spe < basecost / 2) { pline(msgc_failcurse, "Your marker is too dry to write that!"); obfree(new_obj, NULL); return 1; } /* we're really going to write now, so calculate cost no custom RNG used: too much influence from player actions */ actualcost = rn1(basecost / 2, basecost / 2); curseval = bcsign(pen) + bcsign(paper); exercise(A_WIS, TRUE); /* dry out marker */ if (pen->spe < actualcost) { pen->spe = 0; pline(msgc_itemloss, "Your marker dries out!"); /* scrolls disappear, spellbooks don't */ if (paper->oclass == SPBOOK_CLASS) { pline(msgc_failcurse, "The spellbook is left unfinished and your writing fades."); update_inventory(); /* pen charges */ } else { pline(msgc_failcurse, "The scroll is now useless and disappears!"); useup(paper); } obfree(new_obj, NULL); return 1; } pen->spe -= actualcost; /* can't write if we don't know it - unless we're lucky */ if (!(objects[new_obj->otyp].oc_name_known) && (rnl(Role_if(PM_WIZARD) ? 3 : 15))) { pline(msgc_failrandom, "You %s to write that!", by_descr ? "fail" : "don't know how"); /* scrolls disappear, spellbooks don't */ if (paper->oclass == SPBOOK_CLASS) { pline_implied(msgc_failrandom, "You write in your best handwriting: " "\"My Diary\", but it quickly fades."); update_inventory(); /* pen charges */ } else { const char *written; if (by_descr) { written = OBJ_DESCR(objects[new_obj->otyp]); written = eroded_text(written, (6 + MAXULEV - youmonst.m_lev) / 6, 0); } else written = msgprintf("%s was here!", u.uplname); pline_implied(msgc_failrandom, "You write \"%s\" and the scroll disappears.", written); useup(paper); } obfree(new_obj, NULL); return 1; } /* useup old scroll / spellbook */ useup(paper); /* success */ if (new_obj->oclass == SPBOOK_CLASS) { /* acknowledge the change in the object's description... */ pline(msgc_actionok, "The spellbook warps strangely, then turns %s.", OBJ_DESCR(objects[new_obj->otyp])); } new_obj->blessed = (curseval > 0); new_obj->cursed = (curseval < 0); hold_another_object(new_obj, "Oops! %s out of your grasp!", The(aobjnam(new_obj, "slip")), NULL); return 1; }
/* So you want music... */ int do_play_instrument(struct obj *instr, const struct nh_cmd_arg *arg) { char c = 'y'; const char *buf; int x, y; boolean ok; if (Underwater) { pline(msgc_cancelled, "You can't play music underwater!"); return 0; } if (Upolyd && !can_blow_instrument(youmonst.data) && (instr->otyp == BUGLE || instr->otyp == WOODEN_FLUTE || instr->otyp == MAGIC_FLUTE || instr->otyp == TOOLED_HORN || instr->otyp == FIRE_HORN || instr->otyp == FROST_HORN)) { pline(msgc_cancelled, "You are incapable of playing %s in your current form!", the(xname(instr))); return 0; } if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) { c = yn("Improvise?"); } if (c == 'n') { if (u.uevent.uheard_tune == 2 && yn("Play the passtune?") == 'y') { buf = msg_from_string(gamestate.castle_tune); } else { /* Note: This is explicitly not getarglin(); we don't want command repeat to repeat the tune. */ buf = getlin("What tune are you playing? [5 notes, A-G]", FALSE); if (*buf == '\033') buf = ""; buf = msgmungspaces(buf); /* convert to uppercase and change any "H" to the expected "B" */ buf = msgcaseconv(buf, highc_htob, highc_htob, highc_htob); } pline(msgc_occstart, "You extract a strange sound from %s!", the(xname(instr))); /* Check if there was the Stronghold drawbridge near and if the tune conforms to what we're waiting for. */ if (Is_stronghold(&u.uz)) { exercise(A_WIS, TRUE); /* just for trying */ if (!strcmp(buf, gamestate.castle_tune)) { /* Search for the drawbridge */ for (y = youmonst.my - 1; y <= youmonst.my + 1; y++) for (x = youmonst.mx - 1; x <= youmonst.mx + 1; x++) if (isok(x, y)) if (find_drawbridge(&x, &y)) { /* tune now fully known */ u.uevent.uheard_tune = 2; if (level->locations[x][y].typ == DRAWBRIDGE_DOWN) close_drawbridge(x, y); else open_drawbridge(x, y); return 1; } } else if (canhear()) { if (u.uevent.uheard_tune < 1) u.uevent.uheard_tune = 1; /* Okay, it wasn't the right tune, but perhaps we can give the player some hints like in the Mastermind game */ ok = FALSE; for (y = youmonst.my - 1; y <= youmonst.my + 1 && !ok; y++) for (x = youmonst.mx - 1; x <= youmonst.mx + 1 && !ok; x++) if (isok(x, y)) if (IS_DRAWBRIDGE(level->locations[x][y].typ) || is_drawbridge_wall(x, y) >= 0) ok = TRUE; if (ok) { /* There is a drawbridge near */ int tumblers, gears; boolean matched[5]; tumblers = gears = 0; for (x = 0; x < 5; x++) matched[x] = FALSE; for (x = 0; x < (int)strlen(buf); x++) if (x < 5) { if (buf[x] == gamestate.castle_tune[x]) { gears++; matched[x] = TRUE; } else for (y = 0; y < 5; y++) if (!matched[y] && buf[x] == gamestate.castle_tune[y] && buf[y] != gamestate.castle_tune[y]) { tumblers++; matched[y] = TRUE; break; } } if (tumblers) if (gears) You_hear(msgc_hint, "%d tumbler%s click and %d gear%s turn.", tumblers, plur(tumblers), gears, plur(gears)); else You_hear(msgc_hint, "%d tumbler%s click.", tumblers, plur(tumblers)); else if (gears) { You_hear(msgc_hint, "%d gear%s turn.", gears, plur(gears)); /* could only get `gears == 5' by playing five correct notes followed by excess; otherwise, tune would have matched above */ if (gears == 5) u.uevent.uheard_tune = 2; } } } } return 1; } else return do_improvisation(instr, arg); }
void invault(void) { struct monst *guard; int trycount, vaultroom = (int)vault_occupied(u.urooms); boolean messages = TRUE; if (!vaultroom) { u.uinvault = 0; return; } vaultroom -= ROOMOFFSET; guard = findgd(); if (++u.uinvault % 30 == 0 && !guard) { /* if time ok and no guard now. */ int x, y, gx, gy; xchar rx, ry; long umoney; const char *buf; /* first find the goal for the guard */ if (!find_guard_dest(NULL, &rx, &ry)) return; gx = rx; gy = ry; /* next find a good place for a door in the wall */ x = u.ux; y = u.uy; if (level->locations[x][y].typ != ROOM) { /* player dug a door and is in it */ if (level->locations[x + 1][y].typ == ROOM) x = x + 1; else if (level->locations[x][y + 1].typ == ROOM) y = y + 1; else if (level->locations[x - 1][y].typ == ROOM) x = x - 1; else if (level->locations[x][y - 1].typ == ROOM) y = y - 1; else if (level->locations[x + 1][y + 1].typ == ROOM) { x = x + 1; y = y + 1; } else if (level->locations[x - 1][y - 1].typ == ROOM) { x = x - 1; y = y - 1; } else if (level->locations[x + 1][y - 1].typ == ROOM) { x = x + 1; y = y - 1; } else if (level->locations[x - 1][y + 1].typ == ROOM) { x = x - 1; y = y + 1; } } while (level->locations[x][y].typ == ROOM) { 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 (level->locations[x + 1][y].typ == HWALL || level->locations[x + 1][y].typ == DOOR) x = x + 1; else if (level->locations[x - 1][y].typ == HWALL || level->locations[x - 1][y].typ == DOOR) x = x - 1; else if (level->locations[x][y + 1].typ == VWALL || level->locations[x][y + 1].typ == DOOR) y = y + 1; else if (level->locations[x][y - 1].typ == VWALL || level->locations[x][y - 1].typ == DOOR) y = y - 1; else return; } /* make something interesting happen */ if (!(guard = makemon(&mons[PM_GUARD], level, x, y, NO_MM_FLAGS))) return; guard->isgd = 1; msethostility(guard, FALSE, TRUE); 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; /* We used to reset fainted status here, but that doesn't really make sense; instead, that's treated like normal helplessness */ if (canspotmon(guard)) pline("Suddenly one of the Vault's guards enters!"); else if (canhear()) You_hear("someone else enter the Vault."); else messages = FALSE; newsym(guard->mx, guard->my); if (youmonst.m_ap_type == M_AP_OBJECT || u.uundetected || u.uburied) { if (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance != GOLD_PIECE) verbalize("Hey! Who left that %s in here?", mimic_obj_name(&youmonst)); /* You're mimicking some object or you're hidden. */ if (messages) pline("Puzzled, %s turns around and leaves.", mhe(guard)); mongone(guard); return; } if (Engulfed) { if ((!u.ustuck->minvis || perceives(guard->data))) verbalize("How did that %s get in here?", m_monnam(u.ustuck)); if (messages) pline("Puzzled, %s turns around and leaves.", mhe(guard)); mongone(guard); return; } if (Strangled || is_silent(youmonst.data) || u_helpless(hm_all)) { /* [we ought to record whether this this message has already been given in order to vary it upon repeat visits, but discarding the monster and its egd data renders that hard] */ verbalize("I'll be back when you're ready to speak to me!"); mongone(guard); return; } action_interrupted(); trycount = 5; do { buf = getlin("\"Hello stranger, who are you?\" -", FALSE); buf = msgmungspaces(buf); } while (!letter(buf[0]) && --trycount > 0); if (u.ualign.type == A_LAWFUL && /* ignore trailing text, in case player includes character's rank */ strncmpi(buf, u.uplname, (int)strlen(u.uplname)) != 0) { adjalign(-1); /* Liar! */ } if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos") || !strcmpi(buf, "Creosote")) { 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; mon_wield_item(guard); } } return; } verbalize("I don't know you."); umoney = money_cnt(invent); if (!umoney && !hidden_gold()) verbalize("Please follow me."); else { if (!umoney) verbalize("You have hidden money."); verbalize("Most likely all your money was stolen from this vault."); verbalize("Please drop that money 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(level->locations[x][y].typ)) EGD(guard)->fakecorr[0].ftyp = level->locations[x][y].typ; else { /* the initial guard location is a dug door */ int vlt = EGD(guard)->vroom; xchar lowx = level->rooms[vlt].lx, hix = level->rooms[vlt].hx; xchar lowy = level->rooms[vlt].ly, hiy = level->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; } level->locations[x][y].typ = DOOR; level->locations[x][y].doormask = D_NODOOR; unblock_point(x, y); /* doesn't block light */ EGD(guard)->fcend = 1; EGD(guard)->warncnt = 1; } }