void docall(struct obj *obj) { char buf[BUFSZ], qbuf[QBUFSZ]; struct obj otemp; char **str1; if (!obj->dknown) return; /* probably blind */ otemp = *obj; otemp.quan = 1L; otemp.onamelth = 0; otemp.oxlth = 0; if (objects[otemp.otyp].oc_class == POTION_CLASS && otemp.fromsink) /* kludge, meaning it's sink water */ sprintf(qbuf,"Call a stream of %s fluid:", OBJ_DESCR(objects[otemp.otyp])); else sprintf(qbuf, "Call %s:", an(xname(&otemp))); getlin(qbuf, buf); if (!*buf || *buf == '\033') return; /* clear old name */ str1 = &(objects[obj->otyp].oc_uname); if (*str1) free(*str1); /* strip leading and trailing spaces; uncalls item if all spaces */ mungspaces(buf); if (!*buf) { if (*str1) { /* had name, so possibly remove from disco[] */ /* strip name first, for the update_inventory() call from undiscover_object() */ *str1 = NULL; undiscover_object(obj->otyp); } } else { *str1 = strcpy(malloc((unsigned)strlen(buf)+1), buf); discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */ } }
/* Note: may return TRUE when mdef is blind (e.g. new cream-pie attack) */ boolean can_blnd(struct monst * magr, /* NULL == no specific aggressor */ struct monst * mdef, uchar aatyp, struct obj * obj) { /* aatyp == AT_WEAP, AT_SPIT */ boolean is_you = (mdef == &youmonst); boolean check_visor = FALSE; struct obj *o; const char *s; /* no eyes protect against all attacks for now */ if (!haseyes(mdef->data)) return FALSE; switch (aatyp) { case AT_EXPL: case AT_BOOM: case AT_GAZE: case AT_MAGC: case AT_BREA: /* assumed to be lightning */ /* light-based attacks may be cancelled or resisted */ if (magr && magr->mcan) return FALSE; return !resists_blnd(mdef); case AT_WEAP: case AT_SPIT: case AT_NONE: /* an object is used (thrown/spit/other) */ if (obj && (obj->otyp == CREAM_PIE)) { if (is_you && Blindfolded) return FALSE; } else if (obj && (obj->otyp == BLINDING_VENOM)) { /* all ublindf, including LENSES, protect, cream-pies too */ if (is_you && (ublindf || u.ucreamed)) return FALSE; check_visor = TRUE; } else if (obj && (obj->otyp == POT_BLINDNESS)) { return TRUE; /* no defense */ } else return FALSE; /* other objects cannot cause blindness yet */ if ((magr == &youmonst) && Engulfed) return FALSE; /* can't affect eyes while inside monster */ break; case AT_ENGL: if (is_you && (Blindfolded || u_helpless(hm_asleep) || u.ucreamed)) return FALSE; if (!is_you && mdef->msleeping) return FALSE; break; case AT_CLAW: /* e.g. raven: all ublindf, including LENSES, protect */ if (is_you && ublindf) return FALSE; if ((magr == &youmonst) && Engulfed) return FALSE; /* can't affect eyes while inside monster */ check_visor = TRUE; break; case AT_TUCH: case AT_STNG: /* some physical, blind-inducing attacks can be cancelled */ if (magr && magr->mcan) return FALSE; break; default: break; } /* check if wearing a visor (only checked if visor might help) */ if (check_visor) { o = (mdef == &youmonst) ? invent : mdef->minvent; for (; o; o = o->nobj) if ((o->owornmask & W_MASK(os_armh)) && (s = OBJ_DESCR(objects[o->otyp])) != NULL && !strcmp(s, "visored helmet")) return FALSE; } return TRUE; }
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; }
int use_saddle(struct obj *otmp, const struct nh_cmd_arg *arg) { struct monst *mtmp; const struct permonst *ptr; int chance; const char *s; schar dx, dy, dz; /* Can you use it? */ if (nohands(youmonst.data)) { pline("You have no hands!"); /* not `body_part(HAND)' */ return 0; } else if (!freehand()) { pline("You have no free %s.", body_part(HAND)); return 0; } /* Select an animal */ if (Engulfed || Underwater || !getargdir(arg, NULL, &dx, &dy, &dz)) { pline("Never mind."); return 0; } if (!dx && !dy) { pline("Saddle yourself? Very funny..."); return 0; } if (!isok(u.ux + dx, u.uy + dy) || !((mtmp = m_at(level, u.ux + dx, u.uy + dy))) || !canspotmon(mtmp)) { if (knownwormtail(u.ux + dx, u.uy + dy)) pline("It's hard to strap a saddle to a tail."); else pline("I see nobody there."); return 0; } /* Is this a valid monster? */ if (mtmp->misc_worn_check & W_MASK(os_saddle) || which_armor(mtmp, os_saddle)) { pline("%s doesn't need another one.", Monnam(mtmp)); return 0; } ptr = mtmp->data; if (!uarmg && touched_monster(ptr - mons)) { pline("You touch %s.", mon_nam(mtmp)); instapetrify(killer_msg(STONING, msgcat("attempting to saddle ", an(mtmp->data->mname)))); } if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) { pline("Shame on you!"); exercise(A_WIS, FALSE); return 1; } if (mtmp->isminion || mtmp->isshk || mtmp->ispriest || mtmp->isgd || mtmp->iswiz) { pline("I think %s would mind.", mon_nam(mtmp)); return 0; } if (!can_saddle(mtmp)) { pline("You can't saddle such a creature."); return 0; } /* Calculate your chance */ chance = ACURR(A_DEX) + ACURR(A_CHA) / 2 + 2 * mtmp->mtame; chance += u.ulevel * (mtmp->mtame ? 20 : 5); if (!mtmp->mtame) chance -= 10 * mtmp->m_lev; if (Role_if(PM_KNIGHT)) chance += 20; switch (P_SKILL(P_RIDING)) { case P_ISRESTRICTED: case P_UNSKILLED: default: chance -= 20; break; case P_BASIC: break; case P_SKILLED: chance += 15; break; case P_EXPERT: chance += 30; break; } if (Confusion || Fumbling || Glib) chance -= 20; else if (uarmg && (s = OBJ_DESCR(objects[uarmg->otyp])) != NULL && !strncmp(s, "riding ", 7)) /* Bonus for wearing "riding" (but not fumbling) gloves */ chance += 10; else if (uarmf && (s = OBJ_DESCR(objects[uarmf->otyp])) != NULL && !strncmp(s, "riding ", 7)) /* ... or for "riding boots" */ chance += 10; if (otmp->cursed) chance -= 50; /* steed becomes alert if possible */ maybewakesteed(mtmp); /* Make the attempt */ if (rn2(100) < chance) { pline("You put the saddle on %s.", mon_nam(mtmp)); if (otmp->owornmask) remove_worn_item(otmp, FALSE); freeinv(otmp); /* mpickobj may free otmp it if merges, but we have already checked for a saddle above, so no merger should happen */ mpickobj(mtmp, otmp); mtmp->misc_worn_check |= W_MASK(os_saddle); otmp->owornmask = W_MASK(os_saddle); otmp->leashmon = mtmp->m_id; update_mon_intrinsics(mtmp, otmp, TRUE, FALSE); } else pline("%s resists!", Monnam(mtmp)); return 1; }