1 /* NetHack 3.6 artifact.c $NHDT-Date: 1451081581 2015/12/25 22:13:01 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.99 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
10 * Note: both artilist[] and artiexist[] have a dummy element #0,
11 * so loops over them should normally start at #1. The primary
12 * exception is the save & restore code, which doesn't care about
13 * the contents, just the total size.
16 extern boolean notonhead
; /* for long worms */
18 #define get_artifact(o) \
19 (((o) && (o)->oartifact) ? &artilist[(int) (o)->oartifact] : 0)
21 STATIC_DCL boolean
FDECL(bane_applies
, (const struct artifact
*,
23 STATIC_DCL
int FDECL(spec_applies
, (const struct artifact
*, struct monst
*));
24 STATIC_DCL
int FDECL(arti_invoke
, (struct obj
*));
25 STATIC_DCL boolean
FDECL(Mb_hit
, (struct monst
* magr
, struct monst
*mdef
,
26 struct obj
*, int *, int, BOOLEAN_P
, char *));
27 STATIC_DCL
unsigned long FDECL(abil_to_spfx
, (long *));
28 STATIC_DCL uchar
FDECL(abil_to_adtyp
, (long *));
29 STATIC_DCL boolean
FDECL(untouchable
, (struct obj
*, BOOLEAN_P
));
31 /* The amount added to the victim's total hit points to insure that the
32 victim will be killed even after damage bonus/penalty adjustments.
33 Most such penalties are small, and 200 is plenty; the exception is
34 half physical damage. 3.3.1 and previous versions tried to use a very
35 large number to account for this case; now, we just compute the fatal
36 damage by adding it to 2 times the total hit points instead of 1 time.
37 Note: this will still break if they have more than about half the number
38 of hit points that will fit in a 15 bit integer. */
39 #define FATAL_DAMAGE_MODIFIER 200
41 /* coordinate effects from spec_dbon() with messages in artifact_hit() */
42 STATIC_OVL
int spec_dbon_applies
= 0;
44 /* flags including which artifacts have already been created */
45 static boolean artiexist
[1 + NROFARTIFACTS
+ 1];
46 /* and a discovery list for them (no dummy first entry here) */
47 STATIC_OVL xchar artidisco
[NROFARTIFACTS
];
49 STATIC_DCL
void NDECL(hack_artifacts
);
50 STATIC_DCL boolean
FDECL(attacks
, (int, struct obj
*));
52 /* handle some special cases; must be called after u_init() */
57 int alignmnt
= aligns
[flags
.initalign
].value
;
59 /* Fix up the alignments of "gift" artifacts */
60 for (art
= artilist
+ 1; art
->otyp
; art
++)
61 if (art
->role
== Role_switch
&& art
->alignment
!= A_NONE
)
62 art
->alignment
= alignmnt
;
64 /* Excalibur can be used by any lawful character, not just knights */
65 if (!Role_if(PM_KNIGHT
))
66 artilist
[ART_EXCALIBUR
].role
= NON_PM
;
68 /* Fix up the quest artifact */
69 if (urole
.questarti
) {
70 artilist
[urole
.questarti
].alignment
= alignmnt
;
71 artilist
[urole
.questarti
].role
= Role_switch
;
76 /* zero out the artifact existence list */
80 (void) memset((genericptr_t
) artiexist
, 0, sizeof artiexist
);
81 (void) memset((genericptr_t
) artidisco
, 0, sizeof artidisco
);
89 bwrite(fd
, (genericptr_t
) artiexist
, sizeof artiexist
);
90 bwrite(fd
, (genericptr_t
) artidisco
, sizeof artidisco
);
97 mread(fd
, (genericptr_t
) artiexist
, sizeof artiexist
);
98 mread(fd
, (genericptr_t
) artidisco
, sizeof artidisco
);
99 hack_artifacts(); /* redo non-saved special cases */
106 if (artinum
<= 0 || artinum
> NROFARTIFACTS
)
108 return artilist
[artinum
].name
;
112 Make an artifact. If a specific alignment is specified, then an object of
113 the appropriate alignment is created from scratch, or 0 is returned if
114 none is available. (If at least one aligned artifact has already been
115 given, then unaligned ones also become eligible for this.)
116 If no alignment is given, then 'otmp' is converted
117 into an artifact of matching type, or returned as-is if that's not
119 For the 2nd case, caller should use ``obj = mk_artifact(obj, A_NONE);''
120 for the 1st, ``obj = mk_artifact((struct obj *)0, some_alignment);''.
123 mk_artifact(otmp
, alignment
)
124 struct obj
*otmp
; /* existing object; ignored if alignment specified */
125 aligntyp alignment
; /* target alignment, or A_NONE */
127 const struct artifact
*a
;
129 boolean by_align
= (alignment
!= A_NONE
);
130 short o_typ
= (by_align
|| !otmp
) ? 0 : otmp
->otyp
;
131 boolean unique
= !by_align
&& otmp
&& objects
[o_typ
].oc_unique
;
132 short eligible
[NROFARTIFACTS
];
134 n
= altn
= 0; /* no candidates found yet */
135 eligible
[0] = 0; /* lint suppression */
136 /* gather eligible artifacts */
137 for (m
= 1, a
= &artilist
[m
]; a
->otyp
; a
++, m
++) {
140 if ((a
->spfx
& SPFX_NOGEN
) || unique
)
144 /* looking for a particular type of item; not producing a
145 divine gift so we don't care about role's first choice */
146 if (a
->otyp
== o_typ
)
148 continue; /* move on to next possibility */
151 /* we're looking for an alignment-specific item
152 suitable for hero's role+race */
153 if ((a
->alignment
== alignment
|| a
->alignment
== A_NONE
)
154 /* avoid enemies' equipment */
155 && (a
->race
== NON_PM
|| !race_hostile(&mons
[a
->race
]))) {
156 /* when a role-specific first choice is available, use it */
157 if (Role_if(a
->role
)) {
158 /* make this be the only possibility in the list */
161 break; /* skip all other candidates */
163 /* found something to consider for random selection */
164 if (a
->alignment
!= A_NONE
|| u
.ugifts
> 0) {
165 /* right alignment, or non-aligned with at least 1
166 previous gift bestowed, makes this one viable */
169 /* non-aligned with no previous gifts;
170 if no candidates have been found yet, record
171 this one as a[nother] fallback possibility in
172 case all aligned candidates have been used up
173 (via wishing, naming, bones, random generation) */
175 eligible
[altn
++] = m
;
176 /* [once a regular candidate is found, the list
177 is overwritten and `altn' becomes irrelevant] */
182 /* resort to fallback list if main list was empty */
187 /* found at least one candidate; pick one at random */
188 m
= eligible
[rn2(n
)]; /* [0..n-1] */
191 /* make an appropriate object if necessary, then christen it */
193 otmp
= mksobj((int) a
->otyp
, TRUE
, FALSE
);
196 otmp
= oname(otmp
, a
->name
);
201 /* nothing appropriate could be found; return original object */
203 otmp
= 0; /* (there was no original object) */
209 * Returns the full name (with articles and correct capitalization) of an
210 * artifact named "name" if one exists, or NULL, it not.
211 * The given name must be rather close to the real name for it to match.
212 * The object type of the artifact is returned in otyp if the return value
216 artifact_name(name
, otyp
)
220 register const struct artifact
*a
;
221 register const char *aname
;
223 if (!strncmpi(name
, "the ", 4))
226 for (a
= artilist
+ 1; a
->otyp
; a
++) {
228 if (!strncmpi(aname
, "the ", 4))
230 if (!strcmpi(name
, aname
)) {
240 exist_artifact(otyp
, name
)
244 register const struct artifact
*a
;
248 for (a
= artilist
+ 1, arex
= artiexist
+ 1; a
->otyp
; a
++, arex
++)
249 if ((int) a
->otyp
== otyp
&& !strcmp(a
->name
, name
))
255 artifact_exists(otmp
, name
, mod
)
260 register const struct artifact
*a
;
263 for (a
= artilist
+ 1; a
->otyp
; a
++)
264 if (a
->otyp
== otmp
->otyp
&& !strcmp(a
->name
, name
)) {
265 register int m
= (int) (a
- artilist
);
266 otmp
->oartifact
= (char) (mod
? m
: 0);
268 if (otmp
->otyp
== RIN_INCREASE_DAMAGE
)
280 int n
= SIZE(artiexist
);
290 spec_ability(otmp
, abil
)
294 const struct artifact
*arti
= get_artifact(otmp
);
296 return (boolean
) (arti
&& (arti
->spfx
& abil
) != 0L);
299 /* used so that callers don't need to known about SPFX_ codes */
304 /* might as well check for this too */
305 if (obj
->otyp
== LUCKSTONE
)
308 return (boolean
) (obj
->oartifact
&& spec_ability(obj
, SPFX_LUCK
));
311 /* used to check whether a monster is getting reflection from an artifact */
316 const struct artifact
*arti
= get_artifact(obj
);
319 /* while being worn */
320 if ((obj
->owornmask
& ~W_ART
) && (arti
->spfx
& SPFX_REFLECT
))
322 /* just being carried */
323 if (arti
->cspfx
& SPFX_REFLECT
)
329 /* decide whether this obj is effective when attacking against shades;
330 does not consider the bonus for blessed objects versus undead */
335 const struct artifact
*arti
;
337 /* any silver object is effective */
338 if (objects
[obj
->otyp
].oc_material
== SILVER
)
340 /* non-silver artifacts with bonus against undead also are effective */
341 arti
= get_artifact(obj
);
342 if (arti
&& (arti
->spfx
& SPFX_DFLAG2
) && arti
->mtype
== M2_UNDEAD
)
344 /* [if there was anything with special bonus against noncorporeals,
345 it would be effective too] */
346 /* otherwise, harmless to shades */
350 /* returns 1 if name is restricted for otmp->otyp */
352 restrict_name(otmp
, name
)
356 register const struct artifact
*a
;
357 const char *aname
, *odesc
, *other
;
358 boolean sametype
[NUM_OBJECTS
];
359 int i
, lo
, hi
, otyp
= otmp
->otyp
, ocls
= objects
[otyp
].oc_class
;
363 if (!strncmpi(name
, "the ", 4))
366 /* decide what types of objects are the same as otyp;
367 if it's been discovered, then only itself matches;
368 otherwise, include all other undiscovered objects
369 of the same class which have the same description
370 or share the same pool of shuffled descriptions */
371 (void) memset((genericptr_t
) sametype
, 0, sizeof sametype
); /* FALSE */
372 sametype
[otyp
] = TRUE
;
373 if (!objects
[otyp
].oc_name_known
374 && (odesc
= OBJ_DESCR(objects
[otyp
])) != 0) {
375 obj_shuffle_range(otyp
, &lo
, &hi
);
376 for (i
= bases
[ocls
]; i
< NUM_OBJECTS
; i
++) {
377 if (objects
[i
].oc_class
!= ocls
)
379 if (!objects
[i
].oc_name_known
380 && (other
= OBJ_DESCR(objects
[i
])) != 0
381 && (!strcmp(odesc
, other
) || (i
>= lo
&& i
<= hi
)))
386 /* Since almost every artifact is SPFX_RESTR, it doesn't cost
387 us much to do the string comparison before the spfx check.
388 Bug fix: don't name multiple elven daggers "Sting".
390 for (a
= artilist
+ 1; a
->otyp
; a
++) {
391 if (!sametype
[a
->otyp
])
394 if (!strncmpi(aname
, "the ", 4))
396 if (!strcmp(aname
, name
))
397 return (boolean
) ((a
->spfx
& (SPFX_NOGEN
| SPFX_RESTR
)) != 0
409 register const struct artifact
*weap
;
411 if ((weap
= get_artifact(otmp
)) != 0)
412 return (boolean
) (weap
->attk
.adtyp
== adtyp
);
421 register const struct artifact
*weap
;
423 if ((weap
= get_artifact(otmp
)) != 0)
424 return (boolean
) (weap
->defn
.adtyp
== adtyp
);
428 /* used for monsters */
430 defends_when_carried(adtyp
, otmp
)
434 register const struct artifact
*weap
;
436 if ((weap
= get_artifact(otmp
)) != 0)
437 return (boolean
) (weap
->cary
.adtyp
== adtyp
);
441 /* determine whether an item confers Protection */
443 protects(otmp
, being_worn
)
447 const struct artifact
*arti
;
449 if (being_worn
&& objects
[otmp
->otyp
].oc_oprop
== PROTECTION
)
451 arti
= get_artifact(otmp
);
454 return (boolean
) ((arti
->cspfx
& SPFX_PROTECT
) != 0
455 || (being_worn
&& (arti
->spfx
& SPFX_PROTECT
) != 0));
459 * a potential artifact has just been worn/wielded/picked-up or
460 * unworn/unwielded/dropped. Pickup/drop only set/reset the W_ART mask.
463 set_artifact_intrinsic(otmp
, on
, wp_mask
)
469 register const struct artifact
*art
, *oart
= get_artifact(otmp
);
470 register struct obj
*obj
;
477 /* effects from the defn field */
478 dtyp
= (wp_mask
!= W_ART
) ? oart
->defn
.adtyp
: oart
->cary
.adtyp
;
481 mask
= &EFire_resistance
;
482 else if (dtyp
== AD_COLD
)
483 mask
= &ECold_resistance
;
484 else if (dtyp
== AD_ELEC
)
485 mask
= &EShock_resistance
;
486 else if (dtyp
== AD_MAGM
)
488 else if (dtyp
== AD_DISN
)
489 mask
= &EDisint_resistance
;
490 else if (dtyp
== AD_DRST
)
491 mask
= &EPoison_resistance
;
492 else if (dtyp
== AD_DRLI
)
493 mask
= &EDrain_resistance
;
495 if (mask
&& wp_mask
== W_ART
&& !on
) {
496 /* find out if some other artifact also confers this intrinsic;
497 if so, leave the mask alone */
498 for (obj
= invent
; obj
; obj
= obj
->nobj
) {
499 if (obj
!= otmp
&& obj
->oartifact
) {
500 art
= get_artifact(obj
);
501 if (art
->cary
.adtyp
== dtyp
) {
515 /* intrinsics from the spfx field; there could be more than one */
516 spfx
= (wp_mask
!= W_ART
) ? oart
->spfx
: oart
->cspfx
;
517 if (spfx
&& wp_mask
== W_ART
&& !on
) {
518 /* don't change any spfx also conferred by other artifacts */
519 for (obj
= invent
; obj
; obj
= obj
->nobj
)
520 if (obj
!= otmp
&& obj
->oartifact
) {
521 art
= get_artifact(obj
);
526 if (spfx
& SPFX_SEARCH
) {
528 ESearching
|= wp_mask
;
530 ESearching
&= ~wp_mask
;
532 if (spfx
& SPFX_HALRES
) {
533 /* make_hallucinated must (re)set the mask itself to get
534 * the display right */
535 /* restoring needed because this is the only artifact intrinsic
536 * that can print a message--need to guard against being printed
537 * when restoring a game
539 (void) make_hallucinated((long) !on
, restoring
? FALSE
: TRUE
,
542 if (spfx
& SPFX_ESP
) {
546 ETelepat
&= ~wp_mask
;
549 if (spfx
& SPFX_STLTH
) {
553 EStealth
&= ~wp_mask
;
555 if (spfx
& SPFX_REGEN
) {
557 ERegeneration
|= wp_mask
;
559 ERegeneration
&= ~wp_mask
;
561 if (spfx
& SPFX_TCTRL
) {
563 ETeleport_control
|= wp_mask
;
565 ETeleport_control
&= ~wp_mask
;
567 if (spfx
& SPFX_WARN
) {
570 EWarn_of_mon
|= wp_mask
;
571 context
.warntype
.obj
|= spec_m2(otmp
);
573 EWarn_of_mon
&= ~wp_mask
;
574 context
.warntype
.obj
&= ~spec_m2(otmp
);
581 EWarning
&= ~wp_mask
;
584 if (spfx
& SPFX_EREGEN
) {
586 EEnergy_regeneration
|= wp_mask
;
588 EEnergy_regeneration
&= ~wp_mask
;
590 if (spfx
& SPFX_HSPDAM
) {
592 EHalf_spell_damage
|= wp_mask
;
594 EHalf_spell_damage
&= ~wp_mask
;
596 if (spfx
& SPFX_HPHDAM
) {
598 EHalf_physical_damage
|= wp_mask
;
600 EHalf_physical_damage
&= ~wp_mask
;
602 if (spfx
& SPFX_XRAY
) {
603 /* this assumes that no one else is using xray_range */
608 vision_full_recalc
= 1;
610 if ((spfx
& SPFX_REFLECT
) && (wp_mask
& W_WEP
)) {
612 EReflecting
|= wp_mask
;
614 EReflecting
&= ~wp_mask
;
616 if (spfx
& SPFX_PROTECT
) {
618 EProtection
|= wp_mask
;
620 EProtection
&= ~wp_mask
;
623 if (wp_mask
== W_ART
&& !on
&& oart
->inv_prop
) {
624 /* might have to turn off invoked power too */
625 if (oart
->inv_prop
<= LAST_PROP
626 && (u
.uprops
[oart
->inv_prop
].extrinsic
& W_ARTI
))
627 (void) arti_invoke(otmp
);
631 /* touch_artifact()'s return value isn't sufficient to tell whether it
632 dished out damage, and tracking changes to u.uhp, u.mh, Lifesaved
633 when trying to avoid second wounding is too cumbersome */
634 STATIC_VAR boolean touch_blasted
; /* for retouch_object() */
637 * creature (usually hero) tries to touch (pick up or wield) an artifact obj.
638 * Returns 0 if the object refuses to be touched.
639 * This routine does not change any object chains.
640 * Ignores such things as gauntlets, assuming the artifact is not
641 * fooled by such trappings.
644 touch_artifact(obj
, mon
)
648 register const struct artifact
*oart
= get_artifact(obj
);
649 boolean badclass
, badalign
, self_willed
, yours
;
651 touch_blasted
= FALSE
;
655 yours
= (mon
== &youmonst
);
656 /* all quest artifacts are self-willed; it this ever changes, `badclass'
657 will have to be extended to explicitly include quest artifacts */
658 self_willed
= ((oart
->spfx
& SPFX_INTEL
) != 0);
660 badclass
= self_willed
661 && ((oart
->role
!= NON_PM
&& !Role_if(oart
->role
))
662 || (oart
->race
!= NON_PM
&& !Race_if(oart
->race
)));
664 (oart
->spfx
& SPFX_RESTR
) && oart
->alignment
!= A_NONE
665 && (oart
->alignment
!= u
.ualign
.type
|| u
.ualign
.record
< 0);
666 } else if (!is_covetous(mon
->data
) && !is_mplayer(mon
->data
)) {
667 badclass
= self_willed
&& oart
->role
!= NON_PM
668 && oart
!= &artilist
[ART_EXCALIBUR
];
669 badalign
= (oart
->spfx
& SPFX_RESTR
) && oart
->alignment
!= A_NONE
670 && (oart
->alignment
!= mon_aligntyp(mon
));
671 } else { /* an M3_WANTSxxx monster or a fake player */
672 /* special monsters trying to take the Amulet, invocation tools or
673 quest item can touch anything except `spec_applies' artifacts */
674 badclass
= badalign
= FALSE
;
676 /* weapons which attack specific categories of monsters are
677 bad for them even if their alignments happen to match */
679 badalign
= bane_applies(oart
, mon
);
681 if (((badclass
|| badalign
) && self_willed
)
682 || (badalign
&& (!yours
|| !rn2(4)))) {
688 You("are blasted by %s power!", s_suffix(the(xname(obj
))));
689 touch_blasted
= TRUE
;
690 dmg
= d((Antimagic
? 2 : 4), (self_willed
? 10 : 4));
691 /* add half (maybe quarter) of the usual silver damage bonus */
692 if (objects
[obj
->otyp
].oc_material
== SILVER
&& Hate_silver
)
693 tmp
= rnd(10), dmg
+= Maybe_Half_Phys(tmp
);
694 Sprintf(buf
, "touching %s", oart
->name
);
695 losehp(dmg
, buf
, KILLED_BY
); /* magic damage, not physical */
696 exercise(A_WIS
, FALSE
);
699 /* can pick it up unless you're totally non-synch'd with the artifact */
700 if (badclass
&& badalign
&& self_willed
) {
703 pline("%s your grasp!", Tobjnam(obj
, "evade"));
705 pline("%s beyond your control!", Tobjnam(obj
, "are"));
713 /* decide whether an artifact itself is vulnerable to a particular type
714 of erosion damage, independent of the properties of its bearer */
716 arti_immune(obj
, dtyp
)
720 register const struct artifact
*weap
= get_artifact(obj
);
725 return FALSE
; /* nothing is immune to phys dmg */
726 return (boolean
) (weap
->attk
.adtyp
== dtyp
727 || weap
->defn
.adtyp
== dtyp
728 || weap
->cary
.adtyp
== dtyp
);
732 bane_applies(oart
, mon
)
733 const struct artifact
*oart
;
736 struct artifact atmp
;
738 if (oart
&& (oart
->spfx
& SPFX_DBONUS
) != 0) {
740 atmp
.spfx
&= SPFX_DBONUS
; /* clear other spfx fields */
741 if (spec_applies(&atmp
, mon
))
747 /* decide whether an artifact's special attacks apply against mtmp */
749 spec_applies(weap
, mtmp
)
750 register const struct artifact
*weap
;
753 struct permonst
*ptr
;
756 if (!(weap
->spfx
& (SPFX_DBONUS
| SPFX_ATTK
)))
757 return (weap
->attk
.adtyp
== AD_PHYS
);
759 yours
= (mtmp
== &youmonst
);
762 if (weap
->spfx
& SPFX_DMONS
) {
763 return (ptr
== &mons
[(int) weap
->mtype
]);
764 } else if (weap
->spfx
& SPFX_DCLAS
) {
765 return (weap
->mtype
== (unsigned long) ptr
->mlet
);
766 } else if (weap
->spfx
& SPFX_DFLAG1
) {
767 return ((ptr
->mflags1
& weap
->mtype
) != 0L);
768 } else if (weap
->spfx
& SPFX_DFLAG2
) {
769 return ((ptr
->mflags2
& weap
->mtype
)
771 && ((!Upolyd
&& (urace
.selfmask
& weap
->mtype
))
772 || ((weap
->mtype
& M2_WERE
) && u
.ulycn
>= LOW_PM
))));
773 } else if (weap
->spfx
& SPFX_DALIGN
) {
774 return yours
? (u
.ualign
.type
!= weap
->alignment
)
775 : (ptr
->maligntyp
== A_NONE
776 || sgn(ptr
->maligntyp
) != weap
->alignment
);
777 } else if (weap
->spfx
& SPFX_ATTK
) {
778 struct obj
*defending_weapon
= (yours
? uwep
: MON_WEP(mtmp
));
780 if (defending_weapon
&& defending_weapon
->oartifact
781 && defends((int) weap
->attk
.adtyp
, defending_weapon
))
783 switch (weap
->attk
.adtyp
) {
785 return !(yours
? Fire_resistance
: resists_fire(mtmp
));
787 return !(yours
? Cold_resistance
: resists_cold(mtmp
));
789 return !(yours
? Shock_resistance
: resists_elec(mtmp
));
792 return !(yours
? Antimagic
: (rn2(100) < ptr
->mr
));
794 return !(yours
? Poison_resistance
: resists_poison(mtmp
));
796 return !(yours
? Drain_resistance
: resists_drli(mtmp
));
798 return !(yours
? Stone_resistance
: resists_ston(mtmp
));
800 impossible("Weird weapon special attack.");
806 /* return the M2 flags of monster that an artifact's special attacks apply
812 const struct artifact
*artifact
= get_artifact(otmp
);
815 return artifact
->mtype
;
819 /* special attack bonus */
825 const struct artifact
*weap
= get_artifact(otmp
);
827 /* no need for an extra check for `NO_ATTK' because this will
828 always return 0 for any artifact which has that attribute */
830 if (weap
&& weap
->attk
.damn
&& spec_applies(weap
, mon
))
831 return rnd((int) weap
->attk
.damn
);
835 /* special damage bonus */
837 spec_dbon(otmp
, mon
, tmp
)
842 register const struct artifact
*weap
= get_artifact(otmp
);
844 if (!weap
|| (weap
->attk
.adtyp
== AD_PHYS
/* check for `NO_ATTK' */
845 && weap
->attk
.damn
== 0 && weap
->attk
.damd
== 0))
846 spec_dbon_applies
= FALSE
;
847 else if (otmp
->oartifact
== ART_GRIMTOOTH
)
848 /* Grimtooth has SPFX settings to warn against elves but we want its
849 damage bonus to apply to all targets, so bypass spec_applies() */
850 spec_dbon_applies
= TRUE
;
852 spec_dbon_applies
= spec_applies(weap
, mon
);
854 if (spec_dbon_applies
)
855 return weap
->attk
.damd
? rnd((int) weap
->attk
.damd
) : max(tmp
, 1);
859 /* add identified artifact to discoveries list */
866 /* look for this artifact in the discoveries list;
867 if we hit an empty slot then it's not present, so add it */
868 for (i
= 0; i
< NROFARTIFACTS
; i
++)
869 if (artidisco
[i
] == 0 || artidisco
[i
] == m
) {
873 /* there is one slot per artifact, so we should never reach the
874 end without either finding the artifact or an empty slot... */
875 impossible("couldn't discover artifact (%d)", (int) m
);
878 /* used to decide whether an artifact has been fully identified */
880 undiscovered_artifact(m
)
885 /* look for this artifact in the discoveries list;
886 if we hit an empty slot then it's undiscovered */
887 for (i
= 0; i
< NROFARTIFACTS
; i
++)
888 if (artidisco
[i
] == m
)
890 else if (artidisco
[i
] == 0)
895 /* display a list of discovered artifacts; return their count */
897 disp_artifact_discoveries(tmpwin
)
898 winid tmpwin
; /* supplied by dodiscover() */
903 for (i
= 0; i
< NROFARTIFACTS
; i
++) {
904 if (artidisco
[i
] == 0)
905 break; /* empty slot implies end of list */
906 if (tmpwin
== WIN_ERR
)
907 continue; /* for WIN_ERR, we just count */
910 putstr(tmpwin
, iflags
.menu_headings
, "Artifacts");
912 otyp
= artilist
[m
].otyp
;
913 Sprintf(buf
, " %s [%s %s]", artiname(m
),
914 align_str(artilist
[m
].alignment
), simple_typename(otyp
));
915 putstr(tmpwin
, 0, buf
);
921 * Magicbane's intrinsic magic is incompatible with normal
922 * enchantment magic. Thus, its effects have a negative
923 * dependence on spe. Against low mr victims, it typically
924 * does "double athame" damage, 2d4. Occasionally, it will
925 * cast unbalancing magic which effectively averages out to
926 * 4d4 damage (3d4 against high mr victims), for spe = 0.
928 * Prior to 3.4.1, the cancel (aka purge) effect always
929 * included the scare effect too; now it's one or the other.
930 * Likewise, the stun effect won't be combined with either
931 * of those two; it will be chosen separately or possibly
932 * used as a fallback when scare or cancel fails.
934 * [Historical note: a change to artifact_hit() for 3.4.0
935 * unintentionally made all of Magicbane's special effects
936 * be blocked if the defender successfully saved against a
937 * stun attack. As of 3.4.1, those effects can occur but
938 * will be slightly less likely than they were in 3.3.x.]
940 #define MB_MAX_DIEROLL 8 /* rolls above this aren't magical */
941 static const char *const mb_verb
[2][4] = {
942 { "probe", "stun", "scare", "cancel" },
943 { "prod", "amaze", "tickle", "purge" },
945 #define MB_INDEX_PROBE 0
946 #define MB_INDEX_STUN 1
947 #define MB_INDEX_SCARE 2
948 #define MB_INDEX_CANCEL 3
950 /* called when someone is being hit by Magicbane */
952 Mb_hit(magr
, mdef
, mb
, dmgptr
, dieroll
, vis
, hittee
)
953 struct monst
*magr
, *mdef
; /* attacker and defender */
954 struct obj
*mb
; /* Magicbane */
955 int *dmgptr
; /* extra damage target will suffer */
956 int dieroll
; /* d20 that has already scored a hit */
957 boolean vis
; /* whether the action can be seen */
958 char *hittee
; /* target's name: "you" or mon_nam(mdef) */
960 struct permonst
*old_uasmon
;
961 const char *verb
, *fakename
;
962 boolean youattack
= (magr
== &youmonst
), youdefend
= (mdef
== &youmonst
),
963 resisted
= FALSE
, do_stun
, do_confuse
, result
;
964 int attack_indx
, scare_dieroll
= MB_MAX_DIEROLL
/ 2;
966 result
= FALSE
; /* no message given yet */
967 /* the most severe effects are less likely at higher enchantment */
969 scare_dieroll
/= (1 << (mb
->spe
/ 3));
970 /* if target successfully resisted the artifact damage bonus,
971 reduce overall likelihood of the assorted special effects */
972 if (!spec_dbon_applies
)
975 /* might stun even when attempting a more severe effect, but
976 in that case it will only happen if the other effect fails;
977 extra damage will apply regardless; 3.4.1: sometimes might
978 just probe even when it hasn't been enchanted */
979 do_stun
= (max(mb
->spe
, 0) < rn2(spec_dbon_applies
? 11 : 7));
981 /* the special effects also boost physical damage; increments are
982 generally cumulative, but since the stun effect is based on a
983 different criterium its damage might not be included; the base
984 damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending
985 on target's resistance check against AD_STUN (handled by caller)
986 [note that a successful save against AD_STUN doesn't actually
987 prevent the target from ending up stunned] */
988 attack_indx
= MB_INDEX_PROBE
;
989 *dmgptr
+= rnd(4); /* (2..3)d4 */
991 attack_indx
= MB_INDEX_STUN
;
992 *dmgptr
+= rnd(4); /* (3..4)d4 */
994 if (dieroll
<= scare_dieroll
) {
995 attack_indx
= MB_INDEX_SCARE
;
996 *dmgptr
+= rnd(4); /* (3..5)d4 */
998 if (dieroll
<= (scare_dieroll
/ 2)) {
999 attack_indx
= MB_INDEX_CANCEL
;
1000 *dmgptr
+= rnd(4); /* (4..6)d4 */
1003 /* give the hit message prior to inflicting the effects */
1004 verb
= mb_verb
[!!Hallucination
][attack_indx
];
1005 if (youattack
|| youdefend
|| vis
) {
1007 pline_The("magic-absorbing blade %s %s!",
1008 vtense((const char *) 0, verb
), hittee
);
1009 /* assume probing has some sort of noticeable feedback
1010 even if it is being done by one monster to another */
1011 if (attack_indx
== MB_INDEX_PROBE
&& !canspotmon(mdef
))
1012 map_invisible(mdef
->mx
, mdef
->my
);
1015 /* now perform special effects */
1016 switch (attack_indx
) {
1017 case MB_INDEX_CANCEL
:
1018 old_uasmon
= youmonst
.data
;
1019 /* No mdef->mcan check: even a cancelled monster can be polymorphed
1020 * into a golem, and the "cancel" effect acts as if some magical
1021 * energy remains in spellcasting defenders to be absorbed later.
1023 if (!cancel_monst(mdef
, mb
, youattack
, FALSE
, FALSE
)) {
1028 if (youmonst
.data
!= old_uasmon
)
1029 *dmgptr
= 0; /* rehumanized, so no more damage */
1031 You("lose magical energy!");
1038 if (mdef
->data
== &mons
[PM_CLAY_GOLEM
])
1039 mdef
->mhp
= 1; /* cancelled clay golems will die */
1040 if (youattack
&& attacktype(mdef
->data
, AT_MAGC
)) {
1041 You("absorb magical energy!");
1050 case MB_INDEX_SCARE
:
1056 multi_reason
= "being scared stiff";
1058 if (magr
&& magr
== u
.ustuck
&& sticks(youmonst
.data
)) {
1059 u
.ustuck
= (struct monst
*) 0;
1060 You("release %s!", mon_nam(magr
));
1064 if (rn2(2) && resist(mdef
, WEAPON_CLASS
, 0, NOTELL
))
1067 monflee(mdef
, 3, FALSE
, (mdef
->mhp
> *dmgptr
));
1074 do_stun
= TRUE
; /* (this is redundant...) */
1077 case MB_INDEX_PROBE
:
1078 if (youattack
&& (mb
->spe
== 0 || !rn2(3 * abs(mb
->spe
)))) {
1079 pline_The("%s is insightful.", verb
);
1080 /* pre-damage status */
1081 probe_monster(mdef
);
1085 /* stun if that was selected and a worse effect didn't occur */
1088 make_stunned(((HStun
& TIMEOUT
) + 3L), FALSE
);
1091 /* avoid extra stun message below if we used mb_verb["stun"] above */
1092 if (attack_indx
== MB_INDEX_STUN
)
1095 /* lastly, all this magic can be confusing... */
1096 do_confuse
= !rn2(12);
1099 make_confused((HConfusion
& TIMEOUT
) + 4L, FALSE
);
1104 /* now give message(s) describing side-effects;
1105 don't let vtense() be fooled by assigned name ending in 's' */
1106 fakename
= youdefend
? "you" : "mon";
1107 if (youattack
|| youdefend
|| vis
) {
1108 (void) upstart(hittee
); /* capitalize */
1110 pline("%s %s!", hittee
, vtense(fakename
, "resist"));
1111 shieldeff(youdefend
? u
.ux
: mdef
->mx
,
1112 youdefend
? u
.uy
: mdef
->my
);
1114 if ((do_stun
|| do_confuse
) && flags
.verbose
) {
1119 Strcat(buf
, "stunned");
1120 if (do_stun
&& do_confuse
)
1121 Strcat(buf
, " and ");
1123 Strcat(buf
, "confused");
1124 pline("%s %s %s%c", hittee
, vtense(fakename
, "are"), buf
,
1125 (do_stun
&& do_confuse
) ? '!' : '.');
1132 /* Function used when someone attacks someone else with an artifact
1133 * weapon. Only adds the special (artifact) damage, and returns a 1 if it
1134 * did something special (in which case the caller won't print the normal
1135 * hit message). This should be called once upon every artifact attack;
1136 * dmgval() no longer takes artifact bonuses into account. Possible
1137 * extension: change the killer so that when an orc kills you with
1138 * Stormbringer it's "killed by Stormbringer" instead of "killed by an orc".
1141 artifact_hit(magr
, mdef
, otmp
, dmgptr
, dieroll
)
1142 struct monst
*magr
, *mdef
;
1145 int dieroll
; /* needed for Magicbane and vorpal blades */
1147 boolean youattack
= (magr
== &youmonst
);
1148 boolean youdefend
= (mdef
== &youmonst
);
1149 boolean vis
= (!youattack
&& magr
&& cansee(magr
->mx
, magr
->my
))
1150 || (!youdefend
&& cansee(mdef
->mx
, mdef
->my
))
1151 || (youattack
&& u
.uswallow
&& mdef
== u
.ustuck
&& !Blind
);
1152 boolean realizes_damage
;
1153 const char *wepdesc
;
1154 static const char you
[] = "you";
1157 Strcpy(hittee
, youdefend
? you
: mon_nam(mdef
));
1159 /* The following takes care of most of the damage, but not all--
1160 * the exception being for level draining, which is specially
1161 * handled. Messages are done in this function, however.
1163 *dmgptr
+= spec_dbon(otmp
, mdef
, *dmgptr
);
1165 if (youattack
&& youdefend
) {
1166 impossible("attacking yourself with weapon?");
1170 realizes_damage
= (youdefend
|| vis
1171 /* feel the effect even if not seen */
1172 || (youattack
&& mdef
== u
.ustuck
));
1174 /* the four basic attacks: fire, cold, shock and missiles */
1175 if (attacks(AD_FIRE
, otmp
)) {
1176 if (realizes_damage
)
1177 pline_The("fiery blade %s %s%c",
1180 : (mdef
->data
== &mons
[PM_WATER_ELEMENTAL
])
1181 ? "vaporizes part of"
1183 hittee
, !spec_dbon_applies
? '.' : '!');
1185 (void) destroy_mitem(mdef
, POTION_CLASS
, AD_FIRE
);
1187 (void) destroy_mitem(mdef
, SCROLL_CLASS
, AD_FIRE
);
1189 (void) destroy_mitem(mdef
, SPBOOK_CLASS
, AD_FIRE
);
1190 if (youdefend
&& Slimed
)
1192 return realizes_damage
;
1194 if (attacks(AD_COLD
, otmp
)) {
1195 if (realizes_damage
)
1196 pline_The("ice-cold blade %s %s%c",
1197 !spec_dbon_applies
? "hits" : "freezes", hittee
,
1198 !spec_dbon_applies
? '.' : '!');
1200 (void) destroy_mitem(mdef
, POTION_CLASS
, AD_COLD
);
1201 return realizes_damage
;
1203 if (attacks(AD_ELEC
, otmp
)) {
1204 if (realizes_damage
)
1205 pline_The("massive hammer hits%s %s%c",
1206 !spec_dbon_applies
? "" : "! Lightning strikes",
1207 hittee
, !spec_dbon_applies
? '.' : '!');
1209 (void) destroy_mitem(mdef
, RING_CLASS
, AD_ELEC
);
1211 (void) destroy_mitem(mdef
, WAND_CLASS
, AD_ELEC
);
1212 return realizes_damage
;
1214 if (attacks(AD_MAGM
, otmp
)) {
1215 if (realizes_damage
)
1216 pline_The("imaginary widget hits%s %s%c",
1219 : "! A hail of magic missiles strikes",
1220 hittee
, !spec_dbon_applies
? '.' : '!');
1221 return realizes_damage
;
1224 if (attacks(AD_STUN
, otmp
) && dieroll
<= MB_MAX_DIEROLL
) {
1225 /* Magicbane's special attacks (possibly modifies hittee[]) */
1226 return Mb_hit(magr
, mdef
, otmp
, dmgptr
, dieroll
, vis
, hittee
);
1229 if (!spec_dbon_applies
) {
1230 /* since damage bonus didn't apply, nothing more to do;
1231 no further attacks have side-effects on inventory */
1235 /* We really want "on a natural 20" but Nethack does it in */
1236 /* reverse from AD&D. */
1237 if (spec_ability(otmp
, SPFX_BEHEAD
)) {
1238 if (otmp
->oartifact
== ART_TSURUGI_OF_MURAMASA
&& dieroll
== 1) {
1239 wepdesc
= "The razor-sharp blade";
1240 /* not really beheading, but so close, why add another SPFX */
1241 if (youattack
&& u
.uswallow
&& mdef
== u
.ustuck
) {
1242 You("slice %s wide open!", mon_nam(mdef
));
1243 *dmgptr
= 2 * mdef
->mhp
+ FATAL_DAMAGE_MODIFIER
;
1247 /* allow normal cutworm() call to add extra damage */
1251 if (bigmonst(mdef
->data
)) {
1253 You("slice deeply into %s!", mon_nam(mdef
));
1255 pline("%s cuts deeply into %s!", Monnam(magr
),
1260 *dmgptr
= 2 * mdef
->mhp
+ FATAL_DAMAGE_MODIFIER
;
1261 pline("%s cuts %s in half!", wepdesc
, mon_nam(mdef
));
1262 otmp
->dknown
= TRUE
;
1265 if (bigmonst(youmonst
.data
)) {
1266 pline("%s cuts deeply into you!",
1267 magr
? Monnam(magr
) : wepdesc
);
1272 /* Players with negative AC's take less damage instead
1273 * of just not getting hit. We must add a large enough
1274 * value to the damage so that this reduction in
1275 * damage does not prevent death.
1277 *dmgptr
= 2 * (Upolyd
? u
.mh
: u
.uhp
) + FATAL_DAMAGE_MODIFIER
;
1278 pline("%s cuts you in half!", wepdesc
);
1279 otmp
->dknown
= TRUE
;
1282 } else if (otmp
->oartifact
== ART_VORPAL_BLADE
1283 && (dieroll
== 1 || mdef
->data
== &mons
[PM_JABBERWOCK
])) {
1284 static const char *const behead_msg
[2] = { "%s beheads %s!",
1285 "%s decapitates %s!" };
1287 if (youattack
&& u
.uswallow
&& mdef
== u
.ustuck
)
1289 wepdesc
= artilist
[ART_VORPAL_BLADE
].name
;
1291 if (!has_head(mdef
->data
) || notonhead
|| u
.uswallow
) {
1293 pline("Somehow, you miss %s wildly.", mon_nam(mdef
));
1295 pline("Somehow, %s misses wildly.", mon_nam(magr
));
1297 return (boolean
) (youattack
|| vis
);
1299 if (noncorporeal(mdef
->data
) || amorphous(mdef
->data
)) {
1300 pline("%s slices through %s %s.", wepdesc
,
1301 s_suffix(mon_nam(mdef
)), mbodypart(mdef
, NECK
));
1304 *dmgptr
= 2 * mdef
->mhp
+ FATAL_DAMAGE_MODIFIER
;
1305 pline(behead_msg
[rn2(SIZE(behead_msg
))], wepdesc
,
1307 if (Hallucination
&& !flags
.female
)
1308 pline("Good job Henry, but that wasn't Anne.");
1309 otmp
->dknown
= TRUE
;
1312 if (!has_head(youmonst
.data
)) {
1313 pline("Somehow, %s misses you wildly.",
1314 magr
? mon_nam(magr
) : wepdesc
);
1318 if (noncorporeal(youmonst
.data
) || amorphous(youmonst
.data
)) {
1319 pline("%s slices through your %s.", wepdesc
,
1323 *dmgptr
= 2 * (Upolyd
? u
.mh
: u
.uhp
) + FATAL_DAMAGE_MODIFIER
;
1324 pline(behead_msg
[rn2(SIZE(behead_msg
))], wepdesc
, "you");
1325 otmp
->dknown
= TRUE
;
1326 /* Should amulets fall off? */
1331 if (spec_ability(otmp
, SPFX_DRLI
)) {
1332 /* some non-living creatures (golems, vortices) are
1333 vulnerable to life drain effects */
1334 const char *life
= nonliving(mdef
->data
) ? "animating force" : "life";
1338 if (otmp
->oartifact
== ART_STORMBRINGER
)
1339 pline_The("%s blade draws the %s from %s!",
1340 hcolor(NH_BLACK
), life
, mon_nam(mdef
));
1342 pline("%s draws the %s from %s!",
1343 The(distant_name(otmp
, xname
)), life
,
1346 if (mdef
->m_lev
== 0) {
1347 *dmgptr
= 2 * mdef
->mhp
+ FATAL_DAMAGE_MODIFIER
;
1349 int drain
= monhp_per_lvl(mdef
);
1352 mdef
->mhpmax
-= drain
;
1356 healup(drain
, 0, FALSE
, FALSE
);
1359 } else { /* youdefend */
1360 int oldhpmax
= u
.uhpmax
;
1363 You_feel("an %s drain your %s!",
1364 (otmp
->oartifact
== ART_STORMBRINGER
)
1368 else if (otmp
->oartifact
== ART_STORMBRINGER
)
1369 pline_The("%s blade drains your %s!", hcolor(NH_BLACK
), life
);
1371 pline("%s drains your %s!", The(distant_name(otmp
, xname
)),
1373 losexp("life drainage");
1374 if (magr
&& magr
->mhp
< magr
->mhpmax
) {
1375 magr
->mhp
+= (oldhpmax
- u
.uhpmax
) / 2;
1376 if (magr
->mhp
> magr
->mhpmax
)
1377 magr
->mhp
= magr
->mhpmax
;
1385 static NEARDATA
const char recharge_type
[] = { ALLOW_COUNT
, ALL_CLASSES
, 0 };
1386 static NEARDATA
const char invoke_types
[] = { ALL_CLASSES
, 0 };
1387 /* #invoke: an "ugly check" filters out most objects */
1389 /* the #invoke command */
1395 obj
= getobj(invoke_types
, "invoke");
1398 if (!retouch_object(&obj
, FALSE
))
1400 return arti_invoke(obj
);
1407 register const struct artifact
*oart
= get_artifact(obj
);
1409 impossible("arti_invoke without obj");
1412 if (!oart
|| !oart
->inv_prop
) {
1413 if (obj
->otyp
== CRYSTAL_BALL
)
1414 use_crystal_ball(&obj
);
1416 pline1(nothing_happens
);
1420 if (oart
->inv_prop
> LAST_PROP
) {
1421 /* It's a special power, not "just" a property */
1422 if (obj
->age
> monstermoves
) {
1423 /* the artifact is tired :-) */
1424 You_feel("that %s %s ignoring you.", the(xname(obj
)),
1425 otense(obj
, "are"));
1426 /* and just got more so; patience is essential... */
1427 obj
->age
+= (long) d(3, 10);
1430 obj
->age
= monstermoves
+ rnz(100);
1432 switch (oart
->inv_prop
) {
1437 zeroobj
; /* neither cursed nor blessed, zero oextra too */
1438 pseudo
.otyp
= SCR_TAMING
;
1439 (void) seffects(&pseudo
);
1443 int healamt
= (u
.uhpmax
+ 1 - u
.uhp
) / 2;
1444 long creamed
= (long) u
.ucreamed
;
1447 healamt
= (u
.mhmax
+ 1 - u
.mh
) / 2;
1448 if (healamt
|| Sick
|| Slimed
|| Blinded
> creamed
)
1449 You_feel("better.");
1451 goto nothing_special
;
1459 make_sick(0L, (char *) 0, FALSE
, SICK_ALL
);
1461 make_slimed(0L, (char *) 0);
1462 if (Blinded
> creamed
)
1463 make_blinded(creamed
, FALSE
);
1467 case ENERGY_BOOST
: {
1468 int epboost
= (u
.uenmax
+ 1 - u
.uen
) / 2;
1470 epboost
= 120; /* arbitrary */
1471 else if (epboost
< 12)
1472 epboost
= u
.uenmax
- u
.uen
;
1474 You_feel("re-energized.");
1478 goto nothing_special
;
1482 if (!untrap(TRUE
)) {
1483 obj
->age
= 0; /* don't charge for changing their mind */
1489 struct obj
*otmp
= getobj(recharge_type
, "charge");
1497 obj
->blessed
&& (Role_switch
== oart
->role
|| !oart
->role
);
1498 recharge(otmp
, b_effect
? 1 : obj
->cursed
? -1 : 0);
1505 case CREATE_PORTAL
: {
1506 int i
, num_ok_dungeons
, last_ok_dungeon
= 0;
1508 extern int n_dgns
; /* from dungeon.c */
1509 winid tmpwin
= create_nhwindow(NHW_MENU
);
1512 any
= zeroany
; /* set all bits to zero */
1514 /* use index+1 (cant use 0) as identifier */
1515 for (i
= num_ok_dungeons
= 0; i
< n_dgns
; i
++) {
1516 if (!dungeons
[i
].dunlev_ureached
)
1519 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1520 dungeons
[i
].dname
, MENU_UNSELECTED
);
1522 last_ok_dungeon
= i
;
1524 end_menu(tmpwin
, "Open a portal to which dungeon?");
1525 if (num_ok_dungeons
> 1) {
1526 /* more than one entry; display menu for choices */
1527 menu_item
*selected
;
1530 n
= select_menu(tmpwin
, PICK_ONE
, &selected
);
1532 destroy_nhwindow(tmpwin
);
1533 goto nothing_special
;
1535 i
= selected
[0].item
.a_int
- 1;
1536 free((genericptr_t
) selected
);
1538 i
= last_ok_dungeon
; /* also first & only OK dungeon */
1539 destroy_nhwindow(tmpwin
);
1542 * i is now index into dungeon structure for the new dungeon.
1543 * Find the closest level in the given dungeon, open
1544 * a use-once portal to that dungeon and go there.
1545 * The closest level is either the entry or dunlev_ureached.
1548 if (dungeons
[i
].depth_start
>= depth(&u
.uz
))
1549 newlev
.dlevel
= dungeons
[i
].entry_lev
;
1551 newlev
.dlevel
= dungeons
[i
].dunlev_ureached
;
1553 if (u
.uhave
.amulet
|| In_endgame(&u
.uz
) || In_endgame(&newlev
)
1554 || newlev
.dnum
== u
.uz
.dnum
|| !next_to_u()) {
1555 You_feel("very disoriented for a moment.");
1558 You("are surrounded by a shimmering sphere!");
1560 You_feel("weightless for a moment.");
1561 goto_level(&newlev
, FALSE
, FALSE
, FALSE
);
1566 enlightenment(MAGICENLIGHTENMENT
, ENL_GAMEINPROGRESS
);
1569 struct obj
*otmp
= mksobj(ARROW
, TRUE
, FALSE
);
1572 goto nothing_special
;
1573 otmp
->blessed
= obj
->blessed
;
1574 otmp
->cursed
= obj
->cursed
;
1575 otmp
->bknown
= obj
->bknown
;
1579 otmp
->quan
+= rnd(10);
1580 } else if (obj
->cursed
) {
1584 otmp
->quan
+= rnd(5);
1585 otmp
->owt
= weight(otmp
);
1587 hold_another_object(otmp
, "Suddenly %s out.",
1588 aobjnam(otmp
, "fall"), (const char *) 0);
1593 long eprop
= (u
.uprops
[oart
->inv_prop
].extrinsic
^= W_ARTI
),
1594 iprop
= u
.uprops
[oart
->inv_prop
].intrinsic
;
1595 boolean on
= (eprop
& W_ARTI
) != 0; /* true if prop just set */
1597 if (on
&& obj
->age
> monstermoves
) {
1598 /* the artifact is tired :-) */
1599 u
.uprops
[oart
->inv_prop
].extrinsic
^= W_ARTI
;
1600 You_feel("that %s %s ignoring you.", the(xname(obj
)),
1601 otense(obj
, "are"));
1602 /* can't just keep repeatedly trying */
1603 obj
->age
+= (long) d(3, 10);
1606 /* when turning off property, determine downtime */
1607 /* arbitrary for now until we can tune this -dlc */
1608 obj
->age
= monstermoves
+ rnz(100);
1611 if ((eprop
& ~W_ARTI
) || iprop
) {
1613 /* you had the property from some other source too */
1615 You_feel("a surge of power, but nothing seems to happen.");
1618 switch (oart
->inv_prop
) {
1621 You_feel("like a rabble-rouser.");
1623 You_feel("the tension decrease around you.");
1630 (void) float_down(I_SPECIAL
| TIMEOUT
, W_ARTI
);
1633 if (BInvis
|| Blind
)
1634 goto nothing_special
;
1637 Your("body takes on a %s transparency...",
1638 Hallucination
? "normal" : "strange");
1640 Your("body seems to unfade...");
1648 /* will freeing this object from inventory cause levitation to end? */
1650 finesse_ahriman(obj
)
1653 const struct artifact
*oart
;
1654 struct prop save_Lev
;
1657 /* if we aren't levitating or this isn't an artifact which confers
1658 levitation via #invoke then freeinv() won't toggle levitation */
1659 if (!Levitation
|| (oart
= get_artifact(obj
)) == 0
1660 || oart
->inv_prop
!= LEVITATION
|| !(ELevitation
& W_ARTI
))
1663 /* arti_invoke(off) -> float_down() clears I_SPECIAL|TIMEOUT & W_ARTI;
1664 probe ahead to see whether that actually results in floating down;
1665 (this assumes that there aren't two simultaneously invoked artifacts
1666 both conferring levitation--safe, since if there were two of them,
1667 invoking the 2nd would negate the 1st rather than stack with it) */
1668 save_Lev
= u
.uprops
[LEVITATION
];
1669 HLevitation
&= ~(I_SPECIAL
| TIMEOUT
);
1670 ELevitation
&= ~W_ARTI
;
1671 result
= (boolean
) !Levitation
;
1672 u
.uprops
[LEVITATION
] = save_Lev
;
1676 /* WAC return TRUE if artifact is always lit */
1681 return (boolean
) (get_artifact(obj
) && obj
->oartifact
== ART_SUNSWORD
);
1684 /* KMH -- Talking artifacts are finally implemented */
1689 register const struct artifact
*oart
= get_artifact(obj
);
1693 /* Is this a speaking artifact? */
1694 if (!oart
|| !(oart
->spfx
& SPFX_SPEAK
))
1697 line
= getrumor(bcsign(obj
), buf
, TRUE
);
1699 line
= "NetHack rumors file closed for renovation.";
1700 pline("%s:", Tobjnam(obj
, "whisper"));
1706 artifact_has_invprop(otmp
, inv_prop
)
1710 const struct artifact
*arti
= get_artifact(otmp
);
1712 return (boolean
) (arti
&& (arti
->inv_prop
== inv_prop
));
1715 /* Return the price sold to the hero of a given artifact or unique item */
1720 if (!otmp
->oartifact
)
1721 return (long) objects
[otmp
->otyp
].oc_cost
;
1722 else if (artilist
[(int) otmp
->oartifact
].cost
)
1723 return artilist
[(int) otmp
->oartifact
].cost
;
1725 return (100L * (long) objects
[otmp
->otyp
].oc_cost
);
1732 struct abil2adtyp_tag
{
1736 { &EFire_resistance
, AD_FIRE
},
1737 { &ECold_resistance
, AD_COLD
},
1738 { &EShock_resistance
, AD_ELEC
},
1739 { &EAntimagic
, AD_MAGM
},
1740 { &EDisint_resistance
, AD_DISN
},
1741 { &EPoison_resistance
, AD_DRST
},
1742 { &EDrain_resistance
, AD_DRLI
},
1746 for (k
= 0; k
< SIZE(abil2adtyp
); k
++) {
1747 if (abil2adtyp
[k
].abil
== abil
)
1748 return abil2adtyp
[k
].adtyp
;
1753 STATIC_OVL
unsigned long
1757 static const struct abil2spfx_tag
{
1761 { &ESearching
, SPFX_SEARCH
},
1762 { &EHalluc_resistance
, SPFX_HALRES
},
1763 { &ETelepat
, SPFX_ESP
},
1764 { &EStealth
, SPFX_STLTH
},
1765 { &ERegeneration
, SPFX_REGEN
},
1766 { &ETeleport_control
, SPFX_TCTRL
},
1767 { &EWarn_of_mon
, SPFX_WARN
},
1768 { &EWarning
, SPFX_WARN
},
1769 { &EEnergy_regeneration
, SPFX_EREGEN
},
1770 { &EHalf_spell_damage
, SPFX_HSPDAM
},
1771 { &EHalf_physical_damage
, SPFX_HPHDAM
},
1772 { &EReflecting
, SPFX_REFLECT
},
1776 for (k
= 0; k
< SIZE(abil2spfx
); k
++) {
1777 if (abil2spfx
[k
].abil
== abil
)
1778 return abil2spfx
[k
].spfx
;
1784 * Return the first item that is conveying a particular intrinsic.
1794 long wornmask
= (W_ARM
| W_ARMC
| W_ARMH
| W_ARMS
1795 | W_ARMG
| W_ARMF
| W_ARMU
1796 | W_AMUL
| W_RINGL
| W_RINGR
| W_TOOL
1800 wornmask
|= W_SWAPWEP
;
1801 dtyp
= abil_to_adtyp(abil
);
1802 spfx
= abil_to_spfx(abil
);
1803 wornbits
= (wornmask
& *abil
);
1805 for (obj
= invent
; obj
; obj
= obj
->nobj
) {
1807 && (abil
!= &EWarn_of_mon
|| context
.warntype
.obj
)) {
1808 const struct artifact
*art
= get_artifact(obj
);
1812 if (art
->cary
.adtyp
== dtyp
/* carried */
1813 || (art
->defn
.adtyp
== dtyp
/* defends while worn */
1814 && (obj
->owornmask
& ~(W_ART
| W_ARTI
))))
1818 /* property conferred when carried */
1819 if ((art
->cspfx
& spfx
) == spfx
)
1821 /* property conferred when wielded or worn */
1822 if ((art
->spfx
& spfx
) == spfx
&& obj
->owornmask
)
1827 if (wornbits
&& wornbits
== (wornmask
& obj
->owornmask
))
1831 return (struct obj
*) 0;
1835 glow_color(arti_indx
)
1838 int colornum
= artilist
[arti_indx
].acolor
;
1839 const char *colorstr
= clr2colorname(colornum
);
1841 return hcolor(colorstr
);
1844 /* use for warning "glow" for Sting, Orcrist, and Grimtooth */
1846 Sting_effects(orc_count
)
1847 int orc_count
; /* new count (warn_obj_cnt is old count); -1 is a flag value */
1850 && (uwep
->oartifact
== ART_STING
1851 || uwep
->oartifact
== ART_ORCRIST
1852 || uwep
->oartifact
== ART_GRIMTOOTH
)) {
1853 if (orc_count
== -1 && warn_obj_cnt
> 0) {
1854 /* -1 means that blindness has just been toggled; give a
1855 'continue' message that eventual 'stop' message will match */
1856 pline("%s is %s.", bare_artifactname(uwep
),
1857 !Blind
? "glowing" : "quivering");
1858 } else if (orc_count
> 0 && warn_obj_cnt
== 0) {
1859 /* 'start' message */
1861 pline("%s %s %s!", bare_artifactname(uwep
),
1862 otense(uwep
, "glow"), glow_color(uwep
->oartifact
));
1864 pline("%s quivers slightly.", bare_artifactname(uwep
));
1865 } else if (orc_count
== 0 && warn_obj_cnt
> 0) {
1866 /* 'stop' message */
1867 pline("%s stops %s.", bare_artifactname(uwep
),
1868 !Blind
? "glowing" : "quivering");
1873 /* called when hero is wielding/applying/invoking a carried item, or
1874 after undergoing a transformation (alignment change, lycanthropy,
1875 polymorph) which might affect item access */
1877 retouch_object(objp
, loseit
)
1878 struct obj
**objp
; /* might be destroyed or unintentionally dropped */
1879 boolean loseit
; /* whether to drop it if hero can longer touch it */
1881 struct obj
*obj
= *objp
;
1883 if (touch_artifact(obj
, &youmonst
)) {
1887 (objects
[obj
->otyp
].oc_material
== SILVER
&& Hate_silver
),
1888 bane
= bane_applies(get_artifact(obj
), &youmonst
);
1890 /* nothing else to do if hero can successfully handle this object */
1894 /* hero can't handle this object, but didn't get touch_artifact()'s
1895 "<obj> evades your grasp|control" message; give an alternate one */
1896 You_cant("handle %s%s!", yname(obj
),
1897 obj
->owornmask
? " anymore" : "");
1898 /* also inflict damage unless touch_artifact() already did so */
1899 if (!touch_blasted
) {
1900 /* damage is somewhat arbitrary; half the usual 1d20 physical
1901 for silver, 1d10 magical for <foo>bane, potentially both */
1903 tmp
= rnd(10), dmg
+= Maybe_Half_Phys(tmp
);
1906 Sprintf(buf
, "handling %s", killer_xname(obj
));
1907 losehp(dmg
, buf
, KILLED_BY
);
1908 exercise(A_CON
, FALSE
);
1912 /* removing a worn item might result in loss of levitation,
1913 dropping the hero onto a polymorph trap or into water or
1914 lava and potentially dropping or destroying the item */
1915 if (obj
->owornmask
) {
1918 remove_worn_item(obj
, FALSE
);
1919 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
1926 /* if we still have it and caller wants us to drop it, do so now */
1927 if (loseit
&& obj
) {
1932 /* dropx gives a message iff item lands on an altar */
1933 if (!IS_ALTAR(levl
[u
.ux
][u
.uy
].typ
))
1934 pline("%s to the %s.", Tobjnam(obj
, "fall"),
1935 surface(u
.ux
, u
.uy
));
1938 *objp
= obj
= 0; /* no longer in inventory */
1943 /* an item which is worn/wielded or an artifact which conveys
1944 something via being carried or which has an #invoke effect
1945 currently in operation undergoes a touch test; if it fails,
1946 it will be unworn/unwielded and revoked but not dropped */
1948 untouchable(obj
, drop_untouchable
)
1950 boolean drop_untouchable
;
1952 struct artifact
*art
;
1953 boolean beingworn
, carryeffect
, invoked
;
1954 long wearmask
= ~(W_QUIVER
| (u
.twoweap
? 0L : W_SWAPWEP
) | W_BALL
);
1956 beingworn
= ((obj
->owornmask
& wearmask
) != 0L
1957 /* some items in use don't have any wornmask setting */
1958 || (obj
->oclass
== TOOL_CLASS
1959 && (obj
->lamplit
|| (obj
->otyp
== LEASH
&& obj
->leashmon
)
1960 || (Is_container(obj
) && Has_contents(obj
)))));
1962 if ((art
= get_artifact(obj
)) != 0) {
1963 carryeffect
= (art
->cary
.adtyp
|| art
->cspfx
);
1964 invoked
= (art
->inv_prop
> 0 && art
->inv_prop
<= LAST_PROP
1965 && (u
.uprops
[art
->inv_prop
].extrinsic
& W_ARTI
) != 0L);
1967 carryeffect
= invoked
= FALSE
;
1970 if (beingworn
|| carryeffect
|| invoked
) {
1971 if (!retouch_object(&obj
, drop_untouchable
)) {
1972 /* "<artifact> is beyond your control" or "you can't handle
1973 <object>" has been given and it is now unworn/unwielded
1974 and possibly dropped (depending upon caller); if dropped,
1975 carried effect was turned off, else we leave that alone;
1976 we turn off invocation property here if still carried */
1978 arti_invoke(obj
); /* reverse #invoke */
1985 /* check all items currently in use (mostly worn) for touchability */
1987 retouch_equipment(dropflag
)
1988 int dropflag
; /* 0==don't drop, 1==drop all, 2==drop weapon */
1990 static int nesting
= 0; /* recursion control */
1992 boolean dropit
, had_gloves
= (uarmg
!= 0);
1993 int had_rings
= (!!uleft
+ !!uright
);
1996 * We can potentially be called recursively if losing/unwearing
1997 * an item causes worn helm of opposite alignment to come off or
2000 * BUG: if the initial call was due to putting on a helm of
2001 * opposite alignment and it does come off to trigger recursion,
2002 * after the inner call executes, the outer call will finish
2003 * using the non-helm alignment rather than the helm alignment
2004 * which triggered this in the first place.
2007 clear_bypasses(); /* init upon initial entry */
2009 dropit
= (dropflag
> 0); /* drop all or drop weapon */
2010 /* check secondary weapon first, before possibly unwielding primary */
2012 (void) untouchable(uswapwep
, dropit
);
2013 /* check primary weapon next so that they're handled together */
2015 (void) untouchable(uwep
, dropit
);
2017 /* in case someone is daft enough to add artifact or silver saddle */
2018 if (u
.usteed
&& (obj
= which_armor(u
.usteed
, W_SADDLE
)) != 0) {
2019 /* untouchable() calls retouch_object() which expects an object in
2020 hero's inventory, but remove_worn_item() will be harmless for
2021 saddle and we're suppressing drop, so this works as intended */
2022 if (untouchable(obj
, FALSE
))
2023 dismount_steed(DISMOUNT_THROWN
);
2026 * TODO? Force off gloves if either or both rings are going to
2027 * become unworn; force off cloak [suit] before suit [shirt].
2028 * The torso handling is hypothetical; the case for gloves is
2029 * not, due to the possibility of unwearing silver rings.
2032 dropit
= (dropflag
== 1); /* all untouchable items */
2033 /* loss of levitation (silver ring, or Heart of Ahriman invocation)
2034 might cause hero to lose inventory items (by dropping into lava,
2035 for instance), so inventory traversal needs to rescan the whole
2036 invent chain each time it moves on to another object; we use bypass
2037 handling to keep track of which items have already been processed */
2038 while ((obj
= nxt_unbypassed_obj(invent
)) != 0)
2039 (void) untouchable(obj
, dropit
);
2041 if (had_rings
!= (!!uleft
+ !!uright
) && uarmg
&& uarmg
->cursed
)
2042 uncurse(uarmg
); /* temporary? hack for ring removal plausibility */
2043 if (had_gloves
&& !uarmg
)
2044 selftouch("After losing your gloves, you");
2047 clear_bypasses(); /* reset upon final exit */