cmdhelp revamp
[aNetHack.git] / src / artifact.c
blob39525b8d04d47ef06596de69e1fb7d00ca54ccd2
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. */
5 #include "hack.h"
6 #include "artifact.h"
7 #include "artilist.h"
9 /*
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 *,
22 struct monst *));
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() */
53 STATIC_OVL void
54 hack_artifacts()
56 struct artifact *art;
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;
73 return;
76 /* zero out the artifact existence list */
77 void
78 init_artifacts()
80 (void) memset((genericptr_t) artiexist, 0, sizeof artiexist);
81 (void) memset((genericptr_t) artidisco, 0, sizeof artidisco);
82 hack_artifacts();
85 void
86 save_artifacts(fd)
87 int fd;
89 bwrite(fd, (genericptr_t) artiexist, sizeof artiexist);
90 bwrite(fd, (genericptr_t) artidisco, sizeof artidisco);
93 void
94 restore_artifacts(fd)
95 int fd;
97 mread(fd, (genericptr_t) artiexist, sizeof artiexist);
98 mread(fd, (genericptr_t) artidisco, sizeof artidisco);
99 hack_artifacts(); /* redo non-saved special cases */
102 const char *
103 artiname(artinum)
104 int artinum;
106 if (artinum <= 0 || artinum > NROFARTIFACTS)
107 return "";
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
118 possible.
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);''.
122 struct obj *
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;
128 int m, n, altn;
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++) {
138 if (artiexist[m])
139 continue;
140 if ((a->spfx & SPFX_NOGEN) || unique)
141 continue;
143 if (!by_align) {
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)
147 eligible[n++] = m;
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 */
159 eligible[0] = m;
160 n = 1;
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 */
167 eligible[n++] = m;
168 } else {
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) */
174 if (!n)
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 */
183 if (!n)
184 n = altn;
186 if (n) {
187 /* found at least one candidate; pick one at random */
188 m = eligible[rn2(n)]; /* [0..n-1] */
189 a = &artilist[m];
191 /* make an appropriate object if necessary, then christen it */
192 if (by_align)
193 otmp = mksobj((int) a->otyp, TRUE, FALSE);
195 if (otmp) {
196 otmp = oname(otmp, a->name);
197 otmp->oartifact = m;
198 artiexist[m] = TRUE;
200 } else {
201 /* nothing appropriate could be found; return original object */
202 if (by_align)
203 otmp = 0; /* (there was no original object) */
205 return otmp;
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
213 * is non-NULL.
215 const char *
216 artifact_name(name, otyp)
217 const char *name;
218 short *otyp;
220 register const struct artifact *a;
221 register const char *aname;
223 if (!strncmpi(name, "the ", 4))
224 name += 4;
226 for (a = artilist + 1; a->otyp; a++) {
227 aname = a->name;
228 if (!strncmpi(aname, "the ", 4))
229 aname += 4;
230 if (!strcmpi(name, aname)) {
231 *otyp = a->otyp;
232 return a->name;
236 return (char *) 0;
239 boolean
240 exist_artifact(otyp, name)
241 int otyp;
242 const char *name;
244 register const struct artifact *a;
245 boolean *arex;
247 if (otyp && *name)
248 for (a = artilist + 1, arex = artiexist + 1; a->otyp; a++, arex++)
249 if ((int) a->otyp == otyp && !strcmp(a->name, name))
250 return *arex;
251 return FALSE;
254 void
255 artifact_exists(otmp, name, mod)
256 struct obj *otmp;
257 const char *name;
258 boolean mod;
260 register const struct artifact *a;
262 if (otmp && *name)
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);
267 otmp->age = 0;
268 if (otmp->otyp == RIN_INCREASE_DAMAGE)
269 otmp->spe = 0;
270 artiexist[m] = mod;
271 break;
273 return;
277 nartifact_exist()
279 int a = 0;
280 int n = SIZE(artiexist);
282 while (n > 1)
283 if (artiexist[--n])
284 a++;
286 return a;
289 boolean
290 spec_ability(otmp, abil)
291 struct obj *otmp;
292 unsigned long 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 */
300 boolean
301 confers_luck(obj)
302 struct obj *obj;
304 /* might as well check for this too */
305 if (obj->otyp == LUCKSTONE)
306 return TRUE;
308 return (boolean) (obj->oartifact && spec_ability(obj, SPFX_LUCK));
311 /* used to check whether a monster is getting reflection from an artifact */
312 boolean
313 arti_reflects(obj)
314 struct obj *obj;
316 const struct artifact *arti = get_artifact(obj);
318 if (arti) {
319 /* while being worn */
320 if ((obj->owornmask & ~W_ART) && (arti->spfx & SPFX_REFLECT))
321 return TRUE;
322 /* just being carried */
323 if (arti->cspfx & SPFX_REFLECT)
324 return TRUE;
326 return FALSE;
329 /* decide whether this obj is effective when attacking against shades;
330 does not consider the bonus for blessed objects versus undead */
331 boolean
332 shade_glare(obj)
333 struct obj *obj;
335 const struct artifact *arti;
337 /* any silver object is effective */
338 if (objects[obj->otyp].oc_material == SILVER)
339 return TRUE;
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)
343 return TRUE;
344 /* [if there was anything with special bonus against noncorporeals,
345 it would be effective too] */
346 /* otherwise, harmless to shades */
347 return FALSE;
350 /* returns 1 if name is restricted for otmp->otyp */
351 boolean
352 restrict_name(otmp, name)
353 struct obj *otmp;
354 const char *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;
361 if (!*name)
362 return FALSE;
363 if (!strncmpi(name, "the ", 4))
364 name += 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)
378 break;
379 if (!objects[i].oc_name_known
380 && (other = OBJ_DESCR(objects[i])) != 0
381 && (!strcmp(odesc, other) || (i >= lo && i <= hi)))
382 sametype[i] = TRUE;
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])
392 continue;
393 aname = a->name;
394 if (!strncmpi(aname, "the ", 4))
395 aname += 4;
396 if (!strcmp(aname, name))
397 return (boolean) ((a->spfx & (SPFX_NOGEN | SPFX_RESTR)) != 0
398 || otmp->quan > 1L);
401 return FALSE;
404 STATIC_OVL boolean
405 attacks(adtyp, otmp)
406 int adtyp;
407 struct obj *otmp;
409 register const struct artifact *weap;
411 if ((weap = get_artifact(otmp)) != 0)
412 return (boolean) (weap->attk.adtyp == adtyp);
413 return FALSE;
416 boolean
417 defends(adtyp, otmp)
418 int adtyp;
419 struct obj *otmp;
421 register const struct artifact *weap;
423 if ((weap = get_artifact(otmp)) != 0)
424 return (boolean) (weap->defn.adtyp == adtyp);
425 return FALSE;
428 /* used for monsters */
429 boolean
430 defends_when_carried(adtyp, otmp)
431 int adtyp;
432 struct obj *otmp;
434 register const struct artifact *weap;
436 if ((weap = get_artifact(otmp)) != 0)
437 return (boolean) (weap->cary.adtyp == adtyp);
438 return FALSE;
441 /* determine whether an item confers Protection */
442 boolean
443 protects(otmp, being_worn)
444 struct obj *otmp;
445 boolean being_worn;
447 const struct artifact *arti;
449 if (being_worn && objects[otmp->otyp].oc_oprop == PROTECTION)
450 return TRUE;
451 arti = get_artifact(otmp);
452 if (!arti)
453 return FALSE;
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.
462 void
463 set_artifact_intrinsic(otmp, on, wp_mask)
464 struct obj *otmp;
465 boolean on;
466 long wp_mask;
468 long *mask = 0;
469 register const struct artifact *art, *oart = get_artifact(otmp);
470 register struct obj *obj;
471 register uchar dtyp;
472 register long spfx;
474 if (!oart)
475 return;
477 /* effects from the defn field */
478 dtyp = (wp_mask != W_ART) ? oart->defn.adtyp : oart->cary.adtyp;
480 if (dtyp == AD_FIRE)
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)
487 mask = &EAntimagic;
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) {
502 mask = (long *) 0;
503 break;
508 if (mask) {
509 if (on)
510 *mask |= wp_mask;
511 else
512 *mask &= ~wp_mask;
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);
522 spfx &= ~art->cspfx;
526 if (spfx & SPFX_SEARCH) {
527 if (on)
528 ESearching |= wp_mask;
529 else
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,
540 wp_mask);
542 if (spfx & SPFX_ESP) {
543 if (on)
544 ETelepat |= wp_mask;
545 else
546 ETelepat &= ~wp_mask;
547 see_monsters();
549 if (spfx & SPFX_STLTH) {
550 if (on)
551 EStealth |= wp_mask;
552 else
553 EStealth &= ~wp_mask;
555 if (spfx & SPFX_REGEN) {
556 if (on)
557 ERegeneration |= wp_mask;
558 else
559 ERegeneration &= ~wp_mask;
561 if (spfx & SPFX_TCTRL) {
562 if (on)
563 ETeleport_control |= wp_mask;
564 else
565 ETeleport_control &= ~wp_mask;
567 if (spfx & SPFX_WARN) {
568 if (spec_m2(otmp)) {
569 if (on) {
570 EWarn_of_mon |= wp_mask;
571 context.warntype.obj |= spec_m2(otmp);
572 } else {
573 EWarn_of_mon &= ~wp_mask;
574 context.warntype.obj &= ~spec_m2(otmp);
576 see_monsters();
577 } else {
578 if (on)
579 EWarning |= wp_mask;
580 else
581 EWarning &= ~wp_mask;
584 if (spfx & SPFX_EREGEN) {
585 if (on)
586 EEnergy_regeneration |= wp_mask;
587 else
588 EEnergy_regeneration &= ~wp_mask;
590 if (spfx & SPFX_HSPDAM) {
591 if (on)
592 EHalf_spell_damage |= wp_mask;
593 else
594 EHalf_spell_damage &= ~wp_mask;
596 if (spfx & SPFX_HPHDAM) {
597 if (on)
598 EHalf_physical_damage |= wp_mask;
599 else
600 EHalf_physical_damage &= ~wp_mask;
602 if (spfx & SPFX_XRAY) {
603 /* this assumes that no one else is using xray_range */
604 if (on)
605 u.xray_range = 3;
606 else
607 u.xray_range = -1;
608 vision_full_recalc = 1;
610 if ((spfx & SPFX_REFLECT) && (wp_mask & W_WEP)) {
611 if (on)
612 EReflecting |= wp_mask;
613 else
614 EReflecting &= ~wp_mask;
616 if (spfx & SPFX_PROTECT) {
617 if (on)
618 EProtection |= wp_mask;
619 else
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)
645 struct obj *obj;
646 struct monst *mon;
648 register const struct artifact *oart = get_artifact(obj);
649 boolean badclass, badalign, self_willed, yours;
651 touch_blasted = FALSE;
652 if (!oart)
653 return 1;
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);
659 if (yours) {
660 badclass = self_willed
661 && ((oart->role != NON_PM && !Role_if(oart->role))
662 || (oart->race != NON_PM && !Race_if(oart->race)));
663 badalign =
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 */
678 if (!badalign)
679 badalign = bane_applies(oart, mon);
681 if (((badclass || badalign) && self_willed)
682 || (badalign && (!yours || !rn2(4)))) {
683 int dmg, tmp;
684 char buf[BUFSZ];
686 if (!yours)
687 return 0;
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) {
701 if (yours) {
702 if (!carried(obj))
703 pline("%s your grasp!", Tobjnam(obj, "evade"));
704 else
705 pline("%s beyond your control!", Tobjnam(obj, "are"));
707 return 0;
710 return 1;
713 /* decide whether an artifact itself is vulnerable to a particular type
714 of erosion damage, independent of the properties of its bearer */
715 boolean
716 arti_immune(obj, dtyp)
717 struct obj *obj;
718 int dtyp;
720 register const struct artifact *weap = get_artifact(obj);
722 if (!weap)
723 return FALSE;
724 if (dtyp == AD_PHYS)
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);
731 STATIC_OVL boolean
732 bane_applies(oart, mon)
733 const struct artifact *oart;
734 struct monst *mon;
736 struct artifact atmp;
738 if (oart && (oart->spfx & SPFX_DBONUS) != 0) {
739 atmp = *oart;
740 atmp.spfx &= SPFX_DBONUS; /* clear other spfx fields */
741 if (spec_applies(&atmp, mon))
742 return TRUE;
744 return FALSE;
747 /* decide whether an artifact's special attacks apply against mtmp */
748 STATIC_OVL int
749 spec_applies(weap, mtmp)
750 register const struct artifact *weap;
751 struct monst *mtmp;
753 struct permonst *ptr;
754 boolean yours;
756 if (!(weap->spfx & (SPFX_DBONUS | SPFX_ATTK)))
757 return (weap->attk.adtyp == AD_PHYS);
759 yours = (mtmp == &youmonst);
760 ptr = mtmp->data;
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)
770 || (yours
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))
782 return FALSE;
783 switch (weap->attk.adtyp) {
784 case AD_FIRE:
785 return !(yours ? Fire_resistance : resists_fire(mtmp));
786 case AD_COLD:
787 return !(yours ? Cold_resistance : resists_cold(mtmp));
788 case AD_ELEC:
789 return !(yours ? Shock_resistance : resists_elec(mtmp));
790 case AD_MAGM:
791 case AD_STUN:
792 return !(yours ? Antimagic : (rn2(100) < ptr->mr));
793 case AD_DRST:
794 return !(yours ? Poison_resistance : resists_poison(mtmp));
795 case AD_DRLI:
796 return !(yours ? Drain_resistance : resists_drli(mtmp));
797 case AD_STON:
798 return !(yours ? Stone_resistance : resists_ston(mtmp));
799 default:
800 impossible("Weird weapon special attack.");
803 return 0;
806 /* return the M2 flags of monster that an artifact's special attacks apply
807 * against */
808 long
809 spec_m2(otmp)
810 struct obj *otmp;
812 const struct artifact *artifact = get_artifact(otmp);
814 if (artifact)
815 return artifact->mtype;
816 return 0L;
819 /* special attack bonus */
821 spec_abon(otmp, mon)
822 struct obj *otmp;
823 struct monst *mon;
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);
832 return 0;
835 /* special damage bonus */
837 spec_dbon(otmp, mon, tmp)
838 struct obj *otmp;
839 struct monst *mon;
840 int 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;
851 else
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);
856 return 0;
859 /* add identified artifact to discoveries list */
860 void
861 discover_artifact(m)
862 xchar m;
864 int i;
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) {
870 artidisco[i] = m;
871 return;
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 */
879 boolean
880 undiscovered_artifact(m)
881 xchar m;
883 int i;
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)
889 return FALSE;
890 else if (artidisco[i] == 0)
891 break;
892 return TRUE;
895 /* display a list of discovered artifacts; return their count */
897 disp_artifact_discoveries(tmpwin)
898 winid tmpwin; /* supplied by dodiscover() */
900 int i, m, otyp;
901 char buf[BUFSZ];
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 */
909 if (i == 0)
910 putstr(tmpwin, iflags.menu_headings, "Artifacts");
911 m = artidisco[i];
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);
917 return i;
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 */
951 STATIC_OVL boolean
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 */
968 if (mb->spe >= 3)
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)
973 dieroll += 1;
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 */
990 if (do_stun) {
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) {
1006 result = TRUE;
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)) {
1024 resisted = TRUE;
1025 } else {
1026 do_stun = FALSE;
1027 if (youdefend) {
1028 if (youmonst.data != old_uasmon)
1029 *dmgptr = 0; /* rehumanized, so no more damage */
1030 if (u.uenmax > 0) {
1031 You("lose magical energy!");
1032 u.uenmax--;
1033 if (u.uen > 0)
1034 u.uen--;
1035 context.botl = 1;
1037 } else {
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!");
1042 u.uenmax++;
1043 u.uen++;
1044 context.botl = 1;
1048 break;
1050 case MB_INDEX_SCARE:
1051 if (youdefend) {
1052 if (Antimagic) {
1053 resisted = TRUE;
1054 } else {
1055 nomul(-3);
1056 multi_reason = "being scared stiff";
1057 nomovemsg = "";
1058 if (magr && magr == u.ustuck && sticks(youmonst.data)) {
1059 u.ustuck = (struct monst *) 0;
1060 You("release %s!", mon_nam(magr));
1063 } else {
1064 if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL))
1065 resisted = TRUE;
1066 else
1067 monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr));
1069 if (!resisted)
1070 do_stun = FALSE;
1071 break;
1073 case MB_INDEX_STUN:
1074 do_stun = TRUE; /* (this is redundant...) */
1075 break;
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);
1083 break;
1085 /* stun if that was selected and a worse effect didn't occur */
1086 if (do_stun) {
1087 if (youdefend)
1088 make_stunned(((HStun & TIMEOUT) + 3L), FALSE);
1089 else
1090 mdef->mstun = 1;
1091 /* avoid extra stun message below if we used mb_verb["stun"] above */
1092 if (attack_indx == MB_INDEX_STUN)
1093 do_stun = FALSE;
1095 /* lastly, all this magic can be confusing... */
1096 do_confuse = !rn2(12);
1097 if (do_confuse) {
1098 if (youdefend)
1099 make_confused((HConfusion & TIMEOUT) + 4L, FALSE);
1100 else
1101 mdef->mconf = 1;
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 */
1109 if (resisted) {
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) {
1115 char buf[BUFSZ];
1117 buf[0] = '\0';
1118 if (do_stun)
1119 Strcat(buf, "stunned");
1120 if (do_stun && do_confuse)
1121 Strcat(buf, " and ");
1122 if (do_confuse)
1123 Strcat(buf, "confused");
1124 pline("%s %s %s%c", hittee, vtense(fakename, "are"), buf,
1125 (do_stun && do_confuse) ? '!' : '.');
1129 return result;
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".
1140 boolean
1141 artifact_hit(magr, mdef, otmp, dmgptr, dieroll)
1142 struct monst *magr, *mdef;
1143 struct obj *otmp;
1144 int *dmgptr;
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";
1155 char hittee[BUFSZ];
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?");
1167 return FALSE;
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",
1178 !spec_dbon_applies
1179 ? "hits"
1180 : (mdef->data == &mons[PM_WATER_ELEMENTAL])
1181 ? "vaporizes part of"
1182 : "burns",
1183 hittee, !spec_dbon_applies ? '.' : '!');
1184 if (!rn2(4))
1185 (void) destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
1186 if (!rn2(4))
1187 (void) destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
1188 if (!rn2(7))
1189 (void) destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
1190 if (youdefend && Slimed)
1191 burn_away_slime();
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 ? '.' : '!');
1199 if (!rn2(4))
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 ? '.' : '!');
1208 if (!rn2(5))
1209 (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC);
1210 if (!rn2(5))
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",
1217 !spec_dbon_applies
1218 ? ""
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 */
1232 return FALSE;
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;
1244 return TRUE;
1246 if (!youdefend) {
1247 /* allow normal cutworm() call to add extra damage */
1248 if (notonhead)
1249 return FALSE;
1251 if (bigmonst(mdef->data)) {
1252 if (youattack)
1253 You("slice deeply into %s!", mon_nam(mdef));
1254 else if (vis)
1255 pline("%s cuts deeply into %s!", Monnam(magr),
1256 hittee);
1257 *dmgptr *= 2;
1258 return TRUE;
1260 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1261 pline("%s cuts %s in half!", wepdesc, mon_nam(mdef));
1262 otmp->dknown = TRUE;
1263 return TRUE;
1264 } else {
1265 if (bigmonst(youmonst.data)) {
1266 pline("%s cuts deeply into you!",
1267 magr ? Monnam(magr) : wepdesc);
1268 *dmgptr *= 2;
1269 return TRUE;
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;
1280 return 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)
1288 return FALSE;
1289 wepdesc = artilist[ART_VORPAL_BLADE].name;
1290 if (!youdefend) {
1291 if (!has_head(mdef->data) || notonhead || u.uswallow) {
1292 if (youattack)
1293 pline("Somehow, you miss %s wildly.", mon_nam(mdef));
1294 else if (vis)
1295 pline("Somehow, %s misses wildly.", mon_nam(magr));
1296 *dmgptr = 0;
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));
1302 return TRUE;
1304 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1305 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc,
1306 mon_nam(mdef));
1307 if (Hallucination && !flags.female)
1308 pline("Good job Henry, but that wasn't Anne.");
1309 otmp->dknown = TRUE;
1310 return TRUE;
1311 } else {
1312 if (!has_head(youmonst.data)) {
1313 pline("Somehow, %s misses you wildly.",
1314 magr ? mon_nam(magr) : wepdesc);
1315 *dmgptr = 0;
1316 return TRUE;
1318 if (noncorporeal(youmonst.data) || amorphous(youmonst.data)) {
1319 pline("%s slices through your %s.", wepdesc,
1320 body_part(NECK));
1321 return TRUE;
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? */
1327 return TRUE;
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";
1336 if (!youdefend) {
1337 if (vis) {
1338 if (otmp->oartifact == ART_STORMBRINGER)
1339 pline_The("%s blade draws the %s from %s!",
1340 hcolor(NH_BLACK), life, mon_nam(mdef));
1341 else
1342 pline("%s draws the %s from %s!",
1343 The(distant_name(otmp, xname)), life,
1344 mon_nam(mdef));
1346 if (mdef->m_lev == 0) {
1347 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1348 } else {
1349 int drain = monhp_per_lvl(mdef);
1351 *dmgptr += drain;
1352 mdef->mhpmax -= drain;
1353 mdef->m_lev--;
1354 drain /= 2;
1355 if (drain)
1356 healup(drain, 0, FALSE, FALSE);
1358 return vis;
1359 } else { /* youdefend */
1360 int oldhpmax = u.uhpmax;
1362 if (Blind)
1363 You_feel("an %s drain your %s!",
1364 (otmp->oartifact == ART_STORMBRINGER)
1365 ? "unholy blade"
1366 : "object",
1367 life);
1368 else if (otmp->oartifact == ART_STORMBRINGER)
1369 pline_The("%s blade drains your %s!", hcolor(NH_BLACK), life);
1370 else
1371 pline("%s drains your %s!", The(distant_name(otmp, xname)),
1372 life);
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;
1379 return TRUE;
1382 return FALSE;
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 */
1391 doinvoke()
1393 struct obj *obj;
1395 obj = getobj(invoke_types, "invoke");
1396 if (!obj)
1397 return 0;
1398 if (!retouch_object(&obj, FALSE))
1399 return 1;
1400 return arti_invoke(obj);
1403 STATIC_OVL int
1404 arti_invoke(obj)
1405 struct obj *obj;
1407 register const struct artifact *oart = get_artifact(obj);
1408 if (!obj) {
1409 impossible("arti_invoke without obj");
1410 return 0;
1412 if (!oart || !oart->inv_prop) {
1413 if (obj->otyp == CRYSTAL_BALL)
1414 use_crystal_ball(&obj);
1415 else
1416 pline1(nothing_happens);
1417 return 1;
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);
1428 return 1;
1430 obj->age = monstermoves + rnz(100);
1432 switch (oart->inv_prop) {
1433 case TAMING: {
1434 struct obj pseudo;
1436 pseudo =
1437 zeroobj; /* neither cursed nor blessed, zero oextra too */
1438 pseudo.otyp = SCR_TAMING;
1439 (void) seffects(&pseudo);
1440 break;
1442 case HEALING: {
1443 int healamt = (u.uhpmax + 1 - u.uhp) / 2;
1444 long creamed = (long) u.ucreamed;
1446 if (Upolyd)
1447 healamt = (u.mhmax + 1 - u.mh) / 2;
1448 if (healamt || Sick || Slimed || Blinded > creamed)
1449 You_feel("better.");
1450 else
1451 goto nothing_special;
1452 if (healamt > 0) {
1453 if (Upolyd)
1454 u.mh += healamt;
1455 else
1456 u.uhp += healamt;
1458 if (Sick)
1459 make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1460 if (Slimed)
1461 make_slimed(0L, (char *) 0);
1462 if (Blinded > creamed)
1463 make_blinded(creamed, FALSE);
1464 context.botl = 1;
1465 break;
1467 case ENERGY_BOOST: {
1468 int epboost = (u.uenmax + 1 - u.uen) / 2;
1469 if (epboost > 120)
1470 epboost = 120; /* arbitrary */
1471 else if (epboost < 12)
1472 epboost = u.uenmax - u.uen;
1473 if (epboost) {
1474 You_feel("re-energized.");
1475 u.uen += epboost;
1476 context.botl = 1;
1477 } else
1478 goto nothing_special;
1479 break;
1481 case UNTRAP: {
1482 if (!untrap(TRUE)) {
1483 obj->age = 0; /* don't charge for changing their mind */
1484 return 0;
1486 break;
1488 case CHARGE_OBJ: {
1489 struct obj *otmp = getobj(recharge_type, "charge");
1490 boolean b_effect;
1492 if (!otmp) {
1493 obj->age = 0;
1494 return 0;
1496 b_effect =
1497 obj->blessed && (Role_switch == oart->role || !oart->role);
1498 recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0);
1499 update_inventory();
1500 break;
1502 case LEV_TELE:
1503 level_tele();
1504 break;
1505 case CREATE_PORTAL: {
1506 int i, num_ok_dungeons, last_ok_dungeon = 0;
1507 d_level newlev;
1508 extern int n_dgns; /* from dungeon.c */
1509 winid tmpwin = create_nhwindow(NHW_MENU);
1510 anything any;
1512 any = zeroany; /* set all bits to zero */
1513 start_menu(tmpwin);
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)
1517 continue;
1518 any.a_int = i + 1;
1519 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1520 dungeons[i].dname, MENU_UNSELECTED);
1521 num_ok_dungeons++;
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;
1528 int n;
1530 n = select_menu(tmpwin, PICK_ONE, &selected);
1531 if (n <= 0) {
1532 destroy_nhwindow(tmpwin);
1533 goto nothing_special;
1535 i = selected[0].item.a_int - 1;
1536 free((genericptr_t) selected);
1537 } else
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.
1547 newlev.dnum = i;
1548 if (dungeons[i].depth_start >= depth(&u.uz))
1549 newlev.dlevel = dungeons[i].entry_lev;
1550 else
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.");
1556 } else {
1557 if (!Blind)
1558 You("are surrounded by a shimmering sphere!");
1559 else
1560 You_feel("weightless for a moment.");
1561 goto_level(&newlev, FALSE, FALSE, FALSE);
1563 break;
1565 case ENLIGHTENING:
1566 enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS);
1567 break;
1568 case CREATE_AMMO: {
1569 struct obj *otmp = mksobj(ARROW, TRUE, FALSE);
1571 if (!otmp)
1572 goto nothing_special;
1573 otmp->blessed = obj->blessed;
1574 otmp->cursed = obj->cursed;
1575 otmp->bknown = obj->bknown;
1576 if (obj->blessed) {
1577 if (otmp->spe < 0)
1578 otmp->spe = 0;
1579 otmp->quan += rnd(10);
1580 } else if (obj->cursed) {
1581 if (otmp->spe > 0)
1582 otmp->spe = 0;
1583 } else
1584 otmp->quan += rnd(5);
1585 otmp->owt = weight(otmp);
1586 otmp =
1587 hold_another_object(otmp, "Suddenly %s out.",
1588 aobjnam(otmp, "fall"), (const char *) 0);
1589 break;
1592 } else {
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);
1604 return 1;
1605 } else if (!on) {
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) {
1612 nothing_special:
1613 /* you had the property from some other source too */
1614 if (carried(obj))
1615 You_feel("a surge of power, but nothing seems to happen.");
1616 return 1;
1618 switch (oart->inv_prop) {
1619 case CONFLICT:
1620 if (on)
1621 You_feel("like a rabble-rouser.");
1622 else
1623 You_feel("the tension decrease around you.");
1624 break;
1625 case LEVITATION:
1626 if (on) {
1627 float_up();
1628 spoteffects(FALSE);
1629 } else
1630 (void) float_down(I_SPECIAL | TIMEOUT, W_ARTI);
1631 break;
1632 case INVIS:
1633 if (BInvis || Blind)
1634 goto nothing_special;
1635 newsym(u.ux, u.uy);
1636 if (on)
1637 Your("body takes on a %s transparency...",
1638 Hallucination ? "normal" : "strange");
1639 else
1640 Your("body seems to unfade...");
1641 break;
1645 return 1;
1648 /* will freeing this object from inventory cause levitation to end? */
1649 boolean
1650 finesse_ahriman(obj)
1651 struct obj *obj;
1653 const struct artifact *oart;
1654 struct prop save_Lev;
1655 boolean result;
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))
1661 return FALSE;
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;
1673 return result;
1676 /* WAC return TRUE if artifact is always lit */
1677 boolean
1678 artifact_light(obj)
1679 struct obj *obj;
1681 return (boolean) (get_artifact(obj) && obj->oartifact == ART_SUNSWORD);
1684 /* KMH -- Talking artifacts are finally implemented */
1685 void
1686 arti_speak(obj)
1687 struct obj *obj;
1689 register const struct artifact *oart = get_artifact(obj);
1690 const char *line;
1691 char buf[BUFSZ];
1693 /* Is this a speaking artifact? */
1694 if (!oart || !(oart->spfx & SPFX_SPEAK))
1695 return;
1697 line = getrumor(bcsign(obj), buf, TRUE);
1698 if (!*line)
1699 line = "NetHack rumors file closed for renovation.";
1700 pline("%s:", Tobjnam(obj, "whisper"));
1701 verbalize1(line);
1702 return;
1705 boolean
1706 artifact_has_invprop(otmp, inv_prop)
1707 struct obj *otmp;
1708 uchar 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 */
1716 long
1717 arti_cost(otmp)
1718 struct obj *otmp;
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;
1724 else
1725 return (100L * (long) objects[otmp->otyp].oc_cost);
1728 STATIC_OVL uchar
1729 abil_to_adtyp(abil)
1730 long *abil;
1732 struct abil2adtyp_tag {
1733 long *abil;
1734 uchar adtyp;
1735 } abil2adtyp[] = {
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 },
1744 int k;
1746 for (k = 0; k < SIZE(abil2adtyp); k++) {
1747 if (abil2adtyp[k].abil == abil)
1748 return abil2adtyp[k].adtyp;
1750 return 0;
1753 STATIC_OVL unsigned long
1754 abil_to_spfx(abil)
1755 long *abil;
1757 static const struct abil2spfx_tag {
1758 long *abil;
1759 unsigned long spfx;
1760 } abil2spfx[] = {
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 },
1774 int k;
1776 for (k = 0; k < SIZE(abil2spfx); k++) {
1777 if (abil2spfx[k].abil == abil)
1778 return abil2spfx[k].spfx;
1780 return 0L;
1784 * Return the first item that is conveying a particular intrinsic.
1786 struct obj *
1787 what_gives(abil)
1788 long *abil;
1790 struct obj *obj;
1791 uchar dtyp;
1792 unsigned long spfx;
1793 long wornbits;
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
1797 | W_ART | W_ARTI);
1799 if (u.twoweap)
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) {
1806 if (obj->oartifact
1807 && (abil != &EWarn_of_mon || context.warntype.obj)) {
1808 const struct artifact *art = get_artifact(obj);
1810 if (art) {
1811 if (dtyp) {
1812 if (art->cary.adtyp == dtyp /* carried */
1813 || (art->defn.adtyp == dtyp /* defends while worn */
1814 && (obj->owornmask & ~(W_ART | W_ARTI))))
1815 return obj;
1817 if (spfx) {
1818 /* property conferred when carried */
1819 if ((art->cspfx & spfx) == spfx)
1820 return obj;
1821 /* property conferred when wielded or worn */
1822 if ((art->spfx & spfx) == spfx && obj->owornmask)
1823 return obj;
1826 } else {
1827 if (wornbits && wornbits == (wornmask & obj->owornmask))
1828 return obj;
1831 return (struct obj *) 0;
1834 const char *
1835 glow_color(arti_indx)
1836 int 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 */
1845 void
1846 Sting_effects(orc_count)
1847 int orc_count; /* new count (warn_obj_cnt is old count); -1 is a flag value */
1849 if (uwep
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 */
1860 if (!Blind)
1861 pline("%s %s %s!", bare_artifactname(uwep),
1862 otense(uwep, "glow"), glow_color(uwep->oartifact));
1863 else
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)) {
1884 char buf[BUFSZ];
1885 int dmg = 0, tmp;
1886 boolean ag =
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 */
1891 if (!ag && !bane)
1892 return 1;
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 */
1902 if (ag)
1903 tmp = rnd(10), dmg += Maybe_Half_Phys(tmp);
1904 if (bane)
1905 dmg += rnd(10);
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) {
1916 struct obj *otmp;
1918 remove_worn_item(obj, FALSE);
1919 for (otmp = invent; otmp; otmp = otmp->nobj)
1920 if (otmp == obj)
1921 break;
1922 if (!otmp)
1923 *objp = obj = 0;
1926 /* if we still have it and caller wants us to drop it, do so now */
1927 if (loseit && obj) {
1928 if (Levitation) {
1929 freeinv(obj);
1930 hitfloor(obj);
1931 } else {
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));
1936 dropx(obj);
1938 *objp = obj = 0; /* no longer in inventory */
1940 return 0;
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 */
1947 STATIC_OVL boolean
1948 untouchable(obj, drop_untouchable)
1949 struct obj *obj;
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);
1966 } else {
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 */
1977 if (invoked && obj)
1978 arti_invoke(obj); /* reverse #invoke */
1979 return TRUE;
1982 return FALSE;
1985 /* check all items currently in use (mostly worn) for touchability */
1986 void
1987 retouch_equipment(dropflag)
1988 int dropflag; /* 0==don't drop, 1==drop all, 2==drop weapon */
1990 static int nesting = 0; /* recursion control */
1991 struct obj *obj;
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
1998 * be destroyed.
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.
2006 if (!nesting++)
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 */
2011 if (u.twoweap)
2012 (void) untouchable(uswapwep, dropit);
2013 /* check primary weapon next so that they're handled together */
2014 if (uwep)
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");
2046 if (!--nesting)
2047 clear_bypasses(); /* reset upon final exit */
2050 /*artifact.c*/