1 /* NetHack 3.6 artifact.c $NHDT-Date: 1509836679 2017/11/04 23:04:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.106 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2013. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2018 */
9 /* JNetHack may be freely redistributed. See license for details. */
16 #include "artilistj.h"
19 * Note: both artilist[] and artiexist[] have a dummy element #0,
20 * so loops over them should normally start at #1. The primary
21 * exception is the save & restore code, which doesn't care about
22 * the contents, just the total size.
25 extern boolean notonhead; /* for long worms */
27 #define get_artifact(o) \
28 (((o) && (o)->oartifact) ? &artilist[(int) (o)->oartifact] : 0)
30 STATIC_DCL boolean FDECL(bane_applies, (const struct artifact *,
32 STATIC_DCL int FDECL(spec_applies, (const struct artifact *, struct monst *));
33 STATIC_DCL int FDECL(arti_invoke, (struct obj *));
34 STATIC_DCL boolean FDECL(Mb_hit, (struct monst * magr, struct monst *mdef,
35 struct obj *, int *, int, BOOLEAN_P, char *));
36 STATIC_DCL unsigned long FDECL(abil_to_spfx, (long *));
37 STATIC_DCL uchar FDECL(abil_to_adtyp, (long *));
38 STATIC_DCL boolean FDECL(untouchable, (struct obj *, BOOLEAN_P));
39 STATIC_DCL int FDECL(count_surround_traps, (int, int));
41 /* The amount added to the victim's total hit points to insure that the
42 victim will be killed even after damage bonus/penalty adjustments.
43 Most such penalties are small, and 200 is plenty; the exception is
44 half physical damage. 3.3.1 and previous versions tried to use a very
45 large number to account for this case; now, we just compute the fatal
46 damage by adding it to 2 times the total hit points instead of 1 time.
47 Note: this will still break if they have more than about half the number
48 of hit points that will fit in a 15 bit integer. */
49 #define FATAL_DAMAGE_MODIFIER 200
51 /* coordinate effects from spec_dbon() with messages in artifact_hit() */
52 STATIC_OVL int spec_dbon_applies = 0;
54 /* flags including which artifacts have already been created */
55 static boolean artiexist[1 + NROFARTIFACTS + 1];
56 /* and a discovery list for them (no dummy first entry here) */
57 STATIC_OVL xchar artidisco[NROFARTIFACTS];
59 STATIC_DCL void NDECL(hack_artifacts);
60 STATIC_DCL boolean FDECL(attacks, (int, struct obj *));
62 /* handle some special cases; must be called after u_init() */
67 int alignmnt = aligns[flags.initalign].value;
69 /* Fix up the alignments of "gift" artifacts */
70 for (art = artilist + 1; art->otyp; art++)
71 if (art->role == Role_switch && art->alignment != A_NONE)
72 art->alignment = alignmnt;
74 /* Excalibur can be used by any lawful character, not just knights */
75 if (!Role_if(PM_KNIGHT))
76 artilist[ART_EXCALIBUR].role = NON_PM;
78 /* Fix up the quest artifact */
79 if (urole.questarti) {
80 artilist[urole.questarti].alignment = alignmnt;
81 artilist[urole.questarti].role = Role_switch;
86 /* zero out the artifact existence list */
90 (void) memset((genericptr_t) artiexist, 0, sizeof artiexist);
91 (void) memset((genericptr_t) artidisco, 0, sizeof artidisco);
99 bwrite(fd, (genericptr_t) artiexist, sizeof artiexist);
100 bwrite(fd, (genericptr_t) artidisco, sizeof artidisco);
104 restore_artifacts(fd)
107 mread(fd, (genericptr_t) artiexist, sizeof artiexist);
108 mread(fd, (genericptr_t) artidisco, sizeof artidisco);
109 hack_artifacts(); /* redo non-saved special cases */
116 if (artinum <= 0 || artinum > NROFARTIFACTS)
118 return artilist[artinum].name;
122 Make an artifact. If a specific alignment is specified, then an object of
123 the appropriate alignment is created from scratch, or 0 is returned if
124 none is available. (If at least one aligned artifact has already been
125 given, then unaligned ones also become eligible for this.)
126 If no alignment is given, then 'otmp' is converted
127 into an artifact of matching type, or returned as-is if that's not
129 For the 2nd case, caller should use ``obj = mk_artifact(obj, A_NONE);''
130 for the 1st, ``obj = mk_artifact((struct obj *)0, some_alignment);''.
133 mk_artifact(otmp, alignment)
134 struct obj *otmp; /* existing object; ignored if alignment specified */
135 aligntyp alignment; /* target alignment, or A_NONE */
137 const struct artifact *a;
139 boolean by_align = (alignment != A_NONE);
140 short o_typ = (by_align || !otmp) ? 0 : otmp->otyp;
141 boolean unique = !by_align && otmp && objects[o_typ].oc_unique;
142 short eligible[NROFARTIFACTS];
144 n = altn = 0; /* no candidates found yet */
145 eligible[0] = 0; /* lint suppression */
146 /* gather eligible artifacts */
147 for (m = 1, a = &artilist[m]; a->otyp; a++, m++) {
150 if ((a->spfx & SPFX_NOGEN) || unique)
154 /* looking for a particular type of item; not producing a
155 divine gift so we don't care about role's first choice */
156 if (a->otyp == o_typ)
158 continue; /* move on to next possibility */
161 /* we're looking for an alignment-specific item
162 suitable for hero's role+race */
163 if ((a->alignment == alignment || a->alignment == A_NONE)
164 /* avoid enemies' equipment */
165 && (a->race == NON_PM || !race_hostile(&mons[a->race]))) {
166 /* when a role-specific first choice is available, use it */
167 if (Role_if(a->role)) {
168 /* make this be the only possibility in the list */
171 break; /* skip all other candidates */
173 /* found something to consider for random selection */
174 if (a->alignment != A_NONE || u.ugifts > 0) {
175 /* right alignment, or non-aligned with at least 1
176 previous gift bestowed, makes this one viable */
179 /* non-aligned with no previous gifts;
180 if no candidates have been found yet, record
181 this one as a[nother] fallback possibility in
182 case all aligned candidates have been used up
183 (via wishing, naming, bones, random generation) */
185 eligible[altn++] = m;
186 /* [once a regular candidate is found, the list
187 is overwritten and `altn' becomes irrelevant] */
192 /* resort to fallback list if main list was empty */
197 /* found at least one candidate; pick one at random */
198 m = eligible[rn2(n)]; /* [0..n-1] */
201 /* make an appropriate object if necessary, then christen it */
203 otmp = mksobj((int) a->otyp, TRUE, FALSE);
206 otmp = oname(otmp, a->name);
211 /* nothing appropriate could be found; return original object */
213 otmp = 0; /* (there was no original object) */
219 * Returns the full name (with articles and correct capitalization) of an
220 * artifact named "name" if one exists, or NULL, it not.
221 * The given name must be rather close to the real name for it to match.
222 * The object type of the artifact is returned in otyp if the return value
226 artifact_name(name, otyp)
230 register const struct artifact *a;
231 register const char *aname;
233 if (!strncmpi(name, "the ", 4))
236 for (a = artilist + 1; a->otyp; a++) {
238 if (!strncmpi(aname, "the ", 4))
240 if (!strcmpi(name, aname)) {
250 exist_artifact(otyp, name)
254 register const struct artifact *a;
258 for (a = artilist + 1, arex = artiexist + 1; a->otyp; a++, arex++)
259 if ((int) a->otyp == otyp && !strcmp(a->name, name))
265 artifact_exists(otmp, name, mod)
270 register const struct artifact *a;
273 for (a = artilist + 1; a->otyp; a++)
274 if (a->otyp == otmp->otyp && !strcmp(a->name, name)) {
275 register int m = (int) (a - artilist);
276 otmp->oartifact = (char) (mod ? m : 0);
278 if (otmp->otyp == RIN_INCREASE_DAMAGE)
290 int n = SIZE(artiexist);
300 spec_ability(otmp, abil)
304 const struct artifact *arti = get_artifact(otmp);
306 return (boolean) (arti && (arti->spfx & abil) != 0L);
309 /* used so that callers don't need to known about SPFX_ codes */
314 /* might as well check for this too */
315 if (obj->otyp == LUCKSTONE)
318 return (boolean) (obj->oartifact && spec_ability(obj, SPFX_LUCK));
321 /* used to check whether a monster is getting reflection from an artifact */
326 const struct artifact *arti = get_artifact(obj);
329 /* while being worn */
330 if ((obj->owornmask & ~W_ART) && (arti->spfx & SPFX_REFLECT))
332 /* just being carried */
333 if (arti->cspfx & SPFX_REFLECT)
339 /* decide whether this obj is effective when attacking against shades;
340 does not consider the bonus for blessed objects versus undead */
345 const struct artifact *arti;
347 /* any silver object is effective */
348 if (objects[obj->otyp].oc_material == SILVER)
350 /* non-silver artifacts with bonus against undead also are effective */
351 arti = get_artifact(obj);
352 if (arti && (arti->spfx & SPFX_DFLAG2) && arti->mtype == M2_UNDEAD)
354 /* [if there was anything with special bonus against noncorporeals,
355 it would be effective too] */
356 /* otherwise, harmless to shades */
360 /* returns 1 if name is restricted for otmp->otyp */
362 restrict_name(otmp, name)
366 register const struct artifact *a;
367 const char *aname, *odesc, *other;
368 boolean sametype[NUM_OBJECTS];
369 int i, lo, hi, otyp = otmp->otyp, ocls = objects[otyp].oc_class;
373 if (!strncmpi(name, "the ", 4))
376 /* decide what types of objects are the same as otyp;
377 if it's been discovered, then only itself matches;
378 otherwise, include all other undiscovered objects
379 of the same class which have the same description
380 or share the same pool of shuffled descriptions */
381 (void) memset((genericptr_t) sametype, 0, sizeof sametype); /* FALSE */
382 sametype[otyp] = TRUE;
383 if (!objects[otyp].oc_name_known
384 && (odesc = OBJ_DESCR(objects[otyp])) != 0) {
385 obj_shuffle_range(otyp, &lo, &hi);
386 for (i = bases[ocls]; i < NUM_OBJECTS; i++) {
387 if (objects[i].oc_class != ocls)
389 if (!objects[i].oc_name_known
390 && (other = OBJ_DESCR(objects[i])) != 0
391 && (!strcmp(odesc, other) || (i >= lo && i <= hi)))
396 /* Since almost every artifact is SPFX_RESTR, it doesn't cost
397 us much to do the string comparison before the spfx check.
398 Bug fix: don't name multiple elven daggers "Sting".
400 for (a = artilist + 1; a->otyp; a++) {
401 if (!sametype[a->otyp])
404 if (!strncmpi(aname, "the ", 4))
406 if (!strcmp(aname, name))
407 return (boolean) ((a->spfx & (SPFX_NOGEN | SPFX_RESTR)) != 0
419 register const struct artifact *weap;
421 if ((weap = get_artifact(otmp)) != 0)
422 return (boolean) (weap->attk.adtyp == adtyp);
431 register const struct artifact *weap;
433 if ((weap = get_artifact(otmp)) != 0)
434 return (boolean) (weap->defn.adtyp == adtyp);
438 /* used for monsters */
440 defends_when_carried(adtyp, otmp)
444 register const struct artifact *weap;
446 if ((weap = get_artifact(otmp)) != 0)
447 return (boolean) (weap->cary.adtyp == adtyp);
451 /* determine whether an item confers Protection */
453 protects(otmp, being_worn)
457 const struct artifact *arti;
459 if (being_worn && objects[otmp->otyp].oc_oprop == PROTECTION)
461 arti = get_artifact(otmp);
464 return (boolean) ((arti->cspfx & SPFX_PROTECT) != 0
465 || (being_worn && (arti->spfx & SPFX_PROTECT) != 0));
469 * a potential artifact has just been worn/wielded/picked-up or
470 * unworn/unwielded/dropped. Pickup/drop only set/reset the W_ART mask.
473 set_artifact_intrinsic(otmp, on, wp_mask)
479 register const struct artifact *art, *oart = get_artifact(otmp);
480 register struct obj *obj;
487 /* effects from the defn field */
488 dtyp = (wp_mask != W_ART) ? oart->defn.adtyp : oart->cary.adtyp;
491 mask = &EFire_resistance;
492 else if (dtyp == AD_COLD)
493 mask = &ECold_resistance;
494 else if (dtyp == AD_ELEC)
495 mask = &EShock_resistance;
496 else if (dtyp == AD_MAGM)
498 else if (dtyp == AD_DISN)
499 mask = &EDisint_resistance;
500 else if (dtyp == AD_DRST)
501 mask = &EPoison_resistance;
502 else if (dtyp == AD_DRLI)
503 mask = &EDrain_resistance;
505 if (mask && wp_mask == W_ART && !on) {
506 /* find out if some other artifact also confers this intrinsic;
507 if so, leave the mask alone */
508 for (obj = invent; obj; obj = obj->nobj) {
509 if (obj != otmp && obj->oartifact) {
510 art = get_artifact(obj);
511 if (art && art->cary.adtyp == dtyp) {
525 /* intrinsics from the spfx field; there could be more than one */
526 spfx = (wp_mask != W_ART) ? oart->spfx : oart->cspfx;
527 if (spfx && wp_mask == W_ART && !on) {
528 /* don't change any spfx also conferred by other artifacts */
529 for (obj = invent; obj; obj = obj->nobj)
530 if (obj != otmp && obj->oartifact) {
531 art = get_artifact(obj);
537 if (spfx & SPFX_SEARCH) {
539 ESearching |= wp_mask;
541 ESearching &= ~wp_mask;
543 if (spfx & SPFX_HALRES) {
544 /* make_hallucinated must (re)set the mask itself to get
545 * the display right */
546 /* restoring needed because this is the only artifact intrinsic
547 * that can print a message--need to guard against being printed
548 * when restoring a game
550 (void) make_hallucinated((long) !on, restoring ? FALSE : TRUE,
553 if (spfx & SPFX_ESP) {
557 ETelepat &= ~wp_mask;
560 if (spfx & SPFX_STLTH) {
564 EStealth &= ~wp_mask;
566 if (spfx & SPFX_REGEN) {
568 ERegeneration |= wp_mask;
570 ERegeneration &= ~wp_mask;
572 if (spfx & SPFX_TCTRL) {
574 ETeleport_control |= wp_mask;
576 ETeleport_control &= ~wp_mask;
578 if (spfx & SPFX_WARN) {
581 EWarn_of_mon |= wp_mask;
582 context.warntype.obj |= spec_m2(otmp);
584 EWarn_of_mon &= ~wp_mask;
585 context.warntype.obj &= ~spec_m2(otmp);
592 EWarning &= ~wp_mask;
595 if (spfx & SPFX_EREGEN) {
597 EEnergy_regeneration |= wp_mask;
599 EEnergy_regeneration &= ~wp_mask;
601 if (spfx & SPFX_HSPDAM) {
603 EHalf_spell_damage |= wp_mask;
605 EHalf_spell_damage &= ~wp_mask;
607 if (spfx & SPFX_HPHDAM) {
609 EHalf_physical_damage |= wp_mask;
611 EHalf_physical_damage &= ~wp_mask;
613 if (spfx & SPFX_XRAY) {
614 /* this assumes that no one else is using xray_range */
619 vision_full_recalc = 1;
621 if ((spfx & SPFX_REFLECT) && (wp_mask & W_WEP)) {
623 EReflecting |= wp_mask;
625 EReflecting &= ~wp_mask;
627 if (spfx & SPFX_PROTECT) {
629 EProtection |= wp_mask;
631 EProtection &= ~wp_mask;
634 if (wp_mask == W_ART && !on && oart->inv_prop) {
635 /* might have to turn off invoked power too */
636 if (oart->inv_prop <= LAST_PROP
637 && (u.uprops[oart->inv_prop].extrinsic & W_ARTI))
638 (void) arti_invoke(otmp);
642 /* touch_artifact()'s return value isn't sufficient to tell whether it
643 dished out damage, and tracking changes to u.uhp, u.mh, Lifesaved
644 when trying to avoid second wounding is too cumbersome */
645 STATIC_VAR boolean touch_blasted; /* for retouch_object() */
648 * creature (usually hero) tries to touch (pick up or wield) an artifact obj.
649 * Returns 0 if the object refuses to be touched.
650 * This routine does not change any object chains.
651 * Ignores such things as gauntlets, assuming the artifact is not
652 * fooled by such trappings.
655 touch_artifact(obj, mon)
659 register const struct artifact *oart = get_artifact(obj);
660 boolean badclass, badalign, self_willed, yours;
662 touch_blasted = FALSE;
666 yours = (mon == &youmonst);
667 /* all quest artifacts are self-willed; if this ever changes, `badclass'
668 will have to be extended to explicitly include quest artifacts */
669 self_willed = ((oart->spfx & SPFX_INTEL) != 0);
671 badclass = self_willed
672 && ((oart->role != NON_PM && !Role_if(oart->role))
673 || (oart->race != NON_PM && !Race_if(oart->race)));
674 badalign = ((oart->spfx & SPFX_RESTR) != 0
675 && oart->alignment != A_NONE
676 && (oart->alignment != u.ualign.type
677 || u.ualign.record < 0));
678 } else if (!is_covetous(mon->data) && !is_mplayer(mon->data)) {
679 badclass = self_willed && oart->role != NON_PM
680 && oart != &artilist[ART_EXCALIBUR];
681 badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE
682 && (oart->alignment != mon_aligntyp(mon));
683 } else { /* an M3_WANTSxxx monster or a fake player */
684 /* special monsters trying to take the Amulet, invocation tools or
685 quest item can touch anything except `spec_applies' artifacts */
686 badclass = badalign = FALSE;
688 /* weapons which attack specific categories of monsters are
689 bad for them even if their alignments happen to match */
691 badalign = bane_applies(oart, mon);
693 if (((badclass || badalign) && self_willed)
694 || (badalign && (!yours || !rn2(4)))) {
701 You("are blasted by %s power!", s_suffix(the(xname(obj))));
703 You("%s
\82Ì
\97Í
\82ð
\97\81\82Ñ
\82½
\81I", xname(obj));
704 touch_blasted = TRUE;
705 dmg = d((Antimagic ? 2 : 4), (self_willed ? 10 : 4));
706 /* add half (maybe quarter) of the usual silver damage bonus */
707 if (objects[obj->otyp].oc_material == SILVER && Hate_silver)
708 tmp = rnd(10), dmg += Maybe_Half_Phys(tmp);
710 Sprintf(buf, "touching %s", oart->name);
712 Sprintf(buf, "%s
\82É
\90G
\82ê
\82Ä", oart->name);
713 losehp(dmg, buf, KILLED_BY); /* magic damage, not physical */
714 exercise(A_WIS, FALSE);
717 /* can pick it up unless you're totally non-synch'd with the artifact */
718 if (badclass && badalign && self_willed) {
722 pline("%s your grasp!", Tobjnam(obj, "evade"));
724 pline("%s
\82Í
\88¬
\82ë
\82¤
\82Æ
\82·
\82é
\82Æ
\82·
\82é
\82è
\82Æ
\94²
\82¯
\82½
\81I", xname(obj));
727 pline("%s beyond your control!", Tobjnam(obj, "are"));
729 pline("%s
\82Í
\90§
\8cä
\82Å
\82«
\82È
\82¢
\81I", xname(obj));
737 /* decide whether an artifact itself is vulnerable to a particular type
738 of erosion damage, independent of the properties of its bearer */
740 arti_immune(obj, dtyp)
744 register const struct artifact *weap = get_artifact(obj);
749 return FALSE; /* nothing is immune to phys dmg */
750 return (boolean) (weap->attk.adtyp == dtyp
751 || weap->defn.adtyp == dtyp
752 || weap->cary.adtyp == dtyp);
756 bane_applies(oart, mon)
757 const struct artifact *oart;
760 struct artifact atmp;
762 if (oart && (oart->spfx & SPFX_DBONUS) != 0) {
764 atmp.spfx &= SPFX_DBONUS; /* clear other spfx fields */
765 if (spec_applies(&atmp, mon))
771 /* decide whether an artifact's special attacks apply against mtmp */
773 spec_applies(weap, mtmp)
774 register const struct artifact *weap;
777 struct permonst *ptr;
780 if (!(weap->spfx & (SPFX_DBONUS | SPFX_ATTK)))
781 return (weap->attk.adtyp == AD_PHYS);
783 yours = (mtmp == &youmonst);
786 if (weap->spfx & SPFX_DMONS) {
787 return (ptr == &mons[(int) weap->mtype]);
788 } else if (weap->spfx & SPFX_DCLAS) {
789 return (weap->mtype == (unsigned long) ptr->mlet);
790 } else if (weap->spfx & SPFX_DFLAG1) {
791 return ((ptr->mflags1 & weap->mtype) != 0L);
792 } else if (weap->spfx & SPFX_DFLAG2) {
793 return ((ptr->mflags2 & weap->mtype)
795 && ((!Upolyd && (urace.selfmask & weap->mtype))
796 || ((weap->mtype & M2_WERE) && u.ulycn >= LOW_PM))));
797 } else if (weap->spfx & SPFX_DALIGN) {
798 return yours ? (u.ualign.type != weap->alignment)
799 : (ptr->maligntyp == A_NONE
800 || sgn(ptr->maligntyp) != weap->alignment);
801 } else if (weap->spfx & SPFX_ATTK) {
802 struct obj *defending_weapon = (yours ? uwep : MON_WEP(mtmp));
804 if (defending_weapon && defending_weapon->oartifact
805 && defends((int) weap->attk.adtyp, defending_weapon))
807 switch (weap->attk.adtyp) {
809 return !(yours ? Fire_resistance : resists_fire(mtmp));
811 return !(yours ? Cold_resistance : resists_cold(mtmp));
813 return !(yours ? Shock_resistance : resists_elec(mtmp));
816 return !(yours ? Antimagic : (rn2(100) < ptr->mr));
818 return !(yours ? Poison_resistance : resists_poison(mtmp));
820 return !(yours ? Drain_resistance : resists_drli(mtmp));
822 return !(yours ? Stone_resistance : resists_ston(mtmp));
824 impossible("Weird weapon special attack.");
830 /* return the M2 flags of monster that an artifact's special attacks apply
836 const struct artifact *artifact = get_artifact(otmp);
839 return artifact->mtype;
843 /* special attack bonus */
849 const struct artifact *weap = get_artifact(otmp);
851 /* no need for an extra check for `NO_ATTK' because this will
852 always return 0 for any artifact which has that attribute */
854 if (weap && weap->attk.damn && spec_applies(weap, mon))
855 return rnd((int) weap->attk.damn);
859 /* special damage bonus */
861 spec_dbon(otmp, mon, tmp)
866 register const struct artifact *weap = get_artifact(otmp);
868 if (!weap || (weap->attk.adtyp == AD_PHYS /* check for `NO_ATTK' */
869 && weap->attk.damn == 0 && weap->attk.damd == 0))
870 spec_dbon_applies = FALSE;
871 else if (otmp->oartifact == ART_GRIMTOOTH)
872 /* Grimtooth has SPFX settings to warn against elves but we want its
873 damage bonus to apply to all targets, so bypass spec_applies() */
874 spec_dbon_applies = TRUE;
876 spec_dbon_applies = spec_applies(weap, mon);
878 if (spec_dbon_applies)
879 return weap->attk.damd ? rnd((int) weap->attk.damd) : max(tmp, 1);
883 /* add identified artifact to discoveries list */
890 /* look for this artifact in the discoveries list;
891 if we hit an empty slot then it's not present, so add it */
892 for (i = 0; i < NROFARTIFACTS; i++)
893 if (artidisco[i] == 0 || artidisco[i] == m) {
897 /* there is one slot per artifact, so we should never reach the
898 end without either finding the artifact or an empty slot... */
899 impossible("couldn't discover artifact (%d)", (int) m);
902 /* used to decide whether an artifact has been fully identified */
904 undiscovered_artifact(m)
909 /* look for this artifact in the discoveries list;
910 if we hit an empty slot then it's undiscovered */
911 for (i = 0; i < NROFARTIFACTS; i++)
912 if (artidisco[i] == m)
914 else if (artidisco[i] == 0)
919 /* display a list of discovered artifacts; return their count */
921 disp_artifact_discoveries(tmpwin)
922 winid tmpwin; /* supplied by dodiscover() */
927 for (i = 0; i < NROFARTIFACTS; i++) {
928 if (artidisco[i] == 0)
929 break; /* empty slot implies end of list */
930 if (tmpwin == WIN_ERR)
931 continue; /* for WIN_ERR, we just count */
935 putstr(tmpwin, iflags.menu_headings, "Artifacts");
937 putstr(tmpwin, iflags.menu_headings, "
\90¹
\8aí");
939 otyp = artilist[m].otyp;
940 Sprintf(buf, " %s [%s %s]", artiname(m),
941 align_str(artilist[m].alignment), simple_typename(otyp));
942 putstr(tmpwin, 0, buf);
948 * Magicbane's intrinsic magic is incompatible with normal
949 * enchantment magic. Thus, its effects have a negative
950 * dependence on spe. Against low mr victims, it typically
951 * does "double athame" damage, 2d4. Occasionally, it will
952 * cast unbalancing magic which effectively averages out to
953 * 4d4 damage (3d4 against high mr victims), for spe = 0.
955 * Prior to 3.4.1, the cancel (aka purge) effect always
956 * included the scare effect too; now it's one or the other.
957 * Likewise, the stun effect won't be combined with either
958 * of those two; it will be chosen separately or possibly
959 * used as a fallback when scare or cancel fails.
961 * [Historical note: a change to artifact_hit() for 3.4.0
962 * unintentionally made all of Magicbane's special effects
963 * be blocked if the defender successfully saved against a
964 * stun attack. As of 3.4.1, those effects can occur but
965 * will be slightly less likely than they were in 3.3.x.]
968 enum mb_effect_indices {
977 #define MB_MAX_DIEROLL 8 /* rolls above this aren't magical */
978 static const char *const mb_verb[2][NUM_MB_INDICES] = {
980 { "probe", "stun", "scare", "cancel" },
981 { "prod", "amaze", "tickle", "purge" },
983 /* Mb_hit()
\82Å "%s
\82½"
\82Ì
\8c`
\82Å
\97\98\97p */
984 {"
\92²
\8d¸
\82µ", "
\82
\82ç
\82
\82ç
\82³
\82¹", "
\8b¯
\82¦
\82³
\82¹", "
\8fò
\89»
\82µ"},
985 { "
\97ã
\82Ü
\82µ", "
\8bÁ
\82©
\82¹", "
\82
\82·
\82®
\82Á", "
\90´
\82ß" },
989 /* called when someone is being hit by Magicbane */
991 Mb_hit(magr, mdef, mb, dmgptr, dieroll, vis, hittee)
992 struct monst *magr, *mdef; /* attacker and defender */
993 struct obj *mb; /* Magicbane */
994 int *dmgptr; /* extra damage target will suffer */
995 int dieroll; /* d20 that has already scored a hit */
996 boolean vis; /* whether the action can be seen */
997 char *hittee; /* target's name: "you" or mon_nam(mdef) */
999 struct permonst *old_uasmon;
1000 #if 0 /*JP*//* not used */
1001 const char *verb, *fakename;
1005 boolean youattack = (magr == &youmonst), youdefend = (mdef == &youmonst),
1006 resisted = FALSE, do_stun, do_confuse, result;
1007 int attack_indx, scare_dieroll = MB_MAX_DIEROLL / 2;
1009 result = FALSE; /* no message given yet */
1010 /* the most severe effects are less likely at higher enchantment */
1012 scare_dieroll /= (1 << (mb->spe / 3));
1013 /* if target successfully resisted the artifact damage bonus,
1014 reduce overall likelihood of the assorted special effects */
1015 if (!spec_dbon_applies)
1018 /* might stun even when attempting a more severe effect, but
1019 in that case it will only happen if the other effect fails;
1020 extra damage will apply regardless; 3.4.1: sometimes might
1021 just probe even when it hasn't been enchanted */
1022 do_stun = (max(mb->spe, 0) < rn2(spec_dbon_applies ? 11 : 7));
1024 /* the special effects also boost physical damage; increments are
1025 generally cumulative, but since the stun effect is based on a
1026 different criterium its damage might not be included; the base
1027 damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending
1028 on target's resistance check against AD_STUN (handled by caller)
1029 [note that a successful save against AD_STUN doesn't actually
1030 prevent the target from ending up stunned] */
1031 attack_indx = MB_INDEX_PROBE;
1032 *dmgptr += rnd(4); /* (2..3)d4 */
1034 attack_indx = MB_INDEX_STUN;
1035 *dmgptr += rnd(4); /* (3..4)d4 */
1037 if (dieroll <= scare_dieroll) {
1038 attack_indx = MB_INDEX_SCARE;
1039 *dmgptr += rnd(4); /* (3..5)d4 */
1041 if (dieroll <= (scare_dieroll / 2)) {
1042 attack_indx = MB_INDEX_CANCEL;
1043 *dmgptr += rnd(4); /* (4..6)d4 */
1046 /* give the hit message prior to inflicting the effects */
1047 verb = mb_verb[!!Hallucination][attack_indx];
1048 if (youattack || youdefend || vis) {
1051 pline_The("magic-absorbing blade %s %s!",
1052 vtense((const char *) 0, verb), hittee);
1054 pline("
\96\82\97Í
\82ð
\8bz
\82¢
\82Æ
\82é
\90n
\82ª%s
\82ð%s
\82½
\81I",
1057 /* assume probing has some sort of noticeable feedback
1058 even if it is being done by one monster to another */
1059 if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef))
1060 map_invisible(mdef->mx, mdef->my);
1063 /* now perform special effects */
1064 switch (attack_indx) {
1065 case MB_INDEX_CANCEL:
1066 old_uasmon = youmonst.data;
1067 /* No mdef->mcan check: even a cancelled monster can be polymorphed
1068 * into a golem, and the "cancel" effect acts as if some magical
1069 * energy remains in spellcasting defenders to be absorbed later.
1071 if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) {
1076 if (youmonst.data != old_uasmon)
1077 *dmgptr = 0; /* rehumanized, so no more damage */
1080 You("lose magical energy!");
1082 You("
\96\82\96@
\82Ì
\83G
\83l
\83\8b\83M
\81[
\82ð
\8e¸
\82Á
\82½
\81I");
1089 if (mdef->data == &mons[PM_CLAY_GOLEM])
1090 mdef->mhp = 1; /* cancelled clay golems will die */
1091 if (youattack && attacktype(mdef->data, AT_MAGC)) {
1093 You("absorb magical energy!");
1095 You("
\96\82\96@
\82Ì
\83G
\83l
\83\8b\83M
\81[
\82ð
\8bz
\82¢
\82Æ
\82Á
\82½
\81I");
1104 case MB_INDEX_SCARE:
1111 multi_reason = "being scared stiff";
1113 multi_reason = "
\8b°
\95|
\82Å
\98T
\94\82\82µ
\82½
\8c\84\82É";
1115 if (magr && magr == u.ustuck && sticks(youmonst.data)) {
1116 u.ustuck = (struct monst *) 0;
1118 You("release %s!", mon_nam(magr));
1120 You("%s
\82ð
\89ð
\95ú
\82µ
\82½
\81I", mon_nam(magr));
1124 if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL))
1127 monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr));
1134 do_stun = TRUE; /* (this is redundant...) */
1137 case MB_INDEX_PROBE:
1138 if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) {
1140 pline_The("%s is insightful.", verb);
1142 pline("
\91\8a\8eè
\82ð%s
\82½
\81D", verb);
1143 /* pre-damage status */
1144 probe_monster(mdef);
1148 /* stun if that was selected and a worse effect didn't occur */
1151 make_stunned(((HStun & TIMEOUT) + 3L), FALSE);
1154 /* avoid extra stun message below if we used mb_verb["stun"] above */
1155 if (attack_indx == MB_INDEX_STUN)
1158 /* lastly, all this magic can be confusing... */
1159 do_confuse = !rn2(12);
1162 make_confused((HConfusion & TIMEOUT) + 4L, FALSE);
1167 #if 0 /*JP*//* not used */
1168 /* now give message(s) describing side-effects;
1169 don't let vtense() be fooled by assigned name ending in 's' */
1170 fakename = youdefend ? "you" : "mon";
1172 if (youattack || youdefend || vis) {
1173 (void) upstart(hittee); /* capitalize */
1176 pline("%s %s!", hittee, vtense(fakename, "resist"));
1178 pline("%s
\82Í
\96h
\82¢
\82¾
\81I", hittee);
1179 shieldeff(youdefend ? u.ux : mdef->mx,
1180 youdefend ? u.uy : mdef->my);
1182 if ((do_stun || do_confuse) && flags.verbose) {
1188 Strcat(buf, "stunned");
1189 if (do_stun && do_confuse)
1190 Strcat(buf, " and ");
1192 Strcat(buf, "confused");
1193 pline("%s %s %s%c", hittee, vtense(fakename, "are"), buf,
1194 (do_stun && do_confuse) ? '!' : '.');
1196 if (do_stun && do_confuse)
1197 Strcat(buf, "
\82æ
\82ë
\82ß
\82¢
\82Ä");
1199 Strcat(buf, "
\82æ
\82ë
\82ß
\82¢
\82½");
1201 Strcat(buf, "
\8d¬
\97\90\82µ
\82½");
1202 pline("%s
\82Í%s%s", hittee,
1203 buf, (do_stun && do_confuse) ? "
\81I" : "
\81D");
1211 /* Function used when someone attacks someone else with an artifact
1212 * weapon. Only adds the special (artifact) damage, and returns a 1 if it
1213 * did something special (in which case the caller won't print the normal
1214 * hit message). This should be called once upon every artifact attack;
1215 * dmgval() no longer takes artifact bonuses into account. Possible
1216 * extension: change the killer so that when an orc kills you with
1217 * Stormbringer it's "killed by Stormbringer" instead of "killed by an orc".
1220 artifact_hit(magr, mdef, otmp, dmgptr, dieroll)
1221 struct monst *magr, *mdef;
1224 int dieroll; /* needed for Magicbane and vorpal blades */
1226 boolean youattack = (magr == &youmonst);
1227 boolean youdefend = (mdef == &youmonst);
1228 boolean vis = (!youattack && magr && cansee(magr->mx, magr->my))
1229 || (!youdefend && cansee(mdef->mx, mdef->my))
1230 || (youattack && u.uswallow && mdef == u.ustuck && !Blind);
1231 boolean realizes_damage;
1232 const char *wepdesc;
1234 static const char you[] = "you";
1236 static const char you[] = "
\82 \82È
\82½";
1239 Strcpy(hittee, youdefend ? you : mon_nam(mdef));
1241 /* The following takes care of most of the damage, but not all--
1242 * the exception being for level draining, which is specially
1243 * handled. Messages are done in this function, however.
1245 *dmgptr += spec_dbon(otmp, mdef, *dmgptr);
1247 if (youattack && youdefend) {
1248 impossible("attacking yourself with weapon?");
1252 realizes_damage = (youdefend || vis
1253 /* feel the effect even if not seen */
1254 || (youattack && mdef == u.ustuck));
1256 /* the four basic attacks: fire, cold, shock and missiles */
1257 if (attacks(AD_FIRE, otmp)) {
1258 if (realizes_damage)
1260 pline_The("fiery blade %s %s%c",
1263 : (mdef->data == &mons[PM_WATER_ELEMENTAL])
1264 ? "vaporizes part of"
1266 hittee, !spec_dbon_applies ? '.' : '!');
1268 pline_The("
\96Ò
\89Î
\82ª%s%s",
1271 ? "
\82É
\96½
\92\86\82µ
\82½
\81D"
1272 : (mdef->data == &mons[PM_WATER_ELEMENTAL])
1273 ? "
\82Ì
\88ê
\95\94\82ð
\8fÁ
\96Å
\82³
\82¹
\82½
\81I"
1274 : "
\82ð
\8fÄ
\82¢
\82½
\81I");
1277 (void) destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
1279 (void) destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
1281 (void) destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
1282 if (youdefend && Slimed)
1284 return realizes_damage;
1286 if (attacks(AD_COLD, otmp)) {
1287 if (realizes_damage)
1289 pline_The("ice-cold blade %s %s%c",
1290 !spec_dbon_applies ? "hits" : "freezes", hittee,
1291 !spec_dbon_applies ? '.' : '!');
1293 pline_The("
\96Ò
\90\81\90á
\82ª%s%s",
1295 !spec_dbon_applies ? "
\82É
\96½
\92\86\82µ
\82½
\81D" : "
\82ð
\8fP
\82Á
\82½
\81I");
1298 (void) destroy_mitem(mdef, POTION_CLASS, AD_COLD);
1299 return realizes_damage;
1301 if (attacks(AD_ELEC, otmp)) {
1302 if (realizes_damage)
1304 pline_The("massive hammer hits%s %s%c",
1305 !spec_dbon_applies ? "" : "! Lightning strikes",
1306 hittee, !spec_dbon_applies ? '.' : '!');
1308 pline("
\8b\90\91å
\82È
\83n
\83\93\83}
\81[
\82Í%s
\82É
\96½
\92\86\82µ
\82½%s", hittee,
1309 !spec_dbon_applies ? "
\81D" : "
\81I
\93d
\8c\82\82ª
\8fP
\82Á
\82½
\81I");
1312 (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC);
1314 (void) destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
1315 return realizes_damage;
1317 if (attacks(AD_MAGM, otmp)) {
1318 if (realizes_damage)
1320 pline_The("imaginary widget hits%s %s%c",
1323 : "! A hail of magic missiles strikes",
1324 hittee, !spec_dbon_applies ? '.' : '!');
1326 pline("
\8eÀ
\91Ì
\82ð
\8e\9d\82½
\82È
\82¢
\95¨
\91Ì
\82ª%s
\82ð
\8dU
\8c\82\82µ
\82½%s",
1328 !spec_dbon_applies ? "
\81D" :
1329 "
\81I
\96\82\96@
\82Ì
\96î
\82ª
\89J
\82 \82ç
\82ê
\82Æ
\96½
\92\86\82µ
\82½
\81I");
1331 return realizes_damage;
1334 if (attacks(AD_STUN, otmp) && dieroll <= MB_MAX_DIEROLL) {
1335 /* Magicbane's special attacks (possibly modifies hittee[]) */
1336 return Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee);
1339 if (!spec_dbon_applies) {
1340 /* since damage bonus didn't apply, nothing more to do;
1341 no further attacks have side-effects on inventory */
1345 /* We really want "on a natural 20" but Nethack does it in */
1346 /* reverse from AD&D. */
1347 if (spec_ability(otmp, SPFX_BEHEAD)) {
1348 if (otmp->oartifact == ART_TSURUGI_OF_MURAMASA && dieroll == 1) {
1350 wepdesc = "The razor-sharp blade";
1352 wepdesc = "
\8ea
\93S
\8c\95";
1353 /* not really beheading, but so close, why add another SPFX */
1354 if (youattack && u.uswallow && mdef == u.ustuck) {
1356 You("slice %s wide open!", mon_nam(mdef));
1358 You("%s
\82ð
\97Ö
\90Ø
\82è
\82É
\82µ
\82½
\81I", mon_nam(mdef));
1359 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1363 /* allow normal cutworm() call to add extra damage */
1367 if (bigmonst(mdef->data)) {
1370 You("slice deeply into %s!", mon_nam(mdef));
1372 You("%s
\82É
\90[
\82
\8ea
\82è
\82Â
\82¯
\82½
\81I",mon_nam(mdef));
1375 pline("%s cuts deeply into %s!", Monnam(magr),
1378 pline("%s
\82Í%s
\82É
\90[
\82
\8ea
\82è
\82Â
\82¯
\82½
\81I", Monnam(magr),
1384 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1386 pline("%s cuts %s in half!", wepdesc, mon_nam(mdef));
1388 pline("%s
\82ª%s
\82ð
\90^
\82Á
\93ñ
\82Â
\82É
\82µ
\82½
\81I", wepdesc, mon_nam(mdef));
1389 otmp->dknown = TRUE;
1392 if (bigmonst(youmonst.data)) {
1394 pline("%s cuts deeply into you!",
1396 pline("%s
\82Í
\82 \82È
\82½
\82É
\90[
\82
\8ea
\82è
\82Â
\82¯
\82½
\81I",
1397 magr ? Monnam(magr) : wepdesc);
1402 /* Players with negative AC's take less damage instead
1403 * of just not getting hit. We must add a large enough
1404 * value to the damage so that this reduction in
1405 * damage does not prevent death.
1407 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER;
1409 pline("%s cuts you in half!", wepdesc);
1411 pline("%s
\82ª
\82 \82È
\82½
\82ð
\90^
\82Á
\93ñ
\82Â
\82É
\82µ
\82½
\81I", wepdesc);
1412 otmp->dknown = TRUE;
1415 } else if (otmp->oartifact == ART_VORPAL_BLADE
1416 && (dieroll == 1 || mdef->data == &mons[PM_JABBERWOCK])) {
1418 static const char *const behead_msg[2] = { "%s beheads %s!",
1419 "%s decapitates %s!" };
1421 static const char *const behead_msg[2] = { "%s
\82Í%s
\82Ì
\8eñ
\82ð
\90Ø
\82Á
\82½
\81I",
1422 "%s
\82Í%s
\82Ì
\8eñ
\82ð
\90Ø
\82è
\97\8e\82µ
\82½
\81I" };
1425 if (youattack && u.uswallow && mdef == u.ustuck)
1427 wepdesc = artilist[ART_VORPAL_BLADE].name;
1429 if (!has_head(mdef->data) || notonhead || u.uswallow) {
1432 pline("Somehow, you miss %s wildly.", mon_nam(mdef));
1434 pline("
\82È
\82º
\82©
\81C%s
\82Ö
\82Ì
\8dU
\8c\82\82Í
\91å
\82«
\82
\82Í
\82¸
\82ê
\82½
\81D", mon_nam(mdef));
1437 pline("Somehow, %s misses wildly.", mon_nam(magr));
1439 pline("
\82È
\82º
\82©
\81C%s
\82Ì
\8dU
\8c\82\82Í
\91å
\82«
\82
\82Í
\82¸
\82ê
\82½
\81D", mon_nam(magr));
1441 return (boolean) (youattack || vis);
1443 if (noncorporeal(mdef->data) || amorphous(mdef->data)) {
1445 pline("%s slices through %s %s.", wepdesc,
1446 s_suffix(mon_nam(mdef)), mbodypart(mdef, NECK));
1448 pline("%s
\82Í%s
\82Ì%s
\82ð
\90Ø
\82è
\97\8e\82µ
\82½
\81D", wepdesc,
1449 mon_nam(mdef), mbodypart(mdef, NECK));
1453 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1454 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc,
1456 if (Hallucination && !flags.female)
1458 pline("Good job Henry, but that wasn't Anne.");
1460 pline("
\83w
\83\93\83\8a\81[
\82æ
\82
\82â
\82Á
\82½
\81C
\82¾
\82ª
\82»
\82¢
\82Â
\82Í
\83A
\83\93\82¶
\82á
\82È
\82¢
\81D");
1461 otmp->dknown = TRUE;
1464 if (!has_head(youmonst.data)) {
1466 pline("Somehow, %s misses you wildly.",
1468 pline("
\82È
\82º
\82©
\81C%s
\82Ì
\8dU
\8c\82\82Í
\91å
\82«
\82
\82Í
\82¸
\82ê
\82½
\81D",
1469 magr ? mon_nam(magr) : wepdesc);
1473 if (noncorporeal(youmonst.data) || amorphous(youmonst.data)) {
1475 pline("%s slices through your %s.", wepdesc,
1477 pline("%s
\82Í
\82 \82È
\82½
\82Ì%s
\82ð
\90Ø
\82è
\97\8e\82µ
\82½
\81D", wepdesc,
1481 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER;
1483 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "you");
1485 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "
\82 \82È
\82½");
1486 otmp->dknown = TRUE;
1487 /* Should amulets fall off? */
1492 if (spec_ability(otmp, SPFX_DRLI)) {
1493 /* some non-living creatures (golems, vortices) are
1494 vulnerable to life drain effects */
1496 const char *life = nonliving(mdef->data) ? "animating force" : "life";
1498 const char *life = nonliving(mdef->data) ? "
\93®
\8dì
\97Í" : "
\90¶
\96½
\97Í";
1502 if (otmp->oartifact == ART_STORMBRINGER)
1504 pline_The("%s blade draws the %s from %s!",
1505 hcolor(NH_BLACK), life, mon_nam(mdef));
1507 pline("%s
\90n
\82ª%s
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I",
1508 hcolor(NH_BLACK), mon_nam(mdef), life);
1512 pline("%s draws the %s from %s!",
1513 The(distant_name(otmp, xname)), life,
1516 pline("%s
\82Í%s
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I",
1517 The(distant_name(otmp, xname)),
1518 mon_nam(mdef), life);
1521 if (mdef->m_lev == 0) {
1522 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1524 int drain = monhp_per_lvl(mdef);
1527 mdef->mhpmax -= drain;
1531 healup(drain, 0, FALSE, FALSE);
1534 } else { /* youdefend */
1535 int oldhpmax = u.uhpmax;
1539 You_feel("an %s drain your %s!",
1540 (otmp->oartifact == ART_STORMBRINGER)
1545 pline("%s
\82É%s
\82ð
\92D
\82í
\82ê
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I",
1546 (otmp->oartifact == ART_STORMBRINGER)
1547 ? "
\95s
\8fò
\82È
\90n"
1551 else if (otmp->oartifact == ART_STORMBRINGER)
1553 pline_The("%s blade drains your %s!", hcolor(NH_BLACK), life);
1555 pline("%s
\90n
\82ª
\82 \82È
\82½
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I", hcolor(NH_BLACK), life);
1558 pline("%s drains your %s!", The(distant_name(otmp, xname)),
1561 pline("%s
\82ª
\82 \82È
\82½
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I", The(distant_name(otmp, xname)),
1565 losexp("life drainage");
1567 losexp("
\90¶
\96½
\97Í
\82ð
\8bz
\8eû
\82³
\82ê
\82Ä");
1568 if (magr && magr->mhp < magr->mhpmax) {
1569 magr->mhp += (oldhpmax - u.uhpmax) / 2;
1570 if (magr->mhp > magr->mhpmax)
1571 magr->mhp = magr->mhpmax;
1579 static NEARDATA const char recharge_type[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
1580 static NEARDATA const char invoke_types[] = { ALL_CLASSES, 0 };
1581 /* #invoke: an "ugly check" filters out most objects */
1583 /* the #invoke command */
1589 obj = getobj(invoke_types, "invoke");
1592 if (!retouch_object(&obj, FALSE))
1594 return arti_invoke(obj);
1601 register const struct artifact *oart = get_artifact(obj);
1603 impossible("arti_invoke without obj");
1606 if (!oart || !oart->inv_prop) {
1607 if (obj->otyp == CRYSTAL_BALL)
1608 use_crystal_ball(&obj);
1610 pline1(nothing_happens);
1614 if (oart->inv_prop > LAST_PROP) {
1615 /* It's a special power, not "just" a property */
1616 if (obj->age > monstermoves) {
1617 /* the artifact is tired :-) */
1619 You_feel("that %s %s ignoring you.", the(xname(obj)),
1620 otense(obj, "are"));
1622 You_feel("%s
\82ª
\96³
\8e\8b\82µ
\82Ä
\82¢
\82é
\82æ
\82¤
\82É
\8a´
\82¶
\82½
\81D", xname(obj));
1624 /* and just got more so; patience is essential... */
1625 obj->age += (long) d(3, 10);
1628 obj->age = monstermoves + rnz(100);
1630 switch (oart->inv_prop) {
1635 zeroobj; /* neither cursed nor blessed, zero oextra too */
1636 pseudo.otyp = SCR_TAMING;
1637 (void) seffects(&pseudo);
1641 int healamt = (u.uhpmax + 1 - u.uhp) / 2;
1642 long creamed = (long) u.ucreamed;
1645 healamt = (u.mhmax + 1 - u.mh) / 2;
1646 if (healamt || Sick || Slimed || Blinded > creamed)
1648 You_feel("better.");
1650 You_feel("
\8bC
\95ª
\82ª
\82æ
\82
\82È
\82Á
\82½
\81D");
1652 goto nothing_special;
1660 make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1662 make_slimed(0L, (char *) 0);
1663 if (Blinded > creamed)
1664 make_blinded(creamed, FALSE);
1668 case ENERGY_BOOST: {
1669 int epboost = (u.uenmax + 1 - u.uen) / 2;
1671 epboost = 120; /* arbitrary */
1672 else if (epboost < 12)
1673 epboost = u.uenmax - u.uen;
1676 You_feel("re-energized.");
1678 You("
\83G
\83l
\83\8b\83M
\81[
\82Å
\96\9e\82½
\82³
\82ê
\82½
\81D");
1682 goto nothing_special;
1686 if (!untrap(TRUE)) {
1687 obj->age = 0; /* don't charge for changing their mind */
1693 struct obj *otmp = getobj(recharge_type, "charge");
1700 b_effect = (obj->blessed && (oart->role == Role_switch
1701 || oart->role == NON_PM));
1702 recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0);
1709 case CREATE_PORTAL: {
1710 int i, num_ok_dungeons, last_ok_dungeon = 0;
1712 extern int n_dgns; /* from dungeon.c */
1713 winid tmpwin = create_nhwindow(NHW_MENU);
1716 any = zeroany; /* set all bits to zero */
1718 /* use index+1 (cant use 0) as identifier */
1719 for (i = num_ok_dungeons = 0; i < n_dgns; i++) {
1720 if (!dungeons[i].dunlev_ureached)
1723 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1724 dungeons[i].dname, MENU_UNSELECTED);
1726 last_ok_dungeon = i;
1729 end_menu(tmpwin, "Open a portal to which dungeon?");
1731 end_menu(tmpwin, "
\82Ç
\82Ì
\96À
\8b{
\82Ö
\82Ì
\96\82\96@
\82Ì
\93ü
\8cû
\82ð
\8aJ
\82«
\82Ü
\82·
\82©
\81H");
1732 if (num_ok_dungeons > 1) {
1733 /* more than one entry; display menu for choices */
1734 menu_item *selected;
1737 n = select_menu(tmpwin, PICK_ONE, &selected);
1739 destroy_nhwindow(tmpwin);
1740 goto nothing_special;
1742 i = selected[0].item.a_int - 1;
1743 free((genericptr_t) selected);
1745 i = last_ok_dungeon; /* also first & only OK dungeon */
1746 destroy_nhwindow(tmpwin);
1749 * i is now index into dungeon structure for the new dungeon.
1750 * Find the closest level in the given dungeon, open
1751 * a use-once portal to that dungeon and go there.
1752 * The closest level is either the entry or dunlev_ureached.
1755 if (dungeons[i].depth_start >= depth(&u.uz))
1756 newlev.dlevel = dungeons[i].entry_lev;
1758 newlev.dlevel = dungeons[i].dunlev_ureached;
1760 if (u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev)
1761 || newlev.dnum == u.uz.dnum || !next_to_u()) {
1763 You_feel("very disoriented for a moment.");
1765 You("
\88ê
\8fu
\95û
\8cü
\8a´
\8ao
\82ð
\8e¸
\82Á
\82½
\81D");
1769 You("are surrounded by a shimmering sphere!");
1771 You("
\83`
\83J
\83`
\83J
\8cõ
\82é
\8b\85\91Ì
\82É
\95¢
\82í
\82ê
\82½
\81I");
1774 You_feel("weightless for a moment.");
1776 You_feel("
\88ê
\8fu
\81C
\96³
\8fd
\97Í
\8a´
\82ð
\8a´
\82¶
\82½
\81D");
1777 goto_level(&newlev, FALSE, FALSE, FALSE);
1782 enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS);
1785 struct obj *otmp = mksobj(ARROW, TRUE, FALSE);
1788 goto nothing_special;
1789 otmp->blessed = obj->blessed;
1790 otmp->cursed = obj->cursed;
1791 otmp->bknown = obj->bknown;
1795 otmp->quan += rnd(10);
1796 } else if (obj->cursed) {
1800 otmp->quan += rnd(5);
1801 otmp->owt = weight(otmp);
1803 otmp = hold_another_object(otmp, "Suddenly %s out.",
1804 aobjnam(otmp, "fall"), (char *) 0);
1806 otmp = hold_another_object(otmp, "
\93Ë
\91R%s
\82ª
\97\8e\82¿
\82½
\81D",
1813 long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI),
1814 iprop = u.uprops[oart->inv_prop].intrinsic;
1815 boolean on = (eprop & W_ARTI) != 0; /* true if prop just set */
1817 if (on && obj->age > monstermoves) {
1818 /* the artifact is tired :-) */
1819 u.uprops[oart->inv_prop].extrinsic ^= W_ARTI;
1821 You_feel("that %s %s ignoring you.", the(xname(obj)),
1822 otense(obj, "are"));
1824 You_feel("%s
\82ª
\96³
\8e\8b\82µ
\82Ä
\82¢
\82é
\82æ
\82¤
\82É
\8a´
\82¶
\82½
\81D", xname(obj));
1826 /* can't just keep repeatedly trying */
1827 obj->age += (long) d(3, 10);
1830 /* when turning off property, determine downtime */
1831 /* arbitrary for now until we can tune this -dlc */
1832 obj->age = monstermoves + rnz(100);
1835 if ((eprop & ~W_ARTI) || iprop) {
1837 /* you had the property from some other source too */
1840 You_feel("a surge of power, but nothing seems to happen.");
1842 You("
\97Í
\82Ì
\8d\82\82Ü
\82è
\82ð
\8a´
\82¶
\82½
\82ª
\81C
\89½
\82à
\8bN
\82«
\82È
\82©
\82Á
\82½
\82æ
\82¤
\82¾
\81D");
1845 switch (oart->inv_prop) {
1849 You_feel("like a rabble-rouser.");
1851 You("
\96¯
\8fO
\90î
\93®
\89Æ
\82Ì
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D");
1854 You_feel("the tension decrease around you.");
1856 pline("
\82Ü
\82í
\82è
\82Ì
\8bÙ
\92£
\8a´
\82ª
\82È
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D");
1863 (void) float_down(I_SPECIAL | TIMEOUT, W_ARTI);
1866 if (BInvis || Blind)
1867 goto nothing_special;
1871 Your("body takes on a %s transparency...",
1872 Hallucination ? "normal" : "strange");
1874 pline("%s
\81C
\91Ì
\82Í
\93§
\89ß
\90«
\82ð
\82à
\82Á
\82½
\81D
\81D
\81D",
1875 Hallucination ? "
\82 \82½
\82è
\82Ü
\82¦
\82Ì
\82±
\82Æ
\82¾
\82ª" : "
\8aï
\96
\82È
\82±
\82Æ
\82É");
1879 Your("body seems to unfade...");
1881 Your("
\91Ì
\82Í
\8e\9f\91æ
\82É
\8c©
\82¦
\82é
\82æ
\82¤
\82É
\82È
\82Á
\82Ä
\82«
\82½
\81D
\81D
\81D");
1889 /* will freeing this object from inventory cause levitation to end? */
1891 finesse_ahriman(obj)
1894 const struct artifact *oart;
1895 struct prop save_Lev;
1898 /* if we aren't levitating or this isn't an artifact which confers
1899 levitation via #invoke then freeinv() won't toggle levitation */
1900 if (!Levitation || (oart = get_artifact(obj)) == 0
1901 || oart->inv_prop != LEVITATION || !(ELevitation & W_ARTI))
1904 /* arti_invoke(off) -> float_down() clears I_SPECIAL|TIMEOUT & W_ARTI;
1905 probe ahead to see whether that actually results in floating down;
1906 (this assumes that there aren't two simultaneously invoked artifacts
1907 both conferring levitation--safe, since if there were two of them,
1908 invoking the 2nd would negate the 1st rather than stack with it) */
1909 save_Lev = u.uprops[LEVITATION];
1910 HLevitation &= ~(I_SPECIAL | TIMEOUT);
1911 ELevitation &= ~W_ARTI;
1912 result = (boolean) !Levitation;
1913 u.uprops[LEVITATION] = save_Lev;
1917 /* WAC return TRUE if artifact is always lit */
1922 return (boolean) (get_artifact(obj) && obj->oartifact == ART_SUNSWORD);
1925 /* KMH -- Talking artifacts are finally implemented */
1930 register const struct artifact *oart = get_artifact(obj);
1934 /* Is this a speaking artifact? */
1935 if (!oart || !(oart->spfx & SPFX_SPEAK))
1938 line = getrumor(bcsign(obj), buf, TRUE);
1941 line = "NetHack rumors file closed for renovation.";
1943 line = "
\89\
\82Ì
\90^
\91\8a\82Í
\90V
\91\95\82Ì
\82½
\82ß
\88ê
\8e\9e\95Â
\93X
\81D";
1945 pline("%s:", Tobjnam(obj, "whisper"));
1947 pline("%s
\82Í
\82³
\82³
\82â
\82¢
\82½
\81F", xname(obj));
1953 artifact_has_invprop(otmp, inv_prop)
1957 const struct artifact *arti = get_artifact(otmp);
1959 return (boolean) (arti && (arti->inv_prop == inv_prop));
1962 /* Return the price sold to the hero of a given artifact or unique item */
1967 if (!otmp->oartifact)
1968 return (long) objects[otmp->otyp].oc_cost;
1969 else if (artilist[(int) otmp->oartifact].cost)
1970 return artilist[(int) otmp->oartifact].cost;
1972 return (100L * (long) objects[otmp->otyp].oc_cost);
1979 struct abil2adtyp_tag {
1983 { &EFire_resistance, AD_FIRE },
1984 { &ECold_resistance, AD_COLD },
1985 { &EShock_resistance, AD_ELEC },
1986 { &EAntimagic, AD_MAGM },
1987 { &EDisint_resistance, AD_DISN },
1988 { &EPoison_resistance, AD_DRST },
1989 { &EDrain_resistance, AD_DRLI },
1993 for (k = 0; k < SIZE(abil2adtyp); k++) {
1994 if (abil2adtyp[k].abil == abil)
1995 return abil2adtyp[k].adtyp;
2000 STATIC_OVL unsigned long
2004 static const struct abil2spfx_tag {
2008 { &ESearching, SPFX_SEARCH },
2009 { &EHalluc_resistance, SPFX_HALRES },
2010 { &ETelepat, SPFX_ESP },
2011 { &EStealth, SPFX_STLTH },
2012 { &ERegeneration, SPFX_REGEN },
2013 { &ETeleport_control, SPFX_TCTRL },
2014 { &EWarn_of_mon, SPFX_WARN },
2015 { &EWarning, SPFX_WARN },
2016 { &EEnergy_regeneration, SPFX_EREGEN },
2017 { &EHalf_spell_damage, SPFX_HSPDAM },
2018 { &EHalf_physical_damage, SPFX_HPHDAM },
2019 { &EReflecting, SPFX_REFLECT },
2023 for (k = 0; k < SIZE(abil2spfx); k++) {
2024 if (abil2spfx[k].abil == abil)
2025 return abil2spfx[k].spfx;
2031 * Return the first item that is conveying a particular intrinsic.
2041 long wornmask = (W_ARM | W_ARMC | W_ARMH | W_ARMS
2042 | W_ARMG | W_ARMF | W_ARMU
2043 | W_AMUL | W_RINGL | W_RINGR | W_TOOL
2047 wornmask |= W_SWAPWEP;
2048 dtyp = abil_to_adtyp(abil);
2049 spfx = abil_to_spfx(abil);
2050 wornbits = (wornmask & *abil);
2052 for (obj = invent; obj; obj = obj->nobj) {
2054 && (abil != &EWarn_of_mon || context.warntype.obj)) {
2055 const struct artifact *art = get_artifact(obj);
2059 if (art->cary.adtyp == dtyp /* carried */
2060 || (art->defn.adtyp == dtyp /* defends while worn */
2061 && (obj->owornmask & ~(W_ART | W_ARTI))))
2065 /* property conferred when carried */
2066 if ((art->cspfx & spfx) == spfx)
2068 /* property conferred when wielded or worn */
2069 if ((art->spfx & spfx) == spfx && obj->owornmask)
2074 if (wornbits && wornbits == (wornmask & obj->owornmask))
2078 return (struct obj *) 0;
2082 /*JP colornames
\82Í
\90Ý
\92è
\83t
\83@
\83C
\83\8b\82Å
\8eg
\82¤
\82Ì
\82Å
\96|
\96ó
\82¹
\82¸
\81A
2083 \93ú
\96{
\8cê
\90ê
\97p
\82Ì
\94z
\97ñ
\82ð
\95Ê
\82É
\97p
\88Ó
\82·
\82é
\81B
2085 static const struct {
2089 { "
\8d\95\82¢", CLR_BLACK },
2090 { "
\90Ô
\82¢", CLR_RED },
2091 { "
\97Î
\90F
\82Ì", CLR_GREEN },
2092 { "
\92\83\90F
\82¢", CLR_BROWN },
2093 { "
\90Â
\82¢", CLR_BLUE },
2094 { "
\83}
\83[
\83\93\83^
\90F
\82Ì", CLR_MAGENTA },
2095 { "
\83V
\83A
\83\93\90F
\82Ì", CLR_CYAN },
2096 { "
\8aD
\90F
\82Ì", CLR_GRAY },
2097 { "
\8aD
\90F
\82Ì", CLR_GRAY },
2098 { "
\83I
\83\8c\83\93\83W
\90F
\82Ì", CLR_ORANGE },
2099 { "
\92W
\97Î
\90F
\82Ì", CLR_BRIGHT_GREEN },
2100 { "
\89©
\90F
\82¢", CLR_YELLOW },
2101 { "
\92W
\90Â
\90F
\82Ì", CLR_BRIGHT_BLUE },
2102 { "
\96¾
\82é
\82¢
\83}
\83[
\83\93\83^
\90F
\82Ì", CLR_BRIGHT_MAGENTA },
2103 { "
\96¾
\82é
\82¢
\83V
\83A
\83\93\90F
\82Ì", CLR_BRIGHT_CYAN },
2104 { "
\94\92\82¢", CLR_WHITE }
2113 for (i = 0; i < SIZE(colornames2); i++)
2114 if (colornames2[i].color == clr)
2115 return colornames2[i].name;
2121 glow_color(arti_indx)
2124 int colornum = artilist[arti_indx].acolor;
2126 const char *colorstr = clr2colorname(colornum);
2128 const char *colorstr = jconj_adj(clr2colorname2(colornum));
2131 return hcolor(colorstr);
2134 /* use for warning "glow" for Sting, Orcrist, and Grimtooth */
2136 Sting_effects(orc_count)
2137 int orc_count; /* new count (warn_obj_cnt is old count); -1 is a flag value */
2140 && (uwep->oartifact == ART_STING
2141 || uwep->oartifact == ART_ORCRIST
2142 || uwep->oartifact == ART_GRIMTOOTH)) {
2143 if (orc_count == -1 && warn_obj_cnt > 0) {
2144 /* -1 means that blindness has just been toggled; give a
2145 'continue' message that eventual 'stop' message will match */
2147 pline("%s is %s.", bare_artifactname(uwep),
2148 !Blind ? "glowing" : "quivering");
2150 pline("%s
\82Í%s
\82Ä
\82¢
\82é
\81D", bare_artifactname(uwep),
2151 !Blind ? "
\8bP
\82¢" : "
\90k
\82¦");
2153 } else if (orc_count > 0 && warn_obj_cnt == 0) {
2154 /* 'start' message */
2157 pline("%s %s %s!", bare_artifactname(uwep),
2158 otense(uwep, "glow"), glow_color(uwep->oartifact));
2160 pline("%s
\82Í%s
\8bP
\82¢
\82½
\81I", bare_artifactname(uwep),
2161 glow_color(uwep->oartifact));
2165 pline("%s quivers slightly.", bare_artifactname(uwep));
2167 pline("%s
\82Í
\8f
\82µ
\90k
\82¦
\82½
\81D", bare_artifactname(uwep));
2168 } else if (orc_count == 0 && warn_obj_cnt > 0) {
2169 /* 'stop' message */
2171 pline("%s stops %s.", bare_artifactname(uwep),
2172 !Blind ? "glowing" : "quivering");
2174 pline("%s
\82Ì%s
\82Í
\8e~
\82Ü
\82Á
\82½
\81D", bare_artifactname(uwep),
2175 !Blind ? "
\8bP
\82«" : "
\90k
\82¦");
2181 /* called when hero is wielding/applying/invoking a carried item, or
2182 after undergoing a transformation (alignment change, lycanthropy,
2183 polymorph) which might affect item access */
2185 retouch_object(objp, loseit)
2186 struct obj **objp; /* might be destroyed or unintentionally dropped */
2187 boolean loseit; /* whether to drop it if hero can longer touch it */
2189 struct obj *obj = *objp;
2191 if (touch_artifact(obj, &youmonst)) {
2194 boolean ag = (objects[obj->otyp].oc_material == SILVER && Hate_silver),
2195 bane = bane_applies(get_artifact(obj), &youmonst);
2197 /* nothing else to do if hero can successfully handle this object */
2201 /* hero can't handle this object, but didn't get touch_artifact()'s
2202 "<obj> evades your grasp|control" message; give an alternate one */
2204 You_cant("handle %s%s!", yname(obj),
2205 obj->owornmask ? " anymore" : "");
2207 You_cant("%s%s
\82ð
\88µ
\82¦
\82È
\82¢
\81I", obj->owornmask ? "
\82à
\82¤" : "",
2210 /* also inflict damage unless touch_artifact() already did so */
2211 if (!touch_blasted) {
2212 /* damage is somewhat arbitrary; half the usual 1d20 physical
2213 for silver, 1d10 magical for <foo>bane, potentially both */
2215 tmp = rnd(10), dmg += Maybe_Half_Phys(tmp);
2219 Sprintf(buf, "handling %s", killer_xname(obj));
2221 Sprintf(buf, "%s
\82ð
\88µ
\82Á
\82Ä", killer_xname(obj));
2222 losehp(dmg, buf, KILLED_BY);
2223 exercise(A_CON, FALSE);
2227 /* removing a worn item might result in loss of levitation,
2228 dropping the hero onto a polymorph trap or into water or
2229 lava and potentially dropping or destroying the item */
2230 if (obj->owornmask) {
2233 remove_worn_item(obj, FALSE);
2234 for (otmp = invent; otmp; otmp = otmp->nobj)
2241 /* if we still have it and caller wants us to drop it, do so now */
2242 if (loseit && obj) {
2247 /* dropx gives a message iff item lands on an altar */
2248 if (!IS_ALTAR(levl[u.ux][u.uy].typ))
2250 pline("%s to the %s.", Tobjnam(obj, "fall"),
2251 surface(u.ux, u.uy));
2253 pline("%s
\82Í%s
\82É
\97\8e\82¿
\82½
\81D", xname(obj),
2254 surface(u.ux, u.uy));
2258 *objp = obj = 0; /* no longer in inventory */
2263 /* an item which is worn/wielded or an artifact which conveys
2264 something via being carried or which has an #invoke effect
2265 currently in operation undergoes a touch test; if it fails,
2266 it will be unworn/unwielded and revoked but not dropped */
2268 untouchable(obj, drop_untouchable)
2270 boolean drop_untouchable;
2272 struct artifact *art;
2273 boolean beingworn, carryeffect, invoked;
2274 long wearmask = ~(W_QUIVER | (u.twoweap ? 0L : W_SWAPWEP) | W_BALL);
2276 beingworn = ((obj->owornmask & wearmask) != 0L
2277 /* some items in use don't have any wornmask setting */
2278 || (obj->oclass == TOOL_CLASS
2279 && (obj->lamplit || (obj->otyp == LEASH && obj->leashmon)
2280 || (Is_container(obj) && Has_contents(obj)))));
2282 if ((art = get_artifact(obj)) != 0) {
2283 carryeffect = (art->cary.adtyp || art->cspfx);
2284 invoked = (art->inv_prop > 0 && art->inv_prop <= LAST_PROP
2285 && (u.uprops[art->inv_prop].extrinsic & W_ARTI) != 0L);
2287 carryeffect = invoked = FALSE;
2290 if (beingworn || carryeffect || invoked) {
2291 if (!retouch_object(&obj, drop_untouchable)) {
2292 /* "<artifact> is beyond your control" or "you can't handle
2293 <object>" has been given and it is now unworn/unwielded
2294 and possibly dropped (depending upon caller); if dropped,
2295 carried effect was turned off, else we leave that alone;
2296 we turn off invocation property here if still carried */
2298 arti_invoke(obj); /* reverse #invoke */
2305 /* check all items currently in use (mostly worn) for touchability */
2307 retouch_equipment(dropflag)
2308 int dropflag; /* 0==don't drop, 1==drop all, 2==drop weapon */
2310 static int nesting = 0; /* recursion control */
2312 boolean dropit, had_gloves = (uarmg != 0);
2313 int had_rings = (!!uleft + !!uright);
2316 * We can potentially be called recursively if losing/unwearing
2317 * an item causes worn helm of opposite alignment to come off or
2320 * BUG: if the initial call was due to putting on a helm of
2321 * opposite alignment and it does come off to trigger recursion,
2322 * after the inner call executes, the outer call will finish
2323 * using the non-helm alignment rather than the helm alignment
2324 * which triggered this in the first place.
2327 clear_bypasses(); /* init upon initial entry */
2329 dropit = (dropflag > 0); /* drop all or drop weapon */
2330 /* check secondary weapon first, before possibly unwielding primary */
2332 bypass_obj(uswapwep); /* so loop below won't process it again */
2333 (void) untouchable(uswapwep, dropit);
2335 /* check primary weapon next so that they're handled together */
2337 bypass_obj(uwep); /* so loop below won't process it again */
2338 (void) untouchable(uwep, dropit);
2341 /* in case someone is daft enough to add artifact or silver saddle */
2342 if (u.usteed && (obj = which_armor(u.usteed, W_SADDLE)) != 0) {
2343 /* untouchable() calls retouch_object() which expects an object in
2344 hero's inventory, but remove_worn_item() will be harmless for
2345 saddle and we're suppressing drop, so this works as intended */
2346 if (untouchable(obj, FALSE))
2347 dismount_steed(DISMOUNT_THROWN);
2350 * TODO? Force off gloves if either or both rings are going to
2351 * become unworn; force off cloak [suit] before suit [shirt].
2352 * The torso handling is hypothetical; the case for gloves is
2353 * not, due to the possibility of unwearing silver rings.
2356 dropit = (dropflag == 1); /* all untouchable items */
2357 /* loss of levitation (silver ring, or Heart of Ahriman invocation)
2358 might cause hero to lose inventory items (by dropping into lava,
2359 for instance), so inventory traversal needs to rescan the whole
2360 invent chain each time it moves on to another object; we use bypass
2361 handling to keep track of which items have already been processed */
2362 while ((obj = nxt_unbypassed_obj(invent)) != 0)
2363 (void) untouchable(obj, dropit);
2365 if (had_rings != (!!uleft + !!uright) && uarmg && uarmg->cursed)
2366 uncurse(uarmg); /* temporary? hack for ring removal plausibility */
2367 if (had_gloves && !uarmg)
2369 selftouch("After losing your gloves, you");
2371 selftouch("
\8f¬
\8eè
\82ð
\8e¸
\82Á
\82½
\82 \82Æ
\81C
\82 \82È
\82½
\82Í");
2374 clear_bypasses(); /* reset upon final exit */
2377 static int mkot_trap_warn_count = 0;
2380 count_surround_traps(x, y)
2386 int dx, dy, glyph, ret = 0;
2388 for (dx = x - 1; dx < x + 2; ++dx)
2389 for (dy = y - 1; dy < y + 2; ++dy) {
2392 /* If a trap is shown here, don't count it; the hero
2393 * should be expecting it. But if there is a trap here
2394 * that's not shown, either undiscovered or covered by
2395 * something, do count it.
2397 glyph = glyph_at(dx, dy);
2398 if (glyph_is_trap(glyph))
2400 if ((ttmp = t_at(dx, dy)) != 0) {
2404 levp = &levl[dx][dy];
2405 if (IS_DOOR(levp->typ) && (levp->doormask & D_TRAPPED) != 0) {
2409 for (otmp = level.objects[dx][dy]; otmp; otmp = otmp->nexthere)
2410 if (Is_container(otmp) && otmp->otrapped) {
2411 ++ret; /* we're counting locations, so just */
2412 break; /* count the first one in a pile */
2416 * [Shouldn't we also check inventory for a trapped container?
2417 * Even if its trap has already been found, there's no 'tknown'
2418 * flag to help hero remember that so we have nothing comparable
2419 * to a shown glyph to justify skipping it.]
2424 /* sense adjacent traps if wielding MKoT without wearing gloves */
2429 static const char *const heat[7] = {
2430 "cool", "slightly warm", "warm", "very warm",
2431 "hot", "very hot", "like fire"
2434 static const char *const heat[7] = {
2435 "
\97â
\82½
\82", "
\8f
\82µ
\89·
\82©
\82", "
\89·
\82©
\82", "
\82Æ
\82Ä
\82à
\89·
\82©
\82",
2436 "
\94M
\82", "
\82Æ
\82Ä
\82à
\94M
\82", "
\89\8a\82Ì
\82æ
\82¤
\82É"
2440 if (!uarmg && uwep && uwep->oartifact == ART_MASTER_KEY_OF_THIEVERY) {
2441 int idx, ntraps = count_surround_traps(u.ux, u.uy);
2443 if (ntraps != mkot_trap_warn_count) {
2444 idx = min(ntraps, SIZE(heat) - 1);
2446 pline_The("Key feels %s%c", heat[idx], (ntraps > 3) ? '!' : '.');
2448 pline_The("
\8c®
\82Í%s
\8a´
\82¶
\82½%s", heat[idx], (ntraps > 3) ? "
\81I" : "
\81D");
2450 mkot_trap_warn_count = ntraps;
2452 mkot_trap_warn_count = 0;
2455 /* Master Key is magic key if its bless/curse state meets our criteria:
2456 not cursed for rogues or blessed for non-rogues */
2458 is_magic_key(mon, obj)
2459 struct monst *mon; /* if null, non-rogue is assumed */
2462 if (((obj && obj->oartifact == ART_MASTER_KEY_OF_THIEVERY)
2463 && ((mon == &youmonst) ? Role_if(PM_ROGUE)
2464 : (mon && mon->data == &mons[PM_ROGUE])))
2465 ? !obj->cursed : obj->blessed)
2470 /* figure out whether 'mon' (usually youmonst) is carrying the magic key */
2473 struct monst *mon; /* if null, hero assumed */
2476 short key = artilist[ART_MASTER_KEY_OF_THIEVERY].otyp;
2480 for (o = ((mon == &youmonst) ? invent : mon->minvent); o;
2481 o = nxtobj(o, key, FALSE)) {
2482 if (is_magic_key(mon, o))
2485 return (struct obj *) 0;