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-2019 */
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;
1004 int attack_indx, fakeidx, scare_dieroll = MB_MAX_DIEROLL / 2;
1006 result = FALSE; /* no message given yet */
1007 /* the most severe effects are less likely at higher enchantment */
1009 scare_dieroll /= (1 << (mb->spe / 3));
1010 /* if target successfully resisted the artifact damage bonus,
1011 reduce overall likelihood of the assorted special effects */
1012 if (!spec_dbon_applies)
1015 /* might stun even when attempting a more severe effect, but
1016 in that case it will only happen if the other effect fails;
1017 extra damage will apply regardless; 3.4.1: sometimes might
1018 just probe even when it hasn't been enchanted */
1019 do_stun = (max(mb->spe, 0) < rn2(spec_dbon_applies ? 11 : 7));
1021 /* the special effects also boost physical damage; increments are
1022 generally cumulative, but since the stun effect is based on a
1023 different criterium its damage might not be included; the base
1024 damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending
1025 on target's resistance check against AD_STUN (handled by caller)
1026 [note that a successful save against AD_STUN doesn't actually
1027 prevent the target from ending up stunned] */
1028 attack_indx = MB_INDEX_PROBE;
1029 *dmgptr += rnd(4); /* (2..3)d4 */
1031 attack_indx = MB_INDEX_STUN;
1032 *dmgptr += rnd(4); /* (3..4)d4 */
1034 if (dieroll <= scare_dieroll) {
1035 attack_indx = MB_INDEX_SCARE;
1036 *dmgptr += rnd(4); /* (3..5)d4 */
1038 if (dieroll <= (scare_dieroll / 2)) {
1039 attack_indx = MB_INDEX_CANCEL;
1040 *dmgptr += rnd(4); /* (4..6)d4 */
1043 /* give the hit message prior to inflicting the effects */
1044 verb = mb_verb[!!Hallucination][attack_indx];
1045 if (youattack || youdefend || vis) {
1048 pline_The("magic-absorbing blade %s %s!",
1049 vtense((const char *) 0, verb), hittee);
1051 pline("
\96\82\97Í
\82ð
\8bz
\82¢
\82Æ
\82é
\90n
\82ª%s
\82ð%s
\82½
\81I",
1054 /* assume probing has some sort of noticeable feedback
1055 even if it is being done by one monster to another */
1056 if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef))
1057 map_invisible(mdef->mx, mdef->my);
1060 /* now perform special effects */
1061 switch (attack_indx) {
1062 case MB_INDEX_CANCEL:
1063 old_uasmon = youmonst.data;
1064 /* No mdef->mcan check: even a cancelled monster can be polymorphed
1065 * into a golem, and the "cancel" effect acts as if some magical
1066 * energy remains in spellcasting defenders to be absorbed later.
1068 if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) {
1073 if (youmonst.data != old_uasmon)
1074 *dmgptr = 0; /* rehumanized, so no more damage */
1079 context.botl = TRUE;
1081 You("lose magical energy!");
1083 You("
\96\82\96@
\82Ì
\83G
\83l
\83\8b\83M
\81[
\82ð
\8e¸
\82Á
\82½
\81I");
1086 if (mdef->data == &mons[PM_CLAY_GOLEM])
1087 mdef->mhp = 1; /* cancelled clay golems will die */
1088 if (youattack && attacktype(mdef->data, AT_MAGC)) {
1091 context.botl = TRUE;
1093 You("absorb magical energy!");
1095 You("
\96\82\96@
\82Ì
\83G
\83l
\83\8b\83M
\81[
\82ð
\8bz
\82¢
\82Æ
\82Á
\82½
\81I");
1101 case MB_INDEX_SCARE:
1108 multi_reason = "being scared stiff";
1110 multi_reason = "
\8b°
\95|
\82Å
\98T
\94\82\82µ
\82½
\8c\84\82É";
1112 if (magr && magr == u.ustuck && sticks(youmonst.data)) {
1113 u.ustuck = (struct monst *) 0;
1115 You("release %s!", mon_nam(magr));
1117 You("%s
\82ð
\89ð
\95ú
\82µ
\82½
\81I", mon_nam(magr));
1121 if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL))
1124 monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr));
1131 do_stun = TRUE; /* (this is redundant...) */
1134 case MB_INDEX_PROBE:
1135 if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) {
1137 pline_The("%s is insightful.", verb);
1139 pline("
\91\8a\8eè
\82ð%s
\82½
\81D", verb);
1140 /* pre-damage status */
1141 probe_monster(mdef);
1145 /* stun if that was selected and a worse effect didn't occur */
1148 make_stunned(((HStun & TIMEOUT) + 3L), FALSE);
1151 /* avoid extra stun message below if we used mb_verb["stun"] above */
1152 if (attack_indx == MB_INDEX_STUN)
1155 /* lastly, all this magic can be confusing... */
1156 do_confuse = !rn2(12);
1159 make_confused((HConfusion & TIMEOUT) + 4L, FALSE);
1164 /* now give message(s) describing side-effects; Use fakename
1165 so vtense() won't be fooled by assigned name ending in 's' */
1166 fakeidx = youdefend ? 1 : 0;
1167 if (youattack || youdefend || vis) {
1168 (void) upstart(hittee); /* capitalize */
1171 pline("%s %s!", hittee, vtense(fakename[fakeidx], "resist"));
1173 pline("%s
\82Í
\96h
\82¢
\82¾
\81I", hittee);
1174 shieldeff(youdefend ? u.ux : mdef->mx,
1175 youdefend ? u.uy : mdef->my);
1177 if ((do_stun || do_confuse) && flags.verbose) {
1183 Strcat(buf, "stunned");
1184 if (do_stun && do_confuse)
1185 Strcat(buf, " and ");
1187 Strcat(buf, "confused");
1188 pline("%s %s %s%c", hittee, vtense(fakename[fakeidx], "are"), buf,
1189 (do_stun && do_confuse) ? '!' : '.');
1191 if (do_stun && do_confuse)
1192 Strcat(buf, "
\82æ
\82ë
\82ß
\82¢
\82Ä");
1194 Strcat(buf, "
\82æ
\82ë
\82ß
\82¢
\82½");
1196 Strcat(buf, "
\8d¬
\97\90\82µ
\82½");
1197 pline("%s
\82Í%s%s", hittee,
1198 buf, (do_stun && do_confuse) ? "
\81I" : "
\81D");
1206 /* Function used when someone attacks someone else with an artifact
1207 * weapon. Only adds the special (artifact) damage, and returns a 1 if it
1208 * did something special (in which case the caller won't print the normal
1209 * hit message). This should be called once upon every artifact attack;
1210 * dmgval() no longer takes artifact bonuses into account. Possible
1211 * extension: change the killer so that when an orc kills you with
1212 * Stormbringer it's "killed by Stormbringer" instead of "killed by an orc".
1215 artifact_hit(magr, mdef, otmp, dmgptr, dieroll)
1216 struct monst *magr, *mdef;
1219 int dieroll; /* needed for Magicbane and vorpal blades */
1221 boolean youattack = (magr == &youmonst);
1222 boolean youdefend = (mdef == &youmonst);
1223 boolean vis = (!youattack && magr && cansee(magr->mx, magr->my))
1224 || (!youdefend && cansee(mdef->mx, mdef->my))
1225 || (youattack && u.uswallow && mdef == u.ustuck && !Blind);
1226 boolean realizes_damage;
1227 const char *wepdesc;
1229 static const char you[] = "you";
1231 static const char you[] = "
\82 \82È
\82½";
1234 Strcpy(hittee, youdefend ? you : mon_nam(mdef));
1236 /* The following takes care of most of the damage, but not all--
1237 * the exception being for level draining, which is specially
1238 * handled. Messages are done in this function, however.
1240 *dmgptr += spec_dbon(otmp, mdef, *dmgptr);
1242 if (youattack && youdefend) {
1243 impossible("attacking yourself with weapon?");
1247 realizes_damage = (youdefend || vis
1248 /* feel the effect even if not seen */
1249 || (youattack && mdef == u.ustuck));
1251 /* the four basic attacks: fire, cold, shock and missiles */
1252 if (attacks(AD_FIRE, otmp)) {
1253 if (realizes_damage)
1255 pline_The("fiery blade %s %s%c",
1258 : (mdef->data == &mons[PM_WATER_ELEMENTAL])
1259 ? "vaporizes part of"
1261 hittee, !spec_dbon_applies ? '.' : '!');
1263 pline_The("
\96Ò
\89Î
\82ª%s%s",
1266 ? "
\82É
\96½
\92\86\82µ
\82½
\81D"
1267 : (mdef->data == &mons[PM_WATER_ELEMENTAL])
1268 ? "
\82Ì
\88ê
\95\94\82ð
\8fÁ
\96Å
\82³
\82¹
\82½
\81I"
1269 : "
\82ð
\8fÄ
\82¢
\82½
\81I");
1272 (void) destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
1274 (void) destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
1276 (void) destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
1277 if (youdefend && Slimed)
1279 return realizes_damage;
1281 if (attacks(AD_COLD, otmp)) {
1282 if (realizes_damage)
1284 pline_The("ice-cold blade %s %s%c",
1285 !spec_dbon_applies ? "hits" : "freezes", hittee,
1286 !spec_dbon_applies ? '.' : '!');
1288 pline_The("
\96Ò
\90\81\90á
\82ª%s%s",
1290 !spec_dbon_applies ? "
\82É
\96½
\92\86\82µ
\82½
\81D" : "
\82ð
\8fP
\82Á
\82½
\81I");
1293 (void) destroy_mitem(mdef, POTION_CLASS, AD_COLD);
1294 return realizes_damage;
1296 if (attacks(AD_ELEC, otmp)) {
1297 if (realizes_damage)
1299 pline_The("massive hammer hits%s %s%c",
1300 !spec_dbon_applies ? "" : "! Lightning strikes",
1301 hittee, !spec_dbon_applies ? '.' : '!');
1303 pline("
\8b\90\91å
\82È
\83n
\83\93\83}
\81[
\82Í%s
\82É
\96½
\92\86\82µ
\82½%s", hittee,
1304 !spec_dbon_applies ? "
\81D" : "
\81I
\93d
\8c\82\82ª
\8fP
\82Á
\82½
\81I");
1306 if (spec_dbon_applies)
1307 wake_nearto(mdef->mx, mdef->my, 4 * 4);
1309 (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC);
1311 (void) destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
1312 return realizes_damage;
1314 if (attacks(AD_MAGM, otmp)) {
1315 if (realizes_damage)
1317 pline_The("imaginary widget hits%s %s%c",
1320 : "! A hail of magic missiles strikes",
1321 hittee, !spec_dbon_applies ? '.' : '!');
1323 pline("
\8eÀ
\91Ì
\82ð
\8e\9d\82½
\82È
\82¢
\95¨
\91Ì
\82ª%s
\82ð
\8dU
\8c\82\82µ
\82½%s",
1325 !spec_dbon_applies ? "
\81D" :
1326 "
\81I
\96\82\96@
\82Ì
\96î
\82ª
\89J
\82 \82ç
\82ê
\82Æ
\96½
\92\86\82µ
\82½
\81I");
1328 return realizes_damage;
1331 if (attacks(AD_STUN, otmp) && dieroll <= MB_MAX_DIEROLL) {
1332 /* Magicbane's special attacks (possibly modifies hittee[]) */
1333 return Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee);
1336 if (!spec_dbon_applies) {
1337 /* since damage bonus didn't apply, nothing more to do;
1338 no further attacks have side-effects on inventory */
1342 /* We really want "on a natural 20" but Nethack does it in */
1343 /* reverse from AD&D. */
1344 if (spec_ability(otmp, SPFX_BEHEAD)) {
1345 if (otmp->oartifact == ART_TSURUGI_OF_MURAMASA && dieroll == 1) {
1347 wepdesc = "The razor-sharp blade";
1349 wepdesc = "
\8ea
\93S
\8c\95";
1350 /* not really beheading, but so close, why add another SPFX */
1351 if (youattack && u.uswallow && mdef == u.ustuck) {
1353 You("slice %s wide open!", mon_nam(mdef));
1355 You("%s
\82ð
\97Ö
\90Ø
\82è
\82É
\82µ
\82½
\81I", mon_nam(mdef));
1356 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1360 /* allow normal cutworm() call to add extra damage */
1364 if (bigmonst(mdef->data)) {
1367 You("slice deeply into %s!", mon_nam(mdef));
1369 You("%s
\82É
\90[
\82
\8ea
\82è
\82Â
\82¯
\82½
\81I",mon_nam(mdef));
1372 pline("%s cuts deeply into %s!", Monnam(magr),
1375 pline("%s
\82Í%s
\82É
\90[
\82
\8ea
\82è
\82Â
\82¯
\82½
\81I", Monnam(magr),
1381 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1383 pline("%s cuts %s in half!", wepdesc, mon_nam(mdef));
1385 pline("%s
\82ª%s
\82ð
\90^
\82Á
\93ñ
\82Â
\82É
\82µ
\82½
\81I", wepdesc, mon_nam(mdef));
1386 otmp->dknown = TRUE;
1389 if (bigmonst(youmonst.data)) {
1391 pline("%s cuts deeply into you!",
1393 pline("%s
\82Í
\82 \82È
\82½
\82É
\90[
\82
\8ea
\82è
\82Â
\82¯
\82½
\81I",
1394 magr ? Monnam(magr) : wepdesc);
1399 /* Players with negative AC's take less damage instead
1400 * of just not getting hit. We must add a large enough
1401 * value to the damage so that this reduction in
1402 * damage does not prevent death.
1404 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER;
1406 pline("%s cuts you in half!", wepdesc);
1408 pline("%s
\82ª
\82 \82È
\82½
\82ð
\90^
\82Á
\93ñ
\82Â
\82É
\82µ
\82½
\81I", wepdesc);
1409 otmp->dknown = TRUE;
1412 } else if (otmp->oartifact == ART_VORPAL_BLADE
1413 && (dieroll == 1 || mdef->data == &mons[PM_JABBERWOCK])) {
1415 static const char *const behead_msg[2] = { "%s beheads %s!",
1416 "%s decapitates %s!" };
1418 static const char *const behead_msg[2] = { "%s
\82Í%s
\82Ì
\8eñ
\82ð
\90Ø
\82Á
\82½
\81I",
1419 "%s
\82Í%s
\82Ì
\8eñ
\82ð
\90Ø
\82è
\97\8e\82µ
\82½
\81I" };
1422 if (youattack && u.uswallow && mdef == u.ustuck)
1424 wepdesc = artilist[ART_VORPAL_BLADE].name;
1426 if (!has_head(mdef->data) || notonhead || u.uswallow) {
1429 pline("Somehow, you miss %s wildly.", mon_nam(mdef));
1431 pline("
\82È
\82º
\82©
\81C%s
\82Ö
\82Ì
\8dU
\8c\82\82Í
\91å
\82«
\82
\82Í
\82¸
\82ê
\82½
\81D", mon_nam(mdef));
1434 pline("Somehow, %s misses wildly.", mon_nam(magr));
1436 pline("
\82È
\82º
\82©
\81C%s
\82Ì
\8dU
\8c\82\82Í
\91å
\82«
\82
\82Í
\82¸
\82ê
\82½
\81D", mon_nam(magr));
1438 return (boolean) (youattack || vis);
1440 if (noncorporeal(mdef->data) || amorphous(mdef->data)) {
1442 pline("%s slices through %s %s.", wepdesc,
1443 s_suffix(mon_nam(mdef)), mbodypart(mdef, NECK));
1445 pline("%s
\82Í%s
\82Ì%s
\82ð
\90Ø
\82è
\97\8e\82µ
\82½
\81D", wepdesc,
1446 mon_nam(mdef), mbodypart(mdef, NECK));
1450 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1451 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc,
1453 if (Hallucination && !flags.female)
1455 pline("Good job Henry, but that wasn't Anne.");
1457 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");
1458 otmp->dknown = TRUE;
1461 if (!has_head(youmonst.data)) {
1463 pline("Somehow, %s misses you wildly.",
1465 pline("
\82È
\82º
\82©
\81C%s
\82Ì
\8dU
\8c\82\82Í
\91å
\82«
\82
\82Í
\82¸
\82ê
\82½
\81D",
1466 magr ? mon_nam(magr) : wepdesc);
1470 if (noncorporeal(youmonst.data) || amorphous(youmonst.data)) {
1472 pline("%s slices through your %s.", wepdesc,
1474 pline("%s
\82Í
\82 \82È
\82½
\82Ì%s
\82ð
\90Ø
\82è
\97\8e\82µ
\82½
\81D", wepdesc,
1478 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER;
1480 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "you");
1482 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "
\82 \82È
\82½");
1483 otmp->dknown = TRUE;
1484 /* Should amulets fall off? */
1489 if (spec_ability(otmp, SPFX_DRLI)) {
1490 /* some non-living creatures (golems, vortices) are
1491 vulnerable to life drain effects */
1493 const char *life = nonliving(mdef->data) ? "animating force" : "life";
1495 const char *life = nonliving(mdef->data) ? "
\93®
\8dì
\97Í" : "
\90¶
\96½
\97Í";
1499 if (otmp->oartifact == ART_STORMBRINGER)
1501 pline_The("%s blade draws the %s from %s!",
1502 hcolor(NH_BLACK), life, mon_nam(mdef));
1504 pline("%s
\90n
\82ª%s
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I",
1505 hcolor(NH_BLACK), mon_nam(mdef), life);
1509 pline("%s draws the %s from %s!",
1510 The(distant_name(otmp, xname)), life,
1513 pline("%s
\82Í%s
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I",
1514 The(distant_name(otmp, xname)),
1515 mon_nam(mdef), life);
1518 if (mdef->m_lev == 0) {
1519 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1521 int drain = monhp_per_lvl(mdef);
1524 mdef->mhpmax -= drain;
1528 healup(drain, 0, FALSE, FALSE);
1531 } else { /* youdefend */
1532 int oldhpmax = u.uhpmax;
1536 You_feel("an %s drain your %s!",
1537 (otmp->oartifact == ART_STORMBRINGER)
1542 pline("%s
\82É%s
\82ð
\92D
\82í
\82ê
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I",
1543 (otmp->oartifact == ART_STORMBRINGER)
1544 ? "
\95s
\8fò
\82È
\90n"
1548 else if (otmp->oartifact == ART_STORMBRINGER)
1550 pline_The("%s blade drains your %s!", hcolor(NH_BLACK), life);
1552 pline("%s
\90n
\82ª
\82 \82È
\82½
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I", hcolor(NH_BLACK), life);
1555 pline("%s drains your %s!", The(distant_name(otmp, xname)),
1558 pline("%s
\82ª
\82 \82È
\82½
\82Ì%s
\82ð
\92D
\82Á
\82½
\81I", The(distant_name(otmp, xname)),
1562 losexp("life drainage");
1564 losexp("
\90¶
\96½
\97Í
\82ð
\8bz
\8eû
\82³
\82ê
\82Ä");
1565 if (magr && magr->mhp < magr->mhpmax) {
1566 magr->mhp += (oldhpmax - u.uhpmax) / 2;
1567 if (magr->mhp > magr->mhpmax)
1568 magr->mhp = magr->mhpmax;
1576 static NEARDATA const char recharge_type[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
1577 static NEARDATA const char invoke_types[] = { ALL_CLASSES, 0 };
1578 /* #invoke: an "ugly check" filters out most objects */
1580 /* the #invoke command */
1586 obj = getobj(invoke_types, "invoke");
1589 if (!retouch_object(&obj, FALSE))
1591 return arti_invoke(obj);
1598 register const struct artifact *oart = get_artifact(obj);
1600 impossible("arti_invoke without obj");
1603 if (!oart || !oart->inv_prop) {
1604 if (obj->otyp == CRYSTAL_BALL)
1605 use_crystal_ball(&obj);
1607 pline1(nothing_happens);
1611 if (oart->inv_prop > LAST_PROP) {
1612 /* It's a special power, not "just" a property */
1613 if (obj->age > monstermoves) {
1614 /* the artifact is tired :-) */
1616 You_feel("that %s %s ignoring you.", the(xname(obj)),
1617 otense(obj, "are"));
1619 You_feel("%s
\82ª
\96³
\8e\8b\82µ
\82Ä
\82¢
\82é
\82æ
\82¤
\82É
\8a´
\82¶
\82½
\81D", xname(obj));
1621 /* and just got more so; patience is essential... */
1622 obj->age += (long) d(3, 10);
1625 obj->age = monstermoves + rnz(100);
1627 switch (oart->inv_prop) {
1632 zeroobj; /* neither cursed nor blessed, zero oextra too */
1633 pseudo.otyp = SCR_TAMING;
1634 (void) seffects(&pseudo);
1638 int healamt = (u.uhpmax + 1 - u.uhp) / 2;
1639 long creamed = (long) u.ucreamed;
1642 healamt = (u.mhmax + 1 - u.mh) / 2;
1643 if (healamt || Sick || Slimed || Blinded > creamed)
1645 You_feel("better.");
1647 You_feel("
\8bC
\95ª
\82ª
\82æ
\82
\82È
\82Á
\82½
\81D");
1649 goto nothing_special;
1657 make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1659 make_slimed(0L, (char *) 0);
1660 if (Blinded > creamed)
1661 make_blinded(creamed, FALSE);
1662 context.botl = TRUE;
1665 case ENERGY_BOOST: {
1666 int epboost = (u.uenmax + 1 - u.uen) / 2;
1669 epboost = 120; /* arbitrary */
1670 else if (epboost < 12)
1671 epboost = u.uenmax - u.uen;
1674 context.botl = TRUE;
1676 You_feel("re-energized.");
1678 You("
\83G
\83l
\83\8b\83M
\81[
\82Å
\96\9e\82½
\82³
\82ê
\82½
\81D");
1680 goto nothing_special;
1684 if (!untrap(TRUE)) {
1685 obj->age = 0; /* don't charge for changing their mind */
1691 struct obj *otmp = getobj(recharge_type, "charge");
1698 b_effect = (obj->blessed && (oart->role == Role_switch
1699 || oart->role == NON_PM));
1700 recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0);
1707 case CREATE_PORTAL: {
1708 int i, num_ok_dungeons, last_ok_dungeon = 0;
1710 extern int n_dgns; /* from dungeon.c */
1711 winid tmpwin = create_nhwindow(NHW_MENU);
1714 any = zeroany; /* set all bits to zero */
1716 /* use index+1 (cant use 0) as identifier */
1717 for (i = num_ok_dungeons = 0; i < n_dgns; i++) {
1718 if (!dungeons[i].dunlev_ureached)
1721 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1722 dungeons[i].dname, MENU_UNSELECTED);
1724 last_ok_dungeon = i;
1727 end_menu(tmpwin, "Open a portal to which dungeon?");
1729 end_menu(tmpwin, "
\82Ç
\82Ì
\96À
\8b{
\82Ö
\82Ì
\96\82\96@
\82Ì
\93ü
\8cû
\82ð
\8aJ
\82«
\82Ü
\82·
\82©
\81H");
1730 if (num_ok_dungeons > 1) {
1731 /* more than one entry; display menu for choices */
1732 menu_item *selected;
1735 n = select_menu(tmpwin, PICK_ONE, &selected);
1737 destroy_nhwindow(tmpwin);
1738 goto nothing_special;
1740 i = selected[0].item.a_int - 1;
1741 free((genericptr_t) selected);
1743 i = last_ok_dungeon; /* also first & only OK dungeon */
1744 destroy_nhwindow(tmpwin);
1747 * i is now index into dungeon structure for the new dungeon.
1748 * Find the closest level in the given dungeon, open
1749 * a use-once portal to that dungeon and go there.
1750 * The closest level is either the entry or dunlev_ureached.
1753 if (dungeons[i].depth_start >= depth(&u.uz))
1754 newlev.dlevel = dungeons[i].entry_lev;
1756 newlev.dlevel = dungeons[i].dunlev_ureached;
1758 if (u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev)
1759 || newlev.dnum == u.uz.dnum || !next_to_u()) {
1761 You_feel("very disoriented for a moment.");
1763 You("
\88ê
\8fu
\95û
\8cü
\8a´
\8ao
\82ð
\8e¸
\82Á
\82½
\81D");
1767 You("are surrounded by a shimmering sphere!");
1769 You("
\83`
\83J
\83`
\83J
\8cõ
\82é
\8b\85\91Ì
\82É
\95¢
\82í
\82ê
\82½
\81I");
1772 You_feel("weightless for a moment.");
1774 You_feel("
\88ê
\8fu
\81C
\96³
\8fd
\97Í
\8a´
\82ð
\8a´
\82¶
\82½
\81D");
1775 goto_level(&newlev, FALSE, FALSE, FALSE);
1780 enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS);
1783 struct obj *otmp = mksobj(ARROW, TRUE, FALSE);
1786 goto nothing_special;
1787 otmp->blessed = obj->blessed;
1788 otmp->cursed = obj->cursed;
1789 otmp->bknown = obj->bknown;
1793 otmp->quan += rnd(10);
1794 } else if (obj->cursed) {
1798 otmp->quan += rnd(5);
1799 otmp->owt = weight(otmp);
1801 otmp = hold_another_object(otmp, "Suddenly %s out.",
1802 aobjnam(otmp, "fall"), (char *) 0);
1804 otmp = hold_another_object(otmp, "
\93Ë
\91R%s
\82ª
\97\8e\82¿
\82½
\81D",
1812 long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI),
1813 iprop = u.uprops[oart->inv_prop].intrinsic;
1814 boolean on = (eprop & W_ARTI) != 0; /* true if prop just set */
1816 if (on && obj->age > monstermoves) {
1817 /* the artifact is tired :-) */
1818 u.uprops[oart->inv_prop].extrinsic ^= W_ARTI;
1820 You_feel("that %s %s ignoring you.", the(xname(obj)),
1821 otense(obj, "are"));
1823 You_feel("%s
\82ª
\96³
\8e\8b\82µ
\82Ä
\82¢
\82é
\82æ
\82¤
\82É
\8a´
\82¶
\82½
\81D", xname(obj));
1825 /* can't just keep repeatedly trying */
1826 obj->age += (long) d(3, 10);
1829 /* when turning off property, determine downtime */
1830 /* arbitrary for now until we can tune this -dlc */
1831 obj->age = monstermoves + rnz(100);
1834 if ((eprop & ~W_ARTI) || iprop) {
1836 /* you had the property from some other source too */
1839 You_feel("a surge of power, but nothing seems to happen.");
1841 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");
1844 switch (oart->inv_prop) {
1848 You_feel("like a rabble-rouser.");
1850 You("
\96¯
\8fO
\90î
\93®
\89Æ
\82Ì
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D");
1853 You_feel("the tension decrease around you.");
1855 pline("
\82Ü
\82í
\82è
\82Ì
\8bÙ
\92£
\8a´
\82ª
\82È
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D");
1862 (void) float_down(I_SPECIAL | TIMEOUT, W_ARTI);
1865 if (BInvis || Blind)
1866 goto nothing_special;
1870 Your("body takes on a %s transparency...",
1871 Hallucination ? "normal" : "strange");
1873 pline("%s
\81C
\91Ì
\82Í
\93§
\89ß
\90«
\82ð
\82à
\82Á
\82½
\81D
\81D
\81D",
1874 Hallucination ? "
\82 \82½
\82è
\82Ü
\82¦
\82Ì
\82±
\82Æ
\82¾
\82ª" : "
\8aï
\96
\82È
\82±
\82Æ
\82É");
1878 Your("body seems to unfade...");
1880 Your("
\91Ì
\82Í
\8e\9f\91æ
\82É
\8c©
\82¦
\82é
\82æ
\82¤
\82É
\82È
\82Á
\82Ä
\82«
\82½
\81D
\81D
\81D");
1888 /* will freeing this object from inventory cause levitation to end? */
1890 finesse_ahriman(obj)
1893 const struct artifact *oart;
1894 struct prop save_Lev;
1897 /* if we aren't levitating or this isn't an artifact which confers
1898 levitation via #invoke then freeinv() won't toggle levitation */
1899 if (!Levitation || (oart = get_artifact(obj)) == 0
1900 || oart->inv_prop != LEVITATION || !(ELevitation & W_ARTI))
1903 /* arti_invoke(off) -> float_down() clears I_SPECIAL|TIMEOUT & W_ARTI;
1904 probe ahead to see whether that actually results in floating down;
1905 (this assumes that there aren't two simultaneously invoked artifacts
1906 both conferring levitation--safe, since if there were two of them,
1907 invoking the 2nd would negate the 1st rather than stack with it) */
1908 save_Lev = u.uprops[LEVITATION];
1909 HLevitation &= ~(I_SPECIAL | TIMEOUT);
1910 ELevitation &= ~W_ARTI;
1911 result = (boolean) !Levitation;
1912 u.uprops[LEVITATION] = save_Lev;
1916 /* WAC return TRUE if artifact is always lit */
1921 return (boolean) (get_artifact(obj) && obj->oartifact == ART_SUNSWORD);
1924 /* KMH -- Talking artifacts are finally implemented */
1929 register const struct artifact *oart = get_artifact(obj);
1933 /* Is this a speaking artifact? */
1934 if (!oart || !(oart->spfx & SPFX_SPEAK))
1937 line = getrumor(bcsign(obj), buf, TRUE);
1940 line = "NetHack rumors file closed for renovation.";
1942 line = "
\89\
\82Ì
\90^
\91\8a\82Í
\90V
\91\95\82Ì
\82½
\82ß
\88ê
\8e\9e\95Â
\93X
\81D";
1944 pline("%s:", Tobjnam(obj, "whisper"));
1946 pline("%s
\82Í
\82³
\82³
\82â
\82¢
\82½
\81F", xname(obj));
1952 artifact_has_invprop(otmp, inv_prop)
1956 const struct artifact *arti = get_artifact(otmp);
1958 return (boolean) (arti && (arti->inv_prop == inv_prop));
1961 /* Return the price sold to the hero of a given artifact or unique item */
1966 if (!otmp->oartifact)
1967 return (long) objects[otmp->otyp].oc_cost;
1968 else if (artilist[(int) otmp->oartifact].cost)
1969 return artilist[(int) otmp->oartifact].cost;
1971 return (100L * (long) objects[otmp->otyp].oc_cost);
1978 struct abil2adtyp_tag {
1982 { &EFire_resistance, AD_FIRE },
1983 { &ECold_resistance, AD_COLD },
1984 { &EShock_resistance, AD_ELEC },
1985 { &EAntimagic, AD_MAGM },
1986 { &EDisint_resistance, AD_DISN },
1987 { &EPoison_resistance, AD_DRST },
1988 { &EDrain_resistance, AD_DRLI },
1992 for (k = 0; k < SIZE(abil2adtyp); k++) {
1993 if (abil2adtyp[k].abil == abil)
1994 return abil2adtyp[k].adtyp;
1999 STATIC_OVL unsigned long
2003 static const struct abil2spfx_tag {
2007 { &ESearching, SPFX_SEARCH },
2008 { &EHalluc_resistance, SPFX_HALRES },
2009 { &ETelepat, SPFX_ESP },
2010 { &EStealth, SPFX_STLTH },
2011 { &ERegeneration, SPFX_REGEN },
2012 { &ETeleport_control, SPFX_TCTRL },
2013 { &EWarn_of_mon, SPFX_WARN },
2014 { &EWarning, SPFX_WARN },
2015 { &EEnergy_regeneration, SPFX_EREGEN },
2016 { &EHalf_spell_damage, SPFX_HSPDAM },
2017 { &EHalf_physical_damage, SPFX_HPHDAM },
2018 { &EReflecting, SPFX_REFLECT },
2022 for (k = 0; k < SIZE(abil2spfx); k++) {
2023 if (abil2spfx[k].abil == abil)
2024 return abil2spfx[k].spfx;
2030 * Return the first item that is conveying a particular intrinsic.
2040 long wornmask = (W_ARM | W_ARMC | W_ARMH | W_ARMS
2041 | W_ARMG | W_ARMF | W_ARMU
2042 | W_AMUL | W_RINGL | W_RINGR | W_TOOL
2046 wornmask |= W_SWAPWEP;
2047 dtyp = abil_to_adtyp(abil);
2048 spfx = abil_to_spfx(abil);
2049 wornbits = (wornmask & *abil);
2051 for (obj = invent; obj; obj = obj->nobj) {
2053 && (abil != &EWarn_of_mon || context.warntype.obj)) {
2054 const struct artifact *art = get_artifact(obj);
2058 if (art->cary.adtyp == dtyp /* carried */
2059 || (art->defn.adtyp == dtyp /* defends while worn */
2060 && (obj->owornmask & ~(W_ART | W_ARTI))))
2064 /* property conferred when carried */
2065 if ((art->cspfx & spfx) == spfx)
2067 /* property conferred when wielded or worn */
2068 if ((art->spfx & spfx) == spfx && obj->owornmask)
2073 if (wornbits && wornbits == (wornmask & obj->owornmask))
2077 return (struct obj *) 0;
2081 /*JP colornames
\82Í
\90Ý
\92è
\83t
\83@
\83C
\83\8b\82Å
\8eg
\82¤
\82Ì
\82Å
\96|
\96ó
\82¹
\82¸
\81A
2082 \93ú
\96{
\8cê
\90ê
\97p
\82Ì
\94z
\97ñ
\82ð
\95Ê
\82É
\97p
\88Ó
\82·
\82é
\81B
2084 static const struct {
2088 { "
\8d\95\82¢", CLR_BLACK },
2089 { "
\90Ô
\82¢", CLR_RED },
2090 { "
\97Î
\90F
\82Ì", CLR_GREEN },
2091 { "
\92\83\90F
\82¢", CLR_BROWN },
2092 { "
\90Â
\82¢", CLR_BLUE },
2093 { "
\83}
\83[
\83\93\83^
\90F
\82Ì", CLR_MAGENTA },
2094 { "
\83V
\83A
\83\93\90F
\82Ì", CLR_CYAN },
2095 { "
\8aD
\90F
\82Ì", CLR_GRAY },
2096 { "
\8aD
\90F
\82Ì", CLR_GRAY },
2097 { "
\83I
\83\8c\83\93\83W
\90F
\82Ì", CLR_ORANGE },
2098 { "
\92W
\97Î
\90F
\82Ì", CLR_BRIGHT_GREEN },
2099 { "
\89©
\90F
\82¢", CLR_YELLOW },
2100 { "
\92W
\90Â
\90F
\82Ì", CLR_BRIGHT_BLUE },
2101 { "
\96¾
\82é
\82¢
\83}
\83[
\83\93\83^
\90F
\82Ì", CLR_BRIGHT_MAGENTA },
2102 { "
\96¾
\82é
\82¢
\83V
\83A
\83\93\90F
\82Ì", CLR_BRIGHT_CYAN },
2103 { "
\94\92\82¢", CLR_WHITE }
2112 for (i = 0; i < SIZE(colornames2); i++)
2113 if (colornames2[i].color == clr)
2114 return colornames2[i].name;
2120 glow_color(arti_indx)
2123 int colornum = artilist[arti_indx].acolor;
2125 const char *colorstr = clr2colorname(colornum);
2127 const char *colorstr = jconj_adj(clr2colorname2(colornum));
2130 return hcolor(colorstr);
2133 /* glow verb; [0] holds the value used when blind */
2134 static const char *glow_verbs[] = {
2136 "quiver", "flicker", "glimmer", "gleam"
2138 "
\90k
\82¦
\82é", "
\82Ü
\82½
\82½
\82", "
\8cõ
\82é", "
\8bP
\82"
2141 /* relative strength that Sting is glowing (0..3), to select verb */
2143 glow_strength(count)
2146 /* glow strength should also be proportional to proximity and
2147 probably difficulty, but we don't have that information and
2148 gathering it is more trouble than this would be worth */
2149 return (count > 12) ? 3 : (count > 4) ? 2 : (count > 0);
2153 glow_verb(count, ingsfx)
2154 int count; /* 0 means blind rather than no applicable creatures */
2157 static char resbuf[20];
2159 Strcpy(resbuf, glow_verbs[glow_strength(count)]);
2160 /* ing_suffix() will double the last consonant for all the words
2161 we're using and none of them should have that, so bypass it */
2162 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\8eg
\82í
\82È
\82¢*/
2164 Strcat(resbuf, "ing");
2169 /* use for warning "glow" for Sting, Orcrist, and Grimtooth */
2171 Sting_effects(orc_count)
2172 int orc_count; /* new count (warn_obj_cnt is old count); -1 is a flag value */
2175 && (uwep->oartifact == ART_STING
2176 || uwep->oartifact == ART_ORCRIST
2177 || uwep->oartifact == ART_GRIMTOOTH)) {
2178 int oldstr = glow_strength(warn_obj_cnt),
2179 newstr = glow_strength(orc_count);
2181 if (orc_count == -1 && warn_obj_cnt > 0) {
2182 /* -1 means that blindness has just been toggled; give a
2183 'continue' message that eventual 'stop' message will match */
2185 pline("%s is %s.", bare_artifactname(uwep),
2186 glow_verb(Blind ? 0 : warn_obj_cnt, TRUE));
2188 pline("%s
\82Í%s
\82¢
\82é
\81D", bare_artifactname(uwep),
2189 jconj(glow_verb(Blind ? 0 : warn_obj_cnt, TRUE), "
\82Ä"));
2191 } else if (newstr > 0 && newstr != oldstr) {
2192 /* 'start' message */
2195 pline("%s %s %s%c", bare_artifactname(uwep),
2196 otense(uwep, glow_verb(orc_count, FALSE)),
2197 glow_color(uwep->oartifact),
2198 (newstr > oldstr) ? '!' : '.');
2200 pline("%s
\82Í%s%s%s", bare_artifactname(uwep),
2201 jconj_adj(glow_color(uwep->oartifact)),
2202 jconj(glow_verb(orc_count, FALSE), "
\82½"),
2203 (newstr > oldstr) ? "
\81I" : "
\81D");
2205 else if (oldstr == 0) /* quivers */
2207 pline("%s %s slightly.", bare_artifactname(uwep),
2208 otense(uwep, glow_verb(0, FALSE)));
2210 pline("%s
\82Í
\8f
\82µ
\90k
\82¦
\82½
\81D", bare_artifactname(uwep));
2212 } else if (orc_count == 0 && warn_obj_cnt > 0) {
2213 /* 'stop' message */
2215 pline("%s stops %s.", bare_artifactname(uwep),
2216 glow_verb(Blind ? 0 : warn_obj_cnt, TRUE));
2218 pline("%s
\82Í%s
\82Ì
\82ð
\82â
\82ß
\82½
\81D", bare_artifactname(uwep),
2219 glow_verb(Blind ? 0 : warn_obj_cnt, TRUE));
2225 /* called when hero is wielding/applying/invoking a carried item, or
2226 after undergoing a transformation (alignment change, lycanthropy,
2227 polymorph) which might affect item access */
2229 retouch_object(objp, loseit)
2230 struct obj **objp; /* might be destroyed or unintentionally dropped */
2231 boolean loseit; /* whether to drop it if hero can longer touch it */
2233 struct obj *obj = *objp;
2235 if (touch_artifact(obj, &youmonst)) {
2238 boolean ag = (objects[obj->otyp].oc_material == SILVER && Hate_silver),
2239 bane = bane_applies(get_artifact(obj), &youmonst);
2241 /* nothing else to do if hero can successfully handle this object */
2245 /* hero can't handle this object, but didn't get touch_artifact()'s
2246 "<obj> evades your grasp|control" message; give an alternate one */
2248 You_cant("handle %s%s!", yname(obj),
2249 obj->owornmask ? " anymore" : "");
2251 You_cant("%s%s
\82ð
\88µ
\82¦
\82È
\82¢
\81I", obj->owornmask ? "
\82à
\82¤" : "",
2254 /* also inflict damage unless touch_artifact() already did so */
2255 if (!touch_blasted) {
2256 /* damage is somewhat arbitrary; half the usual 1d20 physical
2257 for silver, 1d10 magical for <foo>bane, potentially both */
2259 tmp = rnd(10), dmg += Maybe_Half_Phys(tmp);
2263 Sprintf(buf, "handling %s", killer_xname(obj));
2265 Sprintf(buf, "%s
\82ð
\88µ
\82Á
\82Ä", killer_xname(obj));
2266 losehp(dmg, buf, KILLED_BY);
2267 exercise(A_CON, FALSE);
2271 /* removing a worn item might result in loss of levitation,
2272 dropping the hero onto a polymorph trap or into water or
2273 lava and potentially dropping or destroying the item */
2274 if (obj->owornmask) {
2277 remove_worn_item(obj, FALSE);
2278 for (otmp = invent; otmp; otmp = otmp->nobj)
2285 /* if we still have it and caller wants us to drop it, do so now */
2286 if (loseit && obj) {
2289 hitfloor(obj, TRUE);
2291 /* dropx gives a message iff item lands on an altar */
2292 if (!IS_ALTAR(levl[u.ux][u.uy].typ))
2294 pline("%s to the %s.", Tobjnam(obj, "fall"),
2295 surface(u.ux, u.uy));
2297 pline("%s
\82Í%s
\82É
\97\8e\82¿
\82½
\81D", xname(obj),
2298 surface(u.ux, u.uy));
2302 *objp = obj = 0; /* no longer in inventory */
2307 /* an item which is worn/wielded or an artifact which conveys
2308 something via being carried or which has an #invoke effect
2309 currently in operation undergoes a touch test; if it fails,
2310 it will be unworn/unwielded and revoked but not dropped */
2312 untouchable(obj, drop_untouchable)
2314 boolean drop_untouchable;
2316 struct artifact *art;
2317 boolean beingworn, carryeffect, invoked;
2318 long wearmask = ~(W_QUIVER | (u.twoweap ? 0L : W_SWAPWEP) | W_BALL);
2320 beingworn = ((obj->owornmask & wearmask) != 0L
2321 /* some items in use don't have any wornmask setting */
2322 || (obj->oclass == TOOL_CLASS
2323 && (obj->lamplit || (obj->otyp == LEASH && obj->leashmon)
2324 || (Is_container(obj) && Has_contents(obj)))));
2326 if ((art = get_artifact(obj)) != 0) {
2327 carryeffect = (art->cary.adtyp || art->cspfx);
2328 invoked = (art->inv_prop > 0 && art->inv_prop <= LAST_PROP
2329 && (u.uprops[art->inv_prop].extrinsic & W_ARTI) != 0L);
2331 carryeffect = invoked = FALSE;
2334 if (beingworn || carryeffect || invoked) {
2335 if (!retouch_object(&obj, drop_untouchable)) {
2336 /* "<artifact> is beyond your control" or "you can't handle
2337 <object>" has been given and it is now unworn/unwielded
2338 and possibly dropped (depending upon caller); if dropped,
2339 carried effect was turned off, else we leave that alone;
2340 we turn off invocation property here if still carried */
2342 arti_invoke(obj); /* reverse #invoke */
2349 /* check all items currently in use (mostly worn) for touchability */
2351 retouch_equipment(dropflag)
2352 int dropflag; /* 0==don't drop, 1==drop all, 2==drop weapon */
2354 static int nesting = 0; /* recursion control */
2356 boolean dropit, had_gloves = (uarmg != 0);
2357 int had_rings = (!!uleft + !!uright);
2360 * We can potentially be called recursively if losing/unwearing
2361 * an item causes worn helm of opposite alignment to come off or
2364 * BUG: if the initial call was due to putting on a helm of
2365 * opposite alignment and it does come off to trigger recursion,
2366 * after the inner call executes, the outer call will finish
2367 * using the non-helm alignment rather than the helm alignment
2368 * which triggered this in the first place.
2371 clear_bypasses(); /* init upon initial entry */
2373 dropit = (dropflag > 0); /* drop all or drop weapon */
2374 /* check secondary weapon first, before possibly unwielding primary */
2376 bypass_obj(uswapwep); /* so loop below won't process it again */
2377 (void) untouchable(uswapwep, dropit);
2379 /* check primary weapon next so that they're handled together */
2381 bypass_obj(uwep); /* so loop below won't process it again */
2382 (void) untouchable(uwep, dropit);
2385 /* in case someone is daft enough to add artifact or silver saddle */
2386 if (u.usteed && (obj = which_armor(u.usteed, W_SADDLE)) != 0) {
2387 /* untouchable() calls retouch_object() which expects an object in
2388 hero's inventory, but remove_worn_item() will be harmless for
2389 saddle and we're suppressing drop, so this works as intended */
2390 if (untouchable(obj, FALSE))
2391 dismount_steed(DISMOUNT_THROWN);
2394 * TODO? Force off gloves if either or both rings are going to
2395 * become unworn; force off cloak [suit] before suit [shirt].
2396 * The torso handling is hypothetical; the case for gloves is
2397 * not, due to the possibility of unwearing silver rings.
2400 dropit = (dropflag == 1); /* all untouchable items */
2401 /* loss of levitation (silver ring, or Heart of Ahriman invocation)
2402 might cause hero to lose inventory items (by dropping into lava,
2403 for instance), so inventory traversal needs to rescan the whole
2404 invent chain each time it moves on to another object; we use bypass
2405 handling to keep track of which items have already been processed */
2406 while ((obj = nxt_unbypassed_obj(invent)) != 0)
2407 (void) untouchable(obj, dropit);
2409 if (had_rings != (!!uleft + !!uright) && uarmg && uarmg->cursed)
2410 uncurse(uarmg); /* temporary? hack for ring removal plausibility */
2411 if (had_gloves && !uarmg)
2413 selftouch("After losing your gloves, you");
2415 selftouch("
\8f¬
\8eè
\82ð
\8e¸
\82Á
\82½
\82 \82Æ
\81C
\82 \82È
\82½
\82Í");
2418 clear_bypasses(); /* reset upon final exit */
2421 static int mkot_trap_warn_count = 0;
2424 count_surround_traps(x, y)
2430 int dx, dy, glyph, ret = 0;
2432 for (dx = x - 1; dx < x + 2; ++dx)
2433 for (dy = y - 1; dy < y + 2; ++dy) {
2436 /* If a trap is shown here, don't count it; the hero
2437 * should be expecting it. But if there is a trap here
2438 * that's not shown, either undiscovered or covered by
2439 * something, do count it.
2441 glyph = glyph_at(dx, dy);
2442 if (glyph_is_trap(glyph))
2444 if ((ttmp = t_at(dx, dy)) != 0) {
2448 levp = &levl[dx][dy];
2449 if (IS_DOOR(levp->typ) && (levp->doormask & D_TRAPPED) != 0) {
2453 for (otmp = level.objects[dx][dy]; otmp; otmp = otmp->nexthere)
2454 if (Is_container(otmp) && otmp->otrapped) {
2455 ++ret; /* we're counting locations, so just */
2456 break; /* count the first one in a pile */
2460 * [Shouldn't we also check inventory for a trapped container?
2461 * Even if its trap has already been found, there's no 'tknown'
2462 * flag to help hero remember that so we have nothing comparable
2463 * to a shown glyph to justify skipping it.]
2468 /* sense adjacent traps if wielding MKoT without wearing gloves */
2473 static const char *const heat[7] = {
2474 "cool", "slightly warm", "warm", "very warm",
2475 "hot", "very hot", "like fire"
2478 static const char *const heat[7] = {
2479 "
\97â
\82½
\82", "
\8f
\82µ
\89·
\82©
\82", "
\89·
\82©
\82", "
\82Æ
\82Ä
\82à
\89·
\82©
\82",
2480 "
\94M
\82", "
\82Æ
\82Ä
\82à
\94M
\82", "
\89\8a\82Ì
\82æ
\82¤
\82É"
2484 if (!uarmg && uwep && uwep->oartifact == ART_MASTER_KEY_OF_THIEVERY) {
2485 int idx, ntraps = count_surround_traps(u.ux, u.uy);
2487 if (ntraps != mkot_trap_warn_count) {
2488 idx = min(ntraps, SIZE(heat) - 1);
2490 pline_The("Key feels %s%c", heat[idx], (ntraps > 3) ? '!' : '.');
2492 pline_The("
\8c®
\82Í%s
\8a´
\82¶
\82½%s", heat[idx], (ntraps > 3) ? "
\81I" : "
\81D");
2494 mkot_trap_warn_count = ntraps;
2496 mkot_trap_warn_count = 0;
2499 /* Master Key is magic key if its bless/curse state meets our criteria:
2500 not cursed for rogues or blessed for non-rogues */
2502 is_magic_key(mon, obj)
2503 struct monst *mon; /* if null, non-rogue is assumed */
2506 if (((obj && obj->oartifact == ART_MASTER_KEY_OF_THIEVERY)
2507 && ((mon == &youmonst) ? Role_if(PM_ROGUE)
2508 : (mon && mon->data == &mons[PM_ROGUE])))
2509 ? !obj->cursed : obj->blessed)
2514 /* figure out whether 'mon' (usually youmonst) is carrying the magic key */
2517 struct monst *mon; /* if null, hero assumed */
2520 short key = artilist[ART_MASTER_KEY_OF_THIEVERY].otyp;
2524 for (o = ((mon == &youmonst) ? invent : mon->minvent); o;
2525 o = nxtobj(o, key, FALSE)) {
2526 if (is_magic_key(mon, o))
2529 return (struct obj *) 0;