1 /* NetHack 3.6 artifact.c $NHDT-Date: 1553363416 2019/03/23 17:50:16 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.129 $ */
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-2021 */
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 int FDECL(glow_strength, (int));
39 STATIC_DCL boolean FDECL(untouchable, (struct obj *, BOOLEAN_P));
40 STATIC_DCL int FDECL(count_surround_traps, (int, int));
42 /* The amount added to the victim's total hit points to insure that the
43 victim will be killed even after damage bonus/penalty adjustments.
44 Most such penalties are small, and 200 is plenty; the exception is
45 half physical damage. 3.3.1 and previous versions tried to use a very
46 large number to account for this case; now, we just compute the fatal
47 damage by adding it to 2 times the total hit points instead of 1 time.
48 Note: this will still break if they have more than about half the number
49 of hit points that will fit in a 15 bit integer. */
50 #define FATAL_DAMAGE_MODIFIER 200
52 /* coordinate effects from spec_dbon() with messages in artifact_hit() */
53 STATIC_OVL int spec_dbon_applies = 0;
55 /* flags including which artifacts have already been created */
56 static boolean artiexist[1 + NROFARTIFACTS + 1];
57 /* and a discovery list for them (no dummy first entry here) */
58 STATIC_OVL xchar artidisco[NROFARTIFACTS];
60 STATIC_DCL void NDECL(hack_artifacts);
61 STATIC_DCL boolean FDECL(attacks, (int, struct obj *));
63 /* handle some special cases; must be called after u_init() */
68 int alignmnt = aligns[flags.initalign].value;
70 /* Fix up the alignments of "gift" artifacts */
71 for (art = artilist + 1; art->otyp; art++)
72 if (art->role == Role_switch && art->alignment != A_NONE)
73 art->alignment = alignmnt;
75 /* Excalibur can be used by any lawful character, not just knights */
76 if (!Role_if(PM_KNIGHT))
77 artilist[ART_EXCALIBUR].role = NON_PM;
79 /* Fix up the quest artifact */
80 if (urole.questarti) {
81 artilist[urole.questarti].alignment = alignmnt;
82 artilist[urole.questarti].role = Role_switch;
87 /* zero out the artifact existence list */
91 (void) memset((genericptr_t) artiexist, 0, sizeof artiexist);
92 (void) memset((genericptr_t) artidisco, 0, sizeof artidisco);
100 bwrite(fd, (genericptr_t) artiexist, sizeof artiexist);
101 bwrite(fd, (genericptr_t) artidisco, sizeof artidisco);
105 restore_artifacts(fd)
108 mread(fd, (genericptr_t) artiexist, sizeof artiexist);
109 mread(fd, (genericptr_t) artidisco, sizeof artidisco);
110 hack_artifacts(); /* redo non-saved special cases */
117 if (artinum <= 0 || artinum > NROFARTIFACTS)
119 return artilist[artinum].name;
123 Make an artifact. If a specific alignment is specified, then an object of
124 the appropriate alignment is created from scratch, or 0 is returned if
125 none is available. (If at least one aligned artifact has already been
126 given, then unaligned ones also become eligible for this.)
127 If no alignment is given, then 'otmp' is converted
128 into an artifact of matching type, or returned as-is if that's not
130 For the 2nd case, caller should use ``obj = mk_artifact(obj, A_NONE);''
131 for the 1st, ``obj = mk_artifact((struct obj *)0, some_alignment);''.
134 mk_artifact(otmp, alignment)
135 struct obj *otmp; /* existing object; ignored if alignment specified */
136 aligntyp alignment; /* target alignment, or A_NONE */
138 const struct artifact *a;
140 boolean by_align = (alignment != A_NONE);
141 short o_typ = (by_align || !otmp) ? 0 : otmp->otyp;
142 boolean unique = !by_align && otmp && objects[o_typ].oc_unique;
143 short eligible[NROFARTIFACTS];
145 n = altn = 0; /* no candidates found yet */
146 eligible[0] = 0; /* lint suppression */
147 /* gather eligible artifacts */
148 for (m = 1, a = &artilist[m]; a->otyp; a++, m++) {
151 if ((a->spfx & SPFX_NOGEN) || unique)
155 /* looking for a particular type of item; not producing a
156 divine gift so we don't care about role's first choice */
157 if (a->otyp == o_typ)
159 continue; /* move on to next possibility */
162 /* we're looking for an alignment-specific item
163 suitable for hero's role+race */
164 if ((a->alignment == alignment || a->alignment == A_NONE)
165 /* avoid enemies' equipment */
166 && (a->race == NON_PM || !race_hostile(&mons[a->race]))) {
167 /* when a role-specific first choice is available, use it */
168 if (Role_if(a->role)) {
169 /* make this be the only possibility in the list */
172 break; /* skip all other candidates */
174 /* found something to consider for random selection */
175 if (a->alignment != A_NONE || u.ugifts > 0) {
176 /* right alignment, or non-aligned with at least 1
177 previous gift bestowed, makes this one viable */
180 /* non-aligned with no previous gifts;
181 if no candidates have been found yet, record
182 this one as a[nother] fallback possibility in
183 case all aligned candidates have been used up
184 (via wishing, naming, bones, random generation) */
186 eligible[altn++] = m;
187 /* [once a regular candidate is found, the list
188 is overwritten and `altn' becomes irrelevant] */
193 /* resort to fallback list if main list was empty */
198 /* found at least one candidate; pick one at random */
199 m = eligible[rn2(n)]; /* [0..n-1] */
202 /* make an appropriate object if necessary, then christen it */
204 otmp = mksobj((int) a->otyp, TRUE, FALSE);
207 otmp = oname(otmp, a->name);
212 /* nothing appropriate could be found; return original object */
214 otmp = 0; /* (there was no original object) */
220 * Returns the full name (with articles and correct capitalization) of an
221 * artifact named "name" if one exists, or NULL, it not.
222 * The given name must be rather close to the real name for it to match.
223 * The object type of the artifact is returned in otyp if the return value
227 artifact_name(name, otyp)
231 register const struct artifact *a;
232 register const char *aname;
234 if (!strncmpi(name, "the ", 4))
237 for (a = artilist + 1; a->otyp; a++) {
239 if (!strncmpi(aname, "the ", 4))
241 if (!strcmpi(name, aname)) {
251 exist_artifact(otyp, name)
255 register const struct artifact *a;
259 for (a = artilist + 1, arex = artiexist + 1; a->otyp; a++, arex++)
260 if ((int) a->otyp == otyp && !strcmp(a->name, name))
266 artifact_exists(otmp, name, mod)
271 register const struct artifact *a;
274 for (a = artilist + 1; a->otyp; a++)
275 if (a->otyp == otmp->otyp && !strcmp(a->name, name)) {
276 register int m = (int) (a - artilist);
277 otmp->oartifact = (char) (mod ? m : 0);
279 if (otmp->otyp == RIN_INCREASE_DAMAGE)
291 int n = SIZE(artiexist);
301 spec_ability(otmp, abil)
305 const struct artifact *arti = get_artifact(otmp);
307 return (boolean) (arti && (arti->spfx & abil) != 0L);
310 /* used so that callers don't need to known about SPFX_ codes */
315 /* might as well check for this too */
316 if (obj->otyp == LUCKSTONE)
319 return (boolean) (obj->oartifact && spec_ability(obj, SPFX_LUCK));
322 /* used to check whether a monster is getting reflection from an artifact */
327 const struct artifact *arti = get_artifact(obj);
330 /* while being worn */
331 if ((obj->owornmask & ~W_ART) && (arti->spfx & SPFX_REFLECT))
333 /* just being carried */
334 if (arti->cspfx & SPFX_REFLECT)
340 /* decide whether this obj is effective when attacking against shades;
341 does not consider the bonus for blessed objects versus undead */
346 const struct artifact *arti;
348 /* any silver object is effective */
349 if (objects[obj->otyp].oc_material == SILVER)
351 /* non-silver artifacts with bonus against undead also are effective */
352 arti = get_artifact(obj);
353 if (arti && (arti->spfx & SPFX_DFLAG2) && arti->mtype == M2_UNDEAD)
355 /* [if there was anything with special bonus against noncorporeals,
356 it would be effective too] */
357 /* otherwise, harmless to shades */
361 /* returns 1 if name is restricted for otmp->otyp */
363 restrict_name(otmp, name)
367 register const struct artifact *a;
368 const char *aname, *odesc, *other;
369 boolean sametype[NUM_OBJECTS];
370 int i, lo, hi, otyp = otmp->otyp, ocls = objects[otyp].oc_class;
374 if (!strncmpi(name, "the ", 4))
377 /* decide what types of objects are the same as otyp;
378 if it's been discovered, then only itself matches;
379 otherwise, include all other undiscovered objects
380 of the same class which have the same description
381 or share the same pool of shuffled descriptions */
382 (void) memset((genericptr_t) sametype, 0, sizeof sametype); /* FALSE */
383 sametype[otyp] = TRUE;
384 if (!objects[otyp].oc_name_known
385 && (odesc = OBJ_DESCR(objects[otyp])) != 0) {
386 obj_shuffle_range(otyp, &lo, &hi);
387 for (i = bases[ocls]; i < NUM_OBJECTS; i++) {
388 if (objects[i].oc_class != ocls)
390 if (!objects[i].oc_name_known
391 && (other = OBJ_DESCR(objects[i])) != 0
392 && (!strcmp(odesc, other) || (i >= lo && i <= hi)))
397 /* Since almost every artifact is SPFX_RESTR, it doesn't cost
398 us much to do the string comparison before the spfx check.
399 Bug fix: don't name multiple elven daggers "Sting".
401 for (a = artilist + 1; a->otyp; a++) {
402 if (!sametype[a->otyp])
405 if (!strncmpi(aname, "the ", 4))
407 if (!strcmp(aname, name))
408 return (boolean) ((a->spfx & (SPFX_NOGEN | SPFX_RESTR)) != 0
420 register const struct artifact *weap;
422 if ((weap = get_artifact(otmp)) != 0)
423 return (boolean) (weap->attk.adtyp == adtyp);
432 register const struct artifact *weap;
434 if ((weap = get_artifact(otmp)) != 0)
435 return (boolean) (weap->defn.adtyp == adtyp);
439 /* used for monsters */
441 defends_when_carried(adtyp, otmp)
445 register const struct artifact *weap;
447 if ((weap = get_artifact(otmp)) != 0)
448 return (boolean) (weap->cary.adtyp == adtyp);
452 /* determine whether an item confers Protection */
454 protects(otmp, being_worn)
458 const struct artifact *arti;
460 if (being_worn && objects[otmp->otyp].oc_oprop == PROTECTION)
462 arti = get_artifact(otmp);
465 return (boolean) ((arti->cspfx & SPFX_PROTECT) != 0
466 || (being_worn && (arti->spfx & SPFX_PROTECT) != 0));
470 * a potential artifact has just been worn/wielded/picked-up or
471 * unworn/unwielded/dropped. Pickup/drop only set/reset the W_ART mask.
474 set_artifact_intrinsic(otmp, on, wp_mask)
480 register const struct artifact *art, *oart = get_artifact(otmp);
481 register struct obj *obj;
488 /* effects from the defn field */
489 dtyp = (wp_mask != W_ART) ? oart->defn.adtyp : oart->cary.adtyp;
492 mask = &EFire_resistance;
493 else if (dtyp == AD_COLD)
494 mask = &ECold_resistance;
495 else if (dtyp == AD_ELEC)
496 mask = &EShock_resistance;
497 else if (dtyp == AD_MAGM)
499 else if (dtyp == AD_DISN)
500 mask = &EDisint_resistance;
501 else if (dtyp == AD_DRST)
502 mask = &EPoison_resistance;
503 else if (dtyp == AD_DRLI)
504 mask = &EDrain_resistance;
506 if (mask && wp_mask == W_ART && !on) {
507 /* find out if some other artifact also confers this intrinsic;
508 if so, leave the mask alone */
509 for (obj = invent; obj; obj = obj->nobj) {
510 if (obj != otmp && obj->oartifact) {
511 art = get_artifact(obj);
512 if (art && art->cary.adtyp == dtyp) {
526 /* intrinsics from the spfx field; there could be more than one */
527 spfx = (wp_mask != W_ART) ? oart->spfx : oart->cspfx;
528 if (spfx && wp_mask == W_ART && !on) {
529 /* don't change any spfx also conferred by other artifacts */
530 for (obj = invent; obj; obj = obj->nobj)
531 if (obj != otmp && obj->oartifact) {
532 art = get_artifact(obj);
538 if (spfx & SPFX_SEARCH) {
540 ESearching |= wp_mask;
542 ESearching &= ~wp_mask;
544 if (spfx & SPFX_HALRES) {
545 /* make_hallucinated must (re)set the mask itself to get
546 * the display right */
547 /* restoring needed because this is the only artifact intrinsic
548 * that can print a message--need to guard against being printed
549 * when restoring a game
551 (void) make_hallucinated((long) !on, restoring ? FALSE : TRUE,
554 if (spfx & SPFX_ESP) {
558 ETelepat &= ~wp_mask;
561 if (spfx & SPFX_STLTH) {
565 EStealth &= ~wp_mask;
567 if (spfx & SPFX_REGEN) {
569 ERegeneration |= wp_mask;
571 ERegeneration &= ~wp_mask;
573 if (spfx & SPFX_TCTRL) {
575 ETeleport_control |= wp_mask;
577 ETeleport_control &= ~wp_mask;
579 if (spfx & SPFX_WARN) {
582 EWarn_of_mon |= wp_mask;
583 context.warntype.obj |= spec_m2(otmp);
585 EWarn_of_mon &= ~wp_mask;
586 context.warntype.obj &= ~spec_m2(otmp);
593 EWarning &= ~wp_mask;
596 if (spfx & SPFX_EREGEN) {
598 EEnergy_regeneration |= wp_mask;
600 EEnergy_regeneration &= ~wp_mask;
602 if (spfx & SPFX_HSPDAM) {
604 EHalf_spell_damage |= wp_mask;
606 EHalf_spell_damage &= ~wp_mask;
608 if (spfx & SPFX_HPHDAM) {
610 EHalf_physical_damage |= wp_mask;
612 EHalf_physical_damage &= ~wp_mask;
614 if (spfx & SPFX_XRAY) {
615 /* this assumes that no one else is using xray_range */
620 vision_full_recalc = 1;
622 if ((spfx & SPFX_REFLECT) && (wp_mask & W_WEP)) {
624 EReflecting |= wp_mask;
626 EReflecting &= ~wp_mask;
628 if (spfx & SPFX_PROTECT) {
630 EProtection |= wp_mask;
632 EProtection &= ~wp_mask;
635 if (wp_mask == W_ART && !on && oart->inv_prop) {
636 /* might have to turn off invoked power too */
637 if (oart->inv_prop <= LAST_PROP
638 && (u.uprops[oart->inv_prop].extrinsic & W_ARTI))
639 (void) arti_invoke(otmp);
643 /* touch_artifact()'s return value isn't sufficient to tell whether it
644 dished out damage, and tracking changes to u.uhp, u.mh, Lifesaved
645 when trying to avoid second wounding is too cumbersome */
646 STATIC_VAR boolean touch_blasted; /* for retouch_object() */
649 * creature (usually hero) tries to touch (pick up or wield) an artifact obj.
650 * Returns 0 if the object refuses to be touched.
651 * This routine does not change any object chains.
652 * Ignores such things as gauntlets, assuming the artifact is not
653 * fooled by such trappings.
656 touch_artifact(obj, mon)
660 register const struct artifact *oart = get_artifact(obj);
661 boolean badclass, badalign, self_willed, yours;
663 touch_blasted = FALSE;
667 yours = (mon == &youmonst);
668 /* all quest artifacts are self-willed; if this ever changes, `badclass'
669 will have to be extended to explicitly include quest artifacts */
670 self_willed = ((oart->spfx & SPFX_INTEL) != 0);
672 badclass = self_willed
673 && ((oart->role != NON_PM && !Role_if(oart->role))
674 || (oart->race != NON_PM && !Race_if(oart->race)));
675 badalign = ((oart->spfx & SPFX_RESTR) != 0
676 && oart->alignment != A_NONE
677 && (oart->alignment != u.ualign.type
678 || u.ualign.record < 0));
679 } else if (!is_covetous(mon->data) && !is_mplayer(mon->data)) {
680 badclass = self_willed && oart->role != NON_PM
681 && oart != &artilist[ART_EXCALIBUR];
682 badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE
683 && (oart->alignment != mon_aligntyp(mon));
684 } else { /* an M3_WANTSxxx monster or a fake player */
685 /* special monsters trying to take the Amulet, invocation tools or
686 quest item can touch anything except `spec_applies' artifacts */
687 badclass = badalign = FALSE;
689 /* weapons which attack specific categories of monsters are
690 bad for them even if their alignments happen to match */
692 badalign = bane_applies(oart, mon);
694 if (((badclass || badalign) && self_willed)
695 || (badalign && (!yours || !rn2(4)))) {
702 You("are blasted by %s power!", s_suffix(the(xname(obj))));
704 You("%s
\82Ì
\97Í
\82ð
\97\81\82Ñ
\82½
\81I", xname(obj));
705 touch_blasted = TRUE;
706 dmg = d((Antimagic ? 2 : 4), (self_willed ? 10 : 4));
707 /* add half (maybe quarter) of the usual silver damage bonus */
708 if (objects[obj->otyp].oc_material == SILVER && Hate_silver)
709 tmp = rnd(10), dmg += Maybe_Half_Phys(tmp);
711 Sprintf(buf, "touching %s", oart->name);
713 Sprintf(buf, "%s
\82É
\90G
\82ê
\82Ä", oart->name);
714 losehp(dmg, buf, KILLED_BY); /* magic damage, not physical */
715 exercise(A_WIS, FALSE);
718 /* can pick it up unless you're totally non-synch'd with the artifact */
719 if (badclass && badalign && self_willed) {
723 pline("%s your grasp!", Tobjnam(obj, "evade"));
725 pline("%s
\82Í
\88¬
\82ë
\82¤
\82Æ
\82·
\82é
\82Æ
\82·
\82é
\82è
\82Æ
\94²
\82¯
\82½
\81I", xname(obj));
728 pline("%s beyond your control!", Tobjnam(obj, "are"));
730 pline("%s
\82Í
\90§
\8cä
\82Å
\82«
\82È
\82¢
\81I", xname(obj));
738 /* decide whether an artifact itself is vulnerable to a particular type
739 of erosion damage, independent of the properties of its bearer */
741 arti_immune(obj, dtyp)
745 register const struct artifact *weap = get_artifact(obj);
750 return FALSE; /* nothing is immune to phys dmg */
751 return (boolean) (weap->attk.adtyp == dtyp
752 || weap->defn.adtyp == dtyp
753 || weap->cary.adtyp == dtyp);
757 bane_applies(oart, mon)
758 const struct artifact *oart;
761 struct artifact atmp;
763 if (oart && (oart->spfx & SPFX_DBONUS) != 0) {
765 atmp.spfx &= SPFX_DBONUS; /* clear other spfx fields */
766 if (spec_applies(&atmp, mon))
772 /* decide whether an artifact's special attacks apply against mtmp */
774 spec_applies(weap, mtmp)
775 register const struct artifact *weap;
778 struct permonst *ptr;
781 if (!(weap->spfx & (SPFX_DBONUS | SPFX_ATTK)))
782 return (weap->attk.adtyp == AD_PHYS);
784 yours = (mtmp == &youmonst);
787 if (weap->spfx & SPFX_DMONS) {
788 return (ptr == &mons[(int) weap->mtype]);
789 } else if (weap->spfx & SPFX_DCLAS) {
790 return (weap->mtype == (unsigned long) ptr->mlet);
791 } else if (weap->spfx & SPFX_DFLAG1) {
792 return ((ptr->mflags1 & weap->mtype) != 0L);
793 } else if (weap->spfx & SPFX_DFLAG2) {
794 return ((ptr->mflags2 & weap->mtype)
796 && ((!Upolyd && (urace.selfmask & weap->mtype))
797 || ((weap->mtype & M2_WERE) && u.ulycn >= LOW_PM))));
798 } else if (weap->spfx & SPFX_DALIGN) {
799 return yours ? (u.ualign.type != weap->alignment)
800 : (ptr->maligntyp == A_NONE
801 || sgn(ptr->maligntyp) != weap->alignment);
802 } else if (weap->spfx & SPFX_ATTK) {
803 struct obj *defending_weapon = (yours ? uwep : MON_WEP(mtmp));
805 if (defending_weapon && defending_weapon->oartifact
806 && defends((int) weap->attk.adtyp, defending_weapon))
808 switch (weap->attk.adtyp) {
810 return !(yours ? Fire_resistance : resists_fire(mtmp));
812 return !(yours ? Cold_resistance : resists_cold(mtmp));
814 return !(yours ? Shock_resistance : resists_elec(mtmp));
817 return !(yours ? Antimagic : (rn2(100) < ptr->mr));
819 return !(yours ? Poison_resistance : resists_poison(mtmp));
821 return !(yours ? Drain_resistance : resists_drli(mtmp));
823 return !(yours ? Stone_resistance : resists_ston(mtmp));
825 impossible("Weird weapon special attack.");
831 /* return the M2 flags of monster that an artifact's special attacks apply
837 const struct artifact *artifact = get_artifact(otmp);
840 return artifact->mtype;
844 /* special attack bonus */
850 const struct artifact *weap = get_artifact(otmp);
852 /* no need for an extra check for `NO_ATTK' because this will
853 always return 0 for any artifact which has that attribute */
855 if (weap && weap->attk.damn && spec_applies(weap, mon))
856 return rnd((int) weap->attk.damn);
860 /* special damage bonus */
862 spec_dbon(otmp, mon, tmp)
867 register const struct artifact *weap = get_artifact(otmp);
869 if (!weap || (weap->attk.adtyp == AD_PHYS /* check for `NO_ATTK' */
870 && weap->attk.damn == 0 && weap->attk.damd == 0))
871 spec_dbon_applies = FALSE;
872 else if (otmp->oartifact == ART_GRIMTOOTH)
873 /* Grimtooth has SPFX settings to warn against elves but we want its
874 damage bonus to apply to all targets, so bypass spec_applies() */
875 spec_dbon_applies = TRUE;
877 spec_dbon_applies = spec_applies(weap, mon);
879 if (spec_dbon_applies)
880 return weap->attk.damd ? rnd((int) weap->attk.damd) : max(tmp, 1);
884 /* add identified artifact to discoveries list */
891 /* look for this artifact in the discoveries list;
892 if we hit an empty slot then it's not present, so add it */
893 for (i = 0; i < NROFARTIFACTS; i++)
894 if (artidisco[i] == 0 || artidisco[i] == m) {
898 /* there is one slot per artifact, so we should never reach the
899 end without either finding the artifact or an empty slot... */
900 impossible("couldn't discover artifact (%d)", (int) m);
903 /* used to decide whether an artifact has been fully identified */
905 undiscovered_artifact(m)
910 /* look for this artifact in the discoveries list;
911 if we hit an empty slot then it's undiscovered */
912 for (i = 0; i < NROFARTIFACTS; i++)
913 if (artidisco[i] == m)
915 else if (artidisco[i] == 0)
920 /* display a list of discovered artifacts; return their count */
922 disp_artifact_discoveries(tmpwin)
923 winid tmpwin; /* supplied by dodiscover() */
928 for (i = 0; i < NROFARTIFACTS; i++) {
929 if (artidisco[i] == 0)
930 break; /* empty slot implies end of list */
931 if (tmpwin == WIN_ERR)
932 continue; /* for WIN_ERR, we just count */
936 putstr(tmpwin, iflags.menu_headings, "Artifacts");
938 putstr(tmpwin, iflags.menu_headings, "
\90¹
\8aí");
940 otyp = artilist[m].otyp;
941 Sprintf(buf, " %s [%s %s]", artiname(m),
942 align_str(artilist[m].alignment), simple_typename(otyp));
943 putstr(tmpwin, 0, buf);
949 * Magicbane's intrinsic magic is incompatible with normal
950 * enchantment magic. Thus, its effects have a negative
951 * dependence on spe. Against low mr victims, it typically
952 * does "double athame" damage, 2d4. Occasionally, it will
953 * cast unbalancing magic which effectively averages out to
954 * 4d4 damage (3d4 against high mr victims), for spe = 0.
956 * Prior to 3.4.1, the cancel (aka purge) effect always
957 * included the scare effect too; now it's one or the other.
958 * Likewise, the stun effect won't be combined with either
959 * of those two; it will be chosen separately or possibly
960 * used as a fallback when scare or cancel fails.
962 * [Historical note: a change to artifact_hit() for 3.4.0
963 * unintentionally made all of Magicbane's special effects
964 * be blocked if the defender successfully saved against a
965 * stun attack. As of 3.4.1, those effects can occur but
966 * will be slightly less likely than they were in 3.3.x.]
969 enum mb_effect_indices {
978 #define MB_MAX_DIEROLL 8 /* rolls above this aren't magical */
979 static const char *const mb_verb[2][NUM_MB_INDICES] = {
981 { "probe", "stun", "scare", "cancel" },
982 { "prod", "amaze", "tickle", "purge" },
984 /* Mb_hit()
\82Å "%s
\82½"
\82Ì
\8c`
\82Å
\97\98\97p */
985 {"
\92²
\8d¸
\82µ", "
\82
\82ç
\82
\82ç
\82³
\82¹", "
\8b¯
\82¦
\82³
\82¹", "
\8fò
\89»
\82µ"},
986 { "
\97ã
\82Ü
\82µ", "
\8bÁ
\82©
\82¹", "
\82
\82·
\82®
\82Á", "
\90´
\82ß" },
990 /* called when someone is being hit by Magicbane */
992 Mb_hit(magr, mdef, mb, dmgptr, dieroll, vis, hittee)
993 struct monst *magr, *mdef; /* attacker and defender */
994 struct obj *mb; /* Magicbane */
995 int *dmgptr; /* extra damage target will suffer */
996 int dieroll; /* d20 that has already scored a hit */
997 boolean vis; /* whether the action can be seen */
998 char *hittee; /* target's name: "you" or mon_nam(mdef) */
1000 struct permonst *old_uasmon;
1002 boolean youattack = (magr == &youmonst), youdefend = (mdef == &youmonst),
1003 resisted = FALSE, do_stun, do_confuse, result;
1005 int attack_indx, fakeidx, scare_dieroll = MB_MAX_DIEROLL / 2;
1007 int attack_indx, scare_dieroll = MB_MAX_DIEROLL / 2;
1010 result = FALSE; /* no message given yet */
1011 /* the most severe effects are less likely at higher enchantment */
1013 scare_dieroll /= (1 << (mb->spe / 3));
1014 /* if target successfully resisted the artifact damage bonus,
1015 reduce overall likelihood of the assorted special effects */
1016 if (!spec_dbon_applies)
1019 /* might stun even when attempting a more severe effect, but
1020 in that case it will only happen if the other effect fails;
1021 extra damage will apply regardless; 3.4.1: sometimes might
1022 just probe even when it hasn't been enchanted */
1023 do_stun = (max(mb->spe, 0) < rn2(spec_dbon_applies ? 11 : 7));
1025 /* the special effects also boost physical damage; increments are
1026 generally cumulative, but since the stun effect is based on a
1027 different criterium its damage might not be included; the base
1028 damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending
1029 on target's resistance check against AD_STUN (handled by caller)
1030 [note that a successful save against AD_STUN doesn't actually
1031 prevent the target from ending up stunned] */
1032 attack_indx = MB_INDEX_PROBE;
1033 *dmgptr += rnd(4); /* (2..3)d4 */
1035 attack_indx = MB_INDEX_STUN;
1036 *dmgptr += rnd(4); /* (3..4)d4 */
1038 if (dieroll <= scare_dieroll) {
1039 attack_indx = MB_INDEX_SCARE;
1040 *dmgptr += rnd(4); /* (3..5)d4 */
1042 if (dieroll <= (scare_dieroll / 2)) {
1043 attack_indx = MB_INDEX_CANCEL;
1044 *dmgptr += rnd(4); /* (4..6)d4 */
1047 /* give the hit message prior to inflicting the effects */
1048 verb = mb_verb[!!Hallucination][attack_indx];
1049 if (youattack || youdefend || vis) {
1052 pline_The("magic-absorbing blade %s %s!",
1053 vtense((const char *) 0, verb), hittee);
1055 pline("
\96\82\97Í
\82ð
\8bz
\82¢
\82Æ
\82é
\90n
\82ª%s
\82ð%s
\82½
\81I",
1058 /* assume probing has some sort of noticeable feedback
1059 even if it is being done by one monster to another */
1060 if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef))
1061 map_invisible(mdef->mx, mdef->my);
1064 /* now perform special effects */
1065 switch (attack_indx) {
1066 case MB_INDEX_CANCEL:
1067 old_uasmon = youmonst.data;
1068 /* No mdef->mcan check: even a cancelled monster can be polymorphed
1069 * into a golem, and the "cancel" effect acts as if some magical
1070 * energy remains in spellcasting defenders to be absorbed later.
1072 if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) {
1077 if (youmonst.data != old_uasmon)
1078 *dmgptr = 0; /* rehumanized, so no more damage */
1083 context.botl = TRUE;
1085 You("lose magical energy!");
1087 You("
\96\82\96@
\82Ì
\83G
\83l
\83\8b\83M
\81[
\82ð
\8e¸
\82Á
\82½
\81I");
1090 if (mdef->data == &mons[PM_CLAY_GOLEM])
1091 mdef->mhp = 1; /* cancelled clay golems will die */
1092 if (youattack && attacktype(mdef->data, AT_MAGC)) {
1095 context.botl = TRUE;
1097 You("absorb magical energy!");
1099 You("
\96\82\96@
\82Ì
\83G
\83l
\83\8b\83M
\81[
\82ð
\8bz
\82¢
\82Æ
\82Á
\82½
\81I");
1105 case MB_INDEX_SCARE:
1112 multi_reason = "being scared stiff";
1114 multi_reason = "
\8b°
\95|
\82Å
\98T
\94\82\82µ
\82½
\8c\84\82É";
1116 if (magr && magr == u.ustuck && sticks(youmonst.data)) {
1117 u.ustuck = (struct monst *) 0;
1119 You("release %s!", mon_nam(magr));
1121 You("%s
\82ð
\89ð
\95ú
\82µ
\82½
\81I", mon_nam(magr));
1125 if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL))
1128 monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr));
1135 do_stun = TRUE; /* (this is redundant...) */
1138 case MB_INDEX_PROBE:
1139 if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) {
1141 pline_The("%s is insightful.", verb);
1143 pline("
\91\8a\8eè
\82ð%s
\82½
\81D", verb);
1144 /* pre-damage status */
1145 probe_monster(mdef);
1149 /* stun if that was selected and a worse effect didn't occur */
1152 make_stunned(((HStun & TIMEOUT) + 3L), FALSE);
1155 /* avoid extra stun message below if we used mb_verb["stun"] above */
1156 if (attack_indx == MB_INDEX_STUN)
1159 /* lastly, all this magic can be confusing... */
1160 do_confuse = !rn2(12);
1163 make_confused((HConfusion & TIMEOUT) + 4L, FALSE);
1168 /* now give message(s) describing side-effects; Use fakename
1169 so vtense() won't be fooled by assigned name ending in 's' */
1171 fakeidx = youdefend ? 1 : 0;
1173 if (youattack || youdefend || vis) {
1174 (void) upstart(hittee); /* capitalize */
1177 pline("%s %s!", hittee, vtense(fakename[fakeidx], "resist"));
1179 pline("%s
\82Í
\96h
\82¢
\82¾
\81I", hittee);
1180 shieldeff(youdefend ? u.ux : mdef->mx,
1181 youdefend ? u.uy : mdef->my);
1183 if ((do_stun || do_confuse) && flags.verbose) {
1189 Strcat(buf, "stunned");
1190 if (do_stun && do_confuse)
1191 Strcat(buf, " and ");
1193 Strcat(buf, "confused");
1194 pline("%s %s %s%c", hittee, vtense(fakename[fakeidx], "are"), buf,
1195 (do_stun && do_confuse) ? '!' : '.');
1197 if (do_stun && do_confuse)
1198 Strcat(buf, "
\82æ
\82ë
\82ß
\82¢
\82Ä");
1200 Strcat(buf, "
\82æ
\82ë
\82ß
\82¢
\82½");
1202 Strcat(buf, "
\8d¬
\97\90\82µ
\82½");
1203 pline("%s
\82Í%s%s", hittee,
1204 buf, (do_stun && do_confuse) ? "
\81I" : "
\81D");
1212 /* Function used when someone attacks someone else with an artifact
1213 * weapon. Only adds the special (artifact) damage, and returns a 1 if it
1214 * did something special (in which case the caller won't print the normal
1215 * hit message). This should be called once upon every artifact attack;
1216 * dmgval() no longer takes artifact bonuses into account. Possible
1217 * extension: change the killer so that when an orc kills you with
1218 * Stormbringer it's "killed by Stormbringer" instead of "killed by an orc".
1221 artifact_hit(magr, mdef, otmp, dmgptr, dieroll)
1222 struct monst *magr, *mdef;
1225 int dieroll; /* needed for Magicbane and vorpal blades */
1227 boolean youattack = (magr == &youmonst);
1228 boolean youdefend = (mdef == &youmonst);
1229 boolean vis = (!youattack && magr && cansee(magr->mx, magr->my))
1230 || (!youdefend && cansee(mdef->mx, mdef->my))
1231 || (youattack && u.uswallow && mdef == u.ustuck && !Blind);
1232 boolean realizes_damage;
1233 const char *wepdesc;
1235 static const char you[] = "you";
1237 static const char you[] = "
\82 \82È
\82½";
1240 Strcpy(hittee, youdefend ? you : mon_nam(mdef));
1242 /* The following takes care of most of the damage, but not all--
1243 * the exception being for level draining, which is specially
1244 * handled. Messages are done in this function, however.
1246 *dmgptr += spec_dbon(otmp, mdef, *dmgptr);
1248 if (youattack && youdefend) {
1249 impossible("attacking yourself with weapon?");
1253 realizes_damage = (youdefend || vis
1254 /* feel the effect even if not seen */
1255 || (youattack && mdef == u.ustuck));
1257 /* the four basic attacks: fire, cold, shock and missiles */
1258 if (attacks(AD_FIRE, otmp)) {
1259 if (realizes_damage)
1261 pline_The("fiery blade %s %s%c",
1264 : (mdef->data == &mons[PM_WATER_ELEMENTAL])
1265 ? "vaporizes part of"
1267 hittee, !spec_dbon_applies ? '.' : '!');
1269 pline_The("
\96Ò
\89Î
\82ª%s%s",
1272 ? "
\82É
\96½
\92\86\82µ
\82½
\81D"
1273 : (mdef->data == &mons[PM_WATER_ELEMENTAL])
1274 ? "
\82Ì
\88ê
\95\94\82ð
\8fÁ
\96Å
\82³
\82¹
\82½
\81I"
1275 : "
\82ð
\8fÄ
\82¢
\82½
\81I");
1278 (void) destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
1280 (void) destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
1282 (void) destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
1283 if (youdefend && Slimed)
1285 return realizes_damage;
1287 if (attacks(AD_COLD, otmp)) {
1288 if (realizes_damage)
1290 pline_The("ice-cold blade %s %s%c",
1291 !spec_dbon_applies ? "hits" : "freezes", hittee,
1292 !spec_dbon_applies ? '.' : '!');
1294 pline_The("
\96Ò
\90\81\90á
\82ª%s%s",
1296 !spec_dbon_applies ? "
\82É
\96½
\92\86\82µ
\82½
\81D" : "
\82ð
\8fP
\82Á
\82½
\81I");
1299 (void) destroy_mitem(mdef, POTION_CLASS, AD_COLD);
1300 return realizes_damage;
1302 if (attacks(AD_ELEC, otmp)) {
1303 if (realizes_damage)
1305 pline_The("massive hammer hits%s %s%c",
1306 !spec_dbon_applies ? "" : "! Lightning strikes",
1307 hittee, !spec_dbon_applies ? '.' : '!');
1309 pline("
\8b\90\91å
\82È
\83n
\83\93\83}
\81[
\82Í%s
\82É
\96½
\92\86\82µ
\82½%s", hittee,
1310 !spec_dbon_applies ? "
\81D" : "
\81I
\93d
\8c\82\82ª
\8fP
\82Á
\82½
\81I");
1312 if (spec_dbon_applies)
1313 wake_nearto(mdef->mx, mdef->my, 4 * 4);
1315 (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC);
1317 (void) destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
1318 return realizes_damage;
1320 if (attacks(AD_MAGM, otmp)) {
1321 if (realizes_damage)
1323 pline_The("imaginary widget hits%s %s%c",
1326 : "! A hail of magic missiles strikes",
1327 hittee, !spec_dbon_applies ? '.' : '!');
1329 pline("
\8eÀ
\91Ì
\82ð
\8e\9d\82½
\82È
\82¢
\95¨
\91Ì
\82ª%s
\82ð
\8dU
\8c\82\82µ
\82½%s",
1331 !spec_dbon_applies ? "
\81D" :
1332 "
\81I
\96\82\96@
\82Ì
\96î
\82ª
\89J
\82 \82ç
\82ê
\82Æ
\96½
\92\86\82µ
\82½
\81I");
1334 return realizes_damage;
1337 if (attacks(AD_STUN, otmp) && dieroll <= MB_MAX_DIEROLL) {
1338 /* Magicbane's special attacks (possibly modifies hittee[]) */
1339 return Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee);
1342 if (!spec_dbon_applies) {
1343 /* since damage bonus didn't apply, nothing more to do;
1344 no further attacks have side-effects on inventory */
1348 /* We really want "on a natural 20" but Nethack does it in */
1349 /* reverse from AD&D. */
1350 if (spec_ability(otmp, SPFX_BEHEAD)) {
1351 if (otmp->oartifact == ART_TSURUGI_OF_MURAMASA && dieroll == 1) {
1353 wepdesc = "The razor-sharp blade";
1355 wepdesc = "
\8ea
\93S
\8c\95";
1356 /* not really beheading, but so close, why add another SPFX */
1357 if (youattack && u.uswallow && mdef == u.ustuck) {
1359 You("slice %s wide open!", mon_nam(mdef));
1361 You("%s
\82ð
\97Ö
\90Ø
\82è
\82É
\82µ
\82½
\81I", mon_nam(mdef));
1362 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1366 /* allow normal cutworm() call to add extra damage */
1370 if (bigmonst(mdef->data)) {
1373 You("slice deeply into %s!", mon_nam(mdef));
1375 You("%s
\82É
\90[
\82
\8ea
\82è
\82Â
\82¯
\82½
\81I",mon_nam(mdef));
1378 pline("%s cuts deeply into %s!", Monnam(magr),
1381 pline("%s
\82Í%s
\82É
\90[
\82
\8ea
\82è
\82Â
\82¯
\82½
\81I", Monnam(magr),
1387 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1389 pline("%s cuts %s in half!", wepdesc, mon_nam(mdef));
1391 pline("%s
\82ª%s
\82ð
\90^
\82Á
\93ñ
\82Â
\82É
\82µ
\82½
\81I", wepdesc, mon_nam(mdef));
1392 otmp->dknown = TRUE;
1395 if (bigmonst(youmonst.data)) {
1397 pline("%s cuts deeply into you!",
1399 pline("%s
\82Í
\82 \82È
\82½
\82É
\90[
\82
\8ea
\82è
\82Â
\82¯
\82½
\81I",
1400 magr ? Monnam(magr) : wepdesc);
1405 /* Players with negative AC's take less damage instead
1406 * of just not getting hit. We must add a large enough
1407 * value to the damage so that this reduction in
1408 * damage does not prevent death.
1410 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER;
1412 pline("%s cuts you in half!", wepdesc);
1414 pline("%s
\82ª
\82 \82È
\82½
\82ð
\90^
\82Á
\93ñ
\82Â
\82É
\82µ
\82½
\81I", wepdesc);
1415 otmp->dknown = TRUE;
1418 } else if (otmp->oartifact == ART_VORPAL_BLADE
1419 && (dieroll == 1 || mdef->data == &mons[PM_JABBERWOCK])) {
1421 static const char *const behead_msg[2] = { "%s beheads %s!",
1422 "%s decapitates %s!" };
1424 static const char *const behead_msg[2] = { "%s
\82Í%s
\82Ì
\8eñ
\82ð
\90Ø
\82Á
\82½
\81I",
1425 "%s
\82Í%s
\82Ì
\8eñ
\82ð
\90Ø
\82è
\97\8e\82µ
\82½
\81I" };
1428 if (youattack && u.uswallow && mdef == u.ustuck)
1430 wepdesc = artilist[ART_VORPAL_BLADE].name;
1432 if (!has_head(mdef->data) || notonhead || u.uswallow) {
1435 pline("Somehow, you miss %s wildly.", mon_nam(mdef));
1437 pline("
\82È
\82º
\82©
\81C%s
\82Ö
\82Ì
\8dU
\8c\82\82Í
\91å
\82«
\82
\82Í
\82¸
\82ê
\82½
\81D", mon_nam(mdef));
1440 pline("Somehow, %s misses wildly.", mon_nam(magr));
1442 pline("
\82È
\82º
\82©
\81C%s
\82Ì
\8dU
\8c\82\82Í
\91å
\82«
\82
\82Í
\82¸
\82ê
\82½
\81D", mon_nam(magr));
1444 return (boolean) (youattack || vis);
1446 if (noncorporeal(mdef->data) || amorphous(mdef->data)) {
1448 pline("%s slices through %s %s.", wepdesc,
1449 s_suffix(mon_nam(mdef)), mbodypart(mdef, NECK));
1451 pline("%s
\82Í%s
\82Ì%s
\82ð
\90Ø
\82è
\97\8e\82µ
\82½
\81D", wepdesc,
1452 mon_nam(mdef), mbodypart(mdef, NECK));
1456 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1457 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc,
1459 if (Hallucination && !flags.female)
1461 pline("Good job Henry, but that wasn't Anne.");
1463 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");
1464 otmp->dknown = TRUE;
1467 if (!has_head(youmonst.data)) {
1469 pline("Somehow, %s misses you wildly.",
1471 pline("
\82È
\82º
\82©
\81C%s
\82Ì
\8dU
\8c\82\82Í
\91å
\82«
\82
\82Í
\82¸
\82ê
\82½
\81D",
1472 magr ? mon_nam(magr) : wepdesc);
1476 if (noncorporeal(youmonst.data) || amorphous(youmonst.data)) {
1478 pline("%s slices through your %s.", wepdesc,
1480 pline("%s
\82Í
\82 \82È
\82½
\82Ì%s
\82ð
\90Ø
\82è
\97\8e\82µ
\82½
\81D", wepdesc,
1484 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER;
1486 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "you");
1488 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "
\82 \82È
\82½");
1489 otmp->dknown = TRUE;
1490 /* Should amulets fall off? */
1495 if (spec_ability(otmp, SPFX_DRLI)) {
1496 /* some non-living creatures (golems, vortices) are
1497 vulnerable to life drain effects */
1499 const char *life = nonliving(mdef->data) ? "animating force" : "life";
1501 const char *life = nonliving(mdef->data) ? "
\93®
\8dì
\97Í" : "
\90¶
\96½
\97Í";
1505 if (otmp->oartifact == ART_STORMBRINGER)
1507 pline_The("%s blade draws the %s from %s!",
1508 hcolor(NH_BLACK), life, mon_nam(mdef));
1510 pline("%s
\90n
\82ª%s
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I",
1511 hcolor(NH_BLACK), mon_nam(mdef), life);
1515 pline("%s draws the %s from %s!",
1516 The(distant_name(otmp, xname)), life,
1519 pline("%s
\82Í%s
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I",
1520 The(distant_name(otmp, xname)),
1521 mon_nam(mdef), life);
1524 if (mdef->m_lev == 0) {
1525 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1527 int drain = monhp_per_lvl(mdef);
1530 mdef->mhpmax -= drain;
1534 healup(drain, 0, FALSE, FALSE);
1537 } else { /* youdefend */
1538 int oldhpmax = u.uhpmax;
1542 You_feel("an %s drain your %s!",
1543 (otmp->oartifact == ART_STORMBRINGER)
1548 pline("%s
\82É%s
\82ð
\92D
\82í
\82ê
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I",
1549 (otmp->oartifact == ART_STORMBRINGER)
1550 ? "
\95s
\8fò
\82È
\90n"
1554 else if (otmp->oartifact == ART_STORMBRINGER)
1556 pline_The("%s blade drains your %s!", hcolor(NH_BLACK), life);
1558 pline("%s
\90n
\82ª
\82 \82È
\82½
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I", hcolor(NH_BLACK), life);
1561 pline("%s drains your %s!", The(distant_name(otmp, xname)),
1564 pline("%s
\82ª
\82 \82È
\82½
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I", The(distant_name(otmp, xname)),
1568 losexp("life drainage");
1570 losexp("
\90¶
\96½
\97Í
\82ð
\8bz
\8eû
\82³
\82ê
\82Ä");
1571 if (magr && magr->mhp < magr->mhpmax) {
1572 magr->mhp += (oldhpmax - u.uhpmax) / 2;
1573 if (magr->mhp > magr->mhpmax)
1574 magr->mhp = magr->mhpmax;
1582 static NEARDATA const char recharge_type[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
1583 static NEARDATA const char invoke_types[] = { ALL_CLASSES, 0 };
1584 /* #invoke: an "ugly check" filters out most objects */
1586 /* the #invoke command */
1592 obj = getobj(invoke_types, "invoke");
1595 if (!retouch_object(&obj, FALSE))
1597 return arti_invoke(obj);
1604 register const struct artifact *oart = get_artifact(obj);
1606 impossible("arti_invoke without obj");
1609 if (!oart || !oart->inv_prop) {
1610 if (obj->otyp == CRYSTAL_BALL)
1611 use_crystal_ball(&obj);
1613 pline1(nothing_happens);
1617 if (oart->inv_prop > LAST_PROP) {
1618 /* It's a special power, not "just" a property */
1619 if (obj->age > monstermoves) {
1620 /* the artifact is tired :-) */
1622 You_feel("that %s %s ignoring you.", the(xname(obj)),
1623 otense(obj, "are"));
1625 You_feel("%s
\82ª
\96³
\8e\8b\82µ
\82Ä
\82¢
\82é
\82æ
\82¤
\82É
\8a´
\82¶
\82½
\81D", xname(obj));
1627 /* and just got more so; patience is essential... */
1628 obj->age += (long) d(3, 10);
1631 obj->age = monstermoves + rnz(100);
1633 switch (oart->inv_prop) {
1638 zeroobj; /* neither cursed nor blessed, zero oextra too */
1639 pseudo.otyp = SCR_TAMING;
1640 (void) seffects(&pseudo);
1644 int healamt = (u.uhpmax + 1 - u.uhp) / 2;
1645 long creamed = (long) u.ucreamed;
1648 healamt = (u.mhmax + 1 - u.mh) / 2;
1649 if (healamt || Sick || Slimed || Blinded > creamed)
1651 You_feel("better.");
1653 You_feel("
\8bC
\95ª
\82ª
\82æ
\82
\82È
\82Á
\82½
\81D");
1655 goto nothing_special;
1663 make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1665 make_slimed(0L, (char *) 0);
1666 if (Blinded > creamed)
1667 make_blinded(creamed, FALSE);
1668 context.botl = TRUE;
1671 case ENERGY_BOOST: {
1672 int epboost = (u.uenmax + 1 - u.uen) / 2;
1675 epboost = 120; /* arbitrary */
1676 else if (epboost < 12)
1677 epboost = u.uenmax - u.uen;
1680 context.botl = TRUE;
1682 You_feel("re-energized.");
1684 You("
\83G
\83l
\83\8b\83M
\81[
\82Å
\96\9e\82½
\82³
\82ê
\82½
\81D");
1686 goto nothing_special;
1690 if (!untrap(TRUE)) {
1691 obj->age = 0; /* don't charge for changing their mind */
1697 struct obj *otmp = getobj(recharge_type, "charge");
1704 b_effect = (obj->blessed && (oart->role == Role_switch
1705 || oart->role == NON_PM));
1706 recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0);
1713 case CREATE_PORTAL: {
1714 int i, num_ok_dungeons, last_ok_dungeon = 0;
1716 extern int n_dgns; /* from dungeon.c */
1717 winid tmpwin = create_nhwindow(NHW_MENU);
1720 any = zeroany; /* set all bits to zero */
1722 /* use index+1 (cant use 0) as identifier */
1723 for (i = num_ok_dungeons = 0; i < n_dgns; i++) {
1724 if (!dungeons[i].dunlev_ureached)
1727 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1728 dungeons[i].dname, MENU_UNSELECTED);
1730 last_ok_dungeon = i;
1733 end_menu(tmpwin, "Open a portal to which dungeon?");
1735 end_menu(tmpwin, "
\82Ç
\82Ì
\96À
\8b{
\82Ö
\82Ì
\96\82\96@
\82Ì
\93ü
\8cû
\82ð
\8aJ
\82«
\82Ü
\82·
\82©
\81H");
1736 if (num_ok_dungeons > 1) {
1737 /* more than one entry; display menu for choices */
1738 menu_item *selected;
1741 n = select_menu(tmpwin, PICK_ONE, &selected);
1743 destroy_nhwindow(tmpwin);
1744 goto nothing_special;
1746 i = selected[0].item.a_int - 1;
1747 free((genericptr_t) selected);
1749 i = last_ok_dungeon; /* also first & only OK dungeon */
1750 destroy_nhwindow(tmpwin);
1753 * i is now index into dungeon structure for the new dungeon.
1754 * Find the closest level in the given dungeon, open
1755 * a use-once portal to that dungeon and go there.
1756 * The closest level is either the entry or dunlev_ureached.
1759 if (dungeons[i].depth_start >= depth(&u.uz))
1760 newlev.dlevel = dungeons[i].entry_lev;
1762 newlev.dlevel = dungeons[i].dunlev_ureached;
1764 if (u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev)
1765 || newlev.dnum == u.uz.dnum || !next_to_u()) {
1767 You_feel("very disoriented for a moment.");
1769 You("
\88ê
\8fu
\95û
\8cü
\8a´
\8ao
\82ð
\8e¸
\82Á
\82½
\81D");
1773 You("are surrounded by a shimmering sphere!");
1775 You("
\83`
\83J
\83`
\83J
\8cõ
\82é
\8b\85\91Ì
\82É
\95¢
\82í
\82ê
\82½
\81I");
1778 You_feel("weightless for a moment.");
1780 You_feel("
\88ê
\8fu
\81C
\96³
\8fd
\97Í
\8a´
\82ð
\8a´
\82¶
\82½
\81D");
1781 goto_level(&newlev, FALSE, FALSE, FALSE);
1786 enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS);
1789 struct obj *otmp = mksobj(ARROW, TRUE, FALSE);
1792 goto nothing_special;
1793 otmp->blessed = obj->blessed;
1794 otmp->cursed = obj->cursed;
1795 otmp->bknown = obj->bknown;
1799 otmp->quan += rnd(10);
1800 } else if (obj->cursed) {
1804 otmp->quan += rnd(5);
1805 otmp->owt = weight(otmp);
1807 otmp = hold_another_object(otmp, "Suddenly %s out.",
1808 aobjnam(otmp, "fall"), (char *) 0);
1810 otmp = hold_another_object(otmp, "
\93Ë
\91R%s
\82ª
\97\8e\82¿
\82½
\81D",
1818 long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI),
1819 iprop = u.uprops[oart->inv_prop].intrinsic;
1820 boolean on = (eprop & W_ARTI) != 0; /* true if prop just set */
1822 if (on && obj->age > monstermoves) {
1823 /* the artifact is tired :-) */
1824 u.uprops[oart->inv_prop].extrinsic ^= W_ARTI;
1826 You_feel("that %s %s ignoring you.", the(xname(obj)),
1827 otense(obj, "are"));
1829 You_feel("%s
\82ª
\96³
\8e\8b\82µ
\82Ä
\82¢
\82é
\82æ
\82¤
\82É
\8a´
\82¶
\82½
\81D", xname(obj));
1831 /* can't just keep repeatedly trying */
1832 obj->age += (long) d(3, 10);
1835 /* when turning off property, determine downtime */
1836 /* arbitrary for now until we can tune this -dlc */
1837 obj->age = monstermoves + rnz(100);
1840 if ((eprop & ~W_ARTI) || iprop) {
1842 /* you had the property from some other source too */
1845 You_feel("a surge of power, but nothing seems to happen.");
1847 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");
1850 switch (oart->inv_prop) {
1854 You_feel("like a rabble-rouser.");
1856 You("
\96¯
\8fO
\90î
\93®
\89Æ
\82Ì
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D");
1859 You_feel("the tension decrease around you.");
1861 pline("
\82Ü
\82í
\82è
\82Ì
\8bÙ
\92£
\8a´
\82ª
\82È
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D");
1868 (void) float_down(I_SPECIAL | TIMEOUT, W_ARTI);
1871 if (BInvis || Blind)
1872 goto nothing_special;
1876 Your("body takes on a %s transparency...",
1877 Hallucination ? "normal" : "strange");
1879 pline("%s
\81C
\91Ì
\82Í
\93§
\89ß
\90«
\82ð
\82à
\82Á
\82½
\81D
\81D
\81D",
1880 Hallucination ? "
\82 \82½
\82è
\82Ü
\82¦
\82Ì
\82±
\82Æ
\82¾
\82ª" : "
\8aï
\96
\82È
\82±
\82Æ
\82É");
1884 Your("body seems to unfade...");
1886 Your("
\91Ì
\82Í
\8e\9f\91æ
\82É
\8c©
\82¦
\82é
\82æ
\82¤
\82É
\82È
\82Á
\82Ä
\82«
\82½
\81D
\81D
\81D");
1894 /* will freeing this object from inventory cause levitation to end? */
1896 finesse_ahriman(obj)
1899 const struct artifact *oart;
1900 struct prop save_Lev;
1903 /* if we aren't levitating or this isn't an artifact which confers
1904 levitation via #invoke then freeinv() won't toggle levitation */
1905 if (!Levitation || (oart = get_artifact(obj)) == 0
1906 || oart->inv_prop != LEVITATION || !(ELevitation & W_ARTI))
1909 /* arti_invoke(off) -> float_down() clears I_SPECIAL|TIMEOUT & W_ARTI;
1910 probe ahead to see whether that actually results in floating down;
1911 (this assumes that there aren't two simultaneously invoked artifacts
1912 both conferring levitation--safe, since if there were two of them,
1913 invoking the 2nd would negate the 1st rather than stack with it) */
1914 save_Lev = u.uprops[LEVITATION];
1915 HLevitation &= ~(I_SPECIAL | TIMEOUT);
1916 ELevitation &= ~W_ARTI;
1917 result = (boolean) !Levitation;
1918 u.uprops[LEVITATION] = save_Lev;
1922 /* WAC return TRUE if artifact is always lit */
1927 return (boolean) (get_artifact(obj) && obj->oartifact == ART_SUNSWORD);
1930 /* KMH -- Talking artifacts are finally implemented */
1935 register const struct artifact *oart = get_artifact(obj);
1939 /* Is this a speaking artifact? */
1940 if (!oart || !(oart->spfx & SPFX_SPEAK))
1943 line = getrumor(bcsign(obj), buf, TRUE);
1946 line = "NetHack rumors file closed for renovation.";
1948 line = "
\89\
\82Ì
\90^
\91\8a\82Í
\90V
\91\95\82Ì
\82½
\82ß
\88ê
\8e\9e\95Â
\93X
\81D";
1950 pline("%s:", Tobjnam(obj, "whisper"));
1952 pline("%s
\82Í
\82³
\82³
\82â
\82¢
\82½
\81F", xname(obj));
1958 artifact_has_invprop(otmp, inv_prop)
1962 const struct artifact *arti = get_artifact(otmp);
1964 return (boolean) (arti && (arti->inv_prop == inv_prop));
1967 /* Return the price sold to the hero of a given artifact or unique item */
1972 if (!otmp->oartifact)
1973 return (long) objects[otmp->otyp].oc_cost;
1974 else if (artilist[(int) otmp->oartifact].cost)
1975 return artilist[(int) otmp->oartifact].cost;
1977 return (100L * (long) objects[otmp->otyp].oc_cost);
1984 struct abil2adtyp_tag {
1988 { &EFire_resistance, AD_FIRE },
1989 { &ECold_resistance, AD_COLD },
1990 { &EShock_resistance, AD_ELEC },
1991 { &EAntimagic, AD_MAGM },
1992 { &EDisint_resistance, AD_DISN },
1993 { &EPoison_resistance, AD_DRST },
1994 { &EDrain_resistance, AD_DRLI },
1998 for (k = 0; k < SIZE(abil2adtyp); k++) {
1999 if (abil2adtyp[k].abil == abil)
2000 return abil2adtyp[k].adtyp;
2005 STATIC_OVL unsigned long
2009 static const struct abil2spfx_tag {
2013 { &ESearching, SPFX_SEARCH },
2014 { &EHalluc_resistance, SPFX_HALRES },
2015 { &ETelepat, SPFX_ESP },
2016 { &EStealth, SPFX_STLTH },
2017 { &ERegeneration, SPFX_REGEN },
2018 { &ETeleport_control, SPFX_TCTRL },
2019 { &EWarn_of_mon, SPFX_WARN },
2020 { &EWarning, SPFX_WARN },
2021 { &EEnergy_regeneration, SPFX_EREGEN },
2022 { &EHalf_spell_damage, SPFX_HSPDAM },
2023 { &EHalf_physical_damage, SPFX_HPHDAM },
2024 { &EReflecting, SPFX_REFLECT },
2028 for (k = 0; k < SIZE(abil2spfx); k++) {
2029 if (abil2spfx[k].abil == abil)
2030 return abil2spfx[k].spfx;
2036 * Return the first item that is conveying a particular intrinsic.
2046 long wornmask = (W_ARM | W_ARMC | W_ARMH | W_ARMS
2047 | W_ARMG | W_ARMF | W_ARMU
2048 | W_AMUL | W_RINGL | W_RINGR | W_TOOL
2052 wornmask |= W_SWAPWEP;
2053 dtyp = abil_to_adtyp(abil);
2054 spfx = abil_to_spfx(abil);
2055 wornbits = (wornmask & *abil);
2057 for (obj = invent; obj; obj = obj->nobj) {
2059 && (abil != &EWarn_of_mon || context.warntype.obj)) {
2060 const struct artifact *art = get_artifact(obj);
2064 if (art->cary.adtyp == dtyp /* carried */
2065 || (art->defn.adtyp == dtyp /* defends while worn */
2066 && (obj->owornmask & ~(W_ART | W_ARTI))))
2070 /* property conferred when carried */
2071 if ((art->cspfx & spfx) == spfx)
2073 /* property conferred when wielded or worn */
2074 if ((art->spfx & spfx) == spfx && obj->owornmask)
2079 if (wornbits && wornbits == (wornmask & obj->owornmask))
2083 return (struct obj *) 0;
2087 /*JP colornames
\82Í
\90Ý
\92è
\83t
\83@
\83C
\83\8b\82Å
\8eg
\82¤
\82Ì
\82Å
\96|
\96ó
\82¹
\82¸
\81A
2088 \93ú
\96{
\8cê
\90ê
\97p
\82Ì
\94z
\97ñ
\82ð
\95Ê
\82É
\97p
\88Ó
\82·
\82é
\81B
2090 static const struct {
2094 { "
\8d\95\82¢", CLR_BLACK },
2095 { "
\90Ô
\82¢", CLR_RED },
2096 { "
\97Î
\90F
\82Ì", CLR_GREEN },
2097 { "
\92\83\90F
\82¢", CLR_BROWN },
2098 { "
\90Â
\82¢", CLR_BLUE },
2099 { "
\83}
\83[
\83\93\83^
\90F
\82Ì", CLR_MAGENTA },
2100 { "
\83V
\83A
\83\93\90F
\82Ì", CLR_CYAN },
2101 { "
\8aD
\90F
\82Ì", CLR_GRAY },
2102 { "
\8aD
\90F
\82Ì", CLR_GRAY },
2103 { "
\83I
\83\8c\83\93\83W
\90F
\82Ì", CLR_ORANGE },
2104 { "
\92W
\97Î
\90F
\82Ì", CLR_BRIGHT_GREEN },
2105 { "
\89©
\90F
\82¢", CLR_YELLOW },
2106 { "
\92W
\90Â
\90F
\82Ì", CLR_BRIGHT_BLUE },
2107 { "
\96¾
\82é
\82¢
\83}
\83[
\83\93\83^
\90F
\82Ì", CLR_BRIGHT_MAGENTA },
2108 { "
\96¾
\82é
\82¢
\83V
\83A
\83\93\90F
\82Ì", CLR_BRIGHT_CYAN },
2109 { "
\94\92\82¢", CLR_WHITE }
2118 for (i = 0; i < SIZE(colornames2); i++)
2119 if (colornames2[i].color == clr)
2120 return colornames2[i].name;
2126 glow_color(arti_indx)
2129 int colornum = artilist[arti_indx].acolor;
2131 const char *colorstr = clr2colorname(colornum);
2133 const char *colorstr = clr2colorname2(colornum);
2137 return hcolor(colorstr);
2139 return hcolor_adv(colorstr);
2143 /* glow verb; [0] holds the value used when blind */
2144 static const char *glow_verbs[] = {
2146 "quiver", "flicker", "glimmer", "gleam"
2148 "
\90k
\82¦
\82é", "
\82Ü
\82½
\82½
\82", "
\8cõ
\82é", "
\8bP
\82"
2151 /* relative strength that Sting is glowing (0..3), to select verb */
2153 glow_strength(count)
2156 /* glow strength should also be proportional to proximity and
2157 probably difficulty, but we don't have that information and
2158 gathering it is more trouble than this would be worth */
2159 return (count > 12) ? 3 : (count > 4) ? 2 : (count > 0);
2163 glow_verb(count, ingsfx)
2164 int count; /* 0 means blind rather than no applicable creatures */
2167 static char resbuf[20];
2169 Strcpy(resbuf, glow_verbs[glow_strength(count)]);
2170 /* ing_suffix() will double the last consonant for all the words
2171 we're using and none of them should have that, so bypass it */
2172 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\8eg
\82í
\82È
\82¢*/
2174 Strcat(resbuf, "ing");
2179 /* use for warning "glow" for Sting, Orcrist, and Grimtooth */
2181 Sting_effects(orc_count)
2182 int orc_count; /* new count (warn_obj_cnt is old count); -1 is a flag value */
2185 && (uwep->oartifact == ART_STING
2186 || uwep->oartifact == ART_ORCRIST
2187 || uwep->oartifact == ART_GRIMTOOTH)) {
2188 int oldstr = glow_strength(warn_obj_cnt),
2189 newstr = glow_strength(orc_count);
2191 if (orc_count == -1 && warn_obj_cnt > 0) {
2192 /* -1 means that blindness has just been toggled; give a
2193 'continue' message that eventual 'stop' message will match */
2195 pline("%s is %s.", bare_artifactname(uwep),
2196 glow_verb(Blind ? 0 : warn_obj_cnt, TRUE));
2198 pline("%s
\82Í%s
\82¢
\82é
\81D", bare_artifactname(uwep),
2199 jconj(glow_verb(Blind ? 0 : warn_obj_cnt, TRUE), "
\82Ä"));
2201 } else if (newstr > 0 && newstr != oldstr) {
2202 /* 'start' message */
2205 pline("%s %s %s%c", bare_artifactname(uwep),
2206 otense(uwep, glow_verb(orc_count, FALSE)),
2207 glow_color(uwep->oartifact),
2208 (newstr > oldstr) ? '!' : '.');
2210 pline("%s
\82Í%s%s%s", bare_artifactname(uwep),
2211 glow_color(uwep->oartifact),
2212 jconj(glow_verb(orc_count, FALSE), "
\82½"),
2213 (newstr > oldstr) ? "
\81I" : "
\81D");
2215 else if (oldstr == 0) /* quivers */
2217 pline("%s %s slightly.", bare_artifactname(uwep),
2218 otense(uwep, glow_verb(0, FALSE)));
2220 pline("%s
\82Í
\8f
\82µ
\90k
\82¦
\82½
\81D", bare_artifactname(uwep));
2222 } else if (orc_count == 0 && warn_obj_cnt > 0) {
2223 /* 'stop' message */
2225 pline("%s stops %s.", bare_artifactname(uwep),
2226 glow_verb(Blind ? 0 : warn_obj_cnt, TRUE));
2228 pline("%s
\82Í%s
\82Ì
\82ð
\82â
\82ß
\82½
\81D", bare_artifactname(uwep),
2229 glow_verb(Blind ? 0 : warn_obj_cnt, TRUE));
2235 /* called when hero is wielding/applying/invoking a carried item, or
2236 after undergoing a transformation (alignment change, lycanthropy,
2237 polymorph) which might affect item access */
2239 retouch_object(objp, loseit)
2240 struct obj **objp; /* might be destroyed or unintentionally dropped */
2241 boolean loseit; /* whether to drop it if hero can longer touch it */
2243 struct obj *obj = *objp;
2245 if (touch_artifact(obj, &youmonst)) {
2248 boolean ag = (objects[obj->otyp].oc_material == SILVER && Hate_silver),
2249 bane = bane_applies(get_artifact(obj), &youmonst);
2251 /* nothing else to do if hero can successfully handle this object */
2255 /* hero can't handle this object, but didn't get touch_artifact()'s
2256 "<obj> evades your grasp|control" message; give an alternate one */
2258 You_cant("handle %s%s!", yname(obj),
2259 obj->owornmask ? " anymore" : "");
2261 You_cant("%s%s
\82ð
\88µ
\82¦
\82È
\82¢
\81I", obj->owornmask ? "
\82à
\82¤" : "",
2264 /* also inflict damage unless touch_artifact() already did so */
2265 if (!touch_blasted) {
2266 /* damage is somewhat arbitrary; half the usual 1d20 physical
2267 for silver, 1d10 magical for <foo>bane, potentially both */
2269 tmp = rnd(10), dmg += Maybe_Half_Phys(tmp);
2273 Sprintf(buf, "handling %s", killer_xname(obj));
2275 Sprintf(buf, "%s
\82ð
\88µ
\82Á
\82Ä", killer_xname(obj));
2276 losehp(dmg, buf, KILLED_BY);
2277 exercise(A_CON, FALSE);
2281 /* removing a worn item might result in loss of levitation,
2282 dropping the hero onto a polymorph trap or into water or
2283 lava and potentially dropping or destroying the item */
2284 if (obj->owornmask) {
2287 remove_worn_item(obj, FALSE);
2288 for (otmp = invent; otmp; otmp = otmp->nobj)
2295 /* if we still have it and caller wants us to drop it, do so now */
2296 if (loseit && obj) {
2299 hitfloor(obj, TRUE);
2301 /* dropx gives a message iff item lands on an altar */
2302 if (!IS_ALTAR(levl[u.ux][u.uy].typ))
2304 pline("%s to the %s.", Tobjnam(obj, "fall"),
2305 surface(u.ux, u.uy));
2307 pline("%s
\82Í%s
\82É
\97\8e\82¿
\82½
\81D", xname(obj),
2308 surface(u.ux, u.uy));
2312 *objp = obj = 0; /* no longer in inventory */
2317 /* an item which is worn/wielded or an artifact which conveys
2318 something via being carried or which has an #invoke effect
2319 currently in operation undergoes a touch test; if it fails,
2320 it will be unworn/unwielded and revoked but not dropped */
2322 untouchable(obj, drop_untouchable)
2324 boolean drop_untouchable;
2326 struct artifact *art;
2327 boolean beingworn, carryeffect, invoked;
2328 long wearmask = ~(W_QUIVER | (u.twoweap ? 0L : W_SWAPWEP) | W_BALL);
2330 beingworn = ((obj->owornmask & wearmask) != 0L
2331 /* some items in use don't have any wornmask setting */
2332 || (obj->oclass == TOOL_CLASS
2333 && (obj->lamplit || (obj->otyp == LEASH && obj->leashmon)
2334 || (Is_container(obj) && Has_contents(obj)))));
2336 if ((art = get_artifact(obj)) != 0) {
2337 carryeffect = (art->cary.adtyp || art->cspfx);
2338 invoked = (art->inv_prop > 0 && art->inv_prop <= LAST_PROP
2339 && (u.uprops[art->inv_prop].extrinsic & W_ARTI) != 0L);
2341 carryeffect = invoked = FALSE;
2344 if (beingworn || carryeffect || invoked) {
2345 if (!retouch_object(&obj, drop_untouchable)) {
2346 /* "<artifact> is beyond your control" or "you can't handle
2347 <object>" has been given and it is now unworn/unwielded
2348 and possibly dropped (depending upon caller); if dropped,
2349 carried effect was turned off, else we leave that alone;
2350 we turn off invocation property here if still carried */
2352 arti_invoke(obj); /* reverse #invoke */
2359 /* check all items currently in use (mostly worn) for touchability */
2361 retouch_equipment(dropflag)
2362 int dropflag; /* 0==don't drop, 1==drop all, 2==drop weapon */
2364 static int nesting = 0; /* recursion control */
2366 boolean dropit, had_gloves = (uarmg != 0);
2367 int had_rings = (!!uleft + !!uright);
2370 * We can potentially be called recursively if losing/unwearing
2371 * an item causes worn helm of opposite alignment to come off or
2374 * BUG: if the initial call was due to putting on a helm of
2375 * opposite alignment and it does come off to trigger recursion,
2376 * after the inner call executes, the outer call will finish
2377 * using the non-helm alignment rather than the helm alignment
2378 * which triggered this in the first place.
2381 clear_bypasses(); /* init upon initial entry */
2383 dropit = (dropflag > 0); /* drop all or drop weapon */
2384 /* check secondary weapon first, before possibly unwielding primary */
2386 bypass_obj(uswapwep); /* so loop below won't process it again */
2387 (void) untouchable(uswapwep, dropit);
2389 /* check primary weapon next so that they're handled together */
2391 bypass_obj(uwep); /* so loop below won't process it again */
2392 (void) untouchable(uwep, dropit);
2395 /* in case someone is daft enough to add artifact or silver saddle */
2396 if (u.usteed && (obj = which_armor(u.usteed, W_SADDLE)) != 0) {
2397 /* untouchable() calls retouch_object() which expects an object in
2398 hero's inventory, but remove_worn_item() will be harmless for
2399 saddle and we're suppressing drop, so this works as intended */
2400 if (untouchable(obj, FALSE))
2401 dismount_steed(DISMOUNT_THROWN);
2404 * TODO? Force off gloves if either or both rings are going to
2405 * become unworn; force off cloak [suit] before suit [shirt].
2406 * The torso handling is hypothetical; the case for gloves is
2407 * not, due to the possibility of unwearing silver rings.
2410 dropit = (dropflag == 1); /* all untouchable items */
2411 /* loss of levitation (silver ring, or Heart of Ahriman invocation)
2412 might cause hero to lose inventory items (by dropping into lava,
2413 for instance), so inventory traversal needs to rescan the whole
2414 invent chain each time it moves on to another object; we use bypass
2415 handling to keep track of which items have already been processed */
2416 while ((obj = nxt_unbypassed_obj(invent)) != 0)
2417 (void) untouchable(obj, dropit);
2419 if (had_rings != (!!uleft + !!uright) && uarmg && uarmg->cursed)
2420 uncurse(uarmg); /* temporary? hack for ring removal plausibility */
2421 if (had_gloves && !uarmg)
2423 selftouch("After losing your gloves, you");
2425 selftouch("
\8f¬
\8eè
\82ð
\8e¸
\82Á
\82½
\82 \82Æ
\81C
\82 \82È
\82½
\82Í");
2428 clear_bypasses(); /* reset upon final exit */
2431 static int mkot_trap_warn_count = 0;
2434 count_surround_traps(x, y)
2440 int dx, dy, glyph, ret = 0;
2442 for (dx = x - 1; dx < x + 2; ++dx)
2443 for (dy = y - 1; dy < y + 2; ++dy) {
2446 /* If a trap is shown here, don't count it; the hero
2447 * should be expecting it. But if there is a trap here
2448 * that's not shown, either undiscovered or covered by
2449 * something, do count it.
2451 glyph = glyph_at(dx, dy);
2452 if (glyph_is_trap(glyph))
2454 if ((ttmp = t_at(dx, dy)) != 0) {
2458 levp = &levl[dx][dy];
2459 if (IS_DOOR(levp->typ) && (levp->doormask & D_TRAPPED) != 0) {
2463 for (otmp = level.objects[dx][dy]; otmp; otmp = otmp->nexthere)
2464 if (Is_container(otmp) && otmp->otrapped) {
2465 ++ret; /* we're counting locations, so just */
2466 break; /* count the first one in a pile */
2470 * [Shouldn't we also check inventory for a trapped container?
2471 * Even if its trap has already been found, there's no 'tknown'
2472 * flag to help hero remember that so we have nothing comparable
2473 * to a shown glyph to justify skipping it.]
2478 /* sense adjacent traps if wielding MKoT without wearing gloves */
2483 static const char *const heat[7] = {
2484 "cool", "slightly warm", "warm", "very warm",
2485 "hot", "very hot", "like fire"
2488 static const char *const heat[7] = {
2489 "
\97â
\82½
\82", "
\8f
\82µ
\89·
\82©
\82", "
\89·
\82©
\82", "
\82Æ
\82Ä
\82à
\89·
\82©
\82",
2490 "
\94M
\82", "
\82Æ
\82Ä
\82à
\94M
\82", "
\89\8a\82Ì
\82æ
\82¤
\82É"
2494 if (!uarmg && uwep && uwep->oartifact == ART_MASTER_KEY_OF_THIEVERY) {
2495 int idx, ntraps = count_surround_traps(u.ux, u.uy);
2497 if (ntraps != mkot_trap_warn_count) {
2498 idx = min(ntraps, SIZE(heat) - 1);
2500 pline_The("Key feels %s%c", heat[idx], (ntraps > 3) ? '!' : '.');
2502 pline_The("
\8c®
\82Í%s
\8a´
\82¶
\82½%s", heat[idx], (ntraps > 3) ? "
\81I" : "
\81D");
2504 mkot_trap_warn_count = ntraps;
2506 mkot_trap_warn_count = 0;
2509 /* Master Key is magic key if its bless/curse state meets our criteria:
2510 not cursed for rogues or blessed for non-rogues */
2512 is_magic_key(mon, obj)
2513 struct monst *mon; /* if null, non-rogue is assumed */
2516 if (((obj && obj->oartifact == ART_MASTER_KEY_OF_THIEVERY)
2517 && ((mon == &youmonst) ? Role_if(PM_ROGUE)
2518 : (mon && mon->data == &mons[PM_ROGUE])))
2519 ? !obj->cursed : obj->blessed)
2524 /* figure out whether 'mon' (usually youmonst) is carrying the magic key */
2527 struct monst *mon; /* if null, hero assumed */
2530 short key = artilist[ART_MASTER_KEY_OF_THIEVERY].otyp;
2534 for (o = ((mon == &youmonst) ? invent : mon->minvent); o;
2535 o = nxtobj(o, key, FALSE)) {
2536 if (is_magic_key(mon, o))
2539 return (struct obj *) 0;