static boolean artifact_hit_drainlife(struct monst *magr, struct monst *mdef, struct obj *otmp, int *dmgptr) { boolean youattack = (magr == &youmonst); boolean youdefend = (mdef == &youmonst); boolean vis = (!youattack && magr && cansee(magr->mx, magr->my)) || (!youdefend && cansee(mdef->mx, mdef->my)) || (youattack && u.uswallow && mdef == u.ustuck && !Blind); if (!youdefend) { if (vis) { if (otmp->oartifact == ART_STORMBRINGER) pline("The %s blade draws the life from %s!", hcolor("black"), mon_nam(mdef)); else pline("%s draws the life from %s!", The(distant_name(otmp, xname)), mon_nam(mdef)); } if (mdef->m_lev == 0) { *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER; } else { int drain = rnd(8); *dmgptr += drain; mdef->mhpmax -= drain; mdef->m_lev--; drain /= 2; if (drain) healup(drain, 0, FALSE, FALSE); } return vis; } else { /* youdefend */ int oldhpmax = u.uhpmax; if (Blind) pline("You feel an %s drain your life!", otmp->oartifact == ART_STORMBRINGER ? "unholy blade" : "object"); else if (otmp->oartifact == ART_STORMBRINGER) pline("The %s blade drains your life!", hcolor("black")); else pline("%s drains your life!", The(distant_name(otmp, xname))); losexp("life drainage"); if (magr && magr->mhp < magr->mhpmax) { magr->mhp += (oldhpmax - u.uhpmax)/2; if (magr->mhp > magr->mhpmax) magr->mhp = magr->mhpmax; } return TRUE; } return FALSE; }
void rndcurse() /* curse a few inventory items at random! */ { int nobj = 0; int cnt, onum; struct obj *otmp; static const char *mal_aura = "feel a malignant aura surround %s."; if (uwep && (uwep->oartifact == ART_MAGICBANE) && rn2(20)) { You(mal_aura, "the magic-absorbing blade"); return; } if(Antimagic) { shieldeff(u.ux, u.uy); You(mal_aura, "you"); } for (otmp = invent; otmp; otmp = otmp->nobj) nobj++; if (nobj) for (cnt = rnd(6/((!!Antimagic) + (!!Half_spell_damage) + 1)); cnt > 0; cnt--) { onum = rn2(nobj); for(otmp = invent; onum != 0; onum--) otmp = otmp->nobj; if(otmp->oartifact && spec_ability(otmp, SPFX_INTEL) && rn2(10) < 8) { pline("%s resists!", The(xname(otmp))); continue; } if(otmp->blessed) unbless(otmp); else curse(otmp); } }
STATIC_OVL void obj_timer_checks(struct obj *otmp, xchar x, xchar y, int force) /* 0 = no force so do checks, <0 = force off, >0 force on */ { long tleft = 0L; short action = ROT_CORPSE; boolean restart_timer = FALSE; boolean on_floor = (otmp->where == OBJ_FLOOR); boolean buried = (otmp->where == OBJ_BURIED); /* Check for corpses just placed on or in ice */ if (otmp->otyp == CORPSE && (on_floor || buried) && is_ice(x,y)) { tleft = stop_timer(action, (genericptr_t)otmp); if (tleft == 0L) { action = REVIVE_MON; tleft = stop_timer(action, (genericptr_t)otmp); } if (tleft != 0L) { long age; tleft = tleft - monstermoves; /* mark the corpse as being on ice */ ON_ICE(otmp) = 1; #ifdef DEBUG_EFFECTS pline("%s is now on ice at %d,%d.", The(xname(otmp)),x,y); #endif /* Adjust the time remaining */ tleft *= ROT_ICE_ADJUSTMENT; restart_timer = TRUE; /* Adjust the age; must be same as in obj_ice_age() */ age = monstermoves - otmp->age; otmp->age = monstermoves - (age * ROT_ICE_ADJUSTMENT); } } /* Check for corpses coming off ice */ else if ((force < 0) || (otmp->otyp == CORPSE && ON_ICE(otmp) && ((on_floor && !is_ice(x,y)) || !on_floor))) { tleft = stop_timer(action, (genericptr_t)otmp); if (tleft == 0L) { action = REVIVE_MON; tleft = stop_timer(action, (genericptr_t)otmp); } if (tleft != 0L) { long age; tleft = tleft - monstermoves; ON_ICE(otmp) = 0; #ifdef DEBUG_EFFECTS pline("%s is no longer on ice at %d,%d.", The(xname(otmp)),x,y); #endif /* Adjust the remaining time */ tleft /= ROT_ICE_ADJUSTMENT; restart_timer = TRUE; /* Adjust the age */ age = monstermoves - otmp->age; otmp->age = otmp->age + (age / ROT_ICE_ADJUSTMENT); } } /* now re-start the timer with the appropriate modifications */ if (restart_timer) (void) start_timer(tleft, TIMER_OBJECT, action, (genericptr_t)otmp); }
/* 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
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; }
static int ready_weapon(struct obj *wep) { /* Separated function so swapping works easily */ int res = 0; if (!wep) { /* No weapon */ if (uwep) { pline("You are empty %s.", body_part(HANDED)); setuwep(NULL); res++; } else pline("You are already empty %s.", body_part(HANDED)); } else if (!uarmg && !Stone_resistance && wep->otyp == CORPSE && touch_petrifies(&mons[wep->corpsenm])) { /* Prevent wielding cockatrice when not wearing gloves --KAA */ char kbuf[BUFSZ]; pline("You wield the %s corpse in your bare %s.", mons[wep->corpsenm].mname, makeplural(body_part(HAND))); sprintf(kbuf, "%s corpse", an(mons[wep->corpsenm].mname)); instapetrify(kbuf); } else if (uarms && bimanual(wep)) pline("You cannot wield a two-handed %s while wearing a shield.", is_sword(wep) ? "sword" : wep->otyp == BATTLE_AXE ? "axe" : "weapon"); else if (wep->oartifact && !touch_artifact(wep, &youmonst)) { res++; /* takes a turn even though it doesn't get wielded */ } else { /* Weapon WILL be wielded after this point */ res++; if (will_weld(wep)) { const char *tmp = xname(wep), *thestr = "The "; if (strncmp(tmp, thestr, 4) && !strncmp(The(tmp),thestr,4)) tmp = thestr; else tmp = ""; pline("%s%s %s to your %s!", tmp, aobjnam(wep, "weld"), (wep->quan == 1L) ? "itself" : "themselves", /* a3 */ bimanual(wep) ? (const char *)makeplural(body_part(HAND)) : body_part(HAND)); wep->bknown = TRUE; } else { /* The message must be printed before setuwep (since * you might die and be revived from changing weapons), * and the message must be before the death message and * Lifesaved rewielding. Yet we want the message to * say "weapon in hand", thus this kludge. */ long dummy = wep->owornmask; wep->owornmask |= W_WEP; prinv(NULL, wep, 0L); wep->owornmask = dummy; } setuwep(wep); /* KMH -- Talking artifacts are finally implemented */ arti_speak(wep); if (artifact_light(wep) && !wep->lamplit) { begin_burn(wep, FALSE); if (!Blind) pline("%s to glow brilliantly!", Tobjnam(wep, "begin")); } if (wep->unpaid) { struct monst *this_shkp; if ((this_shkp = shop_keeper(level, inside_shop(level, u.ux, u.uy))) != NULL) { pline("%s says \"You be careful with my %s!\"", shkname(this_shkp), xname(wep)); } } } return res; }
/* The player is trying to extract something from his/her instrument. */ static int do_improvisation(struct obj *instr, const struct nh_cmd_arg *arg) { int do_spec = !Confusion; if (!do_spec) pline(msgc_yafm, "What you produce is quite far from music..."); else pline(msgc_occstart, "You start playing %s.", the(xname(instr))); switch (instr->otyp) { case MAGIC_FLUTE: /* Make monster fall asleep */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline(msgc_actionok, "You produce soft music."); put_monsters_to_sleep(youmonst.m_lev * 5); exercise(A_DEX, TRUE); break; } /* else FALLTHRU */ case WOODEN_FLUTE: /* May charm snakes */ do_spec &= (rn2(ACURR(A_DEX)) + youmonst.m_lev > 25); pline(do_spec ? msgc_actionok : msgc_failrandom, "%s.", Tobjnam(instr, do_spec ? "trill" : "toot")); if (do_spec) charm_snakes(youmonst.m_lev * 3); exercise(A_DEX, TRUE); break; case FROST_HORN: /* Idem wand of cold */ case FIRE_HORN: /* Idem wand of fire */ if (do_spec && instr->spe > 0) { schar dx, dy, dz; consume_obj_charge(instr, TRUE); if (!getargdir(arg, NULL, &dx, &dy, &dz)) { pline(msgc_yafm, "%s.", Tobjnam(instr, "vibrate")); break; } else { buzz((instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1, rn1(6, 6), youmonst.mx, youmonst.my, dx, dy, 0); } makeknown(instr->otyp); break; } /* else FALLTHRU */ case TOOLED_HORN: /* Awaken or scare monsters */ pline(msgc_actionok, "You produce a frightful, grave sound."); awaken_monsters(&youmonst, youmonst.m_lev * 30); exercise(A_WIS, FALSE); break; case BUGLE: /* Awaken & attract soldiers */ pline(msgc_actionok, "You extract a loud noise from %s.", the(xname(instr))); awaken_soldiers(&youmonst); exercise(A_WIS, FALSE); break; case MAGIC_HARP: /* Charm monsters */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline(msgc_actionok, "%s very attractive music.", Tobjnam(instr, "produce")); charm_monsters((youmonst.m_lev - 1) / 3 + 1); exercise(A_DEX, TRUE); break; } /* else FALLTHRU */ case WOODEN_HARP: /* May calm Nymph */ do_spec &= (rn2(ACURR(A_DEX)) + youmonst.m_lev > 25); pline(do_spec ? msgc_actionok : msgc_failrandom, "%s %s.", The(xname(instr)), do_spec ? "produces a lilting melody" : "twangs"); if (do_spec) calm_nymphs(youmonst.m_lev * 3); exercise(A_DEX, TRUE); break; case DRUM_OF_EARTHQUAKE: /* create several pits */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline(msgc_occstart, "You produce a heavy, thunderous rolling!"); pline_implied(msgc_occstart, "The entire dungeon is shaking around you!"); do_earthquake((youmonst.m_lev - 1) / 3 + 1); /* shake up monsters in a much larger radius... */ awaken_monsters(&youmonst, ROWNO * COLNO); makeknown(DRUM_OF_EARTHQUAKE); break; } /* else FALLTHRU */ case LEATHER_DRUM: /* Awaken monsters */ pline(msgc_actionok, "You beat a deafening row!"); awaken_monsters(&youmonst, youmonst.m_lev * 40); exercise(A_WIS, FALSE); break; default: impossible("What a weird instrument (%d)!", instr->otyp); break; } return 2; /* That takes time */ }