1 /* NetHack 3.7 artifact.c $NHDT-Date: 1620326528 2021/05/06 18:42:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.167 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2013. */
4 /* NetHack may be freely redistributed. See license for details. */
5
6 #include "hack.h"
7 #include "artifact.h"
8 #include "artilist.h"
9
10 /*
11 * Note: both artilist[] and artiexist[] have a dummy element #0,
12 * so loops over them should normally start at #1. The primary
13 * exception is the save & restore code, which doesn't care about
14 * the contents, just the total size.
15 */
16
17 #define get_artifact(o) \
18 (((o) && (o)->oartifact) ? &artilist[(int) (o)->oartifact] : 0)
19
20 static boolean bane_applies(const struct artifact *, struct monst *);
21 static int spec_applies(const struct artifact *, struct monst *);
22 static int invoke_ok(struct obj *);
23 static int arti_invoke(struct obj *);
24 static boolean Mb_hit(struct monst * magr, struct monst *mdef,
25 struct obj *, int *, int, boolean, char *);
26 static unsigned long abil_to_spfx(long *);
27 static uchar abil_to_adtyp(long *);
28 static int glow_strength(int);
29 static boolean untouchable(struct obj *, boolean);
30 static int count_surround_traps(int, int);
31
32 /* The amount added to the victim's total hit points to insure that the
33 victim will be killed even after damage bonus/penalty adjustments.
34 Most such penalties are small, and 200 is plenty; the exception is
35 half physical damage. 3.3.1 and previous versions tried to use a very
36 large number to account for this case; now, we just compute the fatal
37 damage by adding it to 2 times the total hit points instead of 1 time.
38 Note: this will still break if they have more than about half the number
39 of hit points that will fit in a 15 bit integer. */
40 #define FATAL_DAMAGE_MODIFIER 200
41
42 static void hack_artifacts(void);
43 static boolean attacks(int, struct obj *);
44
45 /* handle some special cases; must be called after u_init() */
46 static void
hack_artifacts(void)47 hack_artifacts(void)
48 {
49 struct artifact *art;
50 int alignmnt = aligns[flags.initalign].value;
51
52 /* Fix up the alignments of "gift" artifacts */
53 for (art = artilist + 1; art->otyp; art++)
54 if (art->role == Role_switch && art->alignment != A_NONE)
55 art->alignment = alignmnt;
56
57 /* Excalibur can be used by any lawful character, not just knights */
58 if (!Role_if(PM_KNIGHT))
59 artilist[ART_EXCALIBUR].role = NON_PM;
60
61 /* Fix up the quest artifact */
62 if (g.urole.questarti) {
63 artilist[g.urole.questarti].alignment = alignmnt;
64 artilist[g.urole.questarti].role = Role_switch;
65 }
66 return;
67 }
68
69 /* zero out the artifact existence list */
70 void
init_artifacts(void)71 init_artifacts(void)
72 {
73 (void) memset((genericptr_t) g.artiexist, 0, sizeof g.artiexist);
74 (void) memset((genericptr_t) g.artidisco, 0, sizeof g.artidisco);
75 hack_artifacts();
76 }
77
78 void
save_artifacts(NHFILE * nhfp)79 save_artifacts(NHFILE *nhfp)
80 {
81 if (nhfp->structlevel) {
82 bwrite(nhfp->fd, (genericptr_t) g.artiexist, sizeof g.artiexist);
83 bwrite(nhfp->fd, (genericptr_t) g.artidisco, sizeof g.artidisco);
84 }
85 }
86
87 void
restore_artifacts(NHFILE * nhfp)88 restore_artifacts(NHFILE *nhfp)
89 {
90 if (nhfp->structlevel) {
91 mread(nhfp->fd, (genericptr_t) g.artiexist, sizeof g.artiexist);
92 mread(nhfp->fd, (genericptr_t) g.artidisco, sizeof g.artidisco);
93 }
94 hack_artifacts(); /* redo non-saved special cases */
95 }
96
97 const char *
artiname(int artinum)98 artiname(int artinum)
99 {
100 if (artinum <= 0 || artinum > NROFARTIFACTS)
101 return "";
102 return artilist[artinum].name;
103 }
104
105 /*
106 Make an artifact. If a specific alignment is specified, then an object of
107 the appropriate alignment is created from scratch, or 0 is returned if
108 none is available. (If at least one aligned artifact has already been
109 given, then unaligned ones also become eligible for this.)
110 If no alignment is given, then 'otmp' is converted
111 into an artifact of matching type, or returned as-is if that's not
112 possible.
113 For the 2nd case, caller should use ``obj = mk_artifact(obj, A_NONE);''
114 for the 1st, ``obj = mk_artifact((struct obj *)0, some_alignment);''.
115 */
116 struct obj *
mk_artifact(struct obj * otmp,aligntyp alignment)117 mk_artifact(struct obj *otmp, /* existing object; ignored if alignment specified */
118 aligntyp alignment) /* target alignment, or A_NONE */
119 {
120 const struct artifact *a;
121 int m, n, altn;
122 boolean by_align = (alignment != A_NONE);
123 short o_typ = (by_align || !otmp) ? 0 : otmp->otyp;
124 boolean unique = !by_align && otmp && objects[o_typ].oc_unique;
125 short eligible[NROFARTIFACTS];
126
127 n = altn = 0; /* no candidates found yet */
128 eligible[0] = 0; /* lint suppression */
129 /* gather eligible artifacts */
130 for (m = 1, a = &artilist[m]; a->otyp; a++, m++) {
131 if (g.artiexist[m])
132 continue;
133 if ((a->spfx & SPFX_NOGEN) || unique)
134 continue;
135
136 if (!by_align) {
137 /* looking for a particular type of item; not producing a
138 divine gift so we don't care about role's first choice */
139 if (a->otyp == o_typ)
140 eligible[n++] = m;
141 continue; /* move on to next possibility */
142 }
143
144 /* we're looking for an alignment-specific item
145 suitable for hero's role+race */
146 if ((a->alignment == alignment || a->alignment == A_NONE)
147 /* avoid enemies' equipment */
148 && (a->race == NON_PM || !race_hostile(&mons[a->race]))) {
149 /* when a role-specific first choice is available, use it */
150 if (Role_if(a->role)) {
151 /* make this be the only possibility in the list */
152 eligible[0] = m;
153 n = 1;
154 break; /* skip all other candidates */
155 }
156 /* found something to consider for random selection */
157 if (a->alignment != A_NONE || u.ugifts > 0) {
158 /* right alignment, or non-aligned with at least 1
159 previous gift bestowed, makes this one viable */
160 eligible[n++] = m;
161 } else {
162 /* non-aligned with no previous gifts;
163 if no candidates have been found yet, record
164 this one as a[nother] fallback possibility in
165 case all aligned candidates have been used up
166 (via wishing, naming, bones, random generation) */
167 if (!n)
168 eligible[altn++] = m;
169 /* [once a regular candidate is found, the list
170 is overwritten and `altn' becomes irrelevant] */
171 }
172 }
173 }
174
175 /* resort to fallback list if main list was empty */
176 if (!n)
177 n = altn;
178
179 if (n) {
180 /* found at least one candidate; pick one at random */
181 m = eligible[rn2(n)]; /* [0..n-1] */
182 a = &artilist[m];
183
184 /* make an appropriate object if necessary, then christen it */
185 if (by_align)
186 otmp = mksobj((int) a->otyp, TRUE, FALSE);
187
188 if (otmp) {
189 otmp = oname(otmp, a->name);
190 otmp->oartifact = m;
191 g.artiexist[m] = TRUE;
192 }
193 } else {
194 /* nothing appropriate could be found; return original object */
195 if (by_align)
196 otmp = 0; /* (there was no original object) */
197 }
198 /* poison artifacts that are permapoisoned */
199 if (permapoisoned(otmp))
200 otmp->opoisoned = 1;
201 return otmp;
202 }
203
204 /*
205 * Returns the full name (with articles and correct capitalization) of an
206 * artifact named "name" if one exists, or NULL, it not.
207 * The given name must be rather close to the real name for it to match.
208 * The object type of the artifact is returned in otyp if the return value
209 * is non-NULL.
210 */
211 const char *
artifact_name(const char * name,short * otyp)212 artifact_name(const char *name, short *otyp)
213 {
214 register const struct artifact *a;
215 register const char *aname;
216
217 if (!strncmpi(name, "the ", 4))
218 name += 4;
219
220 for (a = artilist + 1; a->otyp; a++) {
221 aname = a->name;
222 if (!strncmpi(aname, "the ", 4))
223 aname += 4;
224 if (!strcmpi(name, aname)) {
225 *otyp = a->otyp;
226 return a->name;
227 }
228 }
229
230 return (char *) 0;
231 }
232
233 boolean
exist_artifact(int otyp,const char * name)234 exist_artifact(int otyp, const char *name)
235 {
236 register const struct artifact *a;
237 boolean *arex;
238
239 if (otyp && *name)
240 for (a = artilist + 1, arex = g.artiexist + 1; a->otyp; a++, arex++)
241 if ((int) a->otyp == otyp && !strcmp(a->name, name))
242 return *arex;
243 return FALSE;
244 }
245
246 void
artifact_exists(struct obj * otmp,const char * name,boolean mod)247 artifact_exists(struct obj *otmp, const char *name, boolean mod)
248 {
249 register const struct artifact *a;
250
251 if (otmp && *name)
252 for (a = artilist + 1; a->otyp; a++)
253 if (a->otyp == otmp->otyp && !strcmp(a->name, name)) {
254 register int m = (int) (a - artilist);
255 otmp->oartifact = (char) (mod ? m : 0);
256 otmp->age = 0;
257 if (otmp->otyp == RIN_INCREASE_DAMAGE)
258 otmp->spe = 0;
259 g.artiexist[m] = mod;
260 break;
261 }
262 return;
263 }
264
265 int
nartifact_exist(void)266 nartifact_exist(void)
267 {
268 int a = 0;
269 int n = SIZE(g.artiexist);
270
271 while (n > 1)
272 if (g.artiexist[--n])
273 a++;
274
275 return a;
276 }
277
278 boolean
spec_ability(struct obj * otmp,unsigned long abil)279 spec_ability(struct obj *otmp, unsigned long abil)
280 {
281 const struct artifact *arti = get_artifact(otmp);
282
283 return (boolean) (arti && (arti->spfx & abil) != 0L);
284 }
285
286 /* used so that callers don't need to known about SPFX_ codes */
287 boolean
confers_luck(struct obj * obj)288 confers_luck(struct obj *obj)
289 {
290 /* might as well check for this too */
291 if (obj->otyp == LUCKSTONE)
292 return TRUE;
293
294 return (boolean) (obj->oartifact && spec_ability(obj, SPFX_LUCK));
295 }
296
297 /* used to check whether a monster is getting reflection from an artifact */
298 boolean
arti_reflects(struct obj * obj)299 arti_reflects(struct obj *obj)
300 {
301 const struct artifact *arti = get_artifact(obj);
302
303 if (arti) {
304 /* while being worn */
305 if ((obj->owornmask & ~W_ART) && (arti->spfx & SPFX_REFLECT))
306 return TRUE;
307 /* just being carried */
308 if (arti->cspfx & SPFX_REFLECT)
309 return TRUE;
310 }
311 return FALSE;
312 }
313
314 /* decide whether this obj is effective when attacking against shades or any
315 * other incorporeal monster */
316 boolean
shade_glare(struct obj * obj)317 shade_glare(struct obj *obj)
318 {
319 const struct artifact *arti;
320
321 /* any silver object is effective; bone too, though it gets no bonus */
322 if (obj->material == SILVER || obj->material == BONE)
323 return TRUE;
324 /* non-silver artifacts with bonus against undead also are effective */
325 arti = get_artifact(obj);
326 if (arti && (arti->spfx & SPFX_DFLAG2) && arti->mtype == M2_UNDEAD)
327 return TRUE;
328 /* [if there was anything with special bonus against noncorporeals,
329 it would be effective too] */
330 /* otherwise, harmless to shades */
331 return FALSE;
332 }
333
334 /* returns 1 if name is restricted for otmp->otyp */
335 boolean
restrict_name(struct obj * otmp,const char * name)336 restrict_name(struct obj *otmp, const char *name)
337 {
338 register const struct artifact *a;
339 const char *aname, *odesc, *other;
340 boolean sametype[NUM_OBJECTS];
341 int i, lo, hi, otyp = otmp->otyp, ocls = objects[otyp].oc_class;
342
343 if (!*name)
344 return FALSE;
345 if (!strncmpi(name, "the ", 4))
346 name += 4;
347
348 /* decide what types of objects are the same as otyp;
349 if it's been discovered, then only itself matches;
350 otherwise, include all other undiscovered objects
351 of the same class which have the same description
352 or share the same pool of shuffled descriptions */
353 (void) memset((genericptr_t) sametype, 0, sizeof sametype); /* FALSE */
354 sametype[otyp] = TRUE;
355 if (!objects[otyp].oc_name_known
356 && (odesc = OBJ_DESCR(objects[otyp])) != 0) {
357 obj_shuffle_range(otyp, &lo, &hi);
358 for (i = g.bases[ocls]; i < NUM_OBJECTS; i++) {
359 if (objects[i].oc_class != ocls)
360 break;
361 if (!objects[i].oc_name_known
362 && (other = OBJ_DESCR(objects[i])) != 0
363 && (!strcmp(odesc, other) || (i >= lo && i <= hi)))
364 sametype[i] = TRUE;
365 }
366 }
367
368 /* Since almost every artifact is SPFX_RESTR, it doesn't cost
369 us much to do the string comparison before the spfx check.
370 Bug fix: don't name multiple elven daggers "Sting".
371 */
372 for (a = artilist + 1; a->otyp; a++) {
373 if (!sametype[a->otyp])
374 continue;
375 aname = a->name;
376 if (!strncmpi(aname, "the ", 4))
377 aname += 4;
378 if (!strcmp(aname, name))
379 return (boolean) ((a->spfx & (SPFX_NOGEN | SPFX_RESTR)) != 0
380 || otmp->quan > 1L);
381 }
382
383 return FALSE;
384 }
385
386 static boolean
attacks(int adtyp,struct obj * otmp)387 attacks(int adtyp, struct obj *otmp)
388 {
389 register const struct artifact *weap;
390
391 if ((weap = get_artifact(otmp)) != 0)
392 return (boolean) (weap->attk.adtyp == adtyp);
393 return FALSE;
394 }
395
396 boolean
defends(int adtyp,struct obj * otmp)397 defends(int adtyp, struct obj *otmp)
398 {
399 register const struct artifact *weap;
400
401 if ((weap = get_artifact(otmp)) != 0)
402 return (boolean) (weap->defn.adtyp == adtyp);
403 return FALSE;
404 }
405
406 /* used for monsters */
407 boolean
defends_when_carried(int adtyp,struct obj * otmp)408 defends_when_carried(int adtyp, struct obj *otmp)
409 {
410 register const struct artifact *weap;
411
412 if ((weap = get_artifact(otmp)) != 0)
413 return (boolean) (weap->cary.adtyp == adtyp);
414 return FALSE;
415 }
416
417 /* determine whether an item confers Protection */
418 boolean
protects(struct obj * otmp,boolean being_worn)419 protects(struct obj *otmp, boolean being_worn)
420 {
421 const struct artifact *arti;
422
423 if (being_worn && objects[otmp->otyp].oc_oprop == PROTECTION)
424 return TRUE;
425 arti = get_artifact(otmp);
426 if (!arti)
427 return FALSE;
428 return (boolean) ((arti->cspfx & SPFX_PROTECT) != 0
429 || (being_worn && (arti->spfx & SPFX_PROTECT) != 0));
430 }
431
432 /*
433 * a potential artifact has just been worn/wielded/picked-up or
434 * unworn/unwielded/dropped. Pickup/drop only set/reset the W_ART mask.
435 */
436 void
set_artifact_intrinsic(struct obj * otmp,boolean on,long wp_mask)437 set_artifact_intrinsic(struct obj *otmp, boolean on, long wp_mask)
438 {
439 long *mask = 0;
440 register const struct artifact *art, *oart = get_artifact(otmp);
441 register struct obj *obj;
442 register uchar dtyp;
443 register long spfx;
444
445 if (!oart)
446 return;
447
448 /* effects from the defn field */
449 dtyp = (wp_mask != W_ART) ? oart->defn.adtyp : oart->cary.adtyp;
450
451 if (dtyp == AD_FIRE)
452 mask = &EFire_resistance;
453 else if (dtyp == AD_COLD)
454 mask = &ECold_resistance;
455 else if (dtyp == AD_ELEC)
456 mask = &EShock_resistance;
457 else if (dtyp == AD_MAGM)
458 mask = &EAntimagic;
459 else if (dtyp == AD_DISN)
460 mask = &EDisint_resistance;
461 else if (dtyp == AD_DRST)
462 mask = &EPoison_resistance;
463 else if (dtyp == AD_DRLI)
464 mask = &EDrain_resistance;
465
466 if (mask && wp_mask == W_ART && !on) {
467 /* find out if some other artifact also confers this intrinsic;
468 if so, leave the mask alone */
469 for (obj = g.invent; obj; obj = obj->nobj) {
470 if (obj != otmp && obj->oartifact) {
471 art = get_artifact(obj);
472 if (art && art->cary.adtyp == dtyp) {
473 mask = (long *) 0;
474 break;
475 }
476 }
477 }
478 }
479 if (mask) {
480 if (on)
481 *mask |= wp_mask;
482 else
483 *mask &= ~wp_mask;
484 }
485
486 /* intrinsics from the spfx field; there could be more than one */
487 spfx = (wp_mask != W_ART) ? oart->spfx : oart->cspfx;
488 if (spfx && wp_mask == W_ART && !on) {
489 /* don't change any spfx also conferred by other artifacts */
490 for (obj = g.invent; obj; obj = obj->nobj)
491 if (obj != otmp && obj->oartifact) {
492 art = get_artifact(obj);
493 if (art)
494 spfx &= ~art->cspfx;
495 }
496 }
497
498 if (spfx & SPFX_SEARCH) {
499 if (on)
500 ESearching |= wp_mask;
501 else
502 ESearching &= ~wp_mask;
503 }
504 if (spfx & SPFX_HALRES) {
505 /* make_hallucinated must (re)set the mask itself to get
506 * the display right */
507 /* restoring needed because this is the only artifact intrinsic
508 * that can print a message--need to guard against being printed
509 * when restoring a game
510 */
511 if (u.uroleplay.hallu && on) {
512 u.uroleplay.hallu = FALSE;
513 pline_The("world no longer makes any sense to you!");
514 }
515 (void) make_hallucinated((long) !on,
516 g.program_state.restoring ? FALSE : TRUE,
517 wp_mask);
518 }
519 if (spfx & SPFX_ESP) {
520 if (on)
521 ETelepat |= wp_mask;
522 else
523 ETelepat &= ~wp_mask;
524 see_monsters();
525 }
526 if (spfx & SPFX_STLTH) {
527 if (on)
528 EStealth |= wp_mask;
529 else
530 EStealth &= ~wp_mask;
531 }
532 if (spfx & SPFX_REGEN) {
533 if (on)
534 ERegeneration |= wp_mask;
535 else
536 ERegeneration &= ~wp_mask;
537 }
538 if (spfx & SPFX_TCTRL) {
539 if (on)
540 ETeleport_control |= wp_mask;
541 else
542 ETeleport_control &= ~wp_mask;
543 }
544 if (spfx & SPFX_WARN) {
545 if (spec_m2(otmp)) {
546 unsigned long type = spec_m2(otmp);
547 boolean is_mlet = !!(spfx & SPFX_DCLAS);
548 /* NOTE: the way warn_of_mon works for warning of monster letters is
549 * currently not particularly robust, and relies on the assumption
550 * that it is impossible to have warning against two different
551 * monster letters from two different artifacts at the same time.
552 * This currently works because the only artifacts that warn of a
553 * monster class (rather than an M2 flag, which should work fine for
554 * multiples) are weapons. */
555 if (on) {
556 EWarn_of_mon |= wp_mask;
557 if (is_mlet) {
558 g.context.warntype.obj_mlet = type;
559 }
560 else {
561 g.context.warntype.obj |= type;
562 }
563 } else {
564 EWarn_of_mon &= ~wp_mask;
565 if (is_mlet) {
566 g.context.warntype.obj_mlet = 0;
567 }
568 else {
569 g.context.warntype.obj &= ~type;
570 }
571 }
572 see_monsters();
573 } else {
574 if (on)
575 EWarning |= wp_mask;
576 else
577 EWarning &= ~wp_mask;
578 }
579 }
580 if (spfx & SPFX_EREGEN) {
581 if (on)
582 EEnergy_regeneration |= wp_mask;
583 else
584 EEnergy_regeneration &= ~wp_mask;
585 }
586 if (spfx & SPFX_HSPDAM) {
587 if (on)
588 EHalf_spell_damage |= wp_mask;
589 else
590 EHalf_spell_damage &= ~wp_mask;
591 }
592 if (spfx & SPFX_HPHDAM) {
593 if (on)
594 EHalf_physical_damage |= wp_mask;
595 else
596 EHalf_physical_damage &= ~wp_mask;
597 }
598 if (spfx & SPFX_XRAY) {
599 /* this assumes that no one else is using xray_range */
600 if (on)
601 u.xray_range = 3;
602 else
603 u.xray_range = -1;
604 g.vision_full_recalc = 1;
605 }
606 if ((spfx & SPFX_REFLECT) && (wp_mask & W_WEP)) {
607 if (on)
608 EReflecting |= wp_mask;
609 else
610 EReflecting &= ~wp_mask;
611 }
612 if (spfx & SPFX_PROTECT) {
613 if (on)
614 EProtection |= wp_mask;
615 else
616 EProtection &= ~wp_mask;
617 }
618
619 if (wp_mask == W_ART && !on && oart->inv_prop) {
620 /* might have to turn off invoked power too */
621 if (oart->inv_prop <= LAST_PROP
622 && (u.uprops[oart->inv_prop].extrinsic & W_ARTI))
623 (void) arti_invoke(otmp);
624 }
625 }
626
627 /* touch_artifact()'s return value isn't sufficient to tell whether it
628 dished out damage, and tracking changes to u.uhp, u.mh, Lifesaved
629 when trying to avoid second wounding is too cumbersome */
630 static boolean touch_blasted; /* for retouch_object() */
631
632 /*
633 * creature (usually hero) tries to touch (pick up or wield) an artifact obj.
634 * Returns 0 if the object refuses to be touched.
635 * This routine does not change any object chains.
636 * Ignores such things as gauntlets, assuming the artifact is not
637 * fooled by such trappings.
638 */
639 int
touch_artifact(struct obj * obj,struct monst * mon)640 touch_artifact(struct obj *obj, struct monst *mon)
641 {
642 register const struct artifact *oart = get_artifact(obj);
643 boolean badclass, badalign, self_willed, yours;
644
645 touch_blasted = FALSE;
646 if (!oart)
647 return 1;
648
649 yours = (mon == &g.youmonst);
650 /* all quest artifacts are self-willed; if this ever changes, `badclass'
651 will have to be extended to explicitly include quest artifacts */
652 self_willed = ((oart->spfx & SPFX_INTEL) != 0);
653 if (yours) {
654 u.uconduct.artitouch++;
655 badclass = self_willed
656 && ((oart->role != NON_PM && !Role_if(oart->role))
657 || (oart->race != NON_PM && !Race_if(oart->race)));
658 badalign = ((oart->spfx & SPFX_RESTR) != 0
659 && oart->alignment != A_NONE
660 && (oart->alignment != u.ualign.type
661 || u.ualign.record < 0));
662 } else if (!is_covetous(mon->data) && !is_mplayer(mon->data)) {
663 badclass = self_willed && oart->role != NON_PM
664 && oart != &artilist[ART_EXCALIBUR];
665 badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE
666 && (oart->alignment != mon_aligntyp(mon));
667 } else { /* an M3_WANTSxxx monster or a fake player */
668 /* special monsters trying to take the Amulet, invocation tools or
669 quest item can touch anything except `spec_applies' artifacts */
670 badclass = badalign = FALSE;
671 }
672 /* weapons which attack specific categories of monsters are
673 bad for them even if their alignments happen to match */
674 if (!badalign)
675 badalign = bane_applies(oart, mon);
676
677 if (((badclass || badalign) && self_willed)
678 || (badalign && (!yours || !rn2(4)))) {
679 int dmg;
680 char buf[BUFSZ];
681
682 if (!yours)
683 return 0;
684 You("are blasted by %s power!", s_suffix(the(xname(obj))));
685 touch_blasted = TRUE;
686 dmg = d((Antimagic ? 2 : 4), (self_willed ? 10 : 4));
687 /* add half of the usual material damage bonus */
688 if (Hate_material(obj->material)) {
689 dmg += (rnd(sear_damage(obj->material)) / 2) + 1;
690 }
691 Sprintf(buf, "touching %s", oart->name);
692 losehp(dmg, buf, KILLED_BY); /* magic damage, not physical */
693 exercise(A_WIS, FALSE);
694 }
695
696 /* can pick it up unless you're totally non-synch'd with the artifact */
697 if (badclass && badalign && self_willed) {
698 if (yours) {
699 if (!carried(obj))
700 pline("%s your grasp!", Tobjnam(obj, "evade"));
701 else
702 pline("%s beyond your control!", Tobjnam(obj, "are"));
703 }
704 return 0;
705 }
706
707 return 1;
708 }
709
710 /* decide whether an artifact itself is vulnerable to a particular type
711 of erosion damage, independent of the properties of its bearer */
712 boolean
arti_immune(struct obj * obj,int dtyp)713 arti_immune(struct obj *obj, int dtyp)
714 {
715 register const struct artifact *weap = get_artifact(obj);
716
717 if (!weap)
718 return FALSE;
719 if (dtyp == AD_PHYS)
720 return FALSE; /* nothing is immune to phys dmg */
721 return (boolean) (weap->attk.adtyp == dtyp
722 || weap->defn.adtyp == dtyp
723 || weap->cary.adtyp == dtyp);
724 }
725
726 static boolean
bane_applies(const struct artifact * oart,struct monst * mon)727 bane_applies(const struct artifact *oart, struct monst *mon)
728 {
729 struct artifact atmp;
730
731 if (oart && (oart->spfx & SPFX_DBONUS) != 0) {
732 atmp = *oart;
733 atmp.spfx &= SPFX_DBONUS; /* clear other spfx fields */
734 if (spec_applies(&atmp, mon))
735 return TRUE;
736 }
737 return FALSE;
738 }
739
740 /* decide whether an artifact's special attacks apply against mtmp */
741 static int
spec_applies(const struct artifact * weap,struct monst * mtmp)742 spec_applies(const struct artifact *weap, struct monst *mtmp)
743 {
744 struct permonst *ptr;
745 boolean yours;
746
747 if (!(weap->spfx & (SPFX_DBONUS | SPFX_ATTK)))
748 return (weap->attk.adtyp == AD_PHYS);
749
750 yours = (mtmp == &g.youmonst);
751 ptr = mtmp->data;
752
753 if (weap->spfx & SPFX_DMONS) {
754 return (ptr == &mons[(int) weap->mtype]);
755 } else if (weap->spfx & SPFX_DCLAS) {
756 return (weap->mtype == (unsigned long) ptr->mlet);
757 } else if (weap->spfx & SPFX_DFLAG1) {
758 return ((ptr->mflags1 & weap->mtype) != 0L);
759 } else if (weap->spfx & SPFX_DFLAG2) {
760 return ((ptr->mflags2 & weap->mtype)
761 || (yours
762 && ((!Upolyd && (g.urace.selfmask & weap->mtype))
763 || ((weap->mtype & M2_WERE) && u.ulycn >= LOW_PM))));
764 } else if (weap->spfx & SPFX_DALIGN) {
765 return yours ? (u.ualign.type != weap->alignment)
766 : (ptr->maligntyp == A_NONE
767 || sgn(ptr->maligntyp) != weap->alignment);
768 } else if (weap->spfx & SPFX_ATTK) {
769 struct obj *defending_weapon = (yours ? uwep : MON_WEP(mtmp));
770
771 if (defending_weapon && defending_weapon->oartifact
772 && defends((int) weap->attk.adtyp, defending_weapon))
773 return FALSE;
774 switch (weap->attk.adtyp) {
775 case AD_FIRE:
776 return !(yours ? Fire_resistance : resists_fire(mtmp));
777 case AD_COLD:
778 return !(yours ? Cold_resistance : resists_cold(mtmp));
779 case AD_ELEC:
780 return !(yours ? Shock_resistance : resists_elec(mtmp));
781 case AD_MAGM:
782 case AD_STUN:
783 return !(yours ? Antimagic : (rn2(100) < ptr->mr));
784 case AD_DRST:
785 return !(yours ? Poison_resistance : resists_poison(mtmp));
786 case AD_DRLI:
787 return !(yours ? Drain_resistance : resists_drli(mtmp));
788 case AD_STON:
789 return !(yours ? Stone_resistance : resists_ston(mtmp));
790 default:
791 impossible("Weird weapon special attack.");
792 }
793 }
794 return 0;
795 }
796
797 /* return the M2 flags of monster that an artifact's special attacks apply
798 * against */
799 long
spec_m2(struct obj * otmp)800 spec_m2(struct obj *otmp)
801 {
802 const struct artifact *artifact = get_artifact(otmp);
803
804 if (artifact)
805 return artifact->mtype;
806 return 0L;
807 }
808
809 /* special attack bonus */
810 int
spec_abon(struct obj * otmp,struct monst * mon)811 spec_abon(struct obj *otmp, struct monst *mon)
812 {
813 const struct artifact *weap = get_artifact(otmp);
814
815 /* no need for an extra check for `NO_ATTK' because this will
816 always return 0 for any artifact which has that attribute */
817
818 if (weap && weap->attk.damn && spec_applies(weap, mon))
819 return rnd((int) weap->attk.damn);
820 return 0;
821 }
822
823 /* special damage bonus */
824 int
spec_dbon(struct obj * otmp,struct monst * mon,int tmp)825 spec_dbon(struct obj *otmp, struct monst *mon, int tmp)
826 {
827 register const struct artifact *weap = get_artifact(otmp);
828
829 if (!weap || (weap->attk.adtyp == AD_PHYS /* check for `NO_ATTK' */
830 && weap->attk.damn == 0 && weap->attk.damd == 0))
831 g.spec_dbon_applies = FALSE;
832 else if (otmp->oartifact == ART_GRIMTOOTH)
833 /* Grimtooth has SPFX settings to warn against elves but we want its
834 damage bonus to apply to all targets, so bypass spec_applies() */
835 g.spec_dbon_applies = TRUE;
836 else
837 g.spec_dbon_applies = spec_applies(weap, mon);
838
839 if (g.spec_dbon_applies)
840 return weap->attk.damd ? rnd((int) weap->attk.damd) : max(tmp, 1);
841 return 0;
842 }
843
844 /* add identified artifact to discoveries list */
845 void
discover_artifact(xchar m)846 discover_artifact(xchar m)
847 {
848 int i;
849
850 /* look for this artifact in the discoveries list;
851 if we hit an empty slot then it's not present, so add it */
852 for (i = 0; i < NROFARTIFACTS; i++)
853 if (g.artidisco[i] == 0 || g.artidisco[i] == m) {
854 g.artidisco[i] = m;
855 return;
856 }
857 /* there is one slot per artifact, so we should never reach the
858 end without either finding the artifact or an empty slot... */
859 impossible("couldn't discover artifact (%d)", (int) m);
860 }
861
862 /* used to decide whether an artifact has been fully identified */
863 boolean
undiscovered_artifact(xchar m)864 undiscovered_artifact(xchar m)
865 {
866 int i;
867
868 /* look for this artifact in the discoveries list;
869 if we hit an empty slot then it's undiscovered */
870 for (i = 0; i < NROFARTIFACTS; i++)
871 if (g.artidisco[i] == m)
872 return FALSE;
873 else if (g.artidisco[i] == 0)
874 break;
875 return TRUE;
876 }
877
878 /* display a list of discovered artifacts; return their count */
879 int
disp_artifact_discoveries(winid tmpwin)880 disp_artifact_discoveries(winid tmpwin) /* supplied by dodiscover() */
881 {
882 int i, m, otyp;
883 char buf[BUFSZ];
884
885 for (i = 0; i < NROFARTIFACTS; i++) {
886 if (g.artidisco[i] == 0)
887 break; /* empty slot implies end of list */
888 if (tmpwin == WIN_ERR)
889 continue; /* for WIN_ERR, we just count */
890
891 if (i == 0)
892 putstr(tmpwin, iflags.menu_headings, "Artifacts");
893 m = g.artidisco[i];
894 otyp = artilist[m].otyp;
895 Sprintf(buf, " %s [%s %s]", artiname(m),
896 align_str(artilist[m].alignment), simple_typename(otyp));
897 putstr(tmpwin, 0, buf);
898 }
899 return i;
900 }
901
902 /*
903 * Magicbane's intrinsic magic is incompatible with normal
904 * enchantment magic. Thus, its effects have a negative
905 * dependence on spe. Against low mr victims, it typically
906 * does "double athame" damage, 2d4. Occasionally, it will
907 * cast unbalancing magic which effectively averages out to
908 * 4d4 damage (3d4 against high mr victims), for spe = 0.
909 *
910 * Prior to 3.4.1, the cancel (aka purge) effect always
911 * included the scare effect too; now it's one or the other.
912 * Likewise, the stun effect won't be combined with either
913 * of those two; it will be chosen separately or possibly
914 * used as a fallback when scare or cancel fails.
915 *
916 * [Historical note: a change to artifact_hit() for 3.4.0
917 * unintentionally made all of Magicbane's special effects
918 * be blocked if the defender successfully saved against a
919 * stun attack. As of 3.4.1, those effects can occur but
920 * will be slightly less likely than they were in 3.3.x.]
921 */
922
923 enum mb_effect_indices {
924 MB_INDEX_PROBE = 0,
925 MB_INDEX_STUN,
926 MB_INDEX_SCARE,
927 MB_INDEX_CANCEL,
928
929 NUM_MB_INDICES
930 };
931
932 #define MB_MAX_DIEROLL 8 /* rolls above this aren't magical */
933 static const char *const mb_verb[2][NUM_MB_INDICES] = {
934 { "probe", "stun", "scare", "cancel" },
935 { "prod", "amaze", "tickle", "purge" },
936 };
937
938 /* called when someone is being hit by Magicbane */
939 static boolean
Mb_hit(struct monst * magr,struct monst * mdef,struct obj * mb,int * dmgptr,int dieroll,boolean vis,char * hittee)940 Mb_hit(struct monst *magr, /* attacker */
941 struct monst *mdef, /* defender */
942 struct obj *mb, /* Magicbane */
943 int *dmgptr, /* extra damage target will suffer */
944 int dieroll, /* d20 that has already scored a hit */
945 boolean vis, /* whether the action can be seen */
946 char *hittee) /* target's name: "you" or mon_nam(mdef) */
947 {
948 struct permonst *old_uasmon;
949 const char *verb;
950 boolean youattack = (magr == &g.youmonst), youdefend = (mdef == &g.youmonst),
951 resisted = FALSE, do_stun, do_confuse, result;
952 int attack_indx, fakeidx, scare_dieroll = MB_MAX_DIEROLL / 2;
953
954 result = FALSE; /* no message given yet */
955 /* the most severe effects are less likely at higher enchantment */
956 if (mb->spe >= 3)
957 scare_dieroll /= (1 << (mb->spe / 3));
958 /* if target successfully resisted the artifact damage bonus,
959 reduce overall likelihood of the assorted special effects */
960 if (!g.spec_dbon_applies)
961 dieroll += 1;
962
963 /* might stun even when attempting a more severe effect, but
964 in that case it will only happen if the other effect fails;
965 extra damage will apply regardless; 3.4.1: sometimes might
966 just probe even when it hasn't been enchanted */
967 do_stun = (max(mb->spe, 0) < rn2(g.spec_dbon_applies ? 11 : 7));
968
969 /* the special effects also boost physical damage; increments are
970 generally cumulative, but since the stun effect is based on a
971 different criterium its damage might not be included; the base
972 damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending
973 on target's resistance check against AD_STUN (handled by caller)
974 [note that a successful save against AD_STUN doesn't actually
975 prevent the target from ending up stunned] */
976 attack_indx = MB_INDEX_PROBE;
977 *dmgptr += rnd(4); /* (2..3)d4 */
978 if (do_stun) {
979 attack_indx = MB_INDEX_STUN;
980 *dmgptr += rnd(4); /* (3..4)d4 */
981 }
982 if (dieroll <= scare_dieroll) {
983 attack_indx = MB_INDEX_SCARE;
984 *dmgptr += rnd(4); /* (3..5)d4 */
985 }
986 if (dieroll <= (scare_dieroll / 2)) {
987 attack_indx = MB_INDEX_CANCEL;
988 *dmgptr += rnd(4); /* (4..6)d4 */
989 }
990
991 /* give the hit message prior to inflicting the effects */
992 verb = mb_verb[!!Hallucination][attack_indx];
993 if (youattack || youdefend || vis) {
994 result = TRUE;
995 pline_The("magic-absorbing blade %s %s!",
996 vtense((const char *) 0, verb), hittee);
997 /* assume probing has some sort of noticeable feedback
998 even if it is being done by one monster to another */
999 if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef))
1000 map_invisible(mdef->mx, mdef->my);
1001 }
1002
1003 /* now perform special effects */
1004 switch (attack_indx) {
1005 case MB_INDEX_CANCEL:
1006 old_uasmon = g.youmonst.data;
1007 /* No mdef->mcan check: even a cancelled monster can be polymorphed
1008 * into a golem, and the "cancel" effect acts as if some magical
1009 * energy remains in spellcasting defenders to be absorbed later.
1010 */
1011 if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) {
1012 resisted = TRUE;
1013 } else {
1014 do_stun = FALSE;
1015 if (youdefend) {
1016 if (g.youmonst.data != old_uasmon)
1017 *dmgptr = 0; /* rehumanized, so no more damage */
1018 if (u.uenmax > 0) {
1019 u.uenmax--;
1020 if (u.uen > 0)
1021 u.uen--;
1022 g.context.botl = TRUE;
1023 You("lose magical energy!");
1024 }
1025 } else {
1026 if (mdef->data == &mons[PM_CLAY_GOLEM])
1027 mdef->mhp = 1; /* cancelled clay golems will die */
1028 if (youattack && attacktype(mdef->data, AT_MAGC)) {
1029 u.uenmax++;
1030 u.uen++;
1031 g.context.botl = TRUE;
1032 You("absorb magical energy!");
1033 }
1034 }
1035 }
1036 break;
1037
1038 case MB_INDEX_SCARE:
1039 if (youdefend) {
1040 if (Antimagic) {
1041 resisted = TRUE;
1042 } else {
1043 nomul(-3);
1044 g.multi_reason = "being scared stiff";
1045 g.nomovemsg = "";
1046 if (magr && magr == u.ustuck && sticks(g.youmonst.data)) {
1047 set_ustuck((struct monst *) 0);
1048 You("release %s!", mon_nam(magr));
1049 }
1050 }
1051 } else {
1052 if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL))
1053 resisted = TRUE;
1054 else
1055 monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr));
1056 }
1057 if (!resisted)
1058 do_stun = FALSE;
1059 break;
1060
1061 case MB_INDEX_STUN:
1062 do_stun = TRUE; /* (this is redundant...) */
1063 break;
1064
1065 case MB_INDEX_PROBE:
1066 if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) {
1067 pline_The("%s is insightful.", verb);
1068 /* pre-damage status */
1069 probe_monster(mdef);
1070 }
1071 break;
1072 }
1073 /* stun if that was selected and a worse effect didn't occur */
1074 if (do_stun) {
1075 if (youdefend)
1076 make_stunned(((HStun & TIMEOUT) + 3L), FALSE);
1077 else
1078 mdef->mstun = 1;
1079 /* avoid extra stun message below if we used mb_verb["stun"] above */
1080 if (attack_indx == MB_INDEX_STUN)
1081 do_stun = FALSE;
1082 }
1083 /* lastly, all this magic can be confusing... */
1084 do_confuse = !rn2(12);
1085 if (do_confuse) {
1086 if (youdefend)
1087 make_confused((HConfusion & TIMEOUT) + 4L, FALSE);
1088 else
1089 mdef->mconf = 1;
1090 }
1091
1092 /* now give message(s) describing side-effects; Use fakename
1093 so vtense() won't be fooled by assigned name ending in 's' */
1094 fakeidx = youdefend ? 1 : 0;
1095 if (youattack || youdefend || vis) {
1096 (void) upstart(hittee); /* capitalize */
1097 if (resisted) {
1098 pline("%s %s!", hittee, vtense(fakename[fakeidx], "resist"));
1099 shieldeff(youdefend ? u.ux : mdef->mx,
1100 youdefend ? u.uy : mdef->my);
1101 }
1102 if ((do_stun || do_confuse) && flags.verbose) {
1103 char buf[BUFSZ];
1104
1105 buf[0] = '\0';
1106 if (do_stun)
1107 Strcat(buf, "stunned");
1108 if (do_stun && do_confuse)
1109 Strcat(buf, " and ");
1110 if (do_confuse)
1111 Strcat(buf, "confused");
1112 pline("%s %s %s%c", hittee, vtense(fakename[fakeidx], "are"), buf,
1113 (do_stun && do_confuse) ? '!' : '.');
1114 }
1115 }
1116
1117 return result;
1118 }
1119
1120 /* Function used when someone attacks someone else with an artifact
1121 * weapon. Only adds the special (artifact) damage, and returns a bitmask of
1122 * the ARTIFACTHIT flags defined in hack.h indicating what messages it
1123 * printed, so that the caller can avoid printing messages as needed.
1124 * This should be called once upon every artifact attack; dmgval() no longer
1125 * takes artifact bonuses into account. Possible extension: change the killer
1126 * so that when an orc kills you with Stormbringer it's "killed by Stormbringer"
1127 * instead of "killed by an orc".
1128 */
1129 int
artifact_hit(struct monst * magr,struct monst * mdef,struct obj * otmp,int * dmgptr,int dieroll)1130 artifact_hit(struct monst *magr, struct monst *mdef, struct obj *otmp,
1131 int *dmgptr,
1132 int dieroll) /* needed for Magicbane and vorpal blades */
1133 {
1134 boolean youattack = (magr == &g.youmonst);
1135 boolean youdefend = (mdef == &g.youmonst);
1136 boolean vis = (!youattack && magr && cansee(magr->mx, magr->my))
1137 || (!youdefend && cansee(mdef->mx, mdef->my))
1138 || (youattack && u.uswallow && mdef == u.ustuck && !Blind);
1139 int retval = ARTIFACTHIT_NOMSG;
1140 boolean realizes_damage;
1141 const char *wepdesc;
1142 static const char you[] = "you";
1143 char hittee[BUFSZ];
1144
1145 Strcpy(hittee, youdefend ? you : mon_nam(mdef));
1146
1147 /* The following takes care of most of the damage, but not all--
1148 * the exception being for level draining, which is specially
1149 * handled. Messages are done in this function, however.
1150 */
1151 *dmgptr += spec_dbon(otmp, mdef, *dmgptr);
1152
1153 if (youattack && youdefend) {
1154 impossible("attacking yourself with weapon?");
1155 return ARTIFACTHIT_NOMSG;
1156 }
1157
1158 realizes_damage = (youdefend || vis
1159 /* feel the effect even if not seen */
1160 || (youattack && mdef == u.ustuck));
1161
1162 /* the four basic attacks: fire, cold, shock and missiles */
1163 if (attacks(AD_FIRE, otmp)) {
1164 if (realizes_damage) {
1165 pline_The("fiery blade %s %s%c",
1166 !g.spec_dbon_applies
1167 ? "hits"
1168 : (mdef->data == &mons[PM_WATER_ELEMENTAL]
1169 || mdef->data == &mons[PM_ICE_VORTEX])
1170 ? "vaporizes part of"
1171 : "burns",
1172 hittee, !g.spec_dbon_applies ? '.' : '!');
1173 retval |= ARTIFACTHIT_GAVEMSG;
1174 if (completelyburns(mdef->data) || is_wooden(mdef->data)
1175 || mdef->data == &mons[PM_GREEN_SLIME]) {
1176 if (youdefend) {
1177 You("ignite and turn to ash!");
1178 losehp((Upolyd ? u.mh : u.uhp) + 1, "immolation",
1179 NO_KILLER_PREFIX);
1180 }
1181 else {
1182 pline("%s ignites and turns to ash!", Monnam(mdef));
1183 *dmgptr = mdef->mhp + FATAL_DAMAGE_MODIFIER;
1184 mdef->golem_destroyed = 1;
1185 }
1186 retval |= ARTIFACTHIT_INSTAKILLMSG;
1187 }
1188 }
1189 if (!rn2(4)) {
1190 int itemdmg = destroy_items(mdef, AD_FIRE, *dmgptr);
1191 if (!youdefend)
1192 /* kludge for destroy_items only dealing damage if it's the
1193 * player */
1194 *dmgptr += itemdmg;
1195 ignite_items(mdef->minvent);
1196 }
1197 if (youdefend && Slimed)
1198 burn_away_slime();
1199 return retval;
1200 }
1201 if (attacks(AD_COLD, otmp)) {
1202 if (realizes_damage) {
1203 pline_The("ice-cold blade %s %s%c",
1204 !g.spec_dbon_applies ? "hits" : "freezes", hittee,
1205 !g.spec_dbon_applies ? '.' : '!');
1206 retval |= ARTIFACTHIT_GAVEMSG;
1207 }
1208 if (!rn2(4)) {
1209 int itemdmg = destroy_items(mdef, AD_COLD, *dmgptr);
1210 if (!youdefend)
1211 *dmgptr += itemdmg; /* same kludge as above */
1212 }
1213 return retval;
1214 }
1215 if (attacks(AD_ELEC, otmp)) {
1216 if (realizes_damage) {
1217 pline_The("massive hammer hits%s %s%c",
1218 !g.spec_dbon_applies ? "" : "! Lightning strikes",
1219 hittee, !g.spec_dbon_applies ? '.' : '!');
1220 retval |= ARTIFACTHIT_GAVEMSG;
1221 }
1222 if (g.spec_dbon_applies)
1223 wake_nearto(mdef->mx, mdef->my, 4 * 4);
1224 if (!rn2(5)) {
1225 int itemdmg = destroy_items(mdef, AD_ELEC, *dmgptr);
1226 if (!youdefend)
1227 *dmgptr += itemdmg;
1228 }
1229 wake_nearto(mdef->mx, mdef->my, 6 * 6); /* thunder */
1230 return retval;
1231 }
1232 if (attacks(AD_MAGM, otmp)) {
1233 if (realizes_damage) {
1234 pline_The("imaginary widget hits%s %s%c",
1235 !g.spec_dbon_applies
1236 ? ""
1237 : "! A hail of magic missiles strikes",
1238 hittee, !g.spec_dbon_applies ? '.' : '!');
1239 retval |= ARTIFACTHIT_GAVEMSG;
1240 }
1241 return retval;
1242 }
1243
1244 if (attacks(AD_STUN, otmp) && dieroll <= MB_MAX_DIEROLL) {
1245 /* Magicbane's special attacks (possibly modifies hittee[]) */
1246 if (Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee)) {
1247 return ARTIFACTHIT_GAVEMSG;
1248 }
1249 else {
1250 return ARTIFACTHIT_NOMSG;
1251 }
1252 }
1253
1254 /* poison damage is a 1/4 chance; use dieroll to make sure the message syncs
1255 * up with the poison effects */
1256 if (permapoisoned(otmp) && realizes_damage && dieroll <= 5
1257 && !(youdefend ? Poison_resistance : resists_poison(mdef))) {
1258 pline_The("jagged blade poisons %s!", hittee);
1259 return ARTIFACTHIT_GAVEMSG;
1260 }
1261
1262 if (!g.spec_dbon_applies) {
1263 /* since damage bonus didn't apply, nothing more to do;
1264 no further attacks have side-effects on inventory */
1265 return ARTIFACTHIT_NOMSG;
1266 }
1267
1268 /* We really want "on a natural 20" but Nethack does it in */
1269 /* reverse from AD&D. */
1270 if (spec_ability(otmp, SPFX_BEHEAD)) {
1271 if (otmp->oartifact == ART_TSURUGI_OF_MURAMASA && dieroll == 1) {
1272 wepdesc = "The razor-sharp blade";
1273 /* not really beheading, but so close, why add another SPFX */
1274 if (youattack && u.uswallow && mdef == u.ustuck) {
1275 You("slice %s wide open!", mon_nam(mdef));
1276 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1277 return ARTIFACTHIT_INSTAKILLMSG | ARTIFACTHIT_GAVEMSG;
1278 }
1279 if (!youdefend) {
1280 /* allow normal cutworm() call to add extra damage */
1281 if (g.notonhead)
1282 return ARTIFACTHIT_NOMSG;
1283
1284 if (bigmonst(mdef->data)) {
1285 if (youattack)
1286 You("slice deeply into %s!", mon_nam(mdef));
1287 else if (vis)
1288 pline("%s cuts deeply into %s!", Monnam(magr),
1289 hittee);
1290 *dmgptr *= 2;
1291 return ARTIFACTHIT_GAVEMSG;
1292 }
1293 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1294 pline("%s cuts %s in half!", wepdesc, mon_nam(mdef));
1295 otmp->dknown = TRUE;
1296 return ARTIFACTHIT_INSTAKILLMSG | ARTIFACTHIT_GAVEMSG;
1297 } else {
1298 if (bigmonst(g.youmonst.data)) {
1299 pline("%s cuts deeply into you!",
1300 magr ? Monnam(magr) : wepdesc);
1301 *dmgptr *= 2;
1302 return ARTIFACTHIT_GAVEMSG;
1303 }
1304
1305 /* Players with negative AC's take less damage instead
1306 * of just not getting hit. We must add a large enough
1307 * value to the damage so that this reduction in
1308 * damage does not prevent death.
1309 */
1310 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER;
1311 pline("%s cuts you in half!", wepdesc);
1312 otmp->dknown = TRUE;
1313 return ARTIFACTHIT_INSTAKILLMSG | ARTIFACTHIT_GAVEMSG;
1314 }
1315 } else if (otmp->oartifact == ART_VORPAL_BLADE
1316 && (dieroll == 1 || mdef->data == &mons[PM_JABBERWOCK])) {
1317 static const char *const behead_msg[2] = { "%s beheads %s!",
1318 "%s decapitates %s!" };
1319
1320 if (youattack && u.uswallow && mdef == u.ustuck)
1321 return ARTIFACTHIT_NOMSG;
1322 wepdesc = artilist[ART_VORPAL_BLADE].name;
1323 if (!youdefend) {
1324 if (!has_head(mdef->data) || g.notonhead || u.uswallow) {
1325 if (youattack) {
1326 pline("Somehow, you miss %s wildly.", mon_nam(mdef));
1327 retval |= ARTIFACTHIT_GAVEMSG;
1328 }
1329 else if (vis) {
1330 pline("Somehow, %s misses wildly.", mon_nam(magr));
1331 retval |= ARTIFACTHIT_GAVEMSG;
1332 }
1333 *dmgptr = 0;
1334 return retval;
1335 }
1336 if (noncorporeal(mdef->data) || amorphous(mdef->data)) {
1337 pline("%s slices through %s %s.", wepdesc,
1338 s_suffix(mon_nam(mdef)), mbodypart(mdef, NECK));
1339 return ARTIFACTHIT_GAVEMSG;
1340 }
1341 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1342 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc,
1343 mon_nam(mdef));
1344 if (Hallucination && !flags.female)
1345 pline("Good job Henry, but that wasn't Anne.");
1346 if (is_reviver(mdef->data) && !is_rider(mdef->data)
1347 && (!mlifesaver(mdef)
1348 || faulty_lifesaver(mlifesaver(mdef)))) {
1349 /* kind of hard to revive if you've lost your head...
1350 * if they'll be lifesaved, however, we shouldn't cancel
1351 * them, because we assume that'll fix them. */
1352 mdef->mcan = 1;
1353 }
1354 otmp->dknown = TRUE;
1355 return ARTIFACTHIT_INSTAKILLMSG | ARTIFACTHIT_GAVEMSG;
1356 } else {
1357 if (!has_head(g.youmonst.data)) {
1358 pline("Somehow, %s misses you wildly.",
1359 magr ? mon_nam(magr) : wepdesc);
1360 *dmgptr = 0;
1361 return ARTIFACTHIT_GAVEMSG;
1362 }
1363 if (noncorporeal(g.youmonst.data)
1364 || amorphous(g.youmonst.data)) {
1365 pline("%s slices through your %s.", wepdesc,
1366 body_part(NECK));
1367 return ARTIFACTHIT_GAVEMSG;
1368 }
1369 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER;
1370 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "you");
1371 otmp->dknown = TRUE;
1372 /* Should amulets fall off? */
1373 return ARTIFACTHIT_INSTAKILLMSG | ARTIFACTHIT_GAVEMSG;
1374 }
1375 }
1376 }
1377 if (spec_ability(otmp, SPFX_HEAVYHIT)) {
1378 if (otmp->oartifact == ART_OGRESMASHER && dieroll == 1) {
1379 boolean smallmonst = (mdef->data->msize <= MZ_SMALL);
1380 wepdesc = artilist[ART_OGRESMASHER].name;
1381
1382 if (youdefend) {
1383 otmp->dknown = TRUE;
1384 if (smallmonst) {
1385 pline("%s crushes you!", wepdesc);
1386 *dmgptr = 2 * (Upolyd ? u.mh : u.uhp)
1387 + FATAL_DAMAGE_MODIFIER;
1388 return ARTIFACTHIT_INSTAKILLMSG | ARTIFACTHIT_GAVEMSG;
1389 }
1390 else {
1391 pline("%s smashes into you!", wepdesc);
1392 /* No extra damage, but kill speed and inflict status
1393 * ailments. */
1394 if (HFast)
1395 u_slow_down(); /* avoid multiple "You slow down" */
1396 make_stunned((HStun & TIMEOUT) + (long) rn1(5, 5), TRUE);
1397 return ARTIFACTHIT_GAVEMSG;
1398 }
1399 }
1400 else {
1401 if (smallmonst) {
1402 if (vis) {
1403 pline("%s crushes %s!", wepdesc, mon_nam(mdef));
1404 otmp->dknown = TRUE;
1405 retval |= ARTIFACTHIT_INSTAKILLMSG | ARTIFACTHIT_GAVEMSG;
1406 }
1407 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1408 }
1409 else {
1410 if (vis) {
1411 if (youattack)
1412 You("smash %s into %s!", wepdesc, mon_nam(mdef));
1413 else
1414 pline("%s smashes %s into %s!", Monnam(magr),
1415 wepdesc, mon_nam(mdef));
1416 otmp->dknown = TRUE;
1417 retval |= ARTIFACTHIT_GAVEMSG;
1418 }
1419 mon_adjust_speed(mdef, -2, NULL);
1420 mdef->mstun = 1;
1421 }
1422 return retval;
1423 }
1424 }
1425 }
1426 if (spec_ability(otmp, SPFX_DRLI)) {
1427 /* some non-living creatures (golems, vortices) are vulnerable to
1428 life drain effects so can get "<Arti> draws the <life>" feedback */
1429 const char *life = nonliving(mdef->data) ? "animating force" : "life";
1430 if (item_catches_drain(mdef)) {
1431 /* This has to go here rather than along with the resists_drli
1432 * check; otherwise a drainable item gets drained even if the
1433 * attack is a miss.
1434 * Return NOMSG because even though item_catches_drain would have
1435 * printed something, artifact_hit didn't. */
1436 return ARTIFACTHIT_NOMSG;
1437 }
1438
1439 if (!youdefend) {
1440 int m_lev = (int) mdef->m_lev, /* will be 0 for 1d4 mon */
1441 mhpmax = mdef->mhpmax,
1442 drain = monhp_per_lvl(mdef); /* usually 1d8 */
1443 /* note: DRLI attack uses 2d6, attacker doesn't get healed */
1444
1445 /* stop draining HP if it drops too low (still drains level;
1446 also caller still inflicts regular weapon damage) */
1447 if (mhpmax - drain <= m_lev)
1448 drain = (mhpmax > m_lev) ? (mhpmax - (m_lev + 1)) : 0;
1449
1450 if (vis) {
1451 if (otmp->oartifact == ART_STORMBRINGER)
1452 pline_The("%s blade draws the %s from %s!",
1453 hcolor(NH_BLACK), life, mon_nam(mdef));
1454 else
1455 pline("%s draws the %s from %s!",
1456 The(distant_name(otmp, xname)), life,
1457 mon_nam(mdef));
1458 retval |= ARTIFACTHIT_GAVEMSG;
1459 }
1460 if (mdef->m_lev == 0) {
1461 /* losing a level when at 0 is fatal */
1462 *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
1463 } else {
1464 *dmgptr += drain;
1465 mdef->mhpmax -= drain;
1466 mdef->m_lev--;
1467 }
1468
1469 if (drain > 0) {
1470 /* drain: was target's damage, now heal attacker by half */
1471 drain = (drain + 1) / 2; /* drain/2 rounded up */
1472 if (youattack) {
1473 healup(drain, 0, FALSE, FALSE);
1474 } else {
1475 magr->mhp += drain;
1476 if (magr->mhp > magr->mhpmax)
1477 magr->mhp = magr->mhpmax;
1478 }
1479 }
1480 return retval;
1481 } else { /* youdefend */
1482 int oldhpmax = u.uhpmax;
1483
1484 if (Blind)
1485 You_feel("an %s drain your %s!",
1486 (otmp->oartifact == ART_STORMBRINGER)
1487 ? "unholy blade"
1488 : "object",
1489 life);
1490 else if (otmp->oartifact == ART_STORMBRINGER)
1491 pline_The("%s blade drains your %s!", hcolor(NH_BLACK), life);
1492 else
1493 pline("%s drains your %s!", The(distant_name(otmp, xname)),
1494 life);
1495 losexp("life drainage");
1496 if (magr && magr->mhp < magr->mhpmax) {
1497 magr->mhp += (oldhpmax - u.uhpmax + 1) / 2;
1498 if (magr->mhp > magr->mhpmax)
1499 magr->mhp = magr->mhpmax;
1500 }
1501 return ARTIFACTHIT_GAVEMSG;
1502 }
1503 }
1504 return ARTIFACTHIT_NOMSG;
1505 }
1506
1507 /* getobj callback for object to be invoked */
1508 static int
invoke_ok(struct obj * obj)1509 invoke_ok(struct obj *obj)
1510 {
1511 if (!obj)
1512 return GETOBJ_EXCLUDE;
1513
1514 /* artifacts and other special items */
1515 if (obj->oartifact || objects[obj->otyp].oc_unique
1516 || (obj->otyp == FAKE_AMULET_OF_YENDOR && !obj->known))
1517 return GETOBJ_SUGGEST;
1518
1519 /* synonym for apply, though actually invoking it will do different things
1520 * depending if it's a regular crystal ball, an artifact one that has an
1521 * invoke power, and a (theoretical) artifact one that doesn't have an
1522 * invoke power */
1523 if (obj->otyp == CRYSTAL_BALL)
1524 return GETOBJ_SUGGEST;
1525
1526 return GETOBJ_EXCLUDE;
1527 }
1528
1529 /* the #invoke command */
1530 int
doinvoke(void)1531 doinvoke(void)
1532 {
1533 struct obj *obj;
1534
1535 obj = getobj("invoke", invoke_ok, GETOBJ_PROMPT);
1536 if (!obj)
1537 return 0;
1538 if (!retouch_object(&obj, FALSE, FALSE))
1539 return 1;
1540 return arti_invoke(obj);
1541 }
1542
1543 static int
arti_invoke(struct obj * obj)1544 arti_invoke(struct obj *obj)
1545 {
1546 register const struct artifact *oart = get_artifact(obj);
1547 if (!obj) {
1548 impossible("arti_invoke without obj");
1549 return 0;
1550 }
1551 if (!oart || !oart->inv_prop) {
1552 if (obj->otyp == CRYSTAL_BALL)
1553 use_crystal_ball(&obj);
1554 else
1555 pline1(nothing_happens);
1556 return 1;
1557 }
1558
1559 if (oart->inv_prop > LAST_PROP) {
1560 /* It's a special power, not "just" a property */
1561 if (obj->age > g.monstermoves) {
1562 /* the artifact is tired :-) */
1563 You_feel("that %s %s ignoring you.", the(xname(obj)),
1564 otense(obj, "are"));
1565 if (!(wizard && yn("Override?") == 'y')) {
1566 /* and just got more so; patience is essential... */
1567 obj->age += (long) d(3, 10);
1568 return 1;
1569 }
1570 }
1571 obj->age = g.monstermoves + rnz(100);
1572
1573 switch (oart->inv_prop) {
1574 case TAMING: {
1575 struct obj pseudo;
1576
1577 pseudo =
1578 cg.zeroobj; /* neither cursed nor blessed, zero oextra too */
1579 pseudo.otyp = SCR_TAMING;
1580 (void) seffects(&pseudo);
1581 break;
1582 }
1583 case HEALING: {
1584 int healamt = (u.uhpmax + 1 - u.uhp) / 2;
1585 long creamed = (long) u.ucreamed;
1586
1587 if (Upolyd)
1588 healamt = (u.mhmax + 1 - u.mh) / 2;
1589 if (healamt || Sick || Slimed || Blinded > creamed)
1590 You_feel("better.");
1591 else
1592 goto nothing_special;
1593 if (healamt > 0) {
1594 if (Upolyd)
1595 u.mh += healamt;
1596 else
1597 u.uhp += healamt;
1598 }
1599 if (Sick)
1600 make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1601 if (Slimed)
1602 make_slimed(0L, (char *) 0);
1603 if (Blinded > creamed)
1604 make_blinded(creamed, FALSE);
1605 g.context.botl = TRUE;
1606 break;
1607 }
1608 case ENERGY_BOOST: {
1609 int epboost = (u.uenmax + 1 - u.uen) / 2;
1610
1611 if (epboost > 120)
1612 epboost = 120; /* arbitrary */
1613 else if (epboost < 12)
1614 epboost = u.uenmax - u.uen;
1615 if (epboost) {
1616 u.uen += epboost;
1617 g.context.botl = TRUE;
1618 You_feel("re-energized.");
1619 } else
1620 goto nothing_special;
1621 break;
1622 }
1623 case UNTRAP: {
1624 if (!untrap(TRUE)) {
1625 obj->age = 0; /* don't charge for changing their mind */
1626 return 0;
1627 }
1628 break;
1629 }
1630 case CHARGE_OBJ: {
1631 struct obj *otmp = getobj("charge", charge_ok,
1632 GETOBJ_PROMPT | GETOBJ_ALLOWCNT);
1633 boolean b_effect;
1634
1635 if (!otmp) {
1636 obj->age = 0;
1637 return 0;
1638 }
1639 b_effect = (obj->blessed && (oart->role == Role_switch
1640 || oart->role == NON_PM));
1641 recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0);
1642 update_inventory();
1643 break;
1644 }
1645 case LEV_TELE:
1646 level_tele();
1647 break;
1648 case CREATE_PORTAL: {
1649 int i, num_ok_dungeons, last_ok_dungeon = 0;
1650 d_level newlev;
1651 winid tmpwin = create_nhwindow(NHW_MENU);
1652 anything any;
1653
1654 any = cg.zeroany; /* set all bits to zero */
1655 start_menu(tmpwin, MENU_BEHAVE_STANDARD);
1656 /* use index+1 (cant use 0) as identifier */
1657 for (i = num_ok_dungeons = 0; i < g.n_dgns; i++) {
1658 if (!g.dungeons[i].dunlev_ureached)
1659 continue;
1660 any.a_int = i + 1;
1661 add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0,
1662 ATR_NONE, g.dungeons[i].dname, MENU_ITEMFLAGS_NONE);
1663 num_ok_dungeons++;
1664 last_ok_dungeon = i;
1665 }
1666 end_menu(tmpwin, "Open a portal to which dungeon?");
1667 if (num_ok_dungeons > 1) {
1668 /* more than one entry; display menu for choices */
1669 menu_item *selected;
1670 int n;
1671
1672 n = select_menu(tmpwin, PICK_ONE, &selected);
1673 if (n <= 0) {
1674 destroy_nhwindow(tmpwin);
1675 goto nothing_special;
1676 }
1677 i = selected[0].item.a_int - 1;
1678 free((genericptr_t) selected);
1679 } else
1680 i = last_ok_dungeon; /* also first & only OK dungeon */
1681 destroy_nhwindow(tmpwin);
1682
1683 /*
1684 * i is now index into dungeon structure for the new dungeon.
1685 * Find the closest level in the given dungeon, open
1686 * a use-once portal to that dungeon and go there.
1687 * The closest level is either the entry or dunlev_ureached.
1688 */
1689 newlev.dnum = i;
1690 if (g.dungeons[i].depth_start >= depth(&u.uz))
1691 newlev.dlevel = g.dungeons[i].entry_lev;
1692 else
1693 newlev.dlevel = g.dungeons[i].dunlev_ureached;
1694
1695 if (u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev)
1696 || newlev.dnum == u.uz.dnum || !next_to_u()) {
1697 You_feel("very disoriented for a moment.");
1698 } else {
1699 if (!Blind)
1700 You("are surrounded by a shimmering sphere!");
1701 else
1702 You_feel("weightless for a moment.");
1703 goto_level(&newlev, FALSE, FALSE, FALSE);
1704 }
1705 break;
1706 }
1707 case ENLIGHTENING:
1708 enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS);
1709 break;
1710 case CREATE_AMMO: {
1711 struct obj *otmp = mksobj(ARROW, TRUE, FALSE);
1712
1713 if (!otmp)
1714 goto nothing_special;
1715 otmp->blessed = obj->blessed;
1716 otmp->cursed = obj->cursed;
1717 otmp->bknown = obj->bknown;
1718 if (obj->blessed) {
1719 if (otmp->spe < 0)
1720 otmp->spe = 0;
1721 otmp->quan += rnd(10);
1722 } else if (obj->cursed) {
1723 if (otmp->spe > 0)
1724 otmp->spe = 0;
1725 } else
1726 otmp->quan += rnd(5);
1727 otmp->owt = weight(otmp);
1728 otmp = hold_another_object(otmp, "Suddenly %s out.",
1729 aobjnam(otmp, "fall"), (char *) 0);
1730 nhUse(otmp);
1731 break;
1732 }
1733 case LIGHTNING_BOLT: {
1734 struct obj* pseudo = mksobj(WAN_LIGHTNING, FALSE, FALSE);
1735 pseudo->blessed = pseudo->cursed = 0;
1736 /* type is a "spell of lightning bolt" which doesn't actually
1737 * exist: 10 + AD_ELEC - 1 */
1738 if(!getdir(NULL) || (!u.dx && !u.dy && !u.dz)) {
1739 int damage = zapyourself(pseudo, TRUE);
1740 if (damage > 0) {
1741 losehp(damage, "struck by lightning", NO_KILLER_PREFIX);
1742 }
1743 }
1744 else {
1745 /* don't use weffects - we want higher damage than that */
1746 buzz(9 + AD_ELEC, 8, u.ux, u.uy, u.dx, u.dy);
1747 }
1748 obfree(pseudo, NULL);
1749 break;
1750 }
1751 case SMOKE_CLOUD: {
1752 /* Itlachiayaque actually has two invoke effects - you can also gaze
1753 * into it like a crystal ball and look for a certain symbol. The
1754 * hero decides which effect. */
1755 int ret, n;
1756 char c;
1757 winid tmpwin = create_nhwindow(NHW_MENU);
1758 anything any = cg.zeroany;
1759 menu_item *selected;
1760
1761 start_menu(tmpwin, MENU_BEHAVE_STANDARD);
1762 any.a_char = 'a';
1763 add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
1764 "Create a stinking cloud", MENU_ITEMFLAGS_NONE);
1765 any.a_char = 'b';
1766 add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
1767 "Gaze into the surface", MENU_ITEMFLAGS_NONE);
1768 end_menu(tmpwin, "What would you like to do?");
1769 n = select_menu(tmpwin, PICK_ONE, &selected);
1770 destroy_nhwindow(tmpwin);
1771
1772 if (n < 0) {
1773 obj->age = 0;
1774 break;
1775 }
1776 c = selected[0].item.a_char;
1777 if (c == 'a') {
1778 if (!any_quest_artifact(obj) || is_quest_artifact(obj)) {
1779 You("may summon a stinking cloud.");
1780 }
1781 ret = do_stinking_cloud(obj, FALSE);
1782 if (ret == SCLOUD_CANCELED) {
1783 obj->age = 0;
1784 }
1785 }
1786 else {
1787 You("gaze into the polished surface...");
1788 g.context.crystal.ball = obj;
1789 g.context.crystal.o_id = obj->o_id;
1790 g.context.crystal.looktime = rn1(5, 6); /* same as ball */
1791 set_occupation(look_in_crystal_ball, "gazing", 0);
1792 }
1793 break;
1794 }
1795 }
1796 } else {
1797 long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI),
1798 iprop = u.uprops[oart->inv_prop].intrinsic;
1799 boolean on = (eprop & W_ARTI) != 0; /* true if prop just set */
1800
1801 if (on && obj->age > g.monstermoves) {
1802 /* the artifact is tired :-) */
1803 u.uprops[oart->inv_prop].extrinsic ^= W_ARTI;
1804 You_feel("that %s %s ignoring you.", the(xname(obj)),
1805 otense(obj, "are"));
1806 if (!(wizard && yn("Override?") == 'y')) {
1807 /* can't just keep repeatedly trying */
1808 obj->age += (long) d(3, 10);
1809 return 1;
1810 }
1811 } else if (!on) {
1812 /* when turning off property, determine downtime */
1813 /* arbitrary for now until we can tune this -dlc */
1814 obj->age = g.monstermoves + rnz(100);
1815 }
1816
1817 if ((eprop & ~W_ARTI) || iprop) {
1818 nothing_special:
1819 /* you had the property from some other source too */
1820 if (carried(obj))
1821 You_feel("a surge of power, but nothing seems to happen.");
1822 return 1;
1823 }
1824 switch (oart->inv_prop) {
1825 case CONFLICT:
1826 if (on)
1827 You_feel("like a rabble-rouser.");
1828 else
1829 You_feel("the tension decrease around you.");
1830 break;
1831 case LEVITATION:
1832 if (on) {
1833 float_up();
1834 spoteffects(FALSE);
1835 } else
1836 (void) float_down(I_SPECIAL | TIMEOUT, W_ARTI);
1837 break;
1838 /* Formerly used for Orb of Detection, now unused.
1839 case INVIS:
1840 if (BInvis || Blind)
1841 goto nothing_special;
1842 newsym(u.ux, u.uy);
1843 if (on)
1844 Your("body takes on a %s transparency...",
1845 Hallucination ? "normal" : "strange");
1846 else
1847 Your("body seems to unfade...");
1848 break;
1849 */
1850 }
1851 }
1852
1853 return 1;
1854 }
1855
1856 /* will freeing this object from inventory cause levitation to end? */
1857 boolean
finesse_ahriman(struct obj * obj)1858 finesse_ahriman(struct obj *obj)
1859 {
1860 const struct artifact *oart;
1861 struct prop save_Lev;
1862 boolean result;
1863
1864 /* if we aren't levitating or this isn't an artifact which confers
1865 levitation via #invoke then freeinv() won't toggle levitation */
1866 if (!Levitation || (oart = get_artifact(obj)) == 0
1867 || oart->inv_prop != LEVITATION || !(ELevitation & W_ARTI))
1868 return FALSE;
1869
1870 /* arti_invoke(off) -> float_down() clears I_SPECIAL|TIMEOUT & W_ARTI;
1871 probe ahead to see whether that actually results in floating down;
1872 (this assumes that there aren't two simultaneously invoked artifacts
1873 both conferring levitation--safe, since if there were two of them,
1874 invoking the 2nd would negate the 1st rather than stack with it) */
1875 save_Lev = u.uprops[LEVITATION];
1876 HLevitation &= ~(I_SPECIAL | TIMEOUT);
1877 ELevitation &= ~W_ARTI;
1878 result = (boolean) !Levitation;
1879 u.uprops[LEVITATION] = save_Lev;
1880 return result;
1881 }
1882
1883 /* WAC return TRUE if artifact is always lit */
1884 boolean
artifact_light(struct obj * obj)1885 artifact_light(struct obj *obj)
1886 {
1887 return (boolean) (get_artifact(obj) && obj->oartifact == ART_SUNSWORD);
1888 }
1889
1890 /* KMH -- Talking artifacts are finally implemented */
1891 void
arti_speak(struct obj * obj)1892 arti_speak(struct obj *obj)
1893 {
1894 register const struct artifact *oart = get_artifact(obj);
1895 const char *line;
1896 char buf[BUFSZ];
1897
1898 /* Is this a speaking artifact? */
1899 if (!oart || !(oart->spfx & SPFX_SPEAK))
1900 return;
1901
1902 line = getrumor(bcsign(obj), buf, TRUE);
1903 if (!*line)
1904 line = "NetHack rumors file closed for renovation.";
1905 pline("%s:", Tobjnam(obj, "whisper"));
1906 verbalize1(line);
1907 return;
1908 }
1909
1910 boolean
artifact_has_invprop(struct obj * otmp,uchar inv_prop)1911 artifact_has_invprop(struct obj *otmp, uchar inv_prop)
1912 {
1913 const struct artifact *arti = get_artifact(otmp);
1914
1915 return (boolean) (arti && (arti->inv_prop == inv_prop));
1916 }
1917
1918 /* Return the price sold to the hero of a given artifact or unique item */
1919 long
arti_cost(struct obj * otmp)1920 arti_cost(struct obj *otmp)
1921 {
1922 if (!otmp->oartifact)
1923 return (long) objects[otmp->otyp].oc_cost;
1924 else if (artilist[(int) otmp->oartifact].cost)
1925 return artilist[(int) otmp->oartifact].cost;
1926 else
1927 return (100L * (long) objects[otmp->otyp].oc_cost);
1928 }
1929
1930 static uchar
abil_to_adtyp(long * abil)1931 abil_to_adtyp(long *abil)
1932 {
1933 struct abil2adtyp_tag {
1934 long *abil;
1935 uchar adtyp;
1936 } abil2adtyp[] = {
1937 { &EFire_resistance, AD_FIRE },
1938 { &ECold_resistance, AD_COLD },
1939 { &EShock_resistance, AD_ELEC },
1940 { &EAntimagic, AD_MAGM },
1941 { &EDisint_resistance, AD_DISN },
1942 { &EPoison_resistance, AD_DRST },
1943 { &EDrain_resistance, AD_DRLI },
1944 };
1945 int k;
1946
1947 for (k = 0; k < SIZE(abil2adtyp); k++) {
1948 if (abil2adtyp[k].abil == abil)
1949 return abil2adtyp[k].adtyp;
1950 }
1951 return 0;
1952 }
1953
1954 static unsigned long
abil_to_spfx(long * abil)1955 abil_to_spfx(long *abil)
1956 {
1957 static const struct abil2spfx_tag {
1958 long *abil;
1959 unsigned long spfx;
1960 } abil2spfx[] = {
1961 { &ESearching, SPFX_SEARCH },
1962 { &EHalluc_resistance, SPFX_HALRES },
1963 { &ETelepat, SPFX_ESP },
1964 { &EStealth, SPFX_STLTH },
1965 { &ERegeneration, SPFX_REGEN },
1966 { &ETeleport_control, SPFX_TCTRL },
1967 { &EWarn_of_mon, SPFX_WARN },
1968 { &EWarning, SPFX_WARN },
1969 { &EEnergy_regeneration, SPFX_EREGEN },
1970 { &EHalf_spell_damage, SPFX_HSPDAM },
1971 { &EHalf_physical_damage, SPFX_HPHDAM },
1972 { &EReflecting, SPFX_REFLECT },
1973 };
1974 int k;
1975
1976 for (k = 0; k < SIZE(abil2spfx); k++) {
1977 if (abil2spfx[k].abil == abil)
1978 return abil2spfx[k].spfx;
1979 }
1980 return 0L;
1981 }
1982
1983 /*
1984 * Return the first item that is conveying a particular intrinsic.
1985 */
1986 struct obj *
what_gives(long * abil)1987 what_gives(long *abil)
1988 {
1989 struct obj *obj;
1990 uchar dtyp;
1991 unsigned long spfx;
1992 long wornbits;
1993 long wornmask = (W_ARM | W_ARMC | W_ARMH | W_ARMS
1994 | W_ARMG | W_ARMF | W_ARMU
1995 | W_AMUL | W_RINGL | W_RINGR | W_TOOL
1996 | W_ART | W_ARTI);
1997
1998 if (u.twoweap)
1999 wornmask |= W_SWAPWEP;
2000 dtyp = abil_to_adtyp(abil);
2001 spfx = abil_to_spfx(abil);
2002 wornbits = (wornmask & *abil);
2003
2004 for (obj = g.invent; obj; obj = obj->nobj) {
2005 if (obj->oartifact
2006 && (abil != &EWarn_of_mon || g.context.warntype.obj
2007 || g.context.warntype.obj_mlet)) {
2008 const struct artifact *art = get_artifact(obj);
2009
2010 if (art) {
2011 if (dtyp) {
2012 if (art->cary.adtyp == dtyp /* carried */
2013 || (art->defn.adtyp == dtyp /* defends while worn */
2014 && (obj->owornmask & ~(W_ART | W_ARTI))))
2015 return obj;
2016 }
2017 if (spfx) {
2018 /* property conferred when carried */
2019 if ((art->cspfx & spfx) == spfx)
2020 return obj;
2021 /* property conferred when wielded or worn */
2022 if ((art->spfx & spfx) == spfx && obj->owornmask)
2023 return obj;
2024 }
2025 }
2026 } else {
2027 if (wornbits && wornbits == (wornmask & obj->owornmask))
2028 return obj;
2029 }
2030 }
2031 return (struct obj *) 0;
2032 }
2033
2034 const char *
glow_color(int arti_indx)2035 glow_color(int arti_indx)
2036 {
2037 int colornum = artilist[arti_indx].acolor;
2038 const char *colorstr = clr2colorname(colornum);
2039
2040 return hcolor(colorstr);
2041 }
2042
2043 /* glow verb; [0] holds the value used when blind */
2044 static const char *glow_verbs[] = {
2045 "quiver", "flicker", "glimmer", "gleam"
2046 };
2047
2048 /* relative strength that Sting is glowing (0..3), to select verb */
2049 static int
glow_strength(int count)2050 glow_strength(int count)
2051 {
2052 /* glow strength should also be proportional to proximity and
2053 probably difficulty, but we don't have that information and
2054 gathering it is more trouble than this would be worth */
2055 return (count > 12) ? 3 : (count > 4) ? 2 : (count > 0);
2056 }
2057
2058 const char *
glow_verb(int count,boolean ingsfx)2059 glow_verb(int count, /* 0 means blind rather than no applicable creatures */
2060 boolean ingsfx)
2061 {
2062 static char resbuf[20];
2063
2064 Strcpy(resbuf, glow_verbs[glow_strength(count)]);
2065 /* ing_suffix() will double the last consonant for all the words
2066 we're using and none of them should have that, so bypass it */
2067 if (ingsfx)
2068 Strcat(resbuf, "ing");
2069 return resbuf;
2070 }
2071
2072 /* use for warning "glow" for Sting, Orcrist, and Grimtooth */
2073 void
Sting_effects(int orc_count)2074 Sting_effects(int orc_count) /* new count (warn_obj_cnt is old count); -1 is a flag value */
2075 {
2076 if (uwep && uwep->oartifact
2077 && artilist[(int) uwep->oartifact].acolor != NO_COLOR) {
2078 int oldstr = glow_strength(g.warn_obj_cnt),
2079 newstr = glow_strength(orc_count);
2080
2081 if (orc_count == -1 && g.warn_obj_cnt > 0) {
2082 /* -1 means that blindness has just been toggled; give a
2083 'continue' message that eventual 'stop' message will match */
2084 pline("%s is %s.", bare_artifactname(uwep),
2085 glow_verb(Blind ? 0 : g.warn_obj_cnt, TRUE));
2086 } else if (newstr > 0 && newstr != oldstr) {
2087 /* goto_level() -> docrt() -> see_monsters() -> Sting_effects();
2088 if "you materialize on a different level" is pending, give
2089 it now so that start-glowing message comes after it */
2090 maybe_lvltport_feedback(); /* usually called by goto_level() */
2091
2092 /* 'start' message */
2093 if (!Blind)
2094 pline("%s %s %s%c", bare_artifactname(uwep),
2095 otense(uwep, glow_verb(orc_count, FALSE)),
2096 glow_color(uwep->oartifact),
2097 (newstr > oldstr) ? '!' : '.');
2098 else if (oldstr == 0) /* quivers */
2099 pline("%s %s slightly.", bare_artifactname(uwep),
2100 otense(uwep, glow_verb(0, FALSE)));
2101 } else if (orc_count == 0 && g.warn_obj_cnt > 0) {
2102 /* 'stop' message */
2103 pline("%s stops %s.", bare_artifactname(uwep),
2104 glow_verb(Blind ? 0 : g.warn_obj_cnt, TRUE));
2105 }
2106 }
2107 }
2108
2109 /* called when hero is wielding/applying/invoking a carried item, or
2110 after undergoing a transformation (alignment change, lycanthropy,
2111 polymorph) which might affect item access */
2112 int
retouch_object(struct obj ** objp,boolean loseit,boolean protected_by_gear)2113 retouch_object(struct obj **objp, /* might be destroyed or unintentionally dropped */
2114 boolean loseit, /* whether to drop it if hero can longer touch it */
2115 boolean protected_by_gear) /* whether the player has gear that
2116 * will protect them from touching
2117 * *obj if it is a hated material */
2118 {
2119 struct obj *obj = *objp;
2120
2121 /* allow hero in silver-hating form to try to perform invocation ritual */
2122 if (obj->otyp == BELL_OF_OPENING
2123 && invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
2124 return 1;
2125 }
2126
2127 if (touch_artifact(obj, &g.youmonst)) {
2128 char buf[BUFSZ];
2129 int dmg = 0;
2130 boolean hatemat = Hate_material(obj->material),
2131 bane = bane_applies(get_artifact(obj), &g.youmonst);
2132
2133 /* nothing else to do if hero can successfully handle this object */
2134 if (!hatemat && !bane)
2135 return 1;
2136
2137 /* another case where nothing should happen: hero is wearing gloves
2138 * which protect them from directly touching a weapon of a material they
2139 * hate
2140 * (no other gear slots are considered to completely block touching an
2141 * outer piece of gear; e.g. wearing body armor doesn't protect from
2142 * touching a worn cloak) */
2143 if (!bane && protected_by_gear)
2144 return 1;
2145
2146 /* hero can't handle this object, but didn't get touch_artifact()'s
2147 "<obj> evades your grasp|control" message; give an alternate one */
2148
2149 if (!bane && !(hatemat && obj->material == SILVER)) {
2150 pline("The %s of %s hurts to touch!", materialnm[obj->material],
2151 yname(obj));
2152 }
2153 else {
2154 You_cant("handle %s%s!", yname(obj),
2155 obj->owornmask ? " anymore" : "");
2156 }
2157 /* also inflict damage unless touch_artifact() already did so */
2158 if (!touch_blasted) {
2159 /* damage is somewhat arbitrary: 1d10 magical for <foo>bane,
2160 * half of the usual damage for materials */
2161 if (hatemat)
2162 dmg += rnd(sear_damage(obj->material) / 2);
2163 if (bane)
2164 dmg += rnd(10);
2165 Sprintf(buf, "handling %s", killer_xname(obj));
2166 losehp(dmg, buf, KILLED_BY);
2167 exercise(A_CON, FALSE);
2168 }
2169 /* concession to elves wishing to use iron gear: don't make them
2170 * totally unable to use them. In fact, they can touch them just fine
2171 * as long as they're willing to.
2172 * In keeping with the flavor of searing vs just pain implemented
2173 * everywhere else, only silver is actually unbearable -- other
2174 * hated non-silver materials can be used too. */
2175 if (!bane && !(hatemat && obj->material == SILVER))
2176 return 1;
2177 }
2178
2179 /* removing a worn item might result in loss of levitation,
2180 dropping the hero onto a polymorph trap or into water or
2181 lava and potentially dropping or destroying the item */
2182 if (obj->owornmask) {
2183 struct obj *otmp;
2184
2185 remove_worn_item(obj, FALSE);
2186 for (otmp = g.invent; otmp; otmp = otmp->nobj)
2187 if (otmp == obj)
2188 break;
2189 if (!otmp)
2190 *objp = obj = 0;
2191 }
2192
2193 /* if we still have it and caller wants us to drop it, do so now */
2194 if (loseit && obj) {
2195 if (Levitation) {
2196 freeinv(obj);
2197 hitfloor(obj, TRUE);
2198 } else {
2199 /* dropx gives a message iff item lands on an altar */
2200 if (!IS_ALTAR(levl[u.ux][u.uy].typ))
2201 pline("%s to the %s.", Tobjnam(obj, "fall"),
2202 surface(u.ux, u.uy));
2203 dropx(obj);
2204 }
2205 *objp = obj = 0; /* no longer in inventory */
2206 }
2207 return 0;
2208 }
2209
2210 /* an item which is worn/wielded or an artifact which conveys
2211 something via being carried or which has an #invoke effect
2212 currently in operation undergoes a touch test; if it fails,
2213 it will be unworn/unwielded and revoked but not dropped */
2214 static boolean
untouchable(struct obj * obj,boolean drop_untouchable)2215 untouchable(struct obj *obj, boolean drop_untouchable)
2216 {
2217 struct artifact *art;
2218 boolean beingworn, carryeffect, invoked;
2219 long wearmask = ~(W_QUIVER | (u.twoweap ? 0L : W_SWAPWEP) | W_BALL);
2220
2221 beingworn = ((obj->owornmask & wearmask) != 0L
2222 /* some items in use don't have any wornmask setting */
2223 || (obj->oclass == TOOL_CLASS
2224 && (obj->lamplit || (obj->otyp == LEASH && obj->leashmon)
2225 || (Is_container(obj) && Has_contents(obj)))));
2226
2227 if ((art = get_artifact(obj)) != 0) {
2228 carryeffect = (art->cary.adtyp || art->cspfx);
2229 invoked = (art->inv_prop > 0 && art->inv_prop <= LAST_PROP
2230 && (u.uprops[art->inv_prop].extrinsic & W_ARTI) != 0L);
2231 } else {
2232 carryeffect = invoked = FALSE;
2233 }
2234
2235 if (beingworn || carryeffect || invoked) {
2236 if (!retouch_object(&obj, drop_untouchable,
2237 !will_touch_skin(obj->owornmask & wearmask))) {
2238 /* "<artifact> is beyond your control" or "you can't handle
2239 <object>" has been given and it is now unworn/unwielded
2240 and possibly dropped (depending upon caller); if dropped,
2241 carried effect was turned off, else we leave that alone;
2242 we turn off invocation property here if still carried */
2243 if (invoked && obj)
2244 arti_invoke(obj); /* reverse #invoke */
2245 return TRUE;
2246 }
2247 }
2248 return FALSE;
2249 }
2250
2251 /* check all items currently in use (mostly worn) for touchability */
2252 void
retouch_equipment(int dropflag)2253 retouch_equipment(int dropflag) /* 0==don't drop, 1==drop all, 2==drop weapon */
2254 {
2255 static int nesting = 0; /* recursion control */
2256 struct obj *obj;
2257 boolean dropit, had_gloves = (uarmg != 0);
2258 int had_rings = (!!uleft + !!uright);
2259
2260 /*
2261 * We can potentially be called recursively if losing/unwearing
2262 * an item causes worn helm of opposite alignment to come off or
2263 * be destroyed.
2264 *
2265 * BUG: if the initial call was due to putting on a helm of
2266 * opposite alignment and it does come off to trigger recursion,
2267 * after the inner call executes, the outer call will finish
2268 * using the non-helm alignment rather than the helm alignment
2269 * which triggered this in the first place.
2270 */
2271 if (!nesting++)
2272 clear_bypasses(); /* init upon initial entry */
2273
2274 dropit = (dropflag > 0); /* drop all or drop weapon */
2275 /* check secondary weapon first, before possibly unwielding primary */
2276 if (u.twoweap) {
2277 bypass_obj(uswapwep); /* so loop below won't process it again */
2278 (void) untouchable(uswapwep, dropit);
2279 }
2280 /* check primary weapon next so that they're handled together */
2281 if (uwep) {
2282 bypass_obj(uwep); /* so loop below won't process it again */
2283 (void) untouchable(uwep, dropit);
2284 }
2285
2286 /* in case someone is daft enough to add artifact or silver saddle */
2287 if (u.usteed && (obj = which_armor(u.usteed, W_SADDLE)) != 0) {
2288 /* untouchable() calls retouch_object() which expects an object in
2289 hero's inventory, but remove_worn_item() will be harmless for
2290 saddle and we're suppressing drop, so this works as intended */
2291 if (untouchable(obj, FALSE))
2292 dismount_steed(DISMOUNT_THROWN);
2293 }
2294 /*
2295 * TODO? Force off gloves if either or both rings are going to
2296 * become unworn; force off cloak [suit] before suit [shirt].
2297 * The torso handling is hypothetical; the case for gloves is
2298 * not, due to the possibility of unwearing silver rings.
2299 */
2300
2301 dropit = (dropflag == 1); /* all untouchable items */
2302 /* loss of levitation (silver ring, or Heart of Ahriman invocation)
2303 might cause hero to lose inventory items (by dropping into lava,
2304 for instance), so inventory traversal needs to rescan the whole
2305 g.invent chain each time it moves on to another object; we use bypass
2306 handling to keep track of which items have already been processed */
2307 while ((obj = nxt_unbypassed_obj(g.invent)) != 0)
2308 (void) untouchable(obj, dropit);
2309
2310 if (had_rings != (!!uleft + !!uright) && uarmg && uarmg->cursed)
2311 uncurse(uarmg); /* temporary? hack for ring removal plausibility */
2312 if (had_gloves && !uarmg)
2313 selftouch("After losing your gloves, you");
2314
2315 if (!--nesting)
2316 clear_bypasses(); /* reset upon final exit */
2317 }
2318
2319 static int
count_surround_traps(int x,int y)2320 count_surround_traps(int x, int y)
2321 {
2322 struct rm *levp;
2323 struct obj *otmp;
2324 struct trap *ttmp;
2325 int dx, dy, glyph, ret = 0;
2326
2327 for (dx = x - 1; dx < x + 2; ++dx)
2328 for (dy = y - 1; dy < y + 2; ++dy) {
2329 if (!isok(dx, dy))
2330 continue;
2331 /* If a trap is shown here, don't count it; the hero
2332 * should be expecting it. But if there is a trap here
2333 * that's not shown, either undiscovered or covered by
2334 * something, do count it.
2335 */
2336 glyph = glyph_at(dx, dy);
2337 if (glyph_is_trap(glyph))
2338 continue;
2339 if ((ttmp = t_at(dx, dy)) != 0) {
2340 ++ret;
2341 continue;
2342 }
2343 levp = &levl[dx][dy];
2344 if (IS_DOOR(levp->typ) && door_is_trapped(levp)) {
2345 ++ret;
2346 continue;
2347 }
2348 for (otmp = g.level.objects[dx][dy]; otmp; otmp = otmp->nexthere)
2349 if (Is_container(otmp) && otmp->otrapped) {
2350 ++ret; /* we're counting locations, so just */
2351 break; /* count the first one in a pile */
2352 }
2353 }
2354 /*
2355 * [Shouldn't we also check inventory for a trapped container?
2356 * Even if its trap has already been found, there's no 'tknown'
2357 * flag to help hero remember that so we have nothing comparable
2358 * to a shown glyph to justify skipping it.]
2359 */
2360 return ret;
2361 }
2362
2363 /* sense adjacent traps if wielding MKoT without wearing gloves */
2364 void
mkot_trap_warn(void)2365 mkot_trap_warn(void)
2366 {
2367 static const char *const heat[7] = {
2368 "cool", "slightly warm", "warm", "very warm",
2369 "hot", "very hot", "like fire"
2370 };
2371
2372 if (!uarmg && uwep && uwep->oartifact == ART_MASTER_KEY_OF_THIEVERY) {
2373 int idx, ntraps = count_surround_traps(u.ux, u.uy);
2374
2375 if (ntraps != g.mkot_trap_warn_count) {
2376 idx = min(ntraps, SIZE(heat) - 1);
2377 pline_The("Key feels %s%c", heat[idx], (ntraps > 3) ? '!' : '.');
2378 }
2379 g.mkot_trap_warn_count = ntraps;
2380 } else
2381 g.mkot_trap_warn_count = 0;
2382 }
2383
2384 /* Master Key is magic key if its bless/curse state meets our criteria:
2385 not cursed for rogues or blessed for non-rogues */
2386 boolean
is_magic_key(struct monst * mon,struct obj * obj)2387 is_magic_key(struct monst *mon, /* if null, non-rogue is assumed */
2388 struct obj *obj)
2389 {
2390 if (obj && obj->oartifact == ART_MASTER_KEY_OF_THIEVERY) {
2391 if ((mon == &g.youmonst) ? Role_if(PM_ROGUE)
2392 : (mon && mon->data == &mons[PM_ROGUE]))
2393 return !obj->cursed; /* a rogue; non-cursed suffices for magic */
2394 /* not a rogue; key must be blessed to behave as a magic one */
2395 return obj->blessed;
2396 }
2397 return FALSE;
2398 }
2399
2400 /* figure out whether 'mon' (usually youmonst) is carrying the magic key */
2401 struct obj *
has_magic_key(struct monst * mon)2402 has_magic_key(struct monst *mon) /* if null, hero assumed */
2403 {
2404 struct obj *o;
2405 short key = artilist[ART_MASTER_KEY_OF_THIEVERY].otyp;
2406
2407 if (!mon)
2408 mon = &g.youmonst;
2409 for (o = ((mon == &g.youmonst) ? g.invent : mon->minvent); o;
2410 o = nxtobj(o, key, FALSE)) {
2411 if (is_magic_key(mon, o))
2412 return o;
2413 }
2414 return (struct obj *) 0;
2415 }
2416
2417 /* return TRUE if obj is permanently poisoned (currently only true for artifacts
2418 * in general and Grimtooth specifically) */
2419 boolean
permapoisoned(struct obj * obj)2420 permapoisoned(struct obj *obj)
2421 {
2422 return (obj && obj->oartifact == ART_GRIMTOOTH);
2423 }
2424
2425 /* return TRUE if obj is an artifact with a name like "The X [of Y]" */
2426 boolean
arti_starts_with_the(struct obj * obj)2427 arti_starts_with_the(struct obj *obj)
2428 {
2429 const char *artname;
2430 if (!obj->oartifact)
2431 return FALSE;
2432
2433 artname = artiname(obj->oartifact);
2434 if (!strncmp(artname, "The", 3)) {
2435 return TRUE;
2436 }
2437 return FALSE;
2438 }
2439
2440 /*artifact.c*/
2441